[COMMON] android: ion: ion_test add ION_IOC_TEST_PHYS
authorCho KyongHo <pullip.cho@samsung.com>
Tue, 30 May 2017 15:00:57 +0000 (00:00 +0900)
committerSangwook Ju <sw.ju@samsung.com>
Mon, 14 May 2018 10:45:22 +0000 (19:45 +0900)
ION_IOC_TEST_PHYS tests various aspects of the buffers from ION.

Change-Id: I67ac43837eca444ebd4c7b6e838b96532e6d3c9e
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
drivers/staging/android/ion/ion_test.c
drivers/staging/android/uapi/ion_test.h

index 05673eb46de280972e6fac5330bb823ee2e85787..655166ae361c71efc819718f182c2587253c1702 100644 (file)
@@ -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;
        }
index 480242e02f8d64b547792225e2aacb7629b496f8..992984a844a8907277a98fdecc2d5657e6b4a2d6 100644 (file)
@@ -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 */