diff options
Diffstat (limited to 'drivers/edac/sb_edac.c')
| -rw-r--r-- | drivers/edac/sb_edac.c | 593 |
1 files changed, 464 insertions, 129 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 88f60c5fecbc..8472405c5586 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
| @@ -34,7 +34,7 @@ static int probed; | |||
| 34 | /* | 34 | /* |
| 35 | * Alter this version for the module when modifications are made | 35 | * Alter this version for the module when modifications are made |
| 36 | */ | 36 | */ |
| 37 | #define SBRIDGE_REVISION " Ver: 1.0.0 " | 37 | #define SBRIDGE_REVISION " Ver: 1.1.0 " |
| 38 | #define EDAC_MOD_STR "sbridge_edac" | 38 | #define EDAC_MOD_STR "sbridge_edac" |
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| @@ -83,11 +83,17 @@ static int probed; | |||
| 83 | #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3 0x3c77 /* 16.7 */ | 83 | #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3 0x3c77 /* 16.7 */ |
| 84 | 84 | ||
| 85 | /* Devices 12 Function 6, Offsets 0x80 to 0xcc */ | 85 | /* Devices 12 Function 6, Offsets 0x80 to 0xcc */ |
| 86 | static const u32 dram_rule[] = { | 86 | static const u32 sbridge_dram_rule[] = { |
| 87 | 0x80, 0x88, 0x90, 0x98, 0xa0, | 87 | 0x80, 0x88, 0x90, 0x98, 0xa0, |
| 88 | 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, | 88 | 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, |
| 89 | }; | 89 | }; |
| 90 | #define MAX_SAD ARRAY_SIZE(dram_rule) | 90 | |
| 91 | static const u32 ibridge_dram_rule[] = { | ||
| 92 | 0x60, 0x68, 0x70, 0x78, 0x80, | ||
| 93 | 0x88, 0x90, 0x98, 0xa0, 0xa8, | ||
| 94 | 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, | ||
| 95 | 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, | ||
| 96 | }; | ||
| 91 | 97 | ||
| 92 | #define SAD_LIMIT(reg) ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff) | 98 | #define SAD_LIMIT(reg) ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff) |
| 93 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) | 99 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) |
| @@ -108,43 +114,50 @@ static char *get_dram_attr(u32 reg) | |||
| 108 | } | 114 | } |
| 109 | } | 115 | } |
| 110 | 116 | ||
| 111 | static const u32 interleave_list[] = { | 117 | static const u32 sbridge_interleave_list[] = { |
| 112 | 0x84, 0x8c, 0x94, 0x9c, 0xa4, | 118 | 0x84, 0x8c, 0x94, 0x9c, 0xa4, |
| 113 | 0xac, 0xb4, 0xbc, 0xc4, 0xcc, | 119 | 0xac, 0xb4, 0xbc, 0xc4, 0xcc, |
| 114 | }; | 120 | }; |
| 115 | #define MAX_INTERLEAVE ARRAY_SIZE(interleave_list) | 121 | |
| 116 | 122 | static const u32 ibridge_interleave_list[] = { | |
| 117 | #define SAD_PKG0(reg) GET_BITFIELD(reg, 0, 2) | 123 | 0x64, 0x6c, 0x74, 0x7c, 0x84, |
| 118 | #define SAD_PKG1(reg) GET_BITFIELD(reg, 3, 5) | 124 | 0x8c, 0x94, 0x9c, 0xa4, 0xac, |
| 119 | #define SAD_PKG2(reg) GET_BITFIELD(reg, 8, 10) | 125 | 0xb4, 0xbc, 0xc4, 0xcc, 0xd4, |
| 120 | #define SAD_PKG3(reg) GET_BITFIELD(reg, 11, 13) | 126 | 0xdc, 0xe4, 0xec, 0xf4, 0xfc, |
| 121 | #define SAD_PKG4(reg) GET_BITFIELD(reg, 16, 18) | 127 | }; |
| 122 | #define SAD_PKG5(reg) GET_BITFIELD(reg, 19, 21) | 128 | |
| 123 | #define SAD_PKG6(reg) GET_BITFIELD(reg, 24, 26) | 129 | struct interleave_pkg { |
| 124 | #define SAD_PKG7(reg) GET_BITFIELD(reg, 27, 29) | 130 | unsigned char start; |
| 125 | 131 | unsigned char end; | |
| 126 | static inline int sad_pkg(u32 reg, int interleave) | 132 | }; |
| 133 | |||
| 134 | static const struct interleave_pkg sbridge_interleave_pkg[] = { | ||
| 135 | { 0, 2 }, | ||
| 136 | { 3, 5 }, | ||
| 137 | { 8, 10 }, | ||
| 138 | { 11, 13 }, | ||
| 139 | { 16, 18 }, | ||
| 140 | { 19, 21 }, | ||
| 141 | { 24, 26 }, | ||
| 142 | { 27, 29 }, | ||
| 143 | }; | ||
| 144 | |||
| 145 | static const struct interleave_pkg ibridge_interleave_pkg[] = { | ||
| 146 | { 0, 3 }, | ||
| 147 | { 4, 7 }, | ||
| 148 | { 8, 11 }, | ||
| 149 | { 12, 15 }, | ||
| 150 | { 16, 19 }, | ||
| 151 | { 20, 23 }, | ||
| 152 | { 24, 27 }, | ||
| 153 | { 28, 31 }, | ||
| 154 | }; | ||
| 155 | |||
| 156 | static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, | ||
| 157 | int interleave) | ||
| 127 | { | 158 | { |
| 128 | switch (interleave) { | 159 | return GET_BITFIELD(reg, table[interleave].start, |
| 129 | case 0: | 160 | table[interleave].end); |
| 130 | return SAD_PKG0(reg); | ||
| 131 | case 1: | ||
| 132 | return SAD_PKG1(reg); | ||
| 133 | case 2: | ||
| 134 | return SAD_PKG2(reg); | ||
| 135 | case 3: | ||
| 136 | return SAD_PKG3(reg); | ||
| 137 | case 4: | ||
| 138 | return SAD_PKG4(reg); | ||
| 139 | case 5: | ||
| 140 | return SAD_PKG5(reg); | ||
| 141 | case 6: | ||
| 142 | return SAD_PKG6(reg); | ||
| 143 | case 7: | ||
| 144 | return SAD_PKG7(reg); | ||
| 145 | default: | ||
| 146 | return -EINVAL; | ||
| 147 | } | ||
| 148 | } | 161 | } |
| 149 | 162 | ||
| 150 | /* Devices 12 Function 7 */ | 163 | /* Devices 12 Function 7 */ |
| @@ -262,7 +275,9 @@ static const u32 correrrthrsld[] = { | |||
| 262 | 275 | ||
| 263 | /* Device 17, function 0 */ | 276 | /* Device 17, function 0 */ |
| 264 | 277 | ||
| 265 | #define RANK_CFG_A 0x0328 | 278 | #define SB_RANK_CFG_A 0x0328 |
| 279 | |||
| 280 | #define IB_RANK_CFG_A 0x0320 | ||
| 266 | 281 | ||
| 267 | #define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11) | 282 | #define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11) |
| 268 | 283 | ||
| @@ -273,8 +288,23 @@ static const u32 correrrthrsld[] = { | |||
| 273 | #define NUM_CHANNELS 4 | 288 | #define NUM_CHANNELS 4 |
| 274 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ | 289 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ |
| 275 | 290 | ||
| 291 | enum type { | ||
| 292 | SANDY_BRIDGE, | ||
| 293 | IVY_BRIDGE, | ||
| 294 | }; | ||
| 295 | |||
| 296 | struct sbridge_pvt; | ||
| 276 | struct sbridge_info { | 297 | struct sbridge_info { |
| 277 | u32 mcmtr; | 298 | enum type type; |
| 299 | u32 mcmtr; | ||
| 300 | u32 rankcfgr; | ||
| 301 | u64 (*get_tolm)(struct sbridge_pvt *pvt); | ||
| 302 | u64 (*get_tohm)(struct sbridge_pvt *pvt); | ||
| 303 | const u32 *dram_rule; | ||
| 304 | const u32 *interleave_list; | ||
| 305 | const struct interleave_pkg *interleave_pkg; | ||
| 306 | u8 max_sad; | ||
| 307 | u8 max_interleave; | ||
| 278 | }; | 308 | }; |
| 279 | 309 | ||
| 280 | struct sbridge_channel { | 310 | struct sbridge_channel { |
| @@ -305,8 +335,9 @@ struct sbridge_dev { | |||
| 305 | 335 | ||
| 306 | struct sbridge_pvt { | 336 | struct sbridge_pvt { |
| 307 | struct pci_dev *pci_ta, *pci_ddrio, *pci_ras; | 337 | struct pci_dev *pci_ta, *pci_ddrio, *pci_ras; |
| 308 | struct pci_dev *pci_sad0, *pci_sad1, *pci_ha0; | 338 | struct pci_dev *pci_sad0, *pci_sad1; |
| 309 | struct pci_dev *pci_br; | 339 | struct pci_dev *pci_ha0, *pci_ha1; |
| 340 | struct pci_dev *pci_br0, *pci_br1; | ||
| 310 | struct pci_dev *pci_tad[NUM_CHANNELS]; | 341 | struct pci_dev *pci_tad[NUM_CHANNELS]; |
| 311 | 342 | ||
| 312 | struct sbridge_dev *sbridge_dev; | 343 | struct sbridge_dev *sbridge_dev; |
| @@ -364,11 +395,75 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = { | |||
| 364 | {0,} /* 0 terminated list. */ | 395 | {0,} /* 0 terminated list. */ |
| 365 | }; | 396 | }; |
| 366 | 397 | ||
| 398 | /* This changes depending if 1HA or 2HA: | ||
| 399 | * 1HA: | ||
| 400 | * 0x0eb8 (17.0) is DDRIO0 | ||
| 401 | * 2HA: | ||
| 402 | * 0x0ebc (17.4) is DDRIO0 | ||
| 403 | */ | ||
| 404 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0 0x0eb8 | ||
| 405 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0 0x0ebc | ||
| 406 | |||
| 407 | /* pci ids */ | ||
| 408 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0 0x0ea0 | ||
| 409 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA 0x0ea8 | ||
| 410 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS 0x0e71 | ||
| 411 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0 0x0eaa | ||
| 412 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1 0x0eab | ||
| 413 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2 0x0eac | ||
| 414 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3 0x0ead | ||
| 415 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_SAD 0x0ec8 | ||
| 416 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_BR0 0x0ec9 | ||
| 417 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_BR1 0x0eca | ||
| 418 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1 0x0e60 | ||
| 419 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA 0x0e68 | ||
| 420 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS 0x0e79 | ||
| 421 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 0x0e6a | ||
| 422 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1 0x0e6b | ||
| 423 | |||
| 424 | static const struct pci_id_descr pci_dev_descr_ibridge[] = { | ||
| 425 | /* Processor Home Agent */ | ||
| 426 | { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0) }, | ||
| 427 | |||
| 428 | /* Memory controller */ | ||
| 429 | { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0) }, | ||
| 430 | { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0) }, | ||
| 431 | { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0) }, | ||
| 432 | { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0) }, | ||
| 433 | { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0) }, | ||
| 434 | { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0) }, | ||
| 435 | |||
| 436 | /* System Address Decoder */ | ||
| 437 | { PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0) }, | ||
| 438 | |||
| 439 | /* Broadcast Registers */ | ||
| 440 | { PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1) }, | ||
| 441 | { PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0) }, | ||
| 442 | |||
| 443 | /* Optional, mode 2HA */ | ||
| 444 | { PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1) }, | ||
| 445 | #if 0 | ||
| 446 | { PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1) }, | ||
| 447 | { PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1) }, | ||
| 448 | #endif | ||
| 449 | { PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) }, | ||
| 450 | { PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) }, | ||
| 451 | |||
| 452 | { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) }, | ||
| 453 | { PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) }, | ||
| 454 | }; | ||
| 455 | |||
| 456 | static const struct pci_id_table pci_dev_descr_ibridge_table[] = { | ||
| 457 | PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge), | ||
| 458 | {0,} /* 0 terminated list. */ | ||
| 459 | }; | ||
| 460 | |||
| 367 | /* | 461 | /* |
| 368 | * pci_device_id table for which devices we are looking for | 462 | * pci_device_id table for which devices we are looking for |
| 369 | */ | 463 | */ |
| 370 | static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = { | 464 | static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = { |
| 371 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, | 465 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, |
| 466 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, | ||
| 372 | {0,} /* 0 terminated list. */ | 467 | {0,} /* 0 terminated list. */ |
| 373 | }; | 468 | }; |
| 374 | 469 | ||
| @@ -458,6 +553,52 @@ static void free_sbridge_dev(struct sbridge_dev *sbridge_dev) | |||
| 458 | kfree(sbridge_dev); | 553 | kfree(sbridge_dev); |
| 459 | } | 554 | } |
| 460 | 555 | ||
| 556 | static u64 sbridge_get_tolm(struct sbridge_pvt *pvt) | ||
| 557 | { | ||
| 558 | u32 reg; | ||
| 559 | |||
| 560 | /* Address range is 32:28 */ | ||
| 561 | pci_read_config_dword(pvt->pci_sad1, TOLM, ®); | ||
| 562 | return GET_TOLM(reg); | ||
| 563 | } | ||
| 564 | |||
| 565 | static u64 sbridge_get_tohm(struct sbridge_pvt *pvt) | ||
| 566 | { | ||
| 567 | u32 reg; | ||
| 568 | |||
| 569 | pci_read_config_dword(pvt->pci_sad1, TOHM, ®); | ||
| 570 | return GET_TOHM(reg); | ||
| 571 | } | ||
| 572 | |||
| 573 | static u64 ibridge_get_tolm(struct sbridge_pvt *pvt) | ||
| 574 | { | ||
| 575 | u32 reg; | ||
| 576 | |||
| 577 | pci_read_config_dword(pvt->pci_br1, TOLM, ®); | ||
| 578 | |||
| 579 | return GET_TOLM(reg); | ||
| 580 | } | ||
| 581 | |||
| 582 | static u64 ibridge_get_tohm(struct sbridge_pvt *pvt) | ||
| 583 | { | ||
| 584 | u32 reg; | ||
| 585 | |||
| 586 | pci_read_config_dword(pvt->pci_br1, TOHM, ®); | ||
| 587 | |||
| 588 | return GET_TOHM(reg); | ||
| 589 | } | ||
| 590 | |||
| 591 | static inline u8 sad_pkg_socket(u8 pkg) | ||
| 592 | { | ||
| 593 | /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ | ||
| 594 | return (pkg >> 3) | (pkg & 0x3); | ||
| 595 | } | ||
| 596 | |||
| 597 | static inline u8 sad_pkg_ha(u8 pkg) | ||
| 598 | { | ||
| 599 | return (pkg >> 2) & 0x1; | ||
| 600 | } | ||
| 601 | |||
| 461 | /**************************************************************************** | 602 | /**************************************************************************** |
| 462 | Memory check routines | 603 | Memory check routines |
| 463 | ****************************************************************************/ | 604 | ****************************************************************************/ |
| @@ -520,10 +661,10 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 520 | enum edac_type mode; | 661 | enum edac_type mode; |
| 521 | enum mem_type mtype; | 662 | enum mem_type mtype; |
| 522 | 663 | ||
| 523 | pci_read_config_dword(pvt->pci_br, SAD_TARGET, ®); | 664 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); |
| 524 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); | 665 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); |
| 525 | 666 | ||
| 526 | pci_read_config_dword(pvt->pci_br, SAD_CONTROL, ®); | 667 | pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, ®); |
| 527 | pvt->sbridge_dev->node_id = NODE_ID(reg); | 668 | pvt->sbridge_dev->node_id = NODE_ID(reg); |
| 528 | edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n", | 669 | edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n", |
| 529 | pvt->sbridge_dev->mc, | 670 | pvt->sbridge_dev->mc, |
| @@ -558,7 +699,8 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 558 | } | 699 | } |
| 559 | 700 | ||
| 560 | if (pvt->pci_ddrio) { | 701 | if (pvt->pci_ddrio) { |
| 561 | pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, ®); | 702 | pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, |
| 703 | ®); | ||
| 562 | if (IS_RDIMM_ENABLED(reg)) { | 704 | if (IS_RDIMM_ENABLED(reg)) { |
| 563 | /* FIXME: Can also be LRDIMM */ | 705 | /* FIXME: Can also be LRDIMM */ |
| 564 | edac_dbg(0, "Memory is registered\n"); | 706 | edac_dbg(0, "Memory is registered\n"); |
| @@ -629,19 +771,14 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 629 | * Step 1) Get TOLM/TOHM ranges | 771 | * Step 1) Get TOLM/TOHM ranges |
| 630 | */ | 772 | */ |
| 631 | 773 | ||
| 632 | /* Address range is 32:28 */ | 774 | pvt->tolm = pvt->info.get_tolm(pvt); |
| 633 | pci_read_config_dword(pvt->pci_sad1, TOLM, | ||
| 634 | ®); | ||
| 635 | pvt->tolm = GET_TOLM(reg); | ||
| 636 | tmp_mb = (1 + pvt->tolm) >> 20; | 775 | tmp_mb = (1 + pvt->tolm) >> 20; |
| 637 | 776 | ||
| 638 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 777 | mb = div_u64_rem(tmp_mb, 1000, &kb); |
| 639 | edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm); | 778 | edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm); |
| 640 | 779 | ||
| 641 | /* Address range is already 45:25 */ | 780 | /* Address range is already 45:25 */ |
| 642 | pci_read_config_dword(pvt->pci_sad1, TOHM, | 781 | pvt->tohm = pvt->info.get_tohm(pvt); |
| 643 | ®); | ||
| 644 | pvt->tohm = GET_TOHM(reg); | ||
| 645 | tmp_mb = (1 + pvt->tohm) >> 20; | 782 | tmp_mb = (1 + pvt->tohm) >> 20; |
| 646 | 783 | ||
| 647 | mb = div_u64_rem(tmp_mb, 1000, &kb); | 784 | mb = div_u64_rem(tmp_mb, 1000, &kb); |
| @@ -654,9 +791,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 654 | * algorithm bellow. | 791 | * algorithm bellow. |
| 655 | */ | 792 | */ |
| 656 | prv = 0; | 793 | prv = 0; |
| 657 | for (n_sads = 0; n_sads < MAX_SAD; n_sads++) { | 794 | for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) { |
| 658 | /* SAD_LIMIT Address range is 45:26 */ | 795 | /* SAD_LIMIT Address range is 45:26 */ |
| 659 | pci_read_config_dword(pvt->pci_sad0, dram_rule[n_sads], | 796 | pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads], |
| 660 | ®); | 797 | ®); |
| 661 | limit = SAD_LIMIT(reg); | 798 | limit = SAD_LIMIT(reg); |
| 662 | 799 | ||
| @@ -677,15 +814,16 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
| 677 | reg); | 814 | reg); |
| 678 | prv = limit; | 815 | prv = limit; |
| 679 | 816 | ||
| 680 | pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads], | 817 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], |
| 681 | ®); | 818 | ®); |
| 682 | sad_interl = sad_pkg(reg, 0); | 819 | sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0); |
| 683 | for (j = 0; j < 8; j++) { | 820 | for (j = 0; j < 8; j++) { |
| 684 | if (j > 0 && sad_interl == sad_pkg(reg, j)) | 821 | u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, j); |
| 822 | if (j > 0 && sad_interl == pkg) | ||
| 685 | break; | 823 | break; |
| 686 | 824 | ||
| 687 | edac_dbg(0, "SAD#%d, interleave #%d: %d\n", | 825 | edac_dbg(0, "SAD#%d, interleave #%d: %d\n", |
| 688 | n_sads, j, sad_pkg(reg, j)); | 826 | n_sads, j, pkg); |
| 689 | } | 827 | } |
| 690 | } | 828 | } |
| 691 | 829 | ||
| @@ -797,12 +935,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 797 | { | 935 | { |
| 798 | struct mem_ctl_info *new_mci; | 936 | struct mem_ctl_info *new_mci; |
| 799 | struct sbridge_pvt *pvt = mci->pvt_info; | 937 | struct sbridge_pvt *pvt = mci->pvt_info; |
| 938 | struct pci_dev *pci_ha; | ||
| 800 | int n_rir, n_sads, n_tads, sad_way, sck_xch; | 939 | int n_rir, n_sads, n_tads, sad_way, sck_xch; |
| 801 | int sad_interl, idx, base_ch; | 940 | int sad_interl, idx, base_ch; |
| 802 | int interleave_mode; | 941 | int interleave_mode; |
| 803 | unsigned sad_interleave[MAX_INTERLEAVE]; | 942 | unsigned sad_interleave[pvt->info.max_interleave]; |
| 804 | u32 reg; | 943 | u32 reg; |
| 805 | u8 ch_way,sck_way; | 944 | u8 ch_way, sck_way, pkg, sad_ha = 0; |
| 806 | u32 tad_offset; | 945 | u32 tad_offset; |
| 807 | u32 rir_way; | 946 | u32 rir_way; |
| 808 | u32 mb, kb; | 947 | u32 mb, kb; |
| @@ -828,8 +967,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 828 | /* | 967 | /* |
| 829 | * Step 1) Get socket | 968 | * Step 1) Get socket |
| 830 | */ | 969 | */ |
| 831 | for (n_sads = 0; n_sads < MAX_SAD; n_sads++) { | 970 | for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) { |
| 832 | pci_read_config_dword(pvt->pci_sad0, dram_rule[n_sads], | 971 | pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads], |
| 833 | ®); | 972 | ®); |
| 834 | 973 | ||
| 835 | if (!DRAM_RULE_ENABLE(reg)) | 974 | if (!DRAM_RULE_ENABLE(reg)) |
| @@ -844,53 +983,65 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 844 | break; | 983 | break; |
| 845 | prv = limit; | 984 | prv = limit; |
| 846 | } | 985 | } |
| 847 | if (n_sads == MAX_SAD) { | 986 | if (n_sads == pvt->info.max_sad) { |
| 848 | sprintf(msg, "Can't discover the memory socket"); | 987 | sprintf(msg, "Can't discover the memory socket"); |
| 849 | return -EINVAL; | 988 | return -EINVAL; |
| 850 | } | 989 | } |
| 851 | *area_type = get_dram_attr(reg); | 990 | *area_type = get_dram_attr(reg); |
| 852 | interleave_mode = INTERLEAVE_MODE(reg); | 991 | interleave_mode = INTERLEAVE_MODE(reg); |
| 853 | 992 | ||
| 854 | pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads], | 993 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], |
| 855 | ®); | 994 | ®); |
| 856 | sad_interl = sad_pkg(reg, 0); | 995 | |
| 857 | for (sad_way = 0; sad_way < 8; sad_way++) { | 996 | if (pvt->info.type == SANDY_BRIDGE) { |
| 858 | if (sad_way > 0 && sad_interl == sad_pkg(reg, sad_way)) | 997 | sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0); |
| 998 | for (sad_way = 0; sad_way < 8; sad_way++) { | ||
| 999 | u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way); | ||
| 1000 | if (sad_way > 0 && sad_interl == pkg) | ||
| 1001 | break; | ||
| 1002 | sad_interleave[sad_way] = pkg; | ||
| 1003 | edac_dbg(0, "SAD interleave #%d: %d\n", | ||
| 1004 | sad_way, sad_interleave[sad_way]); | ||
| 1005 | } | ||
| 1006 | edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n", | ||
| 1007 | pvt->sbridge_dev->mc, | ||
| 1008 | n_sads, | ||
| 1009 | addr, | ||
| 1010 | limit, | ||
| 1011 | sad_way + 7, | ||
| 1012 | !interleave_mode ? "" : "XOR[18:16]"); | ||
| 1013 | if (interleave_mode) | ||
| 1014 | idx = ((addr >> 6) ^ (addr >> 16)) & 7; | ||
| 1015 | else | ||
| 1016 | idx = (addr >> 6) & 7; | ||
| 1017 | switch (sad_way) { | ||
| 1018 | case 1: | ||
| 1019 | idx = 0; | ||
| 859 | break; | 1020 | break; |
| 860 | sad_interleave[sad_way] = sad_pkg(reg, sad_way); | 1021 | case 2: |
| 861 | edac_dbg(0, "SAD interleave #%d: %d\n", | 1022 | idx = idx & 1; |
| 862 | sad_way, sad_interleave[sad_way]); | 1023 | break; |
| 863 | } | 1024 | case 4: |
| 864 | edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n", | 1025 | idx = idx & 3; |
| 865 | pvt->sbridge_dev->mc, | 1026 | break; |
| 866 | n_sads, | 1027 | case 8: |
| 867 | addr, | 1028 | break; |
| 868 | limit, | 1029 | default: |
| 869 | sad_way + 7, | 1030 | sprintf(msg, "Can't discover socket interleave"); |
| 870 | interleave_mode ? "" : "XOR[18:16]"); | 1031 | return -EINVAL; |
| 871 | if (interleave_mode) | 1032 | } |
| 872 | idx = ((addr >> 6) ^ (addr >> 16)) & 7; | 1033 | *socket = sad_interleave[idx]; |
| 873 | else | 1034 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", |
| 1035 | idx, sad_way, *socket); | ||
| 1036 | } else { | ||
| 1037 | /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */ | ||
| 874 | idx = (addr >> 6) & 7; | 1038 | idx = (addr >> 6) & 7; |
| 875 | switch (sad_way) { | 1039 | pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx); |
| 876 | case 1: | 1040 | *socket = sad_pkg_socket(pkg); |
| 877 | idx = 0; | 1041 | sad_ha = sad_pkg_ha(pkg); |
| 878 | break; | 1042 | edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n", |
| 879 | case 2: | 1043 | idx, *socket, sad_ha); |
| 880 | idx = idx & 1; | ||
| 881 | break; | ||
| 882 | case 4: | ||
| 883 | idx = idx & 3; | ||
| 884 | break; | ||
| 885 | case 8: | ||
| 886 | break; | ||
| 887 | default: | ||
| 888 | sprintf(msg, "Can't discover socket interleave"); | ||
| 889 | return -EINVAL; | ||
| 890 | } | 1044 | } |
| 891 | *socket = sad_interleave[idx]; | ||
| 892 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", | ||
| 893 | idx, sad_way, *socket); | ||
| 894 | 1045 | ||
| 895 | /* | 1046 | /* |
| 896 | * Move to the proper node structure, in order to access the | 1047 | * Move to the proper node structure, in order to access the |
| @@ -909,9 +1060,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 909 | * Step 2) Get memory channel | 1060 | * Step 2) Get memory channel |
| 910 | */ | 1061 | */ |
| 911 | prv = 0; | 1062 | prv = 0; |
| 1063 | if (pvt->info.type == SANDY_BRIDGE) | ||
| 1064 | pci_ha = pvt->pci_ha0; | ||
| 1065 | else { | ||
| 1066 | if (sad_ha) | ||
| 1067 | pci_ha = pvt->pci_ha1; | ||
| 1068 | else | ||
| 1069 | pci_ha = pvt->pci_ha0; | ||
| 1070 | } | ||
| 912 | for (n_tads = 0; n_tads < MAX_TAD; n_tads++) { | 1071 | for (n_tads = 0; n_tads < MAX_TAD; n_tads++) { |
| 913 | pci_read_config_dword(pvt->pci_ha0, tad_dram_rule[n_tads], | 1072 | pci_read_config_dword(pci_ha, tad_dram_rule[n_tads], ®); |
| 914 | ®); | ||
| 915 | limit = TAD_LIMIT(reg); | 1073 | limit = TAD_LIMIT(reg); |
| 916 | if (limit <= prv) { | 1074 | if (limit <= prv) { |
| 917 | sprintf(msg, "Can't discover the memory channel"); | 1075 | sprintf(msg, "Can't discover the memory channel"); |
| @@ -921,14 +1079,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 921 | break; | 1079 | break; |
| 922 | prv = limit; | 1080 | prv = limit; |
| 923 | } | 1081 | } |
| 1082 | if (n_tads == MAX_TAD) { | ||
| 1083 | sprintf(msg, "Can't discover the memory channel"); | ||
| 1084 | return -EINVAL; | ||
| 1085 | } | ||
| 1086 | |||
| 924 | ch_way = TAD_CH(reg) + 1; | 1087 | ch_way = TAD_CH(reg) + 1; |
| 925 | sck_way = TAD_SOCK(reg) + 1; | 1088 | sck_way = TAD_SOCK(reg) + 1; |
| 926 | /* | ||
| 927 | * FIXME: Is it right to always use channel 0 for offsets? | ||
| 928 | */ | ||
| 929 | pci_read_config_dword(pvt->pci_tad[0], | ||
| 930 | tad_ch_nilv_offset[n_tads], | ||
| 931 | &tad_offset); | ||
| 932 | 1089 | ||
| 933 | if (ch_way == 3) | 1090 | if (ch_way == 3) |
| 934 | idx = addr >> 6; | 1091 | idx = addr >> 6; |
| @@ -958,6 +1115,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 958 | } | 1115 | } |
| 959 | *channel_mask = 1 << base_ch; | 1116 | *channel_mask = 1 << base_ch; |
| 960 | 1117 | ||
| 1118 | pci_read_config_dword(pvt->pci_tad[base_ch], | ||
| 1119 | tad_ch_nilv_offset[n_tads], | ||
| 1120 | &tad_offset); | ||
| 1121 | |||
| 961 | if (pvt->is_mirrored) { | 1122 | if (pvt->is_mirrored) { |
| 962 | *channel_mask |= 1 << ((base_ch + 2) % 4); | 1123 | *channel_mask |= 1 << ((base_ch + 2) % 4); |
| 963 | switch(ch_way) { | 1124 | switch(ch_way) { |
| @@ -1091,12 +1252,6 @@ static void sbridge_put_all_devices(void) | |||
| 1091 | } | 1252 | } |
| 1092 | } | 1253 | } |
| 1093 | 1254 | ||
| 1094 | /* | ||
| 1095 | * sbridge_get_all_devices Find and perform 'get' operation on the MCH's | ||
| 1096 | * device/functions we want to reference for this driver | ||
| 1097 | * | ||
| 1098 | * Need to 'get' device 16 func 1 and func 2 | ||
| 1099 | */ | ||
| 1100 | static int sbridge_get_onedevice(struct pci_dev **prev, | 1255 | static int sbridge_get_onedevice(struct pci_dev **prev, |
| 1101 | u8 *num_mc, | 1256 | u8 *num_mc, |
| 1102 | const struct pci_id_table *table, | 1257 | const struct pci_id_table *table, |
| @@ -1198,11 +1353,21 @@ static int sbridge_get_onedevice(struct pci_dev **prev, | |||
| 1198 | return 0; | 1353 | return 0; |
| 1199 | } | 1354 | } |
| 1200 | 1355 | ||
| 1201 | static int sbridge_get_all_devices(u8 *num_mc) | 1356 | /* |
| 1357 | * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's | ||
| 1358 | * device/functions we want to reference for this driver. | ||
| 1359 | * Need to 'get' device 16 func 1 and func 2. | ||
| 1360 | * @num_mc: pointer to the memory controllers count, to be incremented in case | ||
| 1361 | * of success. | ||
| 1362 | * @table: model specific table | ||
| 1363 | * | ||
| 1364 | * returns 0 in case of success or error code | ||
| 1365 | */ | ||
| 1366 | static int sbridge_get_all_devices(u8 *num_mc, | ||
| 1367 | const struct pci_id_table *table) | ||
| 1202 | { | 1368 | { |
| 1203 | int i, rc; | 1369 | int i, rc; |
| 1204 | struct pci_dev *pdev = NULL; | 1370 | struct pci_dev *pdev = NULL; |
| 1205 | const struct pci_id_table *table = pci_dev_descr_sbridge_table; | ||
| 1206 | 1371 | ||
| 1207 | while (table && table->descr) { | 1372 | while (table && table->descr) { |
| 1208 | for (i = 0; i < table->n_devs; i++) { | 1373 | for (i = 0; i < table->n_devs; i++) { |
| @@ -1226,8 +1391,8 @@ static int sbridge_get_all_devices(u8 *num_mc) | |||
| 1226 | return 0; | 1391 | return 0; |
| 1227 | } | 1392 | } |
| 1228 | 1393 | ||
| 1229 | static int mci_bind_devs(struct mem_ctl_info *mci, | 1394 | static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, |
| 1230 | struct sbridge_dev *sbridge_dev) | 1395 | struct sbridge_dev *sbridge_dev) |
| 1231 | { | 1396 | { |
| 1232 | struct sbridge_pvt *pvt = mci->pvt_info; | 1397 | struct sbridge_pvt *pvt = mci->pvt_info; |
| 1233 | struct pci_dev *pdev; | 1398 | struct pci_dev *pdev; |
| @@ -1255,7 +1420,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci, | |||
| 1255 | case 13: | 1420 | case 13: |
| 1256 | switch (func) { | 1421 | switch (func) { |
| 1257 | case 6: | 1422 | case 6: |
| 1258 | pvt->pci_br = pdev; | 1423 | pvt->pci_br0 = pdev; |
| 1259 | break; | 1424 | break; |
| 1260 | default: | 1425 | default: |
| 1261 | goto error; | 1426 | goto error; |
| @@ -1329,6 +1494,131 @@ error: | |||
| 1329 | return -EINVAL; | 1494 | return -EINVAL; |
| 1330 | } | 1495 | } |
| 1331 | 1496 | ||
| 1497 | static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, | ||
| 1498 | struct sbridge_dev *sbridge_dev) | ||
| 1499 | { | ||
| 1500 | struct sbridge_pvt *pvt = mci->pvt_info; | ||
| 1501 | struct pci_dev *pdev, *tmp; | ||
| 1502 | int i, func, slot; | ||
| 1503 | bool mode_2ha = false; | ||
| 1504 | |||
| 1505 | tmp = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
| 1506 | PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, NULL); | ||
| 1507 | if (tmp) { | ||
| 1508 | mode_2ha = true; | ||
| 1509 | pci_dev_put(tmp); | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | for (i = 0; i < sbridge_dev->n_devs; i++) { | ||
| 1513 | pdev = sbridge_dev->pdev[i]; | ||
| 1514 | if (!pdev) | ||
| 1515 | continue; | ||
| 1516 | slot = PCI_SLOT(pdev->devfn); | ||
| 1517 | func = PCI_FUNC(pdev->devfn); | ||
| 1518 | |||
| 1519 | switch (slot) { | ||
| 1520 | case 14: | ||
| 1521 | if (func == 0) { | ||
| 1522 | pvt->pci_ha0 = pdev; | ||
| 1523 | break; | ||
| 1524 | } | ||
| 1525 | goto error; | ||
| 1526 | case 15: | ||
| 1527 | switch (func) { | ||
| 1528 | case 0: | ||
| 1529 | pvt->pci_ta = pdev; | ||
| 1530 | break; | ||
| 1531 | case 1: | ||
| 1532 | pvt->pci_ras = pdev; | ||
| 1533 | break; | ||
| 1534 | case 4: | ||
| 1535 | case 5: | ||
| 1536 | /* if we have 2 HAs active, channels 2 and 3 | ||
| 1537 | * are in other device */ | ||
| 1538 | if (mode_2ha) | ||
| 1539 | break; | ||
| 1540 | /* fall through */ | ||
| 1541 | case 2: | ||
| 1542 | case 3: | ||
| 1543 | pvt->pci_tad[func - 2] = pdev; | ||
| 1544 | break; | ||
| 1545 | default: | ||
| 1546 | goto error; | ||
| 1547 | } | ||
| 1548 | break; | ||
| 1549 | case 17: | ||
| 1550 | if (func == 4) { | ||
| 1551 | pvt->pci_ddrio = pdev; | ||
| 1552 | break; | ||
| 1553 | } else if (func == 0) { | ||
| 1554 | if (!mode_2ha) | ||
| 1555 | pvt->pci_ddrio = pdev; | ||
| 1556 | break; | ||
| 1557 | } | ||
| 1558 | goto error; | ||
| 1559 | case 22: | ||
| 1560 | switch (func) { | ||
| 1561 | case 0: | ||
| 1562 | pvt->pci_sad0 = pdev; | ||
| 1563 | break; | ||
| 1564 | case 1: | ||
| 1565 | pvt->pci_br0 = pdev; | ||
| 1566 | break; | ||
| 1567 | case 2: | ||
| 1568 | pvt->pci_br1 = pdev; | ||
| 1569 | break; | ||
| 1570 | default: | ||
| 1571 | goto error; | ||
| 1572 | } | ||
| 1573 | break; | ||
| 1574 | case 28: | ||
| 1575 | if (func == 0) { | ||
| 1576 | pvt->pci_ha1 = pdev; | ||
| 1577 | break; | ||
| 1578 | } | ||
| 1579 | goto error; | ||
| 1580 | case 29: | ||
| 1581 | /* we shouldn't have this device if we have just one | ||
| 1582 | * HA present */ | ||
| 1583 | WARN_ON(!mode_2ha); | ||
| 1584 | if (func == 2 || func == 3) { | ||
| 1585 | pvt->pci_tad[func] = pdev; | ||
| 1586 | break; | ||
| 1587 | } | ||
| 1588 | goto error; | ||
| 1589 | default: | ||
| 1590 | goto error; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", | ||
| 1594 | sbridge_dev->bus, | ||
| 1595 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
| 1596 | pdev); | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | /* Check if everything were registered */ | ||
| 1600 | if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 || | ||
| 1601 | !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras || | ||
| 1602 | !pvt->pci_ta) | ||
| 1603 | goto enodev; | ||
| 1604 | |||
| 1605 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
| 1606 | if (!pvt->pci_tad[i]) | ||
| 1607 | goto enodev; | ||
| 1608 | } | ||
| 1609 | return 0; | ||
| 1610 | |||
| 1611 | enodev: | ||
| 1612 | sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); | ||
| 1613 | return -ENODEV; | ||
| 1614 | |||
| 1615 | error: | ||
| 1616 | sbridge_printk(KERN_ERR, | ||
| 1617 | "Device %d, function %d is out of the expected range\n", | ||
| 1618 | slot, func); | ||
| 1619 | return -EINVAL; | ||
| 1620 | } | ||
| 1621 | |||
| 1332 | /**************************************************************************** | 1622 | /**************************************************************************** |
| 1333 | Error check routines | 1623 | Error check routines |
| 1334 | ****************************************************************************/ | 1624 | ****************************************************************************/ |
| @@ -1349,7 +1639,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, | |||
| 1349 | bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); | 1639 | bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); |
| 1350 | bool overflow = GET_BITFIELD(m->status, 62, 62); | 1640 | bool overflow = GET_BITFIELD(m->status, 62, 62); |
| 1351 | bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); | 1641 | bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); |
| 1352 | bool recoverable = GET_BITFIELD(m->status, 56, 56); | 1642 | bool recoverable; |
| 1353 | u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52); | 1643 | u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52); |
| 1354 | u32 mscod = GET_BITFIELD(m->status, 16, 31); | 1644 | u32 mscod = GET_BITFIELD(m->status, 16, 31); |
| 1355 | u32 errcode = GET_BITFIELD(m->status, 0, 15); | 1645 | u32 errcode = GET_BITFIELD(m->status, 0, 15); |
| @@ -1360,6 +1650,11 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, | |||
| 1360 | int rc, dimm; | 1650 | int rc, dimm; |
| 1361 | char *area_type = NULL; | 1651 | char *area_type = NULL; |
| 1362 | 1652 | ||
| 1653 | if (pvt->info.type == IVY_BRIDGE) | ||
| 1654 | recoverable = true; | ||
| 1655 | else | ||
| 1656 | recoverable = GET_BITFIELD(m->status, 56, 56); | ||
| 1657 | |||
| 1363 | if (uncorrected_error) { | 1658 | if (uncorrected_error) { |
| 1364 | if (ripv) { | 1659 | if (ripv) { |
| 1365 | type = "FATAL"; | 1660 | type = "FATAL"; |
| @@ -1409,6 +1704,10 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, | |||
| 1409 | } | 1704 | } |
| 1410 | } | 1705 | } |
| 1411 | 1706 | ||
| 1707 | /* Only decode errors with an valid address (ADDRV) */ | ||
| 1708 | if (!GET_BITFIELD(m->status, 58, 58)) | ||
| 1709 | return; | ||
| 1710 | |||
| 1412 | rc = get_memory_error_data(mci, m->addr, &socket, | 1711 | rc = get_memory_error_data(mci, m->addr, &socket, |
| 1413 | &channel_mask, &rank, &area_type, msg); | 1712 | &channel_mask, &rank, &area_type, msg); |
| 1414 | if (rc < 0) | 1713 | if (rc < 0) |
| @@ -1614,11 +1913,12 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev) | |||
| 1614 | sbridge_dev->mci = NULL; | 1913 | sbridge_dev->mci = NULL; |
| 1615 | } | 1914 | } |
| 1616 | 1915 | ||
| 1617 | static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) | 1916 | static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) |
| 1618 | { | 1917 | { |
| 1619 | struct mem_ctl_info *mci; | 1918 | struct mem_ctl_info *mci; |
| 1620 | struct edac_mc_layer layers[2]; | 1919 | struct edac_mc_layer layers[2]; |
| 1621 | struct sbridge_pvt *pvt; | 1920 | struct sbridge_pvt *pvt; |
| 1921 | struct pci_dev *pdev = sbridge_dev->pdev[0]; | ||
| 1622 | int rc; | 1922 | int rc; |
| 1623 | 1923 | ||
| 1624 | /* Check the number of active and not disabled channels */ | 1924 | /* Check the number of active and not disabled channels */ |
| @@ -1640,7 +1940,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) | |||
| 1640 | return -ENOMEM; | 1940 | return -ENOMEM; |
| 1641 | 1941 | ||
| 1642 | edac_dbg(0, "MC: mci = %p, dev = %p\n", | 1942 | edac_dbg(0, "MC: mci = %p, dev = %p\n", |
| 1643 | mci, &sbridge_dev->pdev[0]->dev); | 1943 | mci, &pdev->dev); |
| 1644 | 1944 | ||
| 1645 | pvt = mci->pvt_info; | 1945 | pvt = mci->pvt_info; |
| 1646 | memset(pvt, 0, sizeof(*pvt)); | 1946 | memset(pvt, 0, sizeof(*pvt)); |
| @@ -1654,24 +1954,52 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) | |||
| 1654 | mci->edac_cap = EDAC_FLAG_NONE; | 1954 | mci->edac_cap = EDAC_FLAG_NONE; |
| 1655 | mci->mod_name = "sbridge_edac.c"; | 1955 | mci->mod_name = "sbridge_edac.c"; |
| 1656 | mci->mod_ver = SBRIDGE_REVISION; | 1956 | mci->mod_ver = SBRIDGE_REVISION; |
| 1657 | mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); | 1957 | mci->dev_name = pci_name(pdev); |
| 1658 | mci->dev_name = pci_name(sbridge_dev->pdev[0]); | ||
| 1659 | mci->ctl_page_to_phys = NULL; | 1958 | mci->ctl_page_to_phys = NULL; |
| 1660 | 1959 | ||
| 1661 | /* Set the function pointer to an actual operation function */ | 1960 | /* Set the function pointer to an actual operation function */ |
| 1662 | mci->edac_check = sbridge_check_error; | 1961 | mci->edac_check = sbridge_check_error; |
| 1663 | 1962 | ||
| 1664 | /* Store pci devices at mci for faster access */ | 1963 | pvt->info.type = type; |
| 1665 | rc = mci_bind_devs(mci, sbridge_dev); | 1964 | if (type == IVY_BRIDGE) { |
| 1666 | if (unlikely(rc < 0)) | 1965 | pvt->info.rankcfgr = IB_RANK_CFG_A; |
| 1667 | goto fail0; | 1966 | pvt->info.get_tolm = ibridge_get_tolm; |
| 1967 | pvt->info.get_tohm = ibridge_get_tohm; | ||
| 1968 | pvt->info.dram_rule = ibridge_dram_rule; | ||
| 1969 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | ||
| 1970 | pvt->info.interleave_list = ibridge_interleave_list; | ||
| 1971 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | ||
| 1972 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | ||
| 1973 | mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx); | ||
| 1974 | |||
| 1975 | /* Store pci devices at mci for faster access */ | ||
| 1976 | rc = ibridge_mci_bind_devs(mci, sbridge_dev); | ||
| 1977 | if (unlikely(rc < 0)) | ||
| 1978 | goto fail0; | ||
| 1979 | } else { | ||
| 1980 | pvt->info.rankcfgr = SB_RANK_CFG_A; | ||
| 1981 | pvt->info.get_tolm = sbridge_get_tolm; | ||
| 1982 | pvt->info.get_tohm = sbridge_get_tohm; | ||
| 1983 | pvt->info.dram_rule = sbridge_dram_rule; | ||
| 1984 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); | ||
| 1985 | pvt->info.interleave_list = sbridge_interleave_list; | ||
| 1986 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); | ||
| 1987 | pvt->info.interleave_pkg = sbridge_interleave_pkg; | ||
| 1988 | mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); | ||
| 1989 | |||
| 1990 | /* Store pci devices at mci for faster access */ | ||
| 1991 | rc = sbridge_mci_bind_devs(mci, sbridge_dev); | ||
| 1992 | if (unlikely(rc < 0)) | ||
| 1993 | goto fail0; | ||
| 1994 | } | ||
| 1995 | |||
| 1668 | 1996 | ||
| 1669 | /* Get dimm basic config and the memory layout */ | 1997 | /* Get dimm basic config and the memory layout */ |
| 1670 | get_dimm_config(mci); | 1998 | get_dimm_config(mci); |
| 1671 | get_memory_layout(mci); | 1999 | get_memory_layout(mci); |
| 1672 | 2000 | ||
| 1673 | /* record ptr to the generic device */ | 2001 | /* record ptr to the generic device */ |
| 1674 | mci->pdev = &sbridge_dev->pdev[0]->dev; | 2002 | mci->pdev = &pdev->dev; |
| 1675 | 2003 | ||
| 1676 | /* add this new MC control structure to EDAC's list of MCs */ | 2004 | /* add this new MC control structure to EDAC's list of MCs */ |
| 1677 | if (unlikely(edac_mc_add_mc(mci))) { | 2005 | if (unlikely(edac_mc_add_mc(mci))) { |
| @@ -1702,6 +2030,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1702 | int rc; | 2030 | int rc; |
| 1703 | u8 mc, num_mc = 0; | 2031 | u8 mc, num_mc = 0; |
| 1704 | struct sbridge_dev *sbridge_dev; | 2032 | struct sbridge_dev *sbridge_dev; |
| 2033 | enum type type; | ||
| 1705 | 2034 | ||
| 1706 | /* get the pci devices we want to reserve for our use */ | 2035 | /* get the pci devices we want to reserve for our use */ |
| 1707 | mutex_lock(&sbridge_edac_lock); | 2036 | mutex_lock(&sbridge_edac_lock); |
| @@ -1715,7 +2044,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1715 | } | 2044 | } |
| 1716 | probed++; | 2045 | probed++; |
| 1717 | 2046 | ||
| 1718 | rc = sbridge_get_all_devices(&num_mc); | 2047 | if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) { |
| 2048 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); | ||
| 2049 | type = IVY_BRIDGE; | ||
| 2050 | } else { | ||
| 2051 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); | ||
| 2052 | type = SANDY_BRIDGE; | ||
| 2053 | } | ||
| 1719 | if (unlikely(rc < 0)) | 2054 | if (unlikely(rc < 0)) |
| 1720 | goto fail0; | 2055 | goto fail0; |
| 1721 | mc = 0; | 2056 | mc = 0; |
| @@ -1724,7 +2059,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1724 | edac_dbg(0, "Registering MC#%d (%d of %d)\n", | 2059 | edac_dbg(0, "Registering MC#%d (%d of %d)\n", |
| 1725 | mc, mc + 1, num_mc); | 2060 | mc, mc + 1, num_mc); |
| 1726 | sbridge_dev->mc = mc++; | 2061 | sbridge_dev->mc = mc++; |
| 1727 | rc = sbridge_register_mci(sbridge_dev); | 2062 | rc = sbridge_register_mci(sbridge_dev, type); |
| 1728 | if (unlikely(rc < 0)) | 2063 | if (unlikely(rc < 0)) |
| 1729 | goto fail1; | 2064 | goto fail1; |
| 1730 | } | 2065 | } |
| @@ -1839,5 +2174,5 @@ MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); | |||
| 1839 | MODULE_LICENSE("GPL"); | 2174 | MODULE_LICENSE("GPL"); |
| 1840 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | 2175 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); |
| 1841 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); | 2176 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); |
| 1842 | MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge memory controllers - " | 2177 | MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - " |
| 1843 | SBRIDGE_REVISION); | 2178 | SBRIDGE_REVISION); |
