先说下iommu几个名词
iommu_group:代表共享同一个streamid的一组device,也就是多个device可以在同个group
domain :代表一个具体的设备使用iommu的详细spec
Kernel has DMA mapping API fromorigin. ARM defines IOMMU which can be used to connect scattered physicalmemory as a continuous region for devices which needs continue address towork(e.g: DMA). So IOMMU implementations & CMA should work behind kernelDMA mapping API. E.g: dma_alloc_from_contiguous can be implemented by CMA;dma_alloc_coherent can be implemented by IOMMU or by the normal case(just call__get_free_pages). So for device drivers need dma buffers, we should use dmamapping APIs, not call iommu api directly
说明cma可以实现函数dma_alloc_from_contiguous,iommu可以实现dma_alloc_coherent
iommu是实现在dma mapping api下层的驱动,所以我们只需要使用dma mapping的相关api,不需要直接调用iommu接口。
IOMMU,Input-Output Memory Management Unit
网上有些关于使用iommu的好处。
但是我感觉最终要的是用于将物理上分散的内存页映射成 cif、isp可见的连续内存,如果没有iommu需要在kernel预留比较大的cma内存
在rk芯片,所有模块的iommu公用一个驱动
kernel\drivers\iommu\rockchip-iommu.c
kernel\drivers\iommu\rk-iommu.h
定义iommu的结构:
struct rk_iommu_domain {
struct list_head iommus;
struct platform_device *pdev;
u32 *dt; /* page directory table */
dma_addr_t dt_dma;
struct mutex iommus_lock; /* lock for iommus list */
struct mutex dt_lock; /* lock for modifying page directory table */
struct iommu_domain domain;
};
struct rk_iommu {
struct device *dev;
void __iomem **bases;
int num_mmu;
int *irq;
int num_irq;
bool reset_disabled; /* isp iommu reset operation would failed */
bool skip_read; /* rk3126/rk3128 can't read vop iommu registers */
struct list_head node; /* entry in rk_iommu_domain.iommus */
struct iommu_domain *domain; /* domain to which iommu is attached */
struct clk *aclk; /* aclock belong to master */
struct clk *hclk; /* hclock belong to master */
struct clk *sclk; /* sclock belong to master */
struct list_head dev_node;
};
在模块加载的时候调用
static int __init rk_iommu_init(void)
{
struct device_node *np;
int ret;
np = of_find_matching_node(NULL, rk_iommu_dt_ids);
if (!np)
return 0;
of_node_put(np);
//初始化iommu bus
ret = bus_set_iommu(&platform_bus_type, &rk_iommu_ops);
if (ret)
return ret;
ret = platform_driver_register(&rk_iommu_domain_driver);
if (ret)
return ret;
//注册两个驱动
ret = platform_driver_register(&rk_iommu_driver);
if (ret)
platform_driver_unregister(&rk_iommu_domain_driver);
return ret;
}
其中
bus_se