mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
iommu/s390: allow larger region tables
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 <mjrosato@linux.ibm.com> Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com> Tested-by: Niklas Schnelle <schnelle@linux.ibm.com> Link: https://lore.kernel.org/r/20250411202433.181683-6-mjrosato@linux.ibm.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
d5fbc5efbd
commit
81244074b5
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user