当在code中调用dma_mmap_coherent时,这是个宏
#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
在dma_mmap_attrs 中又会掉用get_dma_ops 来得到dma的ops
static inline int
dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
dma_addr_t dma_addr, size_t size, unsigned long attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!ops);
if (ops->mmap)
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
}
get_dma_ops 的实现如下:
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
if (xen_initial_domain())
return xen_dma_ops;
else
return __generic_dma_ops(dev);
}
在arm64中xen_initial_domain() 肯定是返回false的,因此继续看__generic_dma_ops
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
if (dev && dev->archdata.dma_ops)
return dev->archdata.dma_ops;
/*
* We expect no ISA devices, and all other DMA masters are expected to
* have someone call arch_setup_dma_ops at device creation time.
*/
return &dummy_dma_ops;
}
在dma_map_ops 中首先判断dev->archdata.dma_ops 是否为NULL,而dev->archdata.dma_ops是在do_iommu_attach 中赋值的,显然不为null。
static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
u64 dma_base, u64 size)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
/*
* If the IOMMU driver has the DMA domain support that we require,
* then the IOMMU core will have already configured a group for this
* device, and allocated the default domain for that group.
*/
if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
return false;
}
dev->archdata.dma_ops = &iommu_dma_ops;
return true;
}
注意do_iommu_attach 中返回的是iommu_dma_ops。因此当用户调用dma_mmap_coherent 来申请coherent memory时,在CONFIG_IOMMU_DMA 定义了的情况下就等于在操作iommu的ops.
#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
在dma_mmap_attrs 中又会掉用get_dma_ops 来得到dma的ops
static inline int
dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
dma_addr_t dma_addr, size_t size, unsigned long attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
BUG_ON(!ops);
if (ops->mmap)
return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
}
get_dma_ops 的实现如下:
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
if (xen_initial_domain())
return xen_dma_ops;
else
return __generic_dma_ops(dev);
}
在arm64中xen_initial_domain() 肯定是返回false的,因此继续看__generic_dma_ops
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
if (dev && dev->archdata.dma_ops)
return dev->archdata.dma_ops;
/*
* We expect no ISA devices, and all other DMA masters are expected to
* have someone call arch_setup_dma_ops at device creation time.
*/
return &dummy_dma_ops;
}
在dma_map_ops 中首先判断dev->archdata.dma_ops 是否为NULL,而dev->archdata.dma_ops是在do_iommu_attach 中赋值的,显然不为null。
static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
u64 dma_base, u64 size)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
/*
* If the IOMMU driver has the DMA domain support that we require,
* then the IOMMU core will have already configured a group for this
* device, and allocated the default domain for that group.
*/
if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
return false;
}
dev->archdata.dma_ops = &iommu_dma_ops;
return true;
}
注意do_iommu_attach 中返回的是iommu_dma_ops。因此当用户调用dma_mmap_coherent 来申请coherent memory时,在CONFIG_IOMMU_DMA 定义了的情况下就等于在操作iommu的ops.
更多推荐
dma_mmap_coherent 如何和iommu联系在一起呢?
发布评论