diff options
| -rw-r--r-- | drivers/edac/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/edac/sb_edac.c | 373 |
2 files changed, 351 insertions, 26 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index b59274d2f2e0..afd75cacfc18 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
| @@ -245,12 +245,12 @@ config EDAC_I7300 | |||
| 245 | Clarksboro MCH (Intel 7300 chipset). | 245 | Clarksboro MCH (Intel 7300 chipset). |
| 246 | 246 | ||
| 247 | config EDAC_SBRIDGE | 247 | config EDAC_SBRIDGE |
| 248 | tristate "Intel Sandy-Bridge/Ivy-Bridge Integrated MC" | 248 | tristate "Intel Sandy-Bridge/Ivy-Bridge/Haswell Integrated MC" |
| 249 | depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL | 249 | depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL |
| 250 | depends on PCI_MMCONFIG | 250 | depends on PCI_MMCONFIG |
| 251 | help | 251 | help |
| 252 | Support for error detection and correction the Intel | 252 | Support for error detection and correction the Intel |
| 253 | Sandy Bridge and Ivy Bridge Integrated Memory Controllers. | 253 | Sandy Bridge, Ivy Bridge and Haswell Integrated Memory Controllers. |
| 254 | 254 | ||
| 255 | config EDAC_MPC85XX | 255 | config EDAC_MPC85XX |
| 256 | tristate "Freescale MPC83xx / MPC85xx" | 256 | tristate "Freescale MPC83xx / MPC85xx" |
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 7ff9003a6297..0034c4844428 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
| @@ -99,6 +99,7 @@ static const u32 ibridge_dram_rule[] = { | |||
| 99 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) | 99 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) |
| 100 | #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) | 100 | #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) |
| 101 | #define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0) | 101 | #define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0) |
| 102 | #define A7MODE(reg) GET_BITFIELD(reg, 26, 26) | ||
| 102 | 103 | ||
| 103 | static char *get_dram_attr(u32 reg) | 104 | static char *get_dram_attr(u32 reg) |
| 104 | { | 105 | { |
| @@ -164,6 +165,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, | |||
| 164 | 165 | ||
| 165 | #define TOLM 0x80 | 166 | #define TOLM 0x80 |
| 166 | #define TOHM 0x84 | 167 | #define TOHM 0x84 |
| 168 | #define HASWELL_TOHM_0 0xd4 | ||
| 169 | #define HASWELL_TOHM_1 0xd8 | ||
| 167 | 170 | ||
| 168 | #define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff) | 171 | #define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff) |
| 169 | #define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff) | 172 | #define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff) |
| @@ -286,6 +289,7 @@ static const u32 correrrthrsld[] = { | |||
| 286 | enum type { | 289 | enum type { |
| 287 | SANDY_BRIDGE, | 290 | SANDY_BRIDGE, |
| 288 | IVY_BRIDGE, | 291 | IVY_BRIDGE, |
| 292 | HASWELL, | ||
| 289 | }; | 293 | }; |
| 290 | 294 | ||
| 291 | struct sbridge_pvt; | 295 | struct sbridge_pvt; |
| @@ -303,6 +307,7 @@ struct sbridge_info { | |||
| 303 | u8 max_interleave; | 307 | u8 max_interleave; |
| 304 | u8 (*get_node_id)(struct sbridge_pvt *pvt); | 308 | u8 (*get_node_id)(struct sbridge_pvt *pvt); |
| 305 | enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); | 309 | enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); |
| 310 | struct pci_dev *pci_vtd; | ||
| 306 | }; | 311 | }; |
| 307 | 312 | ||
| 308 | struct sbridge_channel { | 313 | struct sbridge_channel { |
| @@ -334,6 +339,7 @@ struct sbridge_pvt { | |||
| 334 | struct pci_dev *pci_sad0, *pci_sad1; | 339 | struct pci_dev *pci_sad0, *pci_sad1; |
| 335 | struct pci_dev *pci_ha0, *pci_ha1; | 340 | struct pci_dev *pci_ha0, *pci_ha1; |
| 336 | struct pci_dev *pci_br0, *pci_br1; | 341 | struct pci_dev *pci_br0, *pci_br1; |
| 342 | struct pci_dev *pci_ha1_ta; | ||
| 337 | struct pci_dev *pci_tad[NUM_CHANNELS]; | 343 | struct pci_dev *pci_tad[NUM_CHANNELS]; |
| 338 | 344 | ||
| 339 | struct sbridge_dev *sbridge_dev; | 345 | struct sbridge_dev *sbridge_dev; |
| @@ -452,12 +458,80 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = { | |||
| 452 | {0,} /* 0 terminated list. */ | 458 | {0,} /* 0 terminated list. */ |
| 453 | }; | 459 | }; |
| 454 | 460 | ||
| 461 | /* Haswell support */ | ||
| 462 | /* EN processor: | ||
| 463 | * - 1 IMC | ||
| 464 | * - 3 DDR3 channels, 2 DPC per channel | ||
| 465 | * EP processor: | ||
| 466 | * - 1 or 2 IMC | ||
| 467 | * - 4 DDR4 channels, 3 DPC per channel | ||
| 468 | * EP 4S processor: | ||
| 469 | * - 2 IMC | ||
| 470 | * - 4 DDR4 channels, 3 DPC per channel | ||
| 471 | * EX processor: | ||
| 472 | * - 2 IMC | ||
| 473 | * - each IMC interfaces with a SMI 2 channel | ||
| 474 | * - each SMI channel interfaces with a scalable memory buffer | ||
| 475 | * - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC | ||
| 476 | */ | ||
| 477 | #define HASWELL_DDRCRCLKCONTROLS 0xa10 | ||
| 478 | #define HASWELL_HASYSDEFEATURE2 0x84 | ||
| 479 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28 | ||
| 480 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0 | ||
| 481 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1 0x2f60 | ||
| 482 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA 0x2fa8 | ||
| 483 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL 0x2f71 | ||
| 484 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA 0x2f68 | ||
| 485 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL 0x2f79 | ||
| 486 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0 0x2ffc | ||
| 487 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1 0x2ffd | ||
| 488 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0 0x2faa | ||
| 489 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1 0x2fab | ||
| 490 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2 0x2fac | ||
| 491 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3 0x2fad | ||
| 492 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 0x2f6a | ||
| 493 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1 0x2f6b | ||
| 494 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c | ||
| 495 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d | ||
| 496 | #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd | ||
| 497 | static const struct pci_id_descr pci_dev_descr_haswell[] = { | ||
| 498 | /* first item must be the HA */ | ||
| 499 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) }, | ||
| 500 | |||
| 501 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0, 0) }, | ||
| 502 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1, 0) }, | ||
| 503 | |||
| 504 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, 1) }, | ||
| 505 | |||
| 506 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA, 0) }, | ||
| 507 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL, 0) }, | ||
| 508 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0, 0) }, | ||
| 509 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1, 0) }, | ||
| 510 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2, 1) }, | ||
| 511 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) }, | ||
| 512 | |||
| 513 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) }, | ||
| 514 | |||
| 515 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) }, | ||
| 516 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) }, | ||
| 517 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0, 1) }, | ||
| 518 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1, 1) }, | ||
| 519 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2, 1) }, | ||
| 520 | { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3, 1) }, | ||
| 521 | }; | ||
| 522 | |||
| 523 | static const struct pci_id_table pci_dev_descr_haswell_table[] = { | ||
| 524 | PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell), | ||
| 525 | {0,} /* 0 terminated list. */ | ||
| 526 | }; | ||
| 527 | |||
| 455 | /* | 528 | /* |
| 456 | * pci_device_id table for which devices we are looking for | 529 | * pci_device_id table for which devices we are looking for |
| 457 | */ | 530 | */ |
| 458 | static const struct pci_device_id sbridge_pci_tbl[] = { | 531 | static const struct pci_device_id sbridge_pci_tbl[] = { |
| 459 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, | 532 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, |
| 460 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, | 533 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, |
| 534 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)}, | ||
| 461 | {0,} /* 0 terminated list. */ | 535 | {0,} /* 0 terminated list. */ |
| 462 | }; | 536 | }; |
| 463 | 537 | ||
| @@ -466,13 +540,17 @@ static const struct pci_device_id sbridge_pci_tbl[] = { | |||
| 466 | Ancillary status routines | 540 | Ancillary status routines |
| 467 | ****************************************************************************/ | 541 | ****************************************************************************/ |
| 468 | 542 | ||
| 469 | static inline int numrank(u32 mtr) | 543 | static inline int numrank(enum type type, u32 mtr) |
| 470 | { | 544 | { |
| 471 | int ranks = (1 << RANK_CNT_BITS(mtr)); | 545 | int ranks = (1 << RANK_CNT_BITS(mtr)); |
| 546 | int max = 4; | ||
| 547 | |||
| 548 | if (type == HASWELL) | ||
| 549 | max = 8; | ||
| 472 | 550 | ||
| 473 | if (ranks > 4) { | 551 | if (ranks > max) { |
| 474 | edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n", | 552 | edac_dbg(0, "Invalid number of ranks: %d (max = %i) raw value = %x (%04x)\n", |
| 475 | ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr); | 553 | ranks, max, (unsigned int)RANK_CNT_BITS(mtr), mtr); |
| 476 | return -EINVAL; | 554 | return -EINVAL; |
| 477 | } | 555 | } |
| 478 | 556 | ||
| @@ -606,6 +684,38 @@ static enum mem_type get_memory_type(struct sbridge_pvt *pvt) | |||
| 606 | return mtype; | 684 | return mtype; |
| 607 | } | 685 | } |
| 608 | 686 | ||
| 687 | static enum mem_type haswell_get_memory_type(struct sbridge_pvt *pvt) | ||
| 688 | { | ||
| 689 | u32 reg; | ||
| 690 | bool registered = false; | ||
| 691 | enum mem_type mtype = MEM_UNKNOWN; | ||
| 692 | |||
| 693 | if (!pvt->pci_ddrio) | ||
| 694 | goto out; | ||
| 695 | |||
| 696 | pci_read_config_dword(pvt->pci_ddrio, | ||
| 697 | HASWELL_DDRCRCLKCONTROLS, ®); | ||
| 698 | /* Is_Rdimm */ | ||
| 699 | if (GET_BITFIELD(reg, 16, 16)) | ||
| 700 | registered = true; | ||
| 701 | |||
| 702 | pci_read_config_dword(pvt->pci_ta, MCMTR, ®); | ||
| 703 | if (GET_BITFIELD(reg, 14, 14)) { | ||
| 704 | if (registered) | ||
| 705 | mtype = MEM_RDDR4; | ||
| 706 | else | ||
| 707 | mtype = MEM_DDR4; | ||
| 708 | } else { | ||
| 709 | if (registered) | ||
| 710 | mtype = MEM_RDDR3; | ||
| 711 | else | ||
| 712 | mtype = MEM_DDR3; | ||
| 713 | } | ||
| 714 | |||
| 715 | out: | ||
| 716 | return mtype; | ||
| 717 | } | ||
| 718 | |||
| 609 | static u8 get_node_id(struct sbridge_pvt *pvt) | 719 | static u8 get_node_id(struct sbridge_pvt *pvt) |
| 610 | { | 720 | { |
| 611 | u32 reg; | 721 | u32 reg; |
| @@ -613,6 +723,40 @@ static u8 get_node_id(struct sbridge_pvt *pvt) | |||
| 613 | return GET_BITFIELD(reg, 0, 2); | 723 | return GET_BITFIELD(reg, 0, 2); |
| 614 | } | 724 | } |
| 615 | 725 | ||
| 726 | static u8 haswell_get_node_id(struct sbridge_pvt *pvt) | ||
| 727 | { | ||
| 728 | u32 reg; | ||
| 729 | |||
| 730 | pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, ®); | ||
| 731 | return GET_BITFIELD(reg, 0, 3); | ||
| 732 | } | ||
| 733 | |||
| 734 | static u64 haswell_get_tolm(struct sbridge_pvt *pvt) | ||
| 735 | { | ||
| 736 | u32 reg; | ||
| 737 | |||
| 738 | pci_read_config_dword(pvt->info.pci_vtd, TOLM, ®); | ||
| 739 | return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff; | ||
| 740 | } | ||
| 741 | |||
| 742 | static u64 haswell_get_tohm(struct sbridge_pvt *pvt) | ||
| 743 | { | ||
| 744 | u64 rc; | ||
| 745 | u32 reg; | ||
| 746 | |||
| 747 | pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_0, ®); | ||
| 748 | rc = GET_BITFIELD(reg, 26, 31); | ||
| 749 | pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, ®); | ||
| 750 | rc = ((reg << 6) | rc) << 26; | ||
| 751 | |||
| 752 | return rc | 0x1ffffff; | ||
| 753 | } | ||
| 754 | |||
| 755 | static u64 haswell_rir_limit(u32 reg) | ||
| 756 | { | ||
| 757 | return (((u64)GET_BITFIELD(reg, 1, 11) + 1) << 29) - 1; | ||
| 758 | } | ||
| 759 | |||
| 616 | static inline u8 sad_pkg_socket(u8 pkg) | 760 | static inline u8 sad_pkg_socket(u8 pkg) |
| 617 | { | 761 | { |
| 618 | /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ | 762 | /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ |
| @@ -642,7 +786,10 @@ static struct pci_dev *get_pdev_same_bus(u8 bus, u32 id) | |||
| 642 | 786 | ||
| 643 | /** | 787 | /** |
| 644 | * check_if_ecc_is_active() - Checks if ECC is active | 788 | * check_if_ecc_is_active() - Checks if ECC is active |
| 645 | * bus: Device bus | 789 | * @bus: Device bus |
| 790 | * @type: Memory controller type | ||
| 791 | * returns: 0 in case ECC is active, -ENODEV if it can't be determined or | ||
| 792 | * disabled | ||
| 646 | */ | 793 | */ |
| 647 | static int check_if_ecc_is_active(const u8 bus, enum type type) | 794 | static int check_if_ecc_is_active(const u8 bus, enum type type) |
| 648 | { | 795 | { |
| @@ -651,6 +798,8 @@ static int check_if_ecc_is_active(const u8 bus, enum type type) | |||
| 651 | 798 | ||
| 652 | if (type == IVY_BRIDGE) | 799 | if (type == IVY_BRIDGE) |
| 653 | id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; | 800 | id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; |
| 801 | else if (type == HASWELL) | ||
| 802 | id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA; | ||
| 654 | else | 803 | else |
| 655 | id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA; | 804 | id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA; |
| 656 | 805 | ||
| @@ -680,7 +829,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 680 | enum edac_type mode; | 829 | enum edac_type mode; |
| 681 | enum mem_type mtype; | 830 | enum mem_type mtype; |
| 682 | 831 | ||
| 683 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); | 832 | if (pvt->info.type == HASWELL) |
| 833 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); | ||
| 834 | else | ||
| 835 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); | ||
| 836 | |||
| 684 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); | 837 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); |
| 685 | 838 | ||
| 686 | pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt); | 839 | pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt); |
| @@ -717,15 +870,17 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 717 | } | 870 | } |
| 718 | 871 | ||
| 719 | mtype = pvt->info.get_memory_type(pvt); | 872 | mtype = pvt->info.get_memory_type(pvt); |
| 720 | if (mtype == MEM_RDDR3) | 873 | if (mtype == MEM_RDDR3 || mtype == MEM_RDDR4) |
| 721 | edac_dbg(0, "Memory is registered\n"); | 874 | edac_dbg(0, "Memory is registered\n"); |
| 722 | else if (mtype == MEM_UNKNOWN) | 875 | else if (mtype == MEM_UNKNOWN) |
| 723 | edac_dbg(0, "Cannot determine memory type\n"); | 876 | edac_dbg(0, "Cannot determine memory type\n"); |
| 724 | else | 877 | else |
| 725 | edac_dbg(0, "Memory is unregistered\n"); | 878 | edac_dbg(0, "Memory is unregistered\n"); |
| 726 | 879 | ||
| 727 | /* On all supported DDR3 DIMM types, there are 8 banks available */ | 880 | if (mtype == MEM_DDR4 || MEM_RDDR4) |
| 728 | banks = 8; | 881 | banks = 16; |
| 882 | else | ||
| 883 | banks = 8; | ||
| 729 | 884 | ||
| 730 | for (i = 0; i < NUM_CHANNELS; i++) { | 885 | for (i = 0; i < NUM_CHANNELS; i++) { |
| 731 | u32 mtr; | 886 | u32 mtr; |
| @@ -739,11 +894,10 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 739 | if (IS_DIMM_PRESENT(mtr)) { | 894 | if (IS_DIMM_PRESENT(mtr)) { |
| 740 | pvt->channel[i].dimms++; | 895 | pvt->channel[i].dimms++; |
| 741 | 896 | ||
| 742 | ranks = numrank(mtr); | 897 | ranks = numrank(pvt->info.type, mtr); |
| 743 | rows = numrow(mtr); | 898 | rows = numrow(mtr); |
| 744 | cols = numcol(mtr); | 899 | cols = numcol(mtr); |
| 745 | 900 | ||
| 746 | /* DDR3 has 8 I/O banks */ | ||
| 747 | size = ((u64)rows * cols * banks * ranks) >> (20 - 3); | 901 | size = ((u64)rows * cols * banks * ranks) >> (20 - 3); |
| 748 | npages = MiB_TO_PAGES(size); | 902 | npages = MiB_TO_PAGES(size); |
| 749 | 903 | ||
| @@ -754,7 +908,17 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
| 754 | 908 | ||
| 755 | dimm->nr_pages = npages; | 909 | dimm->nr_pages = npages; |
| 756 | dimm->grain = 32; | 910 | dimm->grain = 32; |
| 757 | dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4; | 911 | switch (banks) { |
| 912 | case 16: | ||
| 913 | dimm->dtype = DEV_X16; | ||
| 914 | break; | ||
| 915 | case 8: | ||
| 916 | dimm->dtype = DEV_X8; | ||
| 917 | break; | ||
| 918 | case 4: | ||
| 919 | dimm->dtype = DEV_X4; | ||
| 920 | break; | ||
| 921 | } | ||
| 758 | dimm->mtype = mtype; | 922 | dimm->mtype = mtype; |
| 759 | dimm->edac_mode = mode; | 923 | dimm->edac_mode = mode; |
| 760 | snprintf(dimm->label, sizeof(dimm->label), | 924 | snprintf(dimm->label, sizeof(dimm->label), |
| @@ -948,9 +1112,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 948 | struct pci_dev *pci_ha; | 1112 | struct pci_dev *pci_ha; |
| 949 | int n_rir, n_sads, n_tads, sad_way, sck_xch; | 1113 | int n_rir, n_sads, n_tads, sad_way, sck_xch; |
| 950 | int sad_interl, idx, base_ch; | 1114 | int sad_interl, idx, base_ch; |
| 951 | int interleave_mode; | 1115 | int interleave_mode, shiftup = 0; |
| 952 | unsigned sad_interleave[pvt->info.max_interleave]; | 1116 | unsigned sad_interleave[pvt->info.max_interleave]; |
| 953 | u32 reg; | 1117 | u32 reg, dram_rule; |
| 954 | u8 ch_way, sck_way, pkg, sad_ha = 0; | 1118 | u8 ch_way, sck_way, pkg, sad_ha = 0; |
| 955 | u32 tad_offset; | 1119 | u32 tad_offset; |
| 956 | u32 rir_way; | 1120 | u32 rir_way; |
| @@ -997,8 +1161,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 997 | sprintf(msg, "Can't discover the memory socket"); | 1161 | sprintf(msg, "Can't discover the memory socket"); |
| 998 | return -EINVAL; | 1162 | return -EINVAL; |
| 999 | } | 1163 | } |
| 1000 | *area_type = get_dram_attr(reg); | 1164 | dram_rule = reg; |
| 1001 | interleave_mode = INTERLEAVE_MODE(reg); | 1165 | *area_type = get_dram_attr(dram_rule); |
| 1166 | interleave_mode = INTERLEAVE_MODE(dram_rule); | ||
| 1002 | 1167 | ||
| 1003 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], | 1168 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], |
| 1004 | ®); | 1169 | ®); |
| @@ -1043,6 +1208,36 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 1043 | *socket = sad_interleave[idx]; | 1208 | *socket = sad_interleave[idx]; |
| 1044 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", | 1209 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", |
| 1045 | idx, sad_way, *socket); | 1210 | idx, sad_way, *socket); |
| 1211 | } else if (pvt->info.type == HASWELL) { | ||
| 1212 | int bits, a7mode = A7MODE(dram_rule); | ||
| 1213 | |||
| 1214 | if (a7mode) { | ||
| 1215 | /* A7 mode swaps P9 with P6 */ | ||
| 1216 | bits = GET_BITFIELD(addr, 7, 8) << 1; | ||
| 1217 | bits |= GET_BITFIELD(addr, 9, 9); | ||
| 1218 | } else | ||
| 1219 | bits = GET_BITFIELD(addr, 7, 9); | ||
| 1220 | |||
| 1221 | if (interleave_mode) { | ||
| 1222 | /* interleave mode will XOR {8,7,6} with {18,17,16} */ | ||
| 1223 | idx = GET_BITFIELD(addr, 16, 18); | ||
| 1224 | idx ^= bits; | ||
| 1225 | } else | ||
| 1226 | idx = bits; | ||
| 1227 | |||
| 1228 | pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx); | ||
| 1229 | *socket = sad_pkg_socket(pkg); | ||
| 1230 | sad_ha = sad_pkg_ha(pkg); | ||
| 1231 | |||
| 1232 | if (a7mode) { | ||
| 1233 | /* MCChanShiftUpEnable */ | ||
| 1234 | pci_read_config_dword(pvt->pci_ha0, | ||
| 1235 | HASWELL_HASYSDEFEATURE2, ®); | ||
| 1236 | shiftup = GET_BITFIELD(reg, 22, 22); | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %i, shiftup: %i\n", | ||
| 1240 | idx, *socket, sad_ha, shiftup); | ||
| 1046 | } else { | 1241 | } else { |
| 1047 | /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */ | 1242 | /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */ |
| 1048 | idx = (addr >> 6) & 7; | 1243 | idx = (addr >> 6) & 7; |
| @@ -1100,7 +1295,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 1100 | if (ch_way == 3) | 1295 | if (ch_way == 3) |
| 1101 | idx = addr >> 6; | 1296 | idx = addr >> 6; |
| 1102 | else | 1297 | else |
| 1103 | idx = addr >> (6 + sck_way); | 1298 | idx = (addr >> (6 + sck_way + shiftup)) & 0x3; |
| 1104 | idx = idx % ch_way; | 1299 | idx = idx % ch_way; |
| 1105 | 1300 | ||
| 1106 | /* | 1301 | /* |
| @@ -1207,6 +1402,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
| 1207 | return -EINVAL; | 1402 | return -EINVAL; |
| 1208 | } | 1403 | } |
| 1209 | rir_way = RIR_WAY(reg); | 1404 | rir_way = RIR_WAY(reg); |
| 1405 | |||
| 1210 | if (pvt->is_close_pg) | 1406 | if (pvt->is_close_pg) |
| 1211 | idx = (ch_addr >> 6); | 1407 | idx = (ch_addr >> 6); |
| 1212 | else | 1408 | else |
| @@ -1561,6 +1757,106 @@ error: | |||
| 1561 | return -EINVAL; | 1757 | return -EINVAL; |
| 1562 | } | 1758 | } |
| 1563 | 1759 | ||
| 1760 | static int haswell_mci_bind_devs(struct mem_ctl_info *mci, | ||
| 1761 | struct sbridge_dev *sbridge_dev) | ||
| 1762 | { | ||
| 1763 | struct sbridge_pvt *pvt = mci->pvt_info; | ||
| 1764 | struct pci_dev *pdev, *tmp; | ||
| 1765 | int i; | ||
| 1766 | bool mode_2ha = false; | ||
| 1767 | |||
| 1768 | tmp = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
| 1769 | PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, NULL); | ||
| 1770 | if (tmp) { | ||
| 1771 | mode_2ha = true; | ||
| 1772 | pci_dev_put(tmp); | ||
| 1773 | } | ||
| 1774 | |||
| 1775 | /* there's only one device per system; not tied to any bus */ | ||
| 1776 | if (pvt->info.pci_vtd == NULL) | ||
| 1777 | /* result will be checked later */ | ||
| 1778 | pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
| 1779 | PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC, | ||
| 1780 | NULL); | ||
| 1781 | |||
| 1782 | for (i = 0; i < sbridge_dev->n_devs; i++) { | ||
| 1783 | pdev = sbridge_dev->pdev[i]; | ||
| 1784 | if (!pdev) | ||
| 1785 | continue; | ||
| 1786 | |||
| 1787 | switch (pdev->device) { | ||
| 1788 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0: | ||
| 1789 | pvt->pci_sad0 = pdev; | ||
| 1790 | break; | ||
| 1791 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1: | ||
| 1792 | pvt->pci_sad1 = pdev; | ||
| 1793 | break; | ||
| 1794 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0: | ||
| 1795 | pvt->pci_ha0 = pdev; | ||
| 1796 | break; | ||
| 1797 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA: | ||
| 1798 | pvt->pci_ta = pdev; | ||
| 1799 | break; | ||
| 1800 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL: | ||
| 1801 | pvt->pci_ras = pdev; | ||
| 1802 | break; | ||
| 1803 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0: | ||
| 1804 | pvt->pci_tad[0] = pdev; | ||
| 1805 | break; | ||
| 1806 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1: | ||
| 1807 | pvt->pci_tad[1] = pdev; | ||
| 1808 | break; | ||
| 1809 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2: | ||
| 1810 | if (!mode_2ha) | ||
| 1811 | pvt->pci_tad[2] = pdev; | ||
| 1812 | break; | ||
| 1813 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3: | ||
| 1814 | if (!mode_2ha) | ||
| 1815 | pvt->pci_tad[3] = pdev; | ||
| 1816 | break; | ||
| 1817 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0: | ||
| 1818 | pvt->pci_ddrio = pdev; | ||
| 1819 | break; | ||
| 1820 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1: | ||
| 1821 | pvt->pci_ha1 = pdev; | ||
| 1822 | break; | ||
| 1823 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA: | ||
| 1824 | pvt->pci_ha1_ta = pdev; | ||
| 1825 | break; | ||
| 1826 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0: | ||
| 1827 | if (mode_2ha) | ||
| 1828 | pvt->pci_tad[2] = pdev; | ||
| 1829 | break; | ||
| 1830 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1: | ||
| 1831 | if (mode_2ha) | ||
| 1832 | pvt->pci_tad[3] = pdev; | ||
| 1833 | break; | ||
| 1834 | default: | ||
| 1835 | break; | ||
| 1836 | } | ||
| 1837 | |||
| 1838 | edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", | ||
| 1839 | sbridge_dev->bus, | ||
| 1840 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
| 1841 | pdev); | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | /* Check if everything were registered */ | ||
| 1845 | if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 || | ||
| 1846 | !pvt->pci_ras || !pvt->pci_ta || !pvt->info.pci_vtd) | ||
| 1847 | goto enodev; | ||
| 1848 | |||
| 1849 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
| 1850 | if (!pvt->pci_tad[i]) | ||
| 1851 | goto enodev; | ||
| 1852 | } | ||
| 1853 | return 0; | ||
| 1854 | |||
| 1855 | enodev: | ||
| 1856 | sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); | ||
| 1857 | return -ENODEV; | ||
| 1858 | } | ||
| 1859 | |||
| 1564 | /**************************************************************************** | 1860 | /**************************************************************************** |
| 1565 | Error check routines | 1861 | Error check routines |
| 1566 | ****************************************************************************/ | 1862 | ****************************************************************************/ |
| @@ -1912,7 +2208,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
| 1912 | mci->edac_check = sbridge_check_error; | 2208 | mci->edac_check = sbridge_check_error; |
| 1913 | 2209 | ||
| 1914 | pvt->info.type = type; | 2210 | pvt->info.type = type; |
| 1915 | if (type == IVY_BRIDGE) { | 2211 | switch (type) { |
| 2212 | case IVY_BRIDGE: | ||
| 1916 | pvt->info.rankcfgr = IB_RANK_CFG_A; | 2213 | pvt->info.rankcfgr = IB_RANK_CFG_A; |
| 1917 | pvt->info.get_tolm = ibridge_get_tolm; | 2214 | pvt->info.get_tolm = ibridge_get_tolm; |
| 1918 | pvt->info.get_tohm = ibridge_get_tohm; | 2215 | pvt->info.get_tohm = ibridge_get_tohm; |
| @@ -1930,7 +2227,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
| 1930 | rc = ibridge_mci_bind_devs(mci, sbridge_dev); | 2227 | rc = ibridge_mci_bind_devs(mci, sbridge_dev); |
| 1931 | if (unlikely(rc < 0)) | 2228 | if (unlikely(rc < 0)) |
| 1932 | goto fail0; | 2229 | goto fail0; |
| 1933 | } else { | 2230 | break; |
| 2231 | case SANDY_BRIDGE: | ||
| 1934 | pvt->info.rankcfgr = SB_RANK_CFG_A; | 2232 | pvt->info.rankcfgr = SB_RANK_CFG_A; |
| 1935 | pvt->info.get_tolm = sbridge_get_tolm; | 2233 | pvt->info.get_tolm = sbridge_get_tolm; |
| 1936 | pvt->info.get_tohm = sbridge_get_tohm; | 2234 | pvt->info.get_tohm = sbridge_get_tohm; |
| @@ -1948,8 +2246,27 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
| 1948 | rc = sbridge_mci_bind_devs(mci, sbridge_dev); | 2246 | rc = sbridge_mci_bind_devs(mci, sbridge_dev); |
| 1949 | if (unlikely(rc < 0)) | 2247 | if (unlikely(rc < 0)) |
| 1950 | goto fail0; | 2248 | goto fail0; |
| 1951 | } | 2249 | break; |
| 2250 | case HASWELL: | ||
| 2251 | /* rankcfgr isn't used */ | ||
| 2252 | pvt->info.get_tolm = haswell_get_tolm; | ||
| 2253 | pvt->info.get_tohm = haswell_get_tohm; | ||
| 2254 | pvt->info.dram_rule = ibridge_dram_rule; | ||
| 2255 | pvt->info.get_memory_type = haswell_get_memory_type; | ||
| 2256 | pvt->info.get_node_id = haswell_get_node_id; | ||
| 2257 | pvt->info.rir_limit = haswell_rir_limit; | ||
| 2258 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | ||
| 2259 | pvt->info.interleave_list = ibridge_interleave_list; | ||
| 2260 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | ||
| 2261 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | ||
| 2262 | mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx); | ||
| 1952 | 2263 | ||
| 2264 | /* Store pci devices at mci for faster access */ | ||
| 2265 | rc = haswell_mci_bind_devs(mci, sbridge_dev); | ||
| 2266 | if (unlikely(rc < 0)) | ||
| 2267 | goto fail0; | ||
| 2268 | break; | ||
| 2269 | } | ||
| 1953 | 2270 | ||
| 1954 | /* Get dimm basic config and the memory layout */ | 2271 | /* Get dimm basic config and the memory layout */ |
| 1955 | get_dimm_config(mci); | 2272 | get_dimm_config(mci); |
| @@ -1984,10 +2301,10 @@ fail0: | |||
| 1984 | 2301 | ||
| 1985 | static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 2302 | static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| 1986 | { | 2303 | { |
| 1987 | int rc; | 2304 | int rc = -ENODEV; |
| 1988 | u8 mc, num_mc = 0; | 2305 | u8 mc, num_mc = 0; |
| 1989 | struct sbridge_dev *sbridge_dev; | 2306 | struct sbridge_dev *sbridge_dev; |
| 1990 | enum type type; | 2307 | enum type type = SANDY_BRIDGE; |
| 1991 | 2308 | ||
| 1992 | /* get the pci devices we want to reserve for our use */ | 2309 | /* get the pci devices we want to reserve for our use */ |
| 1993 | mutex_lock(&sbridge_edac_lock); | 2310 | mutex_lock(&sbridge_edac_lock); |
| @@ -2001,12 +2318,19 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 2001 | } | 2318 | } |
| 2002 | probed++; | 2319 | probed++; |
| 2003 | 2320 | ||
| 2004 | if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) { | 2321 | switch (pdev->device) { |
| 2322 | case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: | ||
| 2005 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); | 2323 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); |
| 2006 | type = IVY_BRIDGE; | 2324 | type = IVY_BRIDGE; |
| 2007 | } else { | 2325 | break; |
| 2326 | case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA: | ||
| 2008 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); | 2327 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); |
| 2009 | type = SANDY_BRIDGE; | 2328 | type = SANDY_BRIDGE; |
| 2329 | break; | ||
| 2330 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0: | ||
| 2331 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table); | ||
| 2332 | type = HASWELL; | ||
| 2333 | break; | ||
| 2010 | } | 2334 | } |
| 2011 | if (unlikely(rc < 0)) | 2335 | if (unlikely(rc < 0)) |
| 2012 | goto fail0; | 2336 | goto fail0; |
| @@ -2015,6 +2339,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 2015 | list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) { | 2339 | list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) { |
| 2016 | edac_dbg(0, "Registering MC#%d (%d of %d)\n", | 2340 | edac_dbg(0, "Registering MC#%d (%d of %d)\n", |
| 2017 | mc, mc + 1, num_mc); | 2341 | mc, mc + 1, num_mc); |
| 2342 | |||
| 2018 | sbridge_dev->mc = mc++; | 2343 | sbridge_dev->mc = mc++; |
| 2019 | rc = sbridge_register_mci(sbridge_dev, type); | 2344 | rc = sbridge_register_mci(sbridge_dev, type); |
| 2020 | if (unlikely(rc < 0)) | 2345 | if (unlikely(rc < 0)) |
