From 824d9937b5b382c31fab4a3f44cd1596a79dc56c Mon Sep 17 00:00:00 2001 From: Cho KyongHo Date: Wed, 31 May 2017 00:00:57 +0900 Subject: [PATCH] [COMMON] android: ion: ion_test add ION_IOC_TEST_PHYS ION_IOC_TEST_PHYS tests various aspects of the buffers from ION. Change-Id: I67ac43837eca444ebd4c7b6e838b96532e6d3c9e Signed-off-by: Cho KyongHo --- drivers/staging/android/ion/ion_test.c | 142 ++++++++++++++++++++++++ drivers/staging/android/uapi/ion_test.h | 42 +++++++ 2 files changed, 184 insertions(+) diff --git a/drivers/staging/android/ion/ion_test.c b/drivers/staging/android/ion/ion_test.c index 05673eb46de2..655166ae361c 100644 --- a/drivers/staging/android/ion/ion_test.c +++ b/drivers/staging/android/ion/ion_test.c @@ -144,6 +144,139 @@ err: return ret; } +static int ion_handle_test_phys(struct ion_test_data *test_data, + u32 cmd, u32 arg, u32 *result) +{ + struct dma_buf_attachment *att; + struct sg_table *sgt; + struct scatterlist *sg; + int ret = 0; + int i; + + if (!test_data->dma_buf) { + pr_err("%s: no dmabuf is attached\n", __func__); + return -EINVAL; + } + + att = dma_buf_attach(test_data->dma_buf, test_data->dev); + if (IS_ERR(att)) { + pr_err("%s: Failed to attach dmabuf\n", __func__); + return PTR_ERR(att); + } + + sgt = dma_buf_map_attachment(att, DMA_TO_DEVICE); + if (IS_ERR(sgt)) { + pr_err("%s: Failed to map to attachment\n", __func__); + ret = PTR_ERR(sgt); + goto err_map; + } + + switch (cmd) { + case PHYS_CHUNK_IS_IDENTICAL_SIZE: + { + size_t len = sgt->sgl->length; + + for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { + if (len != sg->length) { + pr_err( + "%s: expected size %zu but found %u at %d\n", + __func__, len, sg->length, i); + ret = -EINVAL; + break; + } + } + break; + } + case PHYS_IS_ORDERED_IN_ADDRESS: + { + phys_addr_t addr = 0; + + for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { + if (addr >= sg_phys(sg)) { + pr_err("%s: pages are not in address order\n", + __func__); + ret = -EINVAL; + break; + } + addr = sg_phys(sg); + } + break; + } + case PHYS_IS_RESERVED: + { + if (sgt->orig_nents != 1) { + pr_err("%s: buffer should be physically contiguous\n", + __func__); + ret = -EINVAL; + break; + } + + if (!PageReserved(sg_page(sgt->sgl))) { + pr_err("%s: page of the buffer is not reserved\n", + __func__); + ret = -EINVAL; + break; + } + + break; + } + case PHYS_IS_CMA: + { + if (sgt->orig_nents != 1) { + pr_err("%s: buffer should be physically contiguous\n", + __func__); + ret = -EINVAL; + break; + } + + if (!is_migrate_cma_page(sg_page(sgt->sgl))) { + pr_err("%s: page of the buffer is not cma page\n", + __func__); + ret = -EINVAL; + break; + } + + break; + } + case PHYS_IS_ALIGNED: + { + if (sgt->orig_nents != 1) { + pr_err("%s: buffer should be physically contiguous\n", + __func__); + ret = -EINVAL; + break; + } + + if ((arg & ~arg) != 0) { + pr_err( + "%s: arg %u of PHYS_IS_ALIGNED is not power of 2\n", + __func__, arg); + ret = -EINVAL; + break; + } + + if (!IS_ALIGNED(sg_phys(sgt->sgl), arg)) { + pr_err("%s: buffer is not aligned by %u\n", + __func__, arg); + ret = -EINVAL; + break; + } + break; + } + default: + pr_err("%s: unknown command %u to ION_IOC_TEST_PHYS\n", + __func__, cmd); + ret = -EINVAL; + break; + } + + dma_buf_unmap_attachment(att, sgt, DMA_TO_DEVICE); +err_map: + dma_buf_detach(test_data->dma_buf, att); + + return ret; +} + static long ion_test_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -152,6 +285,7 @@ static long ion_test_ioctl(struct file *filp, unsigned int cmd, union { struct ion_test_rw_data test_rw; + struct ion_test_phys_data phys; } data; if (_IOC_SIZE(cmd) > sizeof(data)) @@ -195,6 +329,14 @@ static long ion_test_ioctl(struct file *filp, unsigned int cmd, data.test_rw.write); break; } + case ION_IOC_TEST_PHYS: + { + ret = ion_handle_test_phys(test_data, + data.phys.cmd, + data.phys.arg, + &data.phys.result); + break; + } default: return -ENOTTY; } diff --git a/drivers/staging/android/uapi/ion_test.h b/drivers/staging/android/uapi/ion_test.h index 480242e02f8d..992984a844a8 100644 --- a/drivers/staging/android/uapi/ion_test.h +++ b/drivers/staging/android/uapi/ion_test.h @@ -35,6 +35,39 @@ struct ion_test_rw_data { int __padding; }; +/** + * struct ion_test_phys_data - metadata passed to the kernel to check phys + * @cmd: what to test. One of the followings: + * - PHYS_CHUNK_IS_IDENTICAL_SIZE: check if physical memory is + * a set of memory chunks with identical size. If this test + * succeeds, ion_test driver stores the chunk size to + * ion_test_phys_data.result. + * - PHYS_IS_ORDERED_IN_ADDRESS: check if physical memory is + * sorted in address order of each physical memory chunks. + * - PHYS_IS_RESERVED: check if physically contiguous and its + * carved out(!pfn_valid()) or reserve (PG_reserved) + * - PHYS_IS_CMA: check if physically contiguous and its + * migratetype is MIGRATE_CMA + * - PHYS_IS_ALIGNED: check if the address of the first physical + * memory chunk is aligned by @arg. + * @arg: an argument to @cmd. the meaning of @arg varies according to + * @cmd. + * @result: result of @cmd is stored if required. + */ +enum { + PHYS_CHUNK_IS_IDENTICAL_SIZE = 0, + PHYS_IS_ORDERED_IN_ADDRESS = 1, + PHYS_IS_RESERVED = 2, + PHYS_IS_CMA = 3, + PHYS_IS_ALIGNED = 4, +}; + +struct ion_test_phys_data { + __u32 cmd; + __u32 arg; + __u32 result; +}; + #define ION_IOC_MAGIC 'I' /** @@ -66,4 +99,13 @@ struct ion_test_rw_data { #define ION_IOC_TEST_KERNEL_MAPPING \ _IOW(ION_IOC_MAGIC, 0xf2, struct ion_test_rw_data) +/** + * DOC: ION_IOC_TEST_PHYS - Study the properties of physical memory + * + * Studies the properties of the physical memory of the allocated buffer from + * ION. + */ +#define ION_IOC_TEST_PHYS \ + _IOWR(ION_IOC_MAGIC, 0xf3, struct ion_test_phys_data) + #endif /* _UAPI_LINUX_ION_H */ -- 2.20.1