// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 MediaTek Inc. */ #define pr_fmt(fmt) "mtk_iommu: test " fmt /* * If you need to use iommu_test.ko, you must be * define "IOMMU_TEST_EN" as below and add dts node. */ /* #define IOMMU_TEST_EN */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef IOMMU_TEST_EN #include "mtk_heap.h" #define SECURE_HANDLE_TEST #define DEFINE_PROC_ATTRIBUTE(__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ struct inode local_inode = *inode; \ \ local_inode.i_private = PDE_DATA(inode); \ __simple_attr_check_format(__fmt, 0ull); \ return simple_attr_open(&local_inode, file, __get, __set, __fmt); \ } \ static const struct proc_ops __fops = { \ .proc_open = __fops ## _open, \ .proc_release = simple_attr_release, \ .proc_read = simple_attr_read, \ .proc_write = simple_attr_write, \ .proc_lseek = generic_file_llseek, \ } \ enum DMABUF_HEAP { TEST_REQ_SVP_REGION = 0, /* 0x0 normal region */ TEST_REQ_SVP_REGION_ALIGN_UP, /* 0x1 by video up */ TEST_REQ_SVP_REGION_ALIGN_VDEC, /* 0x2 by video up */ TEST_REQ_SVP_REGION_PA, /* 0x3 PA */ TEST_REQ_PROT_REGION = 10, /* 0xa normal region */ TEST_REQ_PROT_REGION_ALIGN_CCU0, /* 0xb by CCU0 */ TEST_REQ_PROT_REGION_PA, /* 0xc PA */ TEST_REQ_SVP_PAGE = 20, /* 0x14 normal region */ TEST_REQ_SVP_PAGE_UP, /* 0x15 special region video up */ TEST_REQ_SVP_PAGE_VDEC, /* 0x16 PA */ TEST_REQ_SVP_PAGE_PA, /* 0x17 PA */ TEST_REQ_PROT_PAGE = 30, /* 0x1e normal region */ TEST_REQ_PROT_PAGE_CCU0, /* 0x1f CCU0 */ TEST_REQ_PROT_PAGE_PA, /* 0x20 PA */ TEST_PROT_2D_FR_REGION = 40, /* 0x28:cancel */ TEST_PROT_2D_FR_REGION_ALIGN, /* 0x29:cancel */ TEST_SAPU_DATA_SHM_REGION = 50, /* 0x32 */ TEST_SAPU_DATA_SHM_REGION_ALIGN, /* 0x33 */ TEST_SAPU_ENGINE_SHM_REGION = 60, /* 0x3c */ TEST_SAPU_ENGINE_SHM_REGION_ALIGN, /* 0x3d */ TEST_WFD_REGION = 70, /* 0x46 normal region */ TEST_WFD_REGION_ALIGN_UP, /* 0x47 by video up */ TEST_WFD_REGION_ALIGN_VDEC, /* 0x48 by VDEC */ TEST_WFD_REGION_PA, /* 0x49 PA */ TEST_MTK_NORMAL = 80, /* 0x50 */ /* * error test: * Use reserved module map buffer with region_heap, it will * return error because of PA/SIZE not 1MB alignment */ TEST_REQ_SVP_REGION_UP_ERR = 90, /* 0x5a video uP */ TEST_REQ_SVP_REGION_VDEC_ERR, /* 0x5b vdec */ TEST_REQ_PROT_REGION_CCU0_ERR, /* 0x5c ccu0 */ TEST_MTK_HEAP_NUM }; struct heap_name { enum DMABUF_HEAP id; char *name; }; static struct heap_name heap_obj[] = { [TEST_REQ_SVP_REGION] = { .id = TEST_REQ_SVP_REGION, .name = "svp_region_heap", }, [TEST_REQ_SVP_REGION_ALIGN_UP] = { .id = TEST_REQ_SVP_REGION_ALIGN_UP, .name = "svp_region_heap-aligned-up", }, [TEST_REQ_SVP_REGION_ALIGN_VDEC] = { .id = TEST_REQ_SVP_REGION_ALIGN_VDEC, .name = "svp_region_heap-aligned-vdec", }, [TEST_REQ_SVP_REGION_PA] = { .id = TEST_REQ_SVP_REGION_PA, .name = "svp_region_heap-PA", }, [TEST_REQ_PROT_REGION] = { .id = TEST_REQ_PROT_REGION, .name = "prot_region_heap", }, [TEST_REQ_PROT_REGION_ALIGN_CCU0] = { .id = TEST_REQ_PROT_REGION_ALIGN_CCU0, .name = "prot_region_heap-align-ccu0", }, [TEST_REQ_PROT_REGION_PA] = { .id = TEST_REQ_PROT_REGION_PA, .name = "prot_region_heap-PA", }, [TEST_REQ_SVP_PAGE] = { .id = TEST_REQ_SVP_PAGE, .name = "svp_page_normal", }, [TEST_REQ_SVP_PAGE_UP] = { .id = TEST_REQ_SVP_PAGE_UP, .name = "svp_page_up", }, [TEST_REQ_SVP_PAGE_VDEC] = { .id = TEST_REQ_SVP_PAGE_VDEC, .name = "svp_page_vdec", }, [TEST_REQ_SVP_PAGE_PA] = { .id = TEST_REQ_SVP_PAGE_PA, .name = "svp_page_pa", }, [TEST_REQ_PROT_PAGE] = { .id = TEST_REQ_PROT_PAGE, .name = "prot_page_normal", }, [TEST_REQ_PROT_PAGE_CCU0] = { .id = TEST_REQ_PROT_PAGE_CCU0, .name = "prot_page_ccu0", }, [TEST_REQ_PROT_PAGE_PA] = { .id = TEST_REQ_PROT_PAGE_PA, .name = "prot_page_pa", }, [TEST_PROT_2D_FR_REGION] = { .id = TEST_PROT_2D_FR_REGION, .name = "prot_2d_fr_region", }, [TEST_PROT_2D_FR_REGION_ALIGN] = { .id = TEST_PROT_2D_FR_REGION_ALIGN, .name = "prot_2d_fr_region-aligned", }, [TEST_SAPU_DATA_SHM_REGION] = { .id = TEST_SAPU_DATA_SHM_REGION, .name = "sapu_data_shm_region", }, [TEST_SAPU_DATA_SHM_REGION_ALIGN] = { .id = TEST_SAPU_DATA_SHM_REGION_ALIGN, .name = "sapu_data_shm_region-aligned", }, [TEST_SAPU_ENGINE_SHM_REGION] = { .id = TEST_SAPU_ENGINE_SHM_REGION, .name = "sapu_engine_shm_region", }, [TEST_SAPU_ENGINE_SHM_REGION_ALIGN] = { .id = TEST_SAPU_ENGINE_SHM_REGION_ALIGN, .name = "sapu_engine_shm_region-aligned", }, [TEST_WFD_REGION] = { .id = TEST_WFD_REGION, .name = "wfd_region", }, [TEST_WFD_REGION_ALIGN_UP] = { .id = TEST_WFD_REGION_ALIGN_UP, .name = "wfd_region_heap-aligned-up", }, [TEST_WFD_REGION_ALIGN_VDEC] = { .id = TEST_WFD_REGION_ALIGN_VDEC, .name = "wfd_region_heap-aligned-vdec", }, [TEST_WFD_REGION_PA] = { .id = TEST_WFD_REGION_PA, .name = "wfd_region_heap-PA", }, [TEST_MTK_NORMAL] = { .id = TEST_MTK_NORMAL, .name = "mm_heap", }, /* error test */ [TEST_REQ_SVP_REGION_UP_ERR] = { .id = TEST_REQ_SVP_REGION_UP_ERR, .name = "svp_region_video_up", }, [TEST_REQ_SVP_REGION_VDEC_ERR] = { .id = TEST_REQ_SVP_REGION_VDEC_ERR, .name = "prot_region_vdec", }, [TEST_REQ_PROT_REGION_CCU0_ERR] = { .id = TEST_REQ_PROT_REGION_CCU0_ERR, .name = "prot_region_ccu0", }, }; struct dmabuf_map { int id; struct dma_buf_attachment *attach; struct sg_table *table; dma_addr_t dma_address; struct list_head map_node; }; struct dmabuf_info { int id; size_t size; struct dma_buf *dmabuf; struct list_head buf_node; struct list_head map_head; struct mutex map_lock; }; struct dmabuf_data { struct device *dev; struct dma_heap *heap; struct mutex buf_lock; struct list_head buf_head; }; struct iommu_test_debug_data { struct proc_dir_entry *debug_root; }; static struct iommu_test_debug_data *debug_data; static struct dmabuf_data dmabuf_data_obj[TEST_MTK_HEAP_NUM]; static int dmabuf_id, attach_id; static size_t test_size = 0x1800; //6K static enum DMABUF_HEAP test_heap = TEST_REQ_PROT_REGION; static struct dmabuf_map *dmabuf_map_alloc(int id) { struct dmabuf_map *map_obj = NULL; map_obj = kzalloc(sizeof(struct dmabuf_map), GFP_KERNEL); if (map_obj == NULL) return NULL; INIT_LIST_HEAD(&(map_obj->map_node)); map_obj->id = id; return map_obj; } static struct dmabuf_info *dmabuf_info_alloc(int buf_id) { struct dmabuf_info *info_obj = NULL; info_obj = kzalloc(sizeof(struct dmabuf_info), GFP_KERNEL); if (info_obj == NULL) return NULL; INIT_LIST_HEAD(&(info_obj->buf_node)); INIT_LIST_HEAD(&(info_obj->map_head)); mutex_init(&info_obj->map_lock); info_obj->id = buf_id; return info_obj; } static void add_dmabuf_info(struct dmabuf_data *data, struct dmabuf_info *plist) { mutex_lock(&(data->buf_lock)); list_add(&(plist->buf_node), &(data->buf_head)); mutex_unlock(&(data->buf_lock)); } static void add_dmabuf_map(struct dmabuf_info *data, struct dmabuf_map *plist) { mutex_lock(&(data->map_lock)); list_add(&(plist->map_node), &(data->map_head)); mutex_unlock(&(data->map_lock)); } /* * if @dmabuf = NULL, we need to find dmabuf_info by @id * if @dmabuf != NULL, we need to find dmabuf_info by @dmabuf */ static struct dmabuf_info *find_dmabuf_info(struct dmabuf_data *data, int id) { struct list_head *plist_tmp; struct dmabuf_info *obj_info; mutex_lock(&(data->buf_lock)); list_for_each(plist_tmp, &(data->buf_head)) { obj_info = container_of(plist_tmp, struct dmabuf_info, buf_node); if (obj_info->id == id) break; } if (plist_tmp == &(data->buf_head)) { pr_info("%s fail, heap:%s, buf_id:%d\n", __func__, dma_heap_get_name(data->heap), id); mutex_unlock(&(data->buf_lock)); return NULL; } mutex_unlock(&(data->buf_lock)); return obj_info; } static struct dmabuf_map *find_dmabuf_map(struct dmabuf_info *data, int attach_id) { struct list_head *map_tmp; struct dmabuf_map *map_obj; mutex_lock(&(data->map_lock)); list_for_each(map_tmp, &(data->map_head)) { map_obj = container_of(map_tmp, struct dmabuf_map, map_node); if (map_obj->id == attach_id) break; } if (map_tmp == &(data->map_head)) { pr_info("%s fail, attach_id:%d\n", __func__, attach_id); mutex_unlock(&(data->map_lock)); return NULL; } mutex_unlock(&(data->map_lock)); return map_obj; } static int check_dmabuf_id(struct dmabuf_data *data, int alloc_id) { struct list_head *plist_tmp; struct dmabuf_info *obj_info; mutex_lock(&(data->buf_lock)); list_for_each(plist_tmp, &(data->buf_head)) { obj_info = container_of(plist_tmp, struct dmabuf_info, buf_node); if (obj_info->id == alloc_id) break; } if (plist_tmp == &(data->buf_head)) { pr_info("%s success, alloc_id(%d) can be used\n", __func__, alloc_id); mutex_unlock(&(data->buf_lock)); return 0; } mutex_unlock(&(data->buf_lock)); pr_info("%s fail, alloc_id(%d) has aleady exist!! dmabuf:0x%lx, sz:0x%zx\n", __func__, alloc_id, obj_info->dmabuf, obj_info->size); return -EINVAL; } static int check_attach_id(struct dmabuf_info *data, int id) { struct list_head *plist_tmp; struct dmabuf_map *map_obj; mutex_lock(&(data->map_lock)); list_for_each(plist_tmp, &(data->map_head)) { map_obj = container_of(plist_tmp, struct dmabuf_map, map_node); if (map_obj->id == id) break; } if (plist_tmp == &(data->map_head)) { pr_info("%s success, attach_id(%d) can be used\n", __func__, id); mutex_unlock(&(data->map_lock)); return 0; } mutex_unlock(&(data->map_lock)); pr_info("%s fail, attach_id(%d) has aleady exist\n", __func__, id); return -EINVAL; } static void del_dmabuf_info(struct dmabuf_info *info_obj) { list_del(&info_obj->buf_node); kfree(info_obj); } static void del_dmabuf_map(struct dmabuf_map *map_obj) { list_del(&map_obj->map_node); kfree(map_obj); } static void dump_dmabuf_info_map(enum DMABUF_HEAP heap) { struct list_head *info_tmp, *map_tmp; struct dmabuf_info *info_obj; struct dmabuf_map *map_obj; struct dmabuf_data *data = &dmabuf_data_obj[heap]; mutex_lock(&(data->buf_lock)); list_for_each(info_tmp, &(data->buf_head)) { info_obj = container_of(info_tmp, struct dmabuf_info, buf_node); pr_info("%s 1, info_obj:0x%lx, buf_id:%d, dmabuf:0x%lx, sz:0x%zx, heap:%s\n", __func__, (unsigned long)info_obj, info_obj->id, (unsigned long)info_obj->dmabuf, info_obj->size, heap_obj[heap].name); mutex_lock(&(info_obj->map_lock)); list_for_each(map_tmp, &(info_obj->map_head)) { map_obj = container_of(map_tmp, struct dmabuf_map, map_node); pr_info("%s 2, map_obj:0x%lx, attach_id:%d, attach:0x%lx, iova:%pa\n", __func__, (unsigned long)map_obj, map_obj->id, (unsigned long)map_obj->attach, &map_obj->dma_address); } mutex_unlock(&(info_obj->map_lock)); } mutex_unlock(&(data->buf_lock)); } static void dmabuf_heap_alloc_test(size_t size, enum DMABUF_HEAP heap, int buf_id) { int ret; struct dmabuf_data *data_obj; struct dmabuf_info *info_obj; pr_info("%s start, heap:%s(%d)\n", __func__, heap_obj[heap].name, heap); ret = check_dmabuf_id(&dmabuf_data_obj[heap], buf_id); if (ret) { pr_info("%s failed, buf_id can not be used:%d\n", __func__, buf_id); return; } switch (heap) { case TEST_MTK_NORMAL: data_obj = &dmabuf_data_obj[TEST_MTK_NORMAL]; data_obj->heap = dma_heap_find("mtk_mm"); if (!data_obj->heap) { pr_info("%s, find mtk_mm failed!!\n", __func__); return; } break; case TEST_REQ_SVP_REGION: case TEST_REQ_SVP_REGION_UP_ERR: case TEST_REQ_SVP_REGION_VDEC_ERR: case TEST_REQ_SVP_REGION_PA: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_svp_region"); if (!data_obj->heap) { pr_info("%s, find mtk_svp_regio failed!!\n", __func__); return; } break; case TEST_REQ_SVP_REGION_ALIGN_UP: case TEST_REQ_SVP_REGION_ALIGN_VDEC: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_svp_region-aligned"); if (!data_obj->heap) { pr_info("%s, find mtk_svp_region-aligned failed!!\n", __func__); return; } break; case TEST_REQ_PROT_REGION: case TEST_REQ_PROT_REGION_PA: case TEST_REQ_PROT_REGION_CCU0_ERR: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_prot_region"); if (!data_obj->heap) { pr_info("%s, find mtk_prot_region failed!!\n", __func__); return; } break; case TEST_REQ_PROT_REGION_ALIGN_CCU0: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_prot_region-aligned"); if (!data_obj->heap) { pr_info("%s, find mtk_prot_region-aligned failed!!\n", __func__); return; } break; case TEST_REQ_SVP_PAGE: case TEST_REQ_SVP_PAGE_UP: case TEST_REQ_SVP_PAGE_VDEC: case TEST_REQ_SVP_PAGE_PA: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_svp_page-uncached"); if (!data_obj->heap) { pr_info("%s, find mtk_svp_page-uncached failed!!\n", __func__); return; } break; case TEST_REQ_PROT_PAGE: case TEST_REQ_PROT_PAGE_CCU0: case TEST_REQ_PROT_PAGE_PA: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_prot_page-uncached"); if (!data_obj->heap) { pr_info("%s, find mtk_svp_page-uncached failed!!\n", __func__); return; } break; case TEST_PROT_2D_FR_REGION: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_2d_fr_region"); if (!data_obj->heap) { pr_info("%s, find mtk_2d_fr_region failed!!\n", __func__); return; } break; case TEST_PROT_2D_FR_REGION_ALIGN: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_2d_fr_region-aligned"); if (!data_obj->heap) { pr_info("%s, find mtk_2d_fr_region-aligned failed!!\n", __func__); return; } break; case TEST_SAPU_DATA_SHM_REGION: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_sapu_data_shm_region"); if (!data_obj->heap) { pr_info("%s, find mtk_sapu_data_shm_region failed!!\n", __func__); return; } break; case TEST_SAPU_DATA_SHM_REGION_ALIGN: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_sapu_data_shm_region-aligned"); if (!data_obj->heap) { pr_info("%s, find mtk_sapu_data_shm_region-aligned failed!!\n", __func__); return; }; case TEST_SAPU_ENGINE_SHM_REGION: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_sapu_engine_shm_region"); if (!data_obj->heap) { pr_info("%s, find mtk_sapu_engine_shm_region failed!!\n", __func__); return; } break; case TEST_SAPU_ENGINE_SHM_REGION_ALIGN: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_sapu_engine_shm_region-aligned"); if (!data_obj->heap) { pr_info("%s, find mtk_sapu_engine_shm_region-aligned failed!!\n", __func__); return; } break; case TEST_WFD_REGION: case TEST_WFD_REGION_PA: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_wfd_region"); if (!data_obj->heap) { pr_info("%s, find mtk_wfd_region failed!!\n", __func__); return; } break; case TEST_WFD_REGION_ALIGN_UP: case TEST_WFD_REGION_ALIGN_VDEC: data_obj = &dmabuf_data_obj[heap]; data_obj->heap = dma_heap_find("mtk_wfd_region-aligned"); if (!data_obj->heap) { pr_info("%s, find mtk_wfd_region-aligned failed!!\n", __func__); return; } break; default: pr_info("%s failed, heap type in invalid:%s(%d)\n", __func__, heap_obj[heap].name, heap); return; } pr_info("%s dma_heap_find done, heap:%s\n", __func__, dma_heap_get_name(data_obj->heap)); info_obj = dmabuf_info_alloc(buf_id); if (!info_obj) { pr_info("%s dmabuf_info_alloc fail, heap:%s(%d)\n", __func__, heap_obj[heap].name, heap); return; } info_obj->dmabuf = dma_heap_buffer_alloc(data_obj->heap, size, DMA_HEAP_VALID_FD_FLAGS, DMA_HEAP_VALID_HEAP_FLAGS); if (IS_ERR(info_obj->dmabuf)) { pr_info("%s, alloc buffer fail, heap:%s(%d)\n", __func__, heap_obj[heap].name, heap); return; } info_obj->size = size; add_dmabuf_info(data_obj, info_obj); pr_info("%s success, heap:%s(%d), dmabuf_info:0x%lx, dmabuf:0x%lx, sz:0x%zx, buf_id:%d\n", __func__, heap_obj[heap].name, heap, (unsigned long)info_obj, (unsigned long)info_obj->dmabuf, size, buf_id); } static void dmabuf_heap_free_test(enum DMABUF_HEAP heap, int buf_id) { struct dmabuf_info *info_obj; info_obj = find_dmabuf_info(&dmabuf_data_obj[heap], buf_id); if (!info_obj) { pr_info("%s find dmabuf_info fail, heap:%s\n", __func__, dma_heap_get_name(dmabuf_data_obj[heap].heap)); return; } pr_info("%s success, heap:%s(%d), dmabuf_info:0x%lx, dmabuf:0x%lx, buf_id:%d\n", __func__, heap_obj[heap].name, heap, (unsigned long)info_obj, (unsigned long)info_obj->dmabuf, buf_id); dma_heap_buffer_free(info_obj->dmabuf); del_dmabuf_info(info_obj); } static void dmabuf_map_iova(enum DMABUF_HEAP heap, int buf_id, int attach_id) { int ret; struct dmabuf_map *map_obj; struct dmabuf_info *info_obj; struct device *dev = dmabuf_data_obj[heap].dev; struct dma_buf_attachment *attach; struct sg_table *table; #ifdef SECURE_HANDLE_TEST u32 sec_handle; #endif pr_info("%s start, heap:%s(%d), dev:%s\n", __func__, heap_obj[heap].name, heap, dev_name(dev)); /* find dmabuf_info by attach buf_id from dmabuf_data */ info_obj = find_dmabuf_info(&dmabuf_data_obj[heap], buf_id); if (!info_obj) { pr_info("%s find dmabuf_info fail, heap:%s\n", __func__, dma_heap_get_name(dmabuf_data_obj[heap].heap)); return; } #ifdef SECURE_HANDLE_TEST /* get secure handle */ sec_handle = dmabuf_to_secure_handle(info_obj->dmabuf); if (!sec_handle) pr_info("%s get secure handle failed, heap:%s\n", __func__, heap_obj[heap].name); else pr_info("%s get secure handle(%u) success, heap:%s\n", __func__, sec_handle, heap_obj[heap].name); #endif ret = check_attach_id(info_obj, attach_id); if (ret) { pr_info("%s failed, attach_id can not be used:%d\n", __func__, attach_id); return; } map_obj = dmabuf_map_alloc(attach_id); if (!map_obj) { pr_info("%s dmabuf_map_alloc fail, heap:%s\n", __func__, dma_heap_get_name(dmabuf_data_obj[heap].heap)); return; } attach = dma_buf_attach(info_obj->dmabuf, dev); if (IS_ERR(attach)) { pr_info("%s, dma_buf_attach failed!!, heap:%s(%d)\n", __func__, heap_obj[heap].name, heap); return; } table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR(table)) { pr_info("%s, dma_buf_map_attachment failed!!, heap:%s\n", __func__, heap_obj[heap].name); return; } map_obj->attach = attach; map_obj->table = table; map_obj->dma_address = sg_dma_address(table->sgl); add_dmabuf_map(info_obj, map_obj); pr_info("%s success, heap:%s(%d), dmabuf:0x%lx, map_obj:0x%lx, buf_id:%d, att_id:%d, attach:0x%lx, iova:%pa\n", __func__, heap_obj[heap].name, heap, (unsigned long)info_obj->dmabuf, (unsigned long)map_obj, buf_id, attach_id, (unsigned long)map_obj->attach, &map_obj->dma_address); } static void dmabuf_unmap_iova(enum DMABUF_HEAP heap, int buf_id, int attach_id) { struct dmabuf_info *info_obj; struct dmabuf_map *map_obj; /* find dmabuf_info by buf_id from dmabuf_data */ info_obj = find_dmabuf_info(&dmabuf_data_obj[heap], buf_id); if (!info_obj) { pr_info("%s find dmabuf_info fail, heap:%s\n", __func__, dma_heap_get_name(dmabuf_data_obj[heap].heap)); return; } map_obj = find_dmabuf_map(info_obj, attach_id); if (!map_obj) { pr_info("%s find dmabuf_map fail, heap:%s\n", __func__, dma_heap_get_name(dmabuf_data_obj[heap].heap)); return; } pr_info("%s success, heap:%s(%d), dmabuf:0x%lx, map_obj:0x%lx, buf_id:%d, att_id:%d, attach:0x%lx, iova:%pa\n", __func__, heap_obj[heap].name, heap, (unsigned long)info_obj->dmabuf, (unsigned long)map_obj, buf_id, attach_id, (unsigned long)map_obj->attach, &map_obj->dma_address); dma_buf_unmap_attachment(map_obj->attach, map_obj->table, DMA_BIDIRECTIONAL); dma_buf_detach(info_obj->dmabuf, map_obj->attach); del_dmabuf_map(map_obj); } enum CMD_INDEX { SET_SIZE_CMD = 0, SET_HEAP_ID_CMD = 1, SET_DMABUF_ID_CMD = 2, SET_ATTACH_ID_CMD = 3, ALLOC_BUF_CMD = 10, MAP_CMD = 11, UNMAP_CMD = 12, FREE_BUF_CMD = 13, DUMP_INFO_CMD = 14, }; struct cmd_name { enum CMD_INDEX index; char *name; }; static struct cmd_name test_cmd_name[] = { [SET_SIZE_CMD] = { .index = SET_SIZE_CMD, .name = "Set buffer size", }, [SET_HEAP_ID_CMD] = { .index = SET_HEAP_ID_CMD, .name = "Set heap type", }, [SET_DMABUF_ID_CMD] = { .index = SET_DMABUF_ID_CMD, .name = "Set dmabuf id", }, [SET_ATTACH_ID_CMD] = { .index = SET_ATTACH_ID_CMD, .name = "Set attach id", }, [ALLOC_BUF_CMD] = { .index = ALLOC_BUF_CMD, .name = "Allocate buffer test", }, [MAP_CMD] = { .index = MAP_CMD, .name = "Map buffer test", }, [UNMAP_CMD] = { .index = UNMAP_CMD, .name = "Unmap buffer test", }, [FREE_BUF_CMD] = { .index = FREE_BUF_CMD, .name = "Free buffer test", }, [DUMP_INFO_CMD] = { .index = DUMP_INFO_CMD, .name = "Dump buffer_info_map test", }, }; /* * iommu test file: /proc/iommu_test/test * * dmabuf secure heap test: * UT-1: map heap_iova && buffer iova test --> pass * step-1. alloc buffer by dmabuf_id = 0 * ---> * step-2. map dmabuf_id = 0 to iova by attach_id=0,1,2 * step-3. check mapping result: * 1.heap region PA && size by alloc in step-1 * 2.heap_region and dmabuf are all mapped in step-2 * 3.heap_iova must be mappped by 1st level, not 2nd level * 4.all dmabuf only mapping one iova not more than one * * UT-2: alloc && map more than more buffer by normal region --> pass * step-1. alloc buffer by dmabuf_id = 0 * step-2. map dmabuf_id = 0 to iova by attach_id=0 * step-3. alloc buffer by dmabuf_id = 1 * ---> check: no need to alloc heap region PA && size(only need it in step1) * step-4. map dmabuf_id = 1 to iova by attach_id=1 * ---> check: no need to run dma_map_sgtable and get iova by PA offset * step-5. alloc buffer by dmabuf_id = 2 * ---> check: no need to alloc heap region PA && size(only need it in step1) * step-6. map dmabuf_id = 2 to iova by attach_id=2 * ---> check: no need to run dma_map_sgtable and get iova by PA offset * step7. free dmabuf_id = 2,1,0 * ---> check: only after last dmabuf free, heap_region iova will free * * UT-3: non-normal iova region test --> pass * step-1. use prot_region_heap0(normal region) to alloc one buffer by dmabuf_id = 0 * step-2. map dmabuf_id = 0 to iova by attach_id=0 and use prot_region_heap0 * step-3. use prot_region_heap1(non-normal region) to alloc one buffer by dmabuf_id = 0 * step-4. use prot_region_heap1 to map dmabuf_id = 0 to iova by attach_id=0 * ---> check: special region mapping must be run dma_map_sgtable * step-5. use prot_region_heap1 to free dmabuf_id = 0 * ---> check: special region unmap must be run dma_unmap_sgtable * * * UT-4: non-normal iova region 1MB align check --> pass * step-1. set test_size not 1MB align(0x3100) * step-2. use prot_region_heap0(normal region) to alloc one buffer by dmabuf_id = 0 * step-3. use prot_region_heap0 to map dmabuf_id = 0 to iova by attach_id = 0 * ---> check: size be aligned to 0x4000 and map success * step-4. use prot_region_heap1(special region) to alloc one buffer by dmabuf_id = 0 * step-5. use prot_region_heap1 to map dmabuf_id = 0 to iova by attach_id = 0 * ---> check: map fail because of not 1MB align * * * UT-5: non-iommu-dev test --> pass * step-1. use prot_region_heap1(non-iommu dev) alloc buffer by dmabuf_id = 0 * step-2. map dmabuf_id = 0 by attach_id=0 * ---> check: run non-iommu mapping pass * step-3. unmap dmabuf_id by attach_id=0 * ---> check: run non-iommu unmap pass * * * UT-6: 1MB alignment test --> pass * step-1. use prot_region_heap0(normal region) alloc 6KB by dmabuf_id = 0,1 * ---> check: 6K align to 8k, PA may be 1MB align * step-2. use prot_region_heap0 map dmabuf_id = 0,1 by attach_id=0,1 * ----> check: heap_region is mapped, and can return buffer iova * step-3. use prot_region_heap1(special region) alloc 6KB by dmabuf_id = 0, 1 * ----> check: 6K align to 1MB, and check PA is 1MB alignemnt * step-4. use prot_region_heap1 map dmabuf_id = 0, 1 by attach_id= 0, 1 * ----> check: special region mapping must be run dma_map_sgtable and success * step-5. use prot_region_heap0(normal region) alloc 6KB by dmabuf_id = 2 again * ---> check: 6K align to 8k * step-6. use prot_region_heap0 map dmabuf_id = 2 by attach_id= 2 * ----> check: can return buffer iova, and PA is after step3 * step-7. use prot_region_heap0 free/unmap dmabuf_id/attach_id = 0,1,2 * ----> check: heap_region shouldn't be unmapped * step-8. use prot_region_heap1 free/unmap dmabuf_id/attach_id = 0 * ----> check: heap_region should be unmapped * step-9. repeat step-1 ~ 8 */ static int iommu_test_debug_set(void *data, u64 input) { u64 index = (input & 0xff); u64 val = (input >> 8); pr_info("%s [%s], start, input:0x%llx, index=%llu, val:%llu\n", __func__, test_cmd_name[index].name, input, index, val); switch (index) { case 0: /* adb shell "echo 0xXXXXX00 > /proc/iommu_test/test" */ test_size = val; break; case 1: /* * mm_heap: adb shell "echo 0xd01 > /proc/iommu_test/test" * prot_region: adb shell "echo 0x101 > /proc/iommu_test/test" */ test_heap = (enum DMABUF_HEAP)val; break; case 2: /* * dmabuf_id=1: adb shell "echo 0x102 > /proc/iommu_test/test" * dmabuf_id=2: adb shell "echo 0x202 > /proc/iommu_test/test" * dmabuf_id=3: adb shell "echo 0x302 > /proc/iommu_test/test" */ dmabuf_id = val; break; case 3: /* * attach_id=1: adb shell "echo 0x103 > /proc/iommu_test/test" * attach_id=2: adb shell "echo 0x203 > /proc/iommu_test/test" * attach_id=3: adb shell "echo 0x303 > /proc/iommu_test/test" */ attach_id = val; break; case 10: /* adb shell "echo 0xa > /proc/iommu_test/test" */ dmabuf_heap_alloc_test(test_size, test_heap, dmabuf_id); break; case 11: /* adb shell "echo 0xb > /proc/iommu_test/test" */ dmabuf_map_iova(test_heap, dmabuf_id, attach_id); break; case 12: /* adb shell "echo 0xc > /proc/iommu_test/test" */ dmabuf_unmap_iova(test_heap, dmabuf_id, attach_id); break; case 13: /* adb shell "echo 0xd > /proc/iommu_test/test" */ dmabuf_heap_free_test(test_heap, dmabuf_id); break; case 14: /* adb shell "echo 0xe > /proc/iommu_test/test" */ dump_dmabuf_info_map(test_heap); break; default: pr_info("%s error,index=%llu\n", __func__, index); } pr_info("%s [%s] done\n", __func__, test_cmd_name[index].name); return 0; } static int iommu_test_debug_get(void *data, u64 *val) { *val = 0; return 0; } DEFINE_PROC_ATTRIBUTE(iommu_test_debug_fops, iommu_test_debug_get, iommu_test_debug_set, "%llu\n"); static int iommu_test_debug_init(struct iommu_test_debug_data *data) { struct proc_dir_entry *debug_file; data->debug_root = proc_mkdir("iommu_test", NULL); if (IS_ERR_OR_NULL(data->debug_root)) pr_info("failed to create debug dir.\n"); debug_file = proc_create_data("test", S_IFREG | 0644, data->debug_root, &iommu_test_debug_fops, NULL); if (IS_ERR_OR_NULL(debug_file)) pr_info("failed to create debug files 2.\n"); return 0; } /******************************************************************************/ static int dmaheap_normal_test_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dmabuf_data_obj[TEST_MTK_NORMAL].dev = dev; mutex_init(&dmabuf_data_obj[TEST_MTK_NORMAL].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_MTK_NORMAL].buf_head); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } static int dmaheap_sec_normal_region_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dmabuf_data_obj[TEST_REQ_SVP_REGION].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_REGION].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_REGION].buf_head); dmabuf_data_obj[TEST_REQ_PROT_REGION].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_REGION].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_REGION].buf_head); dmabuf_data_obj[TEST_REQ_SVP_PAGE].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_PAGE].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_PAGE].buf_head); dmabuf_data_obj[TEST_REQ_PROT_PAGE].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_PAGE].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_PAGE].buf_head); dmabuf_data_obj[TEST_WFD_REGION].dev = dev; mutex_init(&dmabuf_data_obj[TEST_WFD_REGION].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_WFD_REGION].buf_head); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } static int dmaheap_sec_ccu0_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dmabuf_data_obj[TEST_REQ_PROT_REGION_ALIGN_CCU0].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_REGION_ALIGN_CCU0].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_REGION_ALIGN_CCU0].buf_head); dmabuf_data_obj[TEST_REQ_PROT_PAGE_CCU0].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_PAGE_CCU0].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_PAGE_CCU0].buf_head); dmabuf_data_obj[TEST_REQ_PROT_REGION_CCU0_ERR].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_REGION_CCU0_ERR].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_REGION_CCU0_ERR].buf_head); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } static int dmaheap_sec_video_up_probe(struct platform_device *pdev) { /* include region && page dev */ struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dmabuf_data_obj[TEST_REQ_SVP_REGION_ALIGN_UP].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_REGION_ALIGN_UP].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_REGION_ALIGN_UP].buf_head); dmabuf_data_obj[TEST_WFD_REGION_ALIGN_UP].dev = dev; mutex_init(&dmabuf_data_obj[TEST_WFD_REGION_ALIGN_UP].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_WFD_REGION_ALIGN_UP].buf_head); dmabuf_data_obj[TEST_REQ_SVP_PAGE_UP].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_PAGE_UP].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_PAGE_UP].buf_head); dmabuf_data_obj[TEST_REQ_SVP_REGION_UP_ERR].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_REGION_UP_ERR].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_REGION_UP_ERR].buf_head); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } static int dmaheap_sec_vdec_probe(struct platform_device *pdev) { /* include region && page dev */ struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dmabuf_data_obj[TEST_REQ_SVP_REGION_ALIGN_VDEC].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_REGION_ALIGN_VDEC].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_REGION_ALIGN_VDEC].buf_head); dmabuf_data_obj[TEST_REQ_SVP_PAGE_VDEC].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_PAGE_VDEC].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_PAGE_VDEC].buf_head); dmabuf_data_obj[TEST_REQ_SVP_REGION_VDEC_ERR].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_REGION_VDEC_ERR].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_REGION_VDEC_ERR].buf_head); dmabuf_data_obj[TEST_WFD_REGION_ALIGN_VDEC].dev = dev; mutex_init(&dmabuf_data_obj[TEST_WFD_REGION_ALIGN_VDEC].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_WFD_REGION_ALIGN_VDEC].buf_head); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } static int dmaheap_sec_pa_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dmabuf_data_obj[TEST_REQ_SVP_REGION_PA].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_REGION_PA].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_REGION_PA].buf_head); dmabuf_data_obj[TEST_REQ_PROT_REGION_PA].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_REGION_PA].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_REGION_PA].buf_head); dmabuf_data_obj[TEST_REQ_SVP_PAGE_PA].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_SVP_PAGE_PA].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_SVP_PAGE_PA].buf_head); dmabuf_data_obj[TEST_REQ_PROT_PAGE_PA].dev = dev; mutex_init(&dmabuf_data_obj[TEST_REQ_PROT_PAGE_PA].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_REQ_PROT_PAGE_PA].buf_head); dmabuf_data_obj[TEST_WFD_REGION_PA].dev = dev; mutex_init(&dmabuf_data_obj[TEST_WFD_REGION_PA].buf_lock); INIT_LIST_HEAD(&dmabuf_data_obj[TEST_WFD_REGION_PA].buf_head); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } /******************************************************************************/ static const size_t IOVA_SIZES[] = { (SZ_1K), (SZ_4K), (SZ_1K * 10), (SZ_1K * 40), (SZ_64K), (SZ_512K), (PAGE_SIZE), (SZ_1M), (SZ_1M + PAGE_SIZE), (SZ_2M + PAGE_SIZE * 2), (SZ_1M * 6 + PAGE_SIZE * 3), (SZ_16M), (SZ_16M + SZ_4K), (SZ_16M + SZ_1M), (SZ_16M + SZ_1M + PAGE_SIZE), (SZ_32M + SZ_1M), (SZ_64M + SZ_4K), (SZ_128M + SZ_1M * 3), (SZ_256M + SZ_4K), (SZ_512M + SZ_4K) }; static int iommu_test(struct platform_device *pdev) { #define TEST_NUM 20 int i; void *cpu_addr[TEST_NUM]; dma_addr_t dma_addr[TEST_NUM]; pr_info("%s start, dev:%s\n", __func__, dev_name(&pdev->dev)); dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); for (i = 0; i < TEST_NUM; i++) { cpu_addr[i] = dma_alloc_attrs(&pdev->dev, IOVA_SIZES[i], &dma_addr[i], GFP_KERNEL, DMA_ATTR_WRITE_COMBINE); if (!cpu_addr[i] || !dma_addr[i]) { pr_info("dev:%s:%d, alloc iova fail, size:0x%zx\n", dev_name(&pdev->dev), i, IOVA_SIZES[i]); return -EINVAL; } pr_info("dev:%s:%d, alloc iova success, iova:%pa, size:0x%zx\n", dev_name(&pdev->dev), i, &dma_addr[i], IOVA_SIZES[i]); } for (i = 0; i < TEST_NUM; i++) { dma_free_attrs(&pdev->dev, IOVA_SIZES[i], cpu_addr[i], dma_addr[i], DMA_ATTR_WRITE_COMBINE); pr_info("dev:%s:%d, free iova success, iova:%pa, size:0x%zx\n", dev_name(&pdev->dev), i, &dma_addr[i], IOVA_SIZES[i]); } pr_info("%s done, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } static int dmabuf_test(struct platform_device *pdev) { size_t size = SZ_1M; struct dma_heap *heap; struct dma_buf *dmabuf; struct dma_buf_attachment *attach; struct sg_table *table; struct device *dev = &pdev->dev; pr_info("%s start, dev:%s\n", __func__, dev_name(dev)); heap = dma_heap_find("mtk_mm"); if (!heap) { pr_info("%s, find mtk_mm failed!!\n", __func__); return -EINVAL; } dmabuf = dma_heap_buffer_alloc(heap, size, DMA_HEAP_VALID_FD_FLAGS, DMA_HEAP_VALID_HEAP_FLAGS); if (IS_ERR(dmabuf)) { pr_info("%s, alloc buffer fail, heap:%s\n", __func__, dma_heap_get_name(heap)); return -EINVAL; } pr_info("%s alloc dma-buf success, size:0x%zx, heap:%s\n", __func__, size, dma_heap_get_name(heap)); attach = dma_buf_attach(dmabuf, dev); if (IS_ERR(attach)) { pr_info("%s, dma_buf_attach failed!!, heap:%s\n", __func__, dma_heap_get_name(heap)); return -EINVAL; } table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR(attach)) { pr_info("%s, dma_buf_map_attachment failed!!, heap:%s\n", __func__, dma_heap_get_name(heap)); return -EINVAL; } pr_info("%s map dma-buf success, size:0x%zx, heap:%s, iova:0x%lx\n", __func__, size, dma_heap_get_name(heap), (unsigned long)sg_dma_address(table->sgl)); dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL); dma_buf_detach(dmabuf, attach); dma_heap_buffer_free(dmabuf); pr_info("%s done, dev:%s\n", __func__, dev_name(dev)); return 0; } static int iommu_test_dom_probe(struct platform_device *pdev) { int ret; ret = iommu_test(pdev); if (ret) pr_info("%s failed, iommu_test fail, dev:%s\n", __func__, dev_name(&pdev->dev)); ret = dmabuf_test(pdev); if (ret) pr_info("%s failed, dmabuf_test fail, dev:%s\n", __func__, dev_name(&pdev->dev)); return 0; } /*************************************************************************/ /* * iommu test DTS sample node: * iommu_mm_test0 { * compatible = "mediatek,iommu-test-dom0"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&disp_iommu M4U_PORT_L0_DISP_FAKE0>; *}; * * iommu_mm_test1 { * compatible = "mediatek,iommu-test-dom1"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&mdp_iommu M4U_PORT_L4_HW_VDEC_VLD_EXT>; * }; * * iommu_mm_test2 { * compatible = "mediatek,iommu-test-dom0"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&disp_iommu M4U_PORT_L35_RESERVED_0>; * }; * * iommu_mm_test3 { * compatible = "mediatek,iommu-test-dom3"; * dma-ranges = <0x1 0x0 0x1 0x0 0x1 0x0>; * iommus = <&mdp_iommu M4U_PORT_L38_CCU0>; * }; * * iommu_mm_test4 { * compatible = "mediatek,iommu-test-dom4"; * dma-ranges = <0x1 0x0 0x1 0x0 0x1 0x0>; * iommus = <&mdp_iommu M4U_PORT_L38_CCU1>; * }; * * iommu_mm_test5 { * compatible = "mediatek,iommu-test-dom5"; * dma-ranges = <0x1 0x0 0x1 0x0 0x1 0x0>; * iommus = <&mdp_iommu M4U_PORT_L40_VIDEO_UP_512MB1>; * }; * * iommu_mm_test6 { * compatible = "mediatek,iommu-test-dom6"; * dma-ranges = <0x1 0x0 0x1 0x0 0x1 0x0>; * iommus = <&mdp_iommu M4U_PORT_L40_VIDEO_UP_512MB2>; * }; * * iommu_mm_test7 { * compatible = "mediatek,iommu-test-dom7"; * dma-ranges = <0x1 0x0 0x1 0x0 0x1 0x0>; * iommus = <&mdp_iommu M4U_PORT_L40_VIDEO_UP_256MB1>; * }; * * iommu_mm_test8 { * compatible = "mediatek,iommu-test-dom8"; * dma-ranges = <0x1 0x0 0x1 0x0 0x1 0x0>; * iommus = <&mdp_iommu M4U_PORT_L40_VIDEO_UP_256MB2>; * }; * * iommu_apu_test0 { * compatible = "mediatek,iommu-test-dom0"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&apu_iommu0 M4U_PORT_L41_APU_DATA>; * }; * * iommu_apu_test1 { * compatible = "mediatek,iommu-test-dom0"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&apu_iommu1 M4U_PORT_L41_APU_DATA>; * }; * * iommu_apu_test2 { * compatible = "mediatek,iommu-test-dom1"; * dma-ranges = <0x0 0x0 0x0 0x0 0x1 0x0>; * iommus = <&apu_iommu0 M4U_PORT_L41_APU_SECURE>; * }; * * iommu_apu_test3 { * compatible = "mediatek,iommu-test-dom2"; * dma-ranges = <0x0 0x0 0x0 0x0 0x1 0x0>; * iommus = <&apu_iommu0 M4U_PORT_L41_APU_CODE>; * }; * * iommu_test_dmaheap_normal { * compatible = "mediatek,dmaheap-normal"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&disp_iommu M4U_PORT_L0_DISP_FAKE0>; * }; * * iommu_test_dmaheap_normal_region { * compatible = "mediatek,dmaheap-sec-normal-region"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&mdp_iommu M4U_PORT_L0_DISP_FAKE0>; * }; * * iommu_test_dmaheap_ccu0 { * compatible = "mediatek,dmaheap-sec-ccu0"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&disp_iommu M4U_PORT_L38_CCU0>; * }; * * iommu_test_dmaheap_up { * compatible = "mediatek,dmaheap-sec-up"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&disp_iommu M4U_PORT_L40_VIDEO_UP_512MB1>; * }; * * iommu_test_dmaheap_vdec { * compatible = "mediatek,dmaheap-sec-vdec"; * dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; * iommus = <&disp_iommu M4U_PORT_L4_HW_VDEC_VLD_EXT>; * }; * * iommu_test_dmaheap_pa { * compatible = "mediatek,dmaheap-sec-pa"; * }; */ /*************************************************************************/ static const struct of_device_id iommu_test_dom_match_table[] = { {.compatible = "mediatek,iommu-test-dom0"}, {.compatible = "mediatek,iommu-test-dom1"}, {.compatible = "mediatek,iommu-test-dom2"}, {.compatible = "mediatek,iommu-test-dom3"}, {.compatible = "mediatek,iommu-test-dom4"}, {.compatible = "mediatek,iommu-test-dom5"}, {.compatible = "mediatek,iommu-test-dom6"}, {.compatible = "mediatek,iommu-test-dom7"}, {.compatible = "mediatek,iommu-test-dom8"}, {.compatible = "mediatek,iommu-test-dom9"}, {}, }; /*************************************************************************/ static const struct of_device_id dmaheap_normal_match_table[] = { {.compatible = "mediatek,dmaheap-normal"}, {}, }; static const struct of_device_id dmaheap_sec_normal_region_match_table[] = { {.compatible = "mediatek,dmaheap-sec-normal-region"}, {}, }; static const struct of_device_id dmaheap_sec_ccu0_match_table[] = { {.compatible = "mediatek,dmaheap-sec-ccu0"}, {}, }; static const struct of_device_id dmaheap_sec_up_match_table[] = { {.compatible = "mediatek,dmaheap-sec-up"}, {}, }; static const struct of_device_id dmaheap_sec_vdec_match_table[] = { {.compatible = "mediatek,dmaheap-sec-vdec"}, {}, }; static const struct of_device_id dmaheap_sec_pa_match_table[] = { {.compatible = "mediatek,dmaheap-sec-pa"}, {}, }; static struct platform_driver iommu_test_dmaheap_normal = { .probe = dmaheap_normal_test_probe, .driver = { .name = "dmaheap-normal", .of_match_table = dmaheap_normal_match_table, }, }; static struct platform_driver iommu_test_dmaheap_sec_normal = { .probe = dmaheap_sec_normal_region_probe, .driver = { .name = "dmaheap-secure-normal-region", .of_match_table = dmaheap_sec_normal_region_match_table, }, }; static struct platform_driver iommu_test_dmaheap_sec_ccu0 = { .probe = dmaheap_sec_ccu0_probe, .driver = { .name = "dmaheap-secure-ccu0", .of_match_table = dmaheap_sec_ccu0_match_table, }, }; static struct platform_driver iommu_test_dmaheap_sec_up = { .probe = dmaheap_sec_video_up_probe, .driver = { .name = "dmaheap-secure-up", .of_match_table = dmaheap_sec_up_match_table, }, }; static struct platform_driver iommu_test_dmaheap_sec_vdec = { .probe = dmaheap_sec_vdec_probe, .driver = { .name = "dmaheap-secure-vdec", .of_match_table = dmaheap_sec_vdec_match_table, }, }; static struct platform_driver iommu_test_dmaheap_sec_pa = { .probe = dmaheap_sec_pa_probe, .driver = { .name = "dmaheap-secure-pa", .of_match_table = dmaheap_sec_pa_match_table, }, }; /*************************************************************************/ /* iova region test */ static struct platform_driver iommu_test_driver_dom = { .probe = iommu_test_dom_probe, .driver = { .name = "iommu-test-dom", .of_match_table = iommu_test_dom_match_table, }, }; static struct platform_driver *const iommu_test_drivers[] = { &iommu_test_driver_dom, &iommu_test_dmaheap_normal, &iommu_test_dmaheap_sec_normal, &iommu_test_dmaheap_sec_ccu0, &iommu_test_dmaheap_sec_up, &iommu_test_dmaheap_sec_vdec, &iommu_test_dmaheap_sec_pa, }; static int __init iommu_test_init(void) { int ret; int i; pr_info("%s+\n", __func__); debug_data = kmalloc(sizeof(struct iommu_test_debug_data), GFP_KERNEL); if (!debug_data) return -ENOMEM; iommu_test_debug_init(debug_data); for (i = 0; i < ARRAY_SIZE(iommu_test_drivers); i++) { pr_info("%s, register %d\n", __func__, i); ret = platform_driver_register(iommu_test_drivers[i]); if (ret < 0) { pr_err("Failed to register %s driver: %d\n", iommu_test_drivers[i]->driver.name, ret); goto err; } } pr_info("%s-\n", __func__); return 0; err: while (--i >= 0) platform_driver_unregister(iommu_test_drivers[i]); return ret; } static void __exit iommu_test_exit(void) { int i; for (i = ARRAY_SIZE(iommu_test_drivers) - 1; i >= 0; i--) platform_driver_unregister(iommu_test_drivers[i]); } #else static int __init iommu_test_init(void) { return 0; } static void __exit iommu_test_exit(void) { } #endif module_init(iommu_test_init); module_exit(iommu_test_exit); MODULE_LICENSE("GPL v2");