[PATCH v3 RESEND 35/35] iommu/amd: Update amd_iommu_fault structure to include PCI seg ID

2022-07-06 Thread Vasant Hegde via iommu
Rename 'device_id' as 'sbdf' and extend it to 32bit so that we can
pass PCI segment ID to ppr_notifier(). Also pass PCI segment ID to
pci_get_domain_bus_and_slot() instead of default value.

Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 2 +-
 drivers/iommu/amd/iommu.c   | 2 +-
 drivers/iommu/amd/iommu_v2.c| 9 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 1ca54803702a..40f52d02c5b9 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -486,7 +486,7 @@ extern struct kmem_cache *amd_iommu_irq_cache;
 struct amd_iommu_fault {
u64 address;/* IO virtual address of the fault*/
u32 pasid;  /* Address space identifier */
-   u16 device_id;  /* Originating PCI device id */
+   u32 sbdf;   /* Originating PCI device id */
u16 tag;/* PPR tag */
u16 flags;  /* Fault flags */
 
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 6a1db8f9f453..a56a9ad3273e 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -701,7 +701,7 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, 
u64 *raw)
 
fault.address   = raw[1];
fault.pasid = PPR_PASID(raw[0]);
-   fault.device_id = PPR_DEVID(raw[0]);
+   fault.sbdf  = PCI_SEG_DEVID_TO_SBDF(iommu->pci_seg->id, 
PPR_DEVID(raw[0]));
fault.tag   = PPR_TAG(raw[0]);
fault.flags = PPR_FLAGS(raw[0]);
 
diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index 40484af2ffc2..696dbe57 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -518,15 +518,16 @@ static int ppr_notifier(struct notifier_block *nb, 
unsigned long e, void *data)
unsigned long flags;
struct fault *fault;
bool finish;
-   u16 tag, devid;
+   u16 tag, devid, seg_id;
int ret;
 
iommu_fault = data;
tag = iommu_fault->tag & 0x1ff;
finish  = (iommu_fault->tag >> 9) & 1;
 
-   devid = iommu_fault->device_id;
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   seg_id = PCI_SBDF_TO_SEGID(iommu_fault->sbdf);
+   devid = PCI_SBDF_TO_DEVID(iommu_fault->sbdf);
+   pdev = pci_get_domain_bus_and_slot(seg_id, PCI_BUS_NUM(devid),
   devid & 0xff);
if (!pdev)
return -ENODEV;
@@ -540,7 +541,7 @@ static int ppr_notifier(struct notifier_block *nb, unsigned 
long e, void *data)
goto out;
}
 
-   dev_state = get_device_state(iommu_fault->device_id);
+   dev_state = get_device_state(iommu_fault->sbdf);
if (dev_state == NULL)
goto out;
 
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 34/35] iommu/amd: Update device_state structure to include PCI seg ID

2022-07-06 Thread Vasant Hegde via iommu
Rename struct device_state.devid variable to struct device_state.sbdf
and extend it to 32-bit to include the 16-bit PCI segment ID via
the helper function get_pci_sbdf_id().

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu_v2.c | 58 +++-
 1 file changed, 24 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index afb3efd565b7..40484af2ffc2 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -51,7 +51,7 @@ struct pasid_state {
 
 struct device_state {
struct list_head list;
-   u16 devid;
+   u32 sbdf;
atomic_t count;
struct pci_dev *pdev;
struct pasid_state **states;
@@ -83,35 +83,25 @@ static struct workqueue_struct *iommu_wq;
 
 static void free_pasid_states(struct device_state *dev_state);
 
-static u16 device_id(struct pci_dev *pdev)
-{
-   u16 devid;
-
-   devid = pdev->bus->number;
-   devid = (devid << 8) | pdev->devfn;
-
-   return devid;
-}
-
-static struct device_state *__get_device_state(u16 devid)
+static struct device_state *__get_device_state(u32 sbdf)
 {
struct device_state *dev_state;
 
list_for_each_entry(dev_state, _list, list) {
-   if (dev_state->devid == devid)
+   if (dev_state->sbdf == sbdf)
return dev_state;
}
 
return NULL;
 }
 
-static struct device_state *get_device_state(u16 devid)
+static struct device_state *get_device_state(u32 sbdf)
 {
struct device_state *dev_state;
unsigned long flags;
 
spin_lock_irqsave(_lock, flags);
-   dev_state = __get_device_state(devid);
+   dev_state = __get_device_state(sbdf);
if (dev_state != NULL)
atomic_inc(_state->count);
spin_unlock_irqrestore(_lock, flags);
@@ -609,7 +599,7 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
struct pasid_state *pasid_state;
struct device_state *dev_state;
struct mm_struct *mm;
-   u16 devid;
+   u32 sbdf;
int ret;
 
might_sleep();
@@ -617,8 +607,8 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
if (!amd_iommu_v2_supported())
return -ENODEV;
 
-   devid = device_id(pdev);
-   dev_state = get_device_state(devid);
+   sbdf  = get_pci_sbdf_id(pdev);
+   dev_state = get_device_state(sbdf);
 
if (dev_state == NULL)
return -EINVAL;
@@ -692,15 +682,15 @@ void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 
pasid)
 {
struct pasid_state *pasid_state;
struct device_state *dev_state;
-   u16 devid;
+   u32 sbdf;
 
might_sleep();
 
if (!amd_iommu_v2_supported())
return;
 
-   devid = device_id(pdev);
-   dev_state = get_device_state(devid);
+   sbdf = get_pci_sbdf_id(pdev);
+   dev_state = get_device_state(sbdf);
if (dev_state == NULL)
return;
 
@@ -742,7 +732,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
struct iommu_group *group;
unsigned long flags;
int ret, tmp;
-   u16 devid;
+   u32 sbdf;
 
might_sleep();
 
@@ -759,7 +749,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
if (pasids <= 0 || pasids > (PASID_MASK + 1))
return -EINVAL;
 
-   devid = device_id(pdev);
+   sbdf = get_pci_sbdf_id(pdev);
 
dev_state = kzalloc(sizeof(*dev_state), GFP_KERNEL);
if (dev_state == NULL)
@@ -768,7 +758,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
spin_lock_init(_state->lock);
init_waitqueue_head(_state->wq);
dev_state->pdev  = pdev;
-   dev_state->devid = devid;
+   dev_state->sbdf = sbdf;
 
tmp = pasids;
for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9)
@@ -806,7 +796,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 
spin_lock_irqsave(_lock, flags);
 
-   if (__get_device_state(devid) != NULL) {
+   if (__get_device_state(sbdf) != NULL) {
spin_unlock_irqrestore(_lock, flags);
ret = -EBUSY;
goto out_free_domain;
@@ -838,16 +828,16 @@ void amd_iommu_free_device(struct pci_dev *pdev)
 {
struct device_state *dev_state;
unsigned long flags;
-   u16 devid;
+   u32 sbdf;
 
if (!amd_iommu_v2_supported())
return;
 
-   devid = device_id(pdev);
+   sbdf = get_pci_sbdf_id(pdev);
 
spin_lock_irqsave(_lock, flags);
 
-   dev_state = __get_device_state(devid);
+   dev_state = __get_device_state(sbdf);
if (dev_state == NULL) {
spin_unlock_irqrestore(_lock, flags);
return;
@@ -867,18 +857,18 @@ int 

[PATCH v3 RESEND 33/35] iommu/amd: Print PCI segment ID in error log messages

2022-07-06 Thread Vasant Hegde via iommu
Print pci segment ID along with bdf. Useful for debugging.

Co-developed-by: Suravee Suthikulpaint 
Signed-off-by: Suravee Suthikulpaint 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/init.c  | 10 +-
 drivers/iommu/amd/iommu.c | 36 ++--
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 9b1026fa7283..3c82d9c5f1c0 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1855,11 +1855,11 @@ static int __init init_iommu_all(struct 
acpi_table_header *table)
h = (struct ivhd_header *)p;
if (*p == amd_iommu_target_ivhd_type) {
 
-   DUMP_printk("device: %02x:%02x.%01x cap: %04x "
-   "seg: %d flags: %01x info %04x\n",
-   PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
-   PCI_FUNC(h->devid), h->cap_ptr,
-   h->pci_seg, h->flags, h->info);
+   DUMP_printk("device: %04x:%02x:%02x.%01x cap: %04x "
+   "flags: %01x info %04x\n",
+   h->pci_seg, PCI_BUS_NUM(h->devid),
+   PCI_SLOT(h->devid), PCI_FUNC(h->devid),
+   h->cap_ptr, h->flags, h->info);
DUMP_printk("   mmio-addr: %016llx\n",
h->mmio_phys);
 
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 2dbe17e49ffc..6a1db8f9f453 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -496,8 +496,8 @@ static void amd_iommu_report_rmp_hw_error(struct amd_iommu 
*iommu, volatile u32
vmg_tag, spa, flags);
}
} else {
-   pr_err_ratelimited("Event logged [RMP_HW_ERROR 
device=%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [RMP_HW_ERROR 
device=%04x:%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
vmg_tag, spa, flags);
}
 
@@ -529,8 +529,8 @@ static void amd_iommu_report_rmp_fault(struct amd_iommu 
*iommu, volatile u32 *ev
vmg_tag, gpa, flags_rmp, flags);
}
} else {
-   pr_err_ratelimited("Event logged [RMP_PAGE_FAULT 
device=%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, 
flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [RMP_PAGE_FAULT 
device=%04x:%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, 
flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
vmg_tag, gpa, flags_rmp, flags);
}
 
@@ -576,8 +576,8 @@ static void amd_iommu_report_page_fault(struct amd_iommu 
*iommu,
domain_id, address, flags);
}
} else {
-   pr_err_ratelimited("Event logged [IO_PAGE_FAULT 
device=%02x:%02x.%x domain=0x%04x address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [IO_PAGE_FAULT 
device=%04x:%02x:%02x.%x domain=0x%04x address=0x%llx flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
domain_id, address, flags);
}
 
@@ -620,20 +620,20 @@ static void iommu_print_event(struct amd_iommu *iommu, 
void *__evt)
 
switch (type) {
case EVENT_TYPE_ILL_DEV:
-   dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%04x:%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
pasid, address, flags);
dump_dte_entry(iommu, devid);
break;
case EVENT_TYPE_DEV_TAB_ERR:
-   dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%02x:%02x.%x "
+   dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%04x:%02x:%02x.%x "
"address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 

[PATCH v3 RESEND 32/35] iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

By default, PCI segment is zero and can be omitted. To support system
with non-zero PCI segment ID, modify the parsing functions to allow
PCI segment ID.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 .../admin-guide/kernel-parameters.txt | 34 ++
 drivers/iommu/amd/init.c  | 44 ---
 2 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index 2522b11e593f..d45e58328ce6 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2266,23 +2266,39 @@
 
ivrs_ioapic [HW,X86-64]
Provide an override to the IOAPIC-ID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map IOAPIC-ID decimal 10 to
-   PCI device 00:14.0 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+   By default, PCI segment is 0, and can be omitted.
+   For example:
+   * To map IOAPIC-ID decimal 10 to PCI device 00:14.0
+ write the parameter as:
ivrs_ioapic[10]=00:14.0
+   * To map IOAPIC-ID decimal 10 to PCI segment 0x1 and
+ PCI device 00:14.0 write the parameter as:
+   ivrs_ioapic[10]=0001:00:14.0
 
ivrs_hpet   [HW,X86-64]
Provide an override to the HPET-ID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map HPET-ID decimal 0 to
-   PCI device 00:14.0 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+   By default, PCI segment is 0, and can be omitted.
+   For example:
+   * To map HPET-ID decimal 0 to PCI device 00:14.0
+ write the parameter as:
ivrs_hpet[0]=00:14.0
+   * To map HPET-ID decimal 10 to PCI segment 0x1 and
+ PCI device 00:14.0 write the parameter as:
+   ivrs_ioapic[10]=0001:00:14.0
 
ivrs_acpihid[HW,X86-64]
Provide an override to the ACPI-HID:UID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map UART-HID:UID AMD0020:0 to
-   PCI device 00:14.5 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+
+   For example, to map UART-HID:UID AMD0020:0 to
+   PCI segment 0x1 and PCI device ID 00:14.5,
+   write the parameter as:
+   ivrs_acpihid[0001:00:14.5]=AMD0020:0
+
+   By default, PCI segment is 0, and can be omitted.
+   For example, PCI device 00:14.5 write the parameter as:
ivrs_acpihid[00:14.5]=AMD0020:0
 
js= [HW,JOY] Analog joystick
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 9693f0b9e07a..9b1026fa7283 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -84,6 +84,10 @@
 #define ACPI_DEVFLAG_ATSDIS 0x1000
 
 #define LOOP_TIMEOUT   200
+
+#define IVRS_GET_SBDF_ID(seg, bus, dev, fd)(((seg & 0x) << 16) | ((bus 
& 0xff) << 8) \
+| ((dev & 0x1f) << 3) | (fn & 
0x7))
+
 /*
  * ACPI table definitions
  *
@@ -3288,15 +3292,17 @@ static int __init parse_amd_iommu_options(char *str)
 
 static int __init parse_ivrs_ioapic(char *str)
 {
-   unsigned int bus, dev, fn;
+   u32 seg = 0, bus, dev, fn;
int ret, id, i;
-   u16 devid;
+   u32 devid;
 
ret = sscanf(str, "[%d]=%x:%x.%x", , , , );
-
if (ret != 4) {
-   pr_err("Invalid command line: ivrs_ioapic%s\n", str);
-   return 1;
+   ret = sscanf(str, "[%d]=%x:%x:%x.%x", , , , , 
);
+   if (ret != 5) {
+   pr_err("Invalid command line: ivrs_ioapic%s\n", str);
+   return 1;
+   }
}
 
if (early_ioapic_map_size == EARLY_MAP_SIZE) {
@@ -3305,7 +3311,7 @@ static int __init parse_ivrs_ioapic(char *str)
return 1;
}
 
-   devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+   devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn);
 
cmdline_maps= true;
i   = early_ioapic_map_size++;
@@ -3318,15 

[PATCH v3 RESEND 31/35] iommu/amd: Specify PCI segment ID when getting pci device

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Upcoming AMD systems can have multiple PCI segments. Hence pass PCI
segment ID to pci_get_domain_bus_and_slot() instead of '0'.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/init.c  |  6 --
 drivers/iommu/amd/iommu.c | 19 ++-
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index d35081d84460..9693f0b9e07a 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1962,7 +1962,8 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
int cap_ptr = iommu->cap_ptr;
int ret;
 
-   iommu->dev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(iommu->devid),
+   iommu->dev = pci_get_domain_bus_and_slot(iommu->pci_seg->id,
+PCI_BUS_NUM(iommu->devid),
 iommu->devid & 0xff);
if (!iommu->dev)
return -ENODEV;
@@ -2025,7 +2026,8 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
int i, j;
 
iommu->root_pdev =
-   pci_get_domain_bus_and_slot(0, iommu->dev->bus->number,
+   pci_get_domain_bus_and_slot(iommu->pci_seg->id,
+   iommu->dev->bus->number,
PCI_DEVFN(0, 0));
 
/*
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 0751dda04a10..2dbe17e49ffc 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -473,7 +473,7 @@ static void dump_command(unsigned long phys_addr)
pr_err("CMD[%d]: %08x\n", i, cmd->data[i]);
 }
 
-static void amd_iommu_report_rmp_hw_error(volatile u32 *event)
+static void amd_iommu_report_rmp_hw_error(struct amd_iommu *iommu, volatile 
u32 *event)
 {
struct iommu_dev_data *dev_data = NULL;
int devid, vmg_tag, flags;
@@ -485,7 +485,7 @@ static void amd_iommu_report_rmp_hw_error(volatile u32 
*event)
flags   = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
spa = ((u64)event[3] << 32) | (event[2] & 0xFFF8);
 
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, 
PCI_BUS_NUM(devid),
   devid & 0xff);
if (pdev)
dev_data = dev_iommu_priv_get(>dev);
@@ -505,7 +505,7 @@ static void amd_iommu_report_rmp_hw_error(volatile u32 
*event)
pci_dev_put(pdev);
 }
 
-static void amd_iommu_report_rmp_fault(volatile u32 *event)
+static void amd_iommu_report_rmp_fault(struct amd_iommu *iommu, volatile u32 
*event)
 {
struct iommu_dev_data *dev_data = NULL;
int devid, flags_rmp, vmg_tag, flags;
@@ -518,7 +518,7 @@ static void amd_iommu_report_rmp_fault(volatile u32 *event)
flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
gpa   = ((u64)event[3] << 32) | event[2];
 
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, 
PCI_BUS_NUM(devid),
   devid & 0xff);
if (pdev)
dev_data = dev_iommu_priv_get(>dev);
@@ -544,13 +544,14 @@ static void amd_iommu_report_rmp_fault(volatile u32 
*event)
 #define IS_WRITE_REQUEST(flags)\
((flags) & EVENT_FLAG_RW)
 
-static void amd_iommu_report_page_fault(u16 devid, u16 domain_id,
+static void amd_iommu_report_page_fault(struct amd_iommu *iommu,
+   u16 devid, u16 domain_id,
u64 address, int flags)
 {
struct iommu_dev_data *dev_data = NULL;
struct pci_dev *pdev;
 
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, 
PCI_BUS_NUM(devid),
   devid & 0xff);
if (pdev)
dev_data = dev_iommu_priv_get(>dev);
@@ -613,7 +614,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void 
*__evt)
}
 
if (type == EVENT_TYPE_IO_FAULT) {
-   amd_iommu_report_page_fault(devid, pasid, address, flags);
+   amd_iommu_report_page_fault(iommu, devid, pasid, address, 
flags);
return;
}
 
@@ -654,10 +655,10 @@ static void iommu_print_event(struct amd_iommu *iommu, 
void *__evt)
pasid, address, flags);
break;
case EVENT_TYPE_RMP_FAULT:
-   amd_iommu_report_rmp_fault(event);
+   amd_iommu_report_rmp_fault(iommu, event);
break;
case EVENT_TYPE_RMP_HW_ERR:
-   amd_iommu_report_rmp_hw_error(event);
+   

[PATCH v3 RESEND 30/35] iommu/amd: Include PCI segment ID when initialize IOMMU

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Extend current device ID variables to 32-bit to include the 16-bit
segment ID when parsing device information from IVRS table to initialize
each IOMMU.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  2 +-
 drivers/iommu/amd/amd_iommu_types.h |  6 ++--
 drivers/iommu/amd/init.c| 56 +++--
 drivers/iommu/amd/quirks.c  |  4 +--
 4 files changed, 35 insertions(+), 33 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index e73bd48fc716..9b7092182ca7 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -125,7 +125,7 @@ static inline int get_pci_sbdf_id(struct pci_dev *pdev)
 
 extern bool translation_pre_enabled(struct amd_iommu *iommu);
 extern bool amd_iommu_is_attach_deferred(struct device *dev);
-extern int __init add_special_device(u8 type, u8 id, u16 *devid,
+extern int __init add_special_device(u8 type, u8 id, u32 *devid,
 bool cmd_line);
 
 #ifdef CONFIG_DMI
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index ea238e8e6c99..1ca54803702a 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -744,8 +744,8 @@ struct acpihid_map_entry {
struct list_head list;
u8 uid[ACPIHID_UID_LEN];
u8 hid[ACPIHID_HID_LEN];
-   u16 devid;
-   u16 root_devid;
+   u32 devid;
+   u32 root_devid;
bool cmd_line;
struct iommu_group *group;
 };
@@ -753,7 +753,7 @@ struct acpihid_map_entry {
 struct devid_map {
struct list_head list;
u8 id;
-   u16 devid;
+   u32 devid;
bool cmd_line;
 };
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index df8f4b9d20cd..d35081d84460 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1148,7 +1148,7 @@ static void __init set_dev_entry_from_acpi(struct 
amd_iommu *iommu,
amd_iommu_set_rlookup_table(iommu, devid);
 }
 
-int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
+int __init add_special_device(u8 type, u8 id, u32 *devid, bool cmd_line)
 {
struct devid_map *entry;
struct list_head *list;
@@ -1185,7 +1185,7 @@ int __init add_special_device(u8 type, u8 id, u16 *devid, 
bool cmd_line)
return 0;
 }
 
-static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u16 *devid,
+static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u32 *devid,
  bool cmd_line)
 {
struct acpihid_map_entry *entry;
@@ -1264,7 +1264,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 {
u8 *p = (u8 *)h;
u8 *end = p, flags = 0;
-   u16 devid = 0, devid_start = 0, devid_to = 0;
+   u16 devid = 0, devid_start = 0, devid_to = 0, seg_id;
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
@@ -1300,6 +1300,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 
while (p < end) {
e = (struct ivhd_entry *)p;
+   seg_id = pci_seg->id;
+
switch (e->type) {
case IVHD_DEV_ALL:
 
@@ -1310,9 +1312,9 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
break;
case IVHD_DEV_SELECT:
 
-   DUMP_printk("  DEV_SELECT\t\t\t devid: %02x:%02x.%x "
+   DUMP_printk("  DEV_SELECT\t\t\t devid: 
%04x:%02x:%02x.%x "
"flags: %02x\n",
-   PCI_BUS_NUM(e->devid),
+   seg_id, PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags);
@@ -1323,8 +1325,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
case IVHD_DEV_SELECT_RANGE_START:
 
DUMP_printk("  DEV_SELECT_RANGE_START\t "
-   "devid: %02x:%02x.%x flags: %02x\n",
-   PCI_BUS_NUM(e->devid),
+   "devid: %04x:%02x:%02x.%x flags: %02x\n",
+   seg_id, PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags);
@@ -1336,9 +1338,9 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
break;
case IVHD_DEV_ALIAS:
 
-   DUMP_printk("  DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
+   DUMP_printk("  DEV_ALIAS\t\t\t devid: %04x:%02x:%02x.%x 
"
"flags: 

[PATCH v3 RESEND 29/35] iommu/amd: Introduce get_device_sbdf_id() helper function

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Current get_device_id() only provide 16-bit PCI device ID (i.e. BDF).
With multiple PCI segment support, we need to extend the helper function
to include PCI segment ID.

So, introduce a new helper function get_device_sbdf_id() to replace
the current get_pci_device_id().

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  7 
 drivers/iommu/amd/amd_iommu_types.h |  2 +
 drivers/iommu/amd/iommu.c   | 58 ++---
 3 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 64c954e168d7..e73bd48fc716 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -115,6 +115,13 @@ void amd_iommu_domain_clr_pt_root(struct protection_domain 
*domain)
amd_iommu_domain_set_pt_root(domain, 0);
 }
 
+static inline int get_pci_sbdf_id(struct pci_dev *pdev)
+{
+   int seg = pci_domain_nr(pdev->bus);
+   u16 devid = pci_dev_id(pdev);
+
+   return PCI_SEG_DEVID_TO_SBDF(seg, devid);
+}
 
 extern bool translation_pre_enabled(struct amd_iommu *iommu);
 extern bool amd_iommu_is_attach_deferred(struct device *dev);
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 65b02e2ae28f..ea238e8e6c99 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -456,6 +456,8 @@ extern struct kmem_cache *amd_iommu_irq_cache;
 
 #define PCI_SBDF_TO_SEGID(sbdf)(((sbdf) >> 16) & 0x)
 #define PCI_SBDF_TO_DEVID(sbdf)((sbdf) & 0x)
+#define PCI_SEG_DEVID_TO_SBDF(seg, devid)  u32)(seg) & 0x) << 16) 
| \
+((devid) & 0x))
 
 /* Make iterating over all pci segment easier */
 #define for_each_pci_segment(pci_seg) \
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 6914911d4fb6..0751dda04a10 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -92,13 +92,6 @@ static void detach_device(struct device *dev);
  *
  /
 
-static inline u16 get_pci_device_id(struct device *dev)
-{
-   struct pci_dev *pdev = to_pci_dev(dev);
-
-   return pci_dev_id(pdev);
-}
-
 static inline int get_acpihid_device_id(struct device *dev,
struct acpihid_map_entry **entry)
 {
@@ -119,16 +112,16 @@ static inline int get_acpihid_device_id(struct device 
*dev,
return -EINVAL;
 }
 
-static inline int get_device_id(struct device *dev)
+static inline int get_device_sbdf_id(struct device *dev)
 {
-   int devid;
+   int sbdf;
 
if (dev_is_pci(dev))
-   devid = get_pci_device_id(dev);
+   sbdf = get_pci_sbdf_id(to_pci_dev(dev));
else
-   devid = get_acpihid_device_id(dev, NULL);
+   sbdf = get_acpihid_device_id(dev, NULL);
 
-   return devid;
+   return sbdf;
 }
 
 struct dev_table_entry *get_dev_table(struct amd_iommu *iommu)
@@ -182,9 +175,11 @@ static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 
devid)
 static struct amd_iommu *rlookup_amd_iommu(struct device *dev)
 {
u16 seg = get_device_segment(dev);
-   u16 devid = get_device_id(dev);
+   int devid = get_device_sbdf_id(dev);
 
-   return __rlookup_amd_iommu(seg, devid);
+   if (devid < 0)
+   return NULL;
+   return __rlookup_amd_iommu(seg, PCI_SBDF_TO_DEVID(devid));
 }
 
 static struct protection_domain *to_pdomain(struct iommu_domain *dom)
@@ -360,14 +355,15 @@ static bool check_device(struct device *dev)
 {
struct amd_iommu_pci_seg *pci_seg;
struct amd_iommu *iommu;
-   int devid;
+   int devid, sbdf;
 
if (!dev)
return false;
 
-   devid = get_device_id(dev);
-   if (devid < 0)
+   sbdf = get_device_sbdf_id(dev);
+   if (sbdf < 0)
return false;
+   devid = PCI_SBDF_TO_DEVID(sbdf);
 
iommu = rlookup_amd_iommu(dev);
if (!iommu)
@@ -375,7 +371,7 @@ static bool check_device(struct device *dev)
 
/* Out of our scope? */
pci_seg = iommu->pci_seg;
-   if ((devid & 0x) > pci_seg->last_bdf)
+   if (devid > pci_seg->last_bdf)
return false;
 
return true;
@@ -384,15 +380,16 @@ static bool check_device(struct device *dev)
 static int iommu_init_device(struct amd_iommu *iommu, struct device *dev)
 {
struct iommu_dev_data *dev_data;
-   int devid;
+   int devid, sbdf;
 
if (dev_iommu_priv_get(dev))
return 0;
 
-   devid = get_device_id(dev);
-   if (devid < 0)
-   return devid;
+   sbdf = get_device_sbdf_id(dev);
+   if (sbdf < 0)
+   return sbdf;
 
+   devid = 

[PATCH v3 RESEND 28/35] iommu/amd: Flush upto last_bdf only

2022-07-06 Thread Vasant Hegde via iommu
Fix amd_iommu_flush_dte_all() and amd_iommu_flush_tlb_all() to flush
upto last_bdf only.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 94ebffe15960..6914911d4fb6 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1191,8 +1191,9 @@ static int iommu_flush_dte(struct amd_iommu *iommu, u16 
devid)
 static void amd_iommu_flush_dte_all(struct amd_iommu *iommu)
 {
u32 devid;
+   u16 last_bdf = iommu->pci_seg->last_bdf;
 
-   for (devid = 0; devid <= 0x; ++devid)
+   for (devid = 0; devid <= last_bdf; ++devid)
iommu_flush_dte(iommu, devid);
 
iommu_completion_wait(iommu);
@@ -1205,8 +1206,9 @@ static void amd_iommu_flush_dte_all(struct amd_iommu 
*iommu)
 static void amd_iommu_flush_tlb_all(struct amd_iommu *iommu)
 {
u32 dom_id;
+   u16 last_bdf = iommu->pci_seg->last_bdf;
 
-   for (dom_id = 0; dom_id <= 0x; ++dom_id) {
+   for (dom_id = 0; dom_id <= last_bdf; ++dom_id) {
struct iommu_cmd cmd;
build_inv_iommu_pages(, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
  dom_id, 1);
@@ -1249,8 +1251,9 @@ static void iommu_flush_irt(struct amd_iommu *iommu, u16 
devid)
 static void amd_iommu_flush_irt_all(struct amd_iommu *iommu)
 {
u32 devid;
+   u16 last_bdf = iommu->pci_seg->last_bdf;
 
-   for (devid = 0; devid <= MAX_DEV_TABLE_ENTRIES; devid++)
+   for (devid = 0; devid <= last_bdf; devid++)
iommu_flush_irt(iommu, devid);
 
iommu_completion_wait(iommu);
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 27/35] iommu/amd: Remove global amd_iommu_[dev_table/alias_table/last_bdf]

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Replace them with per PCI segment device table.
Also remove dev_table_size, alias_table_size, amd_iommu_last_bdf
variables.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h | 15 -
 drivers/iommu/amd/init.c| 89 +
 drivers/iommu/amd/iommu.c   | 18 --
 3 files changed, 27 insertions(+), 95 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index d932c90329e4..65b02e2ae28f 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -834,24 +834,9 @@ struct unity_map_entry {
  * Data structures for device handling
  */
 
-/*
- * Device table used by hardware. Read and write accesses by software are
- * locked with the amd_iommu_pd_table lock.
- */
-extern struct dev_table_entry *amd_iommu_dev_table;
-
-/*
- * Alias table to find requestor ids to device ids. Not locked because only
- * read on runtime.
- */
-extern u16 *amd_iommu_alias_table;
-
 /* size of the dma_ops aperture as power of 2 */
 extern unsigned amd_iommu_aperture_order;
 
-/* largest PCI device id we expect translation requests for */
-extern u16 amd_iommu_last_bdf;
-
 /* allocation bitmap for domain ids */
 extern unsigned long *amd_iommu_pd_alloc_bitmap;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 508959182c7f..df8f4b9d20cd 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -160,9 +160,6 @@ static bool amd_iommu_disabled __initdata;
 static bool amd_iommu_force_enable __initdata;
 static int amd_iommu_target_ivhd_type;
 
-u16 amd_iommu_last_bdf;/* largest PCI device id we have
-  to handle */
-
 LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
   system */
@@ -185,30 +182,12 @@ bool amdr_ivrs_remap_support __read_mostly;
 
 bool amd_iommu_force_isolation __read_mostly;
 
-/*
- * Pointer to the device table which is shared by all AMD IOMMUs
- * it is indexed by the PCI device id or the HT unit id and contains
- * information about the domain the device belongs to as well as the
- * page table root pointer.
- */
-struct dev_table_entry *amd_iommu_dev_table;
-
-/*
- * The alias table is a driver specific data structure which contains the
- * mappings of the PCI device ids to the actual requestor ids on the IOMMU.
- * More than one device can share the same requestor id.
- */
-u16 *amd_iommu_alias_table;
-
 /*
  * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
  * to know which ones are already in use.
  */
 unsigned long *amd_iommu_pd_alloc_bitmap;
 
-static u32 dev_table_size; /* size of the device table */
-static u32 alias_table_size;   /* size of the alias table */
-
 enum iommu_init_state {
IOMMU_START_STATE,
IOMMU_IVRS_DETECTED,
@@ -263,16 +242,10 @@ static void init_translation_status(struct amd_iommu 
*iommu)
iommu->flags |= AMD_IOMMU_FLAG_TRANS_PRE_ENABLED;
 }
 
-static inline void update_last_devid(u16 devid)
-{
-   if (devid > amd_iommu_last_bdf)
-   amd_iommu_last_bdf = devid;
-}
-
-static inline unsigned long tbl_size(int entry_size)
+static inline unsigned long tbl_size(int entry_size, int last_bdf)
 {
unsigned shift = PAGE_SHIFT +
-get_order(((int)amd_iommu_last_bdf + 1) * entry_size);
+get_order((last_bdf + 1) * entry_size);
 
return 1UL << shift;
 }
@@ -404,10 +377,11 @@ static void iommu_set_device_table(struct amd_iommu 
*iommu)
 {
u64 entry;
u32 dev_table_size = iommu->pci_seg->dev_table_size;
+   void *dev_table = (void *)get_dev_table(iommu);
 
BUG_ON(iommu->mmio_base == NULL);
 
-   entry = iommu_virt_to_phys(amd_iommu_dev_table);
+   entry = iommu_virt_to_phys(dev_table);
entry |= (dev_table_size >> 12) - 1;
memcpy_toio(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET,
, sizeof(entry));
@@ -557,14 +531,12 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
switch (dev->type) {
case IVHD_DEV_ALL:
/* Use maximum BDF value for DEV_ALL */
-   update_last_devid(0x);
return 0x;
case IVHD_DEV_SELECT:
case IVHD_DEV_RANGE_END:
case IVHD_DEV_ALIAS:
case IVHD_DEV_EXT_SELECT:
/* all the above subfield types refer to device ids */
-   update_last_devid(dev->devid);
if (dev->devid > last_devid)
last_devid = dev->devid;

[PATCH v3 RESEND 26/35] iommu/amd: Update set_dev_entry_bit() and get_dev_entry_bit()

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

To include a pointer to per PCI segment device table.

Also include struct amd_iommu as one of the function parameter to
amd_iommu_apply_erratum_63() since it is needed when setting up DTE.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h |  2 +-
 drivers/iommu/amd/init.c  | 59 +++
 drivers/iommu/amd/iommu.c |  2 +-
 3 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 2947239700ce..64c954e168d7 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -13,7 +13,7 @@
 
 extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
 extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
-extern void amd_iommu_apply_erratum_63(u16 devid);
+extern void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid);
 extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
 extern int amd_iommu_init_devices(void);
 extern void amd_iommu_uninit_devices(void);
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 3024fa9a89d5..508959182c7f 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -989,22 +989,37 @@ static void iommu_enable_gt(struct amd_iommu *iommu)
 }
 
 /* sets a specific bit in the device table entry. */
-static void set_dev_entry_bit(u16 devid, u8 bit)
+static void __set_dev_entry_bit(struct dev_table_entry *dev_table,
+   u16 devid, u8 bit)
 {
int i = (bit >> 6) & 0x03;
int _bit = bit & 0x3f;
 
-   amd_iommu_dev_table[devid].data[i] |= (1UL << _bit);
+   dev_table[devid].data[i] |= (1UL << _bit);
 }
 
-static int get_dev_entry_bit(u16 devid, u8 bit)
+static void set_dev_entry_bit(struct amd_iommu *iommu, u16 devid, u8 bit)
+{
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
+
+   return __set_dev_entry_bit(dev_table, devid, bit);
+}
+
+static int __get_dev_entry_bit(struct dev_table_entry *dev_table,
+  u16 devid, u8 bit)
 {
int i = (bit >> 6) & 0x03;
int _bit = bit & 0x3f;
 
-   return (amd_iommu_dev_table[devid].data[i] & (1UL << _bit)) >> _bit;
+   return (dev_table[devid].data[i] & (1UL << _bit)) >> _bit;
 }
 
+static int get_dev_entry_bit(struct amd_iommu *iommu, u16 devid, u8 bit)
+{
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
+
+   return __get_dev_entry_bit(dev_table, devid, bit);
+}
 
 static bool __copy_device_table(struct amd_iommu *iommu)
 {
@@ -1123,15 +1138,15 @@ static bool copy_device_table(void)
return true;
 }
 
-void amd_iommu_apply_erratum_63(u16 devid)
+void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid)
 {
int sysmgt;
 
-   sysmgt = get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1) |
-(get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2) << 1);
+   sysmgt = get_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT1) |
+(get_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT2) << 1);
 
if (sysmgt == 0x01)
-   set_dev_entry_bit(devid, DEV_ENTRY_IW);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_IW);
 }
 
 /* Writes the specific IOMMU for a device into the rlookup table */
@@ -1148,21 +1163,21 @@ static void __init set_dev_entry_from_acpi(struct 
amd_iommu *iommu,
   u16 devid, u32 flags, u32 ext_flags)
 {
if (flags & ACPI_DEVFLAG_INITPASS)
-   set_dev_entry_bit(devid, DEV_ENTRY_INIT_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_INIT_PASS);
if (flags & ACPI_DEVFLAG_EXTINT)
-   set_dev_entry_bit(devid, DEV_ENTRY_EINT_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_EINT_PASS);
if (flags & ACPI_DEVFLAG_NMI)
-   set_dev_entry_bit(devid, DEV_ENTRY_NMI_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_NMI_PASS);
if (flags & ACPI_DEVFLAG_SYSMGT1)
-   set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT1);
if (flags & ACPI_DEVFLAG_SYSMGT2)
-   set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT2);
if (flags & ACPI_DEVFLAG_LINT0)
-   set_dev_entry_bit(devid, DEV_ENTRY_LINT0_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_LINT0_PASS);
if (flags & ACPI_DEVFLAG_LINT1)
-   set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_LINT1_PASS);
 
-   amd_iommu_apply_erratum_63(devid);
+   amd_iommu_apply_erratum_63(iommu, devid);
 
set_iommu_for_device(iommu, devid);
 }
@@ -2519,8 +2534,8 @@ static void init_device_table_dma(struct 

[PATCH v3 RESEND 25/35] iommu/amd: Update (un)init_device_table_dma()

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Include struct amd_iommu_pci_seg as a function parameter since
we need to access per PCI segment device table.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/init.c | 27 ---
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index b7e54bb5efc5..3024fa9a89d5 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -238,7 +238,7 @@ static enum iommu_init_state init_state = IOMMU_START_STATE;
 
 static int amd_iommu_enable_interrupts(void);
 static int __init iommu_go_to_state(enum iommu_init_state state);
-static void init_device_table_dma(void);
+static void init_device_table_dma(struct amd_iommu_pci_seg *pci_seg);
 
 static bool amd_iommu_pre_enabled = true;
 
@@ -2116,6 +2116,7 @@ static void print_iommu_info(void)
 static int __init amd_iommu_init_pci(void)
 {
struct amd_iommu *iommu;
+   struct amd_iommu_pci_seg *pci_seg;
int ret;
 
for_each_iommu(iommu) {
@@ -2146,7 +2147,8 @@ static int __init amd_iommu_init_pci(void)
goto out;
}
 
-   init_device_table_dma();
+   for_each_pci_segment(pci_seg)
+   init_device_table_dma(pci_seg);
 
for_each_iommu(iommu)
iommu_flush_all_caches(iommu);
@@ -2508,9 +2510,13 @@ static int __init init_memory_definitions(struct 
acpi_table_header *table)
 /*
  * Init the device table to not allow DMA access for devices
  */
-static void init_device_table_dma(void)
+static void init_device_table_dma(struct amd_iommu_pci_seg *pci_seg)
 {
u32 devid;
+   struct dev_table_entry *dev_table = pci_seg->dev_table;
+
+   if (dev_table == NULL)
+   return;
 
for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
set_dev_entry_bit(devid, DEV_ENTRY_VALID);
@@ -2518,13 +2524,17 @@ static void init_device_table_dma(void)
}
 }
 
-static void __init uninit_device_table_dma(void)
+static void __init uninit_device_table_dma(struct amd_iommu_pci_seg *pci_seg)
 {
u32 devid;
+   struct dev_table_entry *dev_table = pci_seg->dev_table;
+
+   if (dev_table == NULL)
+   return;
 
for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
-   amd_iommu_dev_table[devid].data[0] = 0ULL;
-   amd_iommu_dev_table[devid].data[1] = 0ULL;
+   dev_table[devid].data[0] = 0ULL;
+   dev_table[devid].data[1] = 0ULL;
}
 }
 
@@ -3117,8 +3127,11 @@ static int __init state_next(void)
free_iommu_resources();
} else {
struct amd_iommu *iommu;
+   struct amd_iommu_pci_seg *pci_seg;
+
+   for_each_pci_segment(pci_seg)
+   uninit_device_table_dma(pci_seg);
 
-   uninit_device_table_dma();
for_each_iommu(iommu)
iommu_flush_all_caches(iommu);
}
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 24/35] iommu/amd: Update set_dte_irq_entry

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment device table instead of global
device table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 790a3449e7b7..f1fab4168101 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2731,18 +2731,20 @@ EXPORT_SYMBOL(amd_iommu_device_info);
 static struct irq_chip amd_ir_chip;
 static DEFINE_SPINLOCK(iommu_table_lock);
 
-static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
+static void set_dte_irq_entry(struct amd_iommu *iommu, u16 devid,
+ struct irq_remap_table *table)
 {
u64 dte;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
 
-   dte = amd_iommu_dev_table[devid].data[2];
+   dte = dev_table[devid].data[2];
dte &= ~DTE_IRQ_PHYS_ADDR_MASK;
dte |= iommu_virt_to_phys(table->table);
dte |= DTE_IRQ_REMAP_INTCTL;
dte |= DTE_INTTABLEN;
dte |= DTE_IRQ_REMAP_ENABLE;
 
-   amd_iommu_dev_table[devid].data[2] = dte;
+   dev_table[devid].data[2] = dte;
 }
 
 static struct irq_remap_table *get_irq_table(struct amd_iommu *iommu, u16 
devid)
@@ -2793,7 +2795,7 @@ static void set_remap_table_entry(struct amd_iommu 
*iommu, u16 devid,
struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
pci_seg->irq_lookup_table[devid] = table;
-   set_dte_irq_entry(devid, table);
+   set_dte_irq_entry(iommu, devid, table);
iommu_flush_dte(iommu, devid);
 }
 
@@ -2809,8 +2811,7 @@ static int set_remap_table_entry_alias(struct pci_dev 
*pdev, u16 alias,
 
pci_seg = iommu->pci_seg;
pci_seg->irq_lookup_table[alias] = table;
-   set_dte_irq_entry(alias, table);
-
+   set_dte_irq_entry(iommu, alias, table);
iommu_flush_dte(pci_seg->rlookup_table[alias], alias);
 
return 0;
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 23/35] iommu/amd: Update dump_dte_entry

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment device table instead of global
device table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 90755da7cff0..790a3449e7b7 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -451,13 +451,13 @@ static void amd_iommu_uninit_device(struct device *dev)
  *
  /
 
-static void dump_dte_entry(u16 devid)
+static void dump_dte_entry(struct amd_iommu *iommu, u16 devid)
 {
int i;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
 
for (i = 0; i < 4; ++i)
-   pr_err("DTE[%d]: %016llx\n", i,
-   amd_iommu_dev_table[devid].data[i]);
+   pr_err("DTE[%d]: %016llx\n", i, dev_table[devid].data[i]);
 }
 
 static void dump_command(unsigned long phys_addr)
@@ -618,7 +618,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void 
*__evt)
dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
pasid, address, flags);
-   dump_dte_entry(devid);
+   dump_dte_entry(iommu, devid);
break;
case EVENT_TYPE_DEV_TAB_ERR:
dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%02x:%02x.%x "
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 22/35] iommu/amd: Update iommu_ignore_device

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment device table instead of global
device table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 493cda5e0246..90755da7cff0 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -413,15 +413,15 @@ static int iommu_init_device(struct amd_iommu *iommu, 
struct device *dev)
 static void iommu_ignore_device(struct amd_iommu *iommu, struct device *dev)
 {
struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
int devid;
 
-   devid = get_device_id(dev);
+   devid = (get_device_id(dev)) & 0x;
if (devid < 0)
return;
 
-
pci_seg->rlookup_table[devid] = NULL;
-   memset(_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
+   memset(_table[devid], 0, sizeof(struct dev_table_entry));
 
setup_aliases(iommu, dev);
 }
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 21/35] iommu/amd: Update set_dte_entry and clear_dte_entry

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment data structures instead of global data
structures.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 19 +++
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 6e0cd9c4f57c..493cda5e0246 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1537,6 +1537,7 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
u64 pte_root = 0;
u64 flags = 0;
u32 old_domid;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
 
if (domain->iop.mode != PAGE_MODE_NONE)
pte_root = iommu_virt_to_phys(domain->iop.root);
@@ -1545,7 +1546,7 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
<< DEV_ENTRY_MODE_SHIFT;
pte_root |= DTE_FLAG_IR | DTE_FLAG_IW | DTE_FLAG_V | DTE_FLAG_TV;
 
-   flags = amd_iommu_dev_table[devid].data[1];
+   flags = dev_table[devid].data[1];
 
if (ats)
flags |= DTE_FLAG_IOTLB;
@@ -1584,9 +1585,9 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
flags &= ~DEV_DOMID_MASK;
flags |= domain->id;
 
-   old_domid = amd_iommu_dev_table[devid].data[1] & DEV_DOMID_MASK;
-   amd_iommu_dev_table[devid].data[1]  = flags;
-   amd_iommu_dev_table[devid].data[0]  = pte_root;
+   old_domid = dev_table[devid].data[1] & DEV_DOMID_MASK;
+   dev_table[devid].data[1]  = flags;
+   dev_table[devid].data[0]  = pte_root;
 
/*
 * A kdump kernel might be replacing a domain ID that was copied from
@@ -1598,11 +1599,13 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
}
 }
 
-static void clear_dte_entry(u16 devid)
+static void clear_dte_entry(struct amd_iommu *iommu, u16 devid)
 {
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
+
/* remove entry from the device table seen by the hardware */
-   amd_iommu_dev_table[devid].data[0]  = DTE_FLAG_V | DTE_FLAG_TV;
-   amd_iommu_dev_table[devid].data[1] &= DTE_FLAG_MASK;
+   dev_table[devid].data[0]  = DTE_FLAG_V | DTE_FLAG_TV;
+   dev_table[devid].data[1] &= DTE_FLAG_MASK;
 
amd_iommu_apply_erratum_63(devid);
 }
@@ -1646,7 +1649,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
/* Update data structures */
dev_data->domain = NULL;
list_del(_data->list);
-   clear_dte_entry(dev_data->devid);
+   clear_dte_entry(iommu, dev_data->devid);
clone_aliases(iommu, dev_data->dev);
 
/* Flush the DTE entry */
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 20/35] iommu/amd: Convert to use per PCI segment rlookup_table

2022-07-06 Thread Vasant Hegde via iommu
Then, remove the global amd_iommu_rlookup_table and rlookup_table_size.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  5 -
 drivers/iommu/amd/init.c| 23 ++-
 drivers/iommu/amd/iommu.c   | 19 +--
 3 files changed, 11 insertions(+), 36 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 67feb847fc13..d932c90329e4 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -846,11 +846,6 @@ extern struct dev_table_entry *amd_iommu_dev_table;
  */
 extern u16 *amd_iommu_alias_table;
 
-/*
- * Reverse lookup table to find the IOMMU which translates a specific device.
- */
-extern struct amd_iommu **amd_iommu_rlookup_table;
-
 /* size of the dma_ops aperture as power of 2 */
 extern unsigned amd_iommu_aperture_order;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index b7b50345c8a5..b7e54bb5efc5 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -200,12 +200,6 @@ struct dev_table_entry *amd_iommu_dev_table;
  */
 u16 *amd_iommu_alias_table;
 
-/*
- * The rlookup table is used to find the IOMMU which is responsible
- * for a specific device. It is also indexed by the PCI device id.
- */
-struct amd_iommu **amd_iommu_rlookup_table;
-
 /*
  * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
  * to know which ones are already in use.
@@ -214,7 +208,6 @@ unsigned long *amd_iommu_pd_alloc_bitmap;
 
 static u32 dev_table_size; /* size of the device table */
 static u32 alias_table_size;   /* size of the alias table */
-static u32 rlookup_table_size; /* size if the rlookup table */
 
 enum iommu_init_state {
IOMMU_START_STATE,
@@ -1144,7 +1137,7 @@ void amd_iommu_apply_erratum_63(u16 devid)
 /* Writes the specific IOMMU for a device into the rlookup table */
 static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid)
 {
-   amd_iommu_rlookup_table[devid] = iommu;
+   iommu->pci_seg->rlookup_table[devid] = iommu;
 }
 
 /*
@@ -1826,7 +1819,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, 
struct ivhd_header *h,
 * Make sure IOMMU is not considered to translate itself. The IVRS
 * table tells us so, but this is a lie!
 */
-   amd_iommu_rlookup_table[iommu->devid] = NULL;
+   pci_seg->rlookup_table[iommu->devid] = NULL;
 
return 0;
 }
@@ -2783,10 +2776,6 @@ static void __init free_iommu_resources(void)
kmem_cache_destroy(amd_iommu_irq_cache);
amd_iommu_irq_cache = NULL;
 
-   free_pages((unsigned long)amd_iommu_rlookup_table,
-  get_order(rlookup_table_size));
-   amd_iommu_rlookup_table = NULL;
-
free_pages((unsigned long)amd_iommu_alias_table,
   get_order(alias_table_size));
amd_iommu_alias_table = NULL;
@@ -2925,7 +2914,6 @@ static int __init early_amd_iommu_init(void)
 
dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
-   rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
 
/* Device table - directly used by all IOMMUs */
ret = -ENOMEM;
@@ -2944,13 +2932,6 @@ static int __init early_amd_iommu_init(void)
if (amd_iommu_alias_table == NULL)
goto out;
 
-   /* IOMMU rlookup table - find the IOMMU for a specific device */
-   amd_iommu_rlookup_table = (void *)__get_free_pages(
-   GFP_KERNEL | __GFP_ZERO,
-   get_order(rlookup_table_size));
-   if (amd_iommu_rlookup_table == NULL)
-   goto out;
-
amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
get_order(MAX_DOMAIN_ID/8));
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 5ee1af9a0a54..6e0cd9c4f57c 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -287,10 +287,9 @@ static void setup_aliases(struct amd_iommu *iommu, struct 
device *dev)
clone_aliases(iommu, dev);
 }
 
-static struct iommu_dev_data *find_dev_data(u16 devid)
+static struct iommu_dev_data *find_dev_data(struct amd_iommu *iommu, u16 devid)
 {
struct iommu_dev_data *dev_data;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
 
dev_data = search_dev_data(iommu, devid);
 
@@ -388,7 +387,7 @@ static int iommu_init_device(struct amd_iommu *iommu, 
struct device *dev)
if (devid < 0)
return devid;
 
-   dev_data = find_dev_data(devid);
+   dev_data = find_dev_data(iommu, devid);
if (!dev_data)
return -ENOMEM;
 
@@ -403,9 +402,6 @@ static int iommu_init_device(struct amd_iommu *iommu, 
struct 

[PATCH v3 RESEND 19/35] iommu/amd: Update alloc_irq_table and alloc_irq_index

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Pass amd_iommu structure as one of the parameter to these functions
as its needed to retrieve variable tables inside these functions.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/iommu.c | 26 +-
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index c4701fa957d0..5ee1af9a0a54 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2814,21 +2814,17 @@ static int set_remap_table_entry_alias(struct pci_dev 
*pdev, u16 alias,
return 0;
 }
 
-static struct irq_remap_table *alloc_irq_table(u16 devid, struct pci_dev *pdev)
+static struct irq_remap_table *alloc_irq_table(struct amd_iommu *iommu,
+  u16 devid, struct pci_dev *pdev)
 {
struct irq_remap_table *table = NULL;
struct irq_remap_table *new_table = NULL;
struct amd_iommu_pci_seg *pci_seg;
-   struct amd_iommu *iommu;
unsigned long flags;
u16 alias;
 
spin_lock_irqsave(_table_lock, flags);
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (!iommu)
-   goto out_unlock;
-
pci_seg = iommu->pci_seg;
table = pci_seg->irq_lookup_table[devid];
if (table)
@@ -2884,18 +2880,14 @@ static struct irq_remap_table *alloc_irq_table(u16 
devid, struct pci_dev *pdev)
return table;
 }
 
-static int alloc_irq_index(u16 devid, int count, bool align,
-  struct pci_dev *pdev)
+static int alloc_irq_index(struct amd_iommu *iommu, u16 devid, int count,
+  bool align, struct pci_dev *pdev)
 {
struct irq_remap_table *table;
int index, c, alignment = 1;
unsigned long flags;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
-
-   if (!iommu)
-   return -ENODEV;
 
-   table = alloc_irq_table(devid, pdev);
+   table = alloc_irq_table(iommu, devid, pdev);
if (!table)
return -ENODEV;
 
@@ -3267,7 +3259,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
struct irq_remap_table *table;
 
-   table = alloc_irq_table(devid, NULL);
+   table = alloc_irq_table(iommu, devid, NULL);
if (table) {
if (!table->min_index) {
/*
@@ -3287,10 +3279,10 @@ static int irq_remapping_alloc(struct irq_domain 
*domain, unsigned int virq,
   info->type == X86_IRQ_ALLOC_TYPE_PCI_MSIX) {
bool align = (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI);
 
-   index = alloc_irq_index(devid, nr_irqs, align,
+   index = alloc_irq_index(iommu, devid, nr_irqs, align,
msi_desc_to_pci_dev(info->desc));
} else {
-   index = alloc_irq_index(devid, nr_irqs, false, NULL);
+   index = alloc_irq_index(iommu, devid, nr_irqs, false, NULL);
}
 
if (index < 0) {
@@ -3416,8 +3408,8 @@ static int irq_remapping_select(struct irq_domain *d, 
struct irq_fwspec *fwspec,
 
if (devid < 0)
return 0;
+   iommu = __rlookup_amd_iommu((devid >> 16), (devid & 0x));
 
-   iommu = amd_iommu_rlookup_table[devid];
return iommu && iommu->ir_domain == d;
 }
 
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 18/35] iommu/amd: Update amd_irte_ops functions

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Pass amd_iommu structure as one of the parameter to amd_irte_ops functions
since its needed to activate/deactivate the iommu.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  6 ++--
 drivers/iommu/amd/iommu.c   | 51 -
 2 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 693926afdd0f..67feb847fc13 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -1007,9 +1007,9 @@ struct amd_ir_data {
 
 struct amd_irte_ops {
void (*prepare)(void *, u32, bool, u8, u32, int);
-   void (*activate)(void *, u16, u16);
-   void (*deactivate)(void *, u16, u16);
-   void (*set_affinity)(void *, u16, u16, u8, u32);
+   void (*activate)(struct amd_iommu *iommu, void *, u16, u16);
+   void (*deactivate)(struct amd_iommu *iommu, void *, u16, u16);
+   void (*set_affinity)(struct amd_iommu *iommu, void *, u16, u16, u8, 
u32);
void *(*get)(struct irq_remap_table *, int);
void (*set_allocated)(struct irq_remap_table *, int);
bool (*is_allocated)(struct irq_remap_table *, int);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 9f373b164762..c4701fa957d0 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2934,19 +2934,14 @@ static int alloc_irq_index(u16 devid, int count, bool 
align,
return index;
 }
 
-static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
- struct amd_ir_data *data)
+static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
+ struct irte_ga *irte, struct amd_ir_data *data)
 {
bool ret;
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
unsigned long flags;
struct irte_ga *entry;
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (iommu == NULL)
-   return -EINVAL;
-
table = get_irq_table(iommu, devid);
if (!table)
return -ENOMEM;
@@ -2978,16 +2973,12 @@ static int modify_irte_ga(u16 devid, int index, struct 
irte_ga *irte,
return 0;
 }
 
-static int modify_irte(u16 devid, int index, union irte *irte)
+static int modify_irte(struct amd_iommu *iommu,
+  u16 devid, int index, union irte *irte)
 {
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
unsigned long flags;
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (iommu == NULL)
-   return -EINVAL;
-
table = get_irq_table(iommu, devid);
if (!table)
return -ENOMEM;
@@ -3049,49 +3040,49 @@ static void irte_ga_prepare(void *entry,
irte->lo.fields_remap.valid   = 1;
 }
 
-static void irte_activate(void *entry, u16 devid, u16 index)
+static void irte_activate(struct amd_iommu *iommu, void *entry, u16 devid, u16 
index)
 {
union irte *irte = (union irte *) entry;
 
irte->fields.valid = 1;
-   modify_irte(devid, index, irte);
+   modify_irte(iommu, devid, index, irte);
 }
 
-static void irte_ga_activate(void *entry, u16 devid, u16 index)
+static void irte_ga_activate(struct amd_iommu *iommu, void *entry, u16 devid, 
u16 index)
 {
struct irte_ga *irte = (struct irte_ga *) entry;
 
irte->lo.fields_remap.valid = 1;
-   modify_irte_ga(devid, index, irte, NULL);
+   modify_irte_ga(iommu, devid, index, irte, NULL);
 }
 
-static void irte_deactivate(void *entry, u16 devid, u16 index)
+static void irte_deactivate(struct amd_iommu *iommu, void *entry, u16 devid, 
u16 index)
 {
union irte *irte = (union irte *) entry;
 
irte->fields.valid = 0;
-   modify_irte(devid, index, irte);
+   modify_irte(iommu, devid, index, irte);
 }
 
-static void irte_ga_deactivate(void *entry, u16 devid, u16 index)
+static void irte_ga_deactivate(struct amd_iommu *iommu, void *entry, u16 
devid, u16 index)
 {
struct irte_ga *irte = (struct irte_ga *) entry;
 
irte->lo.fields_remap.valid = 0;
-   modify_irte_ga(devid, index, irte, NULL);
+   modify_irte_ga(iommu, devid, index, irte, NULL);
 }
 
-static void irte_set_affinity(void *entry, u16 devid, u16 index,
+static void irte_set_affinity(struct amd_iommu *iommu, void *entry, u16 devid, 
u16 index,
  u8 vector, u32 dest_apicid)
 {
union irte *irte = (union irte *) entry;
 
irte->fields.vector = vector;
irte->fields.destination = dest_apicid;
-   modify_irte(devid, index, irte);
+   modify_irte(iommu, devid, index, irte);
 }
 
-static void irte_ga_set_affinity(void *entry, u16 devid, u16 index,
+static void irte_ga_set_affinity(struct amd_iommu *iommu, void *entry, u16 
devid, u16 index,
 u8 vector, u32 

[PATCH v3 RESEND 17/35] iommu/amd: Introduce struct amd_ir_data.iommu

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Add a pointer to struct amd_iommu to amd_ir_data structure, which
can be used to correlate interrupt remapping data to a per-PCI-segment
interrupt remapping table.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h |  1 +
 drivers/iommu/amd/iommu.c   | 34 +
 2 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index ca1a3d55cc83..693926afdd0f 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -989,6 +989,7 @@ struct irq_2_irte {
 
 struct amd_ir_data {
u32 cached_ga_tag;
+   struct amd_iommu *iommu;
struct irq_2_irte irq_2_irte;
struct msi_msg msi_entry;
void *entry;/* Pointer to union irte or struct irte_ga */
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 5e4648cadff9..9f373b164762 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3002,16 +3002,11 @@ static int modify_irte(u16 devid, int index, union irte 
*irte)
return 0;
 }
 
-static void free_irte(u16 devid, int index)
+static void free_irte(struct amd_iommu *iommu, u16 devid, int index)
 {
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
unsigned long flags;
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (iommu == NULL)
-   return;
-
table = get_irq_table(iommu, devid);
if (!table)
return;
@@ -3195,7 +3190,7 @@ static void irq_remapping_prepare_irte(struct amd_ir_data 
*data,
   int devid, int index, int sub_handle)
 {
struct irq_2_irte *irte_info = >irq_2_irte;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+   struct amd_iommu *iommu = data->iommu;
 
if (!iommu)
return;
@@ -3336,6 +3331,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
goto out_free_data;
}
 
+   data->iommu = iommu;
irq_data->hwirq = (devid << 16) + i;
irq_data->chip_data = data;
irq_data->chip = _ir_chip;
@@ -3352,7 +3348,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
kfree(irq_data->chip_data);
}
for (i = 0; i < nr_irqs; i++)
-   free_irte(devid, index + i);
+   free_irte(iommu, devid, index + i);
 out_free_parent:
irq_domain_free_irqs_common(domain, virq, nr_irqs);
return ret;
@@ -3371,7 +3367,7 @@ static void irq_remapping_free(struct irq_domain *domain, 
unsigned int virq,
if (irq_data && irq_data->chip_data) {
data = irq_data->chip_data;
irte_info = >irq_2_irte;
-   free_irte(irte_info->devid, irte_info->index);
+   free_irte(data->iommu, irte_info->devid, 
irte_info->index);
kfree(data->entry);
kfree(data);
}
@@ -3389,7 +3385,7 @@ static int irq_remapping_activate(struct irq_domain 
*domain,
 {
struct amd_ir_data *data = irq_data->chip_data;
struct irq_2_irte *irte_info = >irq_2_irte;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[irte_info->devid];
+   struct amd_iommu *iommu = data->iommu;
struct irq_cfg *cfg = irqd_cfg(irq_data);
 
if (!iommu)
@@ -3406,7 +3402,7 @@ static void irq_remapping_deactivate(struct irq_domain 
*domain,
 {
struct amd_ir_data *data = irq_data->chip_data;
struct irq_2_irte *irte_info = >irq_2_irte;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[irte_info->devid];
+   struct amd_iommu *iommu = data->iommu;
 
if (iommu)
iommu->irte_ops->deactivate(data->entry, irte_info->devid,
@@ -3502,12 +3498,16 @@ EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
 {
int ret;
-   struct amd_iommu *iommu;
struct amd_iommu_pi_data *pi_data = vcpu_info;
struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data;
struct amd_ir_data *ir_data = data->chip_data;
struct irq_2_irte *irte_info = _data->irq_2_irte;
-   struct iommu_dev_data *dev_data = search_dev_data(NULL, 
irte_info->devid);
+   struct iommu_dev_data *dev_data;
+
+   if (ir_data->iommu == NULL)
+   return -EINVAL;
+
+   dev_data = search_dev_data(ir_data->iommu, irte_info->devid);
 
/* Note:
 * This device has never been set up for guest mode.
@@ -3529,10 +3529,6 @@ static int amd_ir_set_vcpu_affinity(struct irq_data 
*data, void *vcpu_info)
pi_data->is_guest_mode = false;
 

[PATCH v3 RESEND 16/35] iommu/amd: Update irq_remapping_alloc to use IOMMU lookup helper function

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

To allow IOMMU rlookup using both PCI segment and device ID.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/iommu.c | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 19db4d54c337..5e4648cadff9 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3246,8 +3246,9 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
struct irq_alloc_info *info = arg;
struct irq_data *irq_data;
struct amd_ir_data *data = NULL;
+   struct amd_iommu *iommu;
struct irq_cfg *cfg;
-   int i, ret, devid;
+   int i, ret, devid, seg, sbdf;
int index;
 
if (!info)
@@ -3263,8 +3264,14 @@ static int irq_remapping_alloc(struct irq_domain 
*domain, unsigned int virq,
if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
 
-   devid = get_devid(info);
-   if (devid < 0)
+   sbdf = get_devid(info);
+   if (sbdf < 0)
+   return -EINVAL;
+
+   seg = PCI_SBDF_TO_SEGID(sbdf);
+   devid = PCI_SBDF_TO_DEVID(sbdf);
+   iommu = __rlookup_amd_iommu(seg, devid);
+   if (!iommu)
return -EINVAL;
 
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
@@ -3273,7 +3280,6 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
 
if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
 
table = alloc_irq_table(devid, NULL);
if (table) {
@@ -3283,7 +3289,6 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
 * interrupts.
 */
table->min_index = 32;
-   iommu = amd_iommu_rlookup_table[devid];
for (i = 0; i < 32; ++i)
iommu->irte_ops->set_allocated(table, 
i);
}
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 15/35] iommu/amd: Convert to use rlookup_amd_iommu helper function

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Use rlookup_amd_iommu() helper function which will give per PCI
segment rlookup_table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 64 +++
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index cfecd072e7a6..19db4d54c337 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -229,13 +229,17 @@ static struct iommu_dev_data *search_dev_data(struct 
amd_iommu *iommu, u16 devid
 
 static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
 {
+   struct amd_iommu *iommu;
u16 devid = pci_dev_id(pdev);
 
if (devid == alias)
return 0;
 
-   amd_iommu_rlookup_table[alias] =
-   amd_iommu_rlookup_table[devid];
+   iommu = rlookup_amd_iommu(>dev);
+   if (!iommu)
+   return 0;
+
+   amd_iommu_set_rlookup_table(iommu, alias);
memcpy(amd_iommu_dev_table[alias].data,
   amd_iommu_dev_table[devid].data,
   sizeof(amd_iommu_dev_table[alias].data));
@@ -366,7 +370,7 @@ static bool check_device(struct device *dev)
if (devid > amd_iommu_last_bdf)
return false;
 
-   if (amd_iommu_rlookup_table[devid] == NULL)
+   if (rlookup_amd_iommu(dev) == NULL)
return false;
 
return true;
@@ -1270,7 +1274,9 @@ static int device_flush_iotlb(struct iommu_dev_data 
*dev_data,
int qdep;
 
qdep = dev_data->ats.qdep;
-   iommu= amd_iommu_rlookup_table[dev_data->devid];
+   iommu= rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return -EINVAL;
 
build_inv_iotlb_pages(, dev_data->devid, qdep, address, size);
 
@@ -1295,7 +1301,9 @@ static int device_flush_dte(struct iommu_dev_data 
*dev_data)
u16 alias;
int ret;
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return -EINVAL;
 
if (dev_is_pci(dev_data->dev))
pdev = to_pci_dev(dev_data->dev);
@@ -1525,8 +1533,8 @@ static void free_gcr3_table(struct protection_domain 
*domain)
free_page((unsigned long)domain->gcr3_tbl);
 }
 
-static void set_dte_entry(u16 devid, struct protection_domain *domain,
- bool ats, bool ppr)
+static void set_dte_entry(struct amd_iommu *iommu, u16 devid,
+ struct protection_domain *domain, bool ats, bool ppr)
 {
u64 pte_root = 0;
u64 flags = 0;
@@ -1545,8 +1553,6 @@ static void set_dte_entry(u16 devid, struct 
protection_domain *domain,
flags |= DTE_FLAG_IOTLB;
 
if (ppr) {
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
-
if (iommu_feature(iommu, FEATURE_EPHSUP))
pte_root |= 1ULL << DEV_ENTRY_PPR;
}
@@ -1590,8 +1596,6 @@ static void set_dte_entry(u16 devid, struct 
protection_domain *domain,
 * entries for the old domain ID that is being overwritten
 */
if (old_domid) {
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
-
amd_iommu_flush_tlb_domid(iommu, old_domid);
}
 }
@@ -1611,7 +1615,9 @@ static void do_attach(struct iommu_dev_data *dev_data,
struct amd_iommu *iommu;
bool ats;
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return;
ats   = dev_data->ats.enabled;
 
/* Update data structures */
@@ -1623,7 +1629,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
domain->dev_cnt += 1;
 
/* Update device table */
-   set_dte_entry(dev_data->devid, domain,
+   set_dte_entry(iommu, dev_data->devid, domain,
  ats, dev_data->iommu_v2);
clone_aliases(iommu, dev_data->dev);
 
@@ -1635,7 +1641,9 @@ static void do_detach(struct iommu_dev_data *dev_data)
struct protection_domain *domain = dev_data->domain;
struct amd_iommu *iommu;
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return;
 
/* Update data structures */
dev_data->domain = NULL;
@@ -1813,13 +1821,14 @@ static struct iommu_device 
*amd_iommu_probe_device(struct device *dev)
 {
struct iommu_device *iommu_dev;
struct amd_iommu *iommu;
-   int ret, devid;
+   int ret;
 
if (!check_device(dev))
return ERR_PTR(-ENODEV);
 
-   devid = get_device_id(dev);
-   iommu = amd_iommu_rlookup_table[devid];
+   iommu = rlookup_amd_iommu(dev);
+   if (!iommu)
+   return ERR_PTR(-ENODEV);
 
if 

[PATCH v3 RESEND 14/35] iommu/amd: Convert to use per PCI segment irq_lookup_table

2022-07-06 Thread Vasant Hegde via iommu
Then, remove the global irq_lookup_table.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  2 --
 drivers/iommu/amd/init.c| 19 ---
 drivers/iommu/amd/iommu.c   | 36 ++---
 3 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 8d2d5fbdb57f..ca1a3d55cc83 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -445,8 +445,6 @@ struct irq_remap_table {
u32 *table;
 };
 
-extern struct irq_remap_table **irq_lookup_table;
-
 /* Interrupt remapping feature used? */
 extern bool amd_iommu_irq_remap;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index afe3bff5bce0..b7b50345c8a5 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -206,12 +206,6 @@ u16 *amd_iommu_alias_table;
  */
 struct amd_iommu **amd_iommu_rlookup_table;
 
-/*
- * This table is used to find the irq remapping table for a given device id
- * quickly.
- */
-struct irq_remap_table **irq_lookup_table;
-
 /*
  * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
  * to know which ones are already in use.
@@ -2786,11 +2780,6 @@ static struct syscore_ops amd_iommu_syscore_ops = {
 
 static void __init free_iommu_resources(void)
 {
-   kmemleak_free(irq_lookup_table);
-   free_pages((unsigned long)irq_lookup_table,
-  get_order(rlookup_table_size));
-   irq_lookup_table = NULL;
-
kmem_cache_destroy(amd_iommu_irq_cache);
amd_iommu_irq_cache = NULL;
 
@@ -3011,14 +3000,6 @@ static int __init early_amd_iommu_init(void)
if (alloc_irq_lookup_table(pci_seg))
goto out;
}
-
-   irq_lookup_table = (void *)__get_free_pages(
-   GFP_KERNEL | __GFP_ZERO,
-   get_order(rlookup_table_size));
-   kmemleak_alloc(irq_lookup_table, rlookup_table_size,
-  1, GFP_KERNEL);
-   if (!irq_lookup_table)
-   goto out;
}
 
ret = init_memory_definitions(ivrs_base);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 53ccee57a7a0..cfecd072e7a6 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2732,16 +2732,18 @@ static void set_dte_irq_entry(u16 devid, struct 
irq_remap_table *table)
amd_iommu_dev_table[devid].data[2] = dte;
 }
 
-static struct irq_remap_table *get_irq_table(u16 devid)
+static struct irq_remap_table *get_irq_table(struct amd_iommu *iommu, u16 
devid)
 {
struct irq_remap_table *table;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
if (WARN_ONCE(!amd_iommu_rlookup_table[devid],
  "%s: no iommu for devid %x\n", __func__, devid))
return NULL;
 
-   table = irq_lookup_table[devid];
-   if (WARN_ONCE(!table, "%s: no table for devid %x\n", __func__, devid))
+   table = pci_seg->irq_lookup_table[devid];
+   if (WARN_ONCE(!table, "%s: no table for devid %x:%x\n",
+ __func__, pci_seg->id, devid))
return NULL;
 
return table;
@@ -2774,7 +2776,9 @@ static struct irq_remap_table *__alloc_irq_table(void)
 static void set_remap_table_entry(struct amd_iommu *iommu, u16 devid,
  struct irq_remap_table *table)
 {
-   irq_lookup_table[devid] = table;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+   pci_seg->irq_lookup_table[devid] = table;
set_dte_irq_entry(devid, table);
iommu_flush_dte(iommu, devid);
 }
@@ -2783,8 +2787,14 @@ static int set_remap_table_entry_alias(struct pci_dev 
*pdev, u16 alias,
   void *data)
 {
struct irq_remap_table *table = data;
+   struct amd_iommu_pci_seg *pci_seg;
+   struct amd_iommu *iommu = rlookup_amd_iommu(>dev);
 
-   irq_lookup_table[alias] = table;
+   if (!iommu)
+   return -EINVAL;
+
+   pci_seg = iommu->pci_seg;
+   pci_seg->irq_lookup_table[alias] = table;
set_dte_irq_entry(alias, table);
 
iommu_flush_dte(amd_iommu_rlookup_table[alias], alias);
@@ -2808,12 +2818,12 @@ static struct irq_remap_table *alloc_irq_table(u16 
devid, struct pci_dev *pdev)
goto out_unlock;
 
pci_seg = iommu->pci_seg;
-   table = irq_lookup_table[devid];
+   table = pci_seg->irq_lookup_table[devid];
if (table)
goto out_unlock;
 
alias = pci_seg->alias_table[devid];
-   table = irq_lookup_table[alias];
+   table = pci_seg->irq_lookup_table[alias];
if (table) {
set_remap_table_entry(iommu, devid, table);
  

[PATCH v3 RESEND 13/35] iommu/amd: Introduce per PCI segment rlookup table size

2022-07-06 Thread Vasant Hegde via iommu
It will replace global "rlookup_table_size" variable.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 +++
 drivers/iommu/amd/init.c| 11 ++-
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 8638b1107dd2..8d2d5fbdb57f 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -561,6 +561,9 @@ struct amd_iommu_pci_seg {
/* Size of the alias table */
u32 alias_table_size;
 
+   /* Size of the rlookup table */
+   u32 rlookup_table_size;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 22a632397818..afe3bff5bce0 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -672,7 +672,7 @@ static inline int __init alloc_rlookup_table(struct 
amd_iommu_pci_seg *pci_seg)
 {
pci_seg->rlookup_table = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
-   get_order(rlookup_table_size));
+   
get_order(pci_seg->rlookup_table_size));
if (pci_seg->rlookup_table == NULL)
return -ENOMEM;
 
@@ -682,7 +682,7 @@ static inline int __init alloc_rlookup_table(struct 
amd_iommu_pci_seg *pci_seg)
 static inline void free_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
 {
free_pages((unsigned long)pci_seg->rlookup_table,
-  get_order(rlookup_table_size));
+  get_order(pci_seg->rlookup_table_size));
pci_seg->rlookup_table = NULL;
 }
 
@@ -690,9 +690,9 @@ static inline int __init alloc_irq_lookup_table(struct 
amd_iommu_pci_seg *pci_se
 {
pci_seg->irq_lookup_table = (void *)__get_free_pages(
 GFP_KERNEL | __GFP_ZERO,
-get_order(rlookup_table_size));
+
get_order(pci_seg->rlookup_table_size));
kmemleak_alloc(pci_seg->irq_lookup_table,
-  rlookup_table_size, 1, GFP_KERNEL);
+  pci_seg->rlookup_table_size, 1, GFP_KERNEL);
if (pci_seg->irq_lookup_table == NULL)
return -ENOMEM;
 
@@ -703,7 +703,7 @@ static inline void free_irq_lookup_table(struct 
amd_iommu_pci_seg *pci_seg)
 {
kmemleak_free(pci_seg->irq_lookup_table);
free_pages((unsigned long)pci_seg->irq_lookup_table,
-  get_order(rlookup_table_size));
+  get_order(pci_seg->rlookup_table_size));
pci_seg->irq_lookup_table = NULL;
 }
 
@@ -1584,6 +1584,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id,
DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
pci_seg->dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
pci_seg->alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
+   pci_seg->rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 12/35] iommu/amd: Introduce per PCI segment alias table size

2022-07-06 Thread Vasant Hegde via iommu
It will replace global "alias_table_size" variable.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 3 +++
 drivers/iommu/amd/init.c| 5 +++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 1dbe9c7f973d..8638b1107dd2 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -558,6 +558,9 @@ struct amd_iommu_pci_seg {
/* Size of the device table */
u32 dev_table_size;
 
+   /* Size of the alias table */
+   u32 alias_table_size;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 4a1807f7a8b9..22a632397818 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -712,7 +712,7 @@ static int __init alloc_alias_table(struct 
amd_iommu_pci_seg *pci_seg)
int i;
 
pci_seg->alias_table = (void *)__get_free_pages(GFP_KERNEL,
-   
get_order(alias_table_size));
+   get_order(pci_seg->alias_table_size));
if (!pci_seg->alias_table)
return -ENOMEM;
 
@@ -728,7 +728,7 @@ static int __init alloc_alias_table(struct 
amd_iommu_pci_seg *pci_seg)
 static void __init free_alias_table(struct amd_iommu_pci_seg *pci_seg)
 {
free_pages((unsigned long)pci_seg->alias_table,
-  get_order(alias_table_size));
+  get_order(pci_seg->alias_table_size));
pci_seg->alias_table = NULL;
 }
 
@@ -1583,6 +1583,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id,
pci_seg->last_bdf = last_bdf;
DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
pci_seg->dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
+   pci_seg->alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 11/35] iommu/amd: Introduce per PCI segment device table size

2022-07-06 Thread Vasant Hegde via iommu
With multiple pci segment support, number of BDF supported by each
segment may differ. Hence introduce per segment device table size
which depends on last_bdf. This will replace global
"device_table_size" variable.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 +++
 drivers/iommu/amd/init.c| 18 ++
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 8be8f3d6b44a..1dbe9c7f973d 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -555,6 +555,9 @@ struct amd_iommu_pci_seg {
/* Largest PCI device id we expect translation requests for */
u16 last_bdf;
 
+   /* Size of the device table */
+   u32 dev_table_size;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 73554ee9c3b3..4a1807f7a8b9 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -416,6 +416,7 @@ static void iommu_set_cwwb_range(struct amd_iommu *iommu)
 static void iommu_set_device_table(struct amd_iommu *iommu)
 {
u64 entry;
+   u32 dev_table_size = iommu->pci_seg->dev_table_size;
 
BUG_ON(iommu->mmio_base == NULL);
 
@@ -652,7 +653,7 @@ static int __init find_last_devid_acpi(struct 
acpi_table_header *table, u16 pci_
 static inline int __init alloc_dev_table(struct amd_iommu_pci_seg *pci_seg)
 {
pci_seg->dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO | 
GFP_DMA32,
- 
get_order(dev_table_size));
+ 
get_order(pci_seg->dev_table_size));
if (!pci_seg->dev_table)
return -ENOMEM;
 
@@ -662,7 +663,7 @@ static inline int __init alloc_dev_table(struct 
amd_iommu_pci_seg *pci_seg)
 static inline void free_dev_table(struct amd_iommu_pci_seg *pci_seg)
 {
free_pages((unsigned long)pci_seg->dev_table,
-   get_order(dev_table_size));
+   get_order(pci_seg->dev_table_size));
pci_seg->dev_table = NULL;
 }
 
@@ -1035,7 +1036,7 @@ static bool __copy_device_table(struct amd_iommu *iommu)
entry = (((u64) hi) << 32) + lo;
 
old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
-   if (old_devtb_size != dev_table_size) {
+   if (old_devtb_size != pci_seg->dev_table_size) {
pr_err("The device table size of IOMMU:%d is not expected!\n",
iommu->index);
return false;
@@ -1054,15 +1055,15 @@ static bool __copy_device_table(struct amd_iommu *iommu)
}
old_devtb = (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT) && 
is_kdump_kernel())
? (__force void *)ioremap_encrypted(old_devtb_phys,
-   dev_table_size)
-   : memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);
+   pci_seg->dev_table_size)
+   : memremap(old_devtb_phys, pci_seg->dev_table_size, 
MEMREMAP_WB);
 
if (!old_devtb)
return false;
 
gfp_flag = GFP_KERNEL | __GFP_ZERO | GFP_DMA32;
pci_seg->old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
-   get_order(dev_table_size));
+   
get_order(pci_seg->dev_table_size));
if (pci_seg->old_dev_tbl_cpy == NULL) {
pr_err("Failed to allocate memory for copying old device 
table!\n");
memunmap(old_devtb);
@@ -1581,6 +1582,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id,
 
pci_seg->last_bdf = last_bdf;
DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
+   pci_seg->dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
@@ -2675,7 +2677,7 @@ static void early_enable_iommus(void)
for_each_pci_segment(pci_seg) {
if (pci_seg->old_dev_tbl_cpy != NULL) {
free_pages((unsigned 
long)pci_seg->old_dev_tbl_cpy,
-   get_order(dev_table_size));
+   
get_order(pci_seg->dev_table_size));
pci_seg->old_dev_tbl_cpy = NULL;
}
}
@@ -2689,7 +2691,7 @@ static void early_enable_iommus(void)
 
for_each_pci_segment(pci_seg) {
free_pages((unsigned long)pci_seg->dev_table,
-  get_order(dev_table_size));
+  

[PATCH v3 RESEND 10/35] iommu/amd: Introduce per PCI segment last_bdf

2022-07-06 Thread Vasant Hegde via iommu
Current code uses global "amd_iommu_last_bdf" to track the last bdf
supported by the system. This value is used for various memory
allocation, device data flushing, etc.

Introduce per PCI segment last_bdf which will be used to track last bdf
supported by the given PCI segment and use this value for all per
segment memory allocations. Eventually it will replace global
"amd_iommu_last_bdf".

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 ++
 drivers/iommu/amd/init.c| 69 ++---
 2 files changed, 45 insertions(+), 27 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 3099a018cef0..8be8f3d6b44a 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -552,6 +552,9 @@ struct amd_iommu_pci_seg {
/* PCI segment number */
u16 id;
 
+   /* Largest PCI device id we expect translation requests for */
+   u16 last_bdf;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 39d04d4143fb..73554ee9c3b3 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -552,6 +552,7 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
 {
u8 *p = (void *)h, *end = (void *)h;
struct ivhd_entry *dev;
+   int last_devid = -EINVAL;
 
u32 ivhd_size = get_ivhd_header_size(h);
 
@@ -569,13 +570,15 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
case IVHD_DEV_ALL:
/* Use maximum BDF value for DEV_ALL */
update_last_devid(0x);
-   break;
+   return 0x;
case IVHD_DEV_SELECT:
case IVHD_DEV_RANGE_END:
case IVHD_DEV_ALIAS:
case IVHD_DEV_EXT_SELECT:
/* all the above subfield types refer to device ids */
update_last_devid(dev->devid);
+   if (dev->devid > last_devid)
+   last_devid = dev->devid;
break;
default:
break;
@@ -585,7 +588,7 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
 
WARN_ON(p != end);
 
-   return 0;
+   return last_devid;
 }
 
 static int __init check_ivrs_checksum(struct acpi_table_header *table)
@@ -609,27 +612,31 @@ static int __init check_ivrs_checksum(struct 
acpi_table_header *table)
  * id which we need to handle. This is the first of three functions which parse
  * the ACPI table. So we check the checksum here.
  */
-static int __init find_last_devid_acpi(struct acpi_table_header *table)
+static int __init find_last_devid_acpi(struct acpi_table_header *table, u16 
pci_seg)
 {
u8 *p = (u8 *)table, *end = (u8 *)table;
struct ivhd_header *h;
+   int last_devid, last_bdf = 0;
 
p += IVRS_HEADER_LENGTH;
 
end += table->length;
while (p < end) {
h = (struct ivhd_header *)p;
-   if (h->type == amd_iommu_target_ivhd_type) {
-   int ret = find_last_devid_from_ivhd(h);
-
-   if (ret)
-   return ret;
+   if (h->pci_seg == pci_seg &&
+   h->type == amd_iommu_target_ivhd_type) {
+   last_devid = find_last_devid_from_ivhd(h);
+
+   if (last_devid < 0)
+   return -EINVAL;
+   if (last_devid > last_bdf)
+   last_bdf = last_devid;
}
p += h->length;
}
WARN_ON(p != end);
 
-   return 0;
+   return last_bdf;
 }
 
 /
@@ -1553,14 +1560,28 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 }
 
 /* Allocate PCI segment data structure */
-static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
+static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id,
+ struct acpi_table_header *ivrs_base)
 {
struct amd_iommu_pci_seg *pci_seg;
+   int last_bdf;
+
+   /*
+* First parse ACPI tables to find the largest Bus/Dev/Func we need to
+* handle in this PCI segment. Upon this information the shared data
+* structures for the PCI segments in the system will be allocated.
+*/
+   last_bdf = find_last_devid_acpi(ivrs_base, id);
+   if (last_bdf < 0)
+   return NULL;
 
pci_seg = kzalloc(sizeof(struct amd_iommu_pci_seg), GFP_KERNEL);
if (pci_seg == NULL)
return NULL;
 
+   pci_seg->last_bdf = 

[PATCH v3 RESEND 09/35] iommu/amd: Introduce per PCI segment unity map list

2022-07-06 Thread Vasant Hegde via iommu
Newer AMD systems can support multiple PCI segments. In order to support
multiple PCI segments IVMD table in IVRS structure is enhanced to
include pci segment id. Update ivmd_header structure to include "pci_seg".

Also introduce per PCI segment unity map list. It will replace global
amd_iommu_unity_map list.

Note that we have used "reserved" field in IVMD table to include "pci_seg
id" which was set to zero. It will take care of backward compatibility
(new kernel will work fine on older systems).

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 13 +++--
 drivers/iommu/amd/init.c| 30 +++--
 drivers/iommu/amd/iommu.c   |  8 +++-
 3 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index c9dd0ab37475..3099a018cef0 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -587,6 +587,13 @@ struct amd_iommu_pci_seg {
 * More than one device can share the same requestor id.
 */
u16 *alias_table;
+
+   /*
+* A list of required unity mappings we find in ACPI. It is not locked
+* because as runtime it is only read. It is created at ACPI table
+* parsing time.
+*/
+   struct list_head unity_map;
 };
 
 /*
@@ -813,12 +820,6 @@ struct unity_map_entry {
int prot;
 };
 
-/*
- * List of all unity mappings. It is not locked because as runtime it is only
- * read. It is created at ACPI table parsing time.
- */
-extern struct list_head amd_iommu_unity_map;
-
 /*
  * Data structures for device handling
  */
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 80e7eef4260f..39d04d4143fb 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -141,7 +141,8 @@ struct ivmd_header {
u16 length;
u16 devid;
u16 aux;
-   u64 resv;
+   u16 pci_seg;
+   u8  resv[6];
u64 range_start;
u64 range_length;
 } __attribute__((packed));
@@ -161,8 +162,6 @@ static int amd_iommu_target_ivhd_type;
 
 u16 amd_iommu_last_bdf;/* largest PCI device id we have
   to handle */
-LIST_HEAD(amd_iommu_unity_map);/* a list of required unity 
mappings
-  we find in ACPI */
 
 LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
@@ -1564,6 +1563,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
+   INIT_LIST_HEAD(_seg->unity_map);
list_add_tail(_seg->list, _iommu_pci_seg_list);
 
if (alloc_dev_table(pci_seg))
@@ -2398,10 +2398,13 @@ static int iommu_init_irq(struct amd_iommu *iommu)
 static void __init free_unity_maps(void)
 {
struct unity_map_entry *entry, *next;
+   struct amd_iommu_pci_seg *p, *pci_seg;
 
-   list_for_each_entry_safe(entry, next, _iommu_unity_map, list) {
-   list_del(>list);
-   kfree(entry);
+   for_each_pci_segment_safe(pci_seg, p) {
+   list_for_each_entry_safe(entry, next, _seg->unity_map, 
list) {
+   list_del(>list);
+   kfree(entry);
+   }
}
 }
 
@@ -2409,8 +2412,13 @@ static void __init free_unity_maps(void)
 static int __init init_unity_map_range(struct ivmd_header *m)
 {
struct unity_map_entry *e = NULL;
+   struct amd_iommu_pci_seg *pci_seg;
char *s;
 
+   pci_seg = get_pci_segment(m->pci_seg);
+   if (pci_seg == NULL)
+   return -ENOMEM;
+
e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL)
return -ENOMEM;
@@ -2448,14 +2456,16 @@ static int __init init_unity_map_range(struct 
ivmd_header *m)
if (m->flags & IVMD_FLAG_EXCL_RANGE)
e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1;
 
-   DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
-   " range_start: %016llx range_end: %016llx flags: %x\n", s,
+   DUMP_printk("%s devid_start: %04x:%02x:%02x.%x devid_end: "
+   "%04x:%02x:%02x.%x range_start: %016llx range_end: %016llx"
+   " flags: %x\n", s, m->pci_seg,
PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
-   PCI_FUNC(e->devid_start), PCI_BUS_NUM(e->devid_end),
+   PCI_FUNC(e->devid_start), m->pci_seg,
+   PCI_BUS_NUM(e->devid_end),
PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
e->address_start, e->address_end, m->flags);
 
-   list_add_tail(>list, _iommu_unity_map);
+   

[PATCH v3 RESEND 08/35] iommu/amd: Introduce per PCI segment alias_table

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

This will replace global alias table (amd_iommu_alias_table).

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h |  7 +
 drivers/iommu/amd/init.c| 41 ++---
 drivers/iommu/amd/iommu.c   | 41 ++---
 3 files changed, 64 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 3ef68d588cc7..c9dd0ab37475 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -580,6 +580,13 @@ struct amd_iommu_pci_seg {
 * will be copied to. It's only be used in kdump kernel.
 */
struct dev_table_entry *old_dev_tbl_cpy;
+
+   /*
+* The alias table is a driver specific data structure which contains 
the
+* mappings of the PCI device ids to the actual requestor ids on the 
IOMMU.
+* More than one device can share the same requestor id.
+*/
+   u16 *alias_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index f188130cc173..80e7eef4260f 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -700,6 +700,31 @@ static inline void free_irq_lookup_table(struct 
amd_iommu_pci_seg *pci_seg)
pci_seg->irq_lookup_table = NULL;
 }
 
+static int __init alloc_alias_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   int i;
+
+   pci_seg->alias_table = (void *)__get_free_pages(GFP_KERNEL,
+   
get_order(alias_table_size));
+   if (!pci_seg->alias_table)
+   return -ENOMEM;
+
+   /*
+* let all alias entries point to itself
+*/
+   for (i = 0; i <= amd_iommu_last_bdf; ++i)
+   pci_seg->alias_table[i] = i;
+
+   return 0;
+}
+
+static void __init free_alias_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   free_pages((unsigned long)pci_seg->alias_table,
+  get_order(alias_table_size));
+   pci_seg->alias_table = NULL;
+}
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
@@ -1268,6 +1293,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
u32 ivhd_size;
int ret;
 
@@ -1349,7 +1375,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
devid_to = e->ext >> 8;
set_dev_entry_from_acpi(iommu, devid   , e->flags, 0);
set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0);
-   amd_iommu_alias_table[devid] = devid_to;
+   pci_seg->alias_table[devid] = devid_to;
break;
case IVHD_DEV_ALIAS_RANGE:
 
@@ -1407,7 +1433,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
devid = e->devid;
for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
if (alias) {
-   amd_iommu_alias_table[dev_i] = devid_to;
+   pci_seg->alias_table[dev_i] = devid_to;
set_dev_entry_from_acpi(iommu,
devid_to, flags, ext_flags);
}
@@ -1542,6 +1568,8 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
if (alloc_dev_table(pci_seg))
return NULL;
+   if (alloc_alias_table(pci_seg))
+   return NULL;
if (alloc_rlookup_table(pci_seg))
return NULL;
 
@@ -1568,6 +1596,7 @@ static void __init free_pci_segments(void)
list_del(_seg->list);
free_irq_lookup_table(pci_seg);
free_rlookup_table(pci_seg);
+   free_alias_table(pci_seg);
free_dev_table(pci_seg);
kfree(pci_seg);
}
@@ -2839,7 +2868,7 @@ static void __init ivinfo_init(void *ivrs)
 static int __init early_amd_iommu_init(void)
 {
struct acpi_table_header *ivrs_base;
-   int i, remap_cache_sz, ret;
+   int remap_cache_sz, ret;
acpi_status status;
 
if (!amd_iommu_detected)
@@ -2910,12 +2939,6 @@ static int __init early_amd_iommu_init(void)
if (amd_iommu_pd_alloc_bitmap == NULL)
goto out;
 
-   /*
-* let all alias entries point to itself
-*/
-   for (i = 0; i <= amd_iommu_last_bdf; ++i)
-   amd_iommu_alias_table[i] = i;
-
/*
 * never allocate domain 0 because its used as the non-allocated and
   

[PATCH v3 RESEND 07/35] iommu/amd: Introduce per PCI segment old_dev_tbl_cpy

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

It will remove global old_dev_tbl_cpy. Also update copy_device_table()
copy device table for all PCI segments.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h |   6 ++
 drivers/iommu/amd/init.c| 109 
 2 files changed, 70 insertions(+), 45 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 5f3cc704f131..3ef68d588cc7 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -574,6 +574,12 @@ struct amd_iommu_pci_seg {
 * device id quickly.
 */
struct irq_remap_table **irq_lookup_table;
+
+   /*
+* Pointer to a device table which the content of old device table
+* will be copied to. It's only be used in kdump kernel.
+*/
+   struct dev_table_entry *old_dev_tbl_cpy;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 509655f86851..f188130cc173 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -193,11 +193,6 @@ bool amd_iommu_force_isolation __read_mostly;
  * page table root pointer.
  */
 struct dev_table_entry *amd_iommu_dev_table;
-/*
- * Pointer to a device table which the content of old device table
- * will be copied to. It's only be used in kdump kernel.
- */
-static struct dev_table_entry *old_dev_tbl_cpy;
 
 /*
  * The alias table is a driver specific data structure which contains the
@@ -992,39 +987,27 @@ static int get_dev_entry_bit(u16 devid, u8 bit)
 }
 
 
-static bool copy_device_table(void)
+static bool __copy_device_table(struct amd_iommu *iommu)
 {
-   u64 int_ctl, int_tab_len, entry = 0, last_entry = 0;
+   u64 int_ctl, int_tab_len, entry = 0;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
struct dev_table_entry *old_devtb = NULL;
u32 lo, hi, devid, old_devtb_size;
phys_addr_t old_devtb_phys;
-   struct amd_iommu *iommu;
u16 dom_id, dte_v, irq_v;
gfp_t gfp_flag;
u64 tmp;
 
-   if (!amd_iommu_pre_enabled)
-   return false;
-
-   pr_warn("Translation is already enabled - trying to copy translation 
structures\n");
-   for_each_iommu(iommu) {
-   /* All IOMMUs should use the same device table with the same 
size */
-   lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET);
-   hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
-   entry = (((u64) hi) << 32) + lo;
-   if (last_entry && last_entry != entry) {
-   pr_err("IOMMU:%d should use the same dev table as 
others!\n",
-   iommu->index);
-   return false;
-   }
-   last_entry = entry;
+   /* Each IOMMU use separate device table with the same size */
+   lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET);
+   hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
+   entry = (((u64) hi) << 32) + lo;
 
-   old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
-   if (old_devtb_size != dev_table_size) {
-   pr_err("The device table size of IOMMU:%d is not 
expected!\n",
-   iommu->index);
-   return false;
-   }
+   old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
+   if (old_devtb_size != dev_table_size) {
+   pr_err("The device table size of IOMMU:%d is not expected!\n",
+   iommu->index);
+   return false;
}
 
/*
@@ -1047,31 +1030,31 @@ static bool copy_device_table(void)
return false;
 
gfp_flag = GFP_KERNEL | __GFP_ZERO | GFP_DMA32;
-   old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
-   get_order(dev_table_size));
-   if (old_dev_tbl_cpy == NULL) {
+   pci_seg->old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
+   get_order(dev_table_size));
+   if (pci_seg->old_dev_tbl_cpy == NULL) {
pr_err("Failed to allocate memory for copying old device 
table!\n");
memunmap(old_devtb);
return false;
}
 
for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
-   old_dev_tbl_cpy[devid] = old_devtb[devid];
+   pci_seg->old_dev_tbl_cpy[devid] = old_devtb[devid];
dom_id = old_devtb[devid].data[1] & DEV_DOMID_MASK;
dte_v = old_devtb[devid].data[0] & DTE_FLAG_V;
 
if (dte_v && dom_id) {
-   old_dev_tbl_cpy[devid].data[0] = 
old_devtb[devid].data[0];
-   old_dev_tbl_cpy[devid].data[1] = 
old_devtb[devid].data[1];
+   

[PATCH v3 RESEND 06/35] iommu/amd: Introduce per PCI segment dev_data_list

2022-07-06 Thread Vasant Hegde via iommu
This will replace global dev_data_list.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 +++
 drivers/iommu/amd/init.c|  1 +
 drivers/iommu/amd/iommu.c   | 21 ++---
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index cfb5f0e44186..5f3cc704f131 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -546,6 +546,9 @@ struct amd_iommu_pci_seg {
/* List with all PCI segments in the system */
struct list_head list;
 
+   /* List of all available dev_data structures */
+   struct llist_head dev_data_list;
+
/* PCI segment number */
u16 id;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index f6678dd56e28..509655f86851 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1527,6 +1527,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
return NULL;
 
pci_seg->id = id;
+   init_llist_head(_seg->dev_data_list);
list_add_tail(_seg->list, _iommu_pci_seg_list);
 
if (alloc_dev_table(pci_seg))
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index b0262b2e749d..48275da7fcb0 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -62,9 +62,6 @@
 
 static DEFINE_SPINLOCK(pd_bitmap_lock);
 
-/* List of all available dev_data structures */
-static LLIST_HEAD(dev_data_list);
-
 LIST_HEAD(ioapic_map);
 LIST_HEAD(hpet_map);
 LIST_HEAD(acpihid_map);
@@ -195,9 +192,10 @@ static struct protection_domain *to_pdomain(struct 
iommu_domain *dom)
return container_of(dom, struct protection_domain, domain);
 }
 
-static struct iommu_dev_data *alloc_dev_data(u16 devid)
+static struct iommu_dev_data *alloc_dev_data(struct amd_iommu *iommu, u16 
devid)
 {
struct iommu_dev_data *dev_data;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
if (!dev_data)
@@ -207,19 +205,20 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid)
dev_data->devid = devid;
ratelimit_default_init(_data->rs);
 
-   llist_add(_data->dev_data_list, _data_list);
+   llist_add(_data->dev_data_list, _seg->dev_data_list);
return dev_data;
 }
 
-static struct iommu_dev_data *search_dev_data(u16 devid)
+static struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 
devid)
 {
struct iommu_dev_data *dev_data;
struct llist_node *node;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
-   if (llist_empty(_data_list))
+   if (llist_empty(_seg->dev_data_list))
return NULL;
 
-   node = dev_data_list.first;
+   node = pci_seg->dev_data_list.first;
llist_for_each_entry(dev_data, node, dev_data_list) {
if (dev_data->devid == devid)
return dev_data;
@@ -288,10 +287,10 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
struct iommu_dev_data *dev_data;
struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
 
-   dev_data = search_dev_data(devid);
+   dev_data = search_dev_data(iommu, devid);
 
if (dev_data == NULL) {
-   dev_data = alloc_dev_data(devid);
+   dev_data = alloc_dev_data(iommu, devid);
if (!dev_data)
return NULL;
 
@@ -3466,7 +3465,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data 
*data, void *vcpu_info)
struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data;
struct amd_ir_data *ir_data = data->chip_data;
struct irq_2_irte *irte_info = _data->irq_2_irte;
-   struct iommu_dev_data *dev_data = search_dev_data(irte_info->devid);
+   struct iommu_dev_data *dev_data = search_dev_data(NULL, 
irte_info->devid);
 
/* Note:
 * This device has never been set up for guest mode.
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 05/35] iommu/amd: Introduce per PCI segment irq_lookup_table

2022-07-06 Thread Vasant Hegde via iommu
This will replace global irq lookup table (irq_lookup_table).

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  6 ++
 drivers/iommu/amd/init.c| 27 +++
 2 files changed, 33 insertions(+)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index d0ee78c656ff..cfb5f0e44186 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -565,6 +565,12 @@ struct amd_iommu_pci_seg {
 * device id.
 */
struct amd_iommu **rlookup_table;
+
+   /*
+* This table is used to find the irq remapping table for a given
+* device id quickly.
+*/
+   struct irq_remap_table **irq_lookup_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 2fb3e1b82e09..f6678dd56e28 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -684,6 +684,26 @@ static inline void free_rlookup_table(struct 
amd_iommu_pci_seg *pci_seg)
pci_seg->rlookup_table = NULL;
 }
 
+static inline int __init alloc_irq_lookup_table(struct amd_iommu_pci_seg 
*pci_seg)
+{
+   pci_seg->irq_lookup_table = (void *)__get_free_pages(
+GFP_KERNEL | __GFP_ZERO,
+get_order(rlookup_table_size));
+   kmemleak_alloc(pci_seg->irq_lookup_table,
+  rlookup_table_size, 1, GFP_KERNEL);
+   if (pci_seg->irq_lookup_table == NULL)
+   return -ENOMEM;
+
+   return 0;
+}
+
+static inline void free_irq_lookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   kmemleak_free(pci_seg->irq_lookup_table);
+   free_pages((unsigned long)pci_seg->irq_lookup_table,
+  get_order(rlookup_table_size));
+   pci_seg->irq_lookup_table = NULL;
+}
 
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
@@ -1535,6 +1555,7 @@ static void __init free_pci_segments(void)
 
for_each_pci_segment_safe(pci_seg, next) {
list_del(_seg->list);
+   free_irq_lookup_table(pci_seg);
free_rlookup_table(pci_seg);
free_dev_table(pci_seg);
kfree(pci_seg);
@@ -2897,6 +2918,7 @@ static int __init early_amd_iommu_init(void)
amd_iommu_irq_remap = check_ioapic_information();
 
if (amd_iommu_irq_remap) {
+   struct amd_iommu_pci_seg *pci_seg;
/*
 * Interrupt remapping enabled, create kmem_cache for the
 * remapping tables.
@@ -2913,6 +2935,11 @@ static int __init early_amd_iommu_init(void)
if (!amd_iommu_irq_cache)
goto out;
 
+   for_each_pci_segment(pci_seg) {
+   if (alloc_irq_lookup_table(pci_seg))
+   goto out;
+   }
+
irq_lookup_table = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
get_order(rlookup_table_size));
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 04/35] iommu/amd: Introduce per PCI segment rlookup table

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

This will replace global rlookup table (amd_iommu_rlookup_table).
Add helper functions to set/get rlookup table for the given device.
Also add macros to get seg/devid from sbdf.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  1 +
 drivers/iommu/amd/amd_iommu_types.h | 11 
 drivers/iommu/amd/init.c| 23 +++
 drivers/iommu/amd/iommu.c   | 44 +
 4 files changed, 79 insertions(+)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 885570cd0d77..2947239700ce 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -19,6 +19,7 @@ extern int amd_iommu_init_devices(void);
 extern void amd_iommu_uninit_devices(void);
 extern void amd_iommu_init_notifier(void);
 extern int amd_iommu_init_api(void);
+extern void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);
 
 #ifdef CONFIG_AMD_IOMMU_DEBUGFS
 void amd_iommu_debugfs_setup(struct amd_iommu *iommu);
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 422ea87ae4c7..d0ee78c656ff 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -456,6 +456,9 @@ extern bool amdr_ivrs_remap_support;
 /* kmem_cache to get tables with 128 byte alignement */
 extern struct kmem_cache *amd_iommu_irq_cache;
 
+#define PCI_SBDF_TO_SEGID(sbdf)(((sbdf) >> 16) & 0x)
+#define PCI_SBDF_TO_DEVID(sbdf)((sbdf) & 0x)
+
 /* Make iterating over all pci segment easier */
 #define for_each_pci_segment(pci_seg) \
list_for_each_entry((pci_seg), _iommu_pci_seg_list, list)
@@ -490,6 +493,7 @@ struct amd_iommu_fault {
 };
 
 
+struct amd_iommu;
 struct iommu_domain;
 struct irq_domain;
 struct amd_irte_ops;
@@ -554,6 +558,13 @@ struct amd_iommu_pci_seg {
 * page table root pointer.
 */
struct dev_table_entry *dev_table;
+
+   /*
+* The rlookup iommu table is used to find the IOMMU which is
+* responsible for a specific device. It is indexed by the PCI
+* device id.
+*/
+   struct amd_iommu **rlookup_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 5152243593bf..2fb3e1b82e09 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -665,6 +665,26 @@ static inline void free_dev_table(struct amd_iommu_pci_seg 
*pci_seg)
pci_seg->dev_table = NULL;
 }
 
+/* Allocate per PCI segment IOMMU rlookup table. */
+static inline int __init alloc_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   pci_seg->rlookup_table = (void *)__get_free_pages(
+   GFP_KERNEL | __GFP_ZERO,
+   get_order(rlookup_table_size));
+   if (pci_seg->rlookup_table == NULL)
+   return -ENOMEM;
+
+   return 0;
+}
+
+static inline void free_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   free_pages((unsigned long)pci_seg->rlookup_table,
+  get_order(rlookup_table_size));
+   pci_seg->rlookup_table = NULL;
+}
+
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
@@ -1491,6 +1511,8 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
if (alloc_dev_table(pci_seg))
return NULL;
+   if (alloc_rlookup_table(pci_seg))
+   return NULL;
 
return pci_seg;
 }
@@ -1513,6 +1535,7 @@ static void __init free_pci_segments(void)
 
for_each_pci_segment_safe(pci_seg, next) {
list_del(_seg->list);
+   free_rlookup_table(pci_seg);
free_dev_table(pci_seg);
kfree(pci_seg);
}
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index ac8f81f527b4..b0262b2e749d 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -146,6 +146,50 @@ struct dev_table_entry *get_dev_table(struct amd_iommu 
*iommu)
return dev_table;
 }
 
+static inline u16 get_device_segment(struct device *dev)
+{
+   u16 seg;
+
+   if (dev_is_pci(dev)) {
+   struct pci_dev *pdev = to_pci_dev(dev);
+
+   seg = pci_domain_nr(pdev->bus);
+   } else {
+   u32 devid = get_acpihid_device_id(dev, NULL);
+
+   seg = PCI_SBDF_TO_SEGID(devid);
+   }
+
+   return seg;
+}
+
+/* Writes the specific IOMMU for a device into the PCI segment rlookup table */
+void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid)
+{
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+   pci_seg->rlookup_table[devid] = iommu;
+}
+
+static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 devid)
+{
+   struct 

[PATCH v3 RESEND 03/35] iommu/amd: Introduce per PCI segment device table

2022-07-06 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Introduce per PCI segment device table. All IOMMUs within the segment
will share this device table. This will replace global device
table i.e. amd_iommu_dev_table.

Also introduce helper function to get the device table for the given IOMMU.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  1 +
 drivers/iommu/amd/amd_iommu_types.h | 10 ++
 drivers/iommu/amd/init.c| 26 --
 drivers/iommu/amd/iommu.c   | 12 
 4 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 1ab31074f5b3..885570cd0d77 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -128,4 +128,5 @@ static inline void amd_iommu_apply_ivrs_quirks(void) { }
 
 extern void amd_iommu_domain_set_pgtable(struct protection_domain *domain,
 u64 *root, int mode);
+extern struct dev_table_entry *get_dev_table(struct amd_iommu *iommu);
 #endif
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 2243b1a22d78..422ea87ae4c7 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -544,6 +544,16 @@ struct amd_iommu_pci_seg {
 
/* PCI segment number */
u16 id;
+
+   /*
+* device table virtual address
+*
+* Pointer to the per PCI segment device table.
+* It is indexed by the PCI device id or the HT unit id and contains
+* information about the domain the device belongs to as well as the
+* page table root pointer.
+*/
+   struct dev_table_entry *dev_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index c1b5d530dbf3..5152243593bf 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -642,11 +642,29 @@ static int __init find_last_devid_acpi(struct 
acpi_table_header *table)
  *
  * The following functions belong to the code path which parses the ACPI table
  * the second time. In this ACPI parsing iteration we allocate IOMMU specific
- * data structures, initialize the device/alias/rlookup table and also
- * basically initialize the hardware.
+ * data structures, initialize the per PCI segment device/alias/rlookup table
+ * and also basically initialize the hardware.
  *
  /
 
+/* Allocate per PCI segment device table */
+static inline int __init alloc_dev_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   pci_seg->dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO | 
GFP_DMA32,
+ 
get_order(dev_table_size));
+   if (!pci_seg->dev_table)
+   return -ENOMEM;
+
+   return 0;
+}
+
+static inline void free_dev_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   free_pages((unsigned long)pci_seg->dev_table,
+   get_order(dev_table_size));
+   pci_seg->dev_table = NULL;
+}
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
@@ -1471,6 +1489,9 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
pci_seg->id = id;
list_add_tail(_seg->list, _iommu_pci_seg_list);
 
+   if (alloc_dev_table(pci_seg))
+   return NULL;
+
return pci_seg;
 }
 
@@ -1492,6 +1513,7 @@ static void __init free_pci_segments(void)
 
for_each_pci_segment_safe(pci_seg, next) {
list_del(_seg->list);
+   free_dev_table(pci_seg);
kfree(pci_seg);
}
 }
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index efa8af5a9419..ac8f81f527b4 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -134,6 +134,18 @@ static inline int get_device_id(struct device *dev)
return devid;
 }
 
+struct dev_table_entry *get_dev_table(struct amd_iommu *iommu)
+{
+   struct dev_table_entry *dev_table;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+   BUG_ON(pci_seg == NULL);
+   dev_table = pci_seg->dev_table;
+   BUG_ON(dev_table == NULL);
+
+   return dev_table;
+}
+
 static struct protection_domain *to_pdomain(struct iommu_domain *dom)
 {
return container_of(dom, struct protection_domain, domain);
-- 
2.31.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 RESEND 02/35] iommu/amd: Introduce pci segment structure

2022-07-06 Thread Vasant Hegde via iommu
Newer AMD systems can support multiple PCI segments, where each segment
contains one or more IOMMU instances. However, an IOMMU instance can only
support a single PCI segment.

Current code assumes that system contains only one pci segment (segment 0)
and creates global data structures such as device table, rlookup table,
etc.

Introducing per PCI segment data structure, which contains segment
specific data structures. This will eventually replace the global
data structures.

Also update `amd_iommu->pci_seg` variable to point to PCI segment
structure instead of PCI segment ID.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 24 ++-
 drivers/iommu/amd/init.c| 46 -
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 9b563f850f1d..2243b1a22d78 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -456,6 +456,11 @@ extern bool amdr_ivrs_remap_support;
 /* kmem_cache to get tables with 128 byte alignement */
 extern struct kmem_cache *amd_iommu_irq_cache;
 
+/* Make iterating over all pci segment easier */
+#define for_each_pci_segment(pci_seg) \
+   list_for_each_entry((pci_seg), _iommu_pci_seg_list, list)
+#define for_each_pci_segment_safe(pci_seg, next) \
+   list_for_each_entry_safe((pci_seg), (next), _iommu_pci_seg_list, 
list)
 /*
  * Make iterating over all IOMMUs easier
  */
@@ -530,6 +535,17 @@ struct protection_domain {
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
 };
 
+/*
+ * This structure contains information about one PCI segment in the system.
+ */
+struct amd_iommu_pci_seg {
+   /* List with all PCI segments in the system */
+   struct list_head list;
+
+   /* PCI segment number */
+   u16 id;
+};
+
 /*
  * Structure where we save information about one hardware AMD IOMMU in the
  * system.
@@ -581,7 +597,7 @@ struct amd_iommu {
u16 cap_ptr;
 
/* pci domain of this IOMMU */
-   u16 pci_seg;
+   struct amd_iommu_pci_seg *pci_seg;
 
/* start of exclusion range of that IOMMU */
u64 exclusion_start;
@@ -709,6 +725,12 @@ extern struct list_head ioapic_map;
 extern struct list_head hpet_map;
 extern struct list_head acpihid_map;
 
+/*
+ * List with all PCI segments in the system. This list is not locked because
+ * it is only written at driver initialization time
+ */
+extern struct list_head amd_iommu_pci_seg_list;
+
 /*
  * List with all IOMMUs in the system. This list is not locked because it is
  * only written and read at driver initialization or suspend time
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 1d08f87e734b..c1b5d530dbf3 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -164,6 +164,7 @@ u16 amd_iommu_last_bdf; /* largest PCI 
device id we have
 LIST_HEAD(amd_iommu_unity_map);/* a list of required unity 
mappings
   we find in ACPI */
 
+LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
   system */
 
@@ -1458,6 +1459,43 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
return 0;
 }
 
+/* Allocate PCI segment data structure */
+static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
+{
+   struct amd_iommu_pci_seg *pci_seg;
+
+   pci_seg = kzalloc(sizeof(struct amd_iommu_pci_seg), GFP_KERNEL);
+   if (pci_seg == NULL)
+   return NULL;
+
+   pci_seg->id = id;
+   list_add_tail(_seg->list, _iommu_pci_seg_list);
+
+   return pci_seg;
+}
+
+static struct amd_iommu_pci_seg *__init get_pci_segment(u16 id)
+{
+   struct amd_iommu_pci_seg *pci_seg;
+
+   for_each_pci_segment(pci_seg) {
+   if (pci_seg->id == id)
+   return pci_seg;
+   }
+
+   return alloc_pci_segment(id);
+}
+
+static void __init free_pci_segments(void)
+{
+   struct amd_iommu_pci_seg *pci_seg, *next;
+
+   for_each_pci_segment_safe(pci_seg, next) {
+   list_del(_seg->list);
+   kfree(pci_seg);
+   }
+}
+
 static void __init free_iommu_one(struct amd_iommu *iommu)
 {
free_cwwb_sem(iommu);
@@ -1544,8 +1582,14 @@ static void amd_iommu_ats_write_check_workaround(struct 
amd_iommu *iommu)
  */
 static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header 
*h)
 {
+   struct amd_iommu_pci_seg *pci_seg;
int ret;
 
+   pci_seg = get_pci_segment(h->pci_seg);
+   if (pci_seg == NULL)
+   return -ENOMEM;
+   iommu->pci_seg = pci_seg;
+
raw_spin_lock_init(>lock);
iommu->cmd_sem_val = 0;
 

[PATCH v3 RESEND 01/35] iommu/amd: Update struct iommu_dev_data definition

2022-07-06 Thread Vasant Hegde via iommu
struct iommu_dev_data contains member "pdev" to point to pci_dev. This is
valid for only PCI devices and for other devices this will be NULL. This
causes unnecessary "pdev != NULL" check at various places.

Replace "struct pci_dev" member with "struct device" and use to_pci_dev()
to get pci device reference as needed. Also adjust setup_aliases() and
clone_aliases() function.

No functional change intended.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  2 +-
 drivers/iommu/amd/iommu.c   | 32 +
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 72d0f5e2f651..9b563f850f1d 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -689,7 +689,7 @@ struct iommu_dev_data {
struct list_head list;/* For domain->dev_list */
struct llist_node dev_data_list;  /* For global dev_data_list */
struct protection_domain *domain; /* Domain the device is bound to */
-   struct pci_dev *pdev;
+   struct device *dev;
u16 devid;/* PCI Device ID */
bool iommu_v2;/* Device can make use of IOMMUv2 */
struct {
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 840831d5d2ad..efa8af5a9419 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -188,10 +188,13 @@ static int clone_alias(struct pci_dev *pdev, u16 alias, 
void *data)
return 0;
 }
 
-static void clone_aliases(struct pci_dev *pdev)
+static void clone_aliases(struct device *dev)
 {
-   if (!pdev)
+   struct pci_dev *pdev;
+
+   if (!dev_is_pci(dev))
return;
+   pdev = to_pci_dev(dev);
 
/*
 * The IVRS alias stored in the alias table may not be
@@ -203,14 +206,14 @@ static void clone_aliases(struct pci_dev *pdev)
pci_for_each_dma_alias(pdev, clone_alias, NULL);
 }
 
-static struct pci_dev *setup_aliases(struct device *dev)
+static void setup_aliases(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
u16 ivrs_alias;
 
/* For ACPI HID devices, there are no aliases */
if (!dev_is_pci(dev))
-   return NULL;
+   return;
 
/*
 * Add the IVRS alias to the pci aliases if it is on the same
@@ -221,9 +224,7 @@ static struct pci_dev *setup_aliases(struct device *dev)
PCI_BUS_NUM(ivrs_alias) == pdev->bus->number)
pci_add_dma_alias(pdev, ivrs_alias & 0xff, 1);
 
-   clone_aliases(pdev);
-
-   return pdev;
+   clone_aliases(dev);
 }
 
 static struct iommu_dev_data *find_dev_data(u16 devid)
@@ -331,7 +332,8 @@ static int iommu_init_device(struct device *dev)
if (!dev_data)
return -ENOMEM;
 
-   dev_data->pdev = setup_aliases(dev);
+   dev_data->dev = dev;
+   setup_aliases(dev);
 
/*
 * By default we use passthrough mode for IOMMUv2 capable device.
@@ -1232,13 +1234,17 @@ static int device_flush_dte_alias(struct pci_dev *pdev, 
u16 alias, void *data)
 static int device_flush_dte(struct iommu_dev_data *dev_data)
 {
struct amd_iommu *iommu;
+   struct pci_dev *pdev = NULL;
u16 alias;
int ret;
 
iommu = amd_iommu_rlookup_table[dev_data->devid];
 
-   if (dev_data->pdev)
-   ret = pci_for_each_dma_alias(dev_data->pdev,
+   if (dev_is_pci(dev_data->dev))
+   pdev = to_pci_dev(dev_data->dev);
+
+   if (pdev)
+   ret = pci_for_each_dma_alias(pdev,
 device_flush_dte_alias, iommu);
else
ret = iommu_flush_dte(iommu, dev_data->devid);
@@ -1561,7 +1567,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
/* Update device table */
set_dte_entry(dev_data->devid, domain,
  ats, dev_data->iommu_v2);
-   clone_aliases(dev_data->pdev);
+   clone_aliases(dev_data->dev);
 
device_flush_dte(dev_data);
 }
@@ -1577,7 +1583,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
dev_data->domain = NULL;
list_del(_data->list);
clear_dte_entry(dev_data->devid);
-   clone_aliases(dev_data->pdev);
+   clone_aliases(dev_data->dev);
 
/* Flush the DTE entry */
device_flush_dte(dev_data);
@@ -1818,7 +1824,7 @@ static void update_device_table(struct protection_domain 
*domain)
list_for_each_entry(dev_data, >dev_list, list) {
set_dte_entry(dev_data->devid, domain,
  dev_data->ats.enabled, dev_data->iommu_v2);
-   clone_aliases(dev_data->pdev);
+   clone_aliases(dev_data->dev);
}
 }
 
-- 
2.31.1


[PATCH v3 RESEND 00/35] iommu/amd: Add multiple PCI segments support

2022-07-06 Thread Vasant Hegde via iommu
Hi Joerg,
   As discussed in other thread, I have updated "From:" tag and
   resending patchset. No changes in the actual patch content.
   This patchset is based on top on "iommu/x86/amd" branch.
   Base commit : 0d10fe75911787 ("iommu/amd: Use try_cmpxchg64 in ")

Newer AMD systems can support multiple PCI segments, where each segment
contains one or more IOMMU instances. However, an IOMMU instance can only
support a single PCI segment.

Current code assumes a system contains only one PCI segment (segment 0)
and creates global data structures such as device table, rlookup table,
etc.

This series introduces per-PCI-segment data structure, which contains
device table, alias table, etc. For each PCI segment, all IOMMUs
share the same data structure. The series also makes necessary code
adjustment and logging enhancements. Finally it removes global data
structures like device table, alias table, etc.

In case of system w/ single PCI segment (e.g. PCI segment ID is zero),
IOMMU driver allocates one PCI segment data structure, which will
be shared by all IOMMUs.

Patch 1 updates struct iommu_dev_data definition.

Patch 2 - 13 introduce new PCI segment structure and allocate per
data structures, and introduce the amd_iommu.pci_seg pointer to point
to the corresponded pci_segment structure. Also, we have introduced
a helper function rlookup_amd_iommu() to reverse-lookup each iommu
for a particular device.

Patch 14 - 27 adopt to per PCI segment data structure and removes
global data structure.

Patch 28 fixes flushing logic to flush upto last_bdf.

Patch 29 - 35 convert usages of 16-bit PCI device ID to include
16-bit segment ID.

v3 patchset: 
https://lore.kernel.org/linux-iommu/20220511072141.15485-1-vasant.he...@amd.com/

Changes from v2 -> v3:
  - Addressed Joerg's review comments
- Fixed typo in patch 1 subject
- Fixed few minor things in patch 2
- Merged patch 27 - 29 into one patch
- Added new macros to get seg and devid from sbdf
  - Patch 32 : Extend devid to 32bit and added new macro.

v2 patchset : 
https://lore.kernel.org/linux-iommu/20220425113415.24087-1-vasant.he...@amd.com/T/#t

Changes from v1 -> v2:
  - Updated patch 1 to include dev_is_pci() check

v1 patchset : 
https://lore.kernel.org/linux-iommu/20220404100023.324645-1-vasant.he...@amd.com/T/#t

Changes from RFC -> v1:
  - Rebased patches on top of iommu/next tree.
  - Update struct iommu_dev_data definition
  - Updated few log message to print segment ID
  - Fix smatch warnings

RFC patchset : 
https://lore.kernel.org/linux-iommu/20220311094854.31595-1-vasant.he...@amd.com/T/#t


Regards,
Vasant

Suravee Suthikulpanit (20):
  iommu/amd: Introduce per PCI segment device table
  iommu/amd: Introduce per PCI segment rlookup table
  iommu/amd: Introduce per PCI segment old_dev_tbl_cpy
  iommu/amd: Introduce per PCI segment alias_table
  iommu/amd: Convert to use rlookup_amd_iommu helper function
  iommu/amd: Update irq_remapping_alloc to use IOMMU lookup helper function
  iommu/amd: Introduce struct amd_ir_data.iommu
  iommu/amd: Update amd_irte_ops functions
  iommu/amd: Update alloc_irq_table and alloc_irq_index
  iommu/amd: Update set_dte_entry and clear_dte_entry
  iommu/amd: Update iommu_ignore_device
  iommu/amd: Update dump_dte_entry
  iommu/amd: Update set_dte_irq_entry
  iommu/amd: Update (un)init_device_table_dma()
  iommu/amd: Update set_dev_entry_bit() and get_dev_entry_bit()
  iommu/amd: Remove global amd_iommu_[dev_table/alias_table/last_bdf]
  iommu/amd: Introduce get_device_sbdf_id() helper function
  iommu/amd: Include PCI segment ID when initialize IOMMU
  iommu/amd: Specify PCI segment ID when getting pci device
  iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands

Vasant Hegde (15):
  iommu/amd: Update struct iommu_dev_data definition
  iommu/amd: Introduce pci segment structure
  iommu/amd: Introduce per PCI segment irq_lookup_table
  iommu/amd: Introduce per PCI segment dev_data_list
  iommu/amd: Introduce per PCI segment unity map list
  iommu/amd: Introduce per PCI segment last_bdf
  iommu/amd: Introduce per PCI segment device table size
  iommu/amd: Introduce per PCI segment alias table size
  iommu/amd: Introduce per PCI segment rlookup table size
  iommu/amd: Convert to use per PCI segment irq_lookup_table
  iommu/amd: Convert to use per PCI segment rlookup_table
  iommu/amd: Flush upto last_bdf only
  iommu/amd: Print PCI segment ID in error log messages
  iommu/amd: Update device_state structure to include PCI seg ID
  iommu/amd: Update amd_iommu_fault structure to include PCI seg ID

 .../admin-guide/kernel-parameters.txt |  34 +-
 drivers/iommu/amd/amd_iommu.h |  13 +-
 drivers/iommu/amd/amd_iommu_types.h   | 133 +++-
 drivers/iommu/amd/init.c  | 687 +++---
 drivers/iommu/amd/iommu.c | 563 --
 drivers/iommu/amd/iommu_v2.c  |  67 +-
 

Re: [PATCH v1 0/7] iommu/amd: Add Generic IO Page Table Framework Support for v2 Page Table

2022-06-28 Thread Vasant Hegde via iommu
Hi Joerg,

On 6/23/2022 1:45 PM, Joerg Roedel wrote:
> On Fri, Jun 03, 2022 at 04:51:00PM +0530, Vasant Hegde wrote:
>> - Part 1 (patch 1-4 and 6)
>>   Refactor the current IOMMU page table code to adopt the generic IO page
>>   table framework, and add AMD IOMMU Guest (v2) page table management code.
>>
>> - Part 2 (patch 5)
>>   Add support for the AMD IOMMU Guest IO Protection feature (GIOV)
>>   where requests from the I/O device without a PASID are treated as
>>   if they have PASID of 0.
>>
>> - Part 3 (patch 7)
>>   Introduce new "amd_iommu_pgtable" command-line to allow users
>>   to select the mode of operation (v1 or v2).
> 
> Something I didn't get entirely from the review is support level of the
> amd_iommu_v2 driver. I think it will continue to work and the
> requirement that the device identity maps DMA requests without PASID is
> removed, right?

Sorry. I didn't get last statement ("device identity maps DMA requests without 
PASID").
Can you please elaborate?

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v1 7/7] iommu/amd: Introduce amd_iommu_pgtable command-line option

2022-06-28 Thread Vasant Hegde via iommu
Hi Joerg,


On 6/23/2022 1:42 PM, Joerg Roedel wrote:
> On Fri, Jun 03, 2022 at 04:51:07PM +0530, Vasant Hegde wrote:
>> +amd_iommu_pgtable= [HW,X86-64]
>> +Specifies one of the following AMD IOMMU page table to
>> +be used for DMA remapping for DMA-API:
>> +v1 - Use v1 page table (Default)
>> +v2 - Use v2 page table
>> +
> 
> Can we handle this somehow in the amd_iommu= option? Something like
> amd_iommu=pgtbl_v2|pgtbl_v1?
> 

I think it will complicate the parsing logic. We do have `amd_iommu=off` option.
How are we going to handle `amd_iommu=off,[pgtable_v1/v2]` ? 

-Vasant
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v3 00/35] iommu/amd: Add multiple PCI segments support

2022-06-28 Thread Vasant Hegde via iommu
Hi Joerg,

On 6/23/2022 1:24 PM, Joerg Roedel wrote:
> Hi Vasant,
> 
> On Wed, May 11, 2022 at 12:51:06PM +0530, Vasant Hegde wrote:
>>  .../admin-guide/kernel-parameters.txt |  34 +-
>>  drivers/iommu/amd/amd_iommu.h |  13 +-
>>  drivers/iommu/amd/amd_iommu_types.h   | 133 +++-
>>  drivers/iommu/amd/init.c  | 687 +++---
>>  drivers/iommu/amd/iommu.c | 563 --
>>  drivers/iommu/amd/iommu_v2.c  |  67 +-
>>  drivers/iommu/amd/quirks.c|   4 +-
>>  7 files changed, 904 insertions(+), 597 deletions(-)
> 
> So this is applied now to the IOMMU tree, thanks for the work. Something
> that bothered me while looking at this was the almost complete lack of
> locking while accessing the global data structures. Some of them are
> lock-less, so it is partially fine, and most of them are used read-only
> during system runtime. But I would appreciate if you and/or Suravee
> could look over that again and check again if there needs to be more
> locking.

Thanks. We did look into the code and we think it should be fine for now.

> 
> The current situation will fire back at the point where you want to
> implement IOMMU hotplug. Note that device hotplug is already possible
> today, either with real devices or SR-IOV.

You are right. We think IOMMU hotplug support needs lot more changes
including locking existing global structures. We will look into it
whenever we support IOMMU hotplug.

-Vasant

> 
> Regards,
> 
>   Joerg
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v1 3/7] iommu/amd: Fix sparse warning

2022-06-27 Thread Vasant Hegde via iommu


On 6/23/2022 3:12 PM, Robin Murphy wrote:
> On 2022-06-23 09:03, Joerg Roedel wrote:
>> On Fri, Jun 03, 2022 at 04:51:03PM +0530, Vasant Hegde wrote:
>>> Fix below sparse warning:
>>>    CHECK   drivers/iommu/amd/iommu.c
>>>    drivers/iommu/amd/iommu.c:73:24: warning: symbol 'amd_iommu_ops' was not 
>>> declared. Should it be static?
>>>
>>> Also we are going to introduce v2 page table which has different
>>> pgsize_bitmaps. Hence remove 'const' qualifier.
>>
>> I am not a fan of removing the consts. Please use separate ops
>> structures for v2 page-tables and make then const as well. This probably
>> also has some optimization potential in the future when we can make the
>> ops call-back functions page-table specific.
> 
> TBH it's probably time to retire iommu_ops->pgsize_bitmap anyway. At the very 
> least it would be logical to move it to iommu_domain_ops now, but maybe we 
> could skip ahead and just rely on drivers initialising domain->pgsize_bitmap 
> directly in their .domain_alloc?
> 

Robin,

Something like below? If yes, I will cleanup and get proper fix.


-Vasant


diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 840831d5d2ad..32dd84a7c1da 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1916,6 +1916,7 @@ static int protection_domain_init_v1(struct 
protection_domain *domain, int mode)
return -ENOMEM;
}
 
+   domain->domain.pgsize_bitmap= AMD_IOMMU_PGSIZES;
amd_iommu_domain_set_pgtable(domain, pt_root, mode);
 
return 0;
@@ -2282,7 +2283,6 @@ const struct iommu_ops amd_iommu_ops = {
.get_resv_regions = amd_iommu_get_resv_regions,
.put_resv_regions = generic_iommu_put_resv_regions,
.is_attach_deferred = amd_iommu_is_attach_deferred,
-   .pgsize_bitmap  = AMD_IOMMU_PGSIZES,
.def_domain_type = amd_iommu_def_domain_type,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = amd_iommu_attach_device,
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 847ad47a2dfd..73cfba6a6728 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1915,8 +1915,6 @@ static struct iommu_domain *__iommu_domain_alloc(struct 
bus_type *bus,
return NULL;
 
domain->type = type;
-   /* Assume all sizes by default; the driver may override this later */
-   domain->pgsize_bitmap = bus->iommu_ops->pgsize_bitmap;
if (!domain->ops)
domain->ops = bus->iommu_ops->default_domain_ops;
 
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5e1afe169549..0c028aa71b96 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -255,7 +255,6 @@ struct iommu_ops {
int (*def_domain_type)(struct device *dev);
 
const struct iommu_domain_ops *default_domain_ops;
-   unsigned long pgsize_bitmap;
struct module *owner;
 };
 


> (and FWIW I'm leaning towards the same for the domain->ops as well; the more 
> I look at ops->default_domain_ops, the more it starts looking like a stupid 
> mess... my stupid mess... sorry about that)
> 
> Robin.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH v3 00/35] iommu/amd: Add multiple PCI segments support

2022-06-22 Thread Vasant Hegde via iommu
Hi Joerg,

On 6/7/2022 4:17 PM, Vasant Hegde wrote:
> Hello Joerg,
> 
> 
> On 5/20/2022 5:42 PM, Vasant Hegde wrote:
>> Joerg,
>>
>>
>> On 5/20/2022 3:33 PM, Joerg Roedel wrote:
>>> Hi Vasant,
>>>
>>> On Fri, May 20, 2022 at 03:25:38PM +0530, Vasant Hegde wrote:
 Ping. Did you get a chance to look into this series?
>>>
>>> Sorry, too late for this round. The changes are pretty invasive and
>>> merging them at -rc7 stage would not give them enough testing before
>>> being merged. Please send me a reminder after the next merge window.
>>
>> Sure. I will remind you after v5.19 merge window closes.
> 
> Ping. Can you please take a look of this series?
> Do you want me to rebase patchset on to of v5.19-rc1 -OR- latest iommu/next 
> branch?
> 

Ping?

-Vasant
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v3 00/35] iommu/amd: Add multiple PCI segments support

2022-06-07 Thread Vasant Hegde via iommu
Hello Joerg,


On 5/20/2022 5:42 PM, Vasant Hegde wrote:
> Joerg,
> 
> 
> On 5/20/2022 3:33 PM, Joerg Roedel wrote:
>> Hi Vasant,
>>
>> On Fri, May 20, 2022 at 03:25:38PM +0530, Vasant Hegde wrote:
>>> Ping. Did you get a chance to look into this series?
>>
>> Sorry, too late for this round. The changes are pretty invasive and
>> merging them at -rc7 stage would not give them enough testing before
>> being merged. Please send me a reminder after the next merge window.
> 
> Sure. I will remind you after v5.19 merge window closes.

Ping. Can you please take a look of this series?
Do you want me to rebase patchset on to of v5.19-rc1 -OR- latest iommu/next 
branch?

-Vasant
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 7/7] iommu/amd: Introduce amd_iommu_pgtable command-line option

2022-06-03 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

To allow specification whether to use v1 or v2 IOMMU pagetable for
DMA remapping when calling kernel DMA-API.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 Documentation/admin-guide/kernel-parameters.txt |  6 ++
 drivers/iommu/amd/init.c| 17 +
 2 files changed, 23 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index cc8f0c82ff55..d912c4c8b610 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -337,6 +337,12 @@
 This mode requires kvm-amd.avic=1.
 (Default when IOMMU HW support is present.)
 
+   amd_iommu_pgtable= [HW,X86-64]
+   Specifies one of the following AMD IOMMU page table to
+   be used for DMA remapping for DMA-API:
+   v1 - Use v1 page table (Default)
+   v2 - Use v2 page table
+
amijoy.map= [HW,JOY] Amiga joystick support
Map of devices attached to JOY0DAT and JOY1DAT
Format: ,
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index d4d9c812305d..3fae018f62d8 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -3264,6 +3264,22 @@ static int __init parse_amd_iommu_dump(char *str)
return 1;
 }
 
+static int __init parse_amd_iommu_pgtable(char *str)
+{
+   for (; *str; ++str) {
+   if (strncmp(str, "v1", 2) == 0) {
+   amd_iommu_pgtable = AMD_IOMMU_V1;
+   amd_iommu_ops.pgsize_bitmap = AMD_IOMMU_PGSIZES;
+   break;
+   } else if (strncmp(str, "v2", 2) == 0) {
+   amd_iommu_pgtable = AMD_IOMMU_V2;
+   amd_iommu_ops.pgsize_bitmap = AMD_IOMMU_PGSIZES_V2;
+   break;
+   }
+   }
+   return 1;
+}
+
 static int __init parse_amd_iommu_intr(char *str)
 {
for (; *str; ++str) {
@@ -3397,6 +3413,7 @@ static int __init parse_ivrs_acpihid(char *str)
 
 __setup("amd_iommu_dump",  parse_amd_iommu_dump);
 __setup("amd_iommu=",  parse_amd_iommu_options);
+__setup("amd_iommu_pgtable=",  parse_amd_iommu_pgtable);
 __setup("amd_iommu_intr=", parse_amd_iommu_intr);
 __setup("ivrs_ioapic", parse_ivrs_ioapic);
 __setup("ivrs_hpet",   parse_ivrs_hpet);
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 6/7] iommu/amd: Add support for using AMD IOMMU v2 page table for DMA-API

2022-06-03 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Introduce init function for setting up DMA domain for DMA-API with
the IOMMU v2 page table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index f2d939b7cc4d..e5aef845f01c 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2029,6 +2029,24 @@ static int protection_domain_init_v1(struct 
protection_domain *domain, int mode)
return 0;
 }
 
+static int protection_domain_init_v2(struct protection_domain *domain)
+{
+   spin_lock_init(>lock);
+   domain->id = domain_id_alloc();
+   if (!domain->id)
+   return -ENOMEM;
+   INIT_LIST_HEAD(>dev_list);
+
+   domain->flags |= PD_GIOV_MASK;
+
+   if (domain_enable_v2(domain, 1, false)) {
+   domain_id_free(domain->id);
+   return -ENOMEM;
+   }
+
+   return 0;
+}
+
 static struct protection_domain *protection_domain_alloc(unsigned int type)
 {
struct io_pgtable_ops *pgtbl_ops;
@@ -2056,6 +2074,9 @@ static struct protection_domain 
*protection_domain_alloc(unsigned int type)
case AMD_IOMMU_V1:
ret = protection_domain_init_v1(domain, mode);
break;
+   case AMD_IOMMU_V2:
+   ret = protection_domain_init_v2(domain);
+   break;
default:
ret = -EINVAL;
}
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 5/7] iommu/amd: Add support for Guest IO protection

2022-06-03 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

AMD IOMMU introduces support for Guest I/O protection where the request
from the I/O device without a PASID are treated as if they have PASID 0.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h | 3 +++
 drivers/iommu/amd/init.c| 8 
 drivers/iommu/amd/iommu.c   | 5 +
 3 files changed, 16 insertions(+)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 4062313a2407..a25c24188104 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -93,6 +93,7 @@
 #define FEATURE_HE (1ULL<<8)
 #define FEATURE_PC (1ULL<<9)
 #define FEATURE_GAM_VAPIC  (1ULL<<21)
+#define FEATURE_GIOSUP (1ULL<<48)
 #define FEATURE_EPHSUP (1ULL<<50)
 #define FEATURE_SNP(1ULL<<63)
 
@@ -370,6 +371,7 @@
 #define DTE_FLAG_IW (1ULL << 62)
 
 #define DTE_FLAG_IOTLB (1ULL << 32)
+#define DTE_FLAG_GIOV  (1ULL << 54)
 #define DTE_FLAG_GV(1ULL << 55)
 #define DTE_FLAG_MASK  (0x3ffULL << 32)
 #define DTE_GLX_SHIFT  (56)
@@ -427,6 +429,7 @@
 #define PD_PASSTHROUGH_MASK(1UL << 2) /* domain has no page
  translation */
 #define PD_IOMMUV2_MASK(1UL << 3) /* domain has gcr3 table */
+#define PD_GIOV_MASK   (1UL << 4) /* domain enable GIOV support */
 
 extern bool amd_iommu_dump;
 #define DUMP_printk(format, arg...)\
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 453afce7d478..d4d9c812305d 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -2024,6 +2024,12 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
 
init_iommu_perf_ctr(iommu);
 
+   if (amd_iommu_pgtable == AMD_IOMMU_V2 &&
+   !iommu_feature(iommu, FEATURE_GIOSUP)) {
+   pr_warn("Cannot enable v2 page table for DMA-API. Fallback to 
v1.\n");
+   amd_iommu_pgtable = AMD_IOMMU_V1;
+   }
+
if (is_rd890_iommu(iommu->dev)) {
int i, j;
 
@@ -2098,6 +2104,8 @@ static void print_iommu_info(void)
if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE)
pr_info("X2APIC enabled\n");
}
+   if (amd_iommu_pgtable == AMD_IOMMU_V2)
+   pr_info("V2 page table enabled\n");
 }
 
 static int __init amd_iommu_init_pci(void)
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index deb546266d42..f2d939b7cc4d 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1553,6 +1553,11 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
 
pte_root |= (domain->iop.mode & DEV_ENTRY_MODE_MASK)
<< DEV_ENTRY_MODE_SHIFT;
+
+   if ((domain->flags & PD_IOMMUV2_MASK) &&
+   (domain->flags & PD_GIOV_MASK))
+   pte_root |= DTE_FLAG_GIOV;
+
pte_root |= DTE_FLAG_IR | DTE_FLAG_IW | DTE_FLAG_V | DTE_FLAG_TV;
 
flags = dev_table[devid].data[1];
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 4/7] iommu/amd: Initial support for AMD IOMMU v2 page table

2022-06-03 Thread Vasant Hegde via iommu
Introduce IO page table framework support for AMD IOMMU v2 page table.
This patch implements 4 level page table within iommu amd driver and
supports 4K/2M/1G page sizes.

Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/Makefile  |   2 +-
 drivers/iommu/amd/amd_iommu_types.h |   5 +-
 drivers/iommu/amd/io_pgtable_v2.c   | 407 
 drivers/iommu/io-pgtable.c  |   1 +
 include/linux/io-pgtable.h  |   2 +
 5 files changed, 415 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iommu/amd/io_pgtable_v2.c

diff --git a/drivers/iommu/amd/Makefile b/drivers/iommu/amd/Makefile
index a935f8f4b974..773d8aa00283 100644
--- a/drivers/iommu/amd/Makefile
+++ b/drivers/iommu/amd/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_AMD_IOMMU) += iommu.o init.o quirks.o io_pgtable.o
+obj-$(CONFIG_AMD_IOMMU) += iommu.o init.o quirks.o io_pgtable.o io_pgtable_v2.o
 obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += debugfs.o
 obj-$(CONFIG_AMD_IOMMU_V2) += iommu_v2.o
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 328572cf6fa5..4062313a2407 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -268,6 +268,8 @@
  * 512GB Pages are not supported due to a hardware bug
  */
 #define AMD_IOMMU_PGSIZES  ((~0xFFFUL) & ~(2ULL << 38))
+/* 4K, 2MB, 1G page sizes are supported */
+#define AMD_IOMMU_PGSIZES_V2   (PAGE_SIZE | (1ULL << 21) | (1ULL << 30))
 
 /* Bit value definition for dte irq remapping fields*/
 #define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
@@ -514,7 +516,8 @@ struct amd_io_pgtable {
struct io_pgtable   iop;
int mode;
u64 *root;
-   atomic64_t  pt_root;/* pgtable root and pgtable mode */
+   atomic64_t  pt_root;/* pgtable root and pgtable 
mode */
+   u64 *pgd;   /* v2 pgtable pgd pointer */
 };
 
 /*
diff --git a/drivers/iommu/amd/io_pgtable_v2.c 
b/drivers/iommu/amd/io_pgtable_v2.c
new file mode 100644
index ..4248a182a780
--- /dev/null
+++ b/drivers/iommu/amd/io_pgtable_v2.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * CPU-agnostic AMD IO page table v2 allocator.
+ *
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ * Author: Suravee Suthikulpanit 
+ * Author: Vasant Hegde 
+ */
+
+#define pr_fmt(fmt)"AMD-Vi: " fmt
+#define dev_fmt(fmt)   pr_fmt(fmt)
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include "amd_iommu_types.h"
+#include "amd_iommu.h"
+
+#define IOMMU_PAGE_PRESENT BIT_ULL(0)  /* Is present */
+#define IOMMU_PAGE_RW  BIT_ULL(1)  /* Writeable */
+#define IOMMU_PAGE_USERBIT_ULL(2)  /* Userspace 
addressable */
+#define IOMMU_PAGE_PWT BIT_ULL(3)  /* Page write through */
+#define IOMMU_PAGE_PCD BIT_ULL(4)  /* Page cache disabled */
+#define IOMMU_PAGE_ACCESS  BIT_ULL(5)  /* Was accessed (updated by 
IOMMU) */
+#define IOMMU_PAGE_DIRTY   BIT_ULL(6)  /* Was written to (updated by 
IOMMU) */
+#define IOMMU_PAGE_PSE BIT_ULL(7)  /* Page Size Extensions */
+#define IOMMU_PAGE_NX  BIT_ULL(63) /* No execute */
+
+#define MAX_PTRS_PER_PAGE  512
+
+#define IOMMU_PAGE_SIZE_2M BIT_ULL(21)
+#define IOMMU_PAGE_SIZE_1G BIT_ULL(30)
+
+
+static inline int get_pgtable_level(void)
+{
+   /* 5 level page table is not supported */
+   return PAGE_MODE_4_LEVEL;
+}
+
+static inline bool is_large_pte(u64 pte)
+{
+   return (pte & IOMMU_PAGE_PSE);
+}
+
+static inline void *alloc_pgtable_page(void)
+{
+   return (void *)get_zeroed_page(GFP_KERNEL);
+}
+
+static inline u64 set_pgtable_attr(u64 *page)
+{
+   u64 prot;
+
+   prot = IOMMU_PAGE_PRESENT | IOMMU_PAGE_RW | IOMMU_PAGE_USER;
+   prot |= IOMMU_PAGE_ACCESS | IOMMU_PAGE_DIRTY;
+
+   return (iommu_virt_to_phys(page) | prot);
+}
+
+static inline void *get_pgtable_pte(u64 pte)
+{
+   return iommu_phys_to_virt(pte & PM_ADDR_MASK);
+}
+
+static u64 set_pte_attr(u64 paddr, u64 pg_size, int prot)
+{
+   u64 pte;
+
+   pte = __sme_set(paddr & PM_ADDR_MASK);
+   pte |= IOMMU_PAGE_PRESENT | IOMMU_PAGE_USER;
+   pte |= IOMMU_PAGE_ACCESS | IOMMU_PAGE_DIRTY;
+
+   if (prot & IOMMU_PROT_IW)
+   pte |= IOMMU_PAGE_RW;
+
+   /* Large page */
+   if (pg_size == IOMMU_PAGE_SIZE_1G || pg_size == IOMMU_PAGE_SIZE_2M)
+   pte |= IOMMU_PAGE_PSE;
+
+   return pte;
+}
+
+static inline u64 get_alloc_page_size(u64 size)
+{
+   if (size >= IOMMU_PAGE_SIZE_1G)
+   return IOMMU_PAGE_SIZE_1G;
+
+   if (size >= IOMMU_PAGE_SIZE_2M)
+   return IOMMU_PAGE_SIZE_2M;
+
+   return PAGE_SIZE;
+}
+
+static inline int page_size_to_level(u64 pg_size)
+{
+   if (pg_size == IOMMU_PAGE_SIZE_1G)
+   return 

[PATCH v1 3/7] iommu/amd: Fix sparse warning

2022-06-03 Thread Vasant Hegde via iommu
Fix below sparse warning:
  CHECK   drivers/iommu/amd/iommu.c
  drivers/iommu/amd/iommu.c:73:24: warning: symbol 'amd_iommu_ops' was not 
declared. Should it be static?

Also we are going to introduce v2 page table which has different
pgsize_bitmaps. Hence remove 'const' qualifier.

Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/init.c  | 2 +-
 drivers/iommu/amd/iommu.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 8483d98a1775..453afce7d478 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -96,7 +96,7 @@
  * out of it.
  */
 
-extern const struct iommu_ops amd_iommu_ops;
+extern struct iommu_ops amd_iommu_ops;
 
 /*
  * structure describing one IOMMU in the ACPI table. Typically followed by one
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index b558e8c30613..deb546266d42 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -70,7 +70,7 @@ LIST_HEAD(acpihid_map);
  * Domain for untranslated devices - only allocated
  * if iommu=pt passed on kernel cmd line.
  */
-const struct iommu_ops amd_iommu_ops;
+struct iommu_ops amd_iommu_ops;
 
 static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
 int amd_iommu_max_glx_val = -1;
@@ -2374,7 +2374,7 @@ static int amd_iommu_def_domain_type(struct device *dev)
return 0;
 }
 
-const struct iommu_ops amd_iommu_ops = {
+struct iommu_ops amd_iommu_ops = {
.capable = amd_iommu_capable,
.domain_alloc = amd_iommu_domain_alloc,
.probe_device = amd_iommu_probe_device,
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 2/7] iommu/amd: Update sanity check when enable PRI/ATS

2022-06-03 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Currently, PPR/ATS can be enabled only if the domain is type
identity mapping. However, when we allow the IOMMU v2 page table
to be used for DMA-API, the sanity check needs to be updated to
only apply for the case when using AMD_IOMMU_V1 page table mode.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 14 +++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 059e699c43d1..b558e8c30613 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1682,7 +1682,7 @@ static void pdev_iommuv2_disable(struct pci_dev *pdev)
pci_disable_pasid(pdev);
 }
 
-static int pdev_iommuv2_enable(struct pci_dev *pdev)
+static int pdev_pri_ats_enable(struct pci_dev *pdev)
 {
int ret;
 
@@ -1745,11 +1745,19 @@ static int attach_device(struct device *dev,
struct iommu_domain *def_domain = iommu_get_dma_domain(dev);
 
ret = -EINVAL;
-   if (def_domain->type != IOMMU_DOMAIN_IDENTITY)
+
+   /*
+* In case of using AMD_IOMMU_V1 page table mode and the device
+* is enabling for PPR/ATS support (using v2 table),
+* we need to make sure that the domain type is identity map.
+*/
+   if ((amd_iommu_pgtable == AMD_IOMMU_V1) &&
+   def_domain->type != IOMMU_DOMAIN_IDENTITY) {
goto out;
+   }
 
if (dev_data->iommu_v2) {
-   if (pdev_iommuv2_enable(pdev) != 0)
+   if (pdev_pri_ats_enable(pdev) != 0)
goto out;
 
dev_data->ats.enabled = true;
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 1/7] iommu/amd: Refactor amd_iommu_domain_enable_v2

2022-06-03 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

The current function to enable IOMMU v2 also lock the domain.
In order to reuse the same code in different code path, in which
the domain has already been locked, refactor the function to separate
the locking from the enabling logic.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/iommu.c | 46 +++
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index c95c09c56b37..059e699c43d1 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -85,6 +85,7 @@ struct iommu_cmd {
 struct kmem_cache *amd_iommu_irq_cache;
 
 static void detach_device(struct device *dev);
+static int domain_enable_v2(struct protection_domain *domain, int pasids, bool 
has_ppr);
 
 /
  *
@@ -2427,11 +2428,10 @@ void amd_iommu_domain_direct_map(struct iommu_domain 
*dom)
 }
 EXPORT_SYMBOL(amd_iommu_domain_direct_map);
 
-int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids)
+/* Note: This function expects iommu_domain->lock to be held prior calling the 
function. */
+static int domain_enable_v2(struct protection_domain *domain, int pasids, bool 
has_ppr)
 {
-   struct protection_domain *domain = to_pdomain(dom);
-   unsigned long flags;
-   int levels, ret;
+   int levels;
 
/* Number of GCR3 table levels required */
for (levels = 0; (pasids - 1) & ~0x1ff; pasids >>= 9)
@@ -2440,7 +2440,25 @@ int amd_iommu_domain_enable_v2(struct iommu_domain *dom, 
int pasids)
if (levels > amd_iommu_max_glx_val)
return -EINVAL;
 
-   spin_lock_irqsave(>lock, flags);
+   domain->gcr3_tbl = (void *)get_zeroed_page(GFP_ATOMIC);
+   if (domain->gcr3_tbl == NULL)
+   return -ENOMEM;
+
+   domain->glx  = levels;
+   domain->flags   |= PD_IOMMUV2_MASK;
+
+   amd_iommu_domain_update(domain);
+
+   return 0;
+}
+
+int amd_iommu_domain_enable_v2(struct iommu_domain *dom, int pasids)
+{
+   struct protection_domain *pdom = to_pdomain(dom);
+   unsigned long flags;
+   int ret;
+
+   spin_lock_irqsave(>lock, flags);
 
/*
 * Save us all sanity checks whether devices already in the
@@ -2448,24 +2466,14 @@ int amd_iommu_domain_enable_v2(struct iommu_domain 
*dom, int pasids)
 * devices attached when it is switched into IOMMUv2 mode.
 */
ret = -EBUSY;
-   if (domain->dev_cnt > 0 || domain->flags & PD_IOMMUV2_MASK)
-   goto out;
-
-   ret = -ENOMEM;
-   domain->gcr3_tbl = (void *)get_zeroed_page(GFP_ATOMIC);
-   if (domain->gcr3_tbl == NULL)
+   if (pdom->dev_cnt > 0 || pdom->flags & PD_IOMMUV2_MASK)
goto out;
 
-   domain->glx  = levels;
-   domain->flags   |= PD_IOMMUV2_MASK;
-
-   amd_iommu_domain_update(domain);
-
-   ret = 0;
+   if (!pdom->gcr3_tbl)
+   ret = domain_enable_v2(pdom, pasids, true);
 
 out:
-   spin_unlock_irqrestore(>lock, flags);
-
+   spin_unlock_irqrestore(>lock, flags);
return ret;
 }
 EXPORT_SYMBOL(amd_iommu_domain_enable_v2);
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v1 0/7] iommu/amd: Add Generic IO Page Table Framework Support for v2 Page Table

2022-06-03 Thread Vasant Hegde via iommu
This series introduces a new usage model for the v2 page table, where it
can be used to implement support for DMA-API by adopting the generic
IO page table framework.

One of the target usecases is to support nested IO page tables
where the guest uses the guest IO page table (v2) for translating
GVA to GPA, and the hypervisor uses the host I/O page table (v1) for
translating GPA to SPA. This is a pre-requisite for supporting the new
HW-assisted vIOMMU presented at the KVM Forum 2020.

  
https://static.sched.com/hosted_files/kvmforum2020/26/vIOMMU%20KVM%20Forum%202020.pdf

The following components are introduced in this series:

- Part 1 (patch 1-4 and 6)
  Refactor the current IOMMU page table code to adopt the generic IO page
  table framework, and add AMD IOMMU Guest (v2) page table management code.

- Part 2 (patch 5)
  Add support for the AMD IOMMU Guest IO Protection feature (GIOV)
  where requests from the I/O device without a PASID are treated as
  if they have PASID of 0.

- Part 3 (patch 7)
  Introduce new "amd_iommu_pgtable" command-line to allow users
  to select the mode of operation (v1 or v2).

See AMD I/O Virtualization Technology Specification for more detail.

  http://www.amd.com/system/files/TechDocs/48882_IOMMU_3.05_PUB.pdf

Note:
  This patchset is based on top of "iommu/amd: Add multiple PCI segments 
support" patchset [1].

[1] 
https://lore.kernel.org/linux-iommu/20220511072141.15485-1-vasant.he...@amd.com/T/#t

Thanks,
Vasant


Changes from RFC -> v1:
  - Addressed review comments from Joerg
  - Reimplemented v2 page table

RFC patchset : 
https://lore.kernel.org/linux-iommu/20210312090411.6030-1-suravee.suthikulpa...@amd.com/T/#t

Suravee Suthikulpanit (5):
  iommu/amd: Refactor amd_iommu_domain_enable_v2
  iommu/amd: Update sanity check when enable PRI/ATS
  iommu/amd: Add support for Guest IO protection
  iommu/amd: Add support for using AMD IOMMU v2 page table for DMA-API
  iommu/amd: Introduce amd_iommu_pgtable command-line option

Vasant Hegde (2):
  iommu/amd: Fix sparse warning
  iommu/amd: Initial support for AMD IOMMU v2 page table

 .../admin-guide/kernel-parameters.txt |   6 +
 drivers/iommu/amd/Makefile|   2 +-
 drivers/iommu/amd/amd_iommu_types.h   |   8 +-
 drivers/iommu/amd/init.c  |  27 +-
 drivers/iommu/amd/io_pgtable_v2.c | 407 ++
 drivers/iommu/amd/iommu.c |  90 ++--
 drivers/iommu/io-pgtable.c|   1 +
 include/linux/io-pgtable.h|   2 +
 8 files changed, 516 insertions(+), 27 deletions(-)
 create mode 100644 drivers/iommu/amd/io_pgtable_v2.c

-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v3 00/35] iommu/amd: Add multiple PCI segments support

2022-05-20 Thread Vasant Hegde via iommu
Joerg,


On 5/20/2022 3:33 PM, Joerg Roedel wrote:
> Hi Vasant,
> 
> On Fri, May 20, 2022 at 03:25:38PM +0530, Vasant Hegde wrote:
>> Ping. Did you get a chance to look into this series?
> 
> Sorry, too late for this round. The changes are pretty invasive and
> merging them at -rc7 stage would not give them enough testing before
> being merged. Please send me a reminder after the next merge window.

Sure. I will remind you after v5.19 merge window closes.

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v3 00/35] iommu/amd: Add multiple PCI segments support

2022-05-20 Thread Vasant Hegde via iommu
Hello Joerg,



On 5/11/2022 12:51 PM, Vasant Hegde wrote:
> Newer AMD systems can support multiple PCI segments, where each segment
> contains one or more IOMMU instances. However, an IOMMU instance can only
> support a single PCI segment.

Ping. Did you get a chance to look into this series? 

-Vasant


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 35/35] iommu/amd: Update amd_iommu_fault structure to include PCI seg ID

2022-05-11 Thread Vasant Hegde via iommu
Rename 'device_id' as 'sbdf' and extend it to 32bit so that we can
pass PCI segment ID to ppr_notifier(). Also pass PCI segment ID to
pci_get_domain_bus_and_slot() instead of default value.

Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 2 +-
 drivers/iommu/amd/iommu.c   | 2 +-
 drivers/iommu/amd/iommu_v2.c| 9 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 7cf6bc353028..328572cf6fa5 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -482,7 +482,7 @@ extern struct kmem_cache *amd_iommu_irq_cache;
 struct amd_iommu_fault {
u64 address;/* IO virtual address of the fault*/
u32 pasid;  /* Address space identifier */
-   u16 device_id;  /* Originating PCI device id */
+   u32 sbdf;   /* Originating PCI device id */
u16 tag;/* PPR tag */
u16 flags;  /* Fault flags */
 
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 6320f2f97d88..c95c09c56b37 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -701,7 +701,7 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, 
u64 *raw)
 
fault.address   = raw[1];
fault.pasid = PPR_PASID(raw[0]);
-   fault.device_id = PPR_DEVID(raw[0]);
+   fault.sbdf  = PCI_SEG_DEVID_TO_SBDF(iommu->pci_seg->id, 
PPR_DEVID(raw[0]));
fault.tag   = PPR_TAG(raw[0]);
fault.flags = PPR_FLAGS(raw[0]);
 
diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index b186d6e0..28fecc6d0e53 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -518,15 +518,16 @@ static int ppr_notifier(struct notifier_block *nb, 
unsigned long e, void *data)
unsigned long flags;
struct fault *fault;
bool finish;
-   u16 tag, devid;
+   u16 tag, devid, seg_id;
int ret;
 
iommu_fault = data;
tag = iommu_fault->tag & 0x1ff;
finish  = (iommu_fault->tag >> 9) & 1;
 
-   devid = iommu_fault->device_id;
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   seg_id = PCI_SBDF_TO_SEGID(iommu_fault->sbdf);
+   devid = PCI_SBDF_TO_DEVID(iommu_fault->sbdf);
+   pdev = pci_get_domain_bus_and_slot(seg_id, PCI_BUS_NUM(devid),
   devid & 0xff);
if (!pdev)
return -ENODEV;
@@ -540,7 +541,7 @@ static int ppr_notifier(struct notifier_block *nb, unsigned 
long e, void *data)
goto out;
}
 
-   dev_state = get_device_state(iommu_fault->device_id);
+   dev_state = get_device_state(iommu_fault->sbdf);
if (dev_state == NULL)
goto out;
 
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 34/35] iommu/amd: Update device_state structure to include PCI seg ID

2022-05-11 Thread Vasant Hegde via iommu
Rename struct device_state.devid variable to struct device_state.sbdf
and extend it to 32-bit to include the 16-bit PCI segment ID via
the helper function get_pci_sbdf_id().

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu_v2.c | 58 +++-
 1 file changed, 24 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index e56b137ceabd..b186d6e0 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -51,7 +51,7 @@ struct pasid_state {
 
 struct device_state {
struct list_head list;
-   u16 devid;
+   u32 sbdf;
atomic_t count;
struct pci_dev *pdev;
struct pasid_state **states;
@@ -83,35 +83,25 @@ static struct workqueue_struct *iommu_wq;
 
 static void free_pasid_states(struct device_state *dev_state);
 
-static u16 device_id(struct pci_dev *pdev)
-{
-   u16 devid;
-
-   devid = pdev->bus->number;
-   devid = (devid << 8) | pdev->devfn;
-
-   return devid;
-}
-
-static struct device_state *__get_device_state(u16 devid)
+static struct device_state *__get_device_state(u32 sbdf)
 {
struct device_state *dev_state;
 
list_for_each_entry(dev_state, _list, list) {
-   if (dev_state->devid == devid)
+   if (dev_state->sbdf == sbdf)
return dev_state;
}
 
return NULL;
 }
 
-static struct device_state *get_device_state(u16 devid)
+static struct device_state *get_device_state(u32 sbdf)
 {
struct device_state *dev_state;
unsigned long flags;
 
spin_lock_irqsave(_lock, flags);
-   dev_state = __get_device_state(devid);
+   dev_state = __get_device_state(sbdf);
if (dev_state != NULL)
atomic_inc(_state->count);
spin_unlock_irqrestore(_lock, flags);
@@ -609,7 +599,7 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
struct pasid_state *pasid_state;
struct device_state *dev_state;
struct mm_struct *mm;
-   u16 devid;
+   u32 sbdf;
int ret;
 
might_sleep();
@@ -617,8 +607,8 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
if (!amd_iommu_v2_supported())
return -ENODEV;
 
-   devid = device_id(pdev);
-   dev_state = get_device_state(devid);
+   sbdf  = get_pci_sbdf_id(pdev);
+   dev_state = get_device_state(sbdf);
 
if (dev_state == NULL)
return -EINVAL;
@@ -692,15 +682,15 @@ void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 
pasid)
 {
struct pasid_state *pasid_state;
struct device_state *dev_state;
-   u16 devid;
+   u32 sbdf;
 
might_sleep();
 
if (!amd_iommu_v2_supported())
return;
 
-   devid = device_id(pdev);
-   dev_state = get_device_state(devid);
+   sbdf = get_pci_sbdf_id(pdev);
+   dev_state = get_device_state(sbdf);
if (dev_state == NULL)
return;
 
@@ -742,7 +732,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
struct iommu_group *group;
unsigned long flags;
int ret, tmp;
-   u16 devid;
+   u32 sbdf;
 
might_sleep();
 
@@ -759,7 +749,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
if (pasids <= 0 || pasids > (PASID_MASK + 1))
return -EINVAL;
 
-   devid = device_id(pdev);
+   sbdf = get_pci_sbdf_id(pdev);
 
dev_state = kzalloc(sizeof(*dev_state), GFP_KERNEL);
if (dev_state == NULL)
@@ -768,7 +758,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
spin_lock_init(_state->lock);
init_waitqueue_head(_state->wq);
dev_state->pdev  = pdev;
-   dev_state->devid = devid;
+   dev_state->sbdf = sbdf;
 
tmp = pasids;
for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9)
@@ -806,7 +796,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 
spin_lock_irqsave(_lock, flags);
 
-   if (__get_device_state(devid) != NULL) {
+   if (__get_device_state(sbdf) != NULL) {
spin_unlock_irqrestore(_lock, flags);
ret = -EBUSY;
goto out_free_domain;
@@ -838,16 +828,16 @@ void amd_iommu_free_device(struct pci_dev *pdev)
 {
struct device_state *dev_state;
unsigned long flags;
-   u16 devid;
+   u32 sbdf;
 
if (!amd_iommu_v2_supported())
return;
 
-   devid = device_id(pdev);
+   sbdf = get_pci_sbdf_id(pdev);
 
spin_lock_irqsave(_lock, flags);
 
-   dev_state = __get_device_state(devid);
+   dev_state = __get_device_state(sbdf);
if (dev_state == NULL) {
spin_unlock_irqrestore(_lock, flags);
return;
@@ -867,18 +857,18 @@ int 

[PATCH v3 33/35] iommu/amd: Print PCI segment ID in error log messages

2022-05-11 Thread Vasant Hegde via iommu
Print pci segment ID along with bdf. Useful for debugging.

Co-developed-by: Suravee Suthikulpaint 
Signed-off-by: Suravee Suthikulpaint 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/init.c  | 10 +-
 drivers/iommu/amd/iommu.c | 36 ++--
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 969b496f7e74..8483d98a1775 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1853,11 +1853,11 @@ static int __init init_iommu_all(struct 
acpi_table_header *table)
h = (struct ivhd_header *)p;
if (*p == amd_iommu_target_ivhd_type) {
 
-   DUMP_printk("device: %02x:%02x.%01x cap: %04x "
-   "seg: %d flags: %01x info %04x\n",
-   PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
-   PCI_FUNC(h->devid), h->cap_ptr,
-   h->pci_seg, h->flags, h->info);
+   DUMP_printk("device: %04x:%02x:%02x.%01x cap: %04x "
+   "flags: %01x info %04x\n",
+   h->pci_seg, PCI_BUS_NUM(h->devid),
+   PCI_SLOT(h->devid), PCI_FUNC(h->devid),
+   h->cap_ptr, h->flags, h->info);
DUMP_printk("   mmio-addr: %016llx\n",
h->mmio_phys);
 
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 536dbc1d26ad..6320f2f97d88 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -496,8 +496,8 @@ static void amd_iommu_report_rmp_hw_error(struct amd_iommu 
*iommu, volatile u32
vmg_tag, spa, flags);
}
} else {
-   pr_err_ratelimited("Event logged [RMP_HW_ERROR 
device=%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [RMP_HW_ERROR 
device=%04x:%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
vmg_tag, spa, flags);
}
 
@@ -529,8 +529,8 @@ static void amd_iommu_report_rmp_fault(struct amd_iommu 
*iommu, volatile u32 *ev
vmg_tag, gpa, flags_rmp, flags);
}
} else {
-   pr_err_ratelimited("Event logged [RMP_PAGE_FAULT 
device=%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, 
flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [RMP_PAGE_FAULT 
device=%04x:%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, 
flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
vmg_tag, gpa, flags_rmp, flags);
}
 
@@ -576,8 +576,8 @@ static void amd_iommu_report_page_fault(struct amd_iommu 
*iommu,
domain_id, address, flags);
}
} else {
-   pr_err_ratelimited("Event logged [IO_PAGE_FAULT 
device=%02x:%02x.%x domain=0x%04x address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [IO_PAGE_FAULT 
device=%04x:%02x:%02x.%x domain=0x%04x address=0x%llx flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
domain_id, address, flags);
}
 
@@ -620,20 +620,20 @@ static void iommu_print_event(struct amd_iommu *iommu, 
void *__evt)
 
switch (type) {
case EVENT_TYPE_ILL_DEV:
-   dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%04x:%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
pasid, address, flags);
dump_dte_entry(iommu, devid);
break;
case EVENT_TYPE_DEV_TAB_ERR:
-   dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%02x:%02x.%x "
+   dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%04x:%02x:%02x.%x "
"address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 

[PATCH v3 32/35] iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

By default, PCI segment is zero and can be omitted. To support system
with non-zero PCI segment ID, modify the parsing functions to allow
PCI segment ID.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 .../admin-guide/kernel-parameters.txt | 34 ++
 drivers/iommu/amd/init.c  | 44 ---
 2 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index f5a27f067db9..cc8f0c82ff55 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2208,23 +2208,39 @@
 
ivrs_ioapic [HW,X86-64]
Provide an override to the IOAPIC-ID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map IOAPIC-ID decimal 10 to
-   PCI device 00:14.0 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+   By default, PCI segment is 0, and can be omitted.
+   For example:
+   * To map IOAPIC-ID decimal 10 to PCI device 00:14.0
+ write the parameter as:
ivrs_ioapic[10]=00:14.0
+   * To map IOAPIC-ID decimal 10 to PCI segment 0x1 and
+ PCI device 00:14.0 write the parameter as:
+   ivrs_ioapic[10]=0001:00:14.0
 
ivrs_hpet   [HW,X86-64]
Provide an override to the HPET-ID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map HPET-ID decimal 0 to
-   PCI device 00:14.0 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+   By default, PCI segment is 0, and can be omitted.
+   For example:
+   * To map HPET-ID decimal 0 to PCI device 00:14.0
+ write the parameter as:
ivrs_hpet[0]=00:14.0
+   * To map HPET-ID decimal 10 to PCI segment 0x1 and
+ PCI device 00:14.0 write the parameter as:
+   ivrs_ioapic[10]=0001:00:14.0
 
ivrs_acpihid[HW,X86-64]
Provide an override to the ACPI-HID:UID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map UART-HID:UID AMD0020:0 to
-   PCI device 00:14.5 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+
+   For example, to map UART-HID:UID AMD0020:0 to
+   PCI segment 0x1 and PCI device ID 00:14.5,
+   write the parameter as:
+   ivrs_acpihid[0001:00:14.5]=AMD0020:0
+
+   By default, PCI segment is 0, and can be omitted.
+   For example, PCI device 00:14.5 write the parameter as:
ivrs_acpihid[00:14.5]=AMD0020:0
 
js= [HW,JOY] Analog joystick
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ca79637560a3..969b496f7e74 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -85,6 +85,10 @@
 #define ACPI_DEVFLAG_ATSDIS 0x1000
 
 #define LOOP_TIMEOUT   10
+
+#define IVRS_GET_SBDF_ID(seg, bus, dev, fd)(((seg & 0x) << 16) | ((bus 
& 0xff) << 8) \
+| ((dev & 0x1f) << 3) | (fn & 
0x7))
+
 /*
  * ACPI table definitions
  *
@@ -3287,15 +3291,17 @@ static int __init parse_amd_iommu_options(char *str)
 
 static int __init parse_ivrs_ioapic(char *str)
 {
-   unsigned int bus, dev, fn;
+   u32 seg = 0, bus, dev, fn;
int ret, id, i;
-   u16 devid;
+   u32 devid;
 
ret = sscanf(str, "[%d]=%x:%x.%x", , , , );
-
if (ret != 4) {
-   pr_err("Invalid command line: ivrs_ioapic%s\n", str);
-   return 1;
+   ret = sscanf(str, "[%d]=%x:%x:%x.%x", , , , , 
);
+   if (ret != 5) {
+   pr_err("Invalid command line: ivrs_ioapic%s\n", str);
+   return 1;
+   }
}
 
if (early_ioapic_map_size == EARLY_MAP_SIZE) {
@@ -3304,7 +3310,7 @@ static int __init parse_ivrs_ioapic(char *str)
return 1;
}
 
-   devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+   devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn);
 
cmdline_maps= true;
i   = early_ioapic_map_size++;
@@ -3317,15 

[PATCH v3 31/35] iommu/amd: Specify PCI segment ID when getting pci device

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Upcoming AMD systems can have multiple PCI segments. Hence pass PCI
segment ID to pci_get_domain_bus_and_slot() instead of '0'.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/init.c  |  6 --
 drivers/iommu/amd/iommu.c | 19 ++-
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index c746b71c0dbb..ca79637560a3 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1960,7 +1960,8 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
int cap_ptr = iommu->cap_ptr;
int ret;
 
-   iommu->dev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(iommu->devid),
+   iommu->dev = pci_get_domain_bus_and_slot(iommu->pci_seg->id,
+PCI_BUS_NUM(iommu->devid),
 iommu->devid & 0xff);
if (!iommu->dev)
return -ENODEV;
@@ -2023,7 +2024,8 @@ static int __init iommu_init_pci(struct amd_iommu *iommu)
int i, j;
 
iommu->root_pdev =
-   pci_get_domain_bus_and_slot(0, iommu->dev->bus->number,
+   pci_get_domain_bus_and_slot(iommu->pci_seg->id,
+   iommu->dev->bus->number,
PCI_DEVFN(0, 0));
 
/*
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index d9b23f7820a9..536dbc1d26ad 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -473,7 +473,7 @@ static void dump_command(unsigned long phys_addr)
pr_err("CMD[%d]: %08x\n", i, cmd->data[i]);
 }
 
-static void amd_iommu_report_rmp_hw_error(volatile u32 *event)
+static void amd_iommu_report_rmp_hw_error(struct amd_iommu *iommu, volatile 
u32 *event)
 {
struct iommu_dev_data *dev_data = NULL;
int devid, vmg_tag, flags;
@@ -485,7 +485,7 @@ static void amd_iommu_report_rmp_hw_error(volatile u32 
*event)
flags   = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
spa = ((u64)event[3] << 32) | (event[2] & 0xFFF8);
 
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, 
PCI_BUS_NUM(devid),
   devid & 0xff);
if (pdev)
dev_data = dev_iommu_priv_get(>dev);
@@ -505,7 +505,7 @@ static void amd_iommu_report_rmp_hw_error(volatile u32 
*event)
pci_dev_put(pdev);
 }
 
-static void amd_iommu_report_rmp_fault(volatile u32 *event)
+static void amd_iommu_report_rmp_fault(struct amd_iommu *iommu, volatile u32 
*event)
 {
struct iommu_dev_data *dev_data = NULL;
int devid, flags_rmp, vmg_tag, flags;
@@ -518,7 +518,7 @@ static void amd_iommu_report_rmp_fault(volatile u32 *event)
flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
gpa   = ((u64)event[3] << 32) | event[2];
 
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, 
PCI_BUS_NUM(devid),
   devid & 0xff);
if (pdev)
dev_data = dev_iommu_priv_get(>dev);
@@ -544,13 +544,14 @@ static void amd_iommu_report_rmp_fault(volatile u32 
*event)
 #define IS_WRITE_REQUEST(flags)\
((flags) & EVENT_FLAG_RW)
 
-static void amd_iommu_report_page_fault(u16 devid, u16 domain_id,
+static void amd_iommu_report_page_fault(struct amd_iommu *iommu,
+   u16 devid, u16 domain_id,
u64 address, int flags)
 {
struct iommu_dev_data *dev_data = NULL;
struct pci_dev *pdev;
 
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   pdev = pci_get_domain_bus_and_slot(iommu->pci_seg->id, 
PCI_BUS_NUM(devid),
   devid & 0xff);
if (pdev)
dev_data = dev_iommu_priv_get(>dev);
@@ -613,7 +614,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void 
*__evt)
}
 
if (type == EVENT_TYPE_IO_FAULT) {
-   amd_iommu_report_page_fault(devid, pasid, address, flags);
+   amd_iommu_report_page_fault(iommu, devid, pasid, address, 
flags);
return;
}
 
@@ -654,10 +655,10 @@ static void iommu_print_event(struct amd_iommu *iommu, 
void *__evt)
pasid, address, flags);
break;
case EVENT_TYPE_RMP_FAULT:
-   amd_iommu_report_rmp_fault(event);
+   amd_iommu_report_rmp_fault(iommu, event);
break;
case EVENT_TYPE_RMP_HW_ERR:
-   amd_iommu_report_rmp_hw_error(event);
+   

[PATCH v3 30/35] iommu/amd: Include PCI segment ID when initialize IOMMU

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Extend current device ID variables to 32-bit to include the 16-bit
segment ID when parsing device information from IVRS table to initialize
each IOMMU.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  2 +-
 drivers/iommu/amd/amd_iommu_types.h |  6 ++--
 drivers/iommu/amd/init.c| 56 +++--
 drivers/iommu/amd/quirks.c  |  4 +--
 4 files changed, 35 insertions(+), 33 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index e73bd48fc716..9b7092182ca7 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -125,7 +125,7 @@ static inline int get_pci_sbdf_id(struct pci_dev *pdev)
 
 extern bool translation_pre_enabled(struct amd_iommu *iommu);
 extern bool amd_iommu_is_attach_deferred(struct device *dev);
-extern int __init add_special_device(u8 type, u8 id, u16 *devid,
+extern int __init add_special_device(u8 type, u8 id, u32 *devid,
 bool cmd_line);
 
 #ifdef CONFIG_DMI
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 0d47aac685ee..7cf6bc353028 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -740,8 +740,8 @@ struct acpihid_map_entry {
struct list_head list;
u8 uid[ACPIHID_UID_LEN];
u8 hid[ACPIHID_HID_LEN];
-   u16 devid;
-   u16 root_devid;
+   u32 devid;
+   u32 root_devid;
bool cmd_line;
struct iommu_group *group;
 };
@@ -749,7 +749,7 @@ struct acpihid_map_entry {
 struct devid_map {
struct list_head list;
u8 id;
-   u16 devid;
+   u32 devid;
bool cmd_line;
 };
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 7c81e733a3ac..c746b71c0dbb 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1146,7 +1146,7 @@ static void __init set_dev_entry_from_acpi(struct 
amd_iommu *iommu,
amd_iommu_set_rlookup_table(iommu, devid);
 }
 
-int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
+int __init add_special_device(u8 type, u8 id, u32 *devid, bool cmd_line)
 {
struct devid_map *entry;
struct list_head *list;
@@ -1183,7 +1183,7 @@ int __init add_special_device(u8 type, u8 id, u16 *devid, 
bool cmd_line)
return 0;
 }
 
-static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u16 *devid,
+static int __init add_acpi_hid_device(u8 *hid, u8 *uid, u32 *devid,
  bool cmd_line)
 {
struct acpihid_map_entry *entry;
@@ -1262,7 +1262,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 {
u8 *p = (u8 *)h;
u8 *end = p, flags = 0;
-   u16 devid = 0, devid_start = 0, devid_to = 0;
+   u16 devid = 0, devid_start = 0, devid_to = 0, seg_id;
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
@@ -1298,6 +1298,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 
while (p < end) {
e = (struct ivhd_entry *)p;
+   seg_id = pci_seg->id;
+
switch (e->type) {
case IVHD_DEV_ALL:
 
@@ -1308,9 +1310,9 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
break;
case IVHD_DEV_SELECT:
 
-   DUMP_printk("  DEV_SELECT\t\t\t devid: %02x:%02x.%x "
+   DUMP_printk("  DEV_SELECT\t\t\t devid: 
%04x:%02x:%02x.%x "
"flags: %02x\n",
-   PCI_BUS_NUM(e->devid),
+   seg_id, PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags);
@@ -1321,8 +1323,8 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
case IVHD_DEV_SELECT_RANGE_START:
 
DUMP_printk("  DEV_SELECT_RANGE_START\t "
-   "devid: %02x:%02x.%x flags: %02x\n",
-   PCI_BUS_NUM(e->devid),
+   "devid: %04x:%02x:%02x.%x flags: %02x\n",
+   seg_id, PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags);
@@ -1334,9 +1336,9 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
break;
case IVHD_DEV_ALIAS:
 
-   DUMP_printk("  DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
+   DUMP_printk("  DEV_ALIAS\t\t\t devid: %04x:%02x:%02x.%x 
"
"flags: 

[PATCH v3 29/35] iommu/amd: Introduce get_device_sbdf_id() helper function

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Current get_device_id() only provide 16-bit PCI device ID (i.e. BDF).
With multiple PCI segment support, we need to extend the helper function
to include PCI segment ID.

So, introduce a new helper function get_device_sbdf_id() to replace
the current get_pci_device_id().

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  7 
 drivers/iommu/amd/amd_iommu_types.h |  2 +
 drivers/iommu/amd/iommu.c   | 58 ++---
 3 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 64c954e168d7..e73bd48fc716 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -115,6 +115,13 @@ void amd_iommu_domain_clr_pt_root(struct protection_domain 
*domain)
amd_iommu_domain_set_pt_root(domain, 0);
 }
 
+static inline int get_pci_sbdf_id(struct pci_dev *pdev)
+{
+   int seg = pci_domain_nr(pdev->bus);
+   u16 devid = pci_dev_id(pdev);
+
+   return PCI_SEG_DEVID_TO_SBDF(seg, devid);
+}
 
 extern bool translation_pre_enabled(struct amd_iommu *iommu);
 extern bool amd_iommu_is_attach_deferred(struct device *dev);
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index dfb1f2055f0c..0d47aac685ee 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -452,6 +452,8 @@ extern struct kmem_cache *amd_iommu_irq_cache;
 
 #define PCI_SBDF_TO_SEGID(sbdf)(((sbdf) >> 16) & 0x)
 #define PCI_SBDF_TO_DEVID(sbdf)((sbdf) & 0x)
+#define PCI_SEG_DEVID_TO_SBDF(seg, devid)  u32)(seg) & 0x) << 16) 
| \
+((devid) & 0x))
 
 /* Make iterating over all pci segment easier */
 #define for_each_pci_segment(pci_seg) \
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 68ebbccef5c4..d9b23f7820a9 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -92,13 +92,6 @@ static void detach_device(struct device *dev);
  *
  /
 
-static inline u16 get_pci_device_id(struct device *dev)
-{
-   struct pci_dev *pdev = to_pci_dev(dev);
-
-   return pci_dev_id(pdev);
-}
-
 static inline int get_acpihid_device_id(struct device *dev,
struct acpihid_map_entry **entry)
 {
@@ -119,16 +112,16 @@ static inline int get_acpihid_device_id(struct device 
*dev,
return -EINVAL;
 }
 
-static inline int get_device_id(struct device *dev)
+static inline int get_device_sbdf_id(struct device *dev)
 {
-   int devid;
+   int sbdf;
 
if (dev_is_pci(dev))
-   devid = get_pci_device_id(dev);
+   sbdf = get_pci_sbdf_id(to_pci_dev(dev));
else
-   devid = get_acpihid_device_id(dev, NULL);
+   sbdf = get_acpihid_device_id(dev, NULL);
 
-   return devid;
+   return sbdf;
 }
 
 struct dev_table_entry *get_dev_table(struct amd_iommu *iommu)
@@ -182,9 +175,11 @@ static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 
devid)
 static struct amd_iommu *rlookup_amd_iommu(struct device *dev)
 {
u16 seg = get_device_segment(dev);
-   u16 devid = get_device_id(dev);
+   int devid = get_device_sbdf_id(dev);
 
-   return __rlookup_amd_iommu(seg, devid);
+   if (devid < 0)
+   return NULL;
+   return __rlookup_amd_iommu(seg, PCI_SBDF_TO_DEVID(devid));
 }
 
 static struct protection_domain *to_pdomain(struct iommu_domain *dom)
@@ -360,14 +355,15 @@ static bool check_device(struct device *dev)
 {
struct amd_iommu_pci_seg *pci_seg;
struct amd_iommu *iommu;
-   int devid;
+   int devid, sbdf;
 
if (!dev)
return false;
 
-   devid = get_device_id(dev);
-   if (devid < 0)
+   sbdf = get_device_sbdf_id(dev);
+   if (sbdf < 0)
return false;
+   devid = PCI_SBDF_TO_DEVID(sbdf);
 
iommu = rlookup_amd_iommu(dev);
if (!iommu)
@@ -375,7 +371,7 @@ static bool check_device(struct device *dev)
 
/* Out of our scope? */
pci_seg = iommu->pci_seg;
-   if ((devid & 0x) > pci_seg->last_bdf)
+   if (devid > pci_seg->last_bdf)
return false;
 
return true;
@@ -384,15 +380,16 @@ static bool check_device(struct device *dev)
 static int iommu_init_device(struct amd_iommu *iommu, struct device *dev)
 {
struct iommu_dev_data *dev_data;
-   int devid;
+   int devid, sbdf;
 
if (dev_iommu_priv_get(dev))
return 0;
 
-   devid = get_device_id(dev);
-   if (devid < 0)
-   return devid;
+   sbdf = get_device_sbdf_id(dev);
+   if (sbdf < 0)
+   return sbdf;
 
+   devid = 

[PATCH v3 28/35] iommu/amd: Flush upto last_bdf only

2022-05-11 Thread Vasant Hegde via iommu
Fix amd_iommu_flush_dte_all() and amd_iommu_flush_tlb_all() to flush
upto last_bdf only.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index c21346e48bcd..68ebbccef5c4 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1191,8 +1191,9 @@ static int iommu_flush_dte(struct amd_iommu *iommu, u16 
devid)
 static void amd_iommu_flush_dte_all(struct amd_iommu *iommu)
 {
u32 devid;
+   u16 last_bdf = iommu->pci_seg->last_bdf;
 
-   for (devid = 0; devid <= 0x; ++devid)
+   for (devid = 0; devid <= last_bdf; ++devid)
iommu_flush_dte(iommu, devid);
 
iommu_completion_wait(iommu);
@@ -1205,8 +1206,9 @@ static void amd_iommu_flush_dte_all(struct amd_iommu 
*iommu)
 static void amd_iommu_flush_tlb_all(struct amd_iommu *iommu)
 {
u32 dom_id;
+   u16 last_bdf = iommu->pci_seg->last_bdf;
 
-   for (dom_id = 0; dom_id <= 0x; ++dom_id) {
+   for (dom_id = 0; dom_id <= last_bdf; ++dom_id) {
struct iommu_cmd cmd;
build_inv_iommu_pages(, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
  dom_id, 1);
@@ -1249,8 +1251,9 @@ static void iommu_flush_irt(struct amd_iommu *iommu, u16 
devid)
 static void amd_iommu_flush_irt_all(struct amd_iommu *iommu)
 {
u32 devid;
+   u16 last_bdf = iommu->pci_seg->last_bdf;
 
-   for (devid = 0; devid <= MAX_DEV_TABLE_ENTRIES; devid++)
+   for (devid = 0; devid <= last_bdf; devid++)
iommu_flush_irt(iommu, devid);
 
iommu_completion_wait(iommu);
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 27/35] iommu/amd: Remove global amd_iommu_[dev_table/alias_table/last_bdf]

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Replace them with per PCI segment device table.
Also remove dev_table_size, alias_table_size, amd_iommu_last_bdf
variables.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h | 15 -
 drivers/iommu/amd/init.c| 89 +
 drivers/iommu/amd/iommu.c   | 18 --
 3 files changed, 27 insertions(+), 95 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index ddd606daa653..dfb1f2055f0c 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -830,24 +830,9 @@ struct unity_map_entry {
  * Data structures for device handling
  */
 
-/*
- * Device table used by hardware. Read and write accesses by software are
- * locked with the amd_iommu_pd_table lock.
- */
-extern struct dev_table_entry *amd_iommu_dev_table;
-
-/*
- * Alias table to find requestor ids to device ids. Not locked because only
- * read on runtime.
- */
-extern u16 *amd_iommu_alias_table;
-
 /* size of the dma_ops aperture as power of 2 */
 extern unsigned amd_iommu_aperture_order;
 
-/* largest PCI device id we expect translation requests for */
-extern u16 amd_iommu_last_bdf;
-
 /* allocation bitmap for domain ids */
 extern unsigned long *amd_iommu_pd_alloc_bitmap;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 2cdce8a3b86e..7c81e733a3ac 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -161,9 +161,6 @@ static bool amd_iommu_disabled __initdata;
 static bool amd_iommu_force_enable __initdata;
 static int amd_iommu_target_ivhd_type;
 
-u16 amd_iommu_last_bdf;/* largest PCI device id we have
-  to handle */
-
 LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
   system */
@@ -185,30 +182,12 @@ static bool amd_iommu_pc_present __read_mostly;
 
 bool amd_iommu_force_isolation __read_mostly;
 
-/*
- * Pointer to the device table which is shared by all AMD IOMMUs
- * it is indexed by the PCI device id or the HT unit id and contains
- * information about the domain the device belongs to as well as the
- * page table root pointer.
- */
-struct dev_table_entry *amd_iommu_dev_table;
-
-/*
- * The alias table is a driver specific data structure which contains the
- * mappings of the PCI device ids to the actual requestor ids on the IOMMU.
- * More than one device can share the same requestor id.
- */
-u16 *amd_iommu_alias_table;
-
 /*
  * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
  * to know which ones are already in use.
  */
 unsigned long *amd_iommu_pd_alloc_bitmap;
 
-static u32 dev_table_size; /* size of the device table */
-static u32 alias_table_size;   /* size of the alias table */
-
 enum iommu_init_state {
IOMMU_START_STATE,
IOMMU_IVRS_DETECTED,
@@ -263,16 +242,10 @@ static void init_translation_status(struct amd_iommu 
*iommu)
iommu->flags |= AMD_IOMMU_FLAG_TRANS_PRE_ENABLED;
 }
 
-static inline void update_last_devid(u16 devid)
-{
-   if (devid > amd_iommu_last_bdf)
-   amd_iommu_last_bdf = devid;
-}
-
-static inline unsigned long tbl_size(int entry_size)
+static inline unsigned long tbl_size(int entry_size, int last_bdf)
 {
unsigned shift = PAGE_SHIFT +
-get_order(((int)amd_iommu_last_bdf + 1) * entry_size);
+get_order((last_bdf + 1) * entry_size);
 
return 1UL << shift;
 }
@@ -402,10 +375,11 @@ static void iommu_set_device_table(struct amd_iommu 
*iommu)
 {
u64 entry;
u32 dev_table_size = iommu->pci_seg->dev_table_size;
+   void *dev_table = (void *)get_dev_table(iommu);
 
BUG_ON(iommu->mmio_base == NULL);
 
-   entry = iommu_virt_to_phys(amd_iommu_dev_table);
+   entry = iommu_virt_to_phys(dev_table);
entry |= (dev_table_size >> 12) - 1;
memcpy_toio(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET,
, sizeof(entry));
@@ -555,14 +529,12 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
switch (dev->type) {
case IVHD_DEV_ALL:
/* Use maximum BDF value for DEV_ALL */
-   update_last_devid(0x);
return 0x;
case IVHD_DEV_SELECT:
case IVHD_DEV_RANGE_END:
case IVHD_DEV_ALIAS:
case IVHD_DEV_EXT_SELECT:
/* all the above subfield types refer to device ids */
-   update_last_devid(dev->devid);
if (dev->devid > last_devid)
last_devid = dev->devid;
 

[PATCH v3 26/35] iommu/amd: Update set_dev_entry_bit() and get_dev_entry_bit()

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

To include a pointer to per PCI segment device table.

Also include struct amd_iommu as one of the function parameter to
amd_iommu_apply_erratum_63() since it is needed when setting up DTE.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h |  2 +-
 drivers/iommu/amd/init.c  | 59 +++
 drivers/iommu/amd/iommu.c |  2 +-
 3 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 2947239700ce..64c954e168d7 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -13,7 +13,7 @@
 
 extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
 extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
-extern void amd_iommu_apply_erratum_63(u16 devid);
+extern void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid);
 extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
 extern int amd_iommu_init_devices(void);
 extern void amd_iommu_uninit_devices(void);
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ca9131ab745b..2cdce8a3b86e 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -987,22 +987,37 @@ static void iommu_enable_gt(struct amd_iommu *iommu)
 }
 
 /* sets a specific bit in the device table entry. */
-static void set_dev_entry_bit(u16 devid, u8 bit)
+static void __set_dev_entry_bit(struct dev_table_entry *dev_table,
+   u16 devid, u8 bit)
 {
int i = (bit >> 6) & 0x03;
int _bit = bit & 0x3f;
 
-   amd_iommu_dev_table[devid].data[i] |= (1UL << _bit);
+   dev_table[devid].data[i] |= (1UL << _bit);
 }
 
-static int get_dev_entry_bit(u16 devid, u8 bit)
+static void set_dev_entry_bit(struct amd_iommu *iommu, u16 devid, u8 bit)
+{
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
+
+   return __set_dev_entry_bit(dev_table, devid, bit);
+}
+
+static int __get_dev_entry_bit(struct dev_table_entry *dev_table,
+  u16 devid, u8 bit)
 {
int i = (bit >> 6) & 0x03;
int _bit = bit & 0x3f;
 
-   return (amd_iommu_dev_table[devid].data[i] & (1UL << _bit)) >> _bit;
+   return (dev_table[devid].data[i] & (1UL << _bit)) >> _bit;
 }
 
+static int get_dev_entry_bit(struct amd_iommu *iommu, u16 devid, u8 bit)
+{
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
+
+   return __get_dev_entry_bit(dev_table, devid, bit);
+}
 
 static bool __copy_device_table(struct amd_iommu *iommu)
 {
@@ -1121,15 +1136,15 @@ static bool copy_device_table(void)
return true;
 }
 
-void amd_iommu_apply_erratum_63(u16 devid)
+void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid)
 {
int sysmgt;
 
-   sysmgt = get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1) |
-(get_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2) << 1);
+   sysmgt = get_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT1) |
+(get_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT2) << 1);
 
if (sysmgt == 0x01)
-   set_dev_entry_bit(devid, DEV_ENTRY_IW);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_IW);
 }
 
 /* Writes the specific IOMMU for a device into the rlookup table */
@@ -1146,21 +1161,21 @@ static void __init set_dev_entry_from_acpi(struct 
amd_iommu *iommu,
   u16 devid, u32 flags, u32 ext_flags)
 {
if (flags & ACPI_DEVFLAG_INITPASS)
-   set_dev_entry_bit(devid, DEV_ENTRY_INIT_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_INIT_PASS);
if (flags & ACPI_DEVFLAG_EXTINT)
-   set_dev_entry_bit(devid, DEV_ENTRY_EINT_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_EINT_PASS);
if (flags & ACPI_DEVFLAG_NMI)
-   set_dev_entry_bit(devid, DEV_ENTRY_NMI_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_NMI_PASS);
if (flags & ACPI_DEVFLAG_SYSMGT1)
-   set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT1);
if (flags & ACPI_DEVFLAG_SYSMGT2)
-   set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_SYSMGT2);
if (flags & ACPI_DEVFLAG_LINT0)
-   set_dev_entry_bit(devid, DEV_ENTRY_LINT0_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_LINT0_PASS);
if (flags & ACPI_DEVFLAG_LINT1)
-   set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS);
+   set_dev_entry_bit(iommu, devid, DEV_ENTRY_LINT1_PASS);
 
-   amd_iommu_apply_erratum_63(devid);
+   amd_iommu_apply_erratum_63(iommu, devid);
 
set_iommu_for_device(iommu, devid);
 }
@@ -2518,8 +2533,8 @@ static void init_device_table_dma(struct 

[PATCH v3 25/35] iommu/amd: Update (un)init_device_table_dma()

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Include struct amd_iommu_pci_seg as a function parameter since
we need to access per PCI segment device table.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/init.c | 27 ---
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 5e8106641c5c..ca9131ab745b 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -238,7 +238,7 @@ static enum iommu_init_state init_state = IOMMU_START_STATE;
 
 static int amd_iommu_enable_interrupts(void);
 static int __init iommu_go_to_state(enum iommu_init_state state);
-static void init_device_table_dma(void);
+static void init_device_table_dma(struct amd_iommu_pci_seg *pci_seg);
 
 static bool amd_iommu_pre_enabled = true;
 
@@ -2114,6 +2114,7 @@ static void print_iommu_info(void)
 static int __init amd_iommu_init_pci(void)
 {
struct amd_iommu *iommu;
+   struct amd_iommu_pci_seg *pci_seg;
int ret;
 
for_each_iommu(iommu) {
@@ -2144,7 +2145,8 @@ static int __init amd_iommu_init_pci(void)
goto out;
}
 
-   init_device_table_dma();
+   for_each_pci_segment(pci_seg)
+   init_device_table_dma(pci_seg);
 
for_each_iommu(iommu)
iommu_flush_all_caches(iommu);
@@ -2507,9 +2509,13 @@ static int __init init_memory_definitions(struct 
acpi_table_header *table)
 /*
  * Init the device table to not allow DMA access for devices
  */
-static void init_device_table_dma(void)
+static void init_device_table_dma(struct amd_iommu_pci_seg *pci_seg)
 {
u32 devid;
+   struct dev_table_entry *dev_table = pci_seg->dev_table;
+
+   if (dev_table == NULL)
+   return;
 
for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
set_dev_entry_bit(devid, DEV_ENTRY_VALID);
@@ -2517,13 +2523,17 @@ static void init_device_table_dma(void)
}
 }
 
-static void __init uninit_device_table_dma(void)
+static void __init uninit_device_table_dma(struct amd_iommu_pci_seg *pci_seg)
 {
u32 devid;
+   struct dev_table_entry *dev_table = pci_seg->dev_table;
+
+   if (dev_table == NULL)
+   return;
 
for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
-   amd_iommu_dev_table[devid].data[0] = 0ULL;
-   amd_iommu_dev_table[devid].data[1] = 0ULL;
+   dev_table[devid].data[0] = 0ULL;
+   dev_table[devid].data[1] = 0ULL;
}
 }
 
@@ -3116,8 +3126,11 @@ static int __init state_next(void)
free_iommu_resources();
} else {
struct amd_iommu *iommu;
+   struct amd_iommu_pci_seg *pci_seg;
+
+   for_each_pci_segment(pci_seg)
+   uninit_device_table_dma(pci_seg);
 
-   uninit_device_table_dma();
for_each_iommu(iommu)
iommu_flush_all_caches(iommu);
}
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 24/35] iommu/amd: Update set_dte_irq_entry

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment device table instead of global
device table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 8c99e2e161aa..ebae64711691 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2729,18 +2729,20 @@ EXPORT_SYMBOL(amd_iommu_device_info);
 static struct irq_chip amd_ir_chip;
 static DEFINE_SPINLOCK(iommu_table_lock);
 
-static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
+static void set_dte_irq_entry(struct amd_iommu *iommu, u16 devid,
+ struct irq_remap_table *table)
 {
u64 dte;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
 
-   dte = amd_iommu_dev_table[devid].data[2];
+   dte = dev_table[devid].data[2];
dte &= ~DTE_IRQ_PHYS_ADDR_MASK;
dte |= iommu_virt_to_phys(table->table);
dte |= DTE_IRQ_REMAP_INTCTL;
dte |= DTE_INTTABLEN;
dte |= DTE_IRQ_REMAP_ENABLE;
 
-   amd_iommu_dev_table[devid].data[2] = dte;
+   dev_table[devid].data[2] = dte;
 }
 
 static struct irq_remap_table *get_irq_table(struct amd_iommu *iommu, u16 
devid)
@@ -2791,7 +2793,7 @@ static void set_remap_table_entry(struct amd_iommu 
*iommu, u16 devid,
struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
pci_seg->irq_lookup_table[devid] = table;
-   set_dte_irq_entry(devid, table);
+   set_dte_irq_entry(iommu, devid, table);
iommu_flush_dte(iommu, devid);
 }
 
@@ -2807,8 +2809,7 @@ static int set_remap_table_entry_alias(struct pci_dev 
*pdev, u16 alias,
 
pci_seg = iommu->pci_seg;
pci_seg->irq_lookup_table[alias] = table;
-   set_dte_irq_entry(alias, table);
-
+   set_dte_irq_entry(iommu, alias, table);
iommu_flush_dte(pci_seg->rlookup_table[alias], alias);
 
return 0;
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 23/35] iommu/amd: Update dump_dte_entry

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment device table instead of global
device table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 6223af4ccc22..8c99e2e161aa 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -451,13 +451,13 @@ static void amd_iommu_uninit_device(struct device *dev)
  *
  /
 
-static void dump_dte_entry(u16 devid)
+static void dump_dte_entry(struct amd_iommu *iommu, u16 devid)
 {
int i;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
 
for (i = 0; i < 4; ++i)
-   pr_err("DTE[%d]: %016llx\n", i,
-   amd_iommu_dev_table[devid].data[i]);
+   pr_err("DTE[%d]: %016llx\n", i, dev_table[devid].data[i]);
 }
 
 static void dump_command(unsigned long phys_addr)
@@ -618,7 +618,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void 
*__evt)
dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
pasid, address, flags);
-   dump_dte_entry(devid);
+   dump_dte_entry(iommu, devid);
break;
case EVENT_TYPE_DEV_TAB_ERR:
dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%02x:%02x.%x "
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 22/35] iommu/amd: Update iommu_ignore_device

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment device table instead of global
device table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 678eceb808e9..6223af4ccc22 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -413,15 +413,15 @@ static int iommu_init_device(struct amd_iommu *iommu, 
struct device *dev)
 static void iommu_ignore_device(struct amd_iommu *iommu, struct device *dev)
 {
struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
int devid;
 
-   devid = get_device_id(dev);
+   devid = (get_device_id(dev)) & 0x;
if (devid < 0)
return;
 
-
pci_seg->rlookup_table[devid] = NULL;
-   memset(_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
+   memset(_table[devid], 0, sizeof(struct dev_table_entry));
 
setup_aliases(iommu, dev);
 }
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 21/35] iommu/amd: Update set_dte_entry and clear_dte_entry

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Start using per PCI segment data structures instead of global data
structures.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 19 +++
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 126832ae2997..678eceb808e9 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -1537,6 +1537,7 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
u64 pte_root = 0;
u64 flags = 0;
u32 old_domid;
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
 
if (domain->iop.mode != PAGE_MODE_NONE)
pte_root = iommu_virt_to_phys(domain->iop.root);
@@ -1545,7 +1546,7 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
<< DEV_ENTRY_MODE_SHIFT;
pte_root |= DTE_FLAG_IR | DTE_FLAG_IW | DTE_FLAG_V | DTE_FLAG_TV;
 
-   flags = amd_iommu_dev_table[devid].data[1];
+   flags = dev_table[devid].data[1];
 
if (ats)
flags |= DTE_FLAG_IOTLB;
@@ -1584,9 +1585,9 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
flags &= ~DEV_DOMID_MASK;
flags |= domain->id;
 
-   old_domid = amd_iommu_dev_table[devid].data[1] & DEV_DOMID_MASK;
-   amd_iommu_dev_table[devid].data[1]  = flags;
-   amd_iommu_dev_table[devid].data[0]  = pte_root;
+   old_domid = dev_table[devid].data[1] & DEV_DOMID_MASK;
+   dev_table[devid].data[1]  = flags;
+   dev_table[devid].data[0]  = pte_root;
 
/*
 * A kdump kernel might be replacing a domain ID that was copied from
@@ -1598,11 +1599,13 @@ static void set_dte_entry(struct amd_iommu *iommu, u16 
devid,
}
 }
 
-static void clear_dte_entry(u16 devid)
+static void clear_dte_entry(struct amd_iommu *iommu, u16 devid)
 {
+   struct dev_table_entry *dev_table = get_dev_table(iommu);
+
/* remove entry from the device table seen by the hardware */
-   amd_iommu_dev_table[devid].data[0]  = DTE_FLAG_V | DTE_FLAG_TV;
-   amd_iommu_dev_table[devid].data[1] &= DTE_FLAG_MASK;
+   dev_table[devid].data[0]  = DTE_FLAG_V | DTE_FLAG_TV;
+   dev_table[devid].data[1] &= DTE_FLAG_MASK;
 
amd_iommu_apply_erratum_63(devid);
 }
@@ -1646,7 +1649,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
/* Update data structures */
dev_data->domain = NULL;
list_del(_data->list);
-   clear_dte_entry(dev_data->devid);
+   clear_dte_entry(iommu, dev_data->devid);
clone_aliases(iommu, dev_data->dev);
 
/* Flush the DTE entry */
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 20/35] iommu/amd: Convert to use per PCI segment rlookup_table

2022-05-11 Thread Vasant Hegde via iommu
Then, remove the global amd_iommu_rlookup_table and rlookup_table_size.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  5 -
 drivers/iommu/amd/init.c| 23 ++-
 drivers/iommu/amd/iommu.c   | 19 +--
 3 files changed, 11 insertions(+), 36 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 553e9910e91d..ddd606daa653 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -842,11 +842,6 @@ extern struct dev_table_entry *amd_iommu_dev_table;
  */
 extern u16 *amd_iommu_alias_table;
 
-/*
- * Reverse lookup table to find the IOMMU which translates a specific device.
- */
-extern struct amd_iommu **amd_iommu_rlookup_table;
-
 /* size of the dma_ops aperture as power of 2 */
 extern unsigned amd_iommu_aperture_order;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ed40c7cec879..5e8106641c5c 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -200,12 +200,6 @@ struct dev_table_entry *amd_iommu_dev_table;
  */
 u16 *amd_iommu_alias_table;
 
-/*
- * The rlookup table is used to find the IOMMU which is responsible
- * for a specific device. It is also indexed by the PCI device id.
- */
-struct amd_iommu **amd_iommu_rlookup_table;
-
 /*
  * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
  * to know which ones are already in use.
@@ -214,7 +208,6 @@ unsigned long *amd_iommu_pd_alloc_bitmap;
 
 static u32 dev_table_size; /* size of the device table */
 static u32 alias_table_size;   /* size of the alias table */
-static u32 rlookup_table_size; /* size if the rlookup table */
 
 enum iommu_init_state {
IOMMU_START_STATE,
@@ -1142,7 +1135,7 @@ void amd_iommu_apply_erratum_63(u16 devid)
 /* Writes the specific IOMMU for a device into the rlookup table */
 static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid)
 {
-   amd_iommu_rlookup_table[devid] = iommu;
+   iommu->pci_seg->rlookup_table[devid] = iommu;
 }
 
 /*
@@ -1824,7 +1817,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, 
struct ivhd_header *h,
 * Make sure IOMMU is not considered to translate itself. The IVRS
 * table tells us so, but this is a lie!
 */
-   amd_iommu_rlookup_table[iommu->devid] = NULL;
+   pci_seg->rlookup_table[iommu->devid] = NULL;
 
return 0;
 }
@@ -2782,10 +2775,6 @@ static void __init free_iommu_resources(void)
kmem_cache_destroy(amd_iommu_irq_cache);
amd_iommu_irq_cache = NULL;
 
-   free_pages((unsigned long)amd_iommu_rlookup_table,
-  get_order(rlookup_table_size));
-   amd_iommu_rlookup_table = NULL;
-
free_pages((unsigned long)amd_iommu_alias_table,
   get_order(alias_table_size));
amd_iommu_alias_table = NULL;
@@ -2924,7 +2913,6 @@ static int __init early_amd_iommu_init(void)
 
dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
-   rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
 
/* Device table - directly used by all IOMMUs */
ret = -ENOMEM;
@@ -2943,13 +2931,6 @@ static int __init early_amd_iommu_init(void)
if (amd_iommu_alias_table == NULL)
goto out;
 
-   /* IOMMU rlookup table - find the IOMMU for a specific device */
-   amd_iommu_rlookup_table = (void *)__get_free_pages(
-   GFP_KERNEL | __GFP_ZERO,
-   get_order(rlookup_table_size));
-   if (amd_iommu_rlookup_table == NULL)
-   goto out;
-
amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
get_order(MAX_DOMAIN_ID/8));
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 34909faeef76..126832ae2997 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -287,10 +287,9 @@ static void setup_aliases(struct amd_iommu *iommu, struct 
device *dev)
clone_aliases(iommu, dev);
 }
 
-static struct iommu_dev_data *find_dev_data(u16 devid)
+static struct iommu_dev_data *find_dev_data(struct amd_iommu *iommu, u16 devid)
 {
struct iommu_dev_data *dev_data;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
 
dev_data = search_dev_data(iommu, devid);
 
@@ -388,7 +387,7 @@ static int iommu_init_device(struct amd_iommu *iommu, 
struct device *dev)
if (devid < 0)
return devid;
 
-   dev_data = find_dev_data(devid);
+   dev_data = find_dev_data(iommu, devid);
if (!dev_data)
return -ENOMEM;
 
@@ -403,9 +402,6 @@ static int iommu_init_device(struct amd_iommu *iommu, 
struct 

[PATCH v3 19/35] iommu/amd: Update alloc_irq_table and alloc_irq_index

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Pass amd_iommu structure as one of the parameter to these functions
as its needed to retrieve variable tables inside these functions.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/iommu.c | 26 +-
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 2023bb7c2c3a..34909faeef76 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2812,21 +2812,17 @@ static int set_remap_table_entry_alias(struct pci_dev 
*pdev, u16 alias,
return 0;
 }
 
-static struct irq_remap_table *alloc_irq_table(u16 devid, struct pci_dev *pdev)
+static struct irq_remap_table *alloc_irq_table(struct amd_iommu *iommu,
+  u16 devid, struct pci_dev *pdev)
 {
struct irq_remap_table *table = NULL;
struct irq_remap_table *new_table = NULL;
struct amd_iommu_pci_seg *pci_seg;
-   struct amd_iommu *iommu;
unsigned long flags;
u16 alias;
 
spin_lock_irqsave(_table_lock, flags);
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (!iommu)
-   goto out_unlock;
-
pci_seg = iommu->pci_seg;
table = pci_seg->irq_lookup_table[devid];
if (table)
@@ -2882,18 +2878,14 @@ static struct irq_remap_table *alloc_irq_table(u16 
devid, struct pci_dev *pdev)
return table;
 }
 
-static int alloc_irq_index(u16 devid, int count, bool align,
-  struct pci_dev *pdev)
+static int alloc_irq_index(struct amd_iommu *iommu, u16 devid, int count,
+  bool align, struct pci_dev *pdev)
 {
struct irq_remap_table *table;
int index, c, alignment = 1;
unsigned long flags;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
-
-   if (!iommu)
-   return -ENODEV;
 
-   table = alloc_irq_table(devid, pdev);
+   table = alloc_irq_table(iommu, devid, pdev);
if (!table)
return -ENODEV;
 
@@ -3265,7 +3257,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
struct irq_remap_table *table;
 
-   table = alloc_irq_table(devid, NULL);
+   table = alloc_irq_table(iommu, devid, NULL);
if (table) {
if (!table->min_index) {
/*
@@ -3285,10 +3277,10 @@ static int irq_remapping_alloc(struct irq_domain 
*domain, unsigned int virq,
   info->type == X86_IRQ_ALLOC_TYPE_PCI_MSIX) {
bool align = (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI);
 
-   index = alloc_irq_index(devid, nr_irqs, align,
+   index = alloc_irq_index(iommu, devid, nr_irqs, align,
msi_desc_to_pci_dev(info->desc));
} else {
-   index = alloc_irq_index(devid, nr_irqs, false, NULL);
+   index = alloc_irq_index(iommu, devid, nr_irqs, false, NULL);
}
 
if (index < 0) {
@@ -3414,8 +3406,8 @@ static int irq_remapping_select(struct irq_domain *d, 
struct irq_fwspec *fwspec,
 
if (devid < 0)
return 0;
+   iommu = __rlookup_amd_iommu((devid >> 16), (devid & 0x));
 
-   iommu = amd_iommu_rlookup_table[devid];
return iommu && iommu->ir_domain == d;
 }
 
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 18/35] iommu/amd: Update amd_irte_ops functions

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Pass amd_iommu structure as one of the parameter to amd_irte_ops functions
since its needed to activate/deactivate the iommu.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  6 ++--
 drivers/iommu/amd/iommu.c   | 51 -
 2 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index aee923f8ef9e..553e9910e91d 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -1003,9 +1003,9 @@ struct amd_ir_data {
 
 struct amd_irte_ops {
void (*prepare)(void *, u32, bool, u8, u32, int);
-   void (*activate)(void *, u16, u16);
-   void (*deactivate)(void *, u16, u16);
-   void (*set_affinity)(void *, u16, u16, u8, u32);
+   void (*activate)(struct amd_iommu *iommu, void *, u16, u16);
+   void (*deactivate)(struct amd_iommu *iommu, void *, u16, u16);
+   void (*set_affinity)(struct amd_iommu *iommu, void *, u16, u16, u8, 
u32);
void *(*get)(struct irq_remap_table *, int);
void (*set_allocated)(struct irq_remap_table *, int);
bool (*is_allocated)(struct irq_remap_table *, int);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 935e12fb6db4..2023bb7c2c3a 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2932,19 +2932,14 @@ static int alloc_irq_index(u16 devid, int count, bool 
align,
return index;
 }
 
-static int modify_irte_ga(u16 devid, int index, struct irte_ga *irte,
- struct amd_ir_data *data)
+static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
+ struct irte_ga *irte, struct amd_ir_data *data)
 {
bool ret;
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
unsigned long flags;
struct irte_ga *entry;
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (iommu == NULL)
-   return -EINVAL;
-
table = get_irq_table(iommu, devid);
if (!table)
return -ENOMEM;
@@ -2976,16 +2971,12 @@ static int modify_irte_ga(u16 devid, int index, struct 
irte_ga *irte,
return 0;
 }
 
-static int modify_irte(u16 devid, int index, union irte *irte)
+static int modify_irte(struct amd_iommu *iommu,
+  u16 devid, int index, union irte *irte)
 {
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
unsigned long flags;
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (iommu == NULL)
-   return -EINVAL;
-
table = get_irq_table(iommu, devid);
if (!table)
return -ENOMEM;
@@ -3047,49 +3038,49 @@ static void irte_ga_prepare(void *entry,
irte->lo.fields_remap.valid   = 1;
 }
 
-static void irte_activate(void *entry, u16 devid, u16 index)
+static void irte_activate(struct amd_iommu *iommu, void *entry, u16 devid, u16 
index)
 {
union irte *irte = (union irte *) entry;
 
irte->fields.valid = 1;
-   modify_irte(devid, index, irte);
+   modify_irte(iommu, devid, index, irte);
 }
 
-static void irte_ga_activate(void *entry, u16 devid, u16 index)
+static void irte_ga_activate(struct amd_iommu *iommu, void *entry, u16 devid, 
u16 index)
 {
struct irte_ga *irte = (struct irte_ga *) entry;
 
irte->lo.fields_remap.valid = 1;
-   modify_irte_ga(devid, index, irte, NULL);
+   modify_irte_ga(iommu, devid, index, irte, NULL);
 }
 
-static void irte_deactivate(void *entry, u16 devid, u16 index)
+static void irte_deactivate(struct amd_iommu *iommu, void *entry, u16 devid, 
u16 index)
 {
union irte *irte = (union irte *) entry;
 
irte->fields.valid = 0;
-   modify_irte(devid, index, irte);
+   modify_irte(iommu, devid, index, irte);
 }
 
-static void irte_ga_deactivate(void *entry, u16 devid, u16 index)
+static void irte_ga_deactivate(struct amd_iommu *iommu, void *entry, u16 
devid, u16 index)
 {
struct irte_ga *irte = (struct irte_ga *) entry;
 
irte->lo.fields_remap.valid = 0;
-   modify_irte_ga(devid, index, irte, NULL);
+   modify_irte_ga(iommu, devid, index, irte, NULL);
 }
 
-static void irte_set_affinity(void *entry, u16 devid, u16 index,
+static void irte_set_affinity(struct amd_iommu *iommu, void *entry, u16 devid, 
u16 index,
  u8 vector, u32 dest_apicid)
 {
union irte *irte = (union irte *) entry;
 
irte->fields.vector = vector;
irte->fields.destination = dest_apicid;
-   modify_irte(devid, index, irte);
+   modify_irte(iommu, devid, index, irte);
 }
 
-static void irte_ga_set_affinity(void *entry, u16 devid, u16 index,
+static void irte_ga_set_affinity(struct amd_iommu *iommu, void *entry, u16 
devid, u16 index,
 u8 vector, u32 

[PATCH v3 17/35] iommu/amd: Introduce struct amd_ir_data.iommu

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Add a pointer to struct amd_iommu to amd_ir_data structure, which
can be used to correlate interrupt remapping data to a per-PCI-segment
interrupt remapping table.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h |  1 +
 drivers/iommu/amd/iommu.c   | 34 +
 2 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 79c44f6033e0..aee923f8ef9e 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -985,6 +985,7 @@ struct irq_2_irte {
 
 struct amd_ir_data {
u32 cached_ga_tag;
+   struct amd_iommu *iommu;
struct irq_2_irte irq_2_irte;
struct msi_msg msi_entry;
void *entry;/* Pointer to union irte or struct irte_ga */
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 502e66d09c61..935e12fb6db4 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3000,16 +3000,11 @@ static int modify_irte(u16 devid, int index, union irte 
*irte)
return 0;
 }
 
-static void free_irte(u16 devid, int index)
+static void free_irte(struct amd_iommu *iommu, u16 devid, int index)
 {
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
unsigned long flags;
 
-   iommu = amd_iommu_rlookup_table[devid];
-   if (iommu == NULL)
-   return;
-
table = get_irq_table(iommu, devid);
if (!table)
return;
@@ -3193,7 +3188,7 @@ static void irq_remapping_prepare_irte(struct amd_ir_data 
*data,
   int devid, int index, int sub_handle)
 {
struct irq_2_irte *irte_info = >irq_2_irte;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+   struct amd_iommu *iommu = data->iommu;
 
if (!iommu)
return;
@@ -3334,6 +3329,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
goto out_free_data;
}
 
+   data->iommu = iommu;
irq_data->hwirq = (devid << 16) + i;
irq_data->chip_data = data;
irq_data->chip = _ir_chip;
@@ -3350,7 +3346,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
kfree(irq_data->chip_data);
}
for (i = 0; i < nr_irqs; i++)
-   free_irte(devid, index + i);
+   free_irte(iommu, devid, index + i);
 out_free_parent:
irq_domain_free_irqs_common(domain, virq, nr_irqs);
return ret;
@@ -3369,7 +3365,7 @@ static void irq_remapping_free(struct irq_domain *domain, 
unsigned int virq,
if (irq_data && irq_data->chip_data) {
data = irq_data->chip_data;
irte_info = >irq_2_irte;
-   free_irte(irte_info->devid, irte_info->index);
+   free_irte(data->iommu, irte_info->devid, 
irte_info->index);
kfree(data->entry);
kfree(data);
}
@@ -3387,7 +3383,7 @@ static int irq_remapping_activate(struct irq_domain 
*domain,
 {
struct amd_ir_data *data = irq_data->chip_data;
struct irq_2_irte *irte_info = >irq_2_irte;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[irte_info->devid];
+   struct amd_iommu *iommu = data->iommu;
struct irq_cfg *cfg = irqd_cfg(irq_data);
 
if (!iommu)
@@ -3404,7 +3400,7 @@ static void irq_remapping_deactivate(struct irq_domain 
*domain,
 {
struct amd_ir_data *data = irq_data->chip_data;
struct irq_2_irte *irte_info = >irq_2_irte;
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[irte_info->devid];
+   struct amd_iommu *iommu = data->iommu;
 
if (iommu)
iommu->irte_ops->deactivate(data->entry, irte_info->devid,
@@ -3500,12 +3496,16 @@ EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
 {
int ret;
-   struct amd_iommu *iommu;
struct amd_iommu_pi_data *pi_data = vcpu_info;
struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data;
struct amd_ir_data *ir_data = data->chip_data;
struct irq_2_irte *irte_info = _data->irq_2_irte;
-   struct iommu_dev_data *dev_data = search_dev_data(NULL, 
irte_info->devid);
+   struct iommu_dev_data *dev_data;
+
+   if (ir_data->iommu == NULL)
+   return -EINVAL;
+
+   dev_data = search_dev_data(ir_data->iommu, irte_info->devid);
 
/* Note:
 * This device has never been set up for guest mode.
@@ -3527,10 +3527,6 @@ static int amd_ir_set_vcpu_affinity(struct irq_data 
*data, void *vcpu_info)
pi_data->is_guest_mode = false;
 

[PATCH v3 16/35] iommu/amd: Update irq_remapping_alloc to use IOMMU lookup helper function

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

To allow IOMMU rlookup using both PCI segment and device ID.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/iommu.c | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 1485e4d4fb52..502e66d09c61 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3244,8 +3244,9 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
struct irq_alloc_info *info = arg;
struct irq_data *irq_data;
struct amd_ir_data *data = NULL;
+   struct amd_iommu *iommu;
struct irq_cfg *cfg;
-   int i, ret, devid;
+   int i, ret, devid, seg, sbdf;
int index;
 
if (!info)
@@ -3261,8 +3262,14 @@ static int irq_remapping_alloc(struct irq_domain 
*domain, unsigned int virq,
if (info->type == X86_IRQ_ALLOC_TYPE_PCI_MSI)
info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
 
-   devid = get_devid(info);
-   if (devid < 0)
+   sbdf = get_devid(info);
+   if (sbdf < 0)
+   return -EINVAL;
+
+   seg = PCI_SBDF_TO_SEGID(sbdf);
+   devid = PCI_SBDF_TO_DEVID(sbdf);
+   iommu = __rlookup_amd_iommu(seg, devid);
+   if (!iommu)
return -EINVAL;
 
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
@@ -3271,7 +3278,6 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
 
if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
struct irq_remap_table *table;
-   struct amd_iommu *iommu;
 
table = alloc_irq_table(devid, NULL);
if (table) {
@@ -3281,7 +3287,6 @@ static int irq_remapping_alloc(struct irq_domain *domain, 
unsigned int virq,
 * interrupts.
 */
table->min_index = 32;
-   iommu = amd_iommu_rlookup_table[devid];
for (i = 0; i < 32; ++i)
iommu->irte_ops->set_allocated(table, 
i);
}
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 15/35] iommu/amd: Convert to use rlookup_amd_iommu helper function

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Use rlookup_amd_iommu() helper function which will give per PCI
segment rlookup_table.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu.c | 64 +++
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 02fb244c3c7d..1485e4d4fb52 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -229,13 +229,17 @@ static struct iommu_dev_data *search_dev_data(struct 
amd_iommu *iommu, u16 devid
 
 static int clone_alias(struct pci_dev *pdev, u16 alias, void *data)
 {
+   struct amd_iommu *iommu;
u16 devid = pci_dev_id(pdev);
 
if (devid == alias)
return 0;
 
-   amd_iommu_rlookup_table[alias] =
-   amd_iommu_rlookup_table[devid];
+   iommu = rlookup_amd_iommu(>dev);
+   if (!iommu)
+   return 0;
+
+   amd_iommu_set_rlookup_table(iommu, alias);
memcpy(amd_iommu_dev_table[alias].data,
   amd_iommu_dev_table[devid].data,
   sizeof(amd_iommu_dev_table[alias].data));
@@ -366,7 +370,7 @@ static bool check_device(struct device *dev)
if (devid > amd_iommu_last_bdf)
return false;
 
-   if (amd_iommu_rlookup_table[devid] == NULL)
+   if (rlookup_amd_iommu(dev) == NULL)
return false;
 
return true;
@@ -1270,7 +1274,9 @@ static int device_flush_iotlb(struct iommu_dev_data 
*dev_data,
int qdep;
 
qdep = dev_data->ats.qdep;
-   iommu= amd_iommu_rlookup_table[dev_data->devid];
+   iommu= rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return -EINVAL;
 
build_inv_iotlb_pages(, dev_data->devid, qdep, address, size);
 
@@ -1295,7 +1301,9 @@ static int device_flush_dte(struct iommu_dev_data 
*dev_data)
u16 alias;
int ret;
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return -EINVAL;
 
if (dev_is_pci(dev_data->dev))
pdev = to_pci_dev(dev_data->dev);
@@ -1525,8 +1533,8 @@ static void free_gcr3_table(struct protection_domain 
*domain)
free_page((unsigned long)domain->gcr3_tbl);
 }
 
-static void set_dte_entry(u16 devid, struct protection_domain *domain,
- bool ats, bool ppr)
+static void set_dte_entry(struct amd_iommu *iommu, u16 devid,
+ struct protection_domain *domain, bool ats, bool ppr)
 {
u64 pte_root = 0;
u64 flags = 0;
@@ -1545,8 +1553,6 @@ static void set_dte_entry(u16 devid, struct 
protection_domain *domain,
flags |= DTE_FLAG_IOTLB;
 
if (ppr) {
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
-
if (iommu_feature(iommu, FEATURE_EPHSUP))
pte_root |= 1ULL << DEV_ENTRY_PPR;
}
@@ -1590,8 +1596,6 @@ static void set_dte_entry(u16 devid, struct 
protection_domain *domain,
 * entries for the old domain ID that is being overwritten
 */
if (old_domid) {
-   struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
-
amd_iommu_flush_tlb_domid(iommu, old_domid);
}
 }
@@ -1611,7 +1615,9 @@ static void do_attach(struct iommu_dev_data *dev_data,
struct amd_iommu *iommu;
bool ats;
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return;
ats   = dev_data->ats.enabled;
 
/* Update data structures */
@@ -1623,7 +1629,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
domain->dev_cnt += 1;
 
/* Update device table */
-   set_dte_entry(dev_data->devid, domain,
+   set_dte_entry(iommu, dev_data->devid, domain,
  ats, dev_data->iommu_v2);
clone_aliases(iommu, dev_data->dev);
 
@@ -1635,7 +1641,9 @@ static void do_detach(struct iommu_dev_data *dev_data)
struct protection_domain *domain = dev_data->domain;
struct amd_iommu *iommu;
 
-   iommu = amd_iommu_rlookup_table[dev_data->devid];
+   iommu = rlookup_amd_iommu(dev_data->dev);
+   if (!iommu)
+   return;
 
/* Update data structures */
dev_data->domain = NULL;
@@ -1813,13 +1821,14 @@ static struct iommu_device 
*amd_iommu_probe_device(struct device *dev)
 {
struct iommu_device *iommu_dev;
struct amd_iommu *iommu;
-   int ret, devid;
+   int ret;
 
if (!check_device(dev))
return ERR_PTR(-ENODEV);
 
-   devid = get_device_id(dev);
-   iommu = amd_iommu_rlookup_table[devid];
+   iommu = rlookup_amd_iommu(dev);
+   if (!iommu)
+   return ERR_PTR(-ENODEV);
 
if 

[PATCH v3 14/35] iommu/amd: Convert to use per PCI segment irq_lookup_table

2022-05-11 Thread Vasant Hegde via iommu
Then, remove the global irq_lookup_table.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  2 --
 drivers/iommu/amd/init.c| 19 ---
 drivers/iommu/amd/iommu.c   | 36 ++---
 3 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index cf3157ba1225..79c44f6033e0 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -444,8 +444,6 @@ struct irq_remap_table {
u32 *table;
 };
 
-extern struct irq_remap_table **irq_lookup_table;
-
 /* Interrupt remapping feature used? */
 extern bool amd_iommu_irq_remap;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 018dfd0370c6..ed40c7cec879 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -206,12 +206,6 @@ u16 *amd_iommu_alias_table;
  */
 struct amd_iommu **amd_iommu_rlookup_table;
 
-/*
- * This table is used to find the irq remapping table for a given device id
- * quickly.
- */
-struct irq_remap_table **irq_lookup_table;
-
 /*
  * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap
  * to know which ones are already in use.
@@ -2785,11 +2779,6 @@ static struct syscore_ops amd_iommu_syscore_ops = {
 
 static void __init free_iommu_resources(void)
 {
-   kmemleak_free(irq_lookup_table);
-   free_pages((unsigned long)irq_lookup_table,
-  get_order(rlookup_table_size));
-   irq_lookup_table = NULL;
-
kmem_cache_destroy(amd_iommu_irq_cache);
amd_iommu_irq_cache = NULL;
 
@@ -3010,14 +2999,6 @@ static int __init early_amd_iommu_init(void)
if (alloc_irq_lookup_table(pci_seg))
goto out;
}
-
-   irq_lookup_table = (void *)__get_free_pages(
-   GFP_KERNEL | __GFP_ZERO,
-   get_order(rlookup_table_size));
-   kmemleak_alloc(irq_lookup_table, rlookup_table_size,
-  1, GFP_KERNEL);
-   if (!irq_lookup_table)
-   goto out;
}
 
ret = init_memory_definitions(ivrs_base);
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 5118ade206b8..02fb244c3c7d 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2730,16 +2730,18 @@ static void set_dte_irq_entry(u16 devid, struct 
irq_remap_table *table)
amd_iommu_dev_table[devid].data[2] = dte;
 }
 
-static struct irq_remap_table *get_irq_table(u16 devid)
+static struct irq_remap_table *get_irq_table(struct amd_iommu *iommu, u16 
devid)
 {
struct irq_remap_table *table;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
if (WARN_ONCE(!amd_iommu_rlookup_table[devid],
  "%s: no iommu for devid %x\n", __func__, devid))
return NULL;
 
-   table = irq_lookup_table[devid];
-   if (WARN_ONCE(!table, "%s: no table for devid %x\n", __func__, devid))
+   table = pci_seg->irq_lookup_table[devid];
+   if (WARN_ONCE(!table, "%s: no table for devid %x:%x\n",
+ __func__, pci_seg->id, devid))
return NULL;
 
return table;
@@ -2772,7 +2774,9 @@ static struct irq_remap_table *__alloc_irq_table(void)
 static void set_remap_table_entry(struct amd_iommu *iommu, u16 devid,
  struct irq_remap_table *table)
 {
-   irq_lookup_table[devid] = table;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+   pci_seg->irq_lookup_table[devid] = table;
set_dte_irq_entry(devid, table);
iommu_flush_dte(iommu, devid);
 }
@@ -2781,8 +2785,14 @@ static int set_remap_table_entry_alias(struct pci_dev 
*pdev, u16 alias,
   void *data)
 {
struct irq_remap_table *table = data;
+   struct amd_iommu_pci_seg *pci_seg;
+   struct amd_iommu *iommu = rlookup_amd_iommu(>dev);
 
-   irq_lookup_table[alias] = table;
+   if (!iommu)
+   return -EINVAL;
+
+   pci_seg = iommu->pci_seg;
+   pci_seg->irq_lookup_table[alias] = table;
set_dte_irq_entry(alias, table);
 
iommu_flush_dte(amd_iommu_rlookup_table[alias], alias);
@@ -2806,12 +2816,12 @@ static struct irq_remap_table *alloc_irq_table(u16 
devid, struct pci_dev *pdev)
goto out_unlock;
 
pci_seg = iommu->pci_seg;
-   table = irq_lookup_table[devid];
+   table = pci_seg->irq_lookup_table[devid];
if (table)
goto out_unlock;
 
alias = pci_seg->alias_table[devid];
-   table = irq_lookup_table[alias];
+   table = pci_seg->irq_lookup_table[alias];
if (table) {
set_remap_table_entry(iommu, devid, table);
  

[PATCH v3 13/35] iommu/amd: Introduce per PCI segment rlookup table size

2022-05-11 Thread Vasant Hegde via iommu
It will replace global "rlookup_table_size" variable.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 +++
 drivers/iommu/amd/init.c| 11 ++-
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 4912e1913b96..cf3157ba1225 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -557,6 +557,9 @@ struct amd_iommu_pci_seg {
/* Size of the alias table */
u32 alias_table_size;
 
+   /* Size of the rlookup table */
+   u32 rlookup_table_size;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 0d9126a92cff..018dfd0370c6 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -670,7 +670,7 @@ static inline int __init alloc_rlookup_table(struct 
amd_iommu_pci_seg *pci_seg)
 {
pci_seg->rlookup_table = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
-   get_order(rlookup_table_size));
+   
get_order(pci_seg->rlookup_table_size));
if (pci_seg->rlookup_table == NULL)
return -ENOMEM;
 
@@ -680,7 +680,7 @@ static inline int __init alloc_rlookup_table(struct 
amd_iommu_pci_seg *pci_seg)
 static inline void free_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
 {
free_pages((unsigned long)pci_seg->rlookup_table,
-  get_order(rlookup_table_size));
+  get_order(pci_seg->rlookup_table_size));
pci_seg->rlookup_table = NULL;
 }
 
@@ -688,9 +688,9 @@ static inline int __init alloc_irq_lookup_table(struct 
amd_iommu_pci_seg *pci_se
 {
pci_seg->irq_lookup_table = (void *)__get_free_pages(
 GFP_KERNEL | __GFP_ZERO,
-get_order(rlookup_table_size));
+
get_order(pci_seg->rlookup_table_size));
kmemleak_alloc(pci_seg->irq_lookup_table,
-  rlookup_table_size, 1, GFP_KERNEL);
+  pci_seg->rlookup_table_size, 1, GFP_KERNEL);
if (pci_seg->irq_lookup_table == NULL)
return -ENOMEM;
 
@@ -701,7 +701,7 @@ static inline void free_irq_lookup_table(struct 
amd_iommu_pci_seg *pci_seg)
 {
kmemleak_free(pci_seg->irq_lookup_table);
free_pages((unsigned long)pci_seg->irq_lookup_table,
-  get_order(rlookup_table_size));
+  get_order(pci_seg->rlookup_table_size));
pci_seg->irq_lookup_table = NULL;
 }
 
@@ -1582,6 +1582,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id,
DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
pci_seg->dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
pci_seg->alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
+   pci_seg->rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 12/35] iommu/amd: Introduce per PCI segment alias table size

2022-05-11 Thread Vasant Hegde via iommu
It will replace global "alias_table_size" variable.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 3 +++
 drivers/iommu/amd/init.c| 5 +++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 6d979c4efd54..4912e1913b96 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -554,6 +554,9 @@ struct amd_iommu_pci_seg {
/* Size of the device table */
u32 dev_table_size;
 
+   /* Size of the alias table */
+   u32 alias_table_size;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 721154c3bf4d..0d9126a92cff 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -710,7 +710,7 @@ static int __init alloc_alias_table(struct 
amd_iommu_pci_seg *pci_seg)
int i;
 
pci_seg->alias_table = (void *)__get_free_pages(GFP_KERNEL,
-   
get_order(alias_table_size));
+   get_order(pci_seg->alias_table_size));
if (!pci_seg->alias_table)
return -ENOMEM;
 
@@ -726,7 +726,7 @@ static int __init alloc_alias_table(struct 
amd_iommu_pci_seg *pci_seg)
 static void __init free_alias_table(struct amd_iommu_pci_seg *pci_seg)
 {
free_pages((unsigned long)pci_seg->alias_table,
-  get_order(alias_table_size));
+  get_order(pci_seg->alias_table_size));
pci_seg->alias_table = NULL;
 }
 
@@ -1581,6 +1581,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id,
pci_seg->last_bdf = last_bdf;
DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
pci_seg->dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
+   pci_seg->alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 11/35] iommu/amd: Introduce per PCI segment device table size

2022-05-11 Thread Vasant Hegde via iommu
With multiple pci segment support, number of BDF supported by each
segment may differ. Hence introduce per segment device table size
which depends on last_bdf. This will replace global
"device_table_size" variable.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 +++
 drivers/iommu/amd/init.c| 18 ++
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 8b8079fdf0d4..6d979c4efd54 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -551,6 +551,9 @@ struct amd_iommu_pci_seg {
/* Largest PCI device id we expect translation requests for */
u16 last_bdf;
 
+   /* Size of the device table */
+   u32 dev_table_size;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 67a92f453731..721154c3bf4d 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -414,6 +414,7 @@ static void iommu_set_cwwb_range(struct amd_iommu *iommu)
 static void iommu_set_device_table(struct amd_iommu *iommu)
 {
u64 entry;
+   u32 dev_table_size = iommu->pci_seg->dev_table_size;
 
BUG_ON(iommu->mmio_base == NULL);
 
@@ -650,7 +651,7 @@ static int __init find_last_devid_acpi(struct 
acpi_table_header *table, u16 pci_
 static inline int __init alloc_dev_table(struct amd_iommu_pci_seg *pci_seg)
 {
pci_seg->dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO | 
GFP_DMA32,
- 
get_order(dev_table_size));
+ 
get_order(pci_seg->dev_table_size));
if (!pci_seg->dev_table)
return -ENOMEM;
 
@@ -660,7 +661,7 @@ static inline int __init alloc_dev_table(struct 
amd_iommu_pci_seg *pci_seg)
 static inline void free_dev_table(struct amd_iommu_pci_seg *pci_seg)
 {
free_pages((unsigned long)pci_seg->dev_table,
-   get_order(dev_table_size));
+   get_order(pci_seg->dev_table_size));
pci_seg->dev_table = NULL;
 }
 
@@ -1033,7 +1034,7 @@ static bool __copy_device_table(struct amd_iommu *iommu)
entry = (((u64) hi) << 32) + lo;
 
old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
-   if (old_devtb_size != dev_table_size) {
+   if (old_devtb_size != pci_seg->dev_table_size) {
pr_err("The device table size of IOMMU:%d is not expected!\n",
iommu->index);
return false;
@@ -1052,15 +1053,15 @@ static bool __copy_device_table(struct amd_iommu *iommu)
}
old_devtb = (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT) && 
is_kdump_kernel())
? (__force void *)ioremap_encrypted(old_devtb_phys,
-   dev_table_size)
-   : memremap(old_devtb_phys, dev_table_size, MEMREMAP_WB);
+   pci_seg->dev_table_size)
+   : memremap(old_devtb_phys, pci_seg->dev_table_size, 
MEMREMAP_WB);
 
if (!old_devtb)
return false;
 
gfp_flag = GFP_KERNEL | __GFP_ZERO | GFP_DMA32;
pci_seg->old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
-   get_order(dev_table_size));
+   
get_order(pci_seg->dev_table_size));
if (pci_seg->old_dev_tbl_cpy == NULL) {
pr_err("Failed to allocate memory for copying old device 
table!\n");
memunmap(old_devtb);
@@ -1579,6 +1580,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id,
 
pci_seg->last_bdf = last_bdf;
DUMP_printk("PCI segment : 0x%0x, last bdf : 0x%04x\n", id, last_bdf);
+   pci_seg->dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
@@ -2674,7 +2676,7 @@ static void early_enable_iommus(void)
for_each_pci_segment(pci_seg) {
if (pci_seg->old_dev_tbl_cpy != NULL) {
free_pages((unsigned 
long)pci_seg->old_dev_tbl_cpy,
-   get_order(dev_table_size));
+   
get_order(pci_seg->dev_table_size));
pci_seg->old_dev_tbl_cpy = NULL;
}
}
@@ -2688,7 +2690,7 @@ static void early_enable_iommus(void)
 
for_each_pci_segment(pci_seg) {
free_pages((unsigned long)pci_seg->dev_table,
-  get_order(dev_table_size));
+  

[PATCH v3 10/35] iommu/amd: Introduce per PCI segment last_bdf

2022-05-11 Thread Vasant Hegde via iommu
Current code uses global "amd_iommu_last_bdf" to track the last bdf
supported by the system. This value is used for various memory
allocation, device data flushing, etc.

Introduce per PCI segment last_bdf which will be used to track last bdf
supported by the given PCI segment and use this value for all per
segment memory allocations. Eventually it will replace global
"amd_iommu_last_bdf".

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 ++
 drivers/iommu/amd/init.c| 69 ++---
 2 files changed, 45 insertions(+), 27 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 574f4f414f7d..8b8079fdf0d4 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -548,6 +548,9 @@ struct amd_iommu_pci_seg {
/* PCI segment number */
u16 id;
 
+   /* Largest PCI device id we expect translation requests for */
+   u16 last_bdf;
+
/*
 * device table virtual address
 *
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 5cb21d43bd6f..67a92f453731 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -550,6 +550,7 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
 {
u8 *p = (void *)h, *end = (void *)h;
struct ivhd_entry *dev;
+   int last_devid = -EINVAL;
 
u32 ivhd_size = get_ivhd_header_size(h);
 
@@ -567,13 +568,15 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
case IVHD_DEV_ALL:
/* Use maximum BDF value for DEV_ALL */
update_last_devid(0x);
-   break;
+   return 0x;
case IVHD_DEV_SELECT:
case IVHD_DEV_RANGE_END:
case IVHD_DEV_ALIAS:
case IVHD_DEV_EXT_SELECT:
/* all the above subfield types refer to device ids */
update_last_devid(dev->devid);
+   if (dev->devid > last_devid)
+   last_devid = dev->devid;
break;
default:
break;
@@ -583,7 +586,7 @@ static int __init find_last_devid_from_ivhd(struct 
ivhd_header *h)
 
WARN_ON(p != end);
 
-   return 0;
+   return last_devid;
 }
 
 static int __init check_ivrs_checksum(struct acpi_table_header *table)
@@ -607,27 +610,31 @@ static int __init check_ivrs_checksum(struct 
acpi_table_header *table)
  * id which we need to handle. This is the first of three functions which parse
  * the ACPI table. So we check the checksum here.
  */
-static int __init find_last_devid_acpi(struct acpi_table_header *table)
+static int __init find_last_devid_acpi(struct acpi_table_header *table, u16 
pci_seg)
 {
u8 *p = (u8 *)table, *end = (u8 *)table;
struct ivhd_header *h;
+   int last_devid, last_bdf = 0;
 
p += IVRS_HEADER_LENGTH;
 
end += table->length;
while (p < end) {
h = (struct ivhd_header *)p;
-   if (h->type == amd_iommu_target_ivhd_type) {
-   int ret = find_last_devid_from_ivhd(h);
-
-   if (ret)
-   return ret;
+   if (h->pci_seg == pci_seg &&
+   h->type == amd_iommu_target_ivhd_type) {
+   last_devid = find_last_devid_from_ivhd(h);
+
+   if (last_devid < 0)
+   return -EINVAL;
+   if (last_devid > last_bdf)
+   last_bdf = last_devid;
}
p += h->length;
}
WARN_ON(p != end);
 
-   return 0;
+   return last_bdf;
 }
 
 /
@@ -1551,14 +1558,28 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
 }
 
 /* Allocate PCI segment data structure */
-static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
+static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id,
+ struct acpi_table_header *ivrs_base)
 {
struct amd_iommu_pci_seg *pci_seg;
+   int last_bdf;
+
+   /*
+* First parse ACPI tables to find the largest Bus/Dev/Func we need to
+* handle in this PCI segment. Upon this information the shared data
+* structures for the PCI segments in the system will be allocated.
+*/
+   last_bdf = find_last_devid_acpi(ivrs_base, id);
+   if (last_bdf < 0)
+   return NULL;
 
pci_seg = kzalloc(sizeof(struct amd_iommu_pci_seg), GFP_KERNEL);
if (pci_seg == NULL)
return NULL;
 
+   pci_seg->last_bdf = 

[PATCH v3 09/35] iommu/amd: Introduce per PCI segment unity map list

2022-05-11 Thread Vasant Hegde via iommu
Newer AMD systems can support multiple PCI segments. In order to support
multiple PCI segments IVMD table in IVRS structure is enhanced to
include pci segment id. Update ivmd_header structure to include "pci_seg".

Also introduce per PCI segment unity map list. It will replace global
amd_iommu_unity_map list.

Note that we have used "reserved" field in IVMD table to include "pci_seg
id" which was set to zero. It will take care of backward compatibility
(new kernel will work fine on older systems).

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 13 +++--
 drivers/iommu/amd/init.c| 30 +++--
 drivers/iommu/amd/iommu.c   |  8 +++-
 3 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 9534064124f9..574f4f414f7d 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -583,6 +583,13 @@ struct amd_iommu_pci_seg {
 * More than one device can share the same requestor id.
 */
u16 *alias_table;
+
+   /*
+* A list of required unity mappings we find in ACPI. It is not locked
+* because as runtime it is only read. It is created at ACPI table
+* parsing time.
+*/
+   struct list_head unity_map;
 };
 
 /*
@@ -809,12 +816,6 @@ struct unity_map_entry {
int prot;
 };
 
-/*
- * List of all unity mappings. It is not locked because as runtime it is only
- * read. It is created at ACPI table parsing time.
- */
-extern struct list_head amd_iommu_unity_map;
-
 /*
  * Data structures for device handling
  */
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 9d57cb05878e..5cb21d43bd6f 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -142,7 +142,8 @@ struct ivmd_header {
u16 length;
u16 devid;
u16 aux;
-   u64 resv;
+   u16 pci_seg;
+   u8  resv[6];
u64 range_start;
u64 range_length;
 } __attribute__((packed));
@@ -162,8 +163,6 @@ static int amd_iommu_target_ivhd_type;
 
 u16 amd_iommu_last_bdf;/* largest PCI device id we have
   to handle */
-LIST_HEAD(amd_iommu_unity_map);/* a list of required unity 
mappings
-  we find in ACPI */
 
 LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
@@ -1562,6 +1561,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
pci_seg->id = id;
init_llist_head(_seg->dev_data_list);
+   INIT_LIST_HEAD(_seg->unity_map);
list_add_tail(_seg->list, _iommu_pci_seg_list);
 
if (alloc_dev_table(pci_seg))
@@ -2397,10 +2397,13 @@ static int iommu_init_irq(struct amd_iommu *iommu)
 static void __init free_unity_maps(void)
 {
struct unity_map_entry *entry, *next;
+   struct amd_iommu_pci_seg *p, *pci_seg;
 
-   list_for_each_entry_safe(entry, next, _iommu_unity_map, list) {
-   list_del(>list);
-   kfree(entry);
+   for_each_pci_segment_safe(pci_seg, p) {
+   list_for_each_entry_safe(entry, next, _seg->unity_map, 
list) {
+   list_del(>list);
+   kfree(entry);
+   }
}
 }
 
@@ -2408,8 +2411,13 @@ static void __init free_unity_maps(void)
 static int __init init_unity_map_range(struct ivmd_header *m)
 {
struct unity_map_entry *e = NULL;
+   struct amd_iommu_pci_seg *pci_seg;
char *s;
 
+   pci_seg = get_pci_segment(m->pci_seg);
+   if (pci_seg == NULL)
+   return -ENOMEM;
+
e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL)
return -ENOMEM;
@@ -2447,14 +2455,16 @@ static int __init init_unity_map_range(struct 
ivmd_header *m)
if (m->flags & IVMD_FLAG_EXCL_RANGE)
e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1;
 
-   DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
-   " range_start: %016llx range_end: %016llx flags: %x\n", s,
+   DUMP_printk("%s devid_start: %04x:%02x:%02x.%x devid_end: "
+   "%04x:%02x:%02x.%x range_start: %016llx range_end: %016llx"
+   " flags: %x\n", s, m->pci_seg,
PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
-   PCI_FUNC(e->devid_start), PCI_BUS_NUM(e->devid_end),
+   PCI_FUNC(e->devid_start), m->pci_seg,
+   PCI_BUS_NUM(e->devid_end),
PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
e->address_start, e->address_end, m->flags);
 
-   list_add_tail(>list, _iommu_unity_map);
+   

[PATCH v3 08/35] iommu/amd: Introduce per PCI segment alias_table

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

This will replace global alias table (amd_iommu_alias_table).

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h |  7 +
 drivers/iommu/amd/init.c| 41 ++---
 drivers/iommu/amd/iommu.c   | 41 ++---
 3 files changed, 64 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index d43ce65f8e21..9534064124f9 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -576,6 +576,13 @@ struct amd_iommu_pci_seg {
 * will be copied to. It's only be used in kdump kernel.
 */
struct dev_table_entry *old_dev_tbl_cpy;
+
+   /*
+* The alias table is a driver specific data structure which contains 
the
+* mappings of the PCI device ids to the actual requestor ids on the 
IOMMU.
+* More than one device can share the same requestor id.
+*/
+   u16 *alias_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 31b19a418ee8..9d57cb05878e 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -698,6 +698,31 @@ static inline void free_irq_lookup_table(struct 
amd_iommu_pci_seg *pci_seg)
pci_seg->irq_lookup_table = NULL;
 }
 
+static int __init alloc_alias_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   int i;
+
+   pci_seg->alias_table = (void *)__get_free_pages(GFP_KERNEL,
+   
get_order(alias_table_size));
+   if (!pci_seg->alias_table)
+   return -ENOMEM;
+
+   /*
+* let all alias entries point to itself
+*/
+   for (i = 0; i <= amd_iommu_last_bdf; ++i)
+   pci_seg->alias_table[i] = i;
+
+   return 0;
+}
+
+static void __init free_alias_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   free_pages((unsigned long)pci_seg->alias_table,
+  get_order(alias_table_size));
+   pci_seg->alias_table = NULL;
+}
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
@@ -1266,6 +1291,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
u32 dev_i, ext_flags = 0;
bool alias = false;
struct ivhd_entry *e;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
u32 ivhd_size;
int ret;
 
@@ -1347,7 +1373,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
devid_to = e->ext >> 8;
set_dev_entry_from_acpi(iommu, devid   , e->flags, 0);
set_dev_entry_from_acpi(iommu, devid_to, e->flags, 0);
-   amd_iommu_alias_table[devid] = devid_to;
+   pci_seg->alias_table[devid] = devid_to;
break;
case IVHD_DEV_ALIAS_RANGE:
 
@@ -1405,7 +1431,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
devid = e->devid;
for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
if (alias) {
-   amd_iommu_alias_table[dev_i] = devid_to;
+   pci_seg->alias_table[dev_i] = devid_to;
set_dev_entry_from_acpi(iommu,
devid_to, flags, ext_flags);
}
@@ -1540,6 +1566,8 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
if (alloc_dev_table(pci_seg))
return NULL;
+   if (alloc_alias_table(pci_seg))
+   return NULL;
if (alloc_rlookup_table(pci_seg))
return NULL;
 
@@ -1566,6 +1594,7 @@ static void __init free_pci_segments(void)
list_del(_seg->list);
free_irq_lookup_table(pci_seg);
free_rlookup_table(pci_seg);
+   free_alias_table(pci_seg);
free_dev_table(pci_seg);
kfree(pci_seg);
}
@@ -2838,7 +2867,7 @@ static void __init ivinfo_init(void *ivrs)
 static int __init early_amd_iommu_init(void)
 {
struct acpi_table_header *ivrs_base;
-   int i, remap_cache_sz, ret;
+   int remap_cache_sz, ret;
acpi_status status;
 
if (!amd_iommu_detected)
@@ -2909,12 +2938,6 @@ static int __init early_amd_iommu_init(void)
if (amd_iommu_pd_alloc_bitmap == NULL)
goto out;
 
-   /*
-* let all alias entries point to itself
-*/
-   for (i = 0; i <= amd_iommu_last_bdf; ++i)
-   amd_iommu_alias_table[i] = i;
-
/*
 * never allocate domain 0 because its used as the non-allocated and
   

[PATCH v3 07/35] iommu/amd: Introduce per PCI segment old_dev_tbl_cpy

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

It will remove global old_dev_tbl_cpy. Also update copy_device_table()
copy device table for all PCI segments.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu_types.h |   6 ++
 drivers/iommu/amd/init.c| 109 
 2 files changed, 70 insertions(+), 45 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 7dac61226208..d43ce65f8e21 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -570,6 +570,12 @@ struct amd_iommu_pci_seg {
 * device id quickly.
 */
struct irq_remap_table **irq_lookup_table;
+
+   /*
+* Pointer to a device table which the content of old device table
+* will be copied to. It's only be used in kdump kernel.
+*/
+   struct dev_table_entry *old_dev_tbl_cpy;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 144835a5cf6d..31b19a418ee8 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -193,11 +193,6 @@ bool amd_iommu_force_isolation __read_mostly;
  * page table root pointer.
  */
 struct dev_table_entry *amd_iommu_dev_table;
-/*
- * Pointer to a device table which the content of old device table
- * will be copied to. It's only be used in kdump kernel.
- */
-static struct dev_table_entry *old_dev_tbl_cpy;
 
 /*
  * The alias table is a driver specific data structure which contains the
@@ -990,39 +985,27 @@ static int get_dev_entry_bit(u16 devid, u8 bit)
 }
 
 
-static bool copy_device_table(void)
+static bool __copy_device_table(struct amd_iommu *iommu)
 {
-   u64 int_ctl, int_tab_len, entry = 0, last_entry = 0;
+   u64 int_ctl, int_tab_len, entry = 0;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
struct dev_table_entry *old_devtb = NULL;
u32 lo, hi, devid, old_devtb_size;
phys_addr_t old_devtb_phys;
-   struct amd_iommu *iommu;
u16 dom_id, dte_v, irq_v;
gfp_t gfp_flag;
u64 tmp;
 
-   if (!amd_iommu_pre_enabled)
-   return false;
-
-   pr_warn("Translation is already enabled - trying to copy translation 
structures\n");
-   for_each_iommu(iommu) {
-   /* All IOMMUs should use the same device table with the same 
size */
-   lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET);
-   hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
-   entry = (((u64) hi) << 32) + lo;
-   if (last_entry && last_entry != entry) {
-   pr_err("IOMMU:%d should use the same dev table as 
others!\n",
-   iommu->index);
-   return false;
-   }
-   last_entry = entry;
+   /* Each IOMMU use separate device table with the same size */
+   lo = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET);
+   hi = readl(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET + 4);
+   entry = (((u64) hi) << 32) + lo;
 
-   old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
-   if (old_devtb_size != dev_table_size) {
-   pr_err("The device table size of IOMMU:%d is not 
expected!\n",
-   iommu->index);
-   return false;
-   }
+   old_devtb_size = ((entry & ~PAGE_MASK) + 1) << 12;
+   if (old_devtb_size != dev_table_size) {
+   pr_err("The device table size of IOMMU:%d is not expected!\n",
+   iommu->index);
+   return false;
}
 
/*
@@ -1045,31 +1028,31 @@ static bool copy_device_table(void)
return false;
 
gfp_flag = GFP_KERNEL | __GFP_ZERO | GFP_DMA32;
-   old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
-   get_order(dev_table_size));
-   if (old_dev_tbl_cpy == NULL) {
+   pci_seg->old_dev_tbl_cpy = (void *)__get_free_pages(gfp_flag,
+   get_order(dev_table_size));
+   if (pci_seg->old_dev_tbl_cpy == NULL) {
pr_err("Failed to allocate memory for copying old device 
table!\n");
memunmap(old_devtb);
return false;
}
 
for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) {
-   old_dev_tbl_cpy[devid] = old_devtb[devid];
+   pci_seg->old_dev_tbl_cpy[devid] = old_devtb[devid];
dom_id = old_devtb[devid].data[1] & DEV_DOMID_MASK;
dte_v = old_devtb[devid].data[0] & DTE_FLAG_V;
 
if (dte_v && dom_id) {
-   old_dev_tbl_cpy[devid].data[0] = 
old_devtb[devid].data[0];
-   old_dev_tbl_cpy[devid].data[1] = 
old_devtb[devid].data[1];
+   

[PATCH v3 06/35] iommu/amd: Introduce per PCI segment dev_data_list

2022-05-11 Thread Vasant Hegde via iommu
This will replace global dev_data_list.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  3 +++
 drivers/iommu/amd/init.c|  1 +
 drivers/iommu/amd/iommu.c   | 21 ++---
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 55792edfcfbe..7dac61226208 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -542,6 +542,9 @@ struct amd_iommu_pci_seg {
/* List with all PCI segments in the system */
struct list_head list;
 
+   /* List of all available dev_data structures */
+   struct llist_head dev_data_list;
+
/* PCI segment number */
u16 id;
 
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index f513591a0646..144835a5cf6d 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1525,6 +1525,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
return NULL;
 
pci_seg->id = id;
+   init_llist_head(_seg->dev_data_list);
list_add_tail(_seg->list, _iommu_pci_seg_list);
 
if (alloc_dev_table(pci_seg))
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 1590270ac54a..f0764446dea5 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -62,9 +62,6 @@
 
 static DEFINE_SPINLOCK(pd_bitmap_lock);
 
-/* List of all available dev_data structures */
-static LLIST_HEAD(dev_data_list);
-
 LIST_HEAD(ioapic_map);
 LIST_HEAD(hpet_map);
 LIST_HEAD(acpihid_map);
@@ -195,9 +192,10 @@ static struct protection_domain *to_pdomain(struct 
iommu_domain *dom)
return container_of(dom, struct protection_domain, domain);
 }
 
-static struct iommu_dev_data *alloc_dev_data(u16 devid)
+static struct iommu_dev_data *alloc_dev_data(struct amd_iommu *iommu, u16 
devid)
 {
struct iommu_dev_data *dev_data;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
if (!dev_data)
@@ -207,19 +205,20 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid)
dev_data->devid = devid;
ratelimit_default_init(_data->rs);
 
-   llist_add(_data->dev_data_list, _data_list);
+   llist_add(_data->dev_data_list, _seg->dev_data_list);
return dev_data;
 }
 
-static struct iommu_dev_data *search_dev_data(u16 devid)
+static struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 
devid)
 {
struct iommu_dev_data *dev_data;
struct llist_node *node;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
 
-   if (llist_empty(_data_list))
+   if (llist_empty(_seg->dev_data_list))
return NULL;
 
-   node = dev_data_list.first;
+   node = pci_seg->dev_data_list.first;
llist_for_each_entry(dev_data, node, dev_data_list) {
if (dev_data->devid == devid)
return dev_data;
@@ -288,10 +287,10 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
struct iommu_dev_data *dev_data;
struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
 
-   dev_data = search_dev_data(devid);
+   dev_data = search_dev_data(iommu, devid);
 
if (dev_data == NULL) {
-   dev_data = alloc_dev_data(devid);
+   dev_data = alloc_dev_data(iommu, devid);
if (!dev_data)
return NULL;
 
@@ -3464,7 +3463,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data 
*data, void *vcpu_info)
struct vcpu_data *vcpu_pi_info = pi_data->vcpu_data;
struct amd_ir_data *ir_data = data->chip_data;
struct irq_2_irte *irte_info = _data->irq_2_irte;
-   struct iommu_dev_data *dev_data = search_dev_data(irte_info->devid);
+   struct iommu_dev_data *dev_data = search_dev_data(NULL, 
irte_info->devid);
 
/* Note:
 * This device has never been set up for guest mode.
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 05/35] iommu/amd: Introduce per PCI segment irq_lookup_table

2022-05-11 Thread Vasant Hegde via iommu
This will replace global irq lookup table (irq_lookup_table).

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  6 ++
 drivers/iommu/amd/init.c| 27 +++
 2 files changed, 33 insertions(+)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index bc38bf526735..55792edfcfbe 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -561,6 +561,12 @@ struct amd_iommu_pci_seg {
 * device id.
 */
struct amd_iommu **rlookup_table;
+
+   /*
+* This table is used to find the irq remapping table for a given
+* device id quickly.
+*/
+   struct irq_remap_table **irq_lookup_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ccd5e79d64fb..f513591a0646 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -682,6 +682,26 @@ static inline void free_rlookup_table(struct 
amd_iommu_pci_seg *pci_seg)
pci_seg->rlookup_table = NULL;
 }
 
+static inline int __init alloc_irq_lookup_table(struct amd_iommu_pci_seg 
*pci_seg)
+{
+   pci_seg->irq_lookup_table = (void *)__get_free_pages(
+GFP_KERNEL | __GFP_ZERO,
+get_order(rlookup_table_size));
+   kmemleak_alloc(pci_seg->irq_lookup_table,
+  rlookup_table_size, 1, GFP_KERNEL);
+   if (pci_seg->irq_lookup_table == NULL)
+   return -ENOMEM;
+
+   return 0;
+}
+
+static inline void free_irq_lookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   kmemleak_free(pci_seg->irq_lookup_table);
+   free_pages((unsigned long)pci_seg->irq_lookup_table,
+  get_order(rlookup_table_size));
+   pci_seg->irq_lookup_table = NULL;
+}
 
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
@@ -1533,6 +1553,7 @@ static void __init free_pci_segments(void)
 
for_each_pci_segment_safe(pci_seg, next) {
list_del(_seg->list);
+   free_irq_lookup_table(pci_seg);
free_rlookup_table(pci_seg);
free_dev_table(pci_seg);
kfree(pci_seg);
@@ -2896,6 +2917,7 @@ static int __init early_amd_iommu_init(void)
amd_iommu_irq_remap = check_ioapic_information();
 
if (amd_iommu_irq_remap) {
+   struct amd_iommu_pci_seg *pci_seg;
/*
 * Interrupt remapping enabled, create kmem_cache for the
 * remapping tables.
@@ -2912,6 +2934,11 @@ static int __init early_amd_iommu_init(void)
if (!amd_iommu_irq_cache)
goto out;
 
+   for_each_pci_segment(pci_seg) {
+   if (alloc_irq_lookup_table(pci_seg))
+   goto out;
+   }
+
irq_lookup_table = (void *)__get_free_pages(
GFP_KERNEL | __GFP_ZERO,
get_order(rlookup_table_size));
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 04/35] iommu/amd: Introduce per PCI segment rlookup table

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

This will replace global rlookup table (amd_iommu_rlookup_table).
Add helper functions to set/get rlookup table for the given device.
Also add macros to get seg/devid from sbdf.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  1 +
 drivers/iommu/amd/amd_iommu_types.h | 11 
 drivers/iommu/amd/init.c| 23 +++
 drivers/iommu/amd/iommu.c   | 44 +
 4 files changed, 79 insertions(+)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 885570cd0d77..2947239700ce 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -19,6 +19,7 @@ extern int amd_iommu_init_devices(void);
 extern void amd_iommu_uninit_devices(void);
 extern void amd_iommu_init_notifier(void);
 extern int amd_iommu_init_api(void);
+extern void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);
 
 #ifdef CONFIG_AMD_IOMMU_DEBUGFS
 void amd_iommu_debugfs_setup(struct amd_iommu *iommu);
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index a850d69b2849..bc38bf526735 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -452,6 +452,9 @@ extern bool amd_iommu_irq_remap;
 /* kmem_cache to get tables with 128 byte alignement */
 extern struct kmem_cache *amd_iommu_irq_cache;
 
+#define PCI_SBDF_TO_SEGID(sbdf)(((sbdf) >> 16) & 0x)
+#define PCI_SBDF_TO_DEVID(sbdf)((sbdf) & 0x)
+
 /* Make iterating over all pci segment easier */
 #define for_each_pci_segment(pci_seg) \
list_for_each_entry((pci_seg), _iommu_pci_seg_list, list)
@@ -486,6 +489,7 @@ struct amd_iommu_fault {
 };
 
 
+struct amd_iommu;
 struct iommu_domain;
 struct irq_domain;
 struct amd_irte_ops;
@@ -550,6 +554,13 @@ struct amd_iommu_pci_seg {
 * page table root pointer.
 */
struct dev_table_entry *dev_table;
+
+   /*
+* The rlookup iommu table is used to find the IOMMU which is
+* responsible for a specific device. It is indexed by the PCI
+* device id.
+*/
+   struct amd_iommu **rlookup_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 9618bec97141..ccd5e79d64fb 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -663,6 +663,26 @@ static inline void free_dev_table(struct amd_iommu_pci_seg 
*pci_seg)
pci_seg->dev_table = NULL;
 }
 
+/* Allocate per PCI segment IOMMU rlookup table. */
+static inline int __init alloc_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   pci_seg->rlookup_table = (void *)__get_free_pages(
+   GFP_KERNEL | __GFP_ZERO,
+   get_order(rlookup_table_size));
+   if (pci_seg->rlookup_table == NULL)
+   return -ENOMEM;
+
+   return 0;
+}
+
+static inline void free_rlookup_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   free_pages((unsigned long)pci_seg->rlookup_table,
+  get_order(rlookup_table_size));
+   pci_seg->rlookup_table = NULL;
+}
+
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
@@ -1489,6 +1509,8 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
if (alloc_dev_table(pci_seg))
return NULL;
+   if (alloc_rlookup_table(pci_seg))
+   return NULL;
 
return pci_seg;
 }
@@ -1511,6 +1533,7 @@ static void __init free_pci_segments(void)
 
for_each_pci_segment_safe(pci_seg, next) {
list_del(_seg->list);
+   free_rlookup_table(pci_seg);
free_dev_table(pci_seg);
kfree(pci_seg);
}
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 54b8eb764530..1590270ac54a 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -146,6 +146,50 @@ struct dev_table_entry *get_dev_table(struct amd_iommu 
*iommu)
return dev_table;
 }
 
+static inline u16 get_device_segment(struct device *dev)
+{
+   u16 seg;
+
+   if (dev_is_pci(dev)) {
+   struct pci_dev *pdev = to_pci_dev(dev);
+
+   seg = pci_domain_nr(pdev->bus);
+   } else {
+   u32 devid = get_acpihid_device_id(dev, NULL);
+
+   seg = PCI_SBDF_TO_SEGID(devid);
+   }
+
+   return seg;
+}
+
+/* Writes the specific IOMMU for a device into the PCI segment rlookup table */
+void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid)
+{
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+   pci_seg->rlookup_table[devid] = iommu;
+}
+
+static struct amd_iommu *__rlookup_amd_iommu(u16 seg, u16 devid)
+{
+   struct 

[PATCH v3 03/35] iommu/amd: Introduce per PCI segment device table

2022-05-11 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

Introduce per PCI segment device table. All IOMMUs within the segment
will share this device table. This will replace global device
table i.e. amd_iommu_dev_table.

Also introduce helper function to get the device table for the given IOMMU.

Co-developed-by: Vasant Hegde 
Signed-off-by: Vasant Hegde 
Signed-off-by: Suravee Suthikulpanit 
---
 drivers/iommu/amd/amd_iommu.h   |  1 +
 drivers/iommu/amd/amd_iommu_types.h | 10 ++
 drivers/iommu/amd/init.c| 26 --
 drivers/iommu/amd/iommu.c   | 12 
 4 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 1ab31074f5b3..885570cd0d77 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -128,4 +128,5 @@ static inline void amd_iommu_apply_ivrs_quirks(void) { }
 
 extern void amd_iommu_domain_set_pgtable(struct protection_domain *domain,
 u64 *root, int mode);
+extern struct dev_table_entry *get_dev_table(struct amd_iommu *iommu);
 #endif
diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 7ec032afc1b2..a850d69b2849 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -540,6 +540,16 @@ struct amd_iommu_pci_seg {
 
/* PCI segment number */
u16 id;
+
+   /*
+* device table virtual address
+*
+* Pointer to the per PCI segment device table.
+* It is indexed by the PCI device id or the HT unit id and contains
+* information about the domain the device belongs to as well as the
+* page table root pointer.
+*/
+   struct dev_table_entry *dev_table;
 };
 
 /*
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 71be7ee4aa8b..9618bec97141 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -640,11 +640,29 @@ static int __init find_last_devid_acpi(struct 
acpi_table_header *table)
  *
  * The following functions belong to the code path which parses the ACPI table
  * the second time. In this ACPI parsing iteration we allocate IOMMU specific
- * data structures, initialize the device/alias/rlookup table and also
- * basically initialize the hardware.
+ * data structures, initialize the per PCI segment device/alias/rlookup table
+ * and also basically initialize the hardware.
  *
  /
 
+/* Allocate per PCI segment device table */
+static inline int __init alloc_dev_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   pci_seg->dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO | 
GFP_DMA32,
+ 
get_order(dev_table_size));
+   if (!pci_seg->dev_table)
+   return -ENOMEM;
+
+   return 0;
+}
+
+static inline void free_dev_table(struct amd_iommu_pci_seg *pci_seg)
+{
+   free_pages((unsigned long)pci_seg->dev_table,
+   get_order(dev_table_size));
+   pci_seg->dev_table = NULL;
+}
+
 /*
  * Allocates the command buffer. This buffer is per AMD IOMMU. We can
  * write commands to that buffer later and the IOMMU will execute them
@@ -1469,6 +1487,9 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
pci_seg->id = id;
list_add_tail(_seg->list, _iommu_pci_seg_list);
 
+   if (alloc_dev_table(pci_seg))
+   return NULL;
+
return pci_seg;
 }
 
@@ -1490,6 +1511,7 @@ static void __init free_pci_segments(void)
 
for_each_pci_segment_safe(pci_seg, next) {
list_del(_seg->list);
+   free_dev_table(pci_seg);
kfree(pci_seg);
}
 }
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index cf57ffcc8d54..54b8eb764530 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -134,6 +134,18 @@ static inline int get_device_id(struct device *dev)
return devid;
 }
 
+struct dev_table_entry *get_dev_table(struct amd_iommu *iommu)
+{
+   struct dev_table_entry *dev_table;
+   struct amd_iommu_pci_seg *pci_seg = iommu->pci_seg;
+
+   BUG_ON(pci_seg == NULL);
+   dev_table = pci_seg->dev_table;
+   BUG_ON(dev_table == NULL);
+
+   return dev_table;
+}
+
 static struct protection_domain *to_pdomain(struct iommu_domain *dom)
 {
return container_of(dom, struct protection_domain, domain);
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 02/35] iommu/amd: Introduce pci segment structure

2022-05-11 Thread Vasant Hegde via iommu
Newer AMD systems can support multiple PCI segments, where each segment
contains one or more IOMMU instances. However, an IOMMU instance can only
support a single PCI segment.

Current code assumes that system contains only one pci segment (segment 0)
and creates global data structures such as device table, rlookup table,
etc.

Introducing per PCI segment data structure, which contains segment
specific data structures. This will eventually replace the global
data structures.

Also update `amd_iommu->pci_seg` variable to point to PCI segment
structure instead of PCI segment ID.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 24 ++-
 drivers/iommu/amd/init.c| 46 -
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 06235b7cb13d..7ec032afc1b2 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -452,6 +452,11 @@ extern bool amd_iommu_irq_remap;
 /* kmem_cache to get tables with 128 byte alignement */
 extern struct kmem_cache *amd_iommu_irq_cache;
 
+/* Make iterating over all pci segment easier */
+#define for_each_pci_segment(pci_seg) \
+   list_for_each_entry((pci_seg), _iommu_pci_seg_list, list)
+#define for_each_pci_segment_safe(pci_seg, next) \
+   list_for_each_entry_safe((pci_seg), (next), _iommu_pci_seg_list, 
list)
 /*
  * Make iterating over all IOMMUs easier
  */
@@ -526,6 +531,17 @@ struct protection_domain {
unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
 };
 
+/*
+ * This structure contains information about one PCI segment in the system.
+ */
+struct amd_iommu_pci_seg {
+   /* List with all PCI segments in the system */
+   struct list_head list;
+
+   /* PCI segment number */
+   u16 id;
+};
+
 /*
  * Structure where we save information about one hardware AMD IOMMU in the
  * system.
@@ -577,7 +593,7 @@ struct amd_iommu {
u16 cap_ptr;
 
/* pci domain of this IOMMU */
-   u16 pci_seg;
+   struct amd_iommu_pci_seg *pci_seg;
 
/* start of exclusion range of that IOMMU */
u64 exclusion_start;
@@ -705,6 +721,12 @@ extern struct list_head ioapic_map;
 extern struct list_head hpet_map;
 extern struct list_head acpihid_map;
 
+/*
+ * List with all PCI segments in the system. This list is not locked because
+ * it is only written at driver initialization time
+ */
+extern struct list_head amd_iommu_pci_seg_list;
+
 /*
  * List with all IOMMUs in the system. This list is not locked because it is
  * only written and read at driver initialization or suspend time
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index b4a798c7b347..71be7ee4aa8b 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -165,6 +165,7 @@ u16 amd_iommu_last_bdf; /* largest PCI 
device id we have
 LIST_HEAD(amd_iommu_unity_map);/* a list of required unity 
mappings
   we find in ACPI */
 
+LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the
   system */
 
@@ -1456,6 +1457,43 @@ static int __init init_iommu_from_acpi(struct amd_iommu 
*iommu,
return 0;
 }
 
+/* Allocate PCI segment data structure */
+static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
+{
+   struct amd_iommu_pci_seg *pci_seg;
+
+   pci_seg = kzalloc(sizeof(struct amd_iommu_pci_seg), GFP_KERNEL);
+   if (pci_seg == NULL)
+   return NULL;
+
+   pci_seg->id = id;
+   list_add_tail(_seg->list, _iommu_pci_seg_list);
+
+   return pci_seg;
+}
+
+static struct amd_iommu_pci_seg *__init get_pci_segment(u16 id)
+{
+   struct amd_iommu_pci_seg *pci_seg;
+
+   for_each_pci_segment(pci_seg) {
+   if (pci_seg->id == id)
+   return pci_seg;
+   }
+
+   return alloc_pci_segment(id);
+}
+
+static void __init free_pci_segments(void)
+{
+   struct amd_iommu_pci_seg *pci_seg, *next;
+
+   for_each_pci_segment_safe(pci_seg, next) {
+   list_del(_seg->list);
+   kfree(pci_seg);
+   }
+}
+
 static void __init free_iommu_one(struct amd_iommu *iommu)
 {
free_cwwb_sem(iommu);
@@ -1542,8 +1580,14 @@ static void amd_iommu_ats_write_check_workaround(struct 
amd_iommu *iommu)
  */
 static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header 
*h)
 {
+   struct amd_iommu_pci_seg *pci_seg;
int ret;
 
+   pci_seg = get_pci_segment(h->pci_seg);
+   if (pci_seg == NULL)
+   return -ENOMEM;
+   iommu->pci_seg = pci_seg;
+
raw_spin_lock_init(>lock);
iommu->cmd_sem_val = 0;
 
@@ 

[PATCH v3 01/35] iommu/amd: Update struct iommu_dev_data definition

2022-05-11 Thread Vasant Hegde via iommu
struct iommu_dev_data contains member "pdev" to point to pci_dev. This is
valid for only PCI devices and for other devices this will be NULL. This
causes unnecessary "pdev != NULL" check at various places.

Replace "struct pci_dev" member with "struct device" and use to_pci_dev()
to get pci device reference as needed. Also adjust setup_aliases() and
clone_aliases() function.

No functional change intended.

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h |  2 +-
 drivers/iommu/amd/iommu.c   | 32 +
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index 47108ed44fbb..06235b7cb13d 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -685,7 +685,7 @@ struct iommu_dev_data {
struct list_head list;/* For domain->dev_list */
struct llist_node dev_data_list;  /* For global dev_data_list */
struct protection_domain *domain; /* Domain the device is bound to */
-   struct pci_dev *pdev;
+   struct device *dev;
u16 devid;/* PCI Device ID */
bool iommu_v2;/* Device can make use of IOMMUv2 */
struct {
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index a1ada7bff44e..cf57ffcc8d54 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -188,10 +188,13 @@ static int clone_alias(struct pci_dev *pdev, u16 alias, 
void *data)
return 0;
 }
 
-static void clone_aliases(struct pci_dev *pdev)
+static void clone_aliases(struct device *dev)
 {
-   if (!pdev)
+   struct pci_dev *pdev;
+
+   if (!dev_is_pci(dev))
return;
+   pdev = to_pci_dev(dev);
 
/*
 * The IVRS alias stored in the alias table may not be
@@ -203,14 +206,14 @@ static void clone_aliases(struct pci_dev *pdev)
pci_for_each_dma_alias(pdev, clone_alias, NULL);
 }
 
-static struct pci_dev *setup_aliases(struct device *dev)
+static void setup_aliases(struct device *dev)
 {
struct pci_dev *pdev = to_pci_dev(dev);
u16 ivrs_alias;
 
/* For ACPI HID devices, there are no aliases */
if (!dev_is_pci(dev))
-   return NULL;
+   return;
 
/*
 * Add the IVRS alias to the pci aliases if it is on the same
@@ -221,9 +224,7 @@ static struct pci_dev *setup_aliases(struct device *dev)
PCI_BUS_NUM(ivrs_alias) == pdev->bus->number)
pci_add_dma_alias(pdev, ivrs_alias & 0xff, 1);
 
-   clone_aliases(pdev);
-
-   return pdev;
+   clone_aliases(dev);
 }
 
 static struct iommu_dev_data *find_dev_data(u16 devid)
@@ -331,7 +332,8 @@ static int iommu_init_device(struct device *dev)
if (!dev_data)
return -ENOMEM;
 
-   dev_data->pdev = setup_aliases(dev);
+   dev_data->dev = dev;
+   setup_aliases(dev);
 
/*
 * By default we use passthrough mode for IOMMUv2 capable device.
@@ -1232,13 +1234,17 @@ static int device_flush_dte_alias(struct pci_dev *pdev, 
u16 alias, void *data)
 static int device_flush_dte(struct iommu_dev_data *dev_data)
 {
struct amd_iommu *iommu;
+   struct pci_dev *pdev = NULL;
u16 alias;
int ret;
 
iommu = amd_iommu_rlookup_table[dev_data->devid];
 
-   if (dev_data->pdev)
-   ret = pci_for_each_dma_alias(dev_data->pdev,
+   if (dev_is_pci(dev_data->dev))
+   pdev = to_pci_dev(dev_data->dev);
+
+   if (pdev)
+   ret = pci_for_each_dma_alias(pdev,
 device_flush_dte_alias, iommu);
else
ret = iommu_flush_dte(iommu, dev_data->devid);
@@ -1561,7 +1567,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
/* Update device table */
set_dte_entry(dev_data->devid, domain,
  ats, dev_data->iommu_v2);
-   clone_aliases(dev_data->pdev);
+   clone_aliases(dev_data->dev);
 
device_flush_dte(dev_data);
 }
@@ -1577,7 +1583,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
dev_data->domain = NULL;
list_del(_data->list);
clear_dte_entry(dev_data->devid);
-   clone_aliases(dev_data->pdev);
+   clone_aliases(dev_data->dev);
 
/* Flush the DTE entry */
device_flush_dte(dev_data);
@@ -1818,7 +1824,7 @@ static void update_device_table(struct protection_domain 
*domain)
list_for_each_entry(dev_data, >dev_list, list) {
set_dte_entry(dev_data->devid, domain,
  dev_data->ats.enabled, dev_data->iommu_v2);
-   clone_aliases(dev_data->pdev);
+   clone_aliases(dev_data->dev);
}
 }
 
-- 
2.27.0


[PATCH v3 00/35] iommu/amd: Add multiple PCI segments support

2022-05-11 Thread Vasant Hegde via iommu
Newer AMD systems can support multiple PCI segments, where each segment
contains one or more IOMMU instances. However, an IOMMU instance can only
support a single PCI segment.

Current code assumes a system contains only one PCI segment (segment 0)
and creates global data structures such as device table, rlookup table,
etc.

This series introduces per-PCI-segment data structure, which contains
device table, alias table, etc. For each PCI segment, all IOMMUs
share the same data structure. The series also makes necessary code
adjustment and logging enhancements. Finally it removes global data
structures like device table, alias table, etc.

In case of system w/ single PCI segment (e.g. PCI segment ID is zero),
IOMMU driver allocates one PCI segment data structure, which will
be shared by all IOMMUs.

Patch 1 updates struct iommu_dev_data definition.

Patch 2 - 13 introduce new PCI segment structure and allocate per
data structures, and introduce the amd_iommu.pci_seg pointer to point
to the corresponded pci_segment structure. Also, we have introduced
a helper function rlookup_amd_iommu() to reverse-lookup each iommu
for a particular device.

Patch 14 - 27 adopt to per PCI segment data structure and removes
global data structure.

Patch 28 fixes flushing logic to flush upto last_bdf.

Patch 29 - 35 convert usages of 16-bit PCI device ID to include
16-bit segment ID.

Changes from v2 -> v3:
  - Addressed Joerg's review comments
- Fixed typo in patch 1 subject
- Fixed few minor things in patch 2
- Merged patch 27 - 29 into one patch
- Added new macros to get seg and devid from sbdf
  - Patch 32 : Extend devid to 32bit and added new macro.

v2 patchset : 
https://lore.kernel.org/linux-iommu/20220425113415.24087-1-vasant.he...@amd.com/T/#t

Changes from v1 -> v2:
  - Updated patch 1 to include dev_is_pci() check

v1 patchset : 
https://lore.kernel.org/linux-iommu/20220404100023.324645-1-vasant.he...@amd.com/T/#t

Changes from RFC -> v1:
  - Rebased patches on top of iommu/next tree.
  - Update struct iommu_dev_data definition
  - Updated few log message to print segment ID
  - Fix smatch warnings

RFC patchset : 
https://lore.kernel.org/linux-iommu/20220311094854.31595-1-vasant.he...@amd.com/T/#t


Regards,
Vasant

Suravee Suthikulpanit (20):
  iommu/amd: Introduce per PCI segment device table
  iommu/amd: Introduce per PCI segment rlookup table
  iommu/amd: Introduce per PCI segment old_dev_tbl_cpy
  iommu/amd: Introduce per PCI segment alias_table
  iommu/amd: Convert to use rlookup_amd_iommu helper function
  iommu/amd: Update irq_remapping_alloc to use IOMMU lookup helper function
  iommu/amd: Introduce struct amd_ir_data.iommu
  iommu/amd: Update amd_irte_ops functions
  iommu/amd: Update alloc_irq_table and alloc_irq_index
  iommu/amd: Update set_dte_entry and clear_dte_entry
  iommu/amd: Update iommu_ignore_device
  iommu/amd: Update dump_dte_entry
  iommu/amd: Update set_dte_irq_entry
  iommu/amd: Update (un)init_device_table_dma()
  iommu/amd: Update set_dev_entry_bit() and get_dev_entry_bit()
  iommu/amd: Remove global amd_iommu_[dev_table/alias_table/last_bdf]
  iommu/amd: Introduce get_device_sbdf_id() helper function
  iommu/amd: Include PCI segment ID when initialize IOMMU
  iommu/amd: Specify PCI segment ID when getting pci device
  iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] commands

Vasant Hegde (15):
  iommu/amd: Update struct iommu_dev_data definition
  iommu/amd: Introduce pci segment structure
  iommu/amd: Introduce per PCI segment irq_lookup_table
  iommu/amd: Introduce per PCI segment dev_data_list
  iommu/amd: Introduce per PCI segment unity map list
  iommu/amd: Introduce per PCI segment last_bdf
  iommu/amd: Introduce per PCI segment device table size
  iommu/amd: Introduce per PCI segment alias table size
  iommu/amd: Introduce per PCI segment rlookup table size
  iommu/amd: Convert to use per PCI segment irq_lookup_table
  iommu/amd: Convert to use per PCI segment rlookup_table
  iommu/amd: Flush upto last_bdf only
  iommu/amd: Print PCI segment ID in error log messages
  iommu/amd: Update device_state structure to include PCI seg ID
  iommu/amd: Update amd_iommu_fault structure to include PCI seg ID

 .../admin-guide/kernel-parameters.txt |  34 +-
 drivers/iommu/amd/amd_iommu.h |  13 +-
 drivers/iommu/amd/amd_iommu_types.h   | 133 +++-
 drivers/iommu/amd/init.c  | 687 +++---
 drivers/iommu/amd/iommu.c | 563 --
 drivers/iommu/amd/iommu_v2.c  |  67 +-
 drivers/iommu/amd/quirks.c|   4 +-
 7 files changed, 904 insertions(+), 597 deletions(-)

-- 
2.27.0
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 10/37] iommu/amd: Introduce per PCI segment last_bdf

2022-05-05 Thread Vasant Hegde via iommu
Hi Joerg,


On 5/2/2022 4:24 PM, Joerg Roedel wrote:
> Hi Vasant,
> 
> On Fri, Apr 29, 2022 at 08:15:49PM +0530, Vasant Hegde wrote:
>> We still need to parse IVHD to find max devices supported by each PCI segment
>> (same as the way its doing it today). Hence we need all these variables.
> 
> From what I have seen since a few years the IVRS tables enumerate the
> whole PCI segment, up to device ff:1f.7. This results in the maximum
> being allocated for all data structures anyway. Therefore we can
> probably think about skipping the scan to find the largest bdf and just
> assume it is ff:1f.7, saving us all the size-tracking variables?

With PCI segment, I think we will have segments with less than ff:1f:7.
Hence we need these variables.

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 10/37] iommu/amd: Introduce per PCI segment last_bdf

2022-04-29 Thread Vasant Hegde via iommu
Joerg,


On 4/28/2022 3:40 PM, Joerg Roedel wrote:
> On Mon, Apr 25, 2022 at 05:03:48PM +0530, Vasant Hegde wrote:
>> +/* Largest PCI device id we expect translation requests for */
>> +u16 last_bdf;
> 
> How does the IVRS table look like on these systems? Do they still
> enumerate the whole PCI Bus/Dev/Fn space? If so I am fine with getting
> rid of last_bdf alltogether and just allocate the data structures with
> their maximum size.
> 

We still need to parse IVHD to find max devices supported by each PCI segment
(same as the way its doing it today). Hence we need all these variables.


-Vasant
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 02/37] iommu/amd: Introduce pci segment structure

2022-04-29 Thread Vasant Hegde via iommu
Joerg,

On 4/28/2022 3:24 PM, Joerg Roedel wrote:
> Hi Vasant,
> 
> On Mon, Apr 25, 2022 at 05:03:40PM +0530, Vasant Hegde wrote:
>> +/*
>> + * This structure contains information about one PCI segment in the system.
>> + */
>> +struct amd_iommu_pci_seg {
>> +struct list_head list;
> 
> The purpose of this list_head needs a comment.

Sure.

> 
>> +
>> +/* PCI segment number */
>> +u16 id;
>> +};
>> +/*
>> + * List with all PCI segments in the system. This list is not locked because
>> + * it is only written at driver initialization time
>> + */
>> +extern struct list_head amd_iommu_pci_seg_list;
> 
> So there will never be hotplug of a PCI segment? Say together with
> hotplugging a CPU?

As I understood currently we don't support hotplugging.

> 
>> +static void __init free_pci_segment(void)
> 
> This needs plural: free_pci_segments(), as it frees all segments.
> 

Sure. Will fix it in v3.

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 27/37] iommu/amd: Remove global amd_iommu_dev_table

2022-04-29 Thread Vasant Hegde via iommu



On 4/28/2022 3:45 PM, Joerg Roedel wrote:
> On Mon, Apr 25, 2022 at 05:04:05PM +0530, Vasant Hegde wrote:
>> From: Suravee Suthikulpanit 
>>
>> Replace global amd_iommu_dev_table with per PCI segment device table.
>> Also remove "dev_table_size".
>>
>> Co-developed-by: Vasant Hegde 
>> Signed-off-by: Vasant Hegde 
>> Signed-off-by: Suravee Suthikulpanit 
> 
> Patches 27-29 can be merged into one.
> 

Yeah. We can merge them into one. It will become slightly bigger change in one
patch. But these are related changes. So I guess that's fine.

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 37/37] iommu/amd: Update amd_iommu_fault structure to include PCI seg ID

2022-04-29 Thread Vasant Hegde via iommu


Joerg,

On 4/28/2022 3:49 PM, Joerg Roedel wrote:
> On Mon, Apr 25, 2022 at 05:04:15PM +0530, Vasant Hegde wrote:
>> +seg_id = (iommu_fault->sbdf >> 16) & 0x;
>> +devid = iommu_fault->sbdf & 0x;
> 
> This deserves some macros for readability.

Sure. Will add macros in next version.

-Vasant
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 00/37] iommu/amd: Add multiple PCI segments support

2022-04-29 Thread Vasant Hegde via iommu
Joerg,

On 4/28/2022 3:52 PM, Joerg Roedel wrote:
> Hi Vasant, Hi Suravee,
> 
> On Mon, Apr 25, 2022 at 05:03:38PM +0530, Vasant Hegde wrote:
>> Newer AMD systems can support multiple PCI segments, where each segment
>> contains one or more IOMMU instances. However, an IOMMU instance can only
>> support a single PCI segment.
> 
> Thanks for doing this, making the AMD IOMMU driver multi-segment aware
> has been on my todo list for a while too. Overall the series looks good
> to me, just some minor comments to some patches.

Thanks for the review. Will address review comments in v3.

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v2 01/37] iommu/amd: Update struct iommu_dev_data defination

2022-04-29 Thread Vasant Hegde via iommu
Joerg,


On 4/28/2022 3:25 PM, Joerg Roedel wrote:
> On Mon, Apr 25, 2022 at 05:03:39PM +0530, Vasant Hegde wrote:
> 
> Subject: iommu/amd: Update struct iommu_dev_data defination
>  ^^ Typo
> 

Thanks for the review. Will fix it in v3.

-Vasant
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] iommu/amd: Set translation valid bit only when IO page tables are in used

2022-04-28 Thread Vasant Hegde via iommu
On 4/20/2022 4:59 PM, Suravee Suthikulpanit via iommu wrote:
> On AMD system with SNP enabled, IOMMU hardware checks the host translation
> valid (TV) and guest translation valid (GV) bits in the device
> table entry (DTE) before accessing the corresponded page tables.
> 
> However, current IOMMU driver sets the TV bit for all devices
> regardless of whether the host page table is in used.
> This results in ILLEGAL_DEV_TABLE_ENTRY event for devices, which
> do not the host page table root pointer set up.
> 
> Thefore, only set TV bit when host or guest page tables are in used.
> 
> Signed-off-by: Suravee Suthikulpanit 

Looks good to me.

Reviewed-by: Vasant Hegde 

-Vasant

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 37/37] iommu/amd: Update amd_iommu_fault structure to include PCI seg ID

2022-04-25 Thread Vasant Hegde via iommu
Rename 'device_id' as 'sbdf' and extend it to 32bit so that we can
pass PCI segment ID to ppr_notifier(). Also pass PCI segment ID to
pci_get_domain_bus_and_slot() instead of default value.

Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/amd_iommu_types.h | 2 +-
 drivers/iommu/amd/iommu.c   | 2 +-
 drivers/iommu/amd/iommu_v2.c| 9 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index f2bbcb19e92c..a908f18a3632 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -477,7 +477,7 @@ extern struct kmem_cache *amd_iommu_irq_cache;
 struct amd_iommu_fault {
u64 address;/* IO virtual address of the fault*/
u32 pasid;  /* Address space identifier */
-   u16 device_id;  /* Originating PCI device id */
+   u32 sbdf;   /* Originating PCI device id */
u16 tag;/* PPR tag */
u16 flags;  /* Fault flags */
 
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 47946894aff3..5f48cddeaa29 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -701,7 +701,7 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, 
u64 *raw)
 
fault.address   = raw[1];
fault.pasid = PPR_PASID(raw[0]);
-   fault.device_id = PPR_DEVID(raw[0]);
+   fault.sbdf  = (iommu->pci_seg->id << 16) | PPR_DEVID(raw[0]);
fault.tag   = PPR_TAG(raw[0]);
fault.flags = PPR_FLAGS(raw[0]);
 
diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index b186d6e0..631ded8168ff 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -518,15 +518,16 @@ static int ppr_notifier(struct notifier_block *nb, 
unsigned long e, void *data)
unsigned long flags;
struct fault *fault;
bool finish;
-   u16 tag, devid;
+   u16 tag, devid, seg_id;
int ret;
 
iommu_fault = data;
tag = iommu_fault->tag & 0x1ff;
finish  = (iommu_fault->tag >> 9) & 1;
 
-   devid = iommu_fault->device_id;
-   pdev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(devid),
+   seg_id = (iommu_fault->sbdf >> 16) & 0x;
+   devid = iommu_fault->sbdf & 0x;
+   pdev = pci_get_domain_bus_and_slot(seg_id, PCI_BUS_NUM(devid),
   devid & 0xff);
if (!pdev)
return -ENODEV;
@@ -540,7 +541,7 @@ static int ppr_notifier(struct notifier_block *nb, unsigned 
long e, void *data)
goto out;
}
 
-   dev_state = get_device_state(iommu_fault->device_id);
+   dev_state = get_device_state(iommu_fault->sbdf);
if (dev_state == NULL)
goto out;
 
-- 
2.27.0

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v2 36/37] iommu/amd: Update device_state structure to include PCI seg ID

2022-04-25 Thread Vasant Hegde via iommu
Rename struct device_state.devid variable to struct device_state.sbdf
and extend it to 32-bit to include the 16-bit PCI segment ID via
the helper function get_pci_sbdf_id().

Co-developed-by: Suravee Suthikulpanit 
Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/iommu_v2.c | 58 +++-
 1 file changed, 24 insertions(+), 34 deletions(-)

diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index e56b137ceabd..b186d6e0 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -51,7 +51,7 @@ struct pasid_state {
 
 struct device_state {
struct list_head list;
-   u16 devid;
+   u32 sbdf;
atomic_t count;
struct pci_dev *pdev;
struct pasid_state **states;
@@ -83,35 +83,25 @@ static struct workqueue_struct *iommu_wq;
 
 static void free_pasid_states(struct device_state *dev_state);
 
-static u16 device_id(struct pci_dev *pdev)
-{
-   u16 devid;
-
-   devid = pdev->bus->number;
-   devid = (devid << 8) | pdev->devfn;
-
-   return devid;
-}
-
-static struct device_state *__get_device_state(u16 devid)
+static struct device_state *__get_device_state(u32 sbdf)
 {
struct device_state *dev_state;
 
list_for_each_entry(dev_state, _list, list) {
-   if (dev_state->devid == devid)
+   if (dev_state->sbdf == sbdf)
return dev_state;
}
 
return NULL;
 }
 
-static struct device_state *get_device_state(u16 devid)
+static struct device_state *get_device_state(u32 sbdf)
 {
struct device_state *dev_state;
unsigned long flags;
 
spin_lock_irqsave(_lock, flags);
-   dev_state = __get_device_state(devid);
+   dev_state = __get_device_state(sbdf);
if (dev_state != NULL)
atomic_inc(_state->count);
spin_unlock_irqrestore(_lock, flags);
@@ -609,7 +599,7 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
struct pasid_state *pasid_state;
struct device_state *dev_state;
struct mm_struct *mm;
-   u16 devid;
+   u32 sbdf;
int ret;
 
might_sleep();
@@ -617,8 +607,8 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
if (!amd_iommu_v2_supported())
return -ENODEV;
 
-   devid = device_id(pdev);
-   dev_state = get_device_state(devid);
+   sbdf  = get_pci_sbdf_id(pdev);
+   dev_state = get_device_state(sbdf);
 
if (dev_state == NULL)
return -EINVAL;
@@ -692,15 +682,15 @@ void amd_iommu_unbind_pasid(struct pci_dev *pdev, u32 
pasid)
 {
struct pasid_state *pasid_state;
struct device_state *dev_state;
-   u16 devid;
+   u32 sbdf;
 
might_sleep();
 
if (!amd_iommu_v2_supported())
return;
 
-   devid = device_id(pdev);
-   dev_state = get_device_state(devid);
+   sbdf = get_pci_sbdf_id(pdev);
+   dev_state = get_device_state(sbdf);
if (dev_state == NULL)
return;
 
@@ -742,7 +732,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
struct iommu_group *group;
unsigned long flags;
int ret, tmp;
-   u16 devid;
+   u32 sbdf;
 
might_sleep();
 
@@ -759,7 +749,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
if (pasids <= 0 || pasids > (PASID_MASK + 1))
return -EINVAL;
 
-   devid = device_id(pdev);
+   sbdf = get_pci_sbdf_id(pdev);
 
dev_state = kzalloc(sizeof(*dev_state), GFP_KERNEL);
if (dev_state == NULL)
@@ -768,7 +758,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
spin_lock_init(_state->lock);
init_waitqueue_head(_state->wq);
dev_state->pdev  = pdev;
-   dev_state->devid = devid;
+   dev_state->sbdf = sbdf;
 
tmp = pasids;
for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9)
@@ -806,7 +796,7 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 
spin_lock_irqsave(_lock, flags);
 
-   if (__get_device_state(devid) != NULL) {
+   if (__get_device_state(sbdf) != NULL) {
spin_unlock_irqrestore(_lock, flags);
ret = -EBUSY;
goto out_free_domain;
@@ -838,16 +828,16 @@ void amd_iommu_free_device(struct pci_dev *pdev)
 {
struct device_state *dev_state;
unsigned long flags;
-   u16 devid;
+   u32 sbdf;
 
if (!amd_iommu_v2_supported())
return;
 
-   devid = device_id(pdev);
+   sbdf = get_pci_sbdf_id(pdev);
 
spin_lock_irqsave(_lock, flags);
 
-   dev_state = __get_device_state(devid);
+   dev_state = __get_device_state(sbdf);
if (dev_state == NULL) {
spin_unlock_irqrestore(_lock, flags);
return;
@@ -867,18 +857,18 @@ int 

[PATCH v2 35/37] iommu/amd: Print PCI segment ID in error log messages

2022-04-25 Thread Vasant Hegde via iommu
Print pci segment ID along with bdf. Useful for debugging.

Co-developed-by: Suravee Suthikulpaint 
Signed-off-by: Suravee Suthikulpaint 
Signed-off-by: Vasant Hegde 
---
 drivers/iommu/amd/init.c  | 10 +-
 drivers/iommu/amd/iommu.c | 36 ++--
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ba0ef8192a2f..24814ec3dca8 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -1850,11 +1850,11 @@ static int __init init_iommu_all(struct 
acpi_table_header *table)
h = (struct ivhd_header *)p;
if (*p == amd_iommu_target_ivhd_type) {
 
-   DUMP_printk("device: %02x:%02x.%01x cap: %04x "
-   "seg: %d flags: %01x info %04x\n",
-   PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
-   PCI_FUNC(h->devid), h->cap_ptr,
-   h->pci_seg, h->flags, h->info);
+   DUMP_printk("device: %04x:%02x:%02x.%01x cap: %04x "
+   "flags: %01x info %04x\n",
+   h->pci_seg, PCI_BUS_NUM(h->devid),
+   PCI_SLOT(h->devid), PCI_FUNC(h->devid),
+   h->cap_ptr, h->flags, h->info);
DUMP_printk("   mmio-addr: %016llx\n",
h->mmio_phys);
 
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 46236fb05a1f..47946894aff3 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -496,8 +496,8 @@ static void amd_iommu_report_rmp_hw_error(struct amd_iommu 
*iommu, volatile u32
vmg_tag, spa, flags);
}
} else {
-   pr_err_ratelimited("Event logged [RMP_HW_ERROR 
device=%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [RMP_HW_ERROR 
device=%04x:%02x:%02x.%x, vmg_tag=0x%04x, spa=0x%llx, flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
vmg_tag, spa, flags);
}
 
@@ -529,8 +529,8 @@ static void amd_iommu_report_rmp_fault(struct amd_iommu 
*iommu, volatile u32 *ev
vmg_tag, gpa, flags_rmp, flags);
}
} else {
-   pr_err_ratelimited("Event logged [RMP_PAGE_FAULT 
device=%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, 
flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [RMP_PAGE_FAULT 
device=%04x:%02x:%02x.%x, vmg_tag=0x%04x, gpa=0x%llx, flags_rmp=0x%04x, 
flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
vmg_tag, gpa, flags_rmp, flags);
}
 
@@ -576,8 +576,8 @@ static void amd_iommu_report_page_fault(struct amd_iommu 
*iommu,
domain_id, address, flags);
}
} else {
-   pr_err_ratelimited("Event logged [IO_PAGE_FAULT 
device=%02x:%02x.%x domain=0x%04x address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   pr_err_ratelimited("Event logged [IO_PAGE_FAULT 
device=%04x:%02x:%02x.%x domain=0x%04x address=0x%llx flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
domain_id, address, flags);
}
 
@@ -620,20 +620,20 @@ static void iommu_print_event(struct amd_iommu *iommu, 
void *__evt)
 
switch (type) {
case EVENT_TYPE_ILL_DEV:
-   dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   dev_err(dev, "Event logged [ILLEGAL_DEV_TABLE_ENTRY 
device=%04x:%02x:%02x.%x pasid=0x%05x address=0x%llx flags=0x%04x]\n",
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 
PCI_SLOT(devid), PCI_FUNC(devid),
pasid, address, flags);
dump_dte_entry(iommu, devid);
break;
case EVENT_TYPE_DEV_TAB_ERR:
-   dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%02x:%02x.%x "
+   dev_err(dev, "Event logged [DEV_TAB_HARDWARE_ERROR 
device=%04x:%02x:%02x.%x "
"address=0x%llx flags=0x%04x]\n",
-   PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+   iommu->pci_seg->id, PCI_BUS_NUM(devid), 

[PATCH v2 34/37] iommu/amd: Add PCI segment support for ivrs_ioapic, ivrs_hpet, ivrs_acpihid commands

2022-04-25 Thread Vasant Hegde via iommu
From: Suravee Suthikulpanit 

By default, PCI segment is zero and can be omitted. To support system
with non-zero PCI segment ID, modify the parsing functions to allow
PCI segment ID.

Signed-off-by: Suravee Suthikulpanit 
Signed-off-by: Vasant Hegde 
---
 .../admin-guide/kernel-parameters.txt | 34 +++
 drivers/iommu/amd/init.c  | 41 ---
 2 files changed, 51 insertions(+), 24 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt 
b/Documentation/admin-guide/kernel-parameters.txt
index f5a27f067db9..cc8f0c82ff55 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2208,23 +2208,39 @@
 
ivrs_ioapic [HW,X86-64]
Provide an override to the IOAPIC-ID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map IOAPIC-ID decimal 10 to
-   PCI device 00:14.0 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+   By default, PCI segment is 0, and can be omitted.
+   For example:
+   * To map IOAPIC-ID decimal 10 to PCI device 00:14.0
+ write the parameter as:
ivrs_ioapic[10]=00:14.0
+   * To map IOAPIC-ID decimal 10 to PCI segment 0x1 and
+ PCI device 00:14.0 write the parameter as:
+   ivrs_ioapic[10]=0001:00:14.0
 
ivrs_hpet   [HW,X86-64]
Provide an override to the HPET-ID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map HPET-ID decimal 0 to
-   PCI device 00:14.0 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+   By default, PCI segment is 0, and can be omitted.
+   For example:
+   * To map HPET-ID decimal 0 to PCI device 00:14.0
+ write the parameter as:
ivrs_hpet[0]=00:14.0
+   * To map HPET-ID decimal 10 to PCI segment 0x1 and
+ PCI device 00:14.0 write the parameter as:
+   ivrs_ioapic[10]=0001:00:14.0
 
ivrs_acpihid[HW,X86-64]
Provide an override to the ACPI-HID:UID<->DEVICE-ID
-   mapping provided in the IVRS ACPI table. For
-   example, to map UART-HID:UID AMD0020:0 to
-   PCI device 00:14.5 write the parameter as:
+   mapping provided in the IVRS ACPI table.
+
+   For example, to map UART-HID:UID AMD0020:0 to
+   PCI segment 0x1 and PCI device ID 00:14.5,
+   write the parameter as:
+   ivrs_acpihid[0001:00:14.5]=AMD0020:0
+
+   By default, PCI segment is 0, and can be omitted.
+   For example, PCI device 00:14.5 write the parameter as:
ivrs_acpihid[00:14.5]=AMD0020:0
 
js= [HW,JOY] Analog joystick
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index ccc0208d4b69..ba0ef8192a2f 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -3288,15 +3288,17 @@ static int __init parse_amd_iommu_options(char *str)
 
 static int __init parse_ivrs_ioapic(char *str)
 {
-   unsigned int bus, dev, fn;
+   u32 seg = 0, bus, dev, fn;
int ret, id, i;
u16 devid;
 
ret = sscanf(str, "[%d]=%x:%x.%x", , , , );
-
if (ret != 4) {
-   pr_err("Invalid command line: ivrs_ioapic%s\n", str);
-   return 1;
+   ret = sscanf(str, "[%d]=%x:%x:%x.%x", , , , , 
);
+   if (ret != 5) {
+   pr_err("Invalid command line: ivrs_ioapic%s\n", str);
+   return 1;
+   }
}
 
if (early_ioapic_map_size == EARLY_MAP_SIZE) {
@@ -3305,7 +3307,8 @@ static int __init parse_ivrs_ioapic(char *str)
return 1;
}
 
-   devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7);
+   devid = ((seg & 0x) << 16) | ((bus & 0xff) << 8) |
+   ((dev & 0x1f) << 3) | (fn & 0x7);
 
cmdline_maps= true;
i   = early_ioapic_map_size++;
@@ -3318,15 +3321,17 @@ static int __init parse_ivrs_ioapic(char *str)
 
 static int __init parse_ivrs_hpet(char *str)
 {
-   unsigned int bus, dev, fn;
+   u32 seg = 0, bus, dev, fn;
int ret, id, i;
u16 devid;
 
ret = sscanf(str, "[%d]=%x:%x.%x", , , , );
-
if (ret != 4) {
- 

  1   2   3   >