diff mbox series

[kvm-unit-tests] x86/intel-iommu: add test for address width 48 and 57.

Message ID 1541764960-11322-1-git-send-email-yu.c.zhang@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series [kvm-unit-tests] x86/intel-iommu: add test for address width 48 and 57. | expand

Commit Message

Yu Zhang Nov. 9, 2018, 12:02 p.m. UTC
Current iommu test only covers 39-bit address width. This patch
extends the test case to based on the supported maximum guest
address width.

Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
---
 lib/x86/intel-iommu.c | 14 ++++----------
 lib/x86/intel-iommu.h | 11 ++++++++++-
 x86/intel-iommu.c     | 21 ++++++++++++++++-----
 3 files changed, 30 insertions(+), 16 deletions(-)

Comments

Michael S. Tsirkin Nov. 9, 2018, 6:13 p.m. UTC | #1
On Fri, Nov 09, 2018 at 08:02:40PM +0800, Yu Zhang wrote:
> Current iommu test only covers 39-bit address width. This patch
> extends the test case to based on the supported maximum guest
> address width.
> 
> Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>


Reviewed-by: Michael S. Tsirkin <mst@redhat.com>

> ---
>  lib/x86/intel-iommu.c | 14 ++++----------
>  lib/x86/intel-iommu.h | 11 ++++++++++-
>  x86/intel-iommu.c     | 21 ++++++++++++++++-----
>  3 files changed, 30 insertions(+), 16 deletions(-)
> 
> diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c
> index 3f3f211..e1ea9d2 100644
> --- a/lib/x86/intel-iommu.c
> +++ b/lib/x86/intel-iommu.c
> @@ -16,13 +16,6 @@
>  #include "atomic.h"
>  #include "alloc_page.h"
>  
> -/*
> - * VT-d in QEMU currently only support 39 bits address width, which is
> - * 3-level translation.
> - */
> -#define VTD_PAGE_LEVEL      3
> -#define VTD_CE_AW_39BIT     0x1
> -
>  typedef uint64_t vtd_pte_t;
>  
>  struct vtd_root_entry {
> @@ -75,6 +68,8 @@ typedef struct vtd_irte vtd_irte_t;
>  #define VTD_IRTA_MASK (PAGE_MASK)
>  
>  void *vtd_reg_base;
> +uint8_t max_gaw;
> +uint8_t max_page_level;
>  
>  static uint64_t vtd_root_table(void)
>  {
> @@ -149,7 +144,7 @@ static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
>  	unsigned int offset;
>  	void *page;
>  
> -	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
> +	for (level = max_page_level; level > level_target; level--) {
>  		offset = PGDIR_OFFSET(iova, level);
>  		if (!(root[offset] & VTD_PTE_RW)) {
>  			page = alloc_page();
> @@ -213,8 +208,7 @@ void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
>  		memset(ce, 0, sizeof(*ce));
>  		/* To make it simple, domain ID is the same as SID */
>  		ce->domain_id = sid;
> -		/* We only test 39 bits width case (3-level paging) */
> -		ce->addr_width = VTD_CE_AW_39BIT;
> +		ce->addr_width = max_page_level - 2;
>  		ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT;
>  		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
>  		ce->present = 1;
> diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h
> index 05b9744..7057417 100644
> --- a/lib/x86/intel-iommu.h
> +++ b/lib/x86/intel-iommu.h
> @@ -26,6 +26,7 @@
>  #define Q35_HOST_BRIDGE_IOMMU_ADDR  0xfed90000ULL
>  #define VTD_PAGE_SHIFT              PAGE_SHIFT
>  #define VTD_PAGE_SIZE               PAGE_SIZE
> +#define VTD_PAGE_LEVEL_STRIDE       9
>  
>  /*
>   * Intel IOMMU register specification
> @@ -100,7 +101,13 @@
>  #define VTD_CAP_SAGAW_39bit         (0x2ULL << VTD_CAP_SAGAW_SHIFT)
>  /* 48-bit AGAW, 4-level page-table */
>  #define VTD_CAP_SAGAW_48bit         (0x4ULL << VTD_CAP_SAGAW_SHIFT)
> -#define VTD_CAP_SAGAW               VTD_CAP_SAGAW_39bit
> +/* 57-bit AGAW, 5-level page-table */
> +#define VTD_CAP_SAGAW_57bit         (0x8ULL << VTD_CAP_SAGAW_SHIFT)
> +#define VTD_CAP_SAGAW(cap)          (((cap) >> VTD_CAP_SAGAW_SHIFT) & 0x1fULL)
> +
> +/* Maximum Guest Address Widths */
> +#define VTD_CAP_MGAW_SHIFT    16
> +#define VTD_CAP_MGAW(cap)     ((((cap) >> VTD_CAP_MGAW_SHIFT) & 0x3fULL) + 1)
>  
>  /* Both 1G/2M huge pages */
>  #define VTD_CAP_SLLPS               ((1ULL << 34) | (1ULL << 35))
> @@ -118,6 +125,8 @@
>  extern void *vtd_reg_base;
>  #define vtd_reg(reg) ({ assert(vtd_reg_base); \
>  			(volatile void *)(vtd_reg_base + reg); })
> +extern  uint8_t max_gaw;
> +extern  uint8_t max_page_level;
>  
>  static inline void vtd_writel(unsigned int reg, uint32_t value)
>  {
> diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c
> index f24170d..9d2194d 100644
> --- a/x86/intel-iommu.c
> +++ b/x86/intel-iommu.c
> @@ -132,25 +132,36 @@ static void vtd_test_ir(void)
>  
>  int main(int argc, char *argv[])
>  {
> +	uint64_t dmar_cap;
> +	uint8_t sagaw;
> +
>  	setup_vm();
>  	smp_init();
> -
>  	vtd_init();
>  
>  	report_prefix_push("vtd_init");
> -
>  	report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0);
>  	report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI);
>  	report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT);
>  	report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE);
>  	report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR);
>  	report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR);
> -	report("DMAR support 39 bits address width",
> -	       vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW);
>  	report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS);
> -
>  	report_prefix_pop();
>  
> +	dmar_cap = vtd_readq(DMAR_CAP_REG);
> +	max_gaw = VTD_CAP_MGAW(dmar_cap);
> +	sagaw = VTD_CAP_SAGAW(dmar_cap);
> +	max_page_level = (max_gaw - VTD_PAGE_SHIFT)/VTD_PAGE_LEVEL_STRIDE;
> +
> +	report("address width check", ((1 << (max_page_level - 2)) & sagaw));
> +	if (dmar_cap & VTD_CAP_SAGAW_39bit)
> +		printf("DMAR supports 39 bits address width.\n");
> +	if (dmar_cap & VTD_CAP_SAGAW_48bit)
> +		printf("DMAR supports 48 bits address width.\n");
> +	if (dmar_cap & VTD_CAP_SAGAW_57bit)
> +		printf("DMAR supports 57 bits address width.\n");
> +
>  	if (!edu_init(&edu_dev)) {
>  		printf("Please specify \"-device edu\" to do "
>  		       "further IOMMU tests.\n");
> -- 
> 1.9.1
Peter Xu Nov. 12, 2018, 9:24 a.m. UTC | #2
On Fri, Nov 09, 2018 at 08:02:40PM +0800, Yu Zhang wrote:
> Current iommu test only covers 39-bit address width. This patch
> extends the test case to based on the supported maximum guest
> address width.
> 
> Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>

Reviewed-by: Peter Xu <peterx@redhat.com>

Thanks,
Yu Zhang Dec. 14, 2018, 9:22 a.m. UTC | #3
Hi Paolo, any comments on this? Thanks! :)

Yu

On Fri, Nov 09, 2018 at 08:02:40PM +0800, Yu Zhang wrote:
> Current iommu test only covers 39-bit address width. This patch
> extends the test case to based on the supported maximum guest
> address width.
> 
> Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
> ---
>  lib/x86/intel-iommu.c | 14 ++++----------
>  lib/x86/intel-iommu.h | 11 ++++++++++-
>  x86/intel-iommu.c     | 21 ++++++++++++++++-----
>  3 files changed, 30 insertions(+), 16 deletions(-)
> 
> diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c
> index 3f3f211..e1ea9d2 100644
> --- a/lib/x86/intel-iommu.c
> +++ b/lib/x86/intel-iommu.c
> @@ -16,13 +16,6 @@
>  #include "atomic.h"
>  #include "alloc_page.h"
>  
> -/*
> - * VT-d in QEMU currently only support 39 bits address width, which is
> - * 3-level translation.
> - */
> -#define VTD_PAGE_LEVEL      3
> -#define VTD_CE_AW_39BIT     0x1
> -
>  typedef uint64_t vtd_pte_t;
>  
>  struct vtd_root_entry {
> @@ -75,6 +68,8 @@ typedef struct vtd_irte vtd_irte_t;
>  #define VTD_IRTA_MASK (PAGE_MASK)
>  
>  void *vtd_reg_base;
> +uint8_t max_gaw;
> +uint8_t max_page_level;
>  
>  static uint64_t vtd_root_table(void)
>  {
> @@ -149,7 +144,7 @@ static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
>  	unsigned int offset;
>  	void *page;
>  
> -	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
> +	for (level = max_page_level; level > level_target; level--) {
>  		offset = PGDIR_OFFSET(iova, level);
>  		if (!(root[offset] & VTD_PTE_RW)) {
>  			page = alloc_page();
> @@ -213,8 +208,7 @@ void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
>  		memset(ce, 0, sizeof(*ce));
>  		/* To make it simple, domain ID is the same as SID */
>  		ce->domain_id = sid;
> -		/* We only test 39 bits width case (3-level paging) */
> -		ce->addr_width = VTD_CE_AW_39BIT;
> +		ce->addr_width = max_page_level - 2;
>  		ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT;
>  		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
>  		ce->present = 1;
> diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h
> index 05b9744..7057417 100644
> --- a/lib/x86/intel-iommu.h
> +++ b/lib/x86/intel-iommu.h
> @@ -26,6 +26,7 @@
>  #define Q35_HOST_BRIDGE_IOMMU_ADDR  0xfed90000ULL
>  #define VTD_PAGE_SHIFT              PAGE_SHIFT
>  #define VTD_PAGE_SIZE               PAGE_SIZE
> +#define VTD_PAGE_LEVEL_STRIDE       9
>  
>  /*
>   * Intel IOMMU register specification
> @@ -100,7 +101,13 @@
>  #define VTD_CAP_SAGAW_39bit         (0x2ULL << VTD_CAP_SAGAW_SHIFT)
>  /* 48-bit AGAW, 4-level page-table */
>  #define VTD_CAP_SAGAW_48bit         (0x4ULL << VTD_CAP_SAGAW_SHIFT)
> -#define VTD_CAP_SAGAW               VTD_CAP_SAGAW_39bit
> +/* 57-bit AGAW, 5-level page-table */
> +#define VTD_CAP_SAGAW_57bit         (0x8ULL << VTD_CAP_SAGAW_SHIFT)
> +#define VTD_CAP_SAGAW(cap)          (((cap) >> VTD_CAP_SAGAW_SHIFT) & 0x1fULL)
> +
> +/* Maximum Guest Address Widths */
> +#define VTD_CAP_MGAW_SHIFT    16
> +#define VTD_CAP_MGAW(cap)     ((((cap) >> VTD_CAP_MGAW_SHIFT) & 0x3fULL) + 1)
>  
>  /* Both 1G/2M huge pages */
>  #define VTD_CAP_SLLPS               ((1ULL << 34) | (1ULL << 35))
> @@ -118,6 +125,8 @@
>  extern void *vtd_reg_base;
>  #define vtd_reg(reg) ({ assert(vtd_reg_base); \
>  			(volatile void *)(vtd_reg_base + reg); })
> +extern  uint8_t max_gaw;
> +extern  uint8_t max_page_level;
>  
>  static inline void vtd_writel(unsigned int reg, uint32_t value)
>  {
> diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c
> index f24170d..9d2194d 100644
> --- a/x86/intel-iommu.c
> +++ b/x86/intel-iommu.c
> @@ -132,25 +132,36 @@ static void vtd_test_ir(void)
>  
>  int main(int argc, char *argv[])
>  {
> +	uint64_t dmar_cap;
> +	uint8_t sagaw;
> +
>  	setup_vm();
>  	smp_init();
> -
>  	vtd_init();
>  
>  	report_prefix_push("vtd_init");
> -
>  	report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0);
>  	report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI);
>  	report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT);
>  	report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE);
>  	report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR);
>  	report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR);
> -	report("DMAR support 39 bits address width",
> -	       vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW);
>  	report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS);
> -
>  	report_prefix_pop();
>  
> +	dmar_cap = vtd_readq(DMAR_CAP_REG);
> +	max_gaw = VTD_CAP_MGAW(dmar_cap);
> +	sagaw = VTD_CAP_SAGAW(dmar_cap);
> +	max_page_level = (max_gaw - VTD_PAGE_SHIFT)/VTD_PAGE_LEVEL_STRIDE;
> +
> +	report("address width check", ((1 << (max_page_level - 2)) & sagaw));
> +	if (dmar_cap & VTD_CAP_SAGAW_39bit)
> +		printf("DMAR supports 39 bits address width.\n");
> +	if (dmar_cap & VTD_CAP_SAGAW_48bit)
> +		printf("DMAR supports 48 bits address width.\n");
> +	if (dmar_cap & VTD_CAP_SAGAW_57bit)
> +		printf("DMAR supports 57 bits address width.\n");
> +
>  	if (!edu_init(&edu_dev)) {
>  		printf("Please specify \"-device edu\" to do "
>  		       "further IOMMU tests.\n");
> -- 
> 1.9.1
>
diff mbox series

Patch

diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c
index 3f3f211..e1ea9d2 100644
--- a/lib/x86/intel-iommu.c
+++ b/lib/x86/intel-iommu.c
@@ -16,13 +16,6 @@ 
 #include "atomic.h"
 #include "alloc_page.h"
 
-/*
- * VT-d in QEMU currently only support 39 bits address width, which is
- * 3-level translation.
- */
-#define VTD_PAGE_LEVEL      3
-#define VTD_CE_AW_39BIT     0x1
-
 typedef uint64_t vtd_pte_t;
 
 struct vtd_root_entry {
@@ -75,6 +68,8 @@  typedef struct vtd_irte vtd_irte_t;
 #define VTD_IRTA_MASK (PAGE_MASK)
 
 void *vtd_reg_base;
+uint8_t max_gaw;
+uint8_t max_page_level;
 
 static uint64_t vtd_root_table(void)
 {
@@ -149,7 +144,7 @@  static void vtd_install_pte(vtd_pte_t *root, iova_t iova,
 	unsigned int offset;
 	void *page;
 
-	for (level = VTD_PAGE_LEVEL; level > level_target; level--) {
+	for (level = max_page_level; level > level_target; level--) {
 		offset = PGDIR_OFFSET(iova, level);
 		if (!(root[offset] & VTD_PTE_RW)) {
 			page = alloc_page();
@@ -213,8 +208,7 @@  void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size)
 		memset(ce, 0, sizeof(*ce));
 		/* To make it simple, domain ID is the same as SID */
 		ce->domain_id = sid;
-		/* We only test 39 bits width case (3-level paging) */
-		ce->addr_width = VTD_CE_AW_39BIT;
+		ce->addr_width = max_page_level - 2;
 		ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT;
 		ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL;
 		ce->present = 1;
diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h
index 05b9744..7057417 100644
--- a/lib/x86/intel-iommu.h
+++ b/lib/x86/intel-iommu.h
@@ -26,6 +26,7 @@ 
 #define Q35_HOST_BRIDGE_IOMMU_ADDR  0xfed90000ULL
 #define VTD_PAGE_SHIFT              PAGE_SHIFT
 #define VTD_PAGE_SIZE               PAGE_SIZE
+#define VTD_PAGE_LEVEL_STRIDE       9
 
 /*
  * Intel IOMMU register specification
@@ -100,7 +101,13 @@ 
 #define VTD_CAP_SAGAW_39bit         (0x2ULL << VTD_CAP_SAGAW_SHIFT)
 /* 48-bit AGAW, 4-level page-table */
 #define VTD_CAP_SAGAW_48bit         (0x4ULL << VTD_CAP_SAGAW_SHIFT)
-#define VTD_CAP_SAGAW               VTD_CAP_SAGAW_39bit
+/* 57-bit AGAW, 5-level page-table */
+#define VTD_CAP_SAGAW_57bit         (0x8ULL << VTD_CAP_SAGAW_SHIFT)
+#define VTD_CAP_SAGAW(cap)          (((cap) >> VTD_CAP_SAGAW_SHIFT) & 0x1fULL)
+
+/* Maximum Guest Address Widths */
+#define VTD_CAP_MGAW_SHIFT    16
+#define VTD_CAP_MGAW(cap)     ((((cap) >> VTD_CAP_MGAW_SHIFT) & 0x3fULL) + 1)
 
 /* Both 1G/2M huge pages */
 #define VTD_CAP_SLLPS               ((1ULL << 34) | (1ULL << 35))
@@ -118,6 +125,8 @@ 
 extern void *vtd_reg_base;
 #define vtd_reg(reg) ({ assert(vtd_reg_base); \
 			(volatile void *)(vtd_reg_base + reg); })
+extern  uint8_t max_gaw;
+extern  uint8_t max_page_level;
 
 static inline void vtd_writel(unsigned int reg, uint32_t value)
 {
diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c
index f24170d..9d2194d 100644
--- a/x86/intel-iommu.c
+++ b/x86/intel-iommu.c
@@ -132,25 +132,36 @@  static void vtd_test_ir(void)
 
 int main(int argc, char *argv[])
 {
+	uint64_t dmar_cap;
+	uint8_t sagaw;
+
 	setup_vm();
 	smp_init();
-
 	vtd_init();
 
 	report_prefix_push("vtd_init");
-
 	report("fault status check", vtd_readl(DMAR_FSTS_REG) == 0);
 	report("QI enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI);
 	report("DMAR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT);
 	report("IR table setup", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE);
 	report("DMAR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR);
 	report("IR enablement", vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR);
-	report("DMAR support 39 bits address width",
-	       vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW);
 	report("DMAR support huge pages", vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS);
-
 	report_prefix_pop();
 
+	dmar_cap = vtd_readq(DMAR_CAP_REG);
+	max_gaw = VTD_CAP_MGAW(dmar_cap);
+	sagaw = VTD_CAP_SAGAW(dmar_cap);
+	max_page_level = (max_gaw - VTD_PAGE_SHIFT)/VTD_PAGE_LEVEL_STRIDE;
+
+	report("address width check", ((1 << (max_page_level - 2)) & sagaw));
+	if (dmar_cap & VTD_CAP_SAGAW_39bit)
+		printf("DMAR supports 39 bits address width.\n");
+	if (dmar_cap & VTD_CAP_SAGAW_48bit)
+		printf("DMAR supports 48 bits address width.\n");
+	if (dmar_cap & VTD_CAP_SAGAW_57bit)
+		printf("DMAR supports 57 bits address width.\n");
+
 	if (!edu_init(&edu_dev)) {
 		printf("Please specify \"-device edu\" to do "
 		       "further IOMMU tests.\n");