Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2ac2608 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ion: Add hibernation support for system secure heap"

parents 28a66470 842474f1
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -159,6 +159,12 @@ struct ion_device {
	int heap_cnt;
};

/* refer to include/linux/pm.h */
struct ion_pm_ops {
	int (*freeze)(struct ion_heap *heap);
	int (*restore)(struct ion_heap *heap);
};

/**
 * struct ion_heap_ops - ops to operate on a given heap
 * @allocate:		allocate memory
@@ -184,6 +190,7 @@ struct ion_heap_ops {
	int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer,
			struct vm_area_struct *vma);
	int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan);
	struct ion_pm_ops pm;
};

/**
+38 −0
Original line number Diff line number Diff line
@@ -343,6 +343,41 @@ static int ion_system_secure_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
						gfp_mask, nr_to_scan);
}

static int ion_system_secure_heap_pm_freeze(struct ion_heap *heap)
{
	struct ion_system_secure_heap *secure_heap;
	unsigned long count;
	long sz;
	struct shrink_control sc = {
		.gfp_mask = GFP_HIGHUSER,
	};

	secure_heap = container_of(heap, struct ion_system_secure_heap, heap);

	sz = atomic_long_read(&heap->total_allocated);
	if (sz) {
		pr_err("%s: %lx bytes won't be saved across hibernation. Aborting.",
		       __func__, sz);
		return -EINVAL;
	}

	/* Since userspace is frozen, no more requests will be queued */
	cancel_delayed_work_sync(&secure_heap->prefetch_work);

	count = heap->shrinker.count_objects(&heap->shrinker, &sc);
	sc.nr_to_scan = count;
	heap->shrinker.scan_objects(&heap->shrinker, &sc);

	count = heap->shrinker.count_objects(&heap->shrinker, &sc);
	if (count) {
		pr_err("%s: Failed to free all objects - %ld remaining",
		       __func__, count);
		return -EINVAL;
	}

	return 0;
}

static struct ion_heap_ops system_secure_heap_ops = {
	.allocate = ion_system_secure_heap_allocate,
	.free = ion_system_secure_heap_free,
@@ -350,6 +385,9 @@ static struct ion_heap_ops system_secure_heap_ops = {
	.unmap_kernel = ion_system_secure_heap_unmap_kernel,
	.map_user = ion_system_secure_heap_map_user,
	.shrink = ion_system_secure_heap_shrink,
	.pm = {
		.freeze = ion_system_secure_heap_pm_freeze,
	}
};

struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *unused)
+57 −0
Original line number Diff line number Diff line
@@ -344,6 +344,62 @@ static int msm_ion_probe(struct platform_device *pdev)
	return err;
}

static int msm_ion_pm_freeze(struct device *dev)
{
	struct ion_device *ion_dev = dev_get_drvdata(dev);
	struct ion_heap *heap;
	int ret;

	plist_for_each_entry(heap, &ion_dev->heaps, node) {
		if (heap->ops->pm.freeze) {
			ret = heap->ops->pm.freeze(heap);
			if (ret) {
				dev_err(dev, "%s freeze callback failed\n",
					heap->name);
				goto undo;
			}
		}
	}

	return 0;

undo:
	list_for_each_entry_continue_reverse(heap, &ion_dev->heaps.node_list,
					     node.node_list)
		if (heap->ops->pm.restore)
			heap->ops->pm.restore(heap);

	return ret;
}

static int msm_ion_pm_restore(struct device *dev)
{
	struct ion_device *ion_dev = dev_get_drvdata(dev);
	struct ion_heap *heap;
	int ret = 0;

	plist_for_each_entry(heap, &ion_dev->heaps, node) {
		int rc;

		if (heap->ops->pm.restore) {
			rc = heap->ops->pm.restore(heap);
			if (rc) {
				dev_err(dev, "%s restore callback failed.\n",
					heap->name);
				if (!ret)
					ret = rc;
			}
		}
	}

	return ret;
}

static const struct dev_pm_ops msm_ion_pm_ops = {
	.freeze = msm_ion_pm_freeze,
	.restore = msm_ion_pm_restore,
};

static const struct of_device_id msm_ion_match_table[] = {
	{.compatible = ION_COMPAT_STR},
	{},
@@ -354,6 +410,7 @@ static struct platform_driver msm_ion_driver = {
	.driver = {
		.name = "ion-msm",
		.of_match_table = msm_ion_match_table,
		.pm = &msm_ion_pm_ops,
	},
};