mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-07-04 00:03:25 -04:00
iommu/vt-d: Setup pasid entries for iova over first level
Intel VT-d in scalable mode supports two types of page tables for IOVA translation: first level and second level. The IOMMU driver can choose one from both for IOVA translation according to the use case. This sets up the pasid entry if a domain is selected to use the first-level page table for iova translation. Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
87208f22a4
commit
ddf09b6d43
2 changed files with 62 additions and 11 deletions
|
@ -571,6 +571,11 @@ static inline int domain_type_is_si(struct dmar_domain *domain)
|
||||||
return domain->flags & DOMAIN_FLAG_STATIC_IDENTITY;
|
return domain->flags & DOMAIN_FLAG_STATIC_IDENTITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool domain_use_first_level(struct dmar_domain *domain)
|
||||||
|
{
|
||||||
|
return domain->flags & DOMAIN_FLAG_USE_FIRST_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int domain_pfn_supported(struct dmar_domain *domain,
|
static inline int domain_pfn_supported(struct dmar_domain *domain,
|
||||||
unsigned long pfn)
|
unsigned long pfn)
|
||||||
{
|
{
|
||||||
|
@ -932,6 +937,8 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
|
||||||
|
|
||||||
domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
|
domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
|
||||||
pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
|
pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
|
||||||
|
if (domain_use_first_level(domain))
|
||||||
|
pteval |= DMA_FL_PTE_XD;
|
||||||
if (cmpxchg64(&pte->val, 0ULL, pteval))
|
if (cmpxchg64(&pte->val, 0ULL, pteval))
|
||||||
/* Someone else set it while we were thinking; use theirs. */
|
/* Someone else set it while we were thinking; use theirs. */
|
||||||
free_pgtable_page(tmp_page);
|
free_pgtable_page(tmp_page);
|
||||||
|
@ -2281,17 +2288,20 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
|
||||||
unsigned long sg_res = 0;
|
unsigned long sg_res = 0;
|
||||||
unsigned int largepage_lvl = 0;
|
unsigned int largepage_lvl = 0;
|
||||||
unsigned long lvl_pages = 0;
|
unsigned long lvl_pages = 0;
|
||||||
|
u64 attr;
|
||||||
|
|
||||||
BUG_ON(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1));
|
BUG_ON(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1));
|
||||||
|
|
||||||
if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
|
if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
|
attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP);
|
||||||
|
if (domain_use_first_level(domain))
|
||||||
|
attr |= DMA_FL_PTE_PRESENT | DMA_FL_PTE_XD;
|
||||||
|
|
||||||
if (!sg) {
|
if (!sg) {
|
||||||
sg_res = nr_pages;
|
sg_res = nr_pages;
|
||||||
pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
|
pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (nr_pages > 0) {
|
while (nr_pages > 0) {
|
||||||
|
@ -2303,7 +2313,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
|
||||||
sg_res = aligned_nrpages(sg->offset, sg->length);
|
sg_res = aligned_nrpages(sg->offset, sg->length);
|
||||||
sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff;
|
sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff;
|
||||||
sg->dma_length = sg->length;
|
sg->dma_length = sg->length;
|
||||||
pteval = (sg_phys(sg) - pgoff) | prot;
|
pteval = (sg_phys(sg) - pgoff) | attr;
|
||||||
phys_pfn = pteval >> VTD_PAGE_SHIFT;
|
phys_pfn = pteval >> VTD_PAGE_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2515,6 +2525,36 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int domain_setup_first_level(struct intel_iommu *iommu,
|
||||||
|
struct dmar_domain *domain,
|
||||||
|
struct device *dev,
|
||||||
|
int pasid)
|
||||||
|
{
|
||||||
|
int flags = PASID_FLAG_SUPERVISOR_MODE;
|
||||||
|
struct dma_pte *pgd = domain->pgd;
|
||||||
|
int agaw, level;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip top levels of page tables for iommu which has
|
||||||
|
* less agaw than default. Unnecessary for PT mode.
|
||||||
|
*/
|
||||||
|
for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
|
||||||
|
pgd = phys_to_virt(dma_pte_addr(pgd));
|
||||||
|
if (!dma_pte_present(pgd))
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
level = agaw_to_level(agaw);
|
||||||
|
if (level != 4 && level != 5)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
flags |= (level == 5) ? PASID_FLAG_FL5LP : 0;
|
||||||
|
|
||||||
|
return intel_pasid_setup_first_level(iommu, dev, (pgd_t *)pgd, pasid,
|
||||||
|
domain->iommu_did[iommu->seq_id],
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
|
static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
|
||||||
int bus, int devfn,
|
int bus, int devfn,
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
|
@ -2614,6 +2654,9 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
|
||||||
if (hw_pass_through && domain_type_is_si(domain))
|
if (hw_pass_through && domain_type_is_si(domain))
|
||||||
ret = intel_pasid_setup_pass_through(iommu, domain,
|
ret = intel_pasid_setup_pass_through(iommu, domain,
|
||||||
dev, PASID_RID2PASID);
|
dev, PASID_RID2PASID);
|
||||||
|
else if (domain_use_first_level(domain))
|
||||||
|
ret = domain_setup_first_level(iommu, domain, dev,
|
||||||
|
PASID_RID2PASID);
|
||||||
else
|
else
|
||||||
ret = intel_pasid_setup_second_level(iommu, domain,
|
ret = intel_pasid_setup_second_level(iommu, domain,
|
||||||
dev, PASID_RID2PASID);
|
dev, PASID_RID2PASID);
|
||||||
|
@ -5374,6 +5417,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
|
||||||
goto attach_failed;
|
goto attach_failed;
|
||||||
|
|
||||||
/* Setup the PASID entry for mediated devices: */
|
/* Setup the PASID entry for mediated devices: */
|
||||||
|
if (domain_use_first_level(domain))
|
||||||
|
ret = domain_setup_first_level(iommu, domain, dev,
|
||||||
|
domain->default_pasid);
|
||||||
|
else
|
||||||
ret = intel_pasid_setup_second_level(iommu, domain, dev,
|
ret = intel_pasid_setup_second_level(iommu, domain, dev,
|
||||||
domain->default_pasid);
|
domain->default_pasid);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -34,10 +34,13 @@
|
||||||
#define VTD_STRIDE_SHIFT (9)
|
#define VTD_STRIDE_SHIFT (9)
|
||||||
#define VTD_STRIDE_MASK (((u64)-1) << VTD_STRIDE_SHIFT)
|
#define VTD_STRIDE_MASK (((u64)-1) << VTD_STRIDE_SHIFT)
|
||||||
|
|
||||||
#define DMA_PTE_READ (1)
|
#define DMA_PTE_READ BIT_ULL(0)
|
||||||
#define DMA_PTE_WRITE (2)
|
#define DMA_PTE_WRITE BIT_ULL(1)
|
||||||
#define DMA_PTE_LARGE_PAGE (1 << 7)
|
#define DMA_PTE_LARGE_PAGE BIT_ULL(7)
|
||||||
#define DMA_PTE_SNP (1 << 11)
|
#define DMA_PTE_SNP BIT_ULL(11)
|
||||||
|
|
||||||
|
#define DMA_FL_PTE_PRESENT BIT_ULL(0)
|
||||||
|
#define DMA_FL_PTE_XD BIT_ULL(63)
|
||||||
|
|
||||||
#define CONTEXT_TT_MULTI_LEVEL 0
|
#define CONTEXT_TT_MULTI_LEVEL 0
|
||||||
#define CONTEXT_TT_DEV_IOTLB 1
|
#define CONTEXT_TT_DEV_IOTLB 1
|
||||||
|
@ -610,10 +613,11 @@ static inline void dma_clear_pte(struct dma_pte *pte)
|
||||||
static inline u64 dma_pte_addr(struct dma_pte *pte)
|
static inline u64 dma_pte_addr(struct dma_pte *pte)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
return pte->val & VTD_PAGE_MASK;
|
return pte->val & VTD_PAGE_MASK & (~DMA_FL_PTE_XD);
|
||||||
#else
|
#else
|
||||||
/* Must have a full atomic 64-bit read */
|
/* Must have a full atomic 64-bit read */
|
||||||
return __cmpxchg64(&pte->val, 0ULL, 0ULL) & VTD_PAGE_MASK;
|
return __cmpxchg64(&pte->val, 0ULL, 0ULL) &
|
||||||
|
VTD_PAGE_MASK & (~DMA_FL_PTE_XD);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue