aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2016-04-28 18:40:00 -0400
committerBorislav Petkov <bp@suse.de>2016-05-02 13:44:43 -0400
commit2c1ea4c700af3dcfc8eabd94c91d1830b42c5461 (patch)
tree1936dbdab9f678c1c9b1e9cc4524755df588a4de
parent5359534505c74841dbb2c6baf41db1a395acd34d (diff)
EDAC, sb_edac: Use cpu family/model in driver detection
Instead of picking a random PCI ID from the dozen or so we need to access, just use x86_match_cpu() to pick based on CPU model number. The choosing of PCI devices has been problematic in the past, see 11249e739929 ("sb_edac: Fix detection on SNB machines") which fixed problems introduced by d0585cd815fa ("sb_edac: Claim a different PCI device"). This is especially ugly if future hardware might not even have EDAC-relevant registers in PCI config space and we would still be required to choose some "random" PCI devices to scan for just so our driver loads. Is this cleaner/clearer? It deletes much more code than it adds. Only tested on Broadwell. The driver loads/unloads and loads again. Still decodes errors too. Signed-off-by: Tony Luck <tony.luck@intel.com> Suggested-by: Borislav Petkov <bp@alien8.de> Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r--drivers/edac/sb_edac.c134
1 files changed, 36 insertions, 98 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 342167496626..be398e0cf08a 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -21,6 +21,8 @@
21#include <linux/smp.h> 21#include <linux/smp.h>
22#include <linux/bitmap.h> 22#include <linux/bitmap.h>
23#include <linux/math64.h> 23#include <linux/math64.h>
24#include <linux/mod_devicetable.h>
25#include <asm/cpu_device_id.h>
24#include <asm/processor.h> 26#include <asm/processor.h>
25#include <asm/mce.h> 27#include <asm/mce.h>
26 28
@@ -28,8 +30,6 @@
28 30
29/* Static vars */ 31/* Static vars */
30static LIST_HEAD(sbridge_edac_list); 32static LIST_HEAD(sbridge_edac_list);
31static DEFINE_MUTEX(sbridge_edac_lock);
32static int probed;
33 33
34/* 34/*
35 * Alter this version for the module when modifications are made 35 * Alter this version for the module when modifications are made
@@ -651,18 +651,6 @@ static const struct pci_id_table pci_dev_descr_broadwell_table[] = {
651 {0,} /* 0 terminated list. */ 651 {0,} /* 0 terminated list. */
652}; 652};
653 653
654/*
655 * pci_device_id table for which devices we are looking for
656 */
657static const struct pci_device_id sbridge_pci_tbl[] = {
658 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)},
659 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
660 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
661 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
662 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0)},
663 {0,} /* 0 terminated list. */
664};
665
666 654
667/**************************************************************************** 655/****************************************************************************
668 Ancillary status routines 656 Ancillary status routines
@@ -3344,62 +3332,40 @@ fail0:
3344 return rc; 3332 return rc;
3345} 3333}
3346 3334
3335#define ICPU(model, table) \
3336 { X86_VENDOR_INTEL, 6, model, 0, (unsigned long)&table }
3337
3338/* Order here must match "enum type" */
3339static const struct x86_cpu_id sbridge_cpuids[] = {
3340 ICPU(0x2d, pci_dev_descr_sbridge_table), /* SANDY_BRIDGE */
3341 ICPU(0x3e, pci_dev_descr_ibridge_table), /* IVY_BRIDGE */
3342 ICPU(0x3f, pci_dev_descr_haswell_table), /* HASWELL */
3343 ICPU(0x4f, pci_dev_descr_broadwell_table), /* BROADWELL */
3344 ICPU(0x57, pci_dev_descr_knl_table), /* KNIGHTS_LANDING */
3345 { }
3346};
3347MODULE_DEVICE_TABLE(x86cpu, sbridge_cpuids);
3348
3347/* 3349/*
3348 * sbridge_probe Probe for ONE instance of device to see if it is 3350 * sbridge_probe Get all devices and register memory controllers
3349 * present. 3351 * present.
3350 * return: 3352 * return:
3351 * 0 for FOUND a device 3353 * 0 for FOUND a device
3352 * < 0 for error code 3354 * < 0 for error code
3353 */ 3355 */
3354 3356
3355static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) 3357static int sbridge_probe(const struct x86_cpu_id *id)
3356{ 3358{
3357 int rc = -ENODEV; 3359 int rc = -ENODEV;
3358 u8 mc, num_mc = 0; 3360 u8 mc, num_mc = 0;
3359 struct sbridge_dev *sbridge_dev; 3361 struct sbridge_dev *sbridge_dev;
3360 enum type type = SANDY_BRIDGE; 3362 struct pci_id_table *ptable = (struct pci_id_table *)id->driver_data;
3361 3363
3362 /* get the pci devices we want to reserve for our use */ 3364 /* get the pci devices we want to reserve for our use */
3363 mutex_lock(&sbridge_edac_lock); 3365 rc = sbridge_get_all_devices(&num_mc, ptable);
3364 3366
3365 /*
3366 * All memory controllers are allocated at the first pass.
3367 */
3368 if (unlikely(probed >= 1)) {
3369 mutex_unlock(&sbridge_edac_lock);
3370 return -ENODEV;
3371 }
3372 probed++;
3373
3374 switch (pdev->device) {
3375 case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
3376 rc = sbridge_get_all_devices(&num_mc,
3377 pci_dev_descr_ibridge_table);
3378 type = IVY_BRIDGE;
3379 break;
3380 case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
3381 rc = sbridge_get_all_devices(&num_mc,
3382 pci_dev_descr_sbridge_table);
3383 type = SANDY_BRIDGE;
3384 break;
3385 case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
3386 rc = sbridge_get_all_devices(&num_mc,
3387 pci_dev_descr_haswell_table);
3388 type = HASWELL;
3389 break;
3390 case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
3391 rc = sbridge_get_all_devices(&num_mc,
3392 pci_dev_descr_broadwell_table);
3393 type = BROADWELL;
3394 break;
3395 case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
3396 rc = sbridge_get_all_devices_knl(&num_mc,
3397 pci_dev_descr_knl_table);
3398 type = KNIGHTS_LANDING;
3399 break;
3400 }
3401 if (unlikely(rc < 0)) { 3367 if (unlikely(rc < 0)) {
3402 edac_dbg(0, "couldn't get all devices for 0x%x\n", pdev->device); 3368 edac_dbg(0, "couldn't get all devices\n");
3403 goto fail0; 3369 goto fail0;
3404 } 3370 }
3405 3371
@@ -3410,14 +3376,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3410 mc, mc + 1, num_mc); 3376 mc, mc + 1, num_mc);
3411 3377
3412 sbridge_dev->mc = mc++; 3378 sbridge_dev->mc = mc++;
3413 rc = sbridge_register_mci(sbridge_dev, type); 3379 rc = sbridge_register_mci(sbridge_dev, id - sbridge_cpuids);
3414 if (unlikely(rc < 0)) 3380 if (unlikely(rc < 0))
3415 goto fail1; 3381 goto fail1;
3416 } 3382 }
3417 3383
3418 sbridge_printk(KERN_INFO, "%s\n", SBRIDGE_REVISION); 3384 sbridge_printk(KERN_INFO, "%s\n", SBRIDGE_REVISION);
3419 3385
3420 mutex_unlock(&sbridge_edac_lock);
3421 return 0; 3386 return 0;
3422 3387
3423fail1: 3388fail1:
@@ -3426,74 +3391,47 @@ fail1:
3426 3391
3427 sbridge_put_all_devices(); 3392 sbridge_put_all_devices();
3428fail0: 3393fail0:
3429 mutex_unlock(&sbridge_edac_lock);
3430 return rc; 3394 return rc;
3431} 3395}
3432 3396
3433/* 3397/*
3434 * sbridge_remove destructor for one instance of device 3398 * sbridge_remove cleanup
3435 * 3399 *
3436 */ 3400 */
3437static void sbridge_remove(struct pci_dev *pdev) 3401static void sbridge_remove(void)
3438{ 3402{
3439 struct sbridge_dev *sbridge_dev; 3403 struct sbridge_dev *sbridge_dev;
3440 3404
3441 edac_dbg(0, "\n"); 3405 edac_dbg(0, "\n");
3442 3406
3443 /*
3444 * we have a trouble here: pdev value for removal will be wrong, since
3445 * it will point to the X58 register used to detect that the machine
3446 * is a Nehalem or upper design. However, due to the way several PCI
3447 * devices are grouped together to provide MC functionality, we need
3448 * to use a different method for releasing the devices
3449 */
3450
3451 mutex_lock(&sbridge_edac_lock);
3452
3453 if (unlikely(!probed)) {
3454 mutex_unlock(&sbridge_edac_lock);
3455 return;
3456 }
3457
3458 list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) 3407 list_for_each_entry(sbridge_dev, &sbridge_edac_list, list)
3459 sbridge_unregister_mci(sbridge_dev); 3408 sbridge_unregister_mci(sbridge_dev);
3460 3409
3461 /* Release PCI resources */ 3410 /* Release PCI resources */
3462 sbridge_put_all_devices(); 3411 sbridge_put_all_devices();
3463
3464 probed--;
3465
3466 mutex_unlock(&sbridge_edac_lock);
3467} 3412}
3468 3413
3469MODULE_DEVICE_TABLE(pci, sbridge_pci_tbl);
3470
3471/*
3472 * sbridge_driver pci_driver structure for this module
3473 *
3474 */
3475static struct pci_driver sbridge_driver = {
3476 .name = "sbridge_edac",
3477 .probe = sbridge_probe,
3478 .remove = sbridge_remove,
3479 .id_table = sbridge_pci_tbl,
3480};
3481
3482/* 3414/*
3483 * sbridge_init Module entry function 3415 * sbridge_init Module entry function
3484 * Try to initialize this module for its devices 3416 * Try to initialize this module for its devices
3485 */ 3417 */
3486static int __init sbridge_init(void) 3418static int __init sbridge_init(void)
3487{ 3419{
3488 int pci_rc; 3420 const struct x86_cpu_id *id;
3421 int rc;
3489 3422
3490 edac_dbg(2, "\n"); 3423 edac_dbg(2, "\n");
3491 3424
3425 id = x86_match_cpu(sbridge_cpuids);
3426 if (!id)
3427 return -ENODEV;
3428
3492 /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 3429 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
3493 opstate_init(); 3430 opstate_init();
3494 3431
3495 pci_rc = pci_register_driver(&sbridge_driver); 3432 rc = sbridge_probe(id);
3496 if (pci_rc >= 0) { 3433
3434 if (rc >= 0) {
3497 mce_register_decode_chain(&sbridge_mce_dec); 3435 mce_register_decode_chain(&sbridge_mce_dec);
3498 if (get_edac_report_status() == EDAC_REPORTING_DISABLED) 3436 if (get_edac_report_status() == EDAC_REPORTING_DISABLED)
3499 sbridge_printk(KERN_WARNING, "Loading driver, error reporting disabled.\n"); 3437 sbridge_printk(KERN_WARNING, "Loading driver, error reporting disabled.\n");
@@ -3501,9 +3439,9 @@ static int __init sbridge_init(void)
3501 } 3439 }
3502 3440
3503 sbridge_printk(KERN_ERR, "Failed to register device with error %d.\n", 3441 sbridge_printk(KERN_ERR, "Failed to register device with error %d.\n",
3504 pci_rc); 3442 rc);
3505 3443
3506 return pci_rc; 3444 return rc;
3507} 3445}
3508 3446
3509/* 3447/*
@@ -3513,7 +3451,7 @@ static int __init sbridge_init(void)
3513static void __exit sbridge_exit(void) 3451static void __exit sbridge_exit(void)
3514{ 3452{
3515 edac_dbg(2, "\n"); 3453 edac_dbg(2, "\n");
3516 pci_unregister_driver(&sbridge_driver); 3454 sbridge_remove();
3517 mce_unregister_decode_chain(&sbridge_mce_dec); 3455 mce_unregister_decode_chain(&sbridge_mce_dec);
3518} 3456}
3519 3457