diff options
author | Tony Luck <tony.luck@intel.com> | 2016-04-28 18:40:00 -0400 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2016-05-02 13:44:43 -0400 |
commit | 2c1ea4c700af3dcfc8eabd94c91d1830b42c5461 (patch) | |
tree | 1936dbdab9f678c1c9b1e9cc4524755df588a4de | |
parent | 5359534505c74841dbb2c6baf41db1a395acd34d (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.c | 134 |
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 */ |
30 | static LIST_HEAD(sbridge_edac_list); | 32 | static LIST_HEAD(sbridge_edac_list); |
31 | static DEFINE_MUTEX(sbridge_edac_lock); | ||
32 | static 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 | */ | ||
657 | static 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" */ | ||
3339 | static 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 | }; | ||
3347 | MODULE_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 | ||
3355 | static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 3357 | static 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 | ||
3423 | fail1: | 3388 | fail1: |
@@ -3426,74 +3391,47 @@ fail1: | |||
3426 | 3391 | ||
3427 | sbridge_put_all_devices(); | 3392 | sbridge_put_all_devices(); |
3428 | fail0: | 3393 | fail0: |
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 | */ |
3437 | static void sbridge_remove(struct pci_dev *pdev) | 3401 | static 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 | ||
3469 | MODULE_DEVICE_TABLE(pci, sbridge_pci_tbl); | ||
3470 | |||
3471 | /* | ||
3472 | * sbridge_driver pci_driver structure for this module | ||
3473 | * | ||
3474 | */ | ||
3475 | static 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 | */ |
3486 | static int __init sbridge_init(void) | 3418 | static 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) | |||
3513 | static void __exit sbridge_exit(void) | 3451 | static 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 | ||