EDAC, sb_edac: Add support for duplicate device IDs
authorJim Snow <jim.m.snow@intel.com>
Thu, 3 Dec 2015 09:48:53 +0000 (10:48 +0100)
committerBorislav Petkov <bp@suse.de>
Sat, 5 Dec 2015 17:57:41 +0000 (18:57 +0100)
Add options to sbridge_get_all_devices() to allow for duplicate device
IDs and devices that are scattered across mulitple PCI buses.

Signed-off-by: Jim Snow <jim.m.snow@intel.com>
Acked-by: Tony Luck <tony.luck@intel.com>
Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: lukasz.anaczkowski@intel.com
Link: http://lkml.kernel.org/r/1449136134-23706-4-git-send-email-hubert.chrzaniuk@intel.com
[ Rebase to 4.4-rc3. ]
Signed-off-by: Hubert Chrzaniuk <hubert.chrzaniuk@intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
drivers/edac/sb_edac.c

index 2e50a3eeeac282cf22a7b8271f1cf42980cb32c1..c8fbde2bd20af0c8b66c5d96258fb78e8f8279b0 100644 (file)
@@ -637,10 +637,19 @@ static inline int numcol(u32 mtr)
        return 1 << cols;
 }
 
-static struct sbridge_dev *get_sbridge_dev(u8 bus)
+static struct sbridge_dev *get_sbridge_dev(u8 bus, int multi_bus)
 {
        struct sbridge_dev *sbridge_dev;
 
+       /*
+        * If we have devices scattered across several busses that pertain
+        * to the same memory controller, we'll lump them all together.
+        */
+       if (multi_bus) {
+               return list_first_entry_or_null(&sbridge_edac_list,
+                               struct sbridge_dev, list);
+       }
+
        list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
                if (sbridge_dev->bus == bus)
                        return sbridge_dev;
@@ -1588,7 +1597,8 @@ static void sbridge_put_all_devices(void)
 static int sbridge_get_onedevice(struct pci_dev **prev,
                                 u8 *num_mc,
                                 const struct pci_id_table *table,
-                                const unsigned devno)
+                                const unsigned devno,
+                                const int multi_bus)
 {
        struct sbridge_dev *sbridge_dev;
        const struct pci_id_descr *dev_descr = &table->descr[devno];
@@ -1624,7 +1634,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
        }
        bus = pdev->bus->number;
 
-       sbridge_dev = get_sbridge_dev(bus);
+       sbridge_dev = get_sbridge_dev(bus, multi_bus);
        if (!sbridge_dev) {
                sbridge_dev = alloc_sbridge_dev(bus, table);
                if (!sbridge_dev) {
@@ -1673,21 +1683,32 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
  * @num_mc: pointer to the memory controllers count, to be incremented in case
  *         of success.
  * @table: model specific table
+ * @allow_dups: allow for multiple devices to exist with the same device id
+ *              (as implemented, this isn't expected to work correctly in the
+ *              multi-socket case).
+ * @multi_bus: don't assume devices on different buses belong to different
+ *             memory controllers.
  *
  * returns 0 in case of success or error code
  */
-static int sbridge_get_all_devices(u8 *num_mc,
-                                  const struct pci_id_table *table)
+static int sbridge_get_all_devices_full(u8 *num_mc,
+                                       const struct pci_id_table *table,
+                                       int allow_dups,
+                                       int multi_bus)
 {
        int i, rc;
        struct pci_dev *pdev = NULL;
 
        while (table && table->descr) {
                for (i = 0; i < table->n_devs; i++) {
-                       pdev = NULL;
+                       if (!allow_dups || i == 0 ||
+                                       table->descr[i].dev_id !=
+                                               table->descr[i-1].dev_id) {
+                               pdev = NULL;
+                       }
                        do {
                                rc = sbridge_get_onedevice(&pdev, num_mc,
-                                                          table, i);
+                                                          table, i, multi_bus);
                                if (rc < 0) {
                                        if (i == 0) {
                                                i = table->n_devs;
@@ -1696,7 +1717,7 @@ static int sbridge_get_all_devices(u8 *num_mc,
                                        sbridge_put_all_devices();
                                        return -ENODEV;
                                }
-                       } while (pdev);
+                       } while (pdev && !allow_dups);
                }
                table++;
        }
@@ -1704,6 +1725,9 @@ static int sbridge_get_all_devices(u8 *num_mc,
        return 0;
 }
 
+#define sbridge_get_all_devices(num_mc, table) \
+               sbridge_get_all_devices_full(num_mc, table, 0, 0)
+
 static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
                                 struct sbridge_dev *sbridge_dev)
 {