smmu 学习笔记之iova

    xiaoxiao2021-03-25  115

    在iova_domain中有一个变量granule struct iova_domain {     spinlock_t    iova_rbtree_lock; /* Lock to protect update of rbtree */     struct rb_root    rbroot;        /* iova domain rbtree root */     struct rb_node    *cached32_node; /* Save last alloced node */     unsigned long    granule;    /* pfn granularity for this domain */     unsigned long    start_pfn;    /* Lower limit for this domain */     unsigned long    dma_32bit_pfn;     struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE];    /* IOVA range caches */ }; 这个变量会在iommu_dma_init_domain 中通过init_iova_domain来赋值 首先在iommu_dma_init_domain 中得到order,__ffs 这个函数之前分析过,就 order = __ffs(domain->pgsize_bitmap); 是得到domain->pgsize_bitmap 的最低为1的为,我们以4096 为里的话,就是12.然后又1UL << order就等于4096,最后调用init_iova_domain来给granule 赋值. init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn); init_iova_domain(struct iova_domain *iovad, unsigned long granule,     unsigned long start_pfn, unsigned long pfn_32bit) {     /*      * IOVA granularity will normally be equal to the smallest      * supported IOMMU page size; both *must* be capable of      * representing individual CPU pages exactly.      */     BUG_ON((granule > PAGE_SIZE) || !is_power_of_2(granule));     spin_lock_init(&iovad->iova_rbtree_lock);     iovad->rbroot = RB_ROOT;     iovad->cached32_node = NULL;     iovad->granule = granule;     iovad->start_pfn = start_pfn;     iovad->dma_32bit_pfn = pfn_32bit;     init_iova_rcaches(iovad); } 所以这里的granule 就等于4096,也就说这个domain 最低是一个4096 对齐的. 这样我们在iommu_dma_map_page 中调用 size_t iova_off = iova_offset(iovad, phys);来计算iova_off的时候起始就是让phys以granule 对齐 static inline size_t iova_offset(struct iova_domain *iovad, dma_addr_t iova) {     return iova & iova_mask(iovad); } static inline unsigned long iova_mask(struct iova_domain *iovad) {     return iovad->granule - 1; } 这样在调用(iommu_map(domain, dma_addr, phys - iova_off, len, prot))的时候,第三个参数paddr就表示需要映射的物理地址和这个domain 最小支持的page size的差值,一般情况下这个差值为0.因为我们通过iommu映射的时候一般都是pagesize对齐的。 如果不为0的话会在iommu_map->iommu_pgsize 中尝试合并. 最后在计算pte的时候会加上这个paddr pte |= pfn_to_iopte(paddr >> data->pg_shift, data);
    转载请注明原文地址: https://ju.6miu.com/read-13403.html

    最新回复(0)