| From a2c01c5710f87b7d416becc300583c1814d125f1 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 15 Jan 2021 08:42:02 +0800 |
| Subject: iommu/vt-d: Preset Access/Dirty bits for IOVA over FL |
| |
| From: Lu Baolu <baolu.lu@linux.intel.com> |
| |
| [ Upstream commit a8ce9ebbecdfda3322bbcece6b3b25888217f8e3 ] |
| |
| The Access/Dirty bits in the first level page table entry will be set |
| whenever a page table entry was used for address translation or write |
| permission was successfully translated. This is always true when using |
| the first-level page table for kernel IOVA. Instead of wasting hardware |
| cycles to update the certain bits, it's better to set them up at the |
| beginning. |
| |
| Suggested-by: Ashok Raj <ashok.raj@intel.com> |
| Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> |
| Link: https://lore.kernel.org/r/20210115004202.953965-1-baolu.lu@linux.intel.com |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/iommu/intel/iommu.c | 14 ++++++++++++-- |
| include/linux/intel-iommu.h | 2 ++ |
| 2 files changed, 14 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c |
| index 026041308409..2f5d12cdb298 100644 |
| --- a/drivers/iommu/intel/iommu.c |
| +++ b/drivers/iommu/intel/iommu.c |
| @@ -1023,8 +1023,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, |
| |
| 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; |
| - if (domain_use_first_level(domain)) |
| + if (domain_use_first_level(domain)) { |
| pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US; |
| + if (domain->domain.type == IOMMU_DOMAIN_DMA) |
| + pteval |= DMA_FL_PTE_ACCESS; |
| + } |
| if (cmpxchg64(&pte->val, 0ULL, pteval)) |
| /* Someone else set it while we were thinking; use theirs. */ |
| free_pgtable_page(tmp_page); |
| @@ -2351,9 +2354,16 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn, |
| return -EINVAL; |
| |
| attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP); |
| - if (domain_use_first_level(domain)) |
| + if (domain_use_first_level(domain)) { |
| attr |= DMA_FL_PTE_PRESENT | DMA_FL_PTE_XD | DMA_FL_PTE_US; |
| |
| + if (domain->domain.type == IOMMU_DOMAIN_DMA) { |
| + attr |= DMA_FL_PTE_ACCESS; |
| + if (prot & DMA_PTE_WRITE) |
| + attr |= DMA_FL_PTE_DIRTY; |
| + } |
| + } |
| + |
| pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | attr; |
| |
| while (nr_pages > 0) { |
| diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h |
| index 09c6a0bf3892..ecb35fdff03e 100644 |
| --- a/include/linux/intel-iommu.h |
| +++ b/include/linux/intel-iommu.h |
| @@ -42,6 +42,8 @@ |
| |
| #define DMA_FL_PTE_PRESENT BIT_ULL(0) |
| #define DMA_FL_PTE_US BIT_ULL(2) |
| +#define DMA_FL_PTE_ACCESS BIT_ULL(5) |
| +#define DMA_FL_PTE_DIRTY BIT_ULL(6) |
| #define DMA_FL_PTE_XD BIT_ULL(63) |
| |
| #define ADDR_WIDTH_5LEVEL (57) |
| -- |
| 2.30.2 |
| |