summaryrefslogtreecommitdiff
path: root/drivers/edac
diff options
context:
space:
mode:
authorJim Snow <jim.m.snow@intel.com>2015-12-03 10:48:53 +0100
committerBorislav Petkov <bp@suse.de>2015-12-05 18:57:41 +0100
commitc1979ba254810a710bfdc982e3d417a4a7369c31 (patch)
treefa4b28d9c91936e95b6a129e9b9117850ebff2de /drivers/edac
parentc59f9c06bdbdaeff9da107d2fcec4f46e9b10825 (diff)
EDAC, sb_edac: Add support for duplicate device IDs
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>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/sb_edac.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 2e50a3eeeac2..c8fbde2bd20a 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -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)
{