iommu/s390: support additional table regions
Subsystems (3)
Matthew Rosato
maintainerv5 cover iommu/s390: support additional table regions
The series extends the maximum table size allowed by s390-iommu by increasing the number of table regions supported. It also adds logic to construct the table use the minimum number of regions based upon aperture calculation.
Changes for v5:
- fix GFP_KERNEL under spinlock in patch 5
Changes for v4:
- rebase onto master/merge window
- convert patches 3 per Niklas to remove gotos
- convert patch 4 to also remove gotos
- add review tags
Changes for v3:
- rebase onto iommu-next
- move IOTA region type setting into s390-iommu
- remove origin_type and max_table_size from zdev
- adjust reserved region calculation to be dependent on the domain
Changes for v2:
- rebase onto 6.13
- remove 'iommu/s390: add basic routines for region 1st and 2nd tables' and put routines in first patch that uses each. No functional change.
Matthew Rosato (5):
iommu/s390: set appropriate IOTA region type iommu/s390: support cleanup of additional table regions iommu/s390: support iova_to_phys for additional table regions iommu/s390: support map/unmap for additional table regions iommu/s390: allow larger region tables
arch/s390/include/asm/pci_dma.h | 3 + drivers/iommu/s390-iommu.c | 345 ++++++++++++++++++++++++++++---- 2 files changed, 314 insertions(+), 34 deletions(-)
Signature · 1 line
2.49.0
Matthew Rosato
maintainerPATCH v5 1/5 iommu/s390: set appropriate IOTA region type
When registering the I/O Translation Anchor, use the current table type stored in the s390_domain to set the appropriate region type indication. For the moment, the table type will always be stored as region third.
--- drivers/iommu/s390-iommu.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
drivers/iommu/s390-iommu.c +18 -1
@@ -31,6 +31,7 @@ struct s390_domain {unsigned long *dma_table;spinlock_t list_lock;struct rcu_head rcu; +u8 origin_type; };static struct iommu_domain blocking_domain;
@@ -345,6 +346,7 @@ static struct iommu_domain *s390_domain_alloc_paging(struct device *dev) s390_domain->domain.geometry.force_aperture = true; s390_domain->domain.geometry.aperture_start =0 ; s390_domain->domain.geometry.aperture_end =ZPCI_TABLE_SIZE_RT -1 ; + s390_domain->origin_type =ZPCI_TABLE_TYPE_RTX ;spin_lock_init (&s390_domain->list_lock);INIT_LIST_HEAD_RCU (&s390_domain->devices);
@@ -381,6 +383,21 @@ static void zdev_s390_domain_update(struct zpci_dev *zdev,spin_unlock_irqrestore (&zdev->dom_lock, flags); } +static u64 get_iota_region_flag (struct s390_domain *domain) +{ +switch (domain->origin_type) { +case ZPCI_TABLE_TYPE_RTX : +return ZPCI_IOTA_RTTO_FLAG ; +case ZPCI_TABLE_TYPE_RSX : +return ZPCI_IOTA_RSTO_FLAG ; +case ZPCI_TABLE_TYPE_RFX : +return ZPCI_IOTA_RFTO_FLAG ; +default : +WARN_ONCE (1 ,"Invalid IOMMU table (%x)\n" , domain->origin_type); +return 0 ; + } +} +static int s390_iommu_domain_reg_ioat (struct zpci_dev *zdev,struct iommu_domain *domain,u8 *status) {
@@ -399,7 +416,7 @@ static int s390_iommu_domain_reg_ioat(struct zpci_dev *zdev,default : s390_domain =to_s390_domain (domain); iota =virt_to_phys (s390_domain->dma_table) | -ZPCI_IOTA_RTTO_FLAG ; +get_iota_region_flag (s390_domain); rc =zpci_register_ioat (zdev,0 , zdev->start_dma, zdev->end_dma, iota, status); }
Signature · 1 line
2.49.0
Matthew Rosato
maintainerPATCH v5 2/5 iommu/s390: support cleanup of additional table regions
In reply to Matthew RosatoExtend the existing dma_cleanup_tables to also handle region second and region first tables.
--- drivers/iommu/s390-iommu.c | 71 ++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 7 deletions(-)
drivers/iommu/s390-iommu.c +64 -7
@@ -121,6 +121,22 @@ static inline int pt_entry_isvalid(unsigned long entry)return (entry &ZPCI_PTE_VALID_MASK ) ==ZPCI_PTE_VALID ; } +static inline unsigned long *get_rf_rso (unsigned long entry) +{ +if ((entry &ZPCI_TABLE_TYPE_MASK ) ==ZPCI_TABLE_TYPE_RFX ) +return phys_to_virt (entry &ZPCI_RTE_ADDR_MASK ); +else +return NULL ; +} + +static inline unsigned long *get_rs_rto (unsigned long entry) +{ +if ((entry &ZPCI_TABLE_TYPE_MASK ) ==ZPCI_TABLE_TYPE_RSX ) +return phys_to_virt (entry &ZPCI_RTE_ADDR_MASK ); +else +return NULL ; +} +static inline unsigned long *get_rt_sto (unsigned long entry) {if ((entry &ZPCI_TABLE_TYPE_MASK ) ==ZPCI_TABLE_TYPE_RTX )
@@ -192,18 +208,59 @@ static void dma_free_seg_table(unsigned long entry)dma_free_cpu_table (sto); } -static void dma_cleanup_tables (unsigned long *table) +static void dma_free_rt_table (unsigned long entry) { +unsigned long *rto =get_rs_rto (entry);int rtx; -if (!table) +for (rtx =0 ; rtx <ZPCI_TABLE_ENTRIES ; rtx++) +if (reg_entry_isvalid (rto[rtx])) +dma_free_seg_table (rto[rtx]); + +dma_free_cpu_table (rto); +} + +static void dma_free_rs_table (unsigned long entry) +{ +unsigned long *rso =get_rf_rso (entry); +int rsx; + +for (rsx =0 ; rsx <ZPCI_TABLE_ENTRIES ; rsx++) +if (reg_entry_isvalid (rso[rsx])) +dma_free_rt_table (rso[rsx]); + +dma_free_cpu_table (rso); +} + +static void dma_cleanup_tables (struct s390_domain *domain) +{ +int rtx, rsx, rfx; + +if (!domain->dma_table)return ; -for (rtx =0 ; rtx <ZPCI_TABLE_ENTRIES ; rtx++) -if (reg_entry_isvalid (table[rtx])) -dma_free_seg_table (table[rtx]); +switch (domain->origin_type) { +case ZPCI_TABLE_TYPE_RFX : +for (rfx =0 ; rfx <ZPCI_TABLE_ENTRIES ; rfx++) +if (reg_entry_isvalid (domain->dma_table[rfx])) +dma_free_rs_table (domain->dma_table[rfx]); +break ; +case ZPCI_TABLE_TYPE_RSX : +for (rsx =0 ; rsx <ZPCI_TABLE_ENTRIES ; rsx++) +if (reg_entry_isvalid (domain->dma_table[rsx])) +dma_free_rt_table (domain->dma_table[rsx]); +break ; +case ZPCI_TABLE_TYPE_RTX : +for (rtx =0 ; rtx <ZPCI_TABLE_ENTRIES ; rtx++) +if (reg_entry_isvalid (domain->dma_table[rtx])) +dma_free_seg_table (domain->dma_table[rtx]); +break ; +default : +WARN_ONCE (1 ,"Invalid IOMMU table (%x)\n" , domain->origin_type); +return ; + } -dma_free_cpu_table (table); +dma_free_cpu_table (domain->dma_table); }static unsigned long *dma_alloc_page_table (gfp_t gfp)
@@ -358,7 +415,7 @@ static void s390_iommu_rcu_free_domain(struct rcu_head *head) { struct s390_domain *s390_domain = container_of(head, struct s390_domain, rcu); -dma_cleanup_tables (s390_domain->dma_table); +dma_cleanup_tables (s390_domain);kfree (s390_domain); }
Signature · 1 line
2.49.0
Matthew Rosato
maintainerPATCH v5 3/5 iommu/s390: support iova_to_phys for additional table regions
In reply to Matthew RosatoThe origin_type of the dma_table is used to determine how many table levels must be traversed for the translation.
--- arch/s390/include/asm/pci_dma.h | 2 ++ drivers/iommu/s390-iommu.c | 60 ++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-)
arch/s390/include/asm/pci_dma.h +2 -0
@@ -55,6 +55,8 @@ enum zpci_ioat_dtype {#define ZPCI_PT_BITS 8#define ZPCI_ST_SHIFT (ZPCI_PT_BITS + PAGE_SHIFT)#define ZPCI_RT_SHIFT (ZPCI_ST_SHIFT + ZPCI_TABLE_BITS) +#define ZPCI_RS_SHIFT (ZPCI_RT_SHIFT + ZPCI_TABLE_BITS) +#define ZPCI_RF_SHIFT (ZPCI_RS_SHIFT + ZPCI_TABLE_BITS)#define ZPCI_RTE_FLAG_MASK 0x3fffUL#define ZPCI_RTE_ADDR_MASK (~ZPCI_RTE_FLAG_MASK)
drivers/iommu/s390-iommu.c +59 -1
81 lines not on this page · raw message
Signature · 1 line
2.49.0
Matthew Rosato
maintainerPATCH v5 4/5 iommu/s390: support map/unmap for additional table regions
In reply to Matthew RosatoMap and unmap ops use the shared dma_walk_cpu_trans routine, update this using the origin_type of the dma_table to determine how many table levels must be walked.
--- drivers/iommu/s390-iommu.c | 127 ++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 8 deletions(-)
drivers/iommu/s390-iommu.c +119 -8
@@ -67,6 +67,20 @@ static inline void set_pt_pfaa(unsigned long *entry, phys_addr_t pfaa) *entry |= (pfaa &ZPCI_PTE_ADDR_MASK ); } +static inline void set_rf_rso (unsigned long *entry,phys_addr_t rso) +{ + *entry &=ZPCI_RTE_FLAG_MASK ; + *entry |= (rso &ZPCI_RTE_ADDR_MASK ); + *entry |=ZPCI_TABLE_TYPE_RFX ; +} + +static inline void set_rs_rto (unsigned long *entry,phys_addr_t rto) +{ + *entry &=ZPCI_RTE_FLAG_MASK ; + *entry |= (rto &ZPCI_RTE_ADDR_MASK ); + *entry |=ZPCI_TABLE_TYPE_RSX ; +} +static inline void set_rt_sto (unsigned long *entry,phys_addr_t sto) { *entry &=ZPCI_RTE_FLAG_MASK ;
@@ -81,6 +95,22 @@ static inline void set_st_pto(unsigned long *entry, phys_addr_t pto) *entry |=ZPCI_TABLE_TYPE_SX ; } +static inline void validate_rf_entry (unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_VALID_MASK ; + *entry &= ~ZPCI_TABLE_OFFSET_MASK ; + *entry |=ZPCI_TABLE_VALID ; + *entry |=ZPCI_TABLE_LEN_RFX ; +} + +static inline void validate_rs_entry (unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_VALID_MASK ; + *entry &= ~ZPCI_TABLE_OFFSET_MASK ; + *entry |=ZPCI_TABLE_VALID ; + *entry |=ZPCI_TABLE_LEN_RSX ; +} +static inline void validate_rt_entry (unsigned long *entry) { *entry &= ~ZPCI_TABLE_VALID_MASK ;
@@ -286,6 +316,70 @@ static unsigned long *dma_alloc_page_table(gfp_t gfp)return table; } +static unsigned long *dma_walk_rs_table (unsigned long *rso, +dma_addr_t dma_addr,gfp_t gfp) +{ +unsigned int rsx =calc_rsx (dma_addr); +unsigned long old_rse, rse; +unsigned long *rsep, *rto; + + rsep = &rso[rsx]; + rse =READ_ONCE (*rsep); +if (reg_entry_isvalid (rse)) { + rto =get_rs_rto (rse); + }else { + rto =dma_alloc_cpu_table (gfp); +if (!rto) +return NULL ; + +set_rs_rto (&rse,virt_to_phys (rto)); +validate_rs_entry (&rse); +entry_clr_protected (&rse); + + old_rse =cmpxchg (rsep,ZPCI_TABLE_INVALID , rse); +if (old_rse !=ZPCI_TABLE_INVALID ) { +/* Somone else was faster, use theirs */ +dma_free_cpu_table (rto); + rto =get_rs_rto (old_rse); + } + } +return rto; +} + +static unsigned long *dma_walk_rf_table (unsigned long *rfo, +dma_addr_t dma_addr,gfp_t gfp) +{ +unsigned int rfx =calc_rfx (dma_addr); +unsigned long old_rfe, rfe; +unsigned long *rfep, *rso; + + rfep = &rfo[rfx]; + rfe =READ_ONCE (*rfep); +if (reg_entry_isvalid (rfe)) { + rso =get_rf_rso (rfe); + }else { + rso =dma_alloc_cpu_table (gfp); +if (!rso) +return NULL ; + +set_rf_rso (&rfe,virt_to_phys (rso)); +validate_rf_entry (&rfe); +entry_clr_protected (&rfe); + + old_rfe =cmpxchg (rfep,ZPCI_TABLE_INVALID , rfe); +if (old_rfe !=ZPCI_TABLE_INVALID ) { +/* Somone else was faster, use theirs */ +dma_free_cpu_table (rso); + rso =get_rf_rso (old_rfe); + } + } + +if (!rso) +return NULL ; + +return dma_walk_rs_table (rso, dma_addr, gfp); +} +static unsigned long *dma_get_seg_table_origin (unsigned long *rtep,gfp_t gfp) {unsigned long old_rte, rte;
@@ -339,11 +433,31 @@ static unsigned long *dma_get_page_table_origin(unsigned long *step, gfp_t gfp)return pto; } -static unsigned long *dma_walk_cpu_trans (unsigned long *rto,dma_addr_t dma_addr,gfp_t gfp) +static unsigned long *dma_walk_region_tables (struct s390_domain *domain, +dma_addr_t dma_addr,gfp_t gfp) { -unsigned long *sto, *pto; +switch (domain->origin_type) { +case ZPCI_TABLE_TYPE_RFX : +return dma_walk_rf_table (domain->dma_table, dma_addr, gfp); +case ZPCI_TABLE_TYPE_RSX : +return dma_walk_rs_table (domain->dma_table, dma_addr, gfp); +case ZPCI_TABLE_TYPE_RTX : +return domain->dma_table; +default : +return NULL ; + } +} + +static unsigned long *dma_walk_cpu_trans (struct s390_domain *domain, +dma_addr_t dma_addr,gfp_t gfp) +{ +unsigned long *rto, *sto, *pto;unsigned int rtx, sx, px; + rto =dma_walk_region_tables (domain, dma_addr, gfp); +if (!rto) +return NULL ; + rtx =calc_rtx (dma_addr); sto =dma_get_seg_table_origin (&rto[rtx], gfp);if (!sto)
@@ -690,8 +804,7 @@ static int s390_iommu_validate_trans(struct s390_domain *s390_domain,int rc;for (i =0 ; i < nr_pages; i++) { - entry =dma_walk_cpu_trans (s390_domain->dma_table, dma_addr, - gfp); + entry =dma_walk_cpu_trans (s390_domain, dma_addr, gfp);if (unlikely (!entry)) { rc = -ENOMEM ; goto undo_cpu_trans;
@@ -706,8 +819,7 @@ static int s390_iommu_validate_trans(struct s390_domain *s390_domain, undo_cpu_trans:while (i-- >0 ) { dma_addr -=PAGE_SIZE ; - entry =dma_walk_cpu_trans (s390_domain->dma_table, - dma_addr, gfp); + entry =dma_walk_cpu_trans (s390_domain, dma_addr, gfp);if (!entry)break ;dma_update_cpu_trans (entry,0 ,ZPCI_PTE_INVALID );
@@ -724,8 +836,7 @@ static int s390_iommu_invalidate_trans(struct s390_domain *s390_domain,int rc =0 ;for (i =0 ; i < nr_pages; i++) { - entry =dma_walk_cpu_trans (s390_domain->dma_table, dma_addr, -GFP_ATOMIC ); + entry =dma_walk_cpu_trans (s390_domain, dma_addr,GFP_ATOMIC );if (unlikely (!entry)) { rc = -EINVAL ;break ;
Signature · 1 line
2.49.0
Re: [PATCH v5 4/5] iommu/s390: support map/unmap for additional table regions
Quoted 45 lines · Matthew Rosato
Map and unmap ops use the shared
dma_walk_cpu_transroutine, update this using theorigin_typeof thedma_tableto determine how many table levels must be walked.Signed-off-by Matthew Rosato <[email protected]>--- drivers/iommu/s390-iommu.c | 127 ++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 8 deletions(-)drivers/iommu/s390-iommu.c +21
-0@@ -67,6 +67,20 @@ static inline void set_pt_pfaa(unsigned long *entry, phys_addr_t pfaa) *entry |= (pfaa &ZPCI_PTE_ADDR_MASK ); } +static inline void set_rf_rso (unsigned long *entry,phys_addr_t rso) +{ + *entry &=ZPCI_RTE_FLAG_MASK ; + *entry |= (rso &ZPCI_RTE_ADDR_MASK ); + *entry |=ZPCI_TABLE_TYPE_RFX ; +} + +static inline void set_rs_rto (unsigned long *entry,phys_addr_t rto) +{ + *entry &=ZPCI_RTE_FLAG_MASK ; + *entry |= (rto &ZPCI_RTE_ADDR_MASK ); + *entry |=ZPCI_TABLE_TYPE_RSX ; +} +static inline void set_rt_sto (unsigned long *entry,phys_addr_t sto) { *entry &=ZPCI_RTE_FLAG_MASK ;@@ -81,6 +95,22 @@ static inline void set_st_pto(unsigned long *entry, phys_addr_t pto) *entry |=ZPCI_TABLE_TYPE_SX ; } +static inline void validate_rf_entry (unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_VALID_MASK ; + *entry &= ~ZPCI_TABLE_OFFSET_MASK ; + *entry |=ZPCI_TABLE_VALID ; + *entry |=ZPCI_TABLE_LEN_RFX ; +}
drivers/iommu/s390-iommu.c static inline void set_st_pto(unsigned long *entry, phys_addr_t pto) · line 114
Quoted 10 lines
drivers/iommu/s390-iommu.c +9
-0+ +static inline void validate_rs_entry (unsigned long *entry) +{ + *entry &= ~ZPCI_TABLE_VALID_MASK ; + *entry &= ~ZPCI_TABLE_OFFSET_MASK ; + *entry |=ZPCI_TABLE_VALID ; + *entry |=ZPCI_TABLE_LEN_RSX ; +} +
--- snip ---
Quoted 52 lines
drivers/iommu/s390-iommu.c +24
-6-static unsigned long *dma_walk_cpu_trans (unsigned long *rto,dma_addr_t dma_addr,gfp_t gfp) +static unsigned long *dma_walk_region_tables (struct s390_domain *domain, +dma_addr_t dma_addr,gfp_t gfp) { -unsigned long *sto, *pto; +switch (domain->origin_type) { +case ZPCI_TABLE_TYPE_RFX : +return dma_walk_rf_table (domain->dma_table, dma_addr, gfp); +case ZPCI_TABLE_TYPE_RSX : +return dma_walk_rs_table (domain->dma_table, dma_addr, gfp); +case ZPCI_TABLE_TYPE_RTX : +return domain->dma_table; +default : +return NULL ; + } +} + +static unsigned long *dma_walk_cpu_trans (struct s390_domain *domain, +dma_addr_t dma_addr,gfp_t gfp) +{ +unsigned long *rto, *sto, *pto;unsigned int rtx, sx, px; + rto =dma_walk_region_tables (domain, dma_addr, gfp); +if (!rto) +return NULL ; + rtx =calc_rtx (dma_addr); sto =dma_get_seg_table_origin (&rto[rtx], gfp);if (!sto)@@ -690,8 +804,7 @@ static int s390_iommu_validate_trans(struct s390_domain *s390_domain,int rc;for (i =0 ; i < nr_pages; i++) { - entry =dma_walk_cpu_trans (s390_domain->dma_table, dma_addr, - gfp); + entry =dma_walk_cpu_trans (s390_domain, dma_addr, gfp);if (unlikely (!entry)) { rc = -ENOMEM ; goto undo_cpu_trans;@@ -706,8 +819,7 @@ static int s390_iommu_validate_trans(struct s390_domain *s390_domain, undo_cpu_trans:while (i-- >0 ) { dma_addr -=PAGE_SIZE ; - entry =dma_walk_cpu_trans (s390_domain->dma_table, - dma_addr, gfp); + entry =dma_walk_cpu_trans (s390_domain, dma_addr, gfp);if (!entry)break ;dma_update_cpu_trans (entry,0 ,ZPCI_PTE_INVALID );
drivers/iommu/s390-iommu.c static int s390_iommu_invalidate_trans(struct s390_domain *s390_domain, · line 842
Quoted 9 lines
drivers/iommu/s390-iommu.c +1
-2@@ -724,8 +836,7 @@ static int s390_iommu_invalidate_trans(struct s390_domain *s390_domain,int rc =0 ;for (i =0 ; i < nr_pages; i++) { - entry =dma_walk_cpu_trans (s390_domain->dma_table, dma_addr, -GFP_ATOMIC ); + entry =dma_walk_cpu_trans (s390_domain, dma_addr,GFP_ATOMIC );if (unlikely (!entry)) { rc = -EINVAL ;break ;
Looks good to me and we even get nicer formatting :)
Matthew Rosato
maintainerPATCH v5 5/5 iommu/s390: allow larger region tables
In reply to Matthew RosatoExtend the aperture calculation to consider sizes beyond the maximum size of a region third table. Attempt to always use the smallest table size possible to avoid unnecessary extra steps during translation. Update reserved region calculations to use the appropriate table size.
--- arch/s390/include/asm/pci_dma.h | 1 + drivers/iommu/s390-iommu.c | 70 ++++++++++++++++++++++++--------- 2 files changed, 53 insertions(+), 18 deletions(-)
arch/s390/include/asm/pci_dma.h +1 -0
@@ -25,6 +25,7 @@ enum zpci_ioat_dtype {#define ZPCI_KEY (PAGE_DEFAULT_KEY << 5)#define ZPCI_TABLE_SIZE_RT (1UL << 42) +#define ZPCI_TABLE_SIZE_RS (1UL << 53)#define ZPCI_IOTA_STO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)#define ZPCI_IOTA_RTTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
drivers/iommu/s390-iommu.c +52 -18
119 lines not on this page · raw message
Signature · 1 line
2.49.0
Re: [PATCH v5 5/5] iommu/s390: allow larger region tables
Quoted 143 lines · Matthew Rosato
Extend the aperture calculation to consider sizes beyond the maximum size of a region third table. Attempt to always use the smallest table size possible to avoid unnecessary extra steps during translation. Update reserved region calculations to use the appropriate table size.
Signed-off-by Matthew Rosato <[email protected]>--- arch/s390/include/asm/pci_dma.h | 1 + drivers/iommu/s390-iommu.c | 70 ++++++++++++++++++++++++--------- 2 files changed, 53 insertions(+), 18 deletions(-)arch/s390/include/asm/pci_dma.h +1
-0@@ -25,6 +25,7 @@ enum zpci_ioat_dtype {#define ZPCI_KEY (PAGE_DEFAULT_KEY << 5)#define ZPCI_TABLE_SIZE_RT (1UL << 42) +#define ZPCI_TABLE_SIZE_RS (1UL << 53)#define ZPCI_IOTA_STO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)#define ZPCI_IOTA_RTTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)drivers/iommu/s390-iommu.c +52
-12@@ -511,9 +511,25 @@ static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap) } } +static inline u64 max_tbl_size (struct s390_domain *domain) +{ +switch (domain->origin_type) { +case ZPCI_TABLE_TYPE_RTX : +return ZPCI_TABLE_SIZE_RT -1 ; +case ZPCI_TABLE_TYPE_RSX : +return ZPCI_TABLE_SIZE_RS -1 ; +case ZPCI_TABLE_TYPE_RFX : +return U64_MAX ; +default : +return 0 ; + } +} +static struct iommu_domain *s390_domain_alloc_paging (struct device *dev) { +struct zpci_dev *zdev =to_zpci_dev (dev);struct s390_domain *s390_domain; +u64 aperture_size; s390_domain =kzalloc (sizeof (*s390_domain),GFP_KERNEL );if (!s390_domain)@@ -524,10 +540,26 @@ static struct iommu_domain *s390_domain_alloc_paging(struct device *dev)kfree (s390_domain);return NULL ; } + + aperture_size =min (s390_iommu_aperture, + zdev->end_dma - zdev->start_dma +1 ); +if (aperture_size <= (ZPCI_TABLE_SIZE_RT - zdev->start_dma)) { + s390_domain->origin_type =ZPCI_TABLE_TYPE_RTX ; + }else if (aperture_size <= (ZPCI_TABLE_SIZE_RS - zdev->start_dma) && + (zdev->dtsm &ZPCI_IOTA_DT_RS )) { + s390_domain->origin_type =ZPCI_TABLE_TYPE_RSX ; + }else if (zdev->dtsm &ZPCI_IOTA_DT_RF ) { + s390_domain->origin_type =ZPCI_TABLE_TYPE_RFX ; + }else { +/* Assume RTX available */ + s390_domain->origin_type =ZPCI_TABLE_TYPE_RTX ; + aperture_size =ZPCI_TABLE_SIZE_RT - zdev->start_dma; + } + zdev->end_dma = zdev->start_dma + aperture_size -1 ; + s390_domain->domain.geometry.force_aperture = true; s390_domain->domain.geometry.aperture_start =0 ; - s390_domain->domain.geometry.aperture_end =ZPCI_TABLE_SIZE_RT -1 ; - s390_domain->origin_type =ZPCI_TABLE_TYPE_RTX ; + s390_domain->domain.geometry.aperture_end =max_tbl_size (s390_domain);spin_lock_init (&s390_domain->list_lock);INIT_LIST_HEAD_RCU (&s390_domain->devices);@@ -680,6 +712,8 @@ static void s390_iommu_get_resv_regions(struct device *dev, {struct zpci_dev *zdev =to_zpci_dev (dev);struct iommu_resv_region *region; +u64 max_size, end_resv; +unsigned long flags;if (zdev->start_dma) { region = iommu_alloc_resv_region(0, zdev->start_dma, 0,@@ -689,10 +723,21 @@ static void s390_iommu_get_resv_regions(struct device *dev,list_add_tail (®ion->list, list); } -if (zdev->end_dma <ZPCI_TABLE_SIZE_RT -1 ) { - region =iommu_alloc_resv_region (zdev->end_dma +1 , -ZPCI_TABLE_SIZE_RT - zdev->end_dma -1 , -0 ,IOMMU_RESV_RESERVED ,GFP_KERNEL ); +spin_lock_irqsave (&zdev->dom_lock, flags); +if (zdev->s390_domain->type ==IOMMU_DOMAIN_BLOCKED || + zdev->s390_domain->type ==IOMMU_DOMAIN_IDENTITY ) { +spin_unlock_irqrestore (&zdev->dom_lock, flags); +return ; + } + + max_size =max_tbl_size (to_s390_domain (zdev->s390_domain)); +spin_unlock_irqrestore (&zdev->dom_lock, flags); + +if (zdev->end_dma < max_size) { + end_resv = max_size - zdev->end_dma; + region =iommu_alloc_resv_region (zdev->end_dma +1 , end_resv, +0 ,IOMMU_RESV_RESERVED , +GFP_KERNEL );if (!region)return ;list_add_tail (®ion->list, list);@@ -708,13 +753,9 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev) zdev =to_zpci_dev (dev); -if (zdev->start_dma > zdev->end_dma || - zdev->start_dma >ZPCI_TABLE_SIZE_RT -1 ) +if (zdev->start_dma > zdev->end_dma)return ERR_PTR (-EINVAL ); -if (zdev->end_dma >ZPCI_TABLE_SIZE_RT -1 ) - zdev->end_dma =ZPCI_TABLE_SIZE_RT -1 ; -if (zdev->tlb_refresh) dev->iommu->shadow_on_flush =1 ;@@ -999,7 +1040,6 @@ struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev)int zpci_init_iommu (struct zpci_dev *zdev) { -u64 aperture_size;int rc =0 ; rc = iommu_device_sysfs_add(&zdev->iommu_dev, NULL, NULL,@@ -1017,12 +1057,6 @@ int zpci_init_iommu(struct zpci_dev *zdev)if (rc) goto out_sysfs;
drivers/iommu/s390-iommu.c int zpci_init_iommu(struct zpci_dev *zdev) · line 1062
Quoted 10 lines
drivers/iommu/s390-iommu.c +0
-6- zdev->start_dma =PAGE_ALIGN (zdev->start_dma); - aperture_size =min3 (s390_iommu_aperture, -ZPCI_TABLE_SIZE_RT - zdev->start_dma, - zdev->end_dma - zdev->start_dma +1 ); - zdev->end_dma = zdev->start_dma + aperture_size -1 ; -return 0 ; out_sysfs:
Looks good, thanks for the great work!
Quoted 32 lines · Matthew Rosato
The series extends the maximum table size allowed by s390-iommu by increasing the number of table regions supported. It also adds logic to construct the table use the minimum number of regions based upon aperture calculation.
Changes for v5:
- fixGFP_KERNELunder spinlock in patch 5Changes for v4:
- rebase onto master/merge window
- convert patches 3 per Niklas to remove gotos
- convert patch 4 to also remove gotos
- add review tagsChanges for v3:
- rebase onto iommu-next
- move IOTA region type setting into s390-iommu
- removeorigin_typeandmax_table_sizefrom zdev
- adjust reserved region calculation to be dependent on the domainChanges for v2:
- rebase onto 6.13
- remove 'iommu/s390: add basic routines for region 1st and 2nd tables' and put routines in first patch that uses each. No functional change.Matthew Rosato (5):
iommu/s390: set appropriate IOTA region type iommu/s390: support cleanup of additional table regions iommu/s390: supportiova_to_physfor additional table regions iommu/s390: support map/unmap for additional table regions iommu/s390: allow larger region tables
Quoted 4 lines
arch/s390/include/asm/pci_dma.h | 3 + drivers/iommu/s390-iommu.c | 345 ++++++++++++++++++++++++++++---- 2 files changed, 314 insertions(+), 34 deletions(-)
I gave this v5 another test run with it applied atop v6.15-rc2. I used an LPAR with 11 TB of memory and 2 KVM guests each with 5 TB. The guests use iommu.passthrough=1 and have NIC VFs from the same card passed-through. With such large sizes we really need the newly supported table types. For good measure, I also used the PCI transport for the virtio-net NIC.
Traffic between the passed-through VFs works great. Feel free to add:
Quoted 10 lines · Matthew Rosato
Matthew Rosato (5):
iommu/s390: set appropriate IOTA region type iommu/s390: support cleanup of additional table regions iommu/s390: supportiova_to_physfor additional table regions iommu/s390: support map/unmap for additional table regions iommu/s390: allow larger region tablesarch/s390/include/asm/pci_dma.h | 3 + drivers/iommu/s390-iommu.c | 345 ++++++++++++++++++++++++++++---- 2 files changed, 314 insertions(+), 34 deletions(-)
Applied, thanks.