Re: [PATCH v2 5/8] iommu/vt-d: Add first level page table interfaces

2019-12-10 Thread Lu Baolu

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

2019-12-02 Thread Lu Baolu

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

2019-12-02 Thread Jacob Pan
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

2019-11-27 Thread Lu Baolu
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 {
+