Re: [PATCH v2 5/8] iommu/vt-d: Add first level page table interfaces
Hi Jacob, On 12/3/19 7:27 AM, Jacob Pan wrote: On Thu, 28 Nov 2019 10:25:47 +0800 Lu Baolu wrote: This adds functions to manipulate first level page tables which could be used by a scalale mode capable IOMMU unit. FL and SL page tables are very similar, and I presume we are not using all the flag bits in FL paging structures for DMA mapping. Are there enough relevant differences to warrant a new set of helper functions for FL? Or we can merge into one. I evaluated your suggestion these days. It turned out that your suggestion make code simpler and easier for maintainence. Thank you for the comment and I will send out a new version for review soon. Best regards, baolu ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 5/8] iommu/vt-d: Add first level page table interfaces
Hi, On 12/3/19 7:27 AM, Jacob Pan wrote: On Thu, 28 Nov 2019 10:25:47 +0800 Lu Baolu wrote: This adds functions to manipulate first level page tables which could be used by a scalale mode capable IOMMU unit. FL and SL page tables are very similar, and I presume we are not using all the flag bits in FL paging structures for DMA mapping. Are there enough relevant differences to warrant a new set of helper functions for FL? Or we can merge into one. I ever thought about this and I am still open for this suggestion. We had a quick compare on these two page tables. The only concern is the read/write/present encoding. The present bit in first level implies read permission while second level page table explicitly has a READ bit. (recalled from memory, correct me if it's bad. :-)). Anyway, let's listen to more opinions. Best regards, baolu ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 5/8] iommu/vt-d: Add first level page table interfaces
On Thu, 28 Nov 2019 10:25:47 +0800 Lu Baolu wrote: > This adds functions to manipulate first level page tables > which could be used by a scalale mode capable IOMMU unit. > FL and SL page tables are very similar, and I presume we are not using all the flag bits in FL paging structures for DMA mapping. Are there enough relevant differences to warrant a new set of helper functions for FL? Or we can merge into one. > Cc: Ashok Raj > Cc: Jacob Pan > Cc: Kevin Tian > Cc: Liu Yi L > Cc: Yi Sun > Signed-off-by: Lu Baolu > --- > drivers/iommu/Makefile | 2 +- > drivers/iommu/intel-iommu.c| 33 +++ > drivers/iommu/intel-pgtable.c | 376 > + include/linux/intel-iommu.h| > 33 ++- include/trace/events/intel_iommu.h | 60 + > 5 files changed, 502 insertions(+), 2 deletions(-) > create mode 100644 drivers/iommu/intel-pgtable.c > > diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile > index 35d17094fe3b..aa04f4c3ae26 100644 > --- a/drivers/iommu/Makefile > +++ b/drivers/iommu/Makefile > @@ -18,7 +18,7 @@ obj-$(CONFIG_ARM_SMMU) += arm-smmu.o arm-smmu-impl.o > obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o > obj-$(CONFIG_DMAR_TABLE) += dmar.o > obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o > -obj-$(CONFIG_INTEL_IOMMU) += intel-trace.o > +obj-$(CONFIG_INTEL_IOMMU) += intel-trace.o intel-pgtable.o > obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += intel-iommu-debugfs.o > obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o > obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o > diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c > index 66f76f6df2c2..a314892ee72b 100644 > --- a/drivers/iommu/intel-iommu.c > +++ b/drivers/iommu/intel-iommu.c > @@ -1670,6 +1670,37 @@ static void free_dmar_iommu(struct intel_iommu > *iommu) #endif > } > > +/* First level 5-level paging support */ > +static bool first_lvl_5lp_support(void) > +{ > + struct dmar_drhd_unit *drhd; > + struct intel_iommu *iommu; > + static int first_level_5lp_supported = -1; > + > + if (likely(first_level_5lp_supported != -1)) > + return first_level_5lp_supported; > + > + first_level_5lp_supported = 1; > +#ifdef CONFIG_X86 > + /* Match IOMMU first level and CPU paging mode */ > + if (!cpu_feature_enabled(X86_FEATURE_LA57)) { > + first_level_5lp_supported = 0; > + return first_level_5lp_supported; > + } > +#endif /* #ifdef CONFIG_X86 */ > + > + rcu_read_lock(); > + for_each_active_iommu(iommu, drhd) { > + if (!cap_5lp_support(iommu->cap)) { > + first_level_5lp_supported = 0; > + break; > + } > + } > + rcu_read_unlock(); > + > + return first_level_5lp_supported; > +} > + > static struct dmar_domain *alloc_domain(int flags) > { > struct dmar_domain *domain; > @@ -1683,6 +1714,8 @@ static struct dmar_domain *alloc_domain(int > flags) domain->flags = flags; > domain->has_iotlb_device = false; > domain->ops = _lvl_pgtable_ops; > + domain->first_lvl_5lp = first_lvl_5lp_support(); > + spin_lock_init(>page_table_lock); > INIT_LIST_HEAD(>devices); > > return domain; > diff --git a/drivers/iommu/intel-pgtable.c > b/drivers/iommu/intel-pgtable.c new file mode 100644 > index ..4a26d08a7570 > --- /dev/null > +++ b/drivers/iommu/intel-pgtable.c > @@ -0,0 +1,376 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/** > + * intel-pgtable.c - Intel IOMMU page table manipulation library > + * > + * Copyright (C) 2019 Intel Corporation > + * > + * Author: Lu Baolu > + */ > + > +#define pr_fmt(fmt) "DMAR: " fmt > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* > + * first_lvl_map: Map a range of IO virtual address to physical > addresses. > + */ > +#ifdef CONFIG_X86 > +#define pgtable_populate(domain, > nm) \ +do > { > \ > + void *__new = > alloc_pgtable_page(domain->nid); \ > + if > (!__new) \ > + return > -ENOMEM; \ > + > smp_wmb();\ > + > spin_lock(&(domain)->page_table_lock); > \ > + if (nm ## _present(*nm)) > { \ > + > free_pgtable_page(__new); \ > + } else > { \ > + set_##nm(nm, __##nm(__pa(__new) | > _PAGE_TABLE));\ > + domain_flush_cache(domain, nm, > sizeof(nm##_t)); \ > + } > \ > + > spin_unlock(&(domain)->page_table_lock); \ +} > while (0) + > +static int > +first_lvl_map_pte_range(struct dmar_domain *domain, pmd_t *pmd, > + unsigned long addr, unsigned long end, >
[PATCH v2 5/8] iommu/vt-d: Add first level page table interfaces
This adds functions to manipulate first level page tables which could be used by a scalale mode capable IOMMU unit. Cc: Ashok Raj Cc: Jacob Pan Cc: Kevin Tian Cc: Liu Yi L Cc: Yi Sun Signed-off-by: Lu Baolu --- drivers/iommu/Makefile | 2 +- drivers/iommu/intel-iommu.c| 33 +++ drivers/iommu/intel-pgtable.c | 376 + include/linux/intel-iommu.h| 33 ++- include/trace/events/intel_iommu.h | 60 + 5 files changed, 502 insertions(+), 2 deletions(-) create mode 100644 drivers/iommu/intel-pgtable.c diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 35d17094fe3b..aa04f4c3ae26 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_ARM_SMMU) += arm-smmu.o arm-smmu-impl.o obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o obj-$(CONFIG_DMAR_TABLE) += dmar.o obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o -obj-$(CONFIG_INTEL_IOMMU) += intel-trace.o +obj-$(CONFIG_INTEL_IOMMU) += intel-trace.o intel-pgtable.o obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += intel-iommu-debugfs.o obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 66f76f6df2c2..a314892ee72b 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1670,6 +1670,37 @@ static void free_dmar_iommu(struct intel_iommu *iommu) #endif } +/* First level 5-level paging support */ +static bool first_lvl_5lp_support(void) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + static int first_level_5lp_supported = -1; + + if (likely(first_level_5lp_supported != -1)) + return first_level_5lp_supported; + + first_level_5lp_supported = 1; +#ifdef CONFIG_X86 + /* Match IOMMU first level and CPU paging mode */ + if (!cpu_feature_enabled(X86_FEATURE_LA57)) { + first_level_5lp_supported = 0; + return first_level_5lp_supported; + } +#endif /* #ifdef CONFIG_X86 */ + + rcu_read_lock(); + for_each_active_iommu(iommu, drhd) { + if (!cap_5lp_support(iommu->cap)) { + first_level_5lp_supported = 0; + break; + } + } + rcu_read_unlock(); + + return first_level_5lp_supported; +} + static struct dmar_domain *alloc_domain(int flags) { struct dmar_domain *domain; @@ -1683,6 +1714,8 @@ static struct dmar_domain *alloc_domain(int flags) domain->flags = flags; domain->has_iotlb_device = false; domain->ops = _lvl_pgtable_ops; + domain->first_lvl_5lp = first_lvl_5lp_support(); + spin_lock_init(>page_table_lock); INIT_LIST_HEAD(>devices); return domain; diff --git a/drivers/iommu/intel-pgtable.c b/drivers/iommu/intel-pgtable.c new file mode 100644 index ..4a26d08a7570 --- /dev/null +++ b/drivers/iommu/intel-pgtable.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * intel-pgtable.c - Intel IOMMU page table manipulation library + * + * Copyright (C) 2019 Intel Corporation + * + * Author: Lu Baolu + */ + +#define pr_fmt(fmt) "DMAR: " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * first_lvl_map: Map a range of IO virtual address to physical addresses. + */ +#ifdef CONFIG_X86 +#define pgtable_populate(domain, nm) \ +do { \ + void *__new = alloc_pgtable_page(domain->nid); \ + if (!__new) \ + return -ENOMEM; \ + smp_wmb(); \ + spin_lock(&(domain)->page_table_lock); \ + if (nm ## _present(*nm)) { \ + free_pgtable_page(__new); \ + } else {\ + set_##nm(nm, __##nm(__pa(__new) | _PAGE_TABLE));\ + domain_flush_cache(domain, nm, sizeof(nm##_t)); \ + } \ + spin_unlock(&(domain)->page_table_lock);\ +} while (0) + +static int +first_lvl_map_pte_range(struct dmar_domain *domain, pmd_t *pmd, + unsigned long addr, unsigned long end, + phys_addr_t phys_addr, pgprot_t prot) +{ + pte_t *pte, *first_pte; + u64 pfn; + + pfn = phys_addr >> PAGE_SHIFT; + if (unlikely(pmd_none(*pmd))) + pgtable_populate(domain, pmd); + + first_pte = pte = pte_offset_kernel(pmd, addr); + + do { +