diff options
author | Aristeu Rozanski <aris@redhat.com> | 2014-06-20 09:27:54 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-06-26 14:47:01 -0400 |
commit | 50d1bb93672fa2f42cec6e06ce799fbe864f57e9 (patch) | |
tree | 6d054c02570c943bf49e21a39810707d635f1793 | |
parent | c41afdca29acfdc78b89f936cdcb8cabc6b08aae (diff) |
sb_edac: add support for Haswell based systems
Haswell memory controllers are very similar to Ivy Bridge and Sandy Bridge
ones. This patch adds support to Haswell based systems.
[m.chehab@samsung.com: Fix CodingStyle issues]
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Aristeu Rozanski <aris@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-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)) |