All of lore.kernel.org
 help / color / mirror / Atom feed
From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
To: xen-devel@lists.xen.org
Cc: boris.ostrovsky@oracle.com,
	Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>,
	jbeulich@suse.com, sherry.hurwitz@amd.com
Subject: [PATCH] AMD IOMMU: Support IOAPIC IDs larger than 128
Date: Thu, 1 Dec 2016 05:04:56 -0600	[thread overview]
Message-ID: <1480590296-2534-1-git-send-email-suravee.suthikulpanit@amd.com> (raw)

Currently, the driver uses the APIC ID to index into the ioapic_sbdf array.
The current MAX_IO_APICS is 128, which causes the driver initialization
to fail on the system with IOAPIC ID >= 128.

Instead, this patch adds APIC ID in the struct ioapic_sbdf,
which is used to match the entry when searching through the array.

Also, this patch removes the use of ioapic_cmdline bit-map, which is
used to track the ivrs_ioapic options via command line.
Instead, it introduces the cmd flag in the struct ioapic_cmdline,
to identify if the entry is created during ivrs_ioapic command-line parsing.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
 xen/drivers/passthrough/amd/iommu_acpi.c      | 80 +++++++++++++++------------
 xen/drivers/passthrough/amd/iommu_intr.c      | 65 ++++++++++++++++++----
 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h |  6 ++
 3 files changed, 105 insertions(+), 46 deletions(-)

diff --git a/xen/drivers/passthrough/amd/iommu_acpi.c b/xen/drivers/passthrough/amd/iommu_acpi.c
index b92c8ad..8c13471 100644
--- a/xen/drivers/passthrough/amd/iommu_acpi.c
+++ b/xen/drivers/passthrough/amd/iommu_acpi.c
@@ -633,26 +633,36 @@ static u16 __init parse_ivhd_device_extended_range(
     return dev_length;
 }
 
-static DECLARE_BITMAP(ioapic_cmdline, ARRAY_SIZE(ioapic_sbdf)) __initdata;
-
 static void __init parse_ivrs_ioapic(char *str)
 {
     const char *s = str;
     unsigned long id;
     unsigned int seg, bus, dev, func;
+    int idx;
 
     ASSERT(*s == '[');
     id = simple_strtoul(s + 1, &s, 0);
-    if ( id >= ARRAY_SIZE(ioapic_sbdf) || *s != ']' || *++s != '=' )
+
+    if ( *s != ']' || *++s != '=' )
+        return;
+
+    idx = ioapic_id_to_index(id);
+    /* If the entry exist, just ignore the option. */
+    if ( idx >= 0 )
         return;
 
     s = parse_pci(s + 1, &seg, &bus, &dev, &func);
     if ( !s || *s )
         return;
 
-    ioapic_sbdf[id].bdf = PCI_BDF(bus, dev, func);
-    ioapic_sbdf[id].seg = seg;
-    __set_bit(id, ioapic_cmdline);
+    idx = get_next_ioapic_bdf_index();
+    if ( idx < 0 )
+        return;
+
+    ioapic_sbdf[idx].bdf = PCI_BDF(bus, dev, func);
+    ioapic_sbdf[idx].seg = seg;
+    ioapic_sbdf[idx].id  = id;
+    ioapic_sbdf[idx].cmd  = true;
 }
 custom_param("ivrs_ioapic[", parse_ivrs_ioapic);
 
@@ -714,43 +724,36 @@ static u16 __init parse_ivhd_device_special(
          * consistency here --- whether entry's IOAPIC ID is valid and
          * whether there are conflicting/duplicated entries.
          */
-        apic = find_first_bit(ioapic_cmdline, ARRAY_SIZE(ioapic_sbdf));
-        while ( apic < ARRAY_SIZE(ioapic_sbdf) )
+        for ( apic = 0 ; apic < nr_ioapic_sbdf; apic++ )
         {
             if ( ioapic_sbdf[apic].bdf == bdf &&
                  ioapic_sbdf[apic].seg == seg )
                 break;
-            apic = find_next_bit(ioapic_cmdline, ARRAY_SIZE(ioapic_sbdf),
-                                 apic + 1);
         }
-        if ( apic < ARRAY_SIZE(ioapic_sbdf) )
+        if ( apic < nr_ioapic_sbdf )
         {
             AMD_IOMMU_DEBUG("IVHD: Command line override present for IO-APIC %#x"
                             "(IVRS: %#x devID %04x:%02x:%02x.%u)\n",
-                            apic, special->handle, seg, PCI_BUS(bdf),
-                            PCI_SLOT(bdf), PCI_FUNC(bdf));
+                            ioapic_sbdf[apic].id, special->handle, seg,
+                            PCI_BUS(bdf), PCI_SLOT(bdf), PCI_FUNC(bdf));
             break;
         }
 
         for ( apic = 0; apic < nr_ioapics; apic++ )
         {
+            int idx;
+
             if ( IO_APIC_ID(apic) != special->handle )
                 continue;
 
-            if ( special->handle >= ARRAY_SIZE(ioapic_sbdf) )
-            {
-                printk(XENLOG_ERR "IVHD Error: IO-APIC %#x entry beyond bounds\n",
-                       special->handle);
-                return 0;
-            }
-
-            if ( test_bit(special->handle, ioapic_cmdline) )
+            idx = ioapic_id_to_index(special->handle);
+            if ( idx >= 0 && ioapic_sbdf[idx].cmd )
                 AMD_IOMMU_DEBUG("IVHD: Command line override present for IO-APIC %#x\n",
                                 special->handle);
-            else if ( ioapic_sbdf[special->handle].pin_2_idx )
+            else if ( idx >= 0 && ioapic_sbdf[idx].pin_2_idx )
             {
-                if ( ioapic_sbdf[special->handle].bdf == bdf &&
-                     ioapic_sbdf[special->handle].seg == seg )
+                if ( ioapic_sbdf[idx].bdf == bdf &&
+                     ioapic_sbdf[idx].seg == seg )
                     AMD_IOMMU_DEBUG("IVHD Warning: Duplicate IO-APIC %#x entries\n",
                                     special->handle);
                 else
@@ -763,19 +766,24 @@ static u16 __init parse_ivhd_device_special(
             }
             else
             {
+                idx = get_next_ioapic_bdf_index();
+                if ( idx < 0 )
+                    return 0;
+
                 /* set device id of ioapic */
-                ioapic_sbdf[special->handle].bdf = bdf;
-                ioapic_sbdf[special->handle].seg = seg;
+                ioapic_sbdf[idx].bdf = bdf;
+                ioapic_sbdf[idx].seg = seg;
+                ioapic_sbdf[idx].id = special->handle;
 
-                ioapic_sbdf[special->handle].pin_2_idx = xmalloc_array(
+                ioapic_sbdf[idx].pin_2_idx = xmalloc_array(
                     u16, nr_ioapic_entries[apic]);
                 if ( nr_ioapic_entries[apic] &&
-                     !ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx )
+                     !ioapic_sbdf[idx].pin_2_idx )
                 {
                     printk(XENLOG_ERR "IVHD Error: Out of memory\n");
                     return 0;
                 }
-                memset(ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx, -1,
+                memset(ioapic_sbdf[idx].pin_2_idx, -1,
                        nr_ioapic_entries[apic] *
                        sizeof(*ioapic_sbdf->pin_2_idx));
             }
@@ -1028,15 +1036,15 @@ static int __init parse_ivrs_table(struct acpi_table_header *table)
         if ( !nr_ioapic_entries[apic] )
             continue;
 
-        if ( !ioapic_sbdf[IO_APIC_ID(apic)].seg &&
+        if ( !ioapic_sbdf[apic].seg &&
              /* SB IO-APIC is always on this device in AMD systems. */
-             ioapic_sbdf[IO_APIC_ID(apic)].bdf == PCI_BDF(0, 0x14, 0) )
+             ioapic_sbdf[apic].bdf == PCI_BDF(0, 0x14, 0) )
             sb_ioapic = 1;
 
-        if ( ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx )
+        if ( ioapic_sbdf[apic].pin_2_idx )
             continue;
 
-        if ( !test_bit(IO_APIC_ID(apic), ioapic_cmdline) )
+        if ( ioapic_id_to_index(IO_APIC_ID(apic)) < 0 )
         {
             printk(XENLOG_ERR "IVHD Error: no information for IO-APIC %#x\n",
                    IO_APIC_ID(apic));
@@ -1044,10 +1052,10 @@ static int __init parse_ivrs_table(struct acpi_table_header *table)
                 return -ENXIO;
         }
 
-        ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx = xmalloc_array(
+        ioapic_sbdf[apic].pin_2_idx = xmalloc_array(
             u16, nr_ioapic_entries[apic]);
-        if ( ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx )
-            memset(ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx, -1,
+        if ( ioapic_sbdf[apic].pin_2_idx )
+            memset(ioapic_sbdf[apic].pin_2_idx, -1,
                    nr_ioapic_entries[apic] * sizeof(*ioapic_sbdf->pin_2_idx));
         else
         {
diff --git a/xen/drivers/passthrough/amd/iommu_intr.c b/xen/drivers/passthrough/amd/iommu_intr.c
index 0a9f22f..438c78f 100644
--- a/xen/drivers/passthrough/amd/iommu_intr.c
+++ b/xen/drivers/passthrough/amd/iommu_intr.c
@@ -32,9 +32,36 @@ struct hpet_sbdf hpet_sbdf;
 void *shared_intremap_table;
 unsigned long *shared_intremap_inuse;
 static DEFINE_SPINLOCK(shared_intremap_lock);
+unsigned int nr_ioapic_sbdf;
 
 static void dump_intremap_tables(unsigned char key);
 
+int ioapic_id_to_index(unsigned int apic_id)
+{
+    int idx;
+
+    if ( !nr_ioapic_sbdf )
+        return -EINVAL;
+
+    for ( idx = 0 ; idx < nr_ioapic_sbdf; idx++ )
+        if ( ioapic_sbdf[idx].id == apic_id )
+            break;
+
+    if ( idx == nr_ioapic_sbdf )
+        return -EINVAL;
+
+    return idx;
+}
+
+int get_next_ioapic_bdf_index(void)
+{
+    if ( nr_ioapic_sbdf < MAX_IO_APICS )
+	    return nr_ioapic_sbdf++;
+
+    printk(XENLOG_ERR "IVHD Error: Too many IO APICs.\n");
+    return -EINVAL;
+}
+
 static spinlock_t* get_intremap_lock(int seg, int req_id)
 {
     return (amd_iommu_perdev_intremap ?
@@ -218,13 +245,19 @@ int __init amd_iommu_setup_ioapic_remapping(void)
     {
         for ( pin = 0; pin < nr_ioapic_entries[apic]; pin++ )
         {
+            int idx;
+
             rte = __ioapic_read_entry(apic, pin, 1);
             if ( rte.mask == 1 )
                 continue;
 
             /* get device id of ioapic devices */
-            bdf = ioapic_sbdf[IO_APIC_ID(apic)].bdf;
-            seg = ioapic_sbdf[IO_APIC_ID(apic)].seg;
+            idx = ioapic_id_to_index(IO_APIC_ID(apic));
+            if ( idx < 0 )
+                return -EINVAL;
+
+            bdf = ioapic_sbdf[idx].bdf;
+            seg = ioapic_sbdf[idx].seg;
             iommu = find_iommu_for_device(seg, bdf);
             if ( !iommu )
             {
@@ -250,7 +283,7 @@ int __init amd_iommu_setup_ioapic_remapping(void)
             spin_unlock_irqrestore(lock, flags);
 
             set_rte_index(&rte, offset);
-            ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx[pin] = offset;
+            ioapic_sbdf[idx].pin_2_idx[pin] = offset;
             __ioapic_write_entry(apic, pin, 1, rte);
 
             if ( iommu->enabled )
@@ -277,6 +310,7 @@ void amd_iommu_ioapic_update_ire(
     unsigned int pin = (reg - 0x10) / 2;
     int saved_mask, seg, bdf, rc;
     struct amd_iommu *iommu;
+    int idx;
 
     if ( !iommu_intremap )
     {
@@ -284,9 +318,13 @@ void amd_iommu_ioapic_update_ire(
         return;
     }
 
+    idx = ioapic_id_to_index(IO_APIC_ID(apic));
+    if ( idx < 0 )
+	return;
+
     /* get device id of ioapic devices */
-    bdf = ioapic_sbdf[IO_APIC_ID(apic)].bdf;
-    seg = ioapic_sbdf[IO_APIC_ID(apic)].seg;
+    bdf = ioapic_sbdf[idx].bdf;
+    seg = ioapic_sbdf[idx].seg;
     iommu = find_iommu_for_device(seg, bdf);
     if ( !iommu )
     {
@@ -313,7 +351,7 @@ void amd_iommu_ioapic_update_ire(
     }
 
     if ( new_rte.mask &&
-         ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx[pin] >= INTREMAP_ENTRIES )
+         ioapic_sbdf[idx].pin_2_idx[pin] >= INTREMAP_ENTRIES )
     {
         ASSERT(saved_mask);
         __io_apic_write(apic, reg, value);
@@ -330,7 +368,7 @@ void amd_iommu_ioapic_update_ire(
     /* Update interrupt remapping entry */
     rc = update_intremap_entry_from_ioapic(
              bdf, iommu, &new_rte, reg == rte_lo,
-             &ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx[pin]);
+             &ioapic_sbdf[idx].pin_2_idx[pin]);
 
     __io_apic_write(apic, reg, ((u32 *)&new_rte)[reg != rte_lo]);
 
@@ -357,14 +395,21 @@ void amd_iommu_ioapic_update_ire(
 unsigned int amd_iommu_read_ioapic_from_ire(
     unsigned int apic, unsigned int reg)
 {
+    int idx;
+    unsigned int offset;
     unsigned int val = __io_apic_read(apic, reg);
     unsigned int pin = (reg - 0x10) / 2;
-    unsigned int offset = ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx[pin];
+
+    idx = ioapic_id_to_index(IO_APIC_ID(apic));
+    if ( idx < 0 )
+	return -EINVAL;
+
+    offset = ioapic_sbdf[idx].pin_2_idx[pin];
 
     if ( !(reg & 1) && offset < INTREMAP_ENTRIES )
     {
-        u16 bdf = ioapic_sbdf[IO_APIC_ID(apic)].bdf;
-        u16 seg = ioapic_sbdf[IO_APIC_ID(apic)].seg;
+        u16 bdf = ioapic_sbdf[idx].bdf;
+        u16 seg = ioapic_sbdf[idx].seg;
         u16 req_id = get_intremap_requestor_id(seg, bdf);
         const u32 *entry = get_intremap_entry(seg, req_id, offset);
 
diff --git a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
index 6c702e8..d3db8f1 100644
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -104,8 +104,14 @@ int amd_setup_hpet_msi(struct msi_desc *msi_desc);
 extern struct ioapic_sbdf {
     u16 bdf, seg;
     u16 *pin_2_idx;
+    u8 id;
+    bool cmd;
 } ioapic_sbdf[MAX_IO_APICS];
 
+extern unsigned int nr_ioapic_sbdf;
+int ioapic_id_to_index(unsigned int apic_id);
+int get_next_ioapic_bdf_index(void);
+
 extern struct hpet_sbdf {
     u16 bdf, seg, id;
     enum {
-- 
1.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

             reply	other threads:[~2016-12-01 11:04 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-01 11:04 Suravee Suthikulpanit [this message]
2016-12-01 11:58 ` [PATCH] AMD IOMMU: Support IOAPIC IDs larger than 128 Jan Beulich
2016-12-02  3:48   ` Suravee Suthikulpanit
2016-12-02  7:45     ` Jan Beulich
2016-12-05  4:30   ` Suravee Suthikulpanit
2016-12-05  7:46     ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1480590296-2534-1-git-send-email-suravee.suthikulpanit@amd.com \
    --to=suravee.suthikulpanit@amd.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=jbeulich@suse.com \
    --cc=sherry.hurwitz@amd.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.