[PATCH 2/2] iommu/amd: Add efr[HATS] max v1 page table level

Ankit Soni posted 2 patches 7 months, 4 weeks ago
There is a newer version of this series
[PATCH 2/2] iommu/amd: Add efr[HATS] max v1 page table level
Posted by Ankit Soni 7 months, 4 weeks ago
The EFR[HATS] bits indicate maximum host translation level supported by
IOMMU. Adding support to set the maximum host page table level as indicated
by EFR[HATS]. If the HATS=11b (reserved), the driver will attempt to use
guest page table for DMA API.

Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
---
 drivers/iommu/amd/amd_iommu.h       |  1 +
 drivers/iommu/amd/amd_iommu_types.h |  1 +
 drivers/iommu/amd/init.c            | 16 ++++++++++++++++
 drivers/iommu/amd/io_pgtable.c      |  4 ++--
 drivers/iommu/amd/iommu.c           |  2 +-
 5 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index bb14c4800dd0..0286120ad4a5 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -42,6 +42,7 @@ int amd_iommu_enable_faulting(unsigned int cpu);
 extern int amd_iommu_guest_ir;
 extern enum protection_domain_mode amd_iommu_pgtable;
 extern int amd_iommu_gpt_level;
+extern u8 amd_iommu_hpt_level;
 extern unsigned long amd_iommu_pgsize_bitmap;
 extern bool amd_iommu_hatdis;
 
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index 284ff4309660..6bf81197c2c8 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -96,6 +96,7 @@
 #define FEATURE_GA		BIT_ULL(7)
 #define FEATURE_HE		BIT_ULL(8)
 #define FEATURE_PC		BIT_ULL(9)
+#define FEATURE_HATS		GENMASK_ULL(11, 10)
 #define FEATURE_GATS		GENMASK_ULL(13, 12)
 #define FEATURE_GLX		GENMASK_ULL(15, 14)
 #define FEATURE_GAM_VAPIC	BIT_ULL(21)
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index f71b236c2af2..c713756fa44e 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -152,6 +152,8 @@ bool amd_iommu_dump;
 bool amd_iommu_irq_remap __read_mostly;
 
 enum protection_domain_mode amd_iommu_pgtable = PD_MODE_NONE;
+/* Host page table level */
+u8 amd_iommu_hpt_level;
 /* Guest page table level */
 int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
 
@@ -3052,6 +3054,7 @@ static int __init early_amd_iommu_init(void)
 	struct acpi_table_header *ivrs_base;
 	int ret;
 	acpi_status status;
+	u8 efr_hats;
 
 	if (!amd_iommu_detected)
 		return -ENODEV;
@@ -3096,6 +3099,19 @@ static int __init early_amd_iommu_init(void)
 	    FIELD_GET(FEATURE_GATS, amd_iommu_efr) == GUEST_PGTABLE_5_LEVEL)
 		amd_iommu_gpt_level = PAGE_MODE_5_LEVEL;
 
+	efr_hats = FIELD_GET(FEATURE_HATS, amd_iommu_efr);
+	if (efr_hats != 0x3) {
+		/*
+		 * efr[HATS] bits specify the maximum host translation level
+		 * supported, with LEVEL 4 being initial max level.
+		 */
+		amd_iommu_hpt_level = efr_hats + PAGE_MODE_4_LEVEL;
+	} else {
+		pr_warn_once("Disable host address translation due to invalid max level (%#x).\n",
+			     efr_hats);
+		amd_iommu_hatdis = true;
+	}
+
 	if (amd_iommu_pgtable == PD_MODE_V2) {
 		if (!amd_iommu_v2_pgtbl_supported()) {
 			pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n");
diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
index 26cf562dde11..0d8bc06f63d7 100644
--- a/drivers/iommu/amd/io_pgtable.c
+++ b/drivers/iommu/amd/io_pgtable.c
@@ -132,7 +132,7 @@ static bool increase_address_space(struct amd_io_pgtable *pgtable,
 		goto out;
 
 	ret = false;
-	if (WARN_ON_ONCE(pgtable->mode == PAGE_MODE_6_LEVEL))
+	if (WARN_ON_ONCE(pgtable->mode == amd_iommu_hpt_level))
 		goto out;
 
 	*pte = PM_LEVEL_PDE(pgtable->mode, iommu_virt_to_phys(pgtable->root));
@@ -531,7 +531,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
 
 	/* Page-table is not visible to IOMMU anymore, so free it */
 	BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
-	       pgtable->mode > PAGE_MODE_6_LEVEL);
+	       pgtable->mode > amd_iommu_hpt_level);
 
 	free_sub_pt(pgtable->root, pgtable->mode, &freelist);
 	iommu_put_pages_list(&freelist);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 0ebc264726da..a2f957ee9110 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2503,7 +2503,7 @@ static int pdom_setup_pgtable(struct protection_domain *domain,
 static inline u64 dma_max_address(enum protection_domain_mode pgtable)
 {
 	if (pgtable == PD_MODE_V1)
-		return ~0ULL;
+		return PM_LEVEL_SIZE(amd_iommu_hpt_level);
 
 	/* V2 with 4/5 level page table */
 	return ((1ULL << PM_LEVEL_SHIFT(amd_iommu_gpt_level)) - 1);
-- 
2.43.0
Re: [PATCH 2/2] iommu/amd: Add efr[HATS] max v1 page table level
Posted by Vasant Hegde 7 months, 2 weeks ago
On 4/23/2025 12:20 PM, Ankit Soni wrote:
> The EFR[HATS] bits indicate maximum host translation level supported by
> IOMMU. Adding support to set the maximum host page table level as indicated
> by EFR[HATS]. If the HATS=11b (reserved), the driver will attempt to use
> guest page table for DMA API.
> 
> Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>


Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>

Minor nit.

> ---
>  drivers/iommu/amd/amd_iommu.h       |  1 +
>  drivers/iommu/amd/amd_iommu_types.h |  1 +
>  drivers/iommu/amd/init.c            | 16 ++++++++++++++++
>  drivers/iommu/amd/io_pgtable.c      |  4 ++--
>  drivers/iommu/amd/iommu.c           |  2 +-
>  5 files changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
> index bb14c4800dd0..0286120ad4a5 100644
> --- a/drivers/iommu/amd/amd_iommu.h
> +++ b/drivers/iommu/amd/amd_iommu.h
> @@ -42,6 +42,7 @@ int amd_iommu_enable_faulting(unsigned int cpu);
>  extern int amd_iommu_guest_ir;
>  extern enum protection_domain_mode amd_iommu_pgtable;
>  extern int amd_iommu_gpt_level;
> +extern u8 amd_iommu_hpt_level;
>  extern unsigned long amd_iommu_pgsize_bitmap;
>  extern bool amd_iommu_hatdis;
>  
> diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
> index 284ff4309660..6bf81197c2c8 100644
> --- a/drivers/iommu/amd/amd_iommu_types.h
> +++ b/drivers/iommu/amd/amd_iommu_types.h
> @@ -96,6 +96,7 @@
>  #define FEATURE_GA		BIT_ULL(7)
>  #define FEATURE_HE		BIT_ULL(8)
>  #define FEATURE_PC		BIT_ULL(9)
> +#define FEATURE_HATS		GENMASK_ULL(11, 10)
>  #define FEATURE_GATS		GENMASK_ULL(13, 12)
>  #define FEATURE_GLX		GENMASK_ULL(15, 14)
>  #define FEATURE_GAM_VAPIC	BIT_ULL(21)
> diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
> index f71b236c2af2..c713756fa44e 100644
> --- a/drivers/iommu/amd/init.c
> +++ b/drivers/iommu/amd/init.c
> @@ -152,6 +152,8 @@ bool amd_iommu_dump;
>  bool amd_iommu_irq_remap __read_mostly;
>  
>  enum protection_domain_mode amd_iommu_pgtable = PD_MODE_NONE;
> +/* Host page table level */
> +u8 amd_iommu_hpt_level;
>  /* Guest page table level */
>  int amd_iommu_gpt_level = PAGE_MODE_4_LEVEL;
>  
> @@ -3052,6 +3054,7 @@ static int __init early_amd_iommu_init(void)
>  	struct acpi_table_header *ivrs_base;
>  	int ret;
>  	acpi_status status;
> +	u8 efr_hats;
>  
>  	if (!amd_iommu_detected)
>  		return -ENODEV;
> @@ -3096,6 +3099,19 @@ static int __init early_amd_iommu_init(void)
>  	    FIELD_GET(FEATURE_GATS, amd_iommu_efr) == GUEST_PGTABLE_5_LEVEL)
>  		amd_iommu_gpt_level = PAGE_MODE_5_LEVEL;
>  
> +	efr_hats = FIELD_GET(FEATURE_HATS, amd_iommu_efr);
> +	if (efr_hats != 0x3) {
> +		/*
> +		 * efr[HATS] bits specify the maximum host translation level
> +		 * supported, with LEVEL 4 being initial max level.
> +		 */
> +		amd_iommu_hpt_level = efr_hats + PAGE_MODE_4_LEVEL;
> +	} else {
> +		pr_warn_once("Disable host address translation due to invalid max level (%#x).\n",

s/invalid max level/invalid translation level/

-Vasant
Re: [PATCH 2/2] iommu/amd: Add efr[HATS] max v1 page table level
Posted by Jason Gunthorpe 7 months, 2 weeks ago
On Wed, Apr 30, 2025 at 05:27:10PM +0530, Vasant Hegde wrote:
> > +	efr_hats = FIELD_GET(FEATURE_HATS, amd_iommu_efr);
> > +	if (efr_hats != 0x3) {
> > +		/*
> > +		 * efr[HATS] bits specify the maximum host translation level
> > +		 * supported, with LEVEL 4 being initial max level.
> > +		 */
> > +		amd_iommu_hpt_level = efr_hats + PAGE_MODE_4_LEVEL;
> > +	} else {
> > +		pr_warn_once("Disable host address translation due to invalid max level (%#x).\n",
> 
> s/invalid max level/invalid translation level/

This should have a FW_BUG annotation too?

Jason
Re: [PATCH 2/2] iommu/amd: Add efr[HATS] max v1 page table level
Posted by Vasant Hegde 7 months, 2 weeks ago

On 5/6/2025 8:57 PM, Jason Gunthorpe wrote:
> On Wed, Apr 30, 2025 at 05:27:10PM +0530, Vasant Hegde wrote:
>>> +	efr_hats = FIELD_GET(FEATURE_HATS, amd_iommu_efr);
>>> +	if (efr_hats != 0x3) {
>>> +		/*
>>> +		 * efr[HATS] bits specify the maximum host translation level
>>> +		 * supported, with LEVEL 4 being initial max level.
>>> +		 */
>>> +		amd_iommu_hpt_level = efr_hats + PAGE_MODE_4_LEVEL;
>>> +	} else {
>>> +		pr_warn_once("Disable host address translation due to invalid max level (%#x).\n",
>>
>> s/invalid max level/invalid translation level/
> 
> This should have a FW_BUG annotation too?

Ack. We can add FW_BUG.

-Vasant