linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
@ 2013-10-30 16:26 ` Aristeu Rozanski
  2013-10-30 16:40   ` Borislav Petkov
  2013-10-30 16:26 ` [PATCH 02/12] sb_edac: make RANK_CFG_A value part of sbridge_info Aristeu Rozanski
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:26 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, Bjorn Helgaas, open list, open list:PCI SUBSYSTEM

According to the comment, it should be done before submitting upstream.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c  |   21 ++-------------------
 include/linux/pci_ids.h |   11 +++++++++++
 2 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index e04462b..4cdd948 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -57,26 +57,9 @@ static int probed;
  */
 
 /*
- * FIXME: For now, let's order by device function, as it makes
- * easier for driver's development process. This table should be
- * moved to pci_id.h when submitted upstream
+ * Currently, unused, but will be needed in the future
+ * implementations, as they hold the error counters
  */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0	0x3cf4	/* 12.6 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1	0x3cf6	/* 12.7 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR		0x3cf5	/* 13.6 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0	0x3ca0	/* 14.0 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA	0x3ca8	/* 15.0 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS	0x3c71	/* 15.1 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0	0x3caa	/* 15.2 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1	0x3cab	/* 15.3 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2	0x3cac	/* 15.4 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3	0x3cad	/* 15.5 */
-#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO	0x3cb8	/* 17.0 */
-
-	/*
-	 * Currently, unused, but will be needed in the future
-	 * implementations, as they hold the error counters
-	 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0	0x3c72	/* 16.2 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1	0x3c73	/* 16.3 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR2	0x3c76	/* 16.6 */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 97fbecd..d7d4757 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2812,7 +2812,18 @@
 #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE	0x3c43
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0	0x3c44
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1	0x3c45
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS	0x3c71
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0	0x3ca0
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA	0x3ca8
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0	0x3caa
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1	0x3cab
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2	0x3cac
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3	0x3cad
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO	0x3cb8
 #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX	0x3ce0
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0	0x3cf4
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR		0x3cf5
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1	0x3cf6
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB	0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16	0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_19	0x65f3
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 02/12] sb_edac: make RANK_CFG_A value part of sbridge_info
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
  2013-10-30 16:26 ` [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h Aristeu Rozanski
@ 2013-10-30 16:26 ` Aristeu Rozanski
  2013-10-30 16:26 ` [PATCH 03/12] sb_edac: isolate TOLM retrieval Aristeu Rozanski
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:26 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is in preparation of Ivy Bridge support.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 4cdd948..466c313 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -245,7 +245,7 @@ static const u32 correrrthrsld[] = {
 
 /* Device 17, function 0 */
 
-#define RANK_CFG_A		0x0328
+#define SB_RANK_CFG_A		0x0328
 
 #define IS_RDIMM_ENABLED(reg)		GET_BITFIELD(reg, 11, 11)
 
@@ -258,6 +258,7 @@ static const u32 correrrthrsld[] = {
 
 struct sbridge_info {
 	u32	mcmtr;
+	u32	rankcfgr;
 };
 
 struct sbridge_channel {
@@ -503,6 +504,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 	enum edac_type mode;
 	enum mem_type mtype;
 
+	pvt->info.rankcfgr = SB_RANK_CFG_A;
+
 	pci_read_config_dword(pvt->pci_br, SAD_TARGET, &reg);
 	pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
@@ -541,7 +544,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 	}
 
 	if (pvt->pci_ddrio) {
-		pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, &reg);
+		pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
+				      &reg);
 		if (IS_RDIMM_ENABLED(reg)) {
 			/* FIXME: Can also be LRDIMM */
 			edac_dbg(0, "Memory is registered\n");
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 03/12] sb_edac: isolate TOLM retrieval
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
  2013-10-30 16:26 ` [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h Aristeu Rozanski
  2013-10-30 16:26 ` [PATCH 02/12] sb_edac: make RANK_CFG_A value part of sbridge_info Aristeu Rozanski
@ 2013-10-30 16:26 ` Aristeu Rozanski
  2013-10-30 16:26 ` [PATCH 04/12] sb_edac: rename pci_br Aristeu Rozanski
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:26 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is in preparation for the Ivy Bridge support.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 466c313..3e4837f 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -256,9 +256,11 @@ static const u32 correrrthrsld[] = {
 #define NUM_CHANNELS	4
 #define MAX_DIMMS	3		/* Max DIMMS per channel */
 
+struct sbridge_pvt;
 struct sbridge_info {
 	u32	mcmtr;
 	u32	rankcfgr;
+	u64	(*get_tolm)(struct sbridge_pvt *pvt);
 };
 
 struct sbridge_channel {
@@ -442,6 +444,15 @@ static void free_sbridge_dev(struct sbridge_dev *sbridge_dev)
 	kfree(sbridge_dev);
 }
 
+static u64 sbridge_get_tolm(struct sbridge_pvt *pvt)
+{
+	u32 reg;
+
+	/* Address range is 32:28 */
+	pci_read_config_dword(pvt->pci_sad1, TOLM, &reg);
+	return GET_TOLM(reg);
+}
+
 /****************************************************************************
 			Memory check routines
  ****************************************************************************/
@@ -616,10 +627,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 	 * Step 1) Get TOLM/TOHM ranges
 	 */
 
-	/* Address range is 32:28 */
-	pci_read_config_dword(pvt->pci_sad1, TOLM,
-			      &reg);
-	pvt->tolm = GET_TOLM(reg);
+	pvt->tolm = pvt->info.get_tolm(pvt);
 	tmp_mb = (1 + pvt->tolm) >> 20;
 
 	mb = div_u64_rem(tmp_mb, 1000, &kb);
@@ -1644,6 +1652,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
 	mci->dev_name = pci_name(sbridge_dev->pdev[0]);
 	mci->ctl_page_to_phys = NULL;
+	pvt->info.get_tolm = sbridge_get_tolm;
 
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = sbridge_check_error;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 04/12] sb_edac: rename pci_br
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (2 preceding siblings ...)
  2013-10-30 16:26 ` [PATCH 03/12] sb_edac: isolate TOLM retrieval Aristeu Rozanski
@ 2013-10-30 16:26 ` Aristeu Rozanski
  2013-10-30 16:26 ` [PATCH 05/12] sb_edac: isolate TOHM retrieval Aristeu Rozanski
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:26 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

Ivy Bridge has more than one, so rename pci_br to pci_br0

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 3e4837f..eb6c9d4 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -292,7 +292,7 @@ struct sbridge_dev {
 struct sbridge_pvt {
 	struct pci_dev		*pci_ta, *pci_ddrio, *pci_ras;
 	struct pci_dev		*pci_sad0, *pci_sad1, *pci_ha0;
-	struct pci_dev		*pci_br;
+	struct pci_dev		*pci_br0;
 	struct pci_dev		*pci_tad[NUM_CHANNELS];
 
 	struct sbridge_dev	*sbridge_dev;
@@ -517,10 +517,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 
 	pvt->info.rankcfgr = SB_RANK_CFG_A;
 
-	pci_read_config_dword(pvt->pci_br, SAD_TARGET, &reg);
+	pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
 	pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
-	pci_read_config_dword(pvt->pci_br, SAD_CONTROL, &reg);
+	pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
 	pvt->sbridge_dev->node_id = NODE_ID(reg);
 	edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
 		 pvt->sbridge_dev->mc,
@@ -1250,7 +1250,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
 		case 13:
 			switch (func) {
 			case 6:
-				pvt->pci_br = pdev;
+				pvt->pci_br0 = pdev;
 				break;
 			default:
 				goto error;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 05/12] sb_edac: isolate TOHM retrieval
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (3 preceding siblings ...)
  2013-10-30 16:26 ` [PATCH 04/12] sb_edac: rename pci_br Aristeu Rozanski
@ 2013-10-30 16:26 ` Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 06/12] sb_edac: allow different dram_rule arrays Aristeu Rozanski
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:26 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is preparation of Ivy Bridge support.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index eb6c9d4..fcd9c66 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -261,6 +261,7 @@ struct sbridge_info {
 	u32	mcmtr;
 	u32	rankcfgr;
 	u64	(*get_tolm)(struct sbridge_pvt *pvt);
+	u64	(*get_tohm)(struct sbridge_pvt *pvt);
 };
 
 struct sbridge_channel {
@@ -453,6 +454,14 @@ static u64 sbridge_get_tolm(struct sbridge_pvt *pvt)
 	return GET_TOLM(reg);
 }
 
+static u64 sbridge_get_tohm(struct sbridge_pvt *pvt)
+{
+	u32 reg;
+
+	pci_read_config_dword(pvt->pci_sad1, TOHM, &reg);
+	return GET_TOHM(reg);
+}
+
 /****************************************************************************
 			Memory check routines
  ****************************************************************************/
@@ -634,9 +643,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 	edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm);
 
 	/* Address range is already 45:25 */
-	pci_read_config_dword(pvt->pci_sad1, TOHM,
-			      &reg);
-	pvt->tohm = GET_TOHM(reg);
+	pvt->tohm = pvt->info.get_tohm(pvt);
 	tmp_mb = (1 + pvt->tohm) >> 20;
 
 	mb = div_u64_rem(tmp_mb, 1000, &kb);
@@ -1653,6 +1660,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	mci->dev_name = pci_name(sbridge_dev->pdev[0]);
 	mci->ctl_page_to_phys = NULL;
 	pvt->info.get_tolm = sbridge_get_tolm;
+	pvt->info.get_tohm = sbridge_get_tohm;
 
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = sbridge_check_error;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 06/12] sb_edac: allow different dram_rule arrays
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (4 preceding siblings ...)
  2013-10-30 16:26 ` [PATCH 05/12] sb_edac: isolate TOHM retrieval Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 07/12] sb_edac: allow different interleave lists Aristeu Rozanski
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is in preparation for Ivy Bridge support

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |   25 ++++++++++++++-----------
 1 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index fcd9c66..0bafe0a 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -66,11 +66,10 @@ static int probed;
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3	0x3c77	/* 16.7 */
 
 /* Devices 12 Function 6, Offsets 0x80 to 0xcc */
-static const u32 dram_rule[] = {
+static const u32 sbridge_dram_rule[] = {
 	0x80, 0x88, 0x90, 0x98, 0xa0,
 	0xa8, 0xb0, 0xb8, 0xc0, 0xc8,
 };
-#define MAX_SAD		ARRAY_SIZE(dram_rule)
 
 #define SAD_LIMIT(reg)		((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)
 #define DRAM_ATTR(reg)		GET_BITFIELD(reg, 2,  3)
@@ -258,10 +257,12 @@ static const u32 correrrthrsld[] = {
 
 struct sbridge_pvt;
 struct sbridge_info {
-	u32	mcmtr;
-	u32	rankcfgr;
-	u64	(*get_tolm)(struct sbridge_pvt *pvt);
-	u64	(*get_tohm)(struct sbridge_pvt *pvt);
+	u32		mcmtr;
+	u32		rankcfgr;	
+	u64		(*get_tolm)(struct sbridge_pvt *pvt);
+	u64		(*get_tohm)(struct sbridge_pvt *pvt);	
+	const u32	*dram_rule;
+	u8		max_sad;
 };
 
 struct sbridge_channel {
@@ -656,9 +657,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 	 * algorithm bellow.
 	 */
 	prv = 0;
-	for (n_sads = 0; n_sads < MAX_SAD; n_sads++) {
+	for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) {
 		/* SAD_LIMIT Address range is 45:26 */
-		pci_read_config_dword(pvt->pci_sad0, dram_rule[n_sads],
+		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
 				      &reg);
 		limit = SAD_LIMIT(reg);
 
@@ -830,8 +831,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 	/*
 	 * Step 1) Get socket
 	 */
-	for (n_sads = 0; n_sads < MAX_SAD; n_sads++) {
-		pci_read_config_dword(pvt->pci_sad0, dram_rule[n_sads],
+	for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) {
+		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
 				      &reg);
 
 		if (!DRAM_RULE_ENABLE(reg))
@@ -846,7 +847,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 			break;
 		prv = limit;
 	}
-	if (n_sads == MAX_SAD) {
+	if (n_sads == pvt->info.max_sad) {
 		sprintf(msg, "Can't discover the memory socket");
 		return -EINVAL;
 	}
@@ -1661,6 +1662,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	mci->ctl_page_to_phys = NULL;
 	pvt->info.get_tolm = sbridge_get_tolm;
 	pvt->info.get_tohm = sbridge_get_tohm;
+	pvt->info.dram_rule = sbridge_dram_rule;
+	pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
 
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = sbridge_check_error;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 07/12] sb_edac: allow different interleave lists
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (5 preceding siblings ...)
  2013-10-30 16:27 ` [PATCH 06/12] sb_edac: allow different dram_rule arrays Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 08/12] sb_edac: rework sad_pkg Aristeu Rozanski
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is in preparation for Ivy Bridge support

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 0bafe0a..dbd99d3 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -90,11 +90,10 @@ static char *get_dram_attr(u32 reg)
 	}
 }
 
-static const u32 interleave_list[] = {
+static const u32 sbridge_interleave_list[] = {
 	0x84, 0x8c, 0x94, 0x9c, 0xa4,
 	0xac, 0xb4, 0xbc, 0xc4, 0xcc,
 };
-#define MAX_INTERLEAVE	ARRAY_SIZE(interleave_list)
 
 #define SAD_PKG0(reg)		GET_BITFIELD(reg, 0, 2)
 #define SAD_PKG1(reg)		GET_BITFIELD(reg, 3, 5)
@@ -262,7 +261,9 @@ struct sbridge_info {
 	u64		(*get_tolm)(struct sbridge_pvt *pvt);
 	u64		(*get_tohm)(struct sbridge_pvt *pvt);	
 	const u32	*dram_rule;
+	const u32	*interleave_list;
 	u8		max_sad;
+	u8		max_interleave;
 };
 
 struct sbridge_channel {
@@ -680,7 +681,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 			 reg);
 		prv = limit;
 
-		pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads],
+		pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
 				      &reg);
 		sad_interl = sad_pkg(reg, 0);
 		for (j = 0; j < 8; j++) {
@@ -803,7 +804,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 	int 			n_rir, n_sads, n_tads, sad_way, sck_xch;
 	int			sad_interl, idx, base_ch;
 	int			interleave_mode;
-	unsigned		sad_interleave[MAX_INTERLEAVE];
+	unsigned		sad_interleave[pvt->info.max_interleave];
 	u32			reg;
 	u8			ch_way,sck_way;
 	u32			tad_offset;
@@ -854,7 +855,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 	*area_type = get_dram_attr(reg);
 	interleave_mode = INTERLEAVE_MODE(reg);
 
-	pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads],
+	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
 			      &reg);
 	sad_interl = sad_pkg(reg, 0);
 	for (sad_way = 0; sad_way < 8; sad_way++) {
@@ -1664,6 +1665,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	pvt->info.get_tohm = sbridge_get_tohm;
 	pvt->info.dram_rule = sbridge_dram_rule;
 	pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
+	pvt->info.interleave_list = sbridge_interleave_list;
+	pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
 
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = sbridge_check_error;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 08/12] sb_edac: rework sad_pkg
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (6 preceding siblings ...)
  2013-10-30 16:27 ` [PATCH 07/12] sb_edac: allow different interleave lists Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 09/12] sb_edac: enable multiple PCI id tables to be used Aristeu Rozanski
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is in preparation for Ivy Bridge support

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |   66 +++++++++++++++++++++--------------------------
 1 files changed, 30 insertions(+), 36 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index dbd99d3..bf305a2 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -95,37 +95,27 @@ static const u32 sbridge_interleave_list[] = {
 	0xac, 0xb4, 0xbc, 0xc4, 0xcc,
 };
 
-#define SAD_PKG0(reg)		GET_BITFIELD(reg, 0, 2)
-#define SAD_PKG1(reg)		GET_BITFIELD(reg, 3, 5)
-#define SAD_PKG2(reg)		GET_BITFIELD(reg, 8, 10)
-#define SAD_PKG3(reg)		GET_BITFIELD(reg, 11, 13)
-#define SAD_PKG4(reg)		GET_BITFIELD(reg, 16, 18)
-#define SAD_PKG5(reg)		GET_BITFIELD(reg, 19, 21)
-#define SAD_PKG6(reg)		GET_BITFIELD(reg, 24, 26)
-#define SAD_PKG7(reg)		GET_BITFIELD(reg, 27, 29)
-
-static inline int sad_pkg(u32 reg, int interleave)
+struct interleave_pkg {
+	unsigned char start;
+	unsigned char end;
+};
+
+static const struct interleave_pkg sbridge_interleave_pkg[] = {
+	{ 0, 2 },
+	{ 3, 5 },
+	{ 8, 10 },
+	{ 11, 13 },
+	{ 16, 18 },
+	{ 19, 21 },
+	{ 24, 26 },
+	{ 27, 29 },
+};
+
+static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
+			  int interleave)
 {
-	switch (interleave) {
-	case 0:
-		return SAD_PKG0(reg);
-	case 1:
-		return SAD_PKG1(reg);
-	case 2:
-		return SAD_PKG2(reg);
-	case 3:
-		return SAD_PKG3(reg);
-	case 4:
-		return SAD_PKG4(reg);
-	case 5:
-		return SAD_PKG5(reg);
-	case 6:
-		return SAD_PKG6(reg);
-	case 7:
-		return SAD_PKG7(reg);
-	default:
-		return -EINVAL;
-	}
+	return GET_BITFIELD(reg, table[interleave].start,
+			    table[interleave].end);
 }
 
 /* Devices 12 Function 7 */
@@ -262,6 +252,7 @@ struct sbridge_info {
 	u64		(*get_tohm)(struct sbridge_pvt *pvt);	
 	const u32	*dram_rule;
 	const u32	*interleave_list;
+	const struct interleave_pkg *interleave_pkg;
 	u8		max_sad;
 	u8		max_interleave;
 };
@@ -683,13 +674,14 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 
 		pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
 				      &reg);
-		sad_interl = sad_pkg(reg, 0);
+		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
 		for (j = 0; j < 8; j++) {
-			if (j > 0 && sad_interl == sad_pkg(reg, j))
+			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, j);
+			if (j > 0 && sad_interl == pkg)
 				break;
 
 			edac_dbg(0, "SAD#%d, interleave #%d: %d\n",
-				 n_sads, j, sad_pkg(reg, j));
+				 n_sads, j, pkg);
 		}
 	}
 
@@ -857,11 +849,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 
 	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
 			      &reg);
-	sad_interl = sad_pkg(reg, 0);
+	sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
 	for (sad_way = 0; sad_way < 8; sad_way++) {
-		if (sad_way > 0 && sad_interl == sad_pkg(reg, sad_way))
+		u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way);
+		if (sad_way > 0 && sad_interl == pkg)
 			break;
-		sad_interleave[sad_way] = sad_pkg(reg, sad_way);
+		sad_interleave[sad_way] = pkg;
 		edac_dbg(0, "SAD interleave #%d: %d\n",
 			 sad_way, sad_interleave[sad_way]);
 	}
@@ -1667,6 +1660,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
 	pvt->info.interleave_list = sbridge_interleave_list;
 	pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
+	pvt->info.interleave_pkg = sbridge_interleave_pkg;
 
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = sbridge_check_error;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 09/12] sb_edac: enable multiple PCI id tables to be used
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (7 preceding siblings ...)
  2013-10-30 16:27 ` [PATCH 08/12] sb_edac: rework sad_pkg Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 10/12] sb_edac: rename mci_bind_devs() Aristeu Rozanski
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is needed to allow separated PCI id tables for Sandy Bridge and Ivy
Bridge.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |   22 +++++++++++++---------
 1 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index bf305a2..3e07c28 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1088,12 +1088,6 @@ static void sbridge_put_all_devices(void)
 	}
 }
 
-/*
- *	sbridge_get_all_devices	Find and perform 'get' operation on the MCH's
- *			device/functions we want to reference for this driver
- *
- *			Need to 'get' device 16 func 1 and func 2
- */
 static int sbridge_get_onedevice(struct pci_dev **prev,
 				 u8 *num_mc,
 				 const struct pci_id_table *table,
@@ -1195,11 +1189,21 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 	return 0;
 }
 
-static int sbridge_get_all_devices(u8 *num_mc)
+/*
+ * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's
+ *			     device/functions we want to reference for this driver.
+ *			     Need to 'get' device 16 func 1 and func 2.
+ * @num_mc: pointer to the memory controllers count, to be incremented in case
+ * 	    of success.
+ * @table: model specific table
+ *
+ * returns 0 in case of success or error code
+ */
+static int sbridge_get_all_devices(u8 *num_mc,
+				   const struct pci_id_table *table)
 {
 	int i, rc;
 	struct pci_dev *pdev = NULL;
-	const struct pci_id_table *table = pci_dev_descr_sbridge_table;
 
 	while (table && table->descr) {
 		for (i = 0; i < table->n_devs; i++) {
@@ -1719,7 +1723,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	}
 	probed++;
 
-	rc = sbridge_get_all_devices(&num_mc);
+	rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
 	if (unlikely(rc < 0))
 		goto fail0;
 	mc = 0;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 10/12] sb_edac: rename mci_bind_devs()
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (8 preceding siblings ...)
  2013-10-30 16:27 ` [PATCH 09/12] sb_edac: enable multiple PCI id tables to be used Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 11/12] sb_edac: avoid decoding the same error multiple times Aristeu Rozanski
  2013-10-30 16:27 ` [PATCH 12/12] sb_edac: add support for Ivy Bridge Aristeu Rozanski
  11 siblings, 0 replies; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

This is in preparation for Ivy Bridge support

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 3e07c28..2e977b9 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1227,8 +1227,8 @@ static int sbridge_get_all_devices(u8 *num_mc,
 	return 0;
 }
 
-static int mci_bind_devs(struct mem_ctl_info *mci,
-			 struct sbridge_dev *sbridge_dev)
+static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
+				 struct sbridge_dev *sbridge_dev)
 {
 	struct sbridge_pvt *pvt = mci->pvt_info;
 	struct pci_dev *pdev;
@@ -1670,7 +1670,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	mci->edac_check = sbridge_check_error;
 
 	/* Store pci devices at mci for faster access */
-	rc = mci_bind_devs(mci, sbridge_dev);
+	rc = sbridge_mci_bind_devs(mci, sbridge_dev);
 	if (unlikely(rc < 0))
 		goto fail0;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 11/12] sb_edac: avoid decoding the same error multiple times
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (9 preceding siblings ...)
  2013-10-30 16:27 ` [PATCH 10/12] sb_edac: rename mci_bind_devs() Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 17:21   ` Mauro Carvalho Chehab
  2013-10-30 16:27 ` [PATCH 12/12] sb_edac: add support for Ivy Bridge Aristeu Rozanski
  11 siblings, 1 reply; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

Whenever the extended error reporting is active, multiple MCEs will be
generated for the same event, which will lead to multiple repeated
errors to be reported. So check ADDRV and only decode the error if the
MCE address is valid.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 2e977b9..3c2f52b 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -1410,6 +1410,10 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 		}
 	}
 
+	/* Only decode errors with an valid address (ADDRV) */
+	if (!GET_BITFIELD(m->status, 58, 58))
+		return;
+
 	rc = get_memory_error_data(mci, m->addr, &socket,
 				   &channel_mask, &rank, &area_type, msg);
 	if (rc < 0)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 12/12] sb_edac: add support for Ivy Bridge
       [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
                   ` (10 preceding siblings ...)
  2013-10-30 16:27 ` [PATCH 11/12] sb_edac: avoid decoding the same error multiple times Aristeu Rozanski
@ 2013-10-30 16:27 ` Aristeu Rozanski
  2013-10-30 17:25   ` Mauro Carvalho Chehab
  11 siblings, 1 reply; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 16:27 UTC (permalink / raw)
  To: linux-edac
  Cc: tony.luck, Aristeu Rozanski, Mauro Carvalho Chehab,
	Doug Thompson, open list

Since Ivy Bridge memory controller is very similar to Sandy Bridge, it's
wiser to modify sb_edac to support both instead of creating another
driver.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
---
 drivers/edac/sb_edac.c |  447 ++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 377 insertions(+), 70 deletions(-)

diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 3c2f52b..09bf76f 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -34,7 +34,7 @@ static int probed;
 /*
  * Alter this version for the module when modifications are made
  */
-#define SBRIDGE_REVISION    " Ver: 1.0.0 "
+#define SBRIDGE_REVISION    " Ver: 1.1.0 "
 #define EDAC_MOD_STR      "sbridge_edac"
 
 /*
@@ -71,6 +71,14 @@ static const u32 sbridge_dram_rule[] = {
 	0xa8, 0xb0, 0xb8, 0xc0, 0xc8,
 };
 
+static const u32 ibridge_dram_rule[] =
+{
+	0x60, 0x68, 0x70, 0x78, 0x80,
+	0x88, 0x90, 0x98, 0xa0,	0xa8,
+	0xb0, 0xb8, 0xc0, 0xc8, 0xd0,
+	0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
+};
+
 #define SAD_LIMIT(reg)		((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)
 #define DRAM_ATTR(reg)		GET_BITFIELD(reg, 2,  3)
 #define INTERLEAVE_MODE(reg)	GET_BITFIELD(reg, 1,  1)
@@ -95,6 +103,13 @@ static const u32 sbridge_interleave_list[] = {
 	0xac, 0xb4, 0xbc, 0xc4, 0xcc,
 };
 
+static const u32 ibridge_interleave_list[] = {
+	0x64, 0x6c, 0x74, 0x7c, 0x84,
+	0x8c, 0x94, 0x9c, 0xa4, 0xac,
+	0xb4, 0xbc, 0xc4, 0xcc, 0xd4,
+	0xdc, 0xe4, 0xec, 0xf4, 0xfc,
+};
+
 struct interleave_pkg {
 	unsigned char start;
 	unsigned char end;
@@ -111,6 +126,17 @@ static const struct interleave_pkg sbridge_interleave_pkg[] = {
 	{ 27, 29 },
 };
 
+static const struct interleave_pkg ibridge_interleave_pkg[] = {
+	{ 0, 3 },
+	{ 4, 7 },
+	{ 8, 11 },
+	{ 12, 15 },
+	{ 16, 19 },
+	{ 20, 23 },
+	{ 24, 27 },
+	{ 28, 31 },
+};
+
 static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 			  int interleave)
 {
@@ -235,6 +261,8 @@ static const u32 correrrthrsld[] = {
 
 #define SB_RANK_CFG_A		0x0328
 
+#define IB_RANK_CFG_A		0x0320
+
 #define IS_RDIMM_ENABLED(reg)		GET_BITFIELD(reg, 11, 11)
 
 /*
@@ -244,8 +272,14 @@ static const u32 correrrthrsld[] = {
 #define NUM_CHANNELS	4
 #define MAX_DIMMS	3		/* Max DIMMS per channel */
 
+enum type {
+	SANDY_BRIDGE,
+	IVY_BRIDGE,
+};
+
 struct sbridge_pvt;
 struct sbridge_info {
+	enum type	type;
 	u32		mcmtr;
 	u32		rankcfgr;	
 	u64		(*get_tolm)(struct sbridge_pvt *pvt);
@@ -285,8 +319,9 @@ struct sbridge_dev {
 
 struct sbridge_pvt {
 	struct pci_dev		*pci_ta, *pci_ddrio, *pci_ras;
-	struct pci_dev		*pci_sad0, *pci_sad1, *pci_ha0;
-	struct pci_dev		*pci_br0;
+	struct pci_dev		*pci_sad0, *pci_sad1;
+	struct pci_dev		*pci_ha0, *pci_ha1;
+	struct pci_dev		*pci_br0, *pci_br1;
 	struct pci_dev		*pci_tad[NUM_CHANNELS];
 
 	struct sbridge_dev	*sbridge_dev;
@@ -344,11 +379,75 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
 	{0,}			/* 0 terminated list. */
 };
 
+/* This changes depending if 1HA or 2HA:
+ * 1HA:
+ *	0x0eb8 (17.0) is DDRIO0
+ * 2HA:
+ * 	0x0ebc (17.4) is DDRIO0
+ */
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0	0x0eb8
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0	0x0ebc
+
+/* pci ids */
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0		0x0ea0
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA		0x0ea8
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS		0x0e71
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0	0x0eaa
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1	0x0eab
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2	0x0eac
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3	0x0ead
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_SAD			0x0ec8
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR0			0x0ec9
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR1			0x0eca
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1		0x0e60
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA		0x0e68
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS		0x0e79
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0	0x0e6a
+#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1	0x0e6b
+
+static const struct pci_id_descr pci_dev_descr_ibridge[] = {
+		/* Processor Home Agent */
+	{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)	},
+
+		/* Memory controller */
+	{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)	},
+	{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)	},
+	{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)	},
+	{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)	},
+	{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)	},
+	{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)	},
+
+		/* System Address Decoder */
+	{ PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)		},
+
+		/* Broadcast Registers */
+	{ PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)		},
+	{ PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)		},
+
+		/* Optional, mode 2HA */
+	{ PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)	},
+#if 0
+	{ PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)	},
+	{ PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)	},
+#endif
+	{ PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)	},
+	{ PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)	},
+
+	{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) },
+	{ PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) },
+};
+
+static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
+	PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge),
+	{0,}			/* 0 terminated list. */
+};
+
 /*
  *	pci_device_id	table for which devices we are looking for
  */
 static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
 	{0,}			/* 0 terminated list. */
 };
 
@@ -455,6 +554,35 @@ static u64 sbridge_get_tohm(struct sbridge_pvt *pvt)
 	return GET_TOHM(reg);
 }
 
+static u64 ibridge_get_tolm(struct sbridge_pvt *pvt)
+{
+	u32 reg;
+
+	pci_read_config_dword(pvt->pci_br1, TOLM, &reg);
+
+	return GET_TOLM(reg);
+}
+
+static u64 ibridge_get_tohm(struct sbridge_pvt *pvt)
+{
+	u32 reg;
+
+	pci_read_config_dword(pvt->pci_br1, TOHM, &reg);
+
+	return GET_TOHM(reg);
+}
+
+static inline u8 sad_pkg_socket(u8 pkg)
+{
+	/* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */
+	return (pkg >> 3) | (pkg & 0x3);
+}
+
+static inline u8 sad_pkg_ha(u8 pkg)
+{
+	return (pkg >> 2) & 0x1;
+}
+
 /****************************************************************************
 			Memory check routines
  ****************************************************************************/
@@ -517,8 +645,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 	enum edac_type mode;
 	enum mem_type mtype;
 
-	pvt->info.rankcfgr = SB_RANK_CFG_A;
-
 	pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
 	pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
@@ -793,12 +919,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 {
 	struct mem_ctl_info	*new_mci;
 	struct sbridge_pvt *pvt = mci->pvt_info;
+	struct pci_dev		*pci_ha;
 	int 			n_rir, n_sads, n_tads, sad_way, sck_xch;
 	int			sad_interl, idx, base_ch;
 	int			interleave_mode;
 	unsigned		sad_interleave[pvt->info.max_interleave];
 	u32			reg;
-	u8			ch_way,sck_way;
+	u8			ch_way,sck_way,pkg,sad_ha = 0;
 	u32			tad_offset;
 	u32			rir_way;
 	u32			mb, kb;
@@ -849,45 +976,56 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 
 	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
 			      &reg);
-	sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
-	for (sad_way = 0; sad_way < 8; sad_way++) {
-		u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way);
-		if (sad_way > 0 && sad_interl == pkg)
+
+	if (pvt->info.type == SANDY_BRIDGE) {
+		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
+		for (sad_way = 0; sad_way < 8; sad_way++) {
+			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way);
+			if (sad_way > 0 && sad_interl == pkg)
+				break;
+			sad_interleave[sad_way] = pkg;
+			edac_dbg(0, "SAD interleave #%d: %d\n",
+				 sad_way, sad_interleave[sad_way]);
+		}
+		edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
+			 pvt->sbridge_dev->mc,
+			 n_sads,
+			 addr,
+			 limit,
+			 sad_way + 7,
+			 !interleave_mode ? "" : "XOR[18:16]");
+		if (interleave_mode)
+			idx = ((addr >> 6) ^ (addr >> 16)) & 7;
+		else
+			idx = (addr >> 6) & 7;
+		switch (sad_way) {
+		case 1:
+			idx = 0;
 			break;
-		sad_interleave[sad_way] = pkg;
-		edac_dbg(0, "SAD interleave #%d: %d\n",
-			 sad_way, sad_interleave[sad_way]);
-	}
-	edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
-		 pvt->sbridge_dev->mc,
-		 n_sads,
-		 addr,
-		 limit,
-		 sad_way + 7,
-		 interleave_mode ? "" : "XOR[18:16]");
-	if (interleave_mode)
-		idx = ((addr >> 6) ^ (addr >> 16)) & 7;
-	else
+		case 2:
+			idx = idx & 1;
+			break;
+		case 4:
+			idx = idx & 3;
+			break;
+		case 8:
+			break;
+		default:
+			sprintf(msg, "Can't discover socket interleave");
+			return -EINVAL;
+		}
+		*socket = sad_interleave[idx];
+		edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
+			 idx, sad_way, *socket);
+	} else {
+		/* Ivy Bridge's SAD mode doesn't support XOR interleave mode */
 		idx = (addr >> 6) & 7;
-	switch (sad_way) {
-	case 1:
-		idx = 0;
-		break;
-	case 2:
-		idx = idx & 1;
-		break;
-	case 4:
-		idx = idx & 3;
-		break;
-	case 8:
-		break;
-	default:
-		sprintf(msg, "Can't discover socket interleave");
-		return -EINVAL;
+		pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
+		*socket = sad_pkg_socket(pkg);
+		sad_ha = sad_pkg_ha(pkg);
+		edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n",
+			 idx, *socket, sad_ha);
 	}
-	*socket = sad_interleave[idx];
-	edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
-		 idx, sad_way, *socket);
 
 	/*
 	 * Move to the proper node structure, in order to access the
@@ -906,9 +1044,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 	 * Step 2) Get memory channel
 	 */
 	prv = 0;
+	if (pvt->info.type == SANDY_BRIDGE)
+		pci_ha = pvt->pci_ha0;
+	else {
+		if (sad_ha)
+			pci_ha = pvt->pci_ha1;
+		else
+			pci_ha = pvt->pci_ha0;
+	}
 	for (n_tads = 0; n_tads < MAX_TAD; n_tads++) {
-		pci_read_config_dword(pvt->pci_ha0, tad_dram_rule[n_tads],
-				      &reg);
+		pci_read_config_dword(pci_ha, tad_dram_rule[n_tads], &reg);
 		limit = TAD_LIMIT(reg);
 		if (limit <= prv) {
 			sprintf(msg, "Can't discover the memory channel");
@@ -918,14 +1063,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 			break;
 		prv = limit;
 	}
+	if (n_tads == MAX_TAD) {
+		sprintf(msg, "Can't discover the memory channel");
+		return -EINVAL;
+	}
+
 	ch_way = TAD_CH(reg) + 1;
 	sck_way = TAD_SOCK(reg) + 1;
-	/*
-	 * FIXME: Is it right to always use channel 0 for offsets?
-	 */
-	pci_read_config_dword(pvt->pci_tad[0],
-				tad_ch_nilv_offset[n_tads],
-				&tad_offset);
 
 	if (ch_way == 3)
 		idx = addr >> 6;
@@ -955,6 +1099,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 	}
 	*channel_mask = 1 << base_ch;
 
+	pci_read_config_dword(pvt->pci_tad[base_ch],
+				tad_ch_nilv_offset[n_tads],
+				&tad_offset);
+
 	if (pvt->is_mirrored) {
 		*channel_mask |= 1 << ((base_ch + 2) % 4);
 		switch(ch_way) {
@@ -1330,6 +1478,131 @@ error:
 	return -EINVAL;
 }
 
+static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
+				 struct sbridge_dev *sbridge_dev)
+{
+	struct sbridge_pvt *pvt = mci->pvt_info;
+	struct pci_dev *pdev, *tmp;
+	int i, func, slot;
+	bool mode_2ha = false;
+
+	tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
+			     PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, NULL);
+	if (tmp) {
+		mode_2ha = true;
+		pci_dev_put(tmp);
+	}
+
+	for (i = 0; i < sbridge_dev->n_devs; i++) {
+		pdev = sbridge_dev->pdev[i];
+		if (!pdev)
+			continue;
+		slot = PCI_SLOT(pdev->devfn);
+		func = PCI_FUNC(pdev->devfn);
+
+		switch (slot) {
+		case 14:
+			if (func == 0) {
+				pvt->pci_ha0 = pdev;
+				break;
+			}
+			goto error;
+		case 15:
+			switch (func) {
+			case 0:
+				pvt->pci_ta = pdev;
+				break;
+			case 1:
+				pvt->pci_ras = pdev;
+				break;
+			case 4:
+			case 5:
+				/* if we have 2 HAs active, channels 2 and 3
+				 * are in other device */
+				if (mode_2ha)
+					break;
+				/* fall through */
+			case 2:
+			case 3:
+				pvt->pci_tad[func - 2] = pdev;
+				break;
+			default:
+				goto error;
+			}
+			break;
+		case 17:
+			if (func == 4) {
+				pvt->pci_ddrio = pdev;
+				break;
+			} else if (func == 0) {
+				if (!mode_2ha)
+					pvt->pci_ddrio = pdev;
+				break;
+			}
+			goto error;
+		case 22:
+			switch (func) {
+			case 0:
+				pvt->pci_sad0 = pdev;
+				break;
+			case 1:
+				pvt->pci_br0 = pdev;
+				break;
+			case 2:
+				pvt->pci_br1 = pdev;
+				break;
+			default:
+				goto error;
+			}
+			break;
+		case 28:
+			if (func == 0) {
+				pvt->pci_ha1 = pdev;
+				break;
+			}
+			goto error;
+		case 29:
+			/* we shouldn't have this device if we have just one
+			 * HA present */
+			WARN_ON(!mode_2ha);
+			if (func == 2 || func == 3) {
+				pvt->pci_tad[func] = pdev;
+				break;
+			}
+			goto error;
+		default:
+			goto error;
+		}
+
+		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+			 sbridge_dev->bus,
+			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+			 pdev);
+	}
+
+	/* Check if everything were registered */
+	if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 ||
+	    !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras  ||
+	    !pvt->pci_ta)
+		goto enodev;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (!pvt->pci_tad[i])
+			goto enodev;
+	}
+	return 0;
+
+enodev:
+	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+	return -ENODEV;
+
+error:
+	sbridge_printk(KERN_ERR, "Device %d, function %d "
+		      "is out of the expected range\n",
+		      slot, func);
+	return -EINVAL;
+}
+
 /****************************************************************************
 			Error check routines
  ****************************************************************************/
@@ -1350,7 +1623,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
 	bool overflow = GET_BITFIELD(m->status, 62, 62);
 	bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
-	bool recoverable = GET_BITFIELD(m->status, 56, 56);
+	bool recoverable;
 	u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52);
 	u32 mscod = GET_BITFIELD(m->status, 16, 31);
 	u32 errcode = GET_BITFIELD(m->status, 0, 15);
@@ -1361,6 +1634,11 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	int rc, dimm;
 	char *area_type = NULL;
 
+	if (pvt->info.type == IVY_BRIDGE)
+		recoverable = true;
+	else
+		recoverable = GET_BITFIELD(m->status, 56, 56);
+
 	if (uncorrected_error) {
 		if (ripv) {
 			type = "FATAL";
@@ -1619,11 +1897,12 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 	sbridge_dev->mci = NULL;
 }
 
-static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
+static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
 {
 	struct mem_ctl_info *mci;
 	struct edac_mc_layer layers[2];
 	struct sbridge_pvt *pvt;
+	struct pci_dev *pdev = sbridge_dev->pdev[0];
 	int rc;
 
 	/* Check the number of active and not disabled channels */
@@ -1645,7 +1924,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 		return -ENOMEM;
 
 	edac_dbg(0, "MC: mci = %p, dev = %p\n",
-		 mci, &sbridge_dev->pdev[0]->dev);
+		 mci, &pdev->dev);
 
 	pvt = mci->pvt_info;
 	memset(pvt, 0, sizeof(*pvt));
@@ -1659,31 +1938,52 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	mci->edac_cap = EDAC_FLAG_NONE;
 	mci->mod_name = "sbridge_edac.c";
 	mci->mod_ver = SBRIDGE_REVISION;
-	mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
-	mci->dev_name = pci_name(sbridge_dev->pdev[0]);
+	mci->dev_name = pci_name(pdev);
 	mci->ctl_page_to_phys = NULL;
-	pvt->info.get_tolm = sbridge_get_tolm;
-	pvt->info.get_tohm = sbridge_get_tohm;
-	pvt->info.dram_rule = sbridge_dram_rule;
-	pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
-	pvt->info.interleave_list = sbridge_interleave_list;
-	pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
-	pvt->info.interleave_pkg = sbridge_interleave_pkg;
 
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = sbridge_check_error;
 
-	/* Store pci devices at mci for faster access */
-	rc = sbridge_mci_bind_devs(mci, sbridge_dev);
-	if (unlikely(rc < 0))
-		goto fail0;
+	pvt->info.type = type;
+	if (type == IVY_BRIDGE) {
+		pvt->info.rankcfgr = IB_RANK_CFG_A;
+		pvt->info.get_tolm = ibridge_get_tolm;
+		pvt->info.get_tohm = ibridge_get_tohm;
+		pvt->info.dram_rule = ibridge_dram_rule;
+		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
+		pvt->info.interleave_list = ibridge_interleave_list;
+		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
+		pvt->info.interleave_pkg = ibridge_interleave_pkg;
+		mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx);
+
+		/* Store pci devices at mci for faster access */
+		rc = ibridge_mci_bind_devs(mci, sbridge_dev);
+		if (unlikely(rc < 0))
+			goto fail0;
+	} else {
+		pvt->info.rankcfgr = SB_RANK_CFG_A;
+		pvt->info.get_tolm = sbridge_get_tolm;
+		pvt->info.get_tohm = sbridge_get_tohm;
+		pvt->info.dram_rule = sbridge_dram_rule;
+		pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
+		pvt->info.interleave_list = sbridge_interleave_list;
+		pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
+		pvt->info.interleave_pkg = sbridge_interleave_pkg;
+		mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
+
+		/* Store pci devices at mci for faster access */
+		rc = sbridge_mci_bind_devs(mci, sbridge_dev);
+		if (unlikely(rc < 0))
+			goto fail0;
+	}
+
 
 	/* Get dimm basic config and the memory layout */
 	get_dimm_config(mci);
 	get_memory_layout(mci);
 
 	/* record ptr to the generic device */
-	mci->pdev = &sbridge_dev->pdev[0]->dev;
+	mci->pdev = &pdev->dev;
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (unlikely(edac_mc_add_mc(mci))) {
@@ -1714,6 +2014,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	int rc;
 	u8 mc, num_mc = 0;
 	struct sbridge_dev *sbridge_dev;
+	enum type type;
 
 	/* get the pci devices we want to reserve for our use */
 	mutex_lock(&sbridge_edac_lock);
@@ -1727,7 +2028,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	}
 	probed++;
 
-	rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
+	if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) {
+		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
+		type = IVY_BRIDGE;
+	} else {
+		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
+		type = SANDY_BRIDGE;
+	}
 	if (unlikely(rc < 0))
 		goto fail0;
 	mc = 0;
@@ -1736,7 +2043,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		edac_dbg(0, "Registering MC#%d (%d of %d)\n",
 			 mc, mc + 1, num_mc);
 		sbridge_dev->mc = mc++;
-		rc = sbridge_register_mci(sbridge_dev);
+		rc = sbridge_register_mci(sbridge_dev, type);
 		if (unlikely(rc < 0))
 			goto fail1;
 	}
@@ -1851,5 +2158,5 @@ MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge memory controllers - "
+MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - "
 		   SBRIDGE_REVISION);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h
  2013-10-30 16:26 ` [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h Aristeu Rozanski
@ 2013-10-30 16:40   ` Borislav Petkov
  2013-10-30 17:19     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 19+ messages in thread
From: Borislav Petkov @ 2013-10-30 16:40 UTC (permalink / raw)
  To: Aristeu Rozanski
  Cc: linux-edac, tony.luck, Mauro Carvalho Chehab, Doug Thompson,
	Bjorn Helgaas, open list, open list:PCI SUBSYSTEM

On Wed, Oct 30, 2013 at 12:26:55PM -0400, Aristeu Rozanski wrote:
> According to the comment, it should be done before submitting upstream.
> 
> Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
> ---
>  drivers/edac/sb_edac.c  |   21 ++-------------------
>  include/linux/pci_ids.h |   11 +++++++++++
>  2 files changed, 13 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
> index e04462b..4cdd948 100644
> --- a/drivers/edac/sb_edac.c
> +++ b/drivers/edac/sb_edac.c
> @@ -57,26 +57,9 @@ static int probed;
>   */
>  
>  /*
> - * FIXME: For now, let's order by device function, as it makes
> - * easier for driver's development process. This table should be
> - * moved to pci_id.h when submitted upstream

Why, is anything else besides sb_edac.c using those?

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h
  2013-10-30 16:40   ` Borislav Petkov
@ 2013-10-30 17:19     ` Mauro Carvalho Chehab
  2013-10-30 17:21       ` Bjorn Helgaas
  0 siblings, 1 reply; 19+ messages in thread
From: Mauro Carvalho Chehab @ 2013-10-30 17:19 UTC (permalink / raw)
  To: Aristeu Rozanski
  Cc: Borislav Petkov, linux-edac, tony.luck, Doug Thompson,
	Bjorn Helgaas, open list, open list:PCI SUBSYSTEM

Em Wed, 30 Oct 2013 17:40:20 +0100
Borislav Petkov <bp@alien8.de> escreveu:

> On Wed, Oct 30, 2013 at 12:26:55PM -0400, Aristeu Rozanski wrote:
> > According to the comment, it should be done before submitting upstream.
> > 
> > Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
> > ---
> >  drivers/edac/sb_edac.c  |   21 ++-------------------
> >  include/linux/pci_ids.h |   11 +++++++++++
> >  2 files changed, 13 insertions(+), 19 deletions(-)
> > 
> > diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
> > index e04462b..4cdd948 100644
> > --- a/drivers/edac/sb_edac.c
> > +++ b/drivers/edac/sb_edac.c
> > @@ -57,26 +57,9 @@ static int probed;
> >   */
> >  
> >  /*
> > - * FIXME: For now, let's order by device function, as it makes
> > - * easier for driver's development process. This table should be
> > - * moved to pci_id.h when submitted upstream
> 
> Why, is anything else besides sb_edac.c using those?
> 
I think that this patch makes sense, as the other Sandy Bridge registers
are at pci_ids.h. So, it is a matter of consistency.

Also, I won't doubt that other drivers could need to access those, as
there are other things there on a few of those PCI IDs.

Yet, on patch 12/12, you're adding the Ivy Bridge specific PCI IDs
inside the driver.

So, IMHO, you should either move all to pci_ids.h or to keep them inside
the driver.

My personal taste would be to move them all to pci_ids.h.

Regards,
Mauro

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 11/12] sb_edac: avoid decoding the same error multiple times
  2013-10-30 16:27 ` [PATCH 11/12] sb_edac: avoid decoding the same error multiple times Aristeu Rozanski
@ 2013-10-30 17:21   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 19+ messages in thread
From: Mauro Carvalho Chehab @ 2013-10-30 17:21 UTC (permalink / raw)
  To: Aristeu Rozanski; +Cc: linux-edac, tony.luck, Doug Thompson, open list

Em Wed, 30 Oct 2013 12:27:05 -0400
Aristeu Rozanski <arozansk@redhat.com> escreveu:

> Whenever the extended error reporting is active, multiple MCEs will be
> generated for the same event, which will lead to multiple repeated
> errors to be reported. So check ADDRV and only decode the error if the
> MCE address is valid.
> 
> Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>

For patches 2 to 11 on this series:

Reviewed-by: Mauro Carvalho Chehab <m.chehab@samsung.com>

> ---
>  drivers/edac/sb_edac.c |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
> index 2e977b9..3c2f52b 100644
> --- a/drivers/edac/sb_edac.c
> +++ b/drivers/edac/sb_edac.c
> @@ -1410,6 +1410,10 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
>  		}
>  	}
>  
> +	/* Only decode errors with an valid address (ADDRV) */
> +	if (!GET_BITFIELD(m->status, 58, 58))
> +		return;
> +
>  	rc = get_memory_error_data(mci, m->addr, &socket,
>  				   &channel_mask, &rank, &area_type, msg);
>  	if (rc < 0)


-- 

Cheers,
Mauro

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h
  2013-10-30 17:19     ` Mauro Carvalho Chehab
@ 2013-10-30 17:21       ` Bjorn Helgaas
  2013-10-30 20:35         ` Aristeu Rozanski
  0 siblings, 1 reply; 19+ messages in thread
From: Bjorn Helgaas @ 2013-10-30 17:21 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Aristeu Rozanski, Borislav Petkov, linux-edac, Tony Luck,
	Doug Thompson, open list, open list:PCI SUBSYSTEM

On Wed, Oct 30, 2013 at 11:19 AM, Mauro Carvalho Chehab
<m.chehab@samsung.com> wrote:
> Em Wed, 30 Oct 2013 17:40:20 +0100
> Borislav Petkov <bp@alien8.de> escreveu:
>
>> On Wed, Oct 30, 2013 at 12:26:55PM -0400, Aristeu Rozanski wrote:
>> > According to the comment, it should be done before submitting upstream.
>> >
>> > Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
>> > ---
>> >  drivers/edac/sb_edac.c  |   21 ++-------------------
>> >  include/linux/pci_ids.h |   11 +++++++++++
>> >  2 files changed, 13 insertions(+), 19 deletions(-)
>> >
>> > diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
>> > index e04462b..4cdd948 100644
>> > --- a/drivers/edac/sb_edac.c
>> > +++ b/drivers/edac/sb_edac.c
>> > @@ -57,26 +57,9 @@ static int probed;
>> >   */
>> >
>> >  /*
>> > - * FIXME: For now, let's order by device function, as it makes
>> > - * easier for driver's development process. This table should be
>> > - * moved to pci_id.h when submitted upstream
>>
>> Why, is anything else besides sb_edac.c using those?
>>
> I think that this patch makes sense, as the other Sandy Bridge registers
> are at pci_ids.h. So, it is a matter of consistency.
>
> Also, I won't doubt that other drivers could need to access those, as
> there are other things there on a few of those PCI IDs.
>
> Yet, on patch 12/12, you're adding the Ivy Bridge specific PCI IDs
> inside the driver.
>
> So, IMHO, you should either move all to pci_ids.h or to keep them inside
> the driver.
>
> My personal taste would be to move them all to pci_ids.h.

As long as it follows the guideline at the top of pci_ids.h (add them
there only if they are shared between multiple drivers), I'm fine with
putting them in pci_ids.h.

Bjorn

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 12/12] sb_edac: add support for Ivy Bridge
  2013-10-30 16:27 ` [PATCH 12/12] sb_edac: add support for Ivy Bridge Aristeu Rozanski
@ 2013-10-30 17:25   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 19+ messages in thread
From: Mauro Carvalho Chehab @ 2013-10-30 17:25 UTC (permalink / raw)
  To: Aristeu Rozanski; +Cc: linux-edac, tony.luck, Doug Thompson, open list

Em Wed, 30 Oct 2013 12:27:06 -0400
Aristeu Rozanski <arozansk@redhat.com> escreveu:

> Since Ivy Bridge memory controller is very similar to Sandy Bridge, it's
> wiser to modify sb_edac to support both instead of creating another
> driver.

Nice patch! Yeah, it is a way better to reuse the existing driver than
to create another one.

Provided that you fix the minor issue with the PCI IDs, for patches 1 and 12:

Reviewed-by: Mauro Carvalho Chehab <m.chehab@samsung.com>

> 
> Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
> ---
>  drivers/edac/sb_edac.c |  447 ++++++++++++++++++++++++++++++++++++++++--------
>  1 files changed, 377 insertions(+), 70 deletions(-)
> 
> diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
> index 3c2f52b..09bf76f 100644
> --- a/drivers/edac/sb_edac.c
> +++ b/drivers/edac/sb_edac.c
> @@ -34,7 +34,7 @@ static int probed;
>  /*
>   * Alter this version for the module when modifications are made
>   */
> -#define SBRIDGE_REVISION    " Ver: 1.0.0 "
> +#define SBRIDGE_REVISION    " Ver: 1.1.0 "
>  #define EDAC_MOD_STR      "sbridge_edac"
>  
>  /*
> @@ -71,6 +71,14 @@ static const u32 sbridge_dram_rule[] = {
>  	0xa8, 0xb0, 0xb8, 0xc0, 0xc8,
>  };
>  
> +static const u32 ibridge_dram_rule[] =
> +{
> +	0x60, 0x68, 0x70, 0x78, 0x80,
> +	0x88, 0x90, 0x98, 0xa0,	0xa8,
> +	0xb0, 0xb8, 0xc0, 0xc8, 0xd0,
> +	0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
> +};
> +
>  #define SAD_LIMIT(reg)		((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)
>  #define DRAM_ATTR(reg)		GET_BITFIELD(reg, 2,  3)
>  #define INTERLEAVE_MODE(reg)	GET_BITFIELD(reg, 1,  1)
> @@ -95,6 +103,13 @@ static const u32 sbridge_interleave_list[] = {
>  	0xac, 0xb4, 0xbc, 0xc4, 0xcc,
>  };
>  
> +static const u32 ibridge_interleave_list[] = {
> +	0x64, 0x6c, 0x74, 0x7c, 0x84,
> +	0x8c, 0x94, 0x9c, 0xa4, 0xac,
> +	0xb4, 0xbc, 0xc4, 0xcc, 0xd4,
> +	0xdc, 0xe4, 0xec, 0xf4, 0xfc,
> +};
> +
>  struct interleave_pkg {
>  	unsigned char start;
>  	unsigned char end;
> @@ -111,6 +126,17 @@ static const struct interleave_pkg sbridge_interleave_pkg[] = {
>  	{ 27, 29 },
>  };
>  
> +static const struct interleave_pkg ibridge_interleave_pkg[] = {
> +	{ 0, 3 },
> +	{ 4, 7 },
> +	{ 8, 11 },
> +	{ 12, 15 },
> +	{ 16, 19 },
> +	{ 20, 23 },
> +	{ 24, 27 },
> +	{ 28, 31 },
> +};
> +
>  static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
>  			  int interleave)
>  {
> @@ -235,6 +261,8 @@ static const u32 correrrthrsld[] = {
>  
>  #define SB_RANK_CFG_A		0x0328
>  
> +#define IB_RANK_CFG_A		0x0320
> +
>  #define IS_RDIMM_ENABLED(reg)		GET_BITFIELD(reg, 11, 11)
>  
>  /*
> @@ -244,8 +272,14 @@ static const u32 correrrthrsld[] = {
>  #define NUM_CHANNELS	4
>  #define MAX_DIMMS	3		/* Max DIMMS per channel */
>  
> +enum type {
> +	SANDY_BRIDGE,
> +	IVY_BRIDGE,
> +};
> +
>  struct sbridge_pvt;
>  struct sbridge_info {
> +	enum type	type;
>  	u32		mcmtr;
>  	u32		rankcfgr;	
>  	u64		(*get_tolm)(struct sbridge_pvt *pvt);
> @@ -285,8 +319,9 @@ struct sbridge_dev {
>  
>  struct sbridge_pvt {
>  	struct pci_dev		*pci_ta, *pci_ddrio, *pci_ras;
> -	struct pci_dev		*pci_sad0, *pci_sad1, *pci_ha0;
> -	struct pci_dev		*pci_br0;
> +	struct pci_dev		*pci_sad0, *pci_sad1;
> +	struct pci_dev		*pci_ha0, *pci_ha1;
> +	struct pci_dev		*pci_br0, *pci_br1;
>  	struct pci_dev		*pci_tad[NUM_CHANNELS];
>  
>  	struct sbridge_dev	*sbridge_dev;
> @@ -344,11 +379,75 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
>  	{0,}			/* 0 terminated list. */
>  };
>  
> +/* This changes depending if 1HA or 2HA:
> + * 1HA:
> + *	0x0eb8 (17.0) is DDRIO0
> + * 2HA:
> + * 	0x0ebc (17.4) is DDRIO0
> + */
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0	0x0eb8
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0	0x0ebc
> +
> +/* pci ids */
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0		0x0ea0
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA		0x0ea8
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS		0x0e71
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0	0x0eaa
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1	0x0eab
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2	0x0eac
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3	0x0ead
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_SAD			0x0ec8
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR0			0x0ec9
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR1			0x0eca
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1		0x0e60
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA		0x0e68
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS		0x0e79
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0	0x0e6a
> +#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1	0x0e6b

As mentioned on patch 1, please either keep all PCI IDs here, or move
them all to pci_ids.h.

> +
> +static const struct pci_id_descr pci_dev_descr_ibridge[] = {
> +		/* Processor Home Agent */
> +	{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)	},
> +
> +		/* Memory controller */
> +	{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)	},
> +	{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)	},
> +	{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)	},
> +	{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)	},
> +	{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)	},
> +	{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)	},
> +
> +		/* System Address Decoder */
> +	{ PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)		},
> +
> +		/* Broadcast Registers */
> +	{ PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)		},
> +	{ PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)		},
> +
> +		/* Optional, mode 2HA */
> +	{ PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)	},
> +#if 0
> +	{ PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)	},
> +	{ PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)	},
> +#endif
> +	{ PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)	},
> +	{ PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)	},
> +
> +	{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) },
> +	{ PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) },
> +};
> +
> +static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
> +	PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge),
> +	{0,}			/* 0 terminated list. */
> +};
> +
>  /*
>   *	pci_device_id	table for which devices we are looking for
>   */
>  static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
>  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
>  	{0,}			/* 0 terminated list. */
>  };
>  
> @@ -455,6 +554,35 @@ static u64 sbridge_get_tohm(struct sbridge_pvt *pvt)
>  	return GET_TOHM(reg);
>  }
>  
> +static u64 ibridge_get_tolm(struct sbridge_pvt *pvt)
> +{
> +	u32 reg;
> +
> +	pci_read_config_dword(pvt->pci_br1, TOLM, &reg);
> +
> +	return GET_TOLM(reg);
> +}
> +
> +static u64 ibridge_get_tohm(struct sbridge_pvt *pvt)
> +{
> +	u32 reg;
> +
> +	pci_read_config_dword(pvt->pci_br1, TOHM, &reg);
> +
> +	return GET_TOHM(reg);
> +}
> +
> +static inline u8 sad_pkg_socket(u8 pkg)
> +{
> +	/* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */
> +	return (pkg >> 3) | (pkg & 0x3);
> +}
> +
> +static inline u8 sad_pkg_ha(u8 pkg)
> +{
> +	return (pkg >> 2) & 0x1;
> +}
> +
>  /****************************************************************************
>  			Memory check routines
>   ****************************************************************************/
> @@ -517,8 +645,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
>  	enum edac_type mode;
>  	enum mem_type mtype;
>  
> -	pvt->info.rankcfgr = SB_RANK_CFG_A;
> -
>  	pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
>  	pvt->sbridge_dev->source_id = SOURCE_ID(reg);
>  
> @@ -793,12 +919,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
>  {
>  	struct mem_ctl_info	*new_mci;
>  	struct sbridge_pvt *pvt = mci->pvt_info;
> +	struct pci_dev		*pci_ha;
>  	int 			n_rir, n_sads, n_tads, sad_way, sck_xch;
>  	int			sad_interl, idx, base_ch;
>  	int			interleave_mode;
>  	unsigned		sad_interleave[pvt->info.max_interleave];
>  	u32			reg;
> -	u8			ch_way,sck_way;
> +	u8			ch_way,sck_way,pkg,sad_ha = 0;
>  	u32			tad_offset;
>  	u32			rir_way;
>  	u32			mb, kb;
> @@ -849,45 +976,56 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
>  
>  	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
>  			      &reg);
> -	sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
> -	for (sad_way = 0; sad_way < 8; sad_way++) {
> -		u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way);
> -		if (sad_way > 0 && sad_interl == pkg)
> +
> +	if (pvt->info.type == SANDY_BRIDGE) {
> +		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
> +		for (sad_way = 0; sad_way < 8; sad_way++) {
> +			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way);
> +			if (sad_way > 0 && sad_interl == pkg)
> +				break;
> +			sad_interleave[sad_way] = pkg;
> +			edac_dbg(0, "SAD interleave #%d: %d\n",
> +				 sad_way, sad_interleave[sad_way]);
> +		}
> +		edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
> +			 pvt->sbridge_dev->mc,
> +			 n_sads,
> +			 addr,
> +			 limit,
> +			 sad_way + 7,
> +			 !interleave_mode ? "" : "XOR[18:16]");
> +		if (interleave_mode)
> +			idx = ((addr >> 6) ^ (addr >> 16)) & 7;
> +		else
> +			idx = (addr >> 6) & 7;
> +		switch (sad_way) {
> +		case 1:
> +			idx = 0;
>  			break;
> -		sad_interleave[sad_way] = pkg;
> -		edac_dbg(0, "SAD interleave #%d: %d\n",
> -			 sad_way, sad_interleave[sad_way]);
> -	}
> -	edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
> -		 pvt->sbridge_dev->mc,
> -		 n_sads,
> -		 addr,
> -		 limit,
> -		 sad_way + 7,
> -		 interleave_mode ? "" : "XOR[18:16]");
> -	if (interleave_mode)
> -		idx = ((addr >> 6) ^ (addr >> 16)) & 7;
> -	else
> +		case 2:
> +			idx = idx & 1;
> +			break;
> +		case 4:
> +			idx = idx & 3;
> +			break;
> +		case 8:
> +			break;
> +		default:
> +			sprintf(msg, "Can't discover socket interleave");
> +			return -EINVAL;
> +		}
> +		*socket = sad_interleave[idx];
> +		edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
> +			 idx, sad_way, *socket);
> +	} else {
> +		/* Ivy Bridge's SAD mode doesn't support XOR interleave mode */
>  		idx = (addr >> 6) & 7;
> -	switch (sad_way) {
> -	case 1:
> -		idx = 0;
> -		break;
> -	case 2:
> -		idx = idx & 1;
> -		break;
> -	case 4:
> -		idx = idx & 3;
> -		break;
> -	case 8:
> -		break;
> -	default:
> -		sprintf(msg, "Can't discover socket interleave");
> -		return -EINVAL;
> +		pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
> +		*socket = sad_pkg_socket(pkg);
> +		sad_ha = sad_pkg_ha(pkg);
> +		edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n",
> +			 idx, *socket, sad_ha);
>  	}
> -	*socket = sad_interleave[idx];
> -	edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
> -		 idx, sad_way, *socket);
>  
>  	/*
>  	 * Move to the proper node structure, in order to access the
> @@ -906,9 +1044,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
>  	 * Step 2) Get memory channel
>  	 */
>  	prv = 0;
> +	if (pvt->info.type == SANDY_BRIDGE)
> +		pci_ha = pvt->pci_ha0;
> +	else {
> +		if (sad_ha)
> +			pci_ha = pvt->pci_ha1;
> +		else
> +			pci_ha = pvt->pci_ha0;
> +	}
>  	for (n_tads = 0; n_tads < MAX_TAD; n_tads++) {
> -		pci_read_config_dword(pvt->pci_ha0, tad_dram_rule[n_tads],
> -				      &reg);
> +		pci_read_config_dword(pci_ha, tad_dram_rule[n_tads], &reg);
>  		limit = TAD_LIMIT(reg);
>  		if (limit <= prv) {
>  			sprintf(msg, "Can't discover the memory channel");
> @@ -918,14 +1063,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
>  			break;
>  		prv = limit;
>  	}
> +	if (n_tads == MAX_TAD) {
> +		sprintf(msg, "Can't discover the memory channel");
> +		return -EINVAL;
> +	}
> +
>  	ch_way = TAD_CH(reg) + 1;
>  	sck_way = TAD_SOCK(reg) + 1;
> -	/*
> -	 * FIXME: Is it right to always use channel 0 for offsets?
> -	 */
> -	pci_read_config_dword(pvt->pci_tad[0],
> -				tad_ch_nilv_offset[n_tads],
> -				&tad_offset);
>  
>  	if (ch_way == 3)
>  		idx = addr >> 6;
> @@ -955,6 +1099,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
>  	}
>  	*channel_mask = 1 << base_ch;
>  
> +	pci_read_config_dword(pvt->pci_tad[base_ch],
> +				tad_ch_nilv_offset[n_tads],
> +				&tad_offset);
> +
>  	if (pvt->is_mirrored) {
>  		*channel_mask |= 1 << ((base_ch + 2) % 4);
>  		switch(ch_way) {
> @@ -1330,6 +1478,131 @@ error:
>  	return -EINVAL;
>  }
>  
> +static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
> +				 struct sbridge_dev *sbridge_dev)
> +{
> +	struct sbridge_pvt *pvt = mci->pvt_info;
> +	struct pci_dev *pdev, *tmp;
> +	int i, func, slot;
> +	bool mode_2ha = false;
> +
> +	tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
> +			     PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, NULL);
> +	if (tmp) {
> +		mode_2ha = true;
> +		pci_dev_put(tmp);
> +	}
> +
> +	for (i = 0; i < sbridge_dev->n_devs; i++) {
> +		pdev = sbridge_dev->pdev[i];
> +		if (!pdev)
> +			continue;
> +		slot = PCI_SLOT(pdev->devfn);
> +		func = PCI_FUNC(pdev->devfn);
> +
> +		switch (slot) {
> +		case 14:
> +			if (func == 0) {
> +				pvt->pci_ha0 = pdev;
> +				break;
> +			}
> +			goto error;
> +		case 15:
> +			switch (func) {
> +			case 0:
> +				pvt->pci_ta = pdev;
> +				break;
> +			case 1:
> +				pvt->pci_ras = pdev;
> +				break;
> +			case 4:
> +			case 5:
> +				/* if we have 2 HAs active, channels 2 and 3
> +				 * are in other device */
> +				if (mode_2ha)
> +					break;
> +				/* fall through */
> +			case 2:
> +			case 3:
> +				pvt->pci_tad[func - 2] = pdev;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case 17:
> +			if (func == 4) {
> +				pvt->pci_ddrio = pdev;
> +				break;
> +			} else if (func == 0) {
> +				if (!mode_2ha)
> +					pvt->pci_ddrio = pdev;
> +				break;
> +			}
> +			goto error;
> +		case 22:
> +			switch (func) {
> +			case 0:
> +				pvt->pci_sad0 = pdev;
> +				break;
> +			case 1:
> +				pvt->pci_br0 = pdev;
> +				break;
> +			case 2:
> +				pvt->pci_br1 = pdev;
> +				break;
> +			default:
> +				goto error;
> +			}
> +			break;
> +		case 28:
> +			if (func == 0) {
> +				pvt->pci_ha1 = pdev;
> +				break;
> +			}
> +			goto error;
> +		case 29:
> +			/* we shouldn't have this device if we have just one
> +			 * HA present */
> +			WARN_ON(!mode_2ha);
> +			if (func == 2 || func == 3) {
> +				pvt->pci_tad[func] = pdev;
> +				break;
> +			}
> +			goto error;
> +		default:
> +			goto error;
> +		}
> +
> +		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
> +			 sbridge_dev->bus,
> +			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
> +			 pdev);
> +	}
> +
> +	/* Check if everything were registered */
> +	if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 ||
> +	    !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras  ||
> +	    !pvt->pci_ta)
> +		goto enodev;
> +
> +	for (i = 0; i < NUM_CHANNELS; i++) {
> +		if (!pvt->pci_tad[i])
> +			goto enodev;
> +	}
> +	return 0;
> +
> +enodev:
> +	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
> +	return -ENODEV;
> +
> +error:
> +	sbridge_printk(KERN_ERR, "Device %d, function %d "
> +		      "is out of the expected range\n",
> +		      slot, func);
> +	return -EINVAL;
> +}
> +
>  /****************************************************************************
>  			Error check routines
>   ****************************************************************************/
> @@ -1350,7 +1623,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
>  	bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
>  	bool overflow = GET_BITFIELD(m->status, 62, 62);
>  	bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
> -	bool recoverable = GET_BITFIELD(m->status, 56, 56);
> +	bool recoverable;
>  	u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52);
>  	u32 mscod = GET_BITFIELD(m->status, 16, 31);
>  	u32 errcode = GET_BITFIELD(m->status, 0, 15);
> @@ -1361,6 +1634,11 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
>  	int rc, dimm;
>  	char *area_type = NULL;
>  
> +	if (pvt->info.type == IVY_BRIDGE)
> +		recoverable = true;
> +	else
> +		recoverable = GET_BITFIELD(m->status, 56, 56);
> +
>  	if (uncorrected_error) {
>  		if (ripv) {
>  			type = "FATAL";
> @@ -1619,11 +1897,12 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
>  	sbridge_dev->mci = NULL;
>  }
>  
> -static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
> +static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
>  {
>  	struct mem_ctl_info *mci;
>  	struct edac_mc_layer layers[2];
>  	struct sbridge_pvt *pvt;
> +	struct pci_dev *pdev = sbridge_dev->pdev[0];
>  	int rc;
>  
>  	/* Check the number of active and not disabled channels */
> @@ -1645,7 +1924,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
>  		return -ENOMEM;
>  
>  	edac_dbg(0, "MC: mci = %p, dev = %p\n",
> -		 mci, &sbridge_dev->pdev[0]->dev);
> +		 mci, &pdev->dev);
>  
>  	pvt = mci->pvt_info;
>  	memset(pvt, 0, sizeof(*pvt));
> @@ -1659,31 +1938,52 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
>  	mci->edac_cap = EDAC_FLAG_NONE;
>  	mci->mod_name = "sbridge_edac.c";
>  	mci->mod_ver = SBRIDGE_REVISION;
> -	mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
> -	mci->dev_name = pci_name(sbridge_dev->pdev[0]);
> +	mci->dev_name = pci_name(pdev);
>  	mci->ctl_page_to_phys = NULL;
> -	pvt->info.get_tolm = sbridge_get_tolm;
> -	pvt->info.get_tohm = sbridge_get_tohm;
> -	pvt->info.dram_rule = sbridge_dram_rule;
> -	pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
> -	pvt->info.interleave_list = sbridge_interleave_list;
> -	pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
> -	pvt->info.interleave_pkg = sbridge_interleave_pkg;
>  
>  	/* Set the function pointer to an actual operation function */
>  	mci->edac_check = sbridge_check_error;
>  
> -	/* Store pci devices at mci for faster access */
> -	rc = sbridge_mci_bind_devs(mci, sbridge_dev);
> -	if (unlikely(rc < 0))
> -		goto fail0;
> +	pvt->info.type = type;
> +	if (type == IVY_BRIDGE) {
> +		pvt->info.rankcfgr = IB_RANK_CFG_A;
> +		pvt->info.get_tolm = ibridge_get_tolm;
> +		pvt->info.get_tohm = ibridge_get_tohm;
> +		pvt->info.dram_rule = ibridge_dram_rule;
> +		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
> +		pvt->info.interleave_list = ibridge_interleave_list;
> +		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
> +		pvt->info.interleave_pkg = ibridge_interleave_pkg;
> +		mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx);
> +
> +		/* Store pci devices at mci for faster access */
> +		rc = ibridge_mci_bind_devs(mci, sbridge_dev);
> +		if (unlikely(rc < 0))
> +			goto fail0;
> +	} else {
> +		pvt->info.rankcfgr = SB_RANK_CFG_A;
> +		pvt->info.get_tolm = sbridge_get_tolm;
> +		pvt->info.get_tohm = sbridge_get_tohm;
> +		pvt->info.dram_rule = sbridge_dram_rule;
> +		pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
> +		pvt->info.interleave_list = sbridge_interleave_list;
> +		pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
> +		pvt->info.interleave_pkg = sbridge_interleave_pkg;
> +		mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
> +
> +		/* Store pci devices at mci for faster access */
> +		rc = sbridge_mci_bind_devs(mci, sbridge_dev);
> +		if (unlikely(rc < 0))
> +			goto fail0;
> +	}
> +
>  
>  	/* Get dimm basic config and the memory layout */
>  	get_dimm_config(mci);
>  	get_memory_layout(mci);
>  
>  	/* record ptr to the generic device */
> -	mci->pdev = &sbridge_dev->pdev[0]->dev;
> +	mci->pdev = &pdev->dev;
>  
>  	/* add this new MC control structure to EDAC's list of MCs */
>  	if (unlikely(edac_mc_add_mc(mci))) {
> @@ -1714,6 +2014,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	int rc;
>  	u8 mc, num_mc = 0;
>  	struct sbridge_dev *sbridge_dev;
> +	enum type type;
>  
>  	/* get the pci devices we want to reserve for our use */
>  	mutex_lock(&sbridge_edac_lock);
> @@ -1727,7 +2028,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	}
>  	probed++;
>  
> -	rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
> +	if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) {
> +		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
> +		type = IVY_BRIDGE;
> +	} else {
> +		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
> +		type = SANDY_BRIDGE;
> +	}
>  	if (unlikely(rc < 0))
>  		goto fail0;
>  	mc = 0;
> @@ -1736,7 +2043,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  		edac_dbg(0, "Registering MC#%d (%d of %d)\n",
>  			 mc, mc + 1, num_mc);
>  		sbridge_dev->mc = mc++;
> -		rc = sbridge_register_mci(sbridge_dev);
> +		rc = sbridge_register_mci(sbridge_dev, type);
>  		if (unlikely(rc < 0))
>  			goto fail1;
>  	}
> @@ -1851,5 +2158,5 @@ MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
>  MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
> -MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge memory controllers - "
> +MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - "
>  		   SBRIDGE_REVISION);


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h
  2013-10-30 17:21       ` Bjorn Helgaas
@ 2013-10-30 20:35         ` Aristeu Rozanski
  2013-10-30 20:47           ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 19+ messages in thread
From: Aristeu Rozanski @ 2013-10-30 20:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Bjorn Helgaas, Borislav Petkov, linux-edac, Tony Luck,
	Doug Thompson, open list, open list:PCI SUBSYSTEM

On Wed, Oct 30, 2013 at 11:21:49AM -0600, Bjorn Helgaas wrote:
> On Wed, Oct 30, 2013 at 11:19 AM, Mauro Carvalho Chehab
> <m.chehab@samsung.com> wrote:
> > Em Wed, 30 Oct 2013 17:40:20 +0100
> > Borislav Petkov <bp@alien8.de> escreveu:
> >
> >> On Wed, Oct 30, 2013 at 12:26:55PM -0400, Aristeu Rozanski wrote:
> >> > According to the comment, it should be done before submitting upstream.
> >> >
> >> > Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
> >> > ---
> >> >  drivers/edac/sb_edac.c  |   21 ++-------------------
> >> >  include/linux/pci_ids.h |   11 +++++++++++
> >> >  2 files changed, 13 insertions(+), 19 deletions(-)
> >> >
> >> > diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
> >> > index e04462b..4cdd948 100644
> >> > --- a/drivers/edac/sb_edac.c
> >> > +++ b/drivers/edac/sb_edac.c
> >> > @@ -57,26 +57,9 @@ static int probed;
> >> >   */
> >> >
> >> >  /*
> >> > - * FIXME: For now, let's order by device function, as it makes
> >> > - * easier for driver's development process. This table should be
> >> > - * moved to pci_id.h when submitted upstream
> >>
> >> Why, is anything else besides sb_edac.c using those?
> >>
> > I think that this patch makes sense, as the other Sandy Bridge registers
> > are at pci_ids.h. So, it is a matter of consistency.
> >
> > Also, I won't doubt that other drivers could need to access those, as
> > there are other things there on a few of those PCI IDs.
> >
> > Yet, on patch 12/12, you're adding the Ivy Bridge specific PCI IDs
> > inside the driver.
> >
> > So, IMHO, you should either move all to pci_ids.h or to keep them inside
> > the driver.
> >
> > My personal taste would be to move them all to pci_ids.h.
> 
> As long as it follows the guideline at the top of pci_ids.h (add them
> there only if they are shared between multiple drivers), I'm fine with
> putting them in pci_ids.h.

Fair enough, I think we can drop the first patch. I checked and all the
patches apply without the first one and it builds fine. Mauro, want me
to resubmit the patchset anyway?

-- 
Aristeu


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h
  2013-10-30 20:35         ` Aristeu Rozanski
@ 2013-10-30 20:47           ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 19+ messages in thread
From: Mauro Carvalho Chehab @ 2013-10-30 20:47 UTC (permalink / raw)
  To: Aristeu Rozanski
  Cc: Bjorn Helgaas, Borislav Petkov, linux-edac, Tony Luck,
	Doug Thompson, open list, open list:PCI SUBSYSTEM

Em Wed, 30 Oct 2013 16:35:17 -0400
Aristeu Rozanski <arozansk@redhat.com> escreveu:

> On Wed, Oct 30, 2013 at 11:21:49AM -0600, Bjorn Helgaas wrote:
> > On Wed, Oct 30, 2013 at 11:19 AM, Mauro Carvalho Chehab
> > <m.chehab@samsung.com> wrote:
> > > Em Wed, 30 Oct 2013 17:40:20 +0100
> > > Borislav Petkov <bp@alien8.de> escreveu:
> > >
> > >> On Wed, Oct 30, 2013 at 12:26:55PM -0400, Aristeu Rozanski wrote:
> > >> > According to the comment, it should be done before submitting upstream.
> > >> >
> > >> > Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
> > >> > ---
> > >> >  drivers/edac/sb_edac.c  |   21 ++-------------------
> > >> >  include/linux/pci_ids.h |   11 +++++++++++
> > >> >  2 files changed, 13 insertions(+), 19 deletions(-)
> > >> >
> > >> > diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
> > >> > index e04462b..4cdd948 100644
> > >> > --- a/drivers/edac/sb_edac.c
> > >> > +++ b/drivers/edac/sb_edac.c
> > >> > @@ -57,26 +57,9 @@ static int probed;
> > >> >   */
> > >> >
> > >> >  /*
> > >> > - * FIXME: For now, let's order by device function, as it makes
> > >> > - * easier for driver's development process. This table should be
> > >> > - * moved to pci_id.h when submitted upstream
> > >>
> > >> Why, is anything else besides sb_edac.c using those?
> > >>
> > > I think that this patch makes sense, as the other Sandy Bridge registers
> > > are at pci_ids.h. So, it is a matter of consistency.
> > >
> > > Also, I won't doubt that other drivers could need to access those, as
> > > there are other things there on a few of those PCI IDs.
> > >
> > > Yet, on patch 12/12, you're adding the Ivy Bridge specific PCI IDs
> > > inside the driver.
> > >
> > > So, IMHO, you should either move all to pci_ids.h or to keep them inside
> > > the driver.
> > >
> > > My personal taste would be to move them all to pci_ids.h.
> > 
> > As long as it follows the guideline at the top of pci_ids.h (add them
> > there only if they are shared between multiple drivers), I'm fine with
> > putting them in pci_ids.h.
> 
> Fair enough, I think we can drop the first patch. I checked and all the
> patches apply without the first one and it builds fine. Mauro, want me
> to resubmit the patchset anyway?

No need.

Thanks!
Mauro

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2013-10-30 20:47 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1383150426-24730-1-git-send-email-arozansk@redhat.com>
2013-10-30 16:26 ` [PATCH 01/12] sb_edac: move PCI IDs to pci_ids.h Aristeu Rozanski
2013-10-30 16:40   ` Borislav Petkov
2013-10-30 17:19     ` Mauro Carvalho Chehab
2013-10-30 17:21       ` Bjorn Helgaas
2013-10-30 20:35         ` Aristeu Rozanski
2013-10-30 20:47           ` Mauro Carvalho Chehab
2013-10-30 16:26 ` [PATCH 02/12] sb_edac: make RANK_CFG_A value part of sbridge_info Aristeu Rozanski
2013-10-30 16:26 ` [PATCH 03/12] sb_edac: isolate TOLM retrieval Aristeu Rozanski
2013-10-30 16:26 ` [PATCH 04/12] sb_edac: rename pci_br Aristeu Rozanski
2013-10-30 16:26 ` [PATCH 05/12] sb_edac: isolate TOHM retrieval Aristeu Rozanski
2013-10-30 16:27 ` [PATCH 06/12] sb_edac: allow different dram_rule arrays Aristeu Rozanski
2013-10-30 16:27 ` [PATCH 07/12] sb_edac: allow different interleave lists Aristeu Rozanski
2013-10-30 16:27 ` [PATCH 08/12] sb_edac: rework sad_pkg Aristeu Rozanski
2013-10-30 16:27 ` [PATCH 09/12] sb_edac: enable multiple PCI id tables to be used Aristeu Rozanski
2013-10-30 16:27 ` [PATCH 10/12] sb_edac: rename mci_bind_devs() Aristeu Rozanski
2013-10-30 16:27 ` [PATCH 11/12] sb_edac: avoid decoding the same error multiple times Aristeu Rozanski
2013-10-30 17:21   ` Mauro Carvalho Chehab
2013-10-30 16:27 ` [PATCH 12/12] sb_edac: add support for Ivy Bridge Aristeu Rozanski
2013-10-30 17:25   ` Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).