Skip to contentSkip to conversation

Fix EDAC userspace ABI

PATCH In review Mauro Carvalho Chehab 5 participants 63 messages Apr 16, 2012 – May 14, 2012

Subsystems (17)
PowerPC Tracing EDAC-core EDAC-AMD64 +13 more subsystems
lore
Share & tools
lore
#0 lore raw

v13 cover Fix EDAC userspace ABI

This is the remaining EDAC patches needed to fix the EDAC userspace ABI.

They add a trace-based mechanism for error report (HERM), convert the EDAC MC kobj into struct devices and adds a new ABI capable of properly work with FB-DIMMs and RAMBUSes memory controllers, as well as with Nehalem/Sandy Bridge ones.

Quoted 1 line

From what it was planned originally for this patch series, a few

things are left from this series, because of all upstream noise on getting it merged:
- Docbook patches;
- Error Counters: they deserve a separate patch series;
- a MCE-based trace event;

I'll write the Docbook patch in the sequence, just after having this series merged at -next.

The other two items deserve some discussions upstream.

Regards,
Mauro.

Mauro Carvalho Chehab (25):
edac: Initialize the dimm label with the known information
edac: Cleanup the logs for i7core and sb edac drivers
i5400_edac: improve debug messages to better represent the filled
memory
events/hw_event: Create a Hardware Events Report Mecanism (HERM)
i5000_edac: Fix the logic that retrieves memory information
e752x_edac: provide more info about how DIMMS/ranks are mapped
edac: Rename the parent dev to pdev
edac: use Documentation-nano format for some data structs
edac: rewrite the sysfs code to use struct device
mpc85xx_edac: convert sysfs logic to use struct device
amd64_edac: convert sysfs logic to use struct device
i7core_edac: convert it to use struct device
edac: Get rid of the old kobj's from the edac mc code
edac: add a new per-dimm API and make the old per-virtual-rank API
obsolete
edac: add a sysfs node to report the maximum location for the system
edac: Add debufs nodes to allow doing fake error inject
edac: Create a per-Memory Controller bus
edac: Move grain/dtype/edac_type calculus to be out of channel loop
i82975x_edac: Test nr_pages earlier to save a few CPU cycles
i5100_edac: Fix a warning when compiled with 32 bits
i7300_edac: Get rid of some wrongly-solved rebase conflict
edac: Only expose csrows/channels on legacy API if they're populated
edac: Fix a typo at edac_mc_sysfs
edac: change the mem allocation scheme to make
Documentation/kobject.txt happy
i7core_edac: change the mem allocation scheme to make
Documentation/kobject.txt happy

 drivers/edac/Kconfig            |    8 +
 drivers/edac/amd64_edac.c       |   53 +-
 drivers/edac/amd64_edac.h       |   29 +-
 drivers/edac/amd64_edac_dbg.c   |   89 ++--
 drivers/edac/amd64_edac_inj.c   |  128 +++--
 drivers/edac/amd76x_edac.c      |   12 +-
 drivers/edac/cell_edac.c        |   20 +-
 drivers/edac/cpc925_edac.c      |   64 +-
 drivers/edac/e752x_edac.c       |   63 ++-
 drivers/edac/e7xxx_edac.c       |   38 +-
 drivers/edac/edac_core.h        |    2 +-
 drivers/edac/edac_mc.c          |  195 ++++--
 drivers/edac/edac_mc_sysfs.c    | 1355 ++++++++++++++++++++-------------------
 drivers/edac/edac_module.c      |   13 +-
 drivers/edac/edac_module.h      |    9 +-
 drivers/edac/i3000_edac.c       |   10 +-
 drivers/edac/i3200_edac.c       |   10 +-
 drivers/edac/i5000_edac.c       |  155 +++---
 drivers/edac/i5100_edac.c       |    6 +-
 drivers/edac/i5400_edac.c       |   23 +-
 drivers/edac/i7300_edac.c       |    5 +-
 drivers/edac/i7core_edac.c      |  365 +++++++----
 drivers/edac/i82443bxgx_edac.c  |    8 +-
 drivers/edac/i82860_edac.c      |   10 +-
 drivers/edac/i82875p_edac.c     |   14 +-
 drivers/edac/i82975x_edac.c     |   23 +-
 drivers/edac/mpc85xx_edac.c     |  103 ++--
 drivers/edac/mv64x60_edac.c     |    6 +-
 drivers/edac/pasemi_edac.c      |   14 +-
 drivers/edac/ppc4xx_edac.c      |    8 +-
 drivers/edac/r82600_edac.c      |    8 +-
 drivers/edac/sb_edac.c          |   33 +-
 drivers/edac/tile_edac.c        |    8 +-
 drivers/edac/x38_edac.c         |   10 +-
 include/linux/edac.h            |  180 ++++--
 include/trace/events/hw_event.h |  107 +++
 36 files changed, 1810 insertions(+), 1374 deletions(-)
 create mode 100644 include/trace/events/hw_event.h
Signature · 1 line
1.7.8
#1 lore raw

PATCH v13 1/25 edac: Initialize the dimm label with the known information

While userspace doesn't fill the dimm labels, add there the dimm location, as described by the used memory model. This could eventually match what is described at the dmidecode, making easier for people to identify the memory.

For example, on an Intel motherboard, the memory is described as:

Memory Device
Array Handle: 0x0029
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: 1
Locator: A1_DIMM0
Bank Locator: A1_Node0_Channel0_Dimm0
Type: <OUT OF SPEC>
Type Detail: Synchronous
Speed: 800 MHz
Manufacturer: A1_Manufacturer0
Serial Number: A1_SerNum0
Asset Tag: A1_AssetTagNum0
Part Number: A1_PartNum0

After this patch, the memory label will be filled with:

	/sys/devices/system/edac/mc/mc0/dimm0/dimm_label:mc#0channel#0slot#0

With somewhat matches what it is at the Bank Locator DMI information. So, it is easier to associate the dimm labels, of course assuming that the DMI has the Bank Locator filled, and the BIOS doesn't have any bugs.

Yet, even without it, several motherboards are provided with enough info to map from channel/slot (or branch/channel/slot) into the DIMM label. So, letting the EDAC core fill it, by default is a good thing.

It should noticed that, as the label filling happens at the edac_mc_alloc(), drivers can override it to better describe the memories (and some actually do it).

---
 drivers/edac/edac_mc.c       |   21 +++++++++++++++++----
 drivers/edac/edac_mc_sysfs.c |    8 ++++----
 include/linux/edac.h         |    2 --
 3 files changed, 21 insertions(+), 10 deletions(-)
drivers/edac/edac_mc.c +17 -4
index f5be026..3323d99 100644
@@ -202,10 +202,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	struct rank_info *chi, *chp, *chan;
 	struct dimm_info *dimm;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
-	void *pvt;
+	void *pvt, *p;
 	unsigned size, tot_dimms, count, pos[EDAC_MAX_LAYERS];
 	unsigned tot_csrows, tot_cschannels;
-	int i, j;
+	int i, j, n, len;
 	int err;
 	int row, chn;
 
@@ -311,9 +311,22 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 			i, (dimm - mci->dimms),
 			pos[0], pos[1], pos[2], row, chn);
 
-		/* Copy DIMM location */
-		for (j = 0; j < n_layers; j++)
+		/*
+		 * Copy DIMM location and initialize the memory location
+		 */
+		len = sizeof(dimm->label);
+		p = dimm->label;
+		n = snprintf(p, len, "mc#%u", edac_index);
+		p += n;
+		len -= n;
+		for (j = 0; j < n_layers; j++) {
+			n = snprintf(p, len, "%s#%u",
+				     edac_layer_name[layers[j].type],
+				     pos[j]);
+			p += n;
+			len -= n;
 			dimm->location[j] = pos[j];
+		}
 
 		/* Link it to the csrows old API data */
 		chan->dimm = dimm;
drivers/edac/edac_mc_sysfs.c +4 -4
index c0275e6..cfeb92c 100644
@@ -425,8 +425,8 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
 
 	mci->ue_noinfo_count = 0;
 	mci->ce_noinfo_count = 0;
-	mci->ue_count = 0;
-	mci->ce_count = 0;
+	mci->ue_mc = 0;
+	mci->ce_mc = 0;
 
 	for (row = 0; row < mci->nr_csrows; row++) {
 		struct csrow_info *ri = &mci->csrows[row];
@@ -495,12 +495,12 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
 /* default attribute files for the MCI object */
 static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
 {
-	return sprintf(data, "%d\n", mci->ue_count);
+	return sprintf(data, "%d\n", mci->ue_mc);
 }
 
 static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
 {
-	return sprintf(data, "%d\n", mci->ce_count);
+	return sprintf(data, "%d\n", mci->ce_mc);
 }
 
 static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
include/linux/edac.h +0 -2
index 1439670..6d8c394 100644
@@ -553,8 +553,6 @@ struct mem_ctl_info {
 	const char *dev_name;
 	char proc_name[MC_PROC_NAME_MAX_LEN + 1];
 	void *pvt_info;
-	u32 ue_count;           /* Total Uncorrectable Errors for this MC */
-	u32 ce_count;           /* Total Correctable Errors for this MC */
 	unsigned long start_time;	/* mci load start time (in jiffies) */
 
 	/* drivers shouldn't access this struct directly */
Signature · 1 line
1.7.8
#2 lore raw

Re: [EDAC ABI v13 01/25] edac: Initialize the dimm label with the known information

Adding latest version here:

Quoted 8 lines

From 50e9a89aad7045909780d635d73ab2893f8c1f90 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 9 Feb 2012 11:05:20 -0300
Subject: [PATCH] edac: Initialize the dimm label with the known information

While userspace doesn't fill the dimm labels, add there the dimm location, as described by the used memory model. This could eventually match what is described at the dmidecode, making easier for people to identify the

in making it easier

Quoted 1 line

memory.

stick in error.

Quoted 20 lines

For example, on an Intel motherboard, the memory is described as:

Memory Device
Array Handle: 0x0029
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: 1
Locator: A1_DIMM0
Bank Locator: A1_Node0_Channel0_Dimm0
Type: <OUT OF SPEC>
Type Detail: Synchronous
Speed: 800 MHz
Manufacturer: A1_Manufacturer0
Serial Number: A1_SerNum0
Asset Tag: A1_AssetTagNum0
Part Number: A1_PartNum0

Quoted 2 lines

After this patch, the memory label will be filled with:

	/sys/devices/system/edac/mc/mc0/dimm0/dimm_label:mc#0channel#0slot#0

This is only with the Intel-MCs, right, I still have the csrows here:

tree /sys/devices/system/edac/mc/
/sys/devices/system/edac/mc/

|-- mc0
|   |-- ce_count
|   |-- ce_noinfo_count
|   |-- csrow0
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count
|   |-- csrow1
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count
|   |-- csrow2
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count

…

Quoted 1 line

With somewhat matches what it is at the Bank Locator DMI information.

I wouldn't say that - DMI is notoriously unreliable, let's look at some boxes:

1st box:

Handle 0x0038, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x0036
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM0

2nd box:

Memory Device
Array Handle: 0x0014
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 4096 bits
Size: 9 MB
Form Factor: <OUT OF SPEC>
Set: 73
Locator: P0_DIMM_A1
Bank Locator: CHANNEL A

3rd box:

Handle 0x0033, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x0031
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 4096 MB
Form Factor: SODIMM
Set: 2
Locator: J401
Bank Locator: Channel B

and so on.

IOW, DMI fields are almost random permutations of [a-zA-Z0-9].

Quoted 10 lines

So, it is easier to associate the dimm labels, of course assuming that the DMI has the Bank Locator filled, and the BIOS doesn't have any bugs.

Yet, even without it, several motherboards are provided with enough info to map from channel/slot (or branch/channel/slot) into the DIMM label. So, letting the EDAC core fill it, by default is a good thing.

It should noticed that, as the label filling happens at the edac_mc_alloc(), drivers can override it to better describe the memories (and some actually do it).

But I guess having the info is still fine, simply remove the DMI references in the commit message pls.

Quoted 27 lines
Cc Aristeu Rozanski <[email protected]>
Cc Doug Thompson <[email protected]>
---
 drivers/edac/edac_mc.c       |   25 +++++++++++++++++++------
 drivers/edac/edac_mc_sysfs.c |    8 ++++----
 include/linux/edac.h         |    2 +-
 3 files changed, 24 insertions(+), 11 deletions(-)
drivers/edac/edac_mc.c +2 -2
index 4c44cd298c0b..77263b33b7f0 100644
@@ -210,10 +210,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	struct dimm_info *dimm;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 	unsigned pos[EDAC_MAX_LAYERS];
-	void *pvt, *ptr = NULL;
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
-	int i, j, err, row, chn;
+	void *pvt, *p, *ptr = NULL;
+	int i, j, err, row, chn, n, len;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, · line 329

Quoted 7 lines
drivers/edac/edac_mc.c +2 -2
@@ -325,9 +325,22 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 			i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
 			pos[0], pos[1], pos[2], row, chn);
 
-		/* Copy DIMM location */
-		for (j = 0; j < n_layers; j++)
+		/*
+		 * Copy DIMM location and initialize the memory location

initialize it.

or do you mean two different locations?

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 327

Quoted 12 lines
drivers/edac/edac_mc.c +12 -0
+		 */
+		len = sizeof(dimm->label);
+		p = dimm->label;
+		n = snprintf(p, len, "mc#%u", mc_num);
+		p += n;
+		len -= n;
+		for (j = 0; j < n_layers; j++) {
+			n = snprintf(p, len, "%s#%u",
+				     edac_layer_name[layers[j].type],
+				     pos[j]);
+			p += n;
+			len -= n;

Err, you're not checking how much len is left here, i.e. EDAC_MC_LABEL_LEN. Or even better, each time before you do snprintf.

drivers/edac/edac_mc.c static void edac_inc_ce_error(struct mem_ctl_info *mci, · line 853

Quoted 11 lines
drivers/edac/edac_mc.c +2 -1
 			dimm->location[j] = pos[j];
+		}
 
 		/* Link it to the csrows old API data */
 		chan->dimm = dimm;
@@ -837,7 +850,7 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 {
 	int i, index = 0;
 
-	mci->ce_count++;
+	mci->ce_mc++;

Oh, renaming them back, ok.

<rest snipped>

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#3 lore raw

Re: [EDAC ABI v13 01/25] edac: Initialize the dimm label with the known information

Review comments to the one below are still not addressed, maybe slipped through the cracks?

Quoted 216 lines · Borislav Petkov

Adding latest version here:

Quoted 8 lines

From 50e9a89aad7045909780d635d73ab2893f8c1f90 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 9 Feb 2012 11:05:20 -0300
Subject: [PATCH] edac: Initialize the dimm label with the known information

While userspace doesn't fill the dimm labels, add there the dimm location, as described by the used memory model. This could eventually match what is described at the dmidecode, making easier for people to identify the

in making it easier

Quoted 1 line

memory.

stick in error.

Quoted 20 lines

For example, on an Intel motherboard, the memory is described as:

Memory Device
Array Handle: 0x0029
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: 1
Locator: A1_DIMM0
Bank Locator: A1_Node0_Channel0_Dimm0
Type: <OUT OF SPEC>
Type Detail: Synchronous
Speed: 800 MHz
Manufacturer: A1_Manufacturer0
Serial Number: A1_SerNum0
Asset Tag: A1_AssetTagNum0
Part Number: A1_PartNum0

Quoted 2 lines

After this patch, the memory label will be filled with:

	/sys/devices/system/edac/mc/mc0/dimm0/dimm_label:mc#0channel#0slot#0

This is only with the Intel-MCs, right, I still have the csrows here:

tree /sys/devices/system/edac/mc/
/sys/devices/system/edac/mc/

|-- mc0
|   |-- ce_count
|   |-- ce_noinfo_count
|   |-- csrow0
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count
|   |-- csrow1
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count
|   |-- csrow2
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count

…

Quoted 1 line

With somewhat matches what it is at the Bank Locator DMI information.

I wouldn't say that - DMI is notoriously unreliable, let's look at some boxes:

1st box:

Handle 0x0038, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x0036
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM0

2nd box:

Memory Device
Array Handle: 0x0014
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 4096 bits
Size: 9 MB
Form Factor: <OUT OF SPEC>
Set: 73
Locator: P0_DIMM_A1
Bank Locator: CHANNEL A

3rd box:

Handle 0x0033, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x0031
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 4096 MB
Form Factor: SODIMM
Set: 2
Locator: J401
Bank Locator: Channel B

and so on.

IOW, DMI fields are almost random permutations of [a-zA-Z0-9].

Quoted 10 lines

So, it is easier to associate the dimm labels, of course assuming that the DMI has the Bank Locator filled, and the BIOS doesn't have any bugs.

Yet, even without it, several motherboards are provided with enough info to map from channel/slot (or branch/channel/slot) into the DIMM label. So, letting the EDAC core fill it, by default is a good thing.

It should noticed that, as the label filling happens at the edac_mc_alloc(), drivers can override it to better describe the memories (and some actually do it).

But I guess having the info is still fine, simply remove the DMI references in the commit message pls.

Quoted 27 lines
Cc Aristeu Rozanski <[email protected]>
Cc Doug Thompson <[email protected]>
---
 drivers/edac/edac_mc.c       |   25 +++++++++++++++++++------
 drivers/edac/edac_mc_sysfs.c |    8 ++++----
 include/linux/edac.h         |    2 +-
 3 files changed, 24 insertions(+), 11 deletions(-)
drivers/edac/edac_mc.c +2 -2
index 4c44cd298c0b..77263b33b7f0 100644
@@ -210,10 +210,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	struct dimm_info *dimm;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 	unsigned pos[EDAC_MAX_LAYERS];
-	void *pvt, *ptr = NULL;
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
-	int i, j, err, row, chn;
+	void *pvt, *p, *ptr = NULL;
+	int i, j, err, row, chn, n, len;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, · line 329

Quoted 7 lines
drivers/edac/edac_mc.c +2 -2
@@ -325,9 +325,22 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 			i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
 			pos[0], pos[1], pos[2], row, chn);
 
-		/* Copy DIMM location */
-		for (j = 0; j < n_layers; j++)
+		/*
+		 * Copy DIMM location and initialize the memory location

initialize it.

or do you mean two different locations?

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 327

Quoted 12 lines
drivers/edac/edac_mc.c +12 -0
+		 */
+		len = sizeof(dimm->label);
+		p = dimm->label;
+		n = snprintf(p, len, "mc#%u", mc_num);
+		p += n;
+		len -= n;
+		for (j = 0; j < n_layers; j++) {
+			n = snprintf(p, len, "%s#%u",
+				     edac_layer_name[layers[j].type],
+				     pos[j]);
+			p += n;
+			len -= n;

Err, you're not checking how much len is left here, i.e. EDAC_MC_LABEL_LEN. Or even better, each time before you do snprintf.

drivers/edac/edac_mc.c static void edac_inc_ce_error(struct mem_ctl_info *mci, · line 853

Quoted 11 lines
drivers/edac/edac_mc.c +2 -1
 			dimm->location[j] = pos[j];
+		}
 
 		/* Link it to the csrows old API data */
 		chan->dimm = dimm;
@@ -837,7 +850,7 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 {
 	int i, index = 0;
 
-	mci->ce_count++;
+	mci->ce_mc++;

Oh, renaming them back, ok.

<rest snipped>

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#4 lore raw

Re: [EDAC ABI v13 01/25] edac: Initialize the dimm label with the known information

Em 14-05-2012 09:48, Borislav Petkov escreveu:

Quoted 2 lines

Review comments to the one below are still not addressed, maybe slipped through the cracks?

Yeah, I lost that comments. Thanks for reminding it!

Quoted 13 lines · Borislav Petkov
Quoted 11 lines

Adding latest version here:

Quoted 8 lines

From 50e9a89aad7045909780d635d73ab2893f8c1f90 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 9 Feb 2012 11:05:20 -0300
Subject: [PATCH] edac: Initialize the dimm label with the known information

While userspace doesn't fill the dimm labels, add there the dimm location, as described by the used memory model. This could eventually match what is described at the dmidecode, making easier for people to identify the

Quoted 5 lines
Quoted 5 lines

in making it easier

Quoted 1 line

memory.

stick in error.

Fixed.

Quoted 21 lines
Quoted 21 lines
Quoted 21 lines

For example, on an Intel motherboard, the memory is described as:

Memory Device
Array Handle: 0x0029
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: 1
Locator: A1_DIMM0
Bank Locator: A1_Node0_Channel0_Dimm0
Type: <OUT OF SPEC>
Type Detail: Synchronous
Speed: 800 MHz
Manufacturer: A1_Manufacturer0
Serial Number: A1_SerNum0
Asset Tag: A1_AssetTagNum0
Part Number: A1_PartNum0

Quoted 4 lines
Quoted 4 lines
Quoted 2 lines

After this patch, the memory label will be filled with:

	/sys/devices/system/edac/mc/mc0/dimm0/dimm_label:mc#0channel#0slot#0

This is only with the Intel-MCs, right, I still have the csrows here:

The example is for Intel, but this will also fill the dimm labels on csrows-based memory controllers.

It should be noticed that, due to the rebases, expecially because Greg's request of converting the EDAC MC core to struct device, the patches that added the edac/mc/mc0/dimm* API is now after this changeset.

So, the sysfs nodes that you'll see with the labels are the
/sys/devices/system/edac/mc/csrow*/ch*_dimm_label

I'll add it to the comments.

Quoted 87 lines
Quoted 87 lines

tree /sys/devices/system/edac/mc/
/sys/devices/system/edac/mc/

|-- mc0
|   |-- ce_count
|   |-- ce_noinfo_count
|   |-- csrow0
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count
|   |-- csrow1
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count
|   |-- csrow2
|   |   |-- ce_count
|   |   |-- ch0_ce_count
|   |   |-- ch0_dimm_label
|   |   |-- ch1_ce_count
|   |   |-- ch1_dimm_label
|   |   |-- dev_type
|   |   |-- edac_mode
|   |   |-- mem_type
|   |   |-- size_mb
|   |   `-- ue_count

…

Quoted 1 line

With somewhat matches what it is at the Bank Locator DMI information.

I wouldn't say that - DMI is notoriously unreliable, let's look at some boxes:

1st box:

Handle 0x0038, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x0036
Error Information Handle: Not Provided
Total Width: 72 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: None
Locator: DIMM0

2nd box:

Memory Device
Array Handle: 0x0014
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 4096 bits
Size: 9 MB
Form Factor: <OUT OF SPEC>
Set: 73
Locator: P0_DIMM_A1
Bank Locator: CHANNEL A

3rd box:

Handle 0x0033, DMI type 17, 28 bytes
Memory Device
Array Handle: 0x0031
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 4096 MB
Form Factor: SODIMM
Set: 2
Locator: J401
Bank Locator: Channel B

Quoted 1 line
Quoted 1 line

and so on.

Yes, DMI is not very reliable. On that specific motherboard, the DMI table is reliable, so it can be used as a reference for that specific system. It is easier to put the DMI info there than to try to find for a public datasheet for the system(or motherboard), in order to point how the memories are addressed there.

Quoted 2 lines
Quoted 2 lines

IOW, DMI fields are almost random permutations of [a-zA-Z0-9].

:)

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

So, it is easier to associate the dimm labels, of course assuming that the DMI has the Bank Locator filled, and the BIOS doesn't have any bugs.

Yet, even without it, several motherboards are provided with enough info to map from channel/slot (or branch/channel/slot) into the DIMM label. So, letting the EDAC core fill it, by default is a good thing.

Quoted 6 lines
Quoted 6 lines
Quoted 3 lines

It should noticed that, as the label filling happens at the edac_mc_alloc(), drivers can override it to better describe the memories (and some actually do it).

But I guess having the info is still fine, simply remove the DMI references in the commit message pls.

I changed the comment there to:

"For example, on an Intel motherboard where the DMI table is reliable, the first memory stick is described as:

Memory Device"
...

Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Cc Aristeu Rozanski <[email protected]>
Cc Doug Thompson <[email protected]>
---
 drivers/edac/edac_mc.c       |   25 +++++++++++++++++++------
 drivers/edac/edac_mc_sysfs.c |    8 ++++----
 include/linux/edac.h         |    2 +-
 3 files changed, 24 insertions(+), 11 deletions(-)
drivers/edac/edac_mc.c +2 -2
index 4c44cd298c0b..77263b33b7f0 100644
@@ -210,10 +210,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	struct dimm_info *dimm;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 	unsigned pos[EDAC_MAX_LAYERS];
-	void *pvt, *ptr = NULL;
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
-	int i, j, err, row, chn;
+	void *pvt, *p, *ptr = NULL;
+	int i, j, err, row, chn, n, len;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
@@ -325,9 +325,22 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 			i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
 			pos[0], pos[1], pos[2], row, chn);
 
Quoted 8 lines
Quoted 8 lines

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, · line 329

Quoted 4 lines
drivers/edac/edac_mc.c +2 -2
-		/* Copy DIMM location */
-		for (j = 0; j < n_layers; j++)
+		/*
+		 * Copy DIMM location and initialize the memory location

initialize it.

or do you mean two different locations?

Fixed.

Quoted 16 lines
Quoted 16 lines

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, · line 341

Quoted 13 lines
drivers/edac/edac_mc.c +12 -0
+		 */
+		len = sizeof(dimm->label);
+		p = dimm->label;
+		n = snprintf(p, len, "mc#%u", mc_num);
+		p += n;
+		len -= n;
+		for (j = 0; j < n_layers; j++) {
+			n = snprintf(p, len, "%s#%u",
+				     edac_layer_name[layers[j].type],
+				     pos[j]);
+			p += n;
+			len -= n;

Err, you're not checking how much len is left here, i.e. EDAC_MC_LABEL_LEN. Or even better, each time before you do snprintf.

len is initialized with sizeof(dimm->label):

	 struct dimm_info {
	        char label[EDAC_MC_LABEL_LEN + 1];	/* DIMM label on motherboard */
	...

I'll add a break after decrementing len:

		if (len <= 0)
			break;
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/edac/edac_mc.c +1 -0
 			dimm->location[j] = pos[j];
+		}
 
 		/* Link it to the csrows old API data */
 		chan->dimm = dimm;
@@ -837,7 +850,7 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 {
 	int i, index = 0;
 
Quoted 4 lines
Quoted 4 lines

drivers/edac/edac_mc.c static void edac_inc_ce_error(struct mem_ctl_info *mci, · line 853

Quoted 2 lines
drivers/edac/edac_mc.c +1 -1
-	mci->ce_count++;
+	mci->ce_mc++;

Oh, renaming them back, ok.

Yes. That's because "ce_mc" is a better name than "ce_count", as it indicates a memory-controller-wide error.

Quoted 3 lines
Quoted 2 lines

<rest snipped>

Patch enclosed.

Thanks,
Mauro

-

edac: Initialize the dimm label with the known information

From: Mauro Carvalho Chehab <[email protected]>

While userspace doesn't fill the dimm labels, add there the dimm location, as described by the used memory model. This could eventually match what is described at the dmidecode, making easier for people to identify the memory.

For example, on an Intel motherboard where the DMI table is reliable, the first memory stick is described as:

Memory Device
Array Handle: 0x0029
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 2048 MB
Form Factor: DIMM
Set: 1
Locator: A1_DIMM0
Bank Locator: A1_Node0_Channel0_Dimm0
Type: <OUT OF SPEC>
Type Detail: Synchronous
Speed: 800 MHz
Manufacturer: A1_Manufacturer0
Serial Number: A1_SerNum0
Asset Tag: A1_AssetTagNum0
Part Number: A1_PartNum0

The memory named as "A1_DIMM0" is physically located at the first memory controller (node 0), at channel 0, dimm slot 0.

After this patch, the memory label will be filled with:

	/sys/devices/system/edac/mc/csrow0/ch0_dimm_label:mc#0channel#0slot#0

And (after the new EDAC API patches) as:

	/sys/devices/system/edac/mc/mc0/dimm0/dimm_label:mc#0channel#0slot#0

So, even if the memory label is not initialized on userspace, an useful information with the error location is filled there, expecially since several systems/motherboards are provided with enough info to map from channel/slot (or branch/channel/slot) into the DIMM label. So, letting the EDAC core fill it by default is a good thing.

It should noticed that, as the label filling happens at the edac_mc_alloc(), drivers can override it to better describe the memories (and some actually do it).

Cc Aristeu Rozanski <[email protected]>
Cc Doug Thompson <[email protected]>
drivers/edac/edac_mc.c +22 -6
index 03f8fb2..7246a3c 100644
@@ -210,10 +210,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	struct dimm_info *dimm;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 	unsigned pos[EDAC_MAX_LAYERS];
-	void *pvt, *ptr = NULL;
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
-	int i, j, err, row, chn;
+	void *pvt, *p, *ptr = NULL;
+	int i, j, err, row, chn, n, len;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
@@ -325,10 +325,26 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 			i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
 			pos[0], pos[1], pos[2], row, chn);
 
-		/* Copy DIMM location */
-		for (j = 0; j < n_layers; j++)
+		/*
+		 * Copy DIMM location and initialize it.
+		 */
+		len = sizeof(dimm->label);
+		p = dimm->label;
+		n = snprintf(p, len, "mc#%u", mc_num);
+		p += n;
+		len -= n;
+		for (j = 0; j < n_layers; j++) {
+			n = snprintf(p, len, "%s#%u",
+				     edac_layer_name[layers[j].type],
+				     pos[j]);
+			p += n;
+			len -= n;
 			dimm->location[j] = pos[j];
 
+			if (len <= 0)
+				break;
+		}
+
 		/* Link it to the csrows old API data */
 		chan->dimm = dimm;
 		dimm->csrow = row;
@@ -834,7 +850,7 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 {
 	int i, index = 0;
 
-	mci->ce_count++;
+	mci->ce_mc++;
 
 	if (!enable_per_layer_report) {
 		mci->ce_noinfo_count++;
@@ -858,7 +874,7 @@ static void edac_inc_ue_error(struct mem_ctl_info *mci,
 {
 	int i, index = 0;
 
-	mci->ue_count++;
+	mci->ue_mc++;
 
 	if (!enable_per_layer_report) {
 		mci->ce_noinfo_count++;
drivers/edac/edac_mc_sysfs.c +4 -4
index c0275e6..cfeb92c 100644
@@ -425,8 +425,8 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
 
 	mci->ue_noinfo_count = 0;
 	mci->ce_noinfo_count = 0;
-	mci->ue_count = 0;
-	mci->ce_count = 0;
+	mci->ue_mc = 0;
+	mci->ce_mc = 0;
 
 	for (row = 0; row < mci->nr_csrows; row++) {
 		struct csrow_info *ri = &mci->csrows[row];
@@ -495,12 +495,12 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
 /* default attribute files for the MCI object */
 static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
 {
-	return sprintf(data, "%d\n", mci->ue_count);
+	return sprintf(data, "%d\n", mci->ue_mc);
 }
 
 static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
 {
-	return sprintf(data, "%d\n", mci->ce_count);
+	return sprintf(data, "%d\n", mci->ce_mc);
 }
 
 static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
include/linux/edac.h +1 -1
index c8f507d..d6b0c25 100644
@@ -577,7 +577,7 @@ struct mem_ctl_info {
 	 * already handles that.
 	 */
 	u32 ce_noinfo_count, ue_noinfo_count;
-	u32 ue_count, ce_count;
+	u32 ue_mc, ce_mc;
 	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 
 	struct completion complete;
#5 lore raw

PATCH v13 2/25 edac: Cleanup the logs for i7core and sb edac drivers

In reply to Mauro Carvalho Chehab

Remove some information that it is duplicated at the MCE log, and don't have much usage for the error. Those data will be added again, when creating a trace function that outputs both memory errors and MCE fields.

---
 drivers/edac/i7core_edac.c |    9 ++-------
 drivers/edac/sb_edac.c     |   29 ++++++++++++++---------------
 2 files changed, 16 insertions(+), 22 deletions(-)
drivers/edac/i7core_edac.c +2 -7
index 72553dd..42775c4 100644
@@ -1623,7 +1623,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 				    const struct mce *m)
 {
 	struct i7core_pvt *pvt = mci->pvt_info;
-	char *type, *optype, *err, *msg;
+	char *type, *optype, *err, msg[80];
 	enum hw_event_mc_err_type tp_event;
 	unsigned long error = m->status & 0x1ff0000l;
 	bool uncorrected_error = m->mcgstatus & 1ll << 61;
@@ -1701,10 +1701,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 		err = "unknown";
 	}
 
-	msg = kasprintf(GFP_ATOMIC,
-		"addr=0x%08llx cpu=%d count=%d Err=%08llx:%08llx (%s: %s))\n",
-		(long long) m->addr, m->cpu, core_err_cnt,
-		(long long)m->status, (long long)m->misc, optype, err);
+	snprintf(msg, sizeof(msg), "count=%d %s", core_err_cnt, optype);
 
 	/*
 	 * Call the helper to output message
@@ -1718,8 +1715,6 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 				     syndrome,
 				     channel, dimm, -1,
 				     err, msg, m);
-
-	kfree(msg);
 }
 
 /*
drivers/edac/sb_edac.c +14 -15
index b253675..ad27e27 100644
@@ -1433,23 +1433,22 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 		recoverable_msg = "";
 
 	/*
-	 * FIXME: What should we do with "channel" information on mcelog?
-	 * Probably, we can just discard it, as the channel information
-	 * comes from the get_memory_error_data() address decoding
+	 * FIXME: On some memory configurations (mirror, lockstep), the
+	 * Memory Controller can't point the error to a single DIMM. The
+	 * EDAC core should be handling the channel mask, in order to point
+	 * to the group of dimm's where the error may be happening.
 	 */
 	snprintf(msg, sizeof(msg),
-			"%d error(s)%s: %s%s: cpu=%d Err=%04x:%04x addr = 0x%08llx socket=%d Channel=%ld(mask=%ld), rank=%d\n",
-			core_err_cnt,
-			overflow ? " OVERFLOW" : "",
-			area_type,
-			recoverable_msg,
-			m->cpu,
-			mscod, errcode,
-			(long long) m->addr,
-			socket,
-			first_channel,		/* This is the real channel on SB */
-			channel_mask,
-			rank);
+		 "%d error(s)%s: %s%s: Err=%04x:%04x socket=%d channel=%ld/mask=%ld rank=%d",
+		 core_err_cnt,
+		 overflow ? " OVERFLOW" : "",
+		 area_type,
+		 recoverable_msg,
+		 mscod, errcode,
+		 socket,
+		 first_channel,
+		 channel_mask,
+		 rank);
 
 	debugf0("%s", msg);
 
Signature · 1 line
1.7.8
#6 lore raw

PATCH v13 3/25 i5400_edac: improve debug messages to better represent the filled memory

In reply to Mauro Carvalho Chehab

Improves the debug output message, in order to better represent the memory controller hierarchy, when outputing the debug messages.

No functional changes when debug is disabled.

---
 drivers/edac/i5400_edac.c |   15 ++++++++++++++-
 1 files changed, 14 insertions(+), 1 deletions(-)
drivers/edac/i5400_edac.c +14 -1
index 3aa2a1e..5debda9 100644
@@ -963,7 +963,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 	int dimm, max_dimms;
 	char *p, *mem_buffer;
 	int space, n;
-	int channel;
+	int channel, branch;
 
 	/* ================= Generate some debug output ================= */
 	space = PAGE_SIZE;
@@ -1028,6 +1028,19 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
 		space -= n;
 	}
 
+	space -= n;
+	debugf2("%s\n", mem_buffer);
+	p = mem_buffer;
+	space = PAGE_SIZE;
+
+	n = snprintf(p, space, "           ");
+	p += n;
+	for (branch = 0; branch < MAX_BRANCHES; branch++) {
+		n = snprintf(p, space, "       branch %d       | ", branch);
+		p += n;
+		space -= n;
+	}
+
 	/* output the last message and free buffer */
 	debugf2("%s\n", mem_buffer);
 	kfree(mem_buffer);
Signature · 1 line
1.7.8
#7 lore raw

PATCH v13 4/25 events/hw_event: Create a Hardware Events Report Mecanism (HERM)

In reply to Mauro Carvalho Chehab

Adds a trace class for handle hardware events

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

In order to provide a proper hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

As no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch can change the tracepoint, for events originated via MCA.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 drivers/edac/edac_core.h        |    2 +-
 drivers/edac/edac_mc.c          |   11 ++++-
 include/trace/events/hw_event.h |  107 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 include/trace/events/hw_event.h
drivers/edac/edac_core.h +1 -1
index 8aadd83..f7c8c8a 100644
@@ -469,7 +469,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +10 -1
index 3323d99..002e6b6 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
+	trace_hw_event_init("edac", (unsigned)edac_index);
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -900,7 +906,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	unsigned long remapped_page;
 	/* FIXME: too much for stack: move it to some pre-alocated area */
@@ -1038,6 +1044,9 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			"page 0x%lx offset 0x%lx grain %d",
 			page_frame_number, offset_in_page, grain);
 
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
 	if (type == HW_EVENT_ERR_CORRECTED) {
 		if (edac_mc_get_log_ce())
 			edac_mc_printk(mci, KERN_WARNING,
include/trace/events/hw_event.h new file +107 -0

107 lines not on this page · raw message

Signature · 1 line
1.7.8
#8 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Inserting the latest version:

Quoted 5 lines

From 4afb0250415e87b983f5937d456c83407fe96264 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 23 Feb 2012 08:10:34 -0300
Subject: [PATCH] events/hw_event: Create a Hardware Events Report Mecanism
(HERM)

Ok, let's face it: this is just a single trace_mc_error tracepoint, nothing else. Let's drop the HERM bullshit bingo and call the thing by it's name: "Add yet another tracepoint to report DRAM ECC errors".

Quoted 23 lines

Adds a trace class for handle hardware events

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

Quoted 8 lines

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

In order to provide a proper hardware event subsystem, let's

err no, this is not a proper hw event subsystem.

Quoted 5 lines

encapsulate the memory error hardware events into a trace facility.

As no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch can change the tracepoint, for events originated via MCA.

This last paragraph has nothing to do with the patch so it can go.

Quoted 41 lines
Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 drivers/edac/edac_core.h        |    2 +-
 drivers/edac/edac_mc.c          |   26 +++++++---
 include/trace/events/hw_event.h |  107 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 8 deletions(-)
 create mode 100644 include/trace/events/hw_event.h
drivers/edac/edac_core.h +1 -1
index f06ce9ab692c..eee73605c5a0 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +3 -0
index e5b55632359f..c75774dcf434 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, · line 387

Quoted 4 lines
drivers/edac/edac_mc.c +1 -0
@@ -381,6 +384,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+

superfluous newline.

Quoted 66 lines
drivers/edac/edac_mc.c +15 -7
+	trace_hw_event_init("edac", (unsigned)mc_num);
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +988,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1125,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +12 -0
new file mode 100644
index 000000000000..1fabfe21e29a
@@ -0,0 +1,107 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hw_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Anomaly Report Mecanism (HARM) events

include/trace/events/hw_event.h line 22

Quoted 10 lines
include/trace/events/hw_event.h new file +10 -0
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
+ *        MCE subsystem.
+ */
+
+DECLARE_EVENT_CLASS(hw_event_class,

Ok, event classes are for sharing tracepoints which have the same TP_PROTO, TP_ARGS.. etc arguments as Steven's (CCed) article on lwn points out.

I don't see this here and besides, why in the hell would you need a trace event which only announces that the mechanism starts?? A common, run-of-the-mill printk is more than enough here.

Quoted 25 lines
include/trace/events/hw_event.h new file +25 -0
+	TP_PROTO(const char *type, unsigned int instance),
+	TP_ARGS(type, instance),
+
+	TP_STRUCT__entry(
+		__string(	type,		type			)
+		__field(	unsigned int,	instance		)
+	),
+
+	TP_fast_assign(
+		__assign_str(type, type);
+		__entry->instance = instance;
+	),
+
+	TP_printk("Initialized %s#%d\n",
+		__get_str(type),
+		__entry->instance)
+);
+
+/*
+ * This event indicates that a hardware collection mechanism is started
+ */
+DEFINE_EVENT(hw_event_class, hw_event_init,
+
+	TP_PROTO(const char *type, unsigned int instance),
+

include/trace/events/hw_event.h line 57

Quoted 10 lines
include/trace/events/hw_event.h new file +10 -0
+	TP_ARGS(type, instance)
+);
+
+
+/*
+ * Hardware-independent Memory Controller specific events
+ */
+
+/*
+ * Default error mechanisms for Memory Controller errors (CE and UE)

DRAM ECC errors.

Quoted 25 lines
include/trace/events/hw_event.h new file +25 -0
+ */
+TRACE_EVENT(mc_error,
+
+	TP_PROTO(const unsigned int err_type,
+		 const unsigned int mc_index,
+		 const char *msg,
+		 const char *label,
+		 const char *location,
+		 const char *detail,
+		 const char *driver_detail),
+
+	TP_ARGS(err_type, mc_index, msg, label, location,
+		detail, driver_detail),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	err_type		)
+		__field(	unsigned int,	mc_index		)
+		__string(	msg,		msg			)
+		__string(	label,		label			)
+		__string(	detail,		detail			)
+		__string(	location,	location		)
+		__string(	driver_detail,	driver_detail		)
+	),
+
+	TP_fast_assign(

include/trace/events/hw_event.h line 92

Quoted 10 lines
include/trace/events/hw_event.h new file +10 -0
+		__entry->err_type		= err_type;
+		__entry->mc_index		= mc_index;
+		__assign_str(msg, msg);
+		__assign_str(label, label);
+		__assign_str(location, location);
+		__assign_str(detail, detail);
+		__assign_str(driver_detail, driver_detail);
+	),
+
+	TP_printk(HW_ERR "mce#%d: %s error %s on label \"%s\" (%s %s %s)",

memory stick/DIMM

Quoted 17 lines
include/trace/events/hw_event.h new file +15 -0
+		  __entry->mc_index,
+		  (__entry->err_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
+			((__entry->err_type == HW_EVENT_ERR_FATAL) ?
+			"Fatal" : "Uncorrected"),
+		  __get_str(msg),
+		  __get_str(label),
+		  __get_str(location),
+		  __get_str(detail),
+		  __get_str(driver_detail))
+);
+
+#endif /* _TRACE_HW_EVENT_MC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
Signature · 1 line
1.7.9.3.362.g71319
Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
author Reviewed-by Aristeu Rozanski
#9 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 09-05-2012 09:13, Borislav Petkov escreveu:

Quoted 11 lines

Inserting the latest version:

Quoted 5 lines

From 4afb0250415e87b983f5937d456c83407fe96264 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 23 Feb 2012 08:10:34 -0300
Subject: [PATCH] events/hw_event: Create a Hardware Events Report Mecanism
(HERM)

Ok, let's face it: this is just a single trace_mc_error tracepoint, nothing else. Let's drop the HERM bullshit bingo and call the thing by it's name: "Add yet another tracepoint to report DRAM ECC errors".

This name is nice and helps to distinguish this mechanism among others, and will help to distinguish between HARM-aware userspace tools from the existing ones.

Anyway, I'll improve the subject.

Quoted 27 lines
Quoted 27 lines

Adds a trace class for handle hardware events

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Quoted 6 lines
Quoted 4 lines

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

In order to provide a proper hardware event subsystem, let's

err no, this is not a proper hw event subsystem.

This is part of it. Paragraph re-written.

Quoted 8 lines
Quoted 6 lines

encapsulate the memory error hardware events into a trace facility.

As no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch can change the tracepoint, for events originated via MCA.

This last paragraph has nothing to do with the patch so it can go.

The original patch had both mechanisms. I want to preserve here the reason why I've removed the MCA-based tracepont from this patch.

I've re-written the paragraph as a note.

Quoted 35 lines
Quoted 35 lines
Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 drivers/edac/edac_core.h        |    2 +-
 drivers/edac/edac_mc.c          |   26 +++++++---
 include/trace/events/hw_event.h |  107 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+), 8 deletions(-)
 create mode 100644 include/trace/events/hw_event.h
drivers/edac/edac_core.h +1 -1
index f06ce9ab692c..eee73605c5a0 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +0 -0
index e5b55632359f..c75774dcf434 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
Quoted 13 lines

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, · line 387

Quoted 11 lines
drivers/edac/edac_mc.c +4 -0
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+

superfluous newline.

I prefer to keep the init event on a separate line, as this has nothing to do with the comment on the previous lines.

Quoted 73 lines
Quoted 73 lines
drivers/edac/edac_mc.c +15 -7
+	trace_hw_event_init("edac", (unsigned)mc_num);
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +988,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1125,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +18 -0
new file mode 100644
index 000000000000..1fabfe21e29a
@@ -0,0 +1,107 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hw_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Anomaly Report Mecanism (HARM) events
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
Quoted 8 lines

include/trace/events/hw_event.h line 22

Quoted 4 lines
include/trace/events/hw_event.h new file +4 -0
+ *        MCE subsystem.
+ */
+
+DECLARE_EVENT_CLASS(hw_event_class,

Ok, event classes are for sharing tracepoints which have the same TP_PROTO, TP_ARGS.. etc arguments as Steven's (CCed) article on lwn points out.

Other trace mechanisms will be added. One of them is the MCA-based tracepoint, that got removed while no consensus is reached on that.

Quoted 3 lines

I don't see this here and besides, why in the hell would you need a trace event which only announces that the mechanism starts?? A common, run-of-the-mill printk is more than enough here.

A daemon monitoring this trace may need to know when the trace mechanism started, in order to what might be lost before the event init.

Quoted 30 lines
Quoted 30 lines
include/trace/events/hw_event.h new file +29 -0
+	TP_PROTO(const char *type, unsigned int instance),
+	TP_ARGS(type, instance),
+
+	TP_STRUCT__entry(
+		__string(	type,		type			)
+		__field(	unsigned int,	instance		)
+	),
+
+	TP_fast_assign(
+		__assign_str(type, type);
+		__entry->instance = instance;
+	),
+
+	TP_printk("Initialized %s#%d\n",
+		__get_str(type),
+		__entry->instance)
+);
+
+/*
+ * This event indicates that a hardware collection mechanism is started
+ */
+DEFINE_EVENT(hw_event_class, hw_event_init,
+
+	TP_PROTO(const char *type, unsigned int instance),
+
+	TP_ARGS(type, instance)
+);
+
+
Quoted 8 lines

include/trace/events/hw_event.h line 57

Quoted 6 lines
include/trace/events/hw_event.h new file +6 -0
+/*
+ * Hardware-independent Memory Controller specific events
+ */
+
+/*
+ * Default error mechanisms for Memory Controller errors (CE and UE)

DRAM ECC errors.

No, the errors aren't limited to DRAM ECC errors.

Some drivers report errors that aren't related to ECC and not even related to the DIMM. For example, all FB-DIMM controllers can report BUS errors at the channel that it is used to communicate with the Advanced Memory Buffer.

Quoted 30 lines
Quoted 30 lines
include/trace/events/hw_event.h new file +29 -0
+ */
+TRACE_EVENT(mc_error,
+
+	TP_PROTO(const unsigned int err_type,
+		 const unsigned int mc_index,
+		 const char *msg,
+		 const char *label,
+		 const char *location,
+		 const char *detail,
+		 const char *driver_detail),
+
+	TP_ARGS(err_type, mc_index, msg, label, location,
+		detail, driver_detail),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	err_type		)
+		__field(	unsigned int,	mc_index		)
+		__string(	msg,		msg			)
+		__string(	label,		label			)
+		__string(	detail,		detail			)
+		__string(	location,	location		)
+		__string(	driver_detail,	driver_detail		)
+	),
+
+	TP_fast_assign(
+		__entry->err_type		= err_type;
+		__entry->mc_index		= mc_index;
+		__assign_str(msg, msg);
+		__assign_str(label, label);
Quoted 8 lines

include/trace/events/hw_event.h line 92

Quoted 6 lines
include/trace/events/hw_event.h new file +6 -0
+		__assign_str(location, location);
+		__assign_str(detail, detail);
+		__assign_str(driver_detail, driver_detail);
+	),
+
+	TP_printk(HW_ERR "mce#%d: %s error %s on label \"%s\" (%s %s %s)",

memory stick/DIMM

Fixed.

Quoted 10 lines
Quoted 10 lines
include/trace/events/hw_event.h new file +9 -0
+		  __entry->mc_index,
+		  (__entry->err_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
+			((__entry->err_type == HW_EVENT_ERR_FATAL) ?
+			"Fatal" : "Uncorrected"),
+		  __get_str(msg),
+		  __get_str(label),
+		  __get_str(location),
+		  __get_str(detail),
+		  __get_str(driver_detail))
Quoted 10 lines
Quoted 8 lines
include/trace/events/hw_event.h new file +6 -0
+);
+
+#endif /* _TRACE_HW_EVENT_MC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
Signature · 1 line
1.7.9.3.362.g71319

Reviewed patch enclosed.

Regards,
Mauro

-

events/hw_event: use a tracepoint-based Hardware Events Report Mecanism (HERM)

From: Mauro Carvalho Chehab <[email protected]>

Adds a trace class for handle hardware events

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

As part of a hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. Hoever, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
drivers/edac/edac_core.h +1 -1
index f06ce9a..eee7360 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +19 -7
index e5b5563..c75774d 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
+	trace_hw_event_init("edac", (unsigned)mc_num);
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +988,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1125,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +107 -0

107 lines not on this page · raw message

#10 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

+ Tony.

Quoted 9 lines · Mauro Carvalho Chehab

Em 09-05-2012 09:13, Borislav Petkov escreveu:

Quoted 8 lines

Inserting the latest version:

Quoted 5 lines

From 4afb0250415e87b983f5937d456c83407fe96264 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 23 Feb 2012 08:10:34 -0300
Subject: [PATCH] events/hw_event: Create a Hardware Events Report Mecanism
(HERM)

Quoted 7 lines
Quoted 3 lines

Ok, let's face it: this is just a single trace_mc_error tracepoint, nothing else. Let's drop the HERM bullshit bingo and call the thing by it's name: "Add yet another tracepoint to report DRAM ECC errors".

This name is nice and helps to distinguish this mechanism among others, and will help to distinguish between HARM-aware userspace tools from the existing ones.

This may be so but it is not a mechanism - it is simply using a kernel facility - a tracepoint - and that's it.

Now, if you really want to have a generic mechanism for RAS, used by all the kernel, then I don't have a problem with you adding it to include/ras/hw_event.h or somewhere in that vicinity along with making it generic enough for other users and then taking care of it and developing it to address users' needs.

But simply growing stuff here and there for a specific use case is not the way to go.

[ … ]

Quoted 33 lines
Quoted 24 lines
Quoted 24 lines
include/trace/events/hw_event.h new file +18 -0
new file mode 100644
index 000000000000..1fabfe21e29a
@@ -0,0 +1,107 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hw_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Anomaly Report Mecanism (HARM) events
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
Quoted 8 lines

include/trace/events/hw_event.h line 22

Quoted 4 lines
include/trace/events/hw_event.h new file +4 -0
+ *        MCE subsystem.
+ */
+
+DECLARE_EVENT_CLASS(hw_event_class,

Ok, event classes are for sharing tracepoints which have the same TP_PROTO, TP_ARGS.. etc arguments as Steven's (CCed) article on lwn points out.

Quoted 2 lines

Other trace mechanisms will be added. One of them is the MCA-based tracepoint, that got removed while no consensus is reached on that.

You're missing the point: are the other tracepoints using "const char *type" and "unsigned int instance" as arguments? No.

IOW, go look at http://lwn.net/Articles/381064/ for an example what the trace event class is. Hint: sched_wakeup and sched_wakeup_new.

Quoted 6 lines
Quoted 3 lines

I don't see this here and besides, why in the hell would you need a trace event which only announces that the mechanism starts?? A common, run-of-the-mill printk is more than enough here.

A daemon monitoring this trace may need to know when the trace mechanism started, in order to what might be lost before the event init.

Yes, the trace has started when the daemon reads the first sample from the buffer, no need for explicitly letting us know it has.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
author Reviewed-by Aristeu Rozanski
#11 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 09-05-2012 10:22, Borislav Petkov escreveu:

Quoted 1 line

+ Tony.

C/C Steven.

Quoted 14 lines · Mauro Carvalho Chehab
Quoted 13 lines

Em 09-05-2012 09:13, Borislav Petkov escreveu:

Quoted 11 lines

Inserting the latest version:

Quoted 5 lines

From 4afb0250415e87b983f5937d456c83407fe96264 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Thu, 23 Feb 2012 08:10:34 -0300
Subject: [PATCH] events/hw_event: Create a Hardware Events Report Mecanism
(HERM)

Ok, let's face it: this is just a single trace_mc_error tracepoint, nothing else. Let's drop the HERM bullshit bingo and call the thing by it's name: "Add yet another tracepoint to report DRAM ECC errors".

Quoted 6 lines
Quoted 3 lines

This name is nice and helps to distinguish this mechanism among others, and will help to distinguish between HARM-aware userspace tools from the existing ones.

This may be so but it is not a mechanism - it is simply using a kernel facility - a tracepoint - and that's it.

Ok, I'll then rename it to "Hardware Events Report Method".

Quoted 5 lines

Now, if you really want to have a generic mechanism for RAS, used by all the kernel, then I don't have a problem with you adding it to include/ras/hw_event.h or somewhere in that vicinity along with making it generic enough for other users and then taking care of it and developing it to address users' needs.

I'm ok to move it to include/ras, but, if I remember well from my initial tests when I wrote this, several kernel versions ago, there is/was a limitation that required that all trace events should be under include/trace/events/.

One other option would be to call it as "include/trace/events/ras.h".

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

In a matter of fact, my plan is to move the EDAC core to drivers/ras, after making it generic enough.

Quoted 38 lines

But simply growing stuff here and there for a specific use case is not the way to go.

[ … ]

Quoted 33 lines
Quoted 32 lines
Quoted 18 lines
include/trace/events/hw_event.h new file +12 -0
new file mode 100644
index 000000000000..1fabfe21e29a
@@ -0,0 +1,107 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hw_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Anomaly Report Mecanism (HARM) events

include/trace/events/hw_event.h line 22

Quoted 10 lines
include/trace/events/hw_event.h new file +10 -0
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
+ *        MCE subsystem.
+ */
+
+DECLARE_EVENT_CLASS(hw_event_class,

Ok, event classes are for sharing tracepoints which have the same TP_PROTO, TP_ARGS.. etc arguments as Steven's (CCed) article on lwn points out.

Quoted 8 lines
Quoted 2 lines

Other trace mechanisms will be added. One of them is the MCA-based tracepoint, that got removed while no consensus is reached on that.

You're missing the point: are the other tracepoints using "const char *type" and "unsigned int instance" as arguments? No.

IOW, go look at http://lwn.net/Articles/381064/ for an example what the trace event class is. Hint: sched_wakeup and sched_wakeup_new.

I used that article when I wrote this code. Ok, the code is now very different than my original proposal, where the same arguments were repeated on several traces (plus a few more).

Quoted 10 lines
Quoted 7 lines
Quoted 4 lines

I don't see this here and besides, why in the hell would you need a trace event which only announces that the mechanism starts?? A common, run-of-the-mill printk is more than enough here.

A daemon monitoring this trace may need to know when the trace mechanism started, in order to what might be lost before the event init.

Yes, the trace has started when the daemon reads the first sample from the buffer, no need for explicitly letting us know it has.

Ok, I dropped the event class.

Patch enclosed.

Regards,
Mauro

-

events/hw_event: use a tracepoint-based Hardware Events Report Method (HERM)

From: Mauro Carvalho Chehab <[email protected]>

Adds a trace class for handle hardware events

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

As part of a hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. Hoever, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
drivers/edac/edac_core.h +1 -1
index f06ce9a..eee7360 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +17 -7
index e5b5563..eff8266 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +986,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1123,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +77 -0

77 lines not on this page · raw message

#12 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Quoted 11 lines · Mauro Carvalho Chehab
Quoted 5 lines

Now, if you really want to have a generic mechanism for RAS, used by all the kernel, then I don't have a problem with you adding it to include/ras/hw_event.h or somewhere in that vicinity along with making it generic enough for other users and then taking care of it and developing it to address users' needs.

I'm ok to move it to include/ras, but, if I remember well from my initial tests when I wrote this, several kernel versions ago, there is/was a limitation that required that all trace events should be under include/trace/events/.

Quoted 6 lines

One other option would be to call it as "include/trace/events/ras.h".

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

Oh, yeah, I remember vaguely something like that. Lets wait what Steven has to say.

Quoted 2 lines

In a matter of fact, my plan is to move the EDAC core to drivers/ras, after making it generic enough.

Now that sounds like a very bad idea to me. Why would you do that, they're just fine under drivers/edac/ the way they are now. If there's no real reason for doing that, then unnecessary code churn is not what we want.

[ … ]

Quoted 5 lines

events/hw_event: use a tracepoint-based Hardware Events Report Method (HERM)

From: Mauro Carvalho Chehab <[email protected]>

Adds a trace class for handle hardware events

You just removed the class - what class now?

Quoted 131 lines

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

As part of a hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. Hoever, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
drivers/edac/edac_core.h +1 -1
index f06ce9a..eee7360 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +17 -7
index e5b5563..eff8266 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +986,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1123,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +2 -0
new file mode 100644
index 0000000..234220a
@@ -0,0 +1,77 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hw_event

include/trace/events/hw_event.h line 12

Quoted 10 lines
include/trace/events/hw_event.h new file +10 -0
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Anomaly Report Mecanism (HARM) events

and above says "Hardware Events Report Method (HERM)" The fact that you yourself are not exactly sure about what this abbreviation is supposed to be/mean/etc, simply should tell you that it is causing only confusion with no benefit what-so-ever, even to you!

So stop calling it names and simply say "add a tracepoint for memory controller errors" and be done with it. There's no need for marketing speak in the kernel.

Quoted 66 lines
include/trace/events/hw_event.h new file +65 -0
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
+ *        MCE subsystem.
+ */
+
+/*
+ * Hardware-independent Memory Controller specific events
+ */
+
+/*
+ * Default error mechanisms for Memory Controller errors (CE and UE)
+ */
+TRACE_EVENT(mc_error,
+
+	TP_PROTO(const unsigned int err_type,
+		 const unsigned int mc_index,
+		 const char *msg,
+		 const char *label,
+		 const char *location,
+		 const char *detail,
+		 const char *driver_detail),
+
+	TP_ARGS(err_type, mc_index, msg, label, location,
+		detail, driver_detail),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	err_type		)
+		__field(	unsigned int,	mc_index		)
+		__string(	msg,		msg			)
+		__string(	label,		label			)
+		__string(	detail,		detail			)
+		__string(	location,	location		)
+		__string(	driver_detail,	driver_detail		)
+	),
+
+	TP_fast_assign(
+		__entry->err_type		= err_type;
+		__entry->mc_index		= mc_index;
+		__assign_str(msg, msg);
+		__assign_str(label, label);
+		__assign_str(location, location);
+		__assign_str(detail, detail);
+		__assign_str(driver_detail, driver_detail);
+	),
+
+	TP_printk(HW_ERR "mce#%d: %s error %s on memory stick \"%s\" (%s %s %s)",
+		  __entry->mc_index,
+		  (__entry->err_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
+			((__entry->err_type == HW_EVENT_ERR_FATAL) ?
+			"Fatal" : "Uncorrected"),
+		  __get_str(msg),
+		  __get_str(label),
+		  __get_str(location),
+		  __get_str(detail),
+		  __get_str(driver_detail))
+);
+
+#endif /* _TRACE_HW_EVENT_MC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
author Reviewed-by Aristeu Rozanski
#13 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 09-05-2012 11:06, Borislav Petkov escreveu:

Quoted 14 lines · Mauro Carvalho Chehab
Quoted 13 lines
Quoted 5 lines

Now, if you really want to have a generic mechanism for RAS, used by all the kernel, then I don't have a problem with you adding it to include/ras/hw_event.h or somewhere in that vicinity along with making it generic enough for other users and then taking care of it and developing it to address users' needs.

I'm ok to move it to include/ras, but, if I remember well from my initial tests when I wrote this, several kernel versions ago, there is/was a limitation that required that all trace events should be under include/trace/events/.

One other option would be to call it as "include/trace/events/ras.h".

Quoted 7 lines
Quoted 4 lines

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

Oh, yeah, I remember vaguely something like that. Lets wait what Steven has to say.

Ok.

Quoted 7 lines
Quoted 2 lines

In a matter of fact, my plan is to move the EDAC core to drivers/ras, after making it generic enough.

Now that sounds like a very bad idea to me. Why would you do that, they're just fine under drivers/edac/ the way they are now. If there's no real reason for doing that, then unnecessary code churn is not what we want.

Ok.

Quoted 10 lines

[ … ]

Quoted 5 lines

events/hw_event: use a tracepoint-based Hardware Events Report Method (HERM)

From: Mauro Carvalho Chehab <[email protected]>

Adds a trace class for handle hardware events

You just removed the class - what class now?

Fixed.

...

Quoted 8 lines

Review

Quoted 3 lines
(quoted diff) +3 -0
+
+/*
+ * Hardware Anomaly Report Mecanism (HARM) events

and above says "Hardware Events Report Method (HERM)" The fact that you yourself are not exactly sure about what this abbreviation is supposed to be/mean/etc, simply should tell you that it is causing only confusion with no benefit what-so-ever, even to you!

Fixed.

-

events/hw_event: use a tracepoint-based Hardware Events Report Method (HERM)

From: Mauro Carvalho Chehab <[email protected]>

Adds a trace event for handle hardware issues

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

As part of a hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. Hoever, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
drivers/edac/edac_core.h +1 -1
index f06ce9a..eee7360 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +17 -7
index e5b5563..eff8266 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +986,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1123,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +77 -0

77 lines not on this page · raw message

#14 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Quoted 22 lines · Mauro Carvalho Chehab

Em 09-05-2012 11:06, Borislav Petkov escreveu:

Quoted 21 lines · Mauro Carvalho Chehab
Quoted 11 lines
Quoted 5 lines

Now, if you really want to have a generic mechanism for RAS, used by all the kernel, then I don't have a problem with you adding it to include/ras/hw_event.h or somewhere in that vicinity along with making it generic enough for other users and then taking care of it and developing it to address users' needs.

I'm ok to move it to include/ras, but, if I remember well from my initial tests when I wrote this, several kernel versions ago, there is/was a limitation that required that all trace events should be under include/trace/events/.

Quoted 6 lines

One other option would be to call it as "include/trace/events/ras.h".

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

Oh, yeah, I remember vaguely something like that. Lets wait what Steven has to say.

btw, http://lwn.net/Articles/383362/ explains how to define tracepoints outside of include/trace/events.

[ … ]

Quoted 6 lines
Quoted 4 lines

and above says "Hardware Events Report Method (HERM)" The fact that you yourself are not exactly sure about what this abbreviation is supposed to be/mean/etc, simply should tell you that it is causing only confusion with no benefit what-so-ever, even to you!

Fixed.

No, you haven't. It still says HERM below. Please drop the marketing speak!

Quoted 214 lines

events/hw_event: use a tracepoint-based Hardware Events Report Method (HERM)

From: Mauro Carvalho Chehab <[email protected]>

Adds a trace event for handle hardware issues

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

As part of a hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. Hoever, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
drivers/edac/edac_core.h +1 -1
index f06ce9a..eee7360 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +17 -7
index e5b5563..eff8266 100644
@@ -33,6 +33,9 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +384,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +986,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1123,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/trace/events/hw_event.h new file +77 -0
new file mode 100644
index 0000000..fe2ec3b
@@ -0,0 +1,77 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hw_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Events Report Method (HERM)
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
+ *        MCE subsystem.
+ */
+
+/*
+ * Hardware-independent Memory Controller specific events
+ */
+
+/*
+ * Default error mechanisms for Memory Controller errors (CE and UE)
+ */
+TRACE_EVENT(mc_error,
+
+	TP_PROTO(const unsigned int err_type,
+		 const unsigned int mc_index,
+		 const char *msg,
+		 const char *label,
+		 const char *location,
+		 const char *detail,
+		 const char *driver_detail),
+
+	TP_ARGS(err_type, mc_index, msg, label, location,
+		detail, driver_detail),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	err_type		)
+		__field(	unsigned int,	mc_index		)
+		__string(	msg,		msg			)
+		__string(	label,		label			)
+		__string(	detail,		detail			)
+		__string(	location,	location		)
+		__string(	driver_detail,	driver_detail		)
+	),
+
+	TP_fast_assign(
+		__entry->err_type		= err_type;
+		__entry->mc_index		= mc_index;
+		__assign_str(msg, msg);
+		__assign_str(label, label);
+		__assign_str(location, location);
+		__assign_str(detail, detail);
+		__assign_str(driver_detail, driver_detail);
+	),
+
+	TP_printk(HW_ERR "mce#%d: %s error %s on memory stick \"%s\" (%s %s %s)",
+		  __entry->mc_index,
+		  (__entry->err_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
+			((__entry->err_type == HW_EVENT_ERR_FATAL) ?
+			"Fatal" : "Uncorrected"),
+		  __get_str(msg),
+		  __get_str(label),
+		  __get_str(location),
+		  __get_str(detail),
+		  __get_str(driver_detail))
+);
+
+#endif /* _TRACE_HW_EVENT_MC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#15 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 09-05-2012 11:24, Borislav Petkov escreveu:

Quoted 29 lines · Mauro Carvalho Chehab
Quoted 22 lines

Em 09-05-2012 11:06, Borislav Petkov escreveu:

Quoted 21 lines · Mauro Carvalho Chehab
Quoted 11 lines
Quoted 5 lines

Now, if you really want to have a generic mechanism for RAS, used by all the kernel, then I don't have a problem with you adding it to include/ras/hw_event.h or somewhere in that vicinity along with making it generic enough for other users and then taking care of it and developing it to address users' needs.

I'm ok to move it to include/ras, but, if I remember well from my initial tests when I wrote this, several kernel versions ago, there is/was a limitation that required that all trace events should be under include/trace/events/.

Quoted 6 lines

One other option would be to call it as "include/trace/events/ras.h".

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

Oh, yeah, I remember vaguely something like that. Lets wait what Steven has to say.

btw, http://lwn.net/Articles/383362/ explains how to define tracepoints outside of include/trace/events.

[ … ]

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

and above says "Hardware Events Report Method (HERM)" The fact that you yourself are not exactly sure about what this abbreviation is supposed to be/mean/etc, simply should tell you that it is causing only confusion with no benefit what-so-ever, even to you!

Fixed.

No, you haven't. It still says HERM below. Please drop the marketing speak!

Nah, this is not marketing speak. HERM is not a trademark. amd64_edac, on the other hand, is using a trademark on his name. If we use your logic, this would need to be renamed to something else, to avoid using a "marketing speak".

We need some name to differentiate between the broken EDAC core where modern memory controllers are not properly represented and reports errors on fake csrows/channels from the EDAC+HERM core that will properly provide the error information to where it really belongs.

In other words, HERM is just an acronym[1] to the version to point to where EDAC starts to work fine with modern memory controllers.

[1] Btw, EDAC is also an acronym for Error Detection And Correction.

Regards,
Mauro

#16 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Quoted 4 lines · Mauro Carvalho Chehab

Nah, this is not marketing speak. HERM is not a trademark. amd64_edac, on the other hand, is using a trademark on his name. If we use your logic, this would need to be renamed to something else, to avoid using a "marketing speak".

I'm not even going to dignify that with an answer because it is a bunch of bullshit and you know it.

Quoted 4 lines

We need some name to differentiate between the broken EDAC core where modern memory controllers are not properly represented and reports errors on fake csrows/channels from the EDAC+HERM core that will properly provide the error information to where it really belongs.

A kernel version or a commit id is not enough here I guess.

Quoted 2 lines

In other words, HERM is just an acronym[1] to the version to point to where EDAC starts to work fine with modern memory controllers.

Seems to me you're desperately trying to prove your point for having this HERM thing by coming up with a bunch of bogus arguments.

And I'm still waiting for a real, technical reason which legitimizes calling a tracepoint something special.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#17 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 10-05-2012 10:41, Borislav Petkov escreveu:

Quoted 16 lines · Mauro Carvalho Chehab
Quoted 4 lines

Nah, this is not marketing speak. HERM is not a trademark. amd64_edac, on the other hand, is using a trademark on his name. If we use your logic, this would need to be renamed to something else, to avoid using a "marketing speak".

I'm not even going to dignify that with an answer because it is a bunch of bullshit and you know it.

Quoted 4 lines

We need some name to differentiate between the broken EDAC core where modern memory controllers are not properly represented and reports errors on fake csrows/channels from the EDAC+HERM core that will properly provide the error information to where it really belongs.

A kernel version or a commit id is not enough here I guess.

Quoted 8 lines
Quoted 2 lines

In other words, HERM is just an acronym[1] to the version to point to where EDAC starts to work fine with modern memory controllers.

Seems to me you're desperately trying to prove your point for having this HERM thing by coming up with a bunch of bogus arguments.

And I'm still waiting for a real, technical reason which legitimizes calling a tracepoint something special.

Technical reasons were provided already: before this patch series, EDAC is *broken*.

Mauro.

#18 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Quoted 2 lines · Mauro Carvalho Chehab

Technical reasons were provided already: before this patch series, EDAC is *broken*.

Calling it "HERM" doesn't fix it.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#19 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

In reply to Mauro Carvalho Chehab

Em 10-05-2012 11:53, Mauro Carvalho Chehab escreveu:

Quoted 20 lines

Em 10-05-2012 10:41, Borislav Petkov escreveu:

Quoted 19 lines · Mauro Carvalho Chehab
Quoted 4 lines

Nah, this is not marketing speak. HERM is not a trademark. amd64_edac, on the other hand, is using a trademark on his name. If we use your logic, this would need to be renamed to something else, to avoid using a "marketing speak".

I'm not even going to dignify that with an answer because it is a bunch of bullshit and you know it.

Quoted 4 lines

We need some name to differentiate between the broken EDAC core where modern memory controllers are not properly represented and reports errors on fake csrows/channels from the EDAC+HERM core that will properly provide the error information to where it really belongs.

A kernel version or a commit id is not enough here I guess.

Quoted 2 lines

In other words, HERM is just an acronym[1] to the version to point to where EDAC starts to work fine with modern memory controllers.

Quoted 8 lines
Quoted 5 lines

Seems to me you're desperately trying to prove your point for having this HERM thing by coming up with a bunch of bogus arguments.

And I'm still waiting for a real, technical reason which legitimizes calling a tracepoint something special.

Technical reasons were provided already: before this patch series, EDAC is *broken*.

There's also another technical reason to give an acronym to the EDAC version that actually works: changeset numbers are not consistent within distributions (or other trees, like -stable - although this 60+ patch series probably won't fit on -stable merging criteria).

Also, this EDAC changeset 60+ patch series can't be represented by a single changeset, and requires userspace changes in order to get a proper representation model for memories.

Tagging the EDAC core version with a name helps a lot when dealing with all the unsolved bugzillas that will be closed by backporting this patch series in order to fix the serious EDAC core bug that were providing fake information to the end user for all Intel memory controllers manufactured after 2005.

Regards,
Mauro

Quoted 6 lines

Mauro.
--
To unsubscribe from this list: send the line "unsubscribe linux-edac" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#20 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Quoted 9 lines · Mauro Carvalho Chehab

There's also another technical reason to give an acronym to the EDAC version that actually works: changeset numbers are not consistent within distributions (or other trees, like -stable - although this 60+ patch series probably won't fit on -stable merging criteria).

Also, this EDAC changeset 60+ patch series can't be represented by a single changeset, and requires userspace changes in order to get a proper representation model for memories.

Quoted 5 lines

Tagging the EDAC core version with a name helps a lot when dealing with all the unsolved bugzillas that will be closed by backporting this patch series in order to fix the serious EDAC core bug that were providing fake information to the end user for all Intel memory controllers manufactured after 2005.

edac_module.c:18:#define EDAC_VERSION "Ver: 2.1.0"

Increment that in the last patch.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#21 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 10-05-2012 12:12, Borislav Petkov escreveu:

Quoted 16 lines · Mauro Carvalho Chehab
Quoted 9 lines

There's also another technical reason to give an acronym to the EDAC version that actually works: changeset numbers are not consistent within distributions (or other trees, like -stable - although this 60+ patch series probably won't fit on -stable merging criteria).

Also, this EDAC changeset 60+ patch series can't be represented by a single changeset, and requires userspace changes in order to get a proper representation model for memories.

Quoted 5 lines

Tagging the EDAC core version with a name helps a lot when dealing with all the unsolved bugzillas that will be closed by backporting this patch series in order to fix the serious EDAC core bug that were providing fake information to the end user for all Intel memory controllers manufactured after 2005.

Quoted 3 lines

edac_module.c:18:#define EDAC_VERSION "Ver: 2.1.0"

Increment that in the last patch.

Ok, I'll do that.

Mauro.

#22 lore raw

PATCH 1/1 edac: Increase version to 3.0.0 (aka: "HERM" version)

There were lots of changes introduced to justify renaming it to 3.0.0 (HERM - Hardware Events Report Method):

- EDAC core were redesigned to represent all types of

    memory controllers;

- EDAC API were redesigned to properly represent the memory

    controller hierarchy;

- a tracepoint-based API were added to report memory errors.

---
 drivers/edac/edac_module.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/edac/edac_module.c +1 -1
index cbba80d..3454798 100644
@@ -15,7 +15,7 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
-#define EDAC_VERSION "Ver: 2.1.0"
+#define EDAC_VERSION "Ver: 3.0.0"
 
 #ifdef CONFIG_EDAC_DEBUG
 /* Values of 0 to 4 will generate output */
Signature · 1 line
1.7.8
#23 lore raw

Re: [PATCH] edac: Increase version to 3.0.0 (aka: "HERM" version)

Quoted 4 lines · Mauro Carvalho Chehab

There were lots of changes introduced to justify renaming it to 3.0.0 (HERM - Hardware Events Report Method):

- EDAC core were redesigned to represent all types of

Quoted 8 lines
    memory controllers;

- EDAC API were redesigned to properly represent the memory

    controller hierarchy;

- a tracepoint-based API were added to report memory errors.

Dude, drop this goddam "HERM" thing already! Just call EDAC 3.0.0 and stop mentioning HERM anywhere - use it in your own paper jumble if it helps you but don't leak it into the kernel.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
maintainer
#24 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

In reply to Borislav Petkov
Quoted 9 lines · Borislav Petkov
Quoted 8 lines · Mauro Carvalho Chehab

There's also another technical reason to give an acronym to the EDAC version that actually works: changeset numbers are not consistent within distributions (or other trees, like -stable - although this 60+ patch series probably won't fit on -stable merging criteria).

Also, this EDAC changeset 60+ patch series can't be represented by a single changeset, and requires userspace changes in order to get a proper representation model for memories.

Is this a redesign of EDAC or just a fix of it? Does this require userspace to use a new ABI?

Quoted 10 lines
Quoted 6 lines

Tagging the EDAC core version with a name helps a lot when dealing with all the unsolved bugzillas that will be closed by backporting this patch series in order to fix the serious EDAC core bug that were providing fake information to the end user for all Intel memory controllers manufactured after 2005.

edac_module.c:18:#define EDAC_VERSION "Ver: 2.1.0"

Increment that in the last patch.

If this is redesigning a subsystem and changing the ABI for userspace than a new name is appropriate. Much like ipchains turning into iptables.

But if this is just fixing the subsystem where userspace sees no difference, than the same name fits.

-- Steve

#25 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Quoted 21 lines · Steven Rostedt
Quoted 9 lines · Borislav Petkov
Quoted 8 lines · Mauro Carvalho Chehab

There's also another technical reason to give an acronym to the EDAC version that actually works: changeset numbers are not consistent within distributions (or other trees, like -stable - although this 60+ patch series probably won't fit on -stable merging criteria).

Also, this EDAC changeset 60+ patch series can't be represented by a single changeset, and requires userspace changes in order to get a proper representation model for memories.

Is this a redesign of EDAC or just a fix of it? Does this require userspace to use a new ABI?

Quoted 7 lines
Quoted 6 lines

Tagging the EDAC core version with a name helps a lot when dealing with all the unsolved bugzillas that will be closed by backporting this patch series in order to fix the serious EDAC core bug that were providing fake information to the end user for all Intel memory controllers manufactured after 2005.

Quoted 7 lines
Quoted 3 lines

edac_module.c:18:#define EDAC_VERSION "Ver: 2.1.0"

Increment that in the last patch.

If this is redesigning a subsystem and changing the ABI for userspace than a new name is appropriate. Much like ipchains turning into iptables.

But that's not the question. The subsystem is still called EDAC but there's one patch which adds a tracepoint called trace_mc_error and this is called needlessly a name - Hardware Events Report Mechanism - which is only misleading and generating confusion even to its author.

Anyway, I think we solved the issue - we're going to increment EDAC_VERSION and all is fine :-)

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#26 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

In reply to Steven Rostedt

Em 10-05-2012 12:20, Steven Rostedt escreveu:

Quoted 7 lines · Borislav Petkov
Quoted 6 lines · Mauro Carvalho Chehab
Quoted 5 lines

There's also another technical reason to give an acronym to the EDAC version that actually works: changeset numbers are not consistent within distributions (or other trees, like -stable - although this 60+ patch series probably won't fit on -stable merging criteria).

Quoted 5 lines
Quoted 3 lines
Quoted 3 lines

Also, this EDAC changeset 60+ patch series can't be represented by a single changeset, and requires userspace changes in order to get a proper representation model for memories.

Is this a redesign of EDAC or just a fix of it?

It is a redesign. The EDAC core were designed to work only when the memory controller can directly see/work with the DRAM chip select pins and have non-independent channel buses.

In order to fix it, the EDAC core were redesigned.

Quoted 2 lines

Does this require
userspace to use a new ABI?

Yes, it requires a new API.

The legacy ABI will still be provided, if EDAC_LEGACY_SYSFS is selected.

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

Tagging the EDAC core version with a name helps a lot when dealing with all the unsolved bugzillas that will be closed by backporting this patch series in order to fix the serious EDAC core bug that were providing fake information to the end user for all Intel memory controllers manufactured after 2005.

Quoted 7 lines
Quoted 3 lines

edac_module.c:18:#define EDAC_VERSION "Ver: 2.1.0"

Increment that in the last patch.

If this is redesigning a subsystem and changing the ABI for userspace than a new name is appropriate. Much like ipchains turning into iptables.

That's what I think too.

Anyway, I'll move this to the last patch on the series (in the past rebases, this were the last patch on the series), incrementing the version there.

Quoted 4 lines

But if this is just fixing the subsystem where userspace sees no difference, than the same name fits.

-- Steve

Regards,
Mauro

maintainer
#27 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

In reply to Mauro Carvalho Chehab
Quoted 4 lines · Mauro Carvalho Chehab

Em 09-05-2012 10:22, Borislav Petkov escreveu:

Quoted 1 line

+ Tony.

C/C Steven.

Hehe, I was already Cc'd ;-)

Quoted 6 lines

One other option would be to call it as "include/trace/events/ras.h".

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

Yeah, it's not hard. In fact, it's documented in
samples/trace_events/trace-events-sample.h:

/*
* There are several ways I could have done this. If I left out the
* TRACE_INCLUDE_PATH, then it would default to the kernel source
* include/trace/events directory.
*
* I could specify a path from the define_trace.h file back to this
* file.
*
* #define TRACE_INCLUDE_PATH ../../samples/trace_events
*
* But the safest and easiest way to simply make it use the directory
* that the file is in is to add in the Makefile:
*
* CFLAGS_trace-events-sample.o := -I$(src)
*
* This will make sure the current path is part of the include
* structure for our file so that define_trace.h can find it. *
* I could have made only the top level directory the include:
*
* CFLAGS_trace-events-sample.o := -I$(PWD)
*
* And then let the path to this directory be the TRACE_INCLUDE_PATH:
*
* #define TRACE_INCLUDE_PATH samples/trace_events
*
* But then if something defines "samples" or "trace_events" as a macro
* then we could risk that being converted too, and give us an unexpected
* result.
*/

But usually the header would go where the code is:

drivers/edac/hw_event.h

Or rename it. The XFS tracepoints do this:

fs/xfs/xfs_trace.h

-- Steve

author Reviewed-by Aristeu Rozanski
#28 lore raw

Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)

Em 09-05-2012 11:19, Steven Rostedt escreveu:

Quoted 7 lines · Mauro Carvalho Chehab
Quoted 4 lines

Em 09-05-2012 10:22, Borislav Petkov escreveu:

Quoted 1 line

+ Tony.

C/C Steven.

Hehe, I was already Cc'd ;-)

:)

Quoted 41 lines
Quoted 6 lines

One other option would be to call it as "include/trace/events/ras.h".

Steven,

Would it be possible/recommendable to move this trace header to include/linux/ras/hw_event.h?

Yeah, it's not hard. In fact, it's documented in
samples/trace_events/trace-events-sample.h:

/*
* There are several ways I could have done this. If I left out the
* TRACE_INCLUDE_PATH, then it would default to the kernel source
* include/trace/events directory.
*
* I could specify a path from the define_trace.h file back to this
* file.
*
* #define TRACE_INCLUDE_PATH ../../samples/trace_events
*
* But the safest and easiest way to simply make it use the directory
* that the file is in is to add in the Makefile:
*
* CFLAGS_trace-events-sample.o := -I$(src)
*
* This will make sure the current path is part of the include
* structure for our file so that define_trace.h can find it. *
* I could have made only the top level directory the include:
*
* CFLAGS_trace-events-sample.o := -I$(PWD)
*
* And then let the path to this directory be the TRACE_INCLUDE_PATH:
*
* #define TRACE_INCLUDE_PATH samples/trace_events
*
* But then if something defines "samples" or "trace_events" as a macro
* then we could risk that being converted too, and give us an unexpected
* result.
*/

Quoted 7 lines

But usually the header would go where the code is:

drivers/edac/hw_event.h

Or rename it. The XFS tracepoints do this:

fs/xfs/xfs_trace.h

As the idea is to use it on other RAS facilities, it is better to put it at include/ras/hw_event.h

PS.: putting it at include/linux/ras/hw_event.h doesn't work, as "linux" is evaluated to "1" at TRACE_INCLUDE_PATH macro.

Anyway, patch is enclosed.

Regards,
Mauro.

-

edac, ras/hw_event.h: use HERM events to handle hw issues

From: Mauro Carvalho Chehab <[email protected]>

Add a new tracepoint-based Hardware Events Report Method (HERM) for outputing Memory Controller events.

Part of the description bellow is shamelessly copied from Tony Luck's notes about the Hardware Error BoF during LPC 2010 [1]. Tony, thanks for your notes and discussions to generate the h/w error reporting requirements.

[1] http://lwn.net/Articles/416669/

We have several subsystems & methods for reporting hardware errors:

1) EDAC ("Error Detection and Correction"). In its original form this consisted of a platform specific driver that read topology information and error counts from chipset registers and reported the results via a sysfs interface.

2) mcelog - x86 specific decoding of machine check bank registers reporting in binary form via /dev/mcelog. Recent additions make use of the APEI extensions that were documented in version 4.0a of the ACPI specification to acquire more information about errors without having to rely reading chipset registers directly. A user level programs decodes into somewhat human readable format.

3) drivers/edac/mce_amd.c - this driver hooks into the mcelog path and decodes errors reported via machine check bank registers in AMD processors to the console log using printk();

Each of these mechanisms has a band of followers ... and none of them appear to meet all the needs of all users.

As part of a hardware event subsystem, let's encapsulate the memory error hardware events into a trace facility.

NOTE: The original patch was providing an additional mechanism for MCA-based trace events that also contained MCA error register data. Hoever, as no agreement was reached so far for the MCA-based trace events, for now, let's add events only for memory errors. A latter patch is planned to change the tracepoint, for those types of event.

Cc Doug Thompson <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Ingo Molnar <[email protected]>
drivers/edac/edac_core.h +1 -1
index f06ce9a..eee7360 100644
@@ -468,7 +468,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog);
+			  const void *arch_log);
 
 /*
  * edac_device APIs
drivers/edac/edac_mc.c +18 -7
index e5b5563..11f0178 100644
@@ -33,6 +33,10 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#define TRACE_INCLUDE_PATH ../../include/ras
+#include <ras/hw_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
@@ -381,6 +385,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	 * which will perform kobj unregistration and the actual free
 	 * will occur during the kobject callback operation
 	 */
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
@@ -982,7 +987,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  const int layer2,
 			  const char *msg,
 			  const char *other_detail,
-			  const void *mcelog)
+			  const void *arch_log)
 {
 	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80], location[80];
@@ -1119,21 +1124,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 	}
 
 	/* Memory type dependent details about the error */
-	if (type == HW_EVENT_ERR_CORRECTED) {
+	if (type == HW_EVENT_ERR_CORRECTED)
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
 			page_frame_number, offset_in_page,
 			grain, syndrome);
-		edac_ce_error(mci, pos, msg, location, label, detail,
-			      other_detail, enable_per_layer_report,
-			      page_frame_number, offset_in_page, grain);
-	} else {
+	else
 		snprintf(detail, sizeof(detail),
 			"page:0x%lx offset:0x%lx grain:%d",
 			page_frame_number, offset_in_page, grain);
 
+	/* Report the error via the trace interface */
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
+		       detail, other_detail);
+
+	/* Report the error via the edac_mc_printk() interface */
+	if (type == HW_EVENT_ERR_CORRECTED)
+		edac_ce_error(mci, pos, msg, location, label, detail,
+			      other_detail, enable_per_layer_report,
+			      page_frame_number, offset_in_page, grain);
+	else
 		edac_ue_error(mci, pos, msg, location, label, detail,
 			      other_detail, enable_per_layer_report);
-	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
include/ras/hw_event.h new file +77 -0

77 lines not on this page · raw message

#29 lore raw

PATCH v13 5/25 i5000_edac: Fix the logic that retrieves memory information

In reply to Mauro Carvalho Chehab

The logic there is broken: it basically creates two csrows for each DIMM and assumes that all DIMM's are dual rank. Only one of the csrows will contain the entire DIMM size. If single rank memories are found, they'll be marked with 0 bytes.

The check if the AMB is present were also wrong.

Yet, as the error reports don't use the memory size in order to credit an error to the right DIMM, that part of the driver seems to work. That's why probably nobody detected the issue yet.

After this patch, the memory layout is now properly reported, when debug mode is enabled, and the number of ranks per dimm is now shown:

calculate_dimm_size: ----------------------------------------------------------
calculate_dimm_size: slot  3       0 MB   |    0 MB   |    0 MB   |    0 MB   |
calculate_dimm_size: slot  2       0 MB   |    0 MB   |    0 MB   |    0 MB   |
calculate_dimm_size: ----------------------------------------------------------
calculate_dimm_size: slot  1       0 MB   |    0 MB   |    0 MB   |    0 MB   |
calculate_dimm_size: slot  0     512 MB 1R|  512 MB 1R|  512 MB 1R|  512 MB 1R|
calculate_dimm_size: ----------------------------------------------------------
calculate_dimm_size:            channel 0 | channel 1 | channel 2 | channel 3 |
calculate_dimm_size:                   branch 0       |        branch 1       |

(1R above means that all memories on my test machine are single-ranked)

---
 drivers/edac/i5000_edac.c |  150 ++++++++++++++++++++++++---------------------
 1 files changed, 79 insertions(+), 71 deletions(-)
drivers/edac/i5000_edac.c +79 -71
index 1691cdd..659a868 100644
@@ -270,7 +270,8 @@
 #define MTR3		0x8C
 
 #define NUM_MTRS		4
-#define CHANNELS_PER_BRANCH	(2)
+#define CHANNELS_PER_BRANCH	2
+#define MAX_BRANCHES		2
 
 /* Defines to extract the vaious fields from the
  *	MTRx - Memory Technology Registers
@@ -962,14 +963,14 @@ static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
  *
  *	return the proper MTR register as determine by the csrow and channel desired
  */
-static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel)
+static int determine_mtr(struct i5000_pvt *pvt, int slot, int channel)
 {
 	int mtr;
 
 	if (channel < CHANNELS_PER_BRANCH)
-		mtr = pvt->b0_mtr[csrow >> 1];
+		mtr = pvt->b0_mtr[slot];
 	else
-		mtr = pvt->b1_mtr[csrow >> 1];
+		mtr = pvt->b1_mtr[slot];
 
 	return mtr;
 }
@@ -994,37 +995,34 @@ static void decode_mtr(int slot_row, u16 mtr)
 	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
 }
 
-static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
+static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
 			struct i5000_dimm_info *dinfo)
 {
 	int mtr;
 	int amb_present_reg;
 	int addrBits;
 
-	mtr = determine_mtr(pvt, csrow, channel);
+	mtr = determine_mtr(pvt, slot, channel);
 	if (MTR_DIMMS_PRESENT(mtr)) {
 		amb_present_reg = determine_amb_present_reg(pvt, channel);
 
-		/* Determine if there is  a  DIMM present in this DIMM slot */
-		if (amb_present_reg & (1 << (csrow >> 1))) {
+		/* Determine if there is a DIMM present in this DIMM slot */
+		if (amb_present_reg) {
 			dinfo->dual_rank = MTR_DIMM_RANK(mtr);
 
-			if (!((dinfo->dual_rank == 0) &&
-				((csrow & 0x1) == 0x1))) {
-				/* Start with the number of bits for a Bank
-				 * on the DRAM */
-				addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
-				/* Add thenumber of ROW bits */
-				addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
-				/* add the number of COLUMN bits */
-				addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
-
-				addrBits += 6;	/* add 64 bits per DIMM */
-				addrBits -= 20;	/* divide by 2^^20 */
-				addrBits -= 3;	/* 8 bits per bytes */
-
-				dinfo->megabytes = 1 << addrBits;
-			}
+			/* Start with the number of bits for a Bank
+				* on the DRAM */
+			addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
+			/* Add the number of ROW bits */
+			addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+			/* add the number of COLUMN bits */
+			addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+
+			addrBits += 6;	/* add 64 bits per DIMM */
+			addrBits -= 20;	/* divide by 2^^20 */
+			addrBits -= 3;	/* 8 bits per bytes */
+
+			dinfo->megabytes = 1 << addrBits;
 		}
 	}
 }
@@ -1038,10 +1036,9 @@ static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
 static void calculate_dimm_size(struct i5000_pvt *pvt)
 {
 	struct i5000_dimm_info *dinfo;
-	int csrow, max_csrows;
+	int slot, channel, branch;
 	char *p, *mem_buffer;
 	int space, n;
-	int channel;
 
 	/* ================= Generate some debug output ================= */
 	space = PAGE_SIZE;
@@ -1052,22 +1049,17 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 		return;
 	}
 
-	n = snprintf(p, space, "\n");
-	p += n;
-	space -= n;
-
-	/* Scan all the actual CSROWS (which is # of DIMMS * 2)
+	/* Scan all the actual slots
 	 * and calculate the information for each DIMM
-	 * Start with the highest csrow first, to display it first
-	 * and work toward the 0th csrow
+	 * Start with the highest slot first, to display it first
+	 * and work toward the 0th slot
 	 */
-	max_csrows = pvt->maxdimmperch * 2;
-	for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
+	for (slot = pvt->maxdimmperch - 1; slot >= 0; slot--) {
 
-		/* on an odd csrow, first output a 'boundary' marker,
+		/* on an odd slot, first output a 'boundary' marker,
 		 * then reset the message buffer  */
-		if (csrow & 0x1) {
-			n = snprintf(p, space, "---------------------------"
+		if (slot & 0x1) {
+			n = snprintf(p, space, "--------------------------"
 				"--------------------------------");
 			p += n;
 			space -= n;
@@ -1075,30 +1067,39 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 			p = mem_buffer;
 			space = PAGE_SIZE;
 		}
-		n = snprintf(p, space, "csrow %2d    ", csrow);
+		n = snprintf(p, space, "slot %2d    ", slot);
 		p += n;
 		space -= n;
 
 		for (channel = 0; channel < pvt->maxch; channel++) {
-			dinfo = &pvt->dimm_info[csrow][channel];
-			handle_channel(pvt, csrow, channel, dinfo);
-			n = snprintf(p, space, "%4d MB   | ", dinfo->megabytes);
+			dinfo = &pvt->dimm_info[slot][channel];
+			handle_channel(pvt, slot, channel, dinfo);
+			if (dinfo->megabytes)
+				n = snprintf(p, space, "%4d MB %dR| ",
+					     dinfo->megabytes, dinfo->dual_rank + 1);
+			else
+				n = snprintf(p, space, "%4d MB   | ", 0);
 			p += n;
 			space -= n;
 		}
-		n = snprintf(p, space, "\n");
 		p += n;
 		space -= n;
+		debugf2("%s\n", mem_buffer);
+		p = mem_buffer;
+		space = PAGE_SIZE;
 	}
 
 	/* Output the last bottom 'boundary' marker */
-	n = snprintf(p, space, "---------------------------"
-		"--------------------------------\n");
+	n = snprintf(p, space, "--------------------------"
+		"--------------------------------");
 	p += n;
 	space -= n;
+	debugf2("%s\n", mem_buffer);
+	p = mem_buffer;
+	space = PAGE_SIZE;
 
 	/* now output the 'channel' labels */
-	n = snprintf(p, space, "            ");
+	n = snprintf(p, space, "           ");
 	p += n;
 	space -= n;
 	for (channel = 0; channel < pvt->maxch; channel++) {
@@ -1106,9 +1107,17 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
 		p += n;
 		space -= n;
 	}
-	n = snprintf(p, space, "\n");
+	debugf2("%s\n", mem_buffer);
+	p = mem_buffer;
+	space = PAGE_SIZE;
+
+	n = snprintf(p, space, "           ");
 	p += n;
-	space -= n;
+	for (branch = 0; branch < MAX_BRANCHES; branch++) {
+		n = snprintf(p, space, "       branch %d       | ", branch);
+		p += n;
+		space -= n;
+	}
 
 	/* output the last message and free buffer */
 	debugf2("%s\n", mem_buffer);
@@ -1241,14 +1250,13 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
 static int i5000_init_csrows(struct mem_ctl_info *mci)
 {
 	struct i5000_pvt *pvt;
-	struct csrow_info *p_csrow;
 	struct dimm_info *dimm;
 	int empty, channel_count;
 	int max_csrows;
-	int mtr, mtr1;
+	int mtr;
 	int csrow_megs;
 	int channel;
-	int csrow;
+	int slot;
 
 	pvt = mci->pvt_info;
 
@@ -1258,26 +1266,25 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
 	empty = 1;		/* Assume NO memory */
 
 	/*
-	 * TODO: it would be better to not use csrow here, filling
-	 * directly the dimm_info structs, based on branch, channel, dim number
+	 * FIXME: The memory layout used to map slot/channel into the
+	 * real memory architecture is weird: branch+slot are "csrows"
+	 * and channel is channel. That required an extra array (dimm_info)
+	 * to map the dimms. A good cleanup would be to remove this array,
+	 * and do a loop here with branch, channel, slot
 	 */
-	for (csrow = 0; csrow < max_csrows; csrow++) {
-		p_csrow = &mci->csrows[csrow];
+	for (slot = 0; slot < max_csrows; slot++) {
+		for (channel = 0; channel < pvt->maxch; channel++) {
 
-		p_csrow->csrow_idx = csrow;
+			mtr = determine_mtr(pvt, slot, channel);
 
-		/* use branch 0 for the basis */
-		mtr = pvt->b0_mtr[csrow >> 1];
-		mtr1 = pvt->b1_mtr[csrow >> 1];
+			if (!MTR_DIMMS_PRESENT(mtr))
+				continue;
 
-		/* if no DIMMS on this row, continue */
-		if (!MTR_DIMMS_PRESENT(mtr) && !MTR_DIMMS_PRESENT(mtr1))
-			continue;
+			dimm = GET_POS(mci->layers, mci->dimms, mci->n_layers,
+				       channel / MAX_BRANCHES,
+				       channel % MAX_BRANCHES, slot);
 
-		csrow_megs = 0;
-		for (channel = 0; channel < pvt->maxch; channel++) {
-			dimm = p_csrow->channels[channel].dimm;
-			csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
+			csrow_megs = pvt->dimm_info[slot][channel].megabytes;
 			dimm->grain = 8;
 
 			/* Assume DDR2 for now */
@@ -1290,7 +1297,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
 				dimm->dtype = DEV_X4;
 
 			dimm->edac_mode = EDAC_S8ECD8ED;
-			dimm->nr_pages = (csrow_megs << 8) / pvt->maxch;
+			dimm->nr_pages = csrow_megs << 8;
 		}
 
 		empty = 0;
@@ -1337,7 +1344,7 @@ static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
 	 * supported on this memory controller
 	 */
 	pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
-	*num_dimms_per_channel = (int)value *2;
+	*num_dimms_per_channel = (int)value;
 
 	pci_read_config_byte(pdev, MAXCH, &value);
 	*num_channels = (int)value;
@@ -1387,11 +1394,12 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 		__func__, num_channels, num_dimms_per_channel);
 
 	/* allocate a new MC control structure */
+
 	layers[0].type = EDAC_MC_LAYER_BRANCH;
-	layers[0].size = 2;
-	layers[0].is_csrow = true;
+	layers[0].size = MAX_BRANCHES;
+	layers[0].is_csrow = false;
 	layers[1].type = EDAC_MC_LAYER_CHANNEL;
-	layers[1].size = num_channels;
+	layers[1].size = num_channels / MAX_BRANCHES;
 	layers[1].is_csrow = false;
 	layers[2].type = EDAC_MC_LAYER_SLOT;
 	layers[2].size = num_dimms_per_channel;
Signature · 1 line
1.7.8
#30 lore raw

PATCH v13 6/25 e752x_edac: provide more info about how DIMMS/ranks are mapped

In reply to Mauro Carvalho Chehab

No funtional changes here. Only the comments got updated.

---
 drivers/edac/e752x_edac.c |   26 ++++++++++++++++++++++----
 1 files changed, 22 insertions(+), 4 deletions(-)
drivers/edac/e752x_edac.c +22 -4
index 5f20a8e..d9431eb 100644
@@ -4,10 +4,11 @@
  * This file may be distributed under the terms of the
  * GNU General Public License.
  *
- * See "enum e752x_chips" below for supported chipsets
+ * Implement support for the e7520, E7525, e7320 and i3100 memory controllers.
  *
- * Datasheet:
+ * Datasheets:
  *	http://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html
+ *	ftp://download.intel.com/design/intarch/datashts/31345803.pdf
  *
  * Written by Tom Zimmerman
  *
@@ -16,8 +17,6 @@
  * 	Wang Zhenyu at intel.com
  * 	Dave Jiang at mvista.com
  *
- * $Id: edac_e752x.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $
- *
  */
 
 #include <linux/module.h>
@@ -190,6 +189,25 @@ enum e752x_chips {
 	I3100 = 3
 };
 
+/*
+ * Those chips Support single-rank and dual-rank memories only.
+ *
+ * On e752x chips, the odd rows are present only on dual-rank memories.
+ * Dividing the rank by two will provide the dimm#
+ *
+ * i3100 MC has a different mapping: it supports only 4 ranks.
+ *
+ * The mapping is (from 1 to n):
+ *	slot	   single-ranked	double-ranked
+ *	dimm #1 -> rank #4		NA
+ *	dimm #2 -> rank #3		NA
+ *	dimm #3 -> rank #2		Ranks 2 and 3
+ *	dimm #4 -> rank $1		Ranks 1 and 4
+ *
+ * FIXME: The current mapping for i3100 considers that it supports up to 8
+ *	  ranks/chanel, but datasheet says that the MC supports only 4 ranks.
+ */
+
 struct e752x_pvt {
 	struct pci_dev *bridge_ck;
 	struct pci_dev *dev_d0f0;
Signature · 1 line
1.7.8
#31 lore raw

PATCH v13 7/25 edac: Rename the parent dev to pdev

In reply to Mauro Carvalho Chehab

As EDAC doesn't use struct device itself, it created a parent dev pointer called as "pdev". Now that we'll be converting it to use struct device, instead of struct devsys, this needs to be fixed.

No functional changes.

Cc Doug Thompson <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Mark Gross <[email protected]>
Cc Jason Uhlenkott <[email protected]>
Cc Tim Small <[email protected]>
Cc Ranganathan Desikan <[email protected]>
Cc "Arvind R." <[email protected]>
Cc Olof Johansson <[email protected]>
Cc Egor Martovetsky <[email protected]>
Cc Chris Metcalf <[email protected]>
Cc Michal Marek <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Joe Perches <[email protected]>
Cc Dmitry Eremin-Solenikov <[email protected]>
Cc Benjamin Herrenschmidt <[email protected]>
Cc Hitoshi Mitake <[email protected]>
Cc Andrew Morton <[email protected]>
Cc "Niklas Söderlund" <[email protected]>
Cc Shaohui Xie <[email protected]>
Cc Josh Boyer <[email protected]>
---
 drivers/edac/amd64_edac.c      |    2 +-
 drivers/edac/amd76x_edac.c     |    4 ++--
 drivers/edac/cell_edac.c       |   12 ++++++------
 drivers/edac/cpc925_edac.c     |    2 +-
 drivers/edac/e752x_edac.c      |    2 +-
 drivers/edac/e7xxx_edac.c      |    2 +-
 drivers/edac/edac_mc.c         |    8 ++++----
 drivers/edac/edac_mc_sysfs.c   |    2 +-
 drivers/edac/i3000_edac.c      |    4 ++--
 drivers/edac/i3200_edac.c      |    6 +++---
 drivers/edac/i5000_edac.c      |    2 +-
 drivers/edac/i5100_edac.c      |    2 +-
 drivers/edac/i5400_edac.c      |    2 +-
 drivers/edac/i7300_edac.c      |    2 +-
 drivers/edac/i7core_edac.c     |    4 ++--
 drivers/edac/i82443bxgx_edac.c |    4 ++--
 drivers/edac/i82860_edac.c     |    4 ++--
 drivers/edac/i82875p_edac.c    |    4 ++--
 drivers/edac/i82975x_edac.c    |    4 ++--
 drivers/edac/mpc85xx_edac.c    |    4 ++--
 drivers/edac/mv64x60_edac.c    |    2 +-
 drivers/edac/pasemi_edac.c     |    6 +++---
 drivers/edac/ppc4xx_edac.c     |    8 ++++----
 drivers/edac/r82600_edac.c     |    4 ++--
 drivers/edac/sb_edac.c         |    4 ++--
 drivers/edac/tile_edac.c       |    4 ++--
 drivers/edac/x38_edac.c        |    6 +++---
 include/linux/edac.h           |    2 +-
 28 files changed, 56 insertions(+), 56 deletions(-)
drivers/edac/amd64_edac.c +1 -1
index 445ff03..b26fc06 100644
@@ -2572,7 +2572,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 		goto err_siblings;
 
 	mci->pvt_info = pvt;
-	mci->dev = &pvt->F2->dev;
+	mci->pdev = &pvt->F2->dev;
 
 	setup_mci_misc_attrs(mci, fam_type);
 
drivers/edac/amd76x_edac.c +2 -2
index 0184e90..9a34c5f 100644
@@ -105,7 +105,7 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
 			&info->ecc_mode_status);
 
@@ -257,7 +257,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
 		return -ENOMEM;
 
 	debugf0("%s(): mci = %p\n", __func__, mci);
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = ems_mode ?
drivers/edac/cell_edac.c +6 -6
index 39616a3..9e53917 100644
@@ -36,7 +36,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 	struct csrow_info		*csrow = &mci->csrows[0];
 	unsigned long			address, pfn, offset, syndrome;
 
-	dev_dbg(mci->dev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
+	dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
 		priv->node, chan, ar);
 
 	/* Address decoding is likely a bit bogus, to dbl check */
@@ -59,7 +59,7 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
 	struct csrow_info		*csrow = &mci->csrows[0];
 	unsigned long			address, pfn, offset;
 
-	dev_dbg(mci->dev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
+	dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
 		priv->node, chan, ar);
 
 	/* Address decoding is likely a bit bogus, to dbl check */
@@ -83,7 +83,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
 	fir = in_be64(&priv->regs->mic_fir);
 #ifdef DEBUG
 	if (fir != priv->prev_fir) {
-		dev_dbg(mci->dev, "fir change : 0x%016lx\n", fir);
+		dev_dbg(mci->pdev, "fir change : 0x%016lx\n", fir);
 		priv->prev_fir = fir;
 	}
 #endif
@@ -119,7 +119,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
 		mb();	/* sync up */
 #ifdef DEBUG
 		fir = in_be64(&priv->regs->mic_fir);
-		dev_dbg(mci->dev, "fir clear  : 0x%016lx\n", fir);
+		dev_dbg(mci->pdev, "fir clear  : 0x%016lx\n", fir);
 #endif
 	}
 }
@@ -155,7 +155,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 			dimm->edac_mode = EDAC_SECDED;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 		}
-		dev_dbg(mci->dev,
+		dev_dbg(mci->pdev,
 			"Initialized on node %d, chanmask=0x%x,"
 			" first_page=0x%lx, nr_pages=0x%x\n",
 			priv->node, priv->chanmask,
@@ -212,7 +212,7 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
 	priv->regs = regs;
 	priv->node = pdev->id;
 	priv->chanmask = chanmask;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_XDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
drivers/edac/cpc925_edac.c +1 -1
index caaae0d..78881b1 100644
@@ -995,7 +995,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	pdata->edac_idx = edac_mc_idx++;
 	pdata->name = pdev->name;
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	platform_set_drvdata(pdev, mci);
 	mci->dev_name = dev_name(&pdev->dev);
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
drivers/edac/e752x_edac.c +1 -1
index d9431eb..9b252dd 100644
@@ -1309,7 +1309,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
 	/* FIXME - what if different memory types are in different csrows? */
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = E752X_REVISION;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 
 	debugf3("%s(): init pvt\n", __func__);
 	pvt = (struct e752x_pvt *)mci->pvt_info;
drivers/edac/e7xxx_edac.c +1 -1
index 54a6666..dba87a7 100644
@@ -458,7 +458,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 	/* FIXME - what if different memory types are in different csrows? */
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = E7XXX_REVISION;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	debugf3("%s(): init pvt\n", __func__);
 	pvt = (struct e7xxx_pvt *)mci->pvt_info;
 	pvt->dev_info = &e7xxx_devs[dev_idx];
drivers/edac/edac_mc.c +4 -4
index 002e6b6..c1af3d7 100644
@@ -91,7 +91,7 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci)
 		mci->nr_csrows, mci->csrows);
 	debugf3("\tmci->nr_dimms = %d, dimns = %p\n",
 		mci->tot_dimms, mci->dimms);
-	debugf3("\tdev = %p\n", mci->dev);
+	debugf3("\tdev = %p\n", mci->pdev);
 	debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
 	debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
 }
@@ -425,7 +425,7 @@ struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 	list_for_each(item, &mc_devices) {
 		mci = list_entry(item, struct mem_ctl_info, link);
 
-		if (mci->dev == dev)
+		if (mci->pdev == dev)
 			return mci;
 	}
 
@@ -577,7 +577,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
 	insert_before = &mc_devices;
 
-	p = find_mci_by_dev(mci->dev);
+	p = find_mci_by_dev(mci->pdev);
 	if (unlikely(p != NULL))
 		goto fail0;
 
@@ -599,7 +599,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
 fail0:
 	edac_printk(KERN_WARNING, EDAC_MC,
-		"%s (%s) %s %s already assigned %d\n", dev_name(p->dev),
+		"%s (%s) %s %s already assigned %d\n", dev_name(p->pdev),
 		edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
 	return 1;
 
drivers/edac/edac_mc_sysfs.c +1 -1
index cfeb92c..c0dde23 100644
@@ -916,7 +916,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 	INIT_LIST_HEAD(&mci->grp_kobj_list);
 
 	/* create a symlink for the device */
-	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
+	err = sysfs_create_link(kobj_mci, &mci->pdev->kobj,
 				EDAC_DEVICE_SYMLINK);
 	if (err) {
 		debugf1("%s() failure to create symlink\n", __func__);
drivers/edac/i3000_edac.c +2 -2
index 2032d198..2ee50ab 100644
@@ -194,7 +194,7 @@ static void i3000_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -368,7 +368,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 
 	debugf3("MC: %s(): init mci\n", __func__);
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
drivers/edac/i3200_edac.c +3 -3
index 9a35487..798fb65 100644
@@ -159,7 +159,7 @@ static void i3200_clear_error_info(struct mem_ctl_info *mci)
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * Clear any error bits.
@@ -176,7 +176,7 @@ static void i3200_get_and_clear_error_info(struct mem_ctl_info *mci,
 	struct i3200_priv *priv = mci->pvt_info;
 	void __iomem *window = priv->window;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -354,7 +354,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 
 	debugf3("MC: %s(): init mci\n", __func__);
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
drivers/edac/i5000_edac.c +1 -1
index 659a868..60ed0ce 100644
@@ -1412,7 +1412,7 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 	kobject_get(&mci->edac_mci_kobj);
 	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
-	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
 
 	pvt = mci->pvt_info;
 	pvt->system_address = pdev;	/* Record this device in our private */
drivers/edac/i5100_edac.c +1 -1
index fda60f8..11aba5e 100644
@@ -943,7 +943,7 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
 		goto bail_disable_ch1;
 	}
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 
 	priv = mci->pvt_info;
 	priv->ranksperchan = ranksperch;
drivers/edac/i5400_edac.c +1 -1
index 5debda9..a16a2b5 100644
@@ -1300,7 +1300,7 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
 
 	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
-	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
 
 	pvt = mci->pvt_info;
 	pvt->system_address = pdev;	/* Record this device in our private */
drivers/edac/i7300_edac.c +1 -1
index 0ff0b26..57f264d 100644
@@ -1061,7 +1061,7 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
 
 	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
 
-	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
 
 	pvt = mci->pvt_info;
 	pvt->pci_dev_16_0_fsb_ctlr = pdev;	/* Record this device in our private */
drivers/edac/i7core_edac.c +2 -2
index 42775c4..7f81a04 100644
@@ -2119,7 +2119,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
 	i7core_pci_ctl_release(pvt);
 
 	/* Remove MC sysfs nodes */
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 
 	debugf1("%s: free mci struct\n", mci->ctl_name);
 	kfree(mci->ctl_name);
@@ -2185,7 +2185,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 	/* Get dimm basic config */
 	get_dimm_config(mci);
 	/* record ptr to the generic device */
-	mci->dev = &i7core_dev->pdev[0]->dev;
+	mci->pdev = &i7core_dev->pdev[0]->dev;
 	/* Set the function pointer to an actual operation function */
 	mci->edac_check = i7core_check_error;
 
drivers/edac/i82443bxgx_edac.c +2 -2
index 23a0b5d..4c572545 100644
@@ -124,7 +124,7 @@ static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
 				*info)
 {
 	struct pci_dev *pdev;
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 	pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
 	if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
 		/* Clear error to allow next error to be reported [p.61] */
@@ -260,7 +260,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
 		return -ENOMEM;
 
 	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
drivers/edac/i82860_edac.c +2 -2
index b49b3b5..16a54bb 100644
@@ -67,7 +67,7 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -211,7 +211,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
 		return -ENOMEM;
 
 	debugf3("%s(): init mci\n", __func__);
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	/* I"m not sure about this but I think that all RDRAM is SECDED */
drivers/edac/i82875p_edac.c +2 -2
index c2c82c3..8de9250 100644
@@ -189,7 +189,7 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -430,7 +430,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 	kobject_get(&mci->edac_mci_kobj);
 
 	debugf3("%s(): init mci\n", __func__);
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_UNKNOWN;
drivers/edac/i82975x_edac.c +2 -2
index c7db489..ae2a857 100644
@@ -241,7 +241,7 @@ static void i82975x_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -562,7 +562,7 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
 	}
 
 	debugf3("%s(): init mci\n", __func__);
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
drivers/edac/mpc85xx_edac.c +2 -2
index a7f1ff1..6146ab7 100644
@@ -990,9 +990,9 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 	pdata = mci->pvt_info;
 	pdata->name = "mpc85xx_mc_err";
 	pdata->irq = NO_IRQ;
-	mci->dev = &op->dev;
+	mci->pdev = &op->dev;
 	pdata->edac_idx = edac_mc_idx++;
-	dev_set_drvdata(mci->dev, mci);
+	dev_set_drvdata(mci->pdev, mci);
 	mci->ctl_name = pdata->name;
 	mci->dev_name = pdata->name;
 
drivers/edac/mv64x60_edac.c +1 -1
index a32e9b6..ef0e710 100644
@@ -724,7 +724,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
 	}
 
 	pdata = mci->pvt_info;
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	platform_set_drvdata(pdev, mci);
 	pdata->name = "mv64x60_mc_err";
 	pdata->irq = NO_IRQ;
drivers/edac/pasemi_edac.c +3 -3
index caf17c8..47542e7 100644
@@ -74,7 +74,7 @@ static int system_mmc_id;
 
 static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
 {
-	struct pci_dev *pdev = to_pci_dev(mci->dev);
+	struct pci_dev *pdev = to_pci_dev(mci->pdev);
 	u32 tmp;
 
 	pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
@@ -95,7 +95,7 @@ static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
 
 static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 {
-	struct pci_dev *pdev = to_pci_dev(mci->dev);
+	struct pci_dev *pdev = to_pci_dev(mci->pdev);
 	u32 errlog1a;
 	u32 cs;
 
@@ -225,7 +225,7 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
 		MCCFG_ERRCOR_ECC_GEN_EN |
 		MCCFG_ERRCOR_ECC_CRR_EN;
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
drivers/edac/ppc4xx_edac.c +4 -4
index 89e3147..3917b0f 100644
@@ -1027,9 +1027,9 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
 
 	/* Initial driver pointers and private data */
 
-	mci->dev		= &op->dev;
+	mci->pdev		= &op->dev;
 
-	dev_set_drvdata(mci->dev, mci);
+	dev_set_drvdata(mci->pdev, mci);
 
 	pdata			= mci->pvt_info;
 
@@ -1334,7 +1334,7 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op)
 	return 0;
 
  fail1:
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 
  fail:
 	edac_mc_free(mci);
@@ -1368,7 +1368,7 @@ ppc4xx_edac_remove(struct platform_device *op)
 
 	dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN);
 
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 	edac_mc_free(mci);
 
 	return 0;
drivers/edac/r82600_edac.c +2 -2
index fe060db..10464c5 100644
@@ -140,7 +140,7 @@ static void r82600_get_error_info(struct mem_ctl_info *mci,
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 	pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
 
 	if (info->eapr & BIT(0))
@@ -296,7 +296,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 		return -ENOMEM;
 
 	debugf0("%s(): mci = %p\n", __func__, mci);
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	/* FIXME try to work out if the chip leads have been used for COM2
drivers/edac/sb_edac.c +2 -2
index ad27e27..ff07f34 100644
@@ -1612,7 +1612,7 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 	mce_unregister_decode_chain(&sbridge_mce_dec);
 
 	/* Remove MC sysfs nodes */
-	edac_mc_del_mc(mci->dev);
+	edac_mc_del_mc(mci->pdev);
 
 	debugf1("%s: free mci struct\n", mci->ctl_name);
 	kfree(mci->ctl_name);
@@ -1677,7 +1677,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 	get_memory_layout(mci);
 
 	/* record ptr to the generic device */
-	mci->dev = &sbridge_dev->pdev[0]->dev;
+	mci->pdev = &sbridge_dev->pdev[0]->dev;
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (unlikely(edac_mc_add_mc(mci))) {
drivers/edac/tile_edac.c +2 -2
index 3e878bf..32cb2c7 100644
@@ -69,7 +69,7 @@ static void tile_edac_check(struct mem_ctl_info *mci)
 
 	/* Check if the current error count is different from the saved one. */
 	if (mem_error.sbe_count != priv->ce_count) {
-		dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node);
+		dev_dbg(mci->pdev, "ECC CE err on node %d\n", priv->node);
 		priv->ce_count = mem_error.sbe_count;
 		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     0, 0, 0,
@@ -149,7 +149,7 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
 	priv->node = pdev->id;
 	priv->hv_devhdl = hv_devhdl;
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
 
drivers/edac/x38_edac.c +3 -3
index 996d548..dde47e9 100644
@@ -151,7 +151,7 @@ static void x38_clear_error_info(struct mem_ctl_info *mci)
 {
 	struct pci_dev *pdev;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * Clear any error bits.
@@ -172,7 +172,7 @@ static void x38_get_and_clear_error_info(struct mem_ctl_info *mci,
 	struct pci_dev *pdev;
 	void __iomem *window = mci->pvt_info;
 
-	pdev = to_pci_dev(mci->dev);
+	pdev = to_pci_dev(mci->pdev);
 
 	/*
 	 * This is a mess because there is no atomic way to read all the
@@ -354,7 +354,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 
 	debugf3("MC: %s(): init mci\n", __func__);
 
-	mci->dev = &pdev->dev;
+	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR2;
 
 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
include/linux/edac.h +1 -1
index 6d8c394..ffb189b 100644
@@ -546,7 +546,7 @@ struct mem_ctl_info {
 	 * unique.  dev pointer should be sufficiently unique, but
 	 * BUS:SLOT.FUNC numbers may not be unique.
 	 */
-	struct device *dev;
+	struct device *pdev;
 	const char *mod_name;
 	const char *mod_ver;
 	const char *ctl_name;
Signature · 1 line
1.7.8
#32 lore raw

PATCH v13 8/25 edac: use Documentation-nano format for some data structs

In reply to Mauro Carvalho Chehab

No functional changes. Just comment improvements.

---
 include/linux/edac.h |   80 +++++++++++++++++++++++++++++++++++--------------
 1 files changed, 57 insertions(+), 23 deletions(-)
include/linux/edac.h +57 -23
index ffb189b..138b147 100644
@@ -45,7 +45,19 @@ static inline void opstate_init(void)
 #define EDAC_MC_LABEL_LEN	31
 #define MC_PROC_NAME_MAX_LEN	7
 
-/* memory devices */
+/**
+ * enum dev_type - describe the type of memory DRAM chips used at the stick
+ * @DEV_UNKNOWN:	Can't be determined, or MC doesn't support detect it
+ * @DEV_X1:		1 bit for data
+ * @DEV_X2:		2 bits for data
+ * @DEV_X4:		4 bits for data
+ * @DEV_X8:		8 bits for data
+ * @DEV_X16:		16 bits for data
+ * @DEV_X32:		32 bits for data
+ * @DEV_X64:		64 bits for data
+ *
+ * Typical values are x4 and x8.
+ */
 enum dev_type {
 	DEV_UNKNOWN = 0,
 	DEV_X1,
@@ -163,18 +175,29 @@ enum mem_type {
 #define MEM_FLAG_DDR3		 BIT(MEM_DDR3)
 #define MEM_FLAG_RDDR3		 BIT(MEM_RDDR3)
 
-/* chipset Error Detection and Correction capabilities and mode */
+/** enum edac-type - Error Detection and Correction capabilities and mode
+ * @EDAC_UNKNOWN:	Unknown if ECC is available
+ * @EDAC_NONE:		Doesn't support ECC
+ * @EDAC_RESERVED:	Reserved ECC type
+ * @EDAC_PARITY:	Detects parity errors
+ * @EDAC_EC:		Error Checking - no correction
+ * @EDAC_SECDED:	Single bit error correction, Double detection
+ * @EDAC_S2ECD2ED:	Chipkill x2 devices - do these exist?
+ * @EDAC_S4ECD4ED:	Chipkill x4 devices
+ * @EDAC_S8ECD8ED:	Chipkill x8 devices
+ * @EDAC_S16ECD16ED:	Chipkill x16 devices
+ */
 enum edac_type {
-	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
-	EDAC_NONE,		/* Doesn't support ECC */
-	EDAC_RESERVED,		/* Reserved ECC type */
-	EDAC_PARITY,		/* Detects parity errors */
-	EDAC_EC,		/* Error Checking - no correction */
-	EDAC_SECDED,		/* Single bit error correction, Double detection */
-	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
-	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
-	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
-	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
+	EDAC_UNKNOWN =	0,
+	EDAC_NONE,
+	EDAC_RESERVED,
+	EDAC_PARITY,
+	EDAC_EC,
+	EDAC_SECDED,
+	EDAC_S2ECD2ED,
+	EDAC_S4ECD4ED,
+	EDAC_S8ECD8ED,
+	EDAC_S16ECD16ED,
 };
 
 #define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)
@@ -187,18 +210,29 @@ enum edac_type {
 #define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
 
-/* scrubbing capabilities */
+/** enum scrub_type - scrubbing capabilities
+ * @SCRUB_UNKNOWN		Unknown if scrubber is available
+ * @SCRUB_NONE:			No scrubber
+ * @SCRUB_SW_PROG:		SW progressive (sequential) scrubbing
+ * @SCRUB_SW_SRC:		Software scrub only errors
+ * @SCRUB_SW_PROG_SRC:		Progressive software scrub from an error
+ * @SCRUB_SW_TUNABLE:		Software scrub frequency is tunable
+ * @SCRUB_HW_PROG:		HW progressive (sequential) scrubbing
+ * @SCRUB_HW_SRC:		Hardware scrub only errors
+ * @SCRUB_HW_PROG_SRC:		Progressive hardware scrub from an error
+ * SCRUB_HW_TUNABLE:		Hardware scrub frequency is tunable
+ */
 enum scrub_type {
-	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-	SCRUB_NONE,		/* No scrubber */
-	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
-	SCRUB_SW_SRC,		/* Software scrub only errors */
-	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
-	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
+	SCRUB_UNKNOWN =	0,
+	SCRUB_NONE,
+	SCRUB_SW_PROG,
+	SCRUB_SW_SRC,
+	SCRUB_SW_PROG_SRC,
+	SCRUB_SW_TUNABLE,
+	SCRUB_HW_PROG,
+	SCRUB_HW_SRC,
+	SCRUB_HW_PROG_SRC,
+	SCRUB_HW_TUNABLE
 };
 
 #define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
Signature · 1 line
1.7.8
#33 lore raw

Re: [EDAC ABI v13 08/25] edac: use Documentation-nano format for some data structs

Quoted 35 lines · Mauro Carvalho Chehab

No functional changes. Just comment improvements.

---
 include/linux/edac.h |   80 +++++++++++++++++++++++++++++++++++--------------
 1 files changed, 57 insertions(+), 23 deletions(-)
include/linux/edac.h +13 -1
index ffb189b..138b147 100644
@@ -45,7 +45,19 @@ static inline void opstate_init(void)
 #define EDAC_MC_LABEL_LEN	31
 #define MC_PROC_NAME_MAX_LEN	7
 
-/* memory devices */
+/**
+ * enum dev_type - describe the type of memory DRAM chips used at the stick
+ * @DEV_UNKNOWN:	Can't be determined, or MC doesn't support detect it
+ * @DEV_X1:		1 bit for data
+ * @DEV_X2:		2 bits for data
+ * @DEV_X4:		4 bits for data
+ * @DEV_X8:		8 bits for data
+ * @DEV_X16:		16 bits for data
+ * @DEV_X32:		32 bits for data
+ * @DEV_X64:		64 bits for data
+ *
+ * Typical values are x4 and x8.
+ */
 enum dev_type {
 	DEV_UNKNOWN = 0,
 	DEV_X1,

include/linux/edac.h enum mem_type { · line 178

Quoted 5 lines
include/linux/edac.h +1 -1
@@ -163,18 +175,29 @@ enum mem_type {
 #define MEM_FLAG_DDR3		 BIT(MEM_DDR3)
 #define MEM_FLAG_RDDR3		 BIT(MEM_RDDR3)
 
-/* chipset Error Detection and Correction capabilities and mode */
+/** enum edac-type - Error Detection and Correction capabilities and mode

This probably needs to be

/**
* enum edac-type

with the text starting on the second line and leaving the "/**" marker alone on the first line.

Quoted 36 lines
include/linux/edac.h +21 -10
+ * @EDAC_UNKNOWN:	Unknown if ECC is available
+ * @EDAC_NONE:		Doesn't support ECC
+ * @EDAC_RESERVED:	Reserved ECC type
+ * @EDAC_PARITY:	Detects parity errors
+ * @EDAC_EC:		Error Checking - no correction
+ * @EDAC_SECDED:	Single bit error correction, Double detection
+ * @EDAC_S2ECD2ED:	Chipkill x2 devices - do these exist?
+ * @EDAC_S4ECD4ED:	Chipkill x4 devices
+ * @EDAC_S8ECD8ED:	Chipkill x8 devices
+ * @EDAC_S16ECD16ED:	Chipkill x16 devices
+ */
 enum edac_type {
-	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
-	EDAC_NONE,		/* Doesn't support ECC */
-	EDAC_RESERVED,		/* Reserved ECC type */
-	EDAC_PARITY,		/* Detects parity errors */
-	EDAC_EC,		/* Error Checking - no correction */
-	EDAC_SECDED,		/* Single bit error correction, Double detection */
-	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
-	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
-	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
-	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
+	EDAC_UNKNOWN =	0,
+	EDAC_NONE,
+	EDAC_RESERVED,
+	EDAC_PARITY,
+	EDAC_EC,
+	EDAC_SECDED,
+	EDAC_S2ECD2ED,
+	EDAC_S4ECD4ED,
+	EDAC_S8ECD8ED,
+	EDAC_S16ECD16ED,
 };
 
 #define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)

include/linux/edac.h enum edac_type { · line 213

Quoted 5 lines
include/linux/edac.h +1 -1
@@ -187,18 +210,29 @@ enum edac_type {
 #define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
 
-/* scrubbing capabilities */
+/** enum scrub_type - scrubbing capabilities

ditto.

Quoted 43 lines
include/linux/edac.h +21 -10
+ * @SCRUB_UNKNOWN		Unknown if scrubber is available
+ * @SCRUB_NONE:			No scrubber
+ * @SCRUB_SW_PROG:		SW progressive (sequential) scrubbing
+ * @SCRUB_SW_SRC:		Software scrub only errors
+ * @SCRUB_SW_PROG_SRC:		Progressive software scrub from an error
+ * @SCRUB_SW_TUNABLE:		Software scrub frequency is tunable
+ * @SCRUB_HW_PROG:		HW progressive (sequential) scrubbing
+ * @SCRUB_HW_SRC:		Hardware scrub only errors
+ * @SCRUB_HW_PROG_SRC:		Progressive hardware scrub from an error
+ * SCRUB_HW_TUNABLE:		Hardware scrub frequency is tunable
+ */
 enum scrub_type {
-	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-	SCRUB_NONE,		/* No scrubber */
-	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
-	SCRUB_SW_SRC,		/* Software scrub only errors */
-	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
-	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
+	SCRUB_UNKNOWN =	0,
+	SCRUB_NONE,
+	SCRUB_SW_PROG,
+	SCRUB_SW_SRC,
+	SCRUB_SW_PROG_SRC,
+	SCRUB_SW_TUNABLE,
+	SCRUB_HW_PROG,
+	SCRUB_HW_SRC,
+	SCRUB_HW_PROG_SRC,
+	SCRUB_HW_TUNABLE
 };
 
 #define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
Signature · 6 lines
1.7.8

--
To unsubscribe from this list: send the line "unsubscribe linux-edac" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
author Reviewed-by Aristeu Rozanski
#34 lore raw

Re: [EDAC ABI v13 08/25] edac: use Documentation-nano format for some data structs

Em 09-05-2012 09:23, Borislav Petkov escreveu:

Quoted 132 lines · Mauro Carvalho Chehab
Quoted 35 lines

No functional changes. Just comment improvements.

---
 include/linux/edac.h |   80 +++++++++++++++++++++++++++++++++++--------------
 1 files changed, 57 insertions(+), 23 deletions(-)
include/linux/edac.h +13 -1
index ffb189b..138b147 100644
@@ -45,7 +45,19 @@ static inline void opstate_init(void)
 #define EDAC_MC_LABEL_LEN	31
 #define MC_PROC_NAME_MAX_LEN	7
 
-/* memory devices */
+/**
+ * enum dev_type - describe the type of memory DRAM chips used at the stick
+ * @DEV_UNKNOWN:	Can't be determined, or MC doesn't support detect it
+ * @DEV_X1:		1 bit for data
+ * @DEV_X2:		2 bits for data
+ * @DEV_X4:		4 bits for data
+ * @DEV_X8:		8 bits for data
+ * @DEV_X16:		16 bits for data
+ * @DEV_X32:		32 bits for data
+ * @DEV_X64:		64 bits for data
+ *
+ * Typical values are x4 and x8.
+ */
 enum dev_type {
 	DEV_UNKNOWN = 0,
 	DEV_X1,

include/linux/edac.h enum mem_type { · line 178

Quoted 5 lines
include/linux/edac.h +1 -1
@@ -163,18 +175,29 @@ enum mem_type {
 #define MEM_FLAG_DDR3		 BIT(MEM_DDR3)
 #define MEM_FLAG_RDDR3		 BIT(MEM_RDDR3)
 
-/* chipset Error Detection and Correction capabilities and mode */
+/** enum edac-type - Error Detection and Correction capabilities and mode

This probably needs to be

/**
* enum edac-type

with the text starting on the second line and leaving the "/**" marker alone on the first line.

Quoted 36 lines
include/linux/edac.h +21 -10
+ * @EDAC_UNKNOWN:	Unknown if ECC is available
+ * @EDAC_NONE:		Doesn't support ECC
+ * @EDAC_RESERVED:	Reserved ECC type
+ * @EDAC_PARITY:	Detects parity errors
+ * @EDAC_EC:		Error Checking - no correction
+ * @EDAC_SECDED:	Single bit error correction, Double detection
+ * @EDAC_S2ECD2ED:	Chipkill x2 devices - do these exist?
+ * @EDAC_S4ECD4ED:	Chipkill x4 devices
+ * @EDAC_S8ECD8ED:	Chipkill x8 devices
+ * @EDAC_S16ECD16ED:	Chipkill x16 devices
+ */
 enum edac_type {
-	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
-	EDAC_NONE,		/* Doesn't support ECC */
-	EDAC_RESERVED,		/* Reserved ECC type */
-	EDAC_PARITY,		/* Detects parity errors */
-	EDAC_EC,		/* Error Checking - no correction */
-	EDAC_SECDED,		/* Single bit error correction, Double detection */
-	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
-	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
-	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
-	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
+	EDAC_UNKNOWN =	0,
+	EDAC_NONE,
+	EDAC_RESERVED,
+	EDAC_PARITY,
+	EDAC_EC,
+	EDAC_SECDED,
+	EDAC_S2ECD2ED,
+	EDAC_S4ECD4ED,
+	EDAC_S8ECD8ED,
+	EDAC_S16ECD16ED,
 };
 
 #define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)

include/linux/edac.h enum edac_type { · line 213

Quoted 5 lines
include/linux/edac.h +1 -1
@@ -187,18 +210,29 @@ enum edac_type {
 #define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
 
-/* scrubbing capabilities */
+/** enum scrub_type - scrubbing capabilities

ditto.

Quoted 38 lines
include/linux/edac.h +21 -10
+ * @SCRUB_UNKNOWN		Unknown if scrubber is available
+ * @SCRUB_NONE:			No scrubber
+ * @SCRUB_SW_PROG:		SW progressive (sequential) scrubbing
+ * @SCRUB_SW_SRC:		Software scrub only errors
+ * @SCRUB_SW_PROG_SRC:		Progressive software scrub from an error
+ * @SCRUB_SW_TUNABLE:		Software scrub frequency is tunable
+ * @SCRUB_HW_PROG:		HW progressive (sequential) scrubbing
+ * @SCRUB_HW_SRC:		Hardware scrub only errors
+ * @SCRUB_HW_PROG_SRC:		Progressive hardware scrub from an error
+ * SCRUB_HW_TUNABLE:		Hardware scrub frequency is tunable
+ */
 enum scrub_type {
-	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-	SCRUB_NONE,		/* No scrubber */
-	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
-	SCRUB_SW_SRC,		/* Software scrub only errors */
-	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
-	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
+	SCRUB_UNKNOWN =	0,
+	SCRUB_NONE,
+	SCRUB_SW_PROG,
+	SCRUB_SW_SRC,
+	SCRUB_SW_PROG_SRC,
+	SCRUB_SW_TUNABLE,
+	SCRUB_HW_PROG,
+	SCRUB_HW_SRC,
+	SCRUB_HW_PROG_SRC,
+	SCRUB_HW_TUNABLE
 };
 
 #define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
Signature · 1 line
1.7.8
Quoted 6 lines
Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-edac" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Fixed, thanks!
Mauro

-

edac: use Documentation-nano format for some data structs

From: Mauro Carvalho Chehab <[email protected]>

No functional changes. Just comment improvements.

include/linux/edac.h +59 -23
index ff8f9d7..c8b8133 100644
@@ -45,7 +45,19 @@ static inline void opstate_init(void)
 #define EDAC_MC_LABEL_LEN	31
 #define MC_PROC_NAME_MAX_LEN	7
 
-/* memory devices */
+/**
+ * enum dev_type - describe the type of memory DRAM chips used at the stick
+ * @DEV_UNKNOWN:	Can't be determined, or MC doesn't support detect it
+ * @DEV_X1:		1 bit for data
+ * @DEV_X2:		2 bits for data
+ * @DEV_X4:		4 bits for data
+ * @DEV_X8:		8 bits for data
+ * @DEV_X16:		16 bits for data
+ * @DEV_X32:		32 bits for data
+ * @DEV_X64:		64 bits for data
+ *
+ * Typical values are x4 and x8.
+ */
 enum dev_type {
 	DEV_UNKNOWN = 0,
 	DEV_X1,
@@ -163,18 +175,30 @@ enum mem_type {
 #define MEM_FLAG_DDR3		 BIT(MEM_DDR3)
 #define MEM_FLAG_RDDR3		 BIT(MEM_RDDR3)
 
-/* chipset Error Detection and Correction capabilities and mode */
+/**
+ * enum edac-type - Error Detection and Correction capabilities and mode
+ * @EDAC_UNKNOWN:	Unknown if ECC is available
+ * @EDAC_NONE:		Doesn't support ECC
+ * @EDAC_RESERVED:	Reserved ECC type
+ * @EDAC_PARITY:	Detects parity errors
+ * @EDAC_EC:		Error Checking - no correction
+ * @EDAC_SECDED:	Single bit error correction, Double detection
+ * @EDAC_S2ECD2ED:	Chipkill x2 devices - do these exist?
+ * @EDAC_S4ECD4ED:	Chipkill x4 devices
+ * @EDAC_S8ECD8ED:	Chipkill x8 devices
+ * @EDAC_S16ECD16ED:	Chipkill x16 devices
+ */
 enum edac_type {
-	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
-	EDAC_NONE,		/* Doesn't support ECC */
-	EDAC_RESERVED,		/* Reserved ECC type */
-	EDAC_PARITY,		/* Detects parity errors */
-	EDAC_EC,		/* Error Checking - no correction */
-	EDAC_SECDED,		/* Single bit error correction, Double detection */
-	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
-	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
-	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
-	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
+	EDAC_UNKNOWN =	0,
+	EDAC_NONE,
+	EDAC_RESERVED,
+	EDAC_PARITY,
+	EDAC_EC,
+	EDAC_SECDED,
+	EDAC_S2ECD2ED,
+	EDAC_S4ECD4ED,
+	EDAC_S8ECD8ED,
+	EDAC_S16ECD16ED,
 };
 
 #define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)
@@ -187,18 +211,30 @@ enum edac_type {
 #define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
 
-/* scrubbing capabilities */
+/**
+ * enum scrub_type - scrubbing capabilities
+ * @SCRUB_UNKNOWN		Unknown if scrubber is available
+ * @SCRUB_NONE:			No scrubber
+ * @SCRUB_SW_PROG:		SW progressive (sequential) scrubbing
+ * @SCRUB_SW_SRC:		Software scrub only errors
+ * @SCRUB_SW_PROG_SRC:		Progressive software scrub from an error
+ * @SCRUB_SW_TUNABLE:		Software scrub frequency is tunable
+ * @SCRUB_HW_PROG:		HW progressive (sequential) scrubbing
+ * @SCRUB_HW_SRC:		Hardware scrub only errors
+ * @SCRUB_HW_PROG_SRC:		Progressive hardware scrub from an error
+ * SCRUB_HW_TUNABLE:		Hardware scrub frequency is tunable
+ */
 enum scrub_type {
-	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-	SCRUB_NONE,		/* No scrubber */
-	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
-	SCRUB_SW_SRC,		/* Software scrub only errors */
-	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
-	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
+	SCRUB_UNKNOWN =	0,
+	SCRUB_NONE,
+	SCRUB_SW_PROG,
+	SCRUB_SW_SRC,
+	SCRUB_SW_PROG_SRC,
+	SCRUB_SW_TUNABLE,
+	SCRUB_HW_PROG,
+	SCRUB_HW_SRC,
+	SCRUB_HW_PROG_SRC,
+	SCRUB_HW_TUNABLE
 };
 
 #define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
#35 lore raw

PATCH v13 9/25 edac: rewrite the sysfs code to use struct device

In reply to Mauro Carvalho Chehab

The EDAC subsystem uses the old struct sysdev approach, creating all nodes using the raw sysfs API. This is bad, as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing code to struct device.

There's one side-back on this patch: all device-specific sysfs nodes won't be created anymore. While it would be possible to also port the device-specific code, it is easier and nicer to move the code to the drivers, instead, as the core can get rid of some complex logic that just emulates what the device_add() and device_create_file() already does.

The next patches will convert the driver-specific code to use the device-specific calls. Then, the remaining bits of the old sysfs API will be removed.

---
 drivers/edac/edac_mc.c       |   12 +-
 drivers/edac/edac_mc_sysfs.c | 1061 ++++++++++++++++--------------------------
 drivers/edac/edac_module.c   |   13 +-
 drivers/edac/edac_module.h   |    9 +-
 include/linux/edac.h         |   47 ++-
 5 files changed, 434 insertions(+), 708 deletions(-)
drivers/edac/edac_mc.c +1 -11
index c1af3d7..019c5bd 100644
@@ -209,7 +209,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	unsigned size, tot_dimms, count, pos[EDAC_MAX_LAYERS];
 	unsigned tot_csrows, tot_cschannels;
 	int i, j, n, len;
-	int err;
 	int row, chn;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS);
@@ -369,15 +368,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	mci->op_state = OP_ALLOC;
 	INIT_LIST_HEAD(&mci->grp_kobj_list);
 
-	/*
-	 * Initialize the 'root' kobj for the edac_mc controller
-	 */
-	err = edac_mc_register_sysfs_main_kobj(mci);
-	if (err) {
-		kfree(mci);
-		return NULL;
-	}
-
 	/* at this point, the root kobj is valid, and in order to
 	 * 'free' the object, then the function:
 	 *      edac_mc_unregister_sysfs_main_kobj() must be called
@@ -400,7 +390,7 @@ void edac_mc_free(struct mem_ctl_info *mci)
 {
 	debugf1("%s()\n", __func__);
 
-	edac_mc_unregister_sysfs_main_kobj(mci);
+	edac_unregister_sysfs(mci);
 
 	/* free the mci instance memory here */
 	kfree(mci);
drivers/edac/edac_mc_sysfs.c +392 -669

1,319 lines not on this page · raw message

drivers/edac/edac_module.c +3 -10
index 5ddaa86..8735a0d 100644
@@ -90,10 +90,7 @@ static int __init edac_init(void)
 	 */
 	edac_pci_clear_parity_errors();
 
-	/*
-	 * now set up the mc_kset under the edac class object
-	 */
-	err = edac_sysfs_setup_mc_kset();
+	err = edac_mc_sysfs_init();
 	if (err)
 		goto error;
 
@@ -101,15 +98,11 @@ static int __init edac_init(void)
 	err = edac_workqueue_setup();
 	if (err) {
 		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
-		goto workq_fail;
+		goto error;
 	}
 
 	return 0;
 
-	/* Error teardown stack */
-workq_fail:
-	edac_sysfs_teardown_mc_kset();
-
 error:
 	return err;
 }
@@ -124,7 +117,7 @@ static void __exit edac_exit(void)
 
 	/* tear down the various subsystems */
 	edac_workqueue_teardown();
-	edac_sysfs_teardown_mc_kset();
+	edac_mc_sysfs_exit();
 }
 
 /*
drivers/edac/edac_module.h +5 -4
index 0be4b01..2934e5e 100644
@@ -19,12 +19,12 @@
  *
  * edac_mc objects
  */
-extern int edac_sysfs_setup_mc_kset(void);
-extern void edac_sysfs_teardown_mc_kset(void);
-extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
-extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+	/* on edac_mc_sysfs.c */
+int edac_mc_sysfs_init(void);
+void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+void edac_unregister_sysfs(struct mem_ctl_info *mci);
 extern int edac_get_log_ue(void);
 extern int edac_get_log_ce(void);
 extern int edac_get_panic_on_ue(void);
@@ -34,6 +34,7 @@ extern int edac_mc_get_panic_on_ue(void);
 extern int edac_get_poll_msec(void);
 extern int edac_mc_get_poll_msec(void);
 
+	/* on edac_device.c */
 extern int edac_device_register_sysfs_main_kobj(
 				struct edac_device_ctl_info *edac_dev);
 extern void edac_device_unregister_sysfs_main_kobj(
include/linux/edac.h +33 -14

97 lines not on this page · raw message

Signature · 1 line
1.7.8
#36 lore raw

Re: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device

Inserting latest version:

Quoted 5 lines

From e8765894c6d43326c9968a3687f5140708ee163f Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Mon, 16 Apr 2012 16:41:11 -0300
Subject: [PATCH] edac: rewrite the sysfs code to use struct device

Quoted 8 lines

The EDAC subsystem uses the old struct sysdev approach, creating all nodes using the raw sysfs API. This is bad, as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing code to struct device.

There's one side-back on this patch: all device-specific sysfs

drawback to

Quoted 1 line

nodes won't be created anymore. While it would be possible to

which device-specific nodes?

Quoted 5 lines

also port the device-specific code, it is easier and nicer to move the code to the drivers, instead, as the core can get rid of some complex logic that just emulates what the device_add() and device_create_file() already does.

Quoted 7 lines

The next patches will convert the driver-specific code to use the device-specific calls. Then, the remaining bits of the old sysfs API will be removed.

Btw, this patch is b0rked. Here's the EDAC debug output from the second node on when booting:

...

[    9.692291] EDAC amd64: F10h detected (node 1).
[    9.692324] EDAC DEBUG: reserve_mc_sibling_devs: F1: 0000:00:19.1
[    9.692330] EDAC DEBUG: reserve_mc_sibling_devs: F2: 0000:00:19.2
[    9.692335] EDAC DEBUG: reserve_mc_sibling_devs: F3: 0000:00:19.3
[    9.692341] EDAC DEBUG: read_mc_regs:   TOP_MEM:  0x00000000c8000000
[    9.692347] EDAC DEBUG: read_mc_regs:   TOP_MEM2: 0x0000001038000000
[    9.692356] EDAC DEBUG: read_dram_ctl_register: F2x110 (DCTSelLow): 0x000005e4, High range addrs at: 0x0
[    9.692363] EDAC DEBUG: read_dram_ctl_register:   DCTs operate in unganged mode.
[    9.692369] EDAC DEBUG: read_dram_ctl_register:   Address range split per DCT: no
[    9.692376] EDAC DEBUG: read_dram_ctl_register:   data interleave for ECC: enabled, DRAM cleared since last warm reset: yes
[    9.692384] EDAC DEBUG: read_dram_ctl_register:   channel interleave: enabled, interleave bits selector: 0x3
[    9.692395] EDAC DEBUG: read_mc_regs:   DRAM range[0], base: 0x0000000000000000; limit: 0x0000000437ffffff
[    9.692404] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=0
[    9.692413] EDAC DEBUG: read_mc_regs:   DRAM range[1], base: 0x0000000438000000; limit: 0x0000000837ffffff
[    9.692422] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=1
[    9.692431] EDAC DEBUG: read_mc_regs:   DRAM range[2], base: 0x0000000838000000; limit: 0x0000000c37ffffff
[    9.692439] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=2
[    9.692448] EDAC DEBUG: read_mc_regs:   DRAM range[3], base: 0x0000000c38000000; limit: 0x0000001037ffffff
[    9.692456] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=3
[    9.692469] EDAC DEBUG: read_dct_base_mask:   DCSB0[0]=0x00000001 reg: F2x40
[    9.692476] EDAC DEBUG: read_dct_base_mask:   DCSB1[0]=0x00000001 reg: F2x140
[    9.692483] EDAC DEBUG: read_dct_base_mask:   DCSB0[1]=0x00000201 reg: F2x44
[    9.692489] EDAC DEBUG: read_dct_base_mask:   DCSB1[1]=0x00000201 reg: F2x144
[    9.692496] EDAC DEBUG: read_dct_base_mask:   DCSB0[2]=0x00000401 reg: F2x48
[    9.692503] EDAC DEBUG: read_dct_base_mask:   DCSB1[2]=0x00000401 reg: F2x148
[    9.692510] EDAC DEBUG: read_dct_base_mask:   DCSB0[3]=0x00000601 reg: F2x4c
[    9.692516] EDAC DEBUG: read_dct_base_mask:   DCSB1[3]=0x00000601 reg: F2x14c
[    9.692523] EDAC DEBUG: read_dct_base_mask:   DCSB0[4]=0x00000000 reg: F2x50
[    9.692530] EDAC DEBUG: read_dct_base_mask:   DCSB1[4]=0x00000000 reg: F2x150
[    9.692537] EDAC DEBUG: read_dct_base_mask:   DCSB0[5]=0x00000000 reg: F2x54
[    9.692543] EDAC DEBUG: read_dct_base_mask:   DCSB1[5]=0x00000000 reg: F2x154
[    9.692550] EDAC DEBUG: read_dct_base_mask:   DCSB0[6]=0x00000000 reg: F2x58
[    9.692557] EDAC DEBUG: read_dct_base_mask:   DCSB1[6]=0x00000000 reg: F2x158
[    9.692564] EDAC DEBUG: read_dct_base_mask:   DCSB0[7]=0x00000000 reg: F2x5c
[    9.692570] EDAC DEBUG: read_dct_base_mask:   DCSB1[7]=0x00000000 reg: F2x15c
[    9.692577] EDAC DEBUG: read_dct_base_mask:     DCSM0[0]=0x01f839e0 reg: F2x60
[    9.692584] EDAC DEBUG: read_dct_base_mask:     DCSM1[0]=0x01f839e0 reg: F2x160
[    9.692591] EDAC DEBUG: read_dct_base_mask:     DCSM0[1]=0x01f839e0 reg: F2x64
[    9.692598] EDAC DEBUG: read_dct_base_mask:     DCSM1[1]=0x01f839e0 reg: F2x164
[    9.692605] EDAC DEBUG: read_dct_base_mask:     DCSM0[2]=0x00000000 reg: F2x68
[    9.692612] EDAC DEBUG: read_dct_base_mask:     DCSM1[2]=0x00000000 reg: F2x168
[    9.692619] EDAC DEBUG: read_dct_base_mask:     DCSM0[3]=0x00000000 reg: F2x6c
[    9.692625] EDAC DEBUG: read_dct_base_mask:     DCSM1[3]=0x00000000 reg: F2x16c
[    9.692635] EDAC DEBUG: dump_misc_regs: F3xE8 (NB Cap): 0x62f0df1f
[    9.692641] EDAC DEBUG: dump_misc_regs:   NB two channel DRAM capable: yes
[    9.692647] EDAC DEBUG: dump_misc_regs:   ECC capable: yes, ChipKill ECC capable: yes
[    9.692653] EDAC DEBUG: amd64_dump_dramcfg_low: F2x090 (DRAM Cfg Low): 0x00083100
[    9.692660] EDAC DEBUG: amd64_dump_dramcfg_low:   DIMM type: buffered; all DIMMs support ECC: yes
[    9.692666] EDAC DEBUG: amd64_dump_dramcfg_low:   PAR/ERR parity: enabled
[    9.692671] EDAC DEBUG: amd64_dump_dramcfg_low:   DCT 128bit mode width: 64b
[    9.692678] EDAC DEBUG: amd64_dump_dramcfg_low:   x4 logical DIMMs present: L0: yes L1: yes L2: no L3: no
[    9.692685] EDAC DEBUG: dump_misc_regs: F3xB0 (Online Spare): 0x00000000
[    9.692692] EDAC DEBUG: dump_misc_regs: F1xF0 (DRAM Hole Address): 0xc8000002, base: 0xc8000000, offset: 0x00000000
[    9.692699] EDAC DEBUG: dump_misc_regs:   DramHoleValid: no
[    9.692705] EDAC DEBUG: amd64_debug_display_dimm_sizes: F2x080 (DRAM Bank Address Mapping): 0x00000088
[    9.692711] EDAC MC: DCT0 chip selects:
[    9.692717] EDAC amd64: MC: 0:  2048MB 1:  2048MB
[    9.692723] EDAC amd64: MC: 2:  2048MB 3:  2048MB
[    9.692728] EDAC amd64: MC: 4:     0MB 5:     0MB
[    9.692733] EDAC amd64: MC: 6:     0MB 7:     0MB
[    9.692738] EDAC DEBUG: amd64_debug_display_dimm_sizes: F2x180 (DRAM Bank Address Mapping): 0x00000088
[    9.692744] EDAC MC: DCT1 chip selects:
[    9.692749] EDAC amd64: MC: 0:  2048MB 1:  2048MB
[    9.692754] EDAC amd64: MC: 2:  2048MB 3:  2048MB
[    9.692759] EDAC amd64: MC: 4:     0MB 5:     0MB
[    9.692764] EDAC amd64: MC: 6:     0MB 7:     0MB
[    9.692769] EDAC amd64: using x8 syndromes.
[    9.692774] EDAC DEBUG: amd64_dump_dramcfg_low: F2x190 (DRAM Cfg Low): 0x00083100
[    9.692780] EDAC DEBUG: amd64_dump_dramcfg_low:   DIMM type: buffered; all DIMMs support ECC: yes
[    9.692786] EDAC DEBUG: amd64_dump_dramcfg_low:   PAR/ERR parity: enabled
[    9.692791] EDAC DEBUG: amd64_dump_dramcfg_low:   DCT 128bit mode width: 64b
[    9.692798] EDAC DEBUG: amd64_dump_dramcfg_low:   x4 logical DIMMs present: L0: yes L1: yes L2: no L3: no
[    9.692805] EDAC DEBUG: f1x_early_channel_count: Data width is not 128 bits - need more decoding
[    9.692812] EDAC amd64: MCT channel count: 2
[    9.692821] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc(): allocating 30948 bytes for mci data (16 ranks, 16 csrows/channels)
[    9.692851] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 0: rank0 (0:0:0): row 0, chan 0
[    9.692863] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 1: rank1 (0:1:0): row 1, chan 0
[    9.692873] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 2: rank2 (1:0:0): row 2, chan 0
[    9.692883] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 3: rank3 (1:1:0): row 3, chan 0
[    9.692893] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 4: rank4 (2:0:0): row 4, chan 0
[    9.692903] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 5: rank5 (2:1:0): row 5, chan 0
[    9.692912] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 6: rank6 (3:0:0): row 6, chan 0
[    9.692922] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 7: rank7 (3:1:0): row 7, chan 0
[    9.692931] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 8: rank8 (4:0:0): row 0, chan 1
[    9.692941] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 9: rank9 (4:1:0): row 1, chan 1
[    9.692951] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 10: rank10 (5:0:0): row 2, chan 1
[    9.692961] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 11: rank11 (5:1:0): row 3, chan 1
[    9.692971] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 12: rank12 (6:0:0): row 4, chan 1
[    9.692980] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 13: rank13 (6:1:0): row 5, chan 1
[    9.692990] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 14: rank14 (7:0:0): row 6, chan 1
[    9.692999] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 15: rank15 (7:1:0): row 7, chan 1
[    9.693010] EDAC DEBUG: init_csrows: node 1, NBCFG=0x4af0005c[ChipKillEccCap: 1|DramEccEn: 1]
[    9.693017] EDAC DEBUG: init_csrows: ----CSROW 0 VALID for MC node 1
[    9.693022] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=0) DBAM map index= 8
[    9.693029] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693035] EDAC amd64: CS0: Registered DDR3 RAM
[    9.693040] EDAC DEBUG: init_csrows:   for MC node 1 csrow 0:
[    9.693045] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693050] EDAC DEBUG: init_csrows: ----CSROW 1 VALID for MC node 1
[    9.693056] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=1) DBAM map index= 8
[    9.693062] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693068] EDAC amd64: CS1: Registered DDR3 RAM
[    9.693072] EDAC DEBUG: init_csrows:   for MC node 1 csrow 1:
[    9.693077] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693083] EDAC DEBUG: init_csrows: ----CSROW 2 VALID for MC node 1
[    9.693089] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=2) DBAM map index= 8
[    9.693095] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693100] EDAC amd64: CS2: Registered DDR3 RAM
[    9.693105] EDAC DEBUG: init_csrows:   for MC node 1 csrow 2:
[    9.693110] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693116] EDAC DEBUG: init_csrows: ----CSROW 3 VALID for MC node 1
[    9.693121] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=3) DBAM map index= 8
[    9.693128] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693133] EDAC amd64: CS3: Registered DDR3 RAM
[    9.693138] EDAC DEBUG: init_csrows:   for MC node 1 csrow 3:
[    9.693143] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693148] EDAC DEBUG: init_csrows: ----CSROW 4 EMPTY for node 1
[    9.693154] EDAC DEBUG: init_csrows: ----CSROW 5 EMPTY for node 1
[    9.693159] EDAC DEBUG: init_csrows: ----CSROW 6 EMPTY for node 1
[    9.693165] EDAC DEBUG: init_csrows: ----CSROW 7 EMPTY for node 1
[    9.693171] EDAC DEBUG: edac_mc_add_mc: edac_mc_add_mc()
[    9.693179] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device() idx=1
[    9.693193] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device(): creating device mc1
[    9.693288] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm0, located at csrow 0 channel 0 
[    9.693300] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm1, located at csrow 0 channel 1 
[    9.693312] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm2, located at csrow 1 channel 0 
[    9.693322] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm3, located at csrow 1 channel 1 
[    9.693333] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm8, located at csrow 4 channel 0 
[    9.693344] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm9, located at csrow 4 channel 1 
[    9.693355] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm10, located at csrow 5 channel 0 
[    9.693365] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm11, located at csrow 5 channel 1 
[    9.693379] EDAC DEBUG: edac_create_csrow_object: edac_create_csrow_object(): creating (virtual) csrow node csrow0
[    9.693417] ------------[ cut here ]------------
[    9.693434] WARNING: at fs/sysfs/dir.c:481 sysfs_add_one+0x97/0xab()
[    9.693440] Hardware name: <redacted>
[    9.693444] sysfs: cannot create duplicate filename '/bus/edac/devices/csrow0'
[    9.693449] Modules linked in: radeon(+) ttm drm_kms_helper hwmon backlight e1000e amd64_edac_mod(+) ohci_hcd cfbcopyarea cfbimgblt cfbfillrect ehci_hcd edac_core
[    9.693479] Pid: 1569, comm: work_for_cpu Not tainted 3.3.0+ #4
[    9.693484] Call Trace:
[    9.693499]  [<ffffffff8102d50c>] warn_slowpath_common+0x85/0x9d
[    9.693509]  [<ffffffff8102d5c7>] warn_slowpath_fmt+0x46/0x48
[    9.693518]  [<ffffffff8114dd94>] sysfs_add_one+0x97/0xab
[    9.693527]  [<ffffffff8114e542>] sysfs_do_create_link+0x103/0x1a0
[    9.693538]  [<ffffffff8114e5f2>] sysfs_create_link+0x13/0x15
[    9.693549]  [<ffffffff812803e1>] bus_add_device+0xd8/0x163
[    9.693558]  [<ffffffff8127eaa7>] device_add+0x3ca/0x598
[    9.693567]  [<ffffffff8127e6d5>] ? device_private_init+0x5d/0x65
[    9.693588]  [<ffffffffa002aacb>] edac_create_sysfs_mci_device+0x228/0x3f3 [edac_core]
[    9.693604]  [<ffffffffa0028c95>] edac_mc_add_mc+0x5cf/0x711 [edac_core]
[    9.693622]  [<ffffffffa00f0807>] amd64_probe_one_instance+0x143b/0x1559 [amd64_edac_mod]
[    9.693634]  [<ffffffff811e7aac>] local_pci_probe+0x4d/0x96
[    9.693645]  [<ffffffff81042ecf>] ? cwq_dec_nr_in_flight+0x7b/0x7b
[    9.693654]  [<ffffffff81042ee7>] do_work_for_cpu+0x18/0x2a
[    9.693663]  [<ffffffff81048d0d>] kthread+0x89/0x91
[    9.693675]  [<ffffffff8144ca64>] kernel_thread_helper+0x4/0x10
[    9.693686]  [<ffffffff81444f4a>] ? retint_restore_args+0xe/0xe
[    9.693695]  [<ffffffff81048c84>] ? kthread_freezable_should_stop+0x57/0x57
[    9.693704]  [<ffffffff8144ca60>] ? gs_change+0xb/0xb
[    9.693710] ---[ end trace c72c379fedc94aa5 ]---
[    9.693741] ------------[ cut here ]------------
[    9.693751] WARNING: at lib/kobject.c:595 kobject_put+0x37/0x50()
[    9.693755] Hardware name: <redacted>
[    9.693761] kobject: '(null)' (ffff880824e4e8bc): is not initialized, yet kobject_put() is being called.
[    9.693767] Modules linked in: radeon(+) ttm drm_kms_helper hwmon backlight e1000e amd64_edac_mod(+) ohci_hcd cfbcopyarea cfbimgblt cfbfillrect ehci_hcd edac_core
[    9.693790] Pid: 1569, comm: work_for_cpu Tainted: G        W    3.3.0+ #4
[    9.693795] Call Trace:
[    9.693803]  [<ffffffff8102d50c>] warn_slowpath_common+0x85/0x9d
[    9.693811]  [<ffffffff8102d5c7>] warn_slowpath_fmt+0x46/0x48
[    9.693820]  [<ffffffff811c7193>] kobject_put+0x37/0x50
[    9.693829]  [<ffffffff8127d67d>] put_device+0x17/0x19
[    9.693846]  [<ffffffffa002ac4f>] edac_create_sysfs_mci_device+0x3ac/0x3f3 [edac_core]
[    9.693862]  [<ffffffffa0028c95>] edac_mc_add_mc+0x5cf/0x711 [edac_core]
[    9.693877]  [<ffffffffa00f0807>] amd64_probe_one_instance+0x143b/0x1559 [amd64_edac_mod]
[    9.693888]  [<ffffffff811e7aac>] local_pci_probe+0x4d/0x96
[    9.693897]  [<ffffffff81042ecf>] ? cwq_dec_nr_in_flight+0x7b/0x7b
[    9.693905]  [<ffffffff81042ee7>] do_work_for_cpu+0x18/0x2a
[    9.693913]  [<ffffffff81048d0d>] kthread+0x89/0x91
[    9.693922]  [<ffffffff8144ca64>] kernel_thread_helper+0x4/0x10
[    9.693931]  [<ffffffff81444f4a>] ? retint_restore_args+0xe/0xe
[    9.693940]  [<ffffffff81048c84>] ? kthread_freezable_should_stop+0x57/0x57
[    9.693950]  [<ffffffff8144ca60>] ? gs_change+0xb/0xb
[    9.693955] ---[ end trace c72c379fedc94aa6 ]---
[    9.693968] BUG: unable to handle kernel NULL pointer dereference at           (null)
[    9.693976] IP: [<ffffffff8104f240>] __wake_up_common+0x2e/0x84
[    9.693987] PGD 0 
[    9.693992] Oops: 0000 [#1] SMP 
[    9.693999] CPU 6 
[    9.694002] Modules linked in: radeon(+) ttm drm_kms_helper hwmon backlight e1000e amd64_edac_mod(+) ohci_hcd cfbcopyarea cfbimgblt cfbfillrect ehci_hcd edac_core
[    9.694022] 
[    9.694028] Pid: 1569, comm: work_for_cpu Tainted: G        W    3.3.0+ #4 AMD <redacted>/<redacted>
[    9.694037] RIP: 0010:[<ffffffff8104f240>]  [<ffffffff8104f240>] __wake_up_common+0x2e/0x84
[    9.694048] RSP: 0018:ffff8804256d5c60  EFLAGS: 00010097
[    9.694054] RAX: ffffffffffffffe8 RBX: 0000000000000000 RCX: 0000000000000000
[    9.694060] RDX: 0000000000000000 RSI: 0000000000000003 RDI: ffff880824e4e96c
[    9.694067] RBP: ffff8804256d5ca0 R08: 0000000000000000 R09: 00000000fffffffe
[    9.694073] R10: ffff8804a56d5b6f R11: 0000000000000000 R12: 0000000000000003
[    9.694079] R13: ffff880824e4e95c R14: 00000000ffffffff R15: 0000000000000000
[    9.694087] FS:  00007f605e6cc740(0000) GS:ffff880827c00000(0000) knlGS:0000000000000000
[    9.694095] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[    9.694100] CR2: 0000000000000000 CR3: 0000000001a05000 CR4: 00000000000006e0
[    9.694106] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[    9.694113] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[    9.694120] Process work_for_cpu (pid: 1569, threadinfo ffff8804256d4000, task ffff880425510000)
[    9.694125] Stack:
[    9.694129]  0000000000000282 ffff880824e4e96c 00000000ffffffff ffff880824e4e964
[    9.694137]  0000000000000282 ffff880824e4e95c 00000000ffffffff 0000000000000018
[    9.694146]  ffff8804256d5cd0 ffffffff81051d6d ffff8804256d5d00 ffff880824e4e8ac
[    9.694154] Call Trace:
[    9.694164]  [<ffffffff81051d6d>] complete_all+0x40/0x53
[    9.694175]  [<ffffffff8128699c>] device_pm_remove+0x5e/0xbc
[    9.694183]  [<ffffffff8127e47a>] device_del+0x44/0x172
[    9.694199]  [<ffffffffa002ac57>] edac_create_sysfs_mci_device+0x3b4/0x3f3 [edac_core]
[    9.694214]  [<ffffffffa0028c95>] edac_mc_add_mc+0x5cf/0x711 [edac_core]
[    9.694229]  [<ffffffffa00f0807>] amd64_probe_one_instance+0x143b/0x1559 [amd64_edac_mod]
[    9.694239]  [<ffffffff811e7aac>] local_pci_probe+0x4d/0x96
[    9.694249]  [<ffffffff81042ecf>] ? cwq_dec_nr_in_flight+0x7b/0x7b
[    9.694257]  [<ffffffff81042ee7>] do_work_for_cpu+0x18/0x2a
[    9.694265]  [<ffffffff81048d0d>] kthread+0x89/0x91
[    9.694274]  [<ffffffff8144ca64>] kernel_thread_helper+0x4/0x10
[    9.694283]  [<ffffffff81444f4a>] ? retint_restore_args+0xe/0xe
[    9.694292]  [<ffffffff81048c84>] ? kthread_freezable_should_stop+0x57/0x57
[    9.694301]  [<ffffffff8144ca60>] ? gs_change+0xb/0xb
[    9.694306] Code: e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 66 66 66 66 90 48 8b 47 08 48 83 c7 08 41 89 f4 89 d3 41 89 cf 48 89 7d c8 48 83 e8 18 <4c> 8b 68 18 49 83 ed 18 eb 33 44 8b 30 4c 89 c1 4c 89 45 c0 44 
[    9.694363] RIP  [<ffffffff8104f240>] __wake_up_common+0x2e/0x84
[    9.694372]  RSP <ffff8804256d5c60>
[    9.694376] CR2: 0000000000000000
[    9.694382] ---[ end trace c72c379fedc94aa7 ]---
[    9.870234] Console: switching to colour frame buffer device 128x48
[   13.530549] fb0: radeondrmfb frame buffer device
[   13.544530] drm: registered panic notifier
[   13.557928] [drm] Initialized radeon 2.13.0 20080528 for 0000:02:06.0 on minor 0
[   68.764044] EXT3-fs (sda2): using internal journal
[   71.182320] ADDRCONF(NETDEV_UP): eth0: link is not ready
[   74.225091] e1000e: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[   74.246314] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[   84.480093] eth0: no IPv6 routers present
[   87.227601] RPC: Registered named UNIX socket transport module.
[   87.246392] RPC: Registered udp transport module.
[   87.263673] RPC: Registered tcp transport module.
[   87.263678] RPC: Registered tcp NFSv4.1 backchannel transport module.
Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#37 lore raw

Re: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device

(c/c Greg, as this is related to the kobj->struct device conversion)

Em 09-05-2012 09:34, Borislav Petkov escreveu:

Quoted 14 lines

Inserting latest version:

Quoted 12 lines

From e8765894c6d43326c9968a3687f5140708ee163f Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Mon, 16 Apr 2012 16:41:11 -0300
Subject: [PATCH] edac: rewrite the sysfs code to use struct device

The EDAC subsystem uses the old struct sysdev approach, creating all nodes using the raw sysfs API. This is bad, as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing code to struct device.

Quoted 7 lines
Quoted 1 line

There's one side-back on this patch: all device-specific sysfs

drawback to

Quoted 1 line

nodes won't be created anymore. While it would be possible to

which device-specific nodes?

I mean driver-specific. The ones that i7core_edac, amd64_edac and mpc85xx_edac create (mainly) for debug purposes.

Everything will compile and run fine, but the core won't create them anymore, as they're based on kobj.

The next 3 patches on this series will convert each of the above to use kernel devices, solving this issue.

I'll fix the comment.

Quoted 250 lines
Quoted 6 lines

also port the device-specific code, it is easier and nicer to move the code to the drivers, instead, as the core can get rid of some complex logic that just emulates what the device_add() and device_create_file() already does.

Quoted 7 lines

The next patches will convert the driver-specific code to use the device-specific calls. Then, the remaining bits of the old sysfs API will be removed.

Btw, this patch is b0rked. Here's the EDAC debug output from the second node on when booting:

...

[    9.692291] EDAC amd64: F10h detected (node 1).
[    9.692324] EDAC DEBUG: reserve_mc_sibling_devs: F1: 0000:00:19.1
[    9.692330] EDAC DEBUG: reserve_mc_sibling_devs: F2: 0000:00:19.2
[    9.692335] EDAC DEBUG: reserve_mc_sibling_devs: F3: 0000:00:19.3
[    9.692341] EDAC DEBUG: read_mc_regs:   TOP_MEM:  0x00000000c8000000
[    9.692347] EDAC DEBUG: read_mc_regs:   TOP_MEM2: 0x0000001038000000
[    9.692356] EDAC DEBUG: read_dram_ctl_register: F2x110 (DCTSelLow): 0x000005e4, High range addrs at: 0x0
[    9.692363] EDAC DEBUG: read_dram_ctl_register:   DCTs operate in unganged mode.
[    9.692369] EDAC DEBUG: read_dram_ctl_register:   Address range split per DCT: no
[    9.692376] EDAC DEBUG: read_dram_ctl_register:   data interleave for ECC: enabled, DRAM cleared since last warm reset: yes
[    9.692384] EDAC DEBUG: read_dram_ctl_register:   channel interleave: enabled, interleave bits selector: 0x3
[    9.692395] EDAC DEBUG: read_mc_regs:   DRAM range[0], base: 0x0000000000000000; limit: 0x0000000437ffffff
[    9.692404] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=0
[    9.692413] EDAC DEBUG: read_mc_regs:   DRAM range[1], base: 0x0000000438000000; limit: 0x0000000837ffffff
[    9.692422] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=1
[    9.692431] EDAC DEBUG: read_mc_regs:   DRAM range[2], base: 0x0000000838000000; limit: 0x0000000c37ffffff
[    9.692439] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=2
[    9.692448] EDAC DEBUG: read_mc_regs:   DRAM range[3], base: 0x0000000c38000000; limit: 0x0000001037ffffff
[    9.692456] EDAC DEBUG: read_mc_regs:    IntlvEn=Disabled; Range access: RW IntlvSel=0 DstNode=3
[    9.692469] EDAC DEBUG: read_dct_base_mask:   DCSB0[0]=0x00000001 reg: F2x40
[    9.692476] EDAC DEBUG: read_dct_base_mask:   DCSB1[0]=0x00000001 reg: F2x140
[    9.692483] EDAC DEBUG: read_dct_base_mask:   DCSB0[1]=0x00000201 reg: F2x44
[    9.692489] EDAC DEBUG: read_dct_base_mask:   DCSB1[1]=0x00000201 reg: F2x144
[    9.692496] EDAC DEBUG: read_dct_base_mask:   DCSB0[2]=0x00000401 reg: F2x48
[    9.692503] EDAC DEBUG: read_dct_base_mask:   DCSB1[2]=0x00000401 reg: F2x148
[    9.692510] EDAC DEBUG: read_dct_base_mask:   DCSB0[3]=0x00000601 reg: F2x4c
[    9.692516] EDAC DEBUG: read_dct_base_mask:   DCSB1[3]=0x00000601 reg: F2x14c
[    9.692523] EDAC DEBUG: read_dct_base_mask:   DCSB0[4]=0x00000000 reg: F2x50
[    9.692530] EDAC DEBUG: read_dct_base_mask:   DCSB1[4]=0x00000000 reg: F2x150
[    9.692537] EDAC DEBUG: read_dct_base_mask:   DCSB0[5]=0x00000000 reg: F2x54
[    9.692543] EDAC DEBUG: read_dct_base_mask:   DCSB1[5]=0x00000000 reg: F2x154
[    9.692550] EDAC DEBUG: read_dct_base_mask:   DCSB0[6]=0x00000000 reg: F2x58
[    9.692557] EDAC DEBUG: read_dct_base_mask:   DCSB1[6]=0x00000000 reg: F2x158
[    9.692564] EDAC DEBUG: read_dct_base_mask:   DCSB0[7]=0x00000000 reg: F2x5c
[    9.692570] EDAC DEBUG: read_dct_base_mask:   DCSB1[7]=0x00000000 reg: F2x15c
[    9.692577] EDAC DEBUG: read_dct_base_mask:     DCSM0[0]=0x01f839e0 reg: F2x60
[    9.692584] EDAC DEBUG: read_dct_base_mask:     DCSM1[0]=0x01f839e0 reg: F2x160
[    9.692591] EDAC DEBUG: read_dct_base_mask:     DCSM0[1]=0x01f839e0 reg: F2x64
[    9.692598] EDAC DEBUG: read_dct_base_mask:     DCSM1[1]=0x01f839e0 reg: F2x164
[    9.692605] EDAC DEBUG: read_dct_base_mask:     DCSM0[2]=0x00000000 reg: F2x68
[    9.692612] EDAC DEBUG: read_dct_base_mask:     DCSM1[2]=0x00000000 reg: F2x168
[    9.692619] EDAC DEBUG: read_dct_base_mask:     DCSM0[3]=0x00000000 reg: F2x6c
[    9.692625] EDAC DEBUG: read_dct_base_mask:     DCSM1[3]=0x00000000 reg: F2x16c
[    9.692635] EDAC DEBUG: dump_misc_regs: F3xE8 (NB Cap): 0x62f0df1f
[    9.692641] EDAC DEBUG: dump_misc_regs:   NB two channel DRAM capable: yes
[    9.692647] EDAC DEBUG: dump_misc_regs:   ECC capable: yes, ChipKill ECC capable: yes
[    9.692653] EDAC DEBUG: amd64_dump_dramcfg_low: F2x090 (DRAM Cfg Low): 0x00083100
[    9.692660] EDAC DEBUG: amd64_dump_dramcfg_low:   DIMM type: buffered; all DIMMs support ECC: yes
[    9.692666] EDAC DEBUG: amd64_dump_dramcfg_low:   PAR/ERR parity: enabled
[    9.692671] EDAC DEBUG: amd64_dump_dramcfg_low:   DCT 128bit mode width: 64b
[    9.692678] EDAC DEBUG: amd64_dump_dramcfg_low:   x4 logical DIMMs present: L0: yes L1: yes L2: no L3: no
[    9.692685] EDAC DEBUG: dump_misc_regs: F3xB0 (Online Spare): 0x00000000
[    9.692692] EDAC DEBUG: dump_misc_regs: F1xF0 (DRAM Hole Address): 0xc8000002, base: 0xc8000000, offset: 0x00000000
[    9.692699] EDAC DEBUG: dump_misc_regs:   DramHoleValid: no
[    9.692705] EDAC DEBUG: amd64_debug_display_dimm_sizes: F2x080 (DRAM Bank Address Mapping): 0x00000088
[    9.692711] EDAC MC: DCT0 chip selects:
[    9.692717] EDAC amd64: MC: 0:  2048MB 1:  2048MB
[    9.692723] EDAC amd64: MC: 2:  2048MB 3:  2048MB
[    9.692728] EDAC amd64: MC: 4:     0MB 5:     0MB
[    9.692733] EDAC amd64: MC: 6:     0MB 7:     0MB
[    9.692738] EDAC DEBUG: amd64_debug_display_dimm_sizes: F2x180 (DRAM Bank Address Mapping): 0x00000088
[    9.692744] EDAC MC: DCT1 chip selects:
[    9.692749] EDAC amd64: MC: 0:  2048MB 1:  2048MB
[    9.692754] EDAC amd64: MC: 2:  2048MB 3:  2048MB
[    9.692759] EDAC amd64: MC: 4:     0MB 5:     0MB
[    9.692764] EDAC amd64: MC: 6:     0MB 7:     0MB
[    9.692769] EDAC amd64: using x8 syndromes.
[    9.692774] EDAC DEBUG: amd64_dump_dramcfg_low: F2x190 (DRAM Cfg Low): 0x00083100
[    9.692780] EDAC DEBUG: amd64_dump_dramcfg_low:   DIMM type: buffered; all DIMMs support ECC: yes
[    9.692786] EDAC DEBUG: amd64_dump_dramcfg_low:   PAR/ERR parity: enabled
[    9.692791] EDAC DEBUG: amd64_dump_dramcfg_low:   DCT 128bit mode width: 64b
[    9.692798] EDAC DEBUG: amd64_dump_dramcfg_low:   x4 logical DIMMs present: L0: yes L1: yes L2: no L3: no
[    9.692805] EDAC DEBUG: f1x_early_channel_count: Data width is not 128 bits - need more decoding
[    9.692812] EDAC amd64: MCT channel count: 2
[    9.692821] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc(): allocating 30948 bytes for mci data (16 ranks, 16 csrows/channels)
[    9.692851] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 0: rank0 (0:0:0): row 0, chan 0
[    9.692863] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 1: rank1 (0:1:0): row 1, chan 0
[    9.692873] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 2: rank2 (1:0:0): row 2, chan 0
[    9.692883] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 3: rank3 (1:1:0): row 3, chan 0
[    9.692893] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 4: rank4 (2:0:0): row 4, chan 0
[    9.692903] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 5: rank5 (2:1:0): row 5, chan 0
[    9.692912] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 6: rank6 (3:0:0): row 6, chan 0
[    9.692922] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 7: rank7 (3:1:0): row 7, chan 0
[    9.692931] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 8: rank8 (4:0:0): row 0, chan 1
[    9.692941] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 9: rank9 (4:1:0): row 1, chan 1
[    9.692951] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 10: rank10 (5:0:0): row 2, chan 1
[    9.692961] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 11: rank11 (5:1:0): row 3, chan 1
[    9.692971] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 12: rank12 (6:0:0): row 4, chan 1
[    9.692980] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 13: rank13 (6:1:0): row 5, chan 1
[    9.692990] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 14: rank14 (7:0:0): row 6, chan 1
[    9.692999] EDAC DEBUG: edac_mc_alloc: edac_mc_alloc: 15: rank15 (7:1:0): row 7, chan 1
[    9.693010] EDAC DEBUG: init_csrows: node 1, NBCFG=0x4af0005c[ChipKillEccCap: 1|DramEccEn: 1]
[    9.693017] EDAC DEBUG: init_csrows: ----CSROW 0 VALID for MC node 1
[    9.693022] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=0) DBAM map index= 8
[    9.693029] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693035] EDAC amd64: CS0: Registered DDR3 RAM
[    9.693040] EDAC DEBUG: init_csrows:   for MC node 1 csrow 0:
[    9.693045] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693050] EDAC DEBUG: init_csrows: ----CSROW 1 VALID for MC node 1
[    9.693056] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=1) DBAM map index= 8
[    9.693062] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693068] EDAC amd64: CS1: Registered DDR3 RAM
[    9.693072] EDAC DEBUG: init_csrows:   for MC node 1 csrow 1:
[    9.693077] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693083] EDAC DEBUG: init_csrows: ----CSROW 2 VALID for MC node 1
[    9.693089] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=2) DBAM map index= 8
[    9.693095] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693100] EDAC amd64: CS2: Registered DDR3 RAM
[    9.693105] EDAC DEBUG: init_csrows:   for MC node 1 csrow 2:
[    9.693110] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693116] EDAC DEBUG: init_csrows: ----CSROW 3 VALID for MC node 1
[    9.693121] EDAC DEBUG: amd64_csrow_nr_pages:   (csrow=3) DBAM map index= 8
[    9.693128] EDAC DEBUG: amd64_csrow_nr_pages:     nr_pages= 524288  channel-count = 2
[    9.693133] EDAC amd64: CS3: Registered DDR3 RAM
[    9.693138] EDAC DEBUG: init_csrows:   for MC node 1 csrow 3:
[    9.693143] EDAC DEBUG: init_csrows:     nr_pages: 524288
[    9.693148] EDAC DEBUG: init_csrows: ----CSROW 4 EMPTY for node 1
[    9.693154] EDAC DEBUG: init_csrows: ----CSROW 5 EMPTY for node 1
[    9.693159] EDAC DEBUG: init_csrows: ----CSROW 6 EMPTY for node 1
[    9.693165] EDAC DEBUG: init_csrows: ----CSROW 7 EMPTY for node 1
[    9.693171] EDAC DEBUG: edac_mc_add_mc: edac_mc_add_mc()
[    9.693179] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device() idx=1
[    9.693193] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device(): creating device mc1
[    9.693288] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm0, located at csrow 0 channel 0 
[    9.693300] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm1, located at csrow 0 channel 1 
[    9.693312] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm2, located at csrow 1 channel 0 
[    9.693322] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm3, located at csrow 1 channel 1 
[    9.693333] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm8, located at csrow 4 channel 0 
[    9.693344] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm9, located at csrow 4 channel 1 
[    9.693355] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm10, located at csrow 5 channel 0 
[    9.693365] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm11, located at csrow 5 channel 1 
[    9.693379] EDAC DEBUG: edac_create_csrow_object: edac_create_csrow_object(): creating (virtual) csrow node csrow0
[    9.693417] ------------[ cut here ]------------
[    9.693434] WARNING: at fs/sysfs/dir.c:481 sysfs_add_one+0x97/0xab()
[    9.693440] Hardware name: <redacted>
[    9.693444] sysfs: cannot create duplicate filename '/bus/edac/devices/csrow0'
[    9.693449] Modules linked in: radeon(+) ttm drm_kms_helper hwmon backlight e1000e amd64_edac_mod(+) ohci_hcd cfbcopyarea cfbimgblt cfbfillrect ehci_hcd edac_core
[    9.693479] Pid: 1569, comm: work_for_cpu Not tainted 3.3.0+ #4
[    9.693484] Call Trace:
[    9.693499]  [<ffffffff8102d50c>] warn_slowpath_common+0x85/0x9d
[    9.693509]  [<ffffffff8102d5c7>] warn_slowpath_fmt+0x46/0x48
[    9.693518]  [<ffffffff8114dd94>] sysfs_add_one+0x97/0xab
[    9.693527]  [<ffffffff8114e542>] sysfs_do_create_link+0x103/0x1a0
[    9.693538]  [<ffffffff8114e5f2>] sysfs_create_link+0x13/0x15
[    9.693549]  [<ffffffff812803e1>] bus_add_device+0xd8/0x163
[    9.693558]  [<ffffffff8127eaa7>] device_add+0x3ca/0x598
[    9.693567]  [<ffffffff8127e6d5>] ? device_private_init+0x5d/0x65
[    9.693588]  [<ffffffffa002aacb>] edac_create_sysfs_mci_device+0x228/0x3f3 [edac_core]
[    9.693604]  [<ffffffffa0028c95>] edac_mc_add_mc+0x5cf/0x711 [edac_core]
[    9.693622]  [<ffffffffa00f0807>] amd64_probe_one_instance+0x143b/0x1559 [amd64_edac_mod]
[    9.693634]  [<ffffffff811e7aac>] local_pci_probe+0x4d/0x96
[    9.693645]  [<ffffffff81042ecf>] ? cwq_dec_nr_in_flight+0x7b/0x7b
[    9.693654]  [<ffffffff81042ee7>] do_work_for_cpu+0x18/0x2a
[    9.693663]  [<ffffffff81048d0d>] kthread+0x89/0x91
[    9.693675]  [<ffffffff8144ca64>] kernel_thread_helper+0x4/0x10
[    9.693686]  [<ffffffff81444f4a>] ? retint_restore_args+0xe/0xe
[    9.693695]  [<ffffffff81048c84>] ? kthread_freezable_should_stop+0x57/0x57
[    9.693704]  [<ffffffff8144ca60>] ? gs_change+0xb/0xb
[    9.693710] ---[ end trace c72c379fedc94aa5 ]---
[    9.693741] ------------[ cut here ]------------
[    9.693751] WARNING: at lib/kobject.c:595 kobject_put+0x37/0x50()
[    9.693755] Hardware name: <redacted>
[    9.693761] kobject: '(null)' (ffff880824e4e8bc): is not initialized, yet kobject_put() is being called.
[    9.693767] Modules linked in: radeon(+) ttm drm_kms_helper hwmon backlight e1000e amd64_edac_mod(+) ohci_hcd cfbcopyarea cfbimgblt cfbfillrect ehci_hcd edac_core
[    9.693790] Pid: 1569, comm: work_for_cpu Tainted: G        W    3.3.0+ #4
[    9.693795] Call Trace:
[    9.693803]  [<ffffffff8102d50c>] warn_slowpath_common+0x85/0x9d
[    9.693811]  [<ffffffff8102d5c7>] warn_slowpath_fmt+0x46/0x48
[    9.693820]  [<ffffffff811c7193>] kobject_put+0x37/0x50
[    9.693829]  [<ffffffff8127d67d>] put_device+0x17/0x19
[    9.693846]  [<ffffffffa002ac4f>] edac_create_sysfs_mci_device+0x3ac/0x3f3 [edac_core]
[    9.693862]  [<ffffffffa0028c95>] edac_mc_add_mc+0x5cf/0x711 [edac_core]
[    9.693877]  [<ffffffffa00f0807>] amd64_probe_one_instance+0x143b/0x1559 [amd64_edac_mod]
[    9.693888]  [<ffffffff811e7aac>] local_pci_probe+0x4d/0x96
[    9.693897]  [<ffffffff81042ecf>] ? cwq_dec_nr_in_flight+0x7b/0x7b
[    9.693905]  [<ffffffff81042ee7>] do_work_for_cpu+0x18/0x2a
[    9.693913]  [<ffffffff81048d0d>] kthread+0x89/0x91
[    9.693922]  [<ffffffff8144ca64>] kernel_thread_helper+0x4/0x10
[    9.693931]  [<ffffffff81444f4a>] ? retint_restore_args+0xe/0xe
[    9.693940]  [<ffffffff81048c84>] ? kthread_freezable_should_stop+0x57/0x57
[    9.693950]  [<ffffffff8144ca60>] ? gs_change+0xb/0xb
[    9.693955] ---[ end trace c72c379fedc94aa6 ]---
[    9.693968] BUG: unable to handle kernel NULL pointer dereference at           (null)
[    9.693976] IP: [<ffffffff8104f240>] __wake_up_common+0x2e/0x84
[    9.693987] PGD 0 
[    9.693992] Oops: 0000 [#1] SMP 
[    9.693999] CPU 6 
[    9.694002] Modules linked in: radeon(+) ttm drm_kms_helper hwmon backlight e1000e amd64_edac_mod(+) ohci_hcd cfbcopyarea cfbimgblt cfbfillrect ehci_hcd edac_core
[    9.694022] 
[    9.694028] Pid: 1569, comm: work_for_cpu Tainted: G        W    3.3.0+ #4 AMD <redacted>/<redacted>
[    9.694037] RIP: 0010:[<ffffffff8104f240>]  [<ffffffff8104f240>] __wake_up_common+0x2e/0x84
[    9.694048] RSP: 0018:ffff8804256d5c60  EFLAGS: 00010097
[    9.694054] RAX: ffffffffffffffe8 RBX: 0000000000000000 RCX: 0000000000000000
[    9.694060] RDX: 0000000000000000 RSI: 0000000000000003 RDI: ffff880824e4e96c
[    9.694067] RBP: ffff8804256d5ca0 R08: 0000000000000000 R09: 00000000fffffffe
[    9.694073] R10: ffff8804a56d5b6f R11: 0000000000000000 R12: 0000000000000003
[    9.694079] R13: ffff880824e4e95c R14: 00000000ffffffff R15: 0000000000000000
[    9.694087] FS:  00007f605e6cc740(0000) GS:ffff880827c00000(0000) knlGS:0000000000000000
[    9.694095] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[    9.694100] CR2: 0000000000000000 CR3: 0000000001a05000 CR4: 00000000000006e0
[    9.694106] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[    9.694113] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[    9.694120] Process work_for_cpu (pid: 1569, threadinfo ffff8804256d4000, task ffff880425510000)
[    9.694125] Stack:
[    9.694129]  0000000000000282 ffff880824e4e96c 00000000ffffffff ffff880824e4e964
[    9.694137]  0000000000000282 ffff880824e4e95c 00000000ffffffff 0000000000000018
[    9.694146]  ffff8804256d5cd0 ffffffff81051d6d ffff8804256d5d00 ffff880824e4e8ac
[    9.694154] Call Trace:
[    9.694164]  [<ffffffff81051d6d>] complete_all+0x40/0x53
[    9.694175]  [<ffffffff8128699c>] device_pm_remove+0x5e/0xbc
[    9.694183]  [<ffffffff8127e47a>] device_del+0x44/0x172
[    9.694199]  [<ffffffffa002ac57>] edac_create_sysfs_mci_device+0x3b4/0x3f3 [edac_core]
[    9.694214]  [<ffffffffa0028c95>] edac_mc_add_mc+0x5cf/0x711 [edac_core]
[    9.694229]  [<ffffffffa00f0807>] amd64_probe_one_instance+0x143b/0x1559 [amd64_edac_mod]
[    9.694239]  [<ffffffff811e7aac>] local_pci_probe+0x4d/0x96
[    9.694249]  [<ffffffff81042ecf>] ? cwq_dec_nr_in_flight+0x7b/0x7b
[    9.694257]  [<ffffffff81042ee7>] do_work_for_cpu+0x18/0x2a
[    9.694265]  [<ffffffff81048d0d>] kthread+0x89/0x91
[    9.694274]  [<ffffffff8144ca64>] kernel_thread_helper+0x4/0x10
[    9.694283]  [<ffffffff81444f4a>] ? retint_restore_args+0xe/0xe
[    9.694292]  [<ffffffff81048c84>] ? kthread_freezable_should_stop+0x57/0x57
[    9.694301]  [<ffffffff8144ca60>] ? gs_change+0xb/0xb
[    9.694306] Code: e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 66 66 66 66 90 48 8b 47 08 48 83 c7 08 41 89 f4 89 d3 41 89 cf 48 89 7d c8 48 83 e8 18 <4c> 8b 68 18 49 83 ed 18 eb 33 44 8b 30 4c 89 c1 4c 89 45 c0 44 
[    9.694363] RIP  [<ffffffff8104f240>] __wake_up_common+0x2e/0x84
[    9.694372]  RSP <ffff8804256d5c60>
[    9.694376] CR2: 0000000000000000
[    9.694382] ---[ end trace c72c379fedc94aa7 ]---
[    9.870234] Console: switching to colour frame buffer device 128x48
[   13.530549] fb0: radeondrmfb frame buffer device
[   13.544530] drm: registered panic notifier
[   13.557928] [drm] Initialized radeon 2.13.0 20080528 for 0000:02:06.0 on minor 0
[   68.764044] EXT3-fs (sda2): using internal journal
Quoted 8 lines
[   71.182320] ADDRCONF(NETDEV_UP): eth0: link is not ready
[   74.225091] e1000e: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[   74.246314] ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[   84.480093] eth0: no IPv6 routers present
[   87.227601] RPC: Registered named UNIX socket transport module.
[   87.246392] RPC: Registered udp transport module.
[   87.263673] RPC: Registered tcp transport module.
[   87.263678] RPC: Registered tcp NFSv4.1 backchannel transport module.

This is fixed by this patch, already acked-by Greg:

	[EDAC ABI v13 17/25] edac: Create a per-Memory Controller bus
	http://git.infradead.org/users/mchehab/edac.git/commit/a2c90149c2e87e51908003b1ba504f92d749f74b

Basically, on devices with multiple controllers, there a separate per-memory controller bus is needed due to sysfs nodes under /sys/bus.

I opted to keep it on a separate patch, in order to preserve the history, and properly document why this is needed.

Regards,
Mauro

#38 lore raw

Re: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device

Quoted 9 lines · Mauro Carvalho Chehab

This is fixed by this patch, already acked-by Greg:

	[EDAC ABI v13 17/25] edac: Create a per-Memory Controller bus
	http://git.infradead.org/users/mchehab/edac.git/commit/a2c90149c2e87e51908003b1ba504f92d749f74b

Basically, on devices with multiple controllers, there a separate per-memory controller bus is needed due to sysfs nodes under /sys/bus.

I opted to keep it on a separate patch, in order to preserve the history, and properly document why this is needed.

We don't apply patches causing oopses like that because this breaks bisection.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#39 lore raw

PATCH v21 1/1 edac: rewrite the sysfs code to use struct device - Was: Re: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device

Em 09-05-2012 10:24, Borislav Petkov escreveu:

Quoted 5 lines · Mauro Carvalho Chehab
Quoted 4 lines

This is fixed by this patch, already acked-by Greg:

	[EDAC ABI v13 17/25] edac: Create a per-Memory Controller bus
	http://git.infradead.org/users/mchehab/edac.git/commit/a2c90149c2e87e51908003b1ba504f92d749f74b
Quoted 9 lines
Quoted 5 lines

Basically, on devices with multiple controllers, there a separate per-memory controller bus is needed due to sysfs nodes under /sys/bus.

I opted to keep it on a separate patch, in order to preserve the history, and properly document why this is needed.

We don't apply patches causing oopses like that because this breaks bisection.

Merged both patches, adding the second comment as a note.

Regards,
Mauro

-

edac: rewrite the sysfs code to use struct device

From: Mauro Carvalho Chehab <[email protected]>

The EDAC subsystem uses the old struct sysdev approach, creating all nodes using the raw sysfs API. This is bad, as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing code to struct device.

There's one drawback on this patch: driver-specific sysfs nodes, used by mpc85xx_edac, amd64_edac and i7core_edac
won't be created anymore. While it would be possible to
also port the device-specific code, that would mix kobj with struct device, with is not recommended. Also, it is easier and nicer to move the code to the drivers, instead, as the core can get rid of some complex logic that just emulates what the device_add() and device_create_file() already does.

The next patches will convert the driver-specific code to use the device-specific calls. Then, the remaining bits of the old sysfs API will be removed.

NOTE: a per-MC bus is required, otherwise devices with more than one memory controller will hit a bug like the one below:

[  819.094946] EDAC DEBUG: find_mci_by_dev: find_mci_by_dev()
[  819.094948] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device() idx=1
[  819.094952] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device(): creating device mc1
[  819.094967] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm0, located at channel 0 slot 0
[  819.094984] ------------[ cut here ]------------
[  819.100142] WARNING: at fs/sysfs/dir.c:481 sysfs_add_one+0xc1/0xf0()
[  819.107282] Hardware name: S2600CP
[  819.111078] sysfs: cannot create duplicate filename '/bus/edac/devices/dimm0'
[  819.119062] Modules linked in: sb_edac(+) edac_core ip6table_filter ip6_tables ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables bridge stp llc sunrpc binfmt_misc dm_mirror dm_region_hash dm_log vhost_net macvtap macvlan tun kvm microcode pcspkr iTCO_wdt iTCO_vendor_support igb i2c_i801 i2c_core sg ioatdma dca sr_mod cdrom sd_mod crc_t10dif ahci libahci isci libsas libata scsi_transport_sas scsi_mod wmi dm_mod [last unloaded: scsi_wait_scan]
[  819.175748] Pid: 10902, comm: modprobe Not tainted 3.3.0-0.11.el7.v12.2.x86_64 #1
[  819.184113] Call Trace:
[  819.186868]  [<ffffffff8105adaf>] warn_slowpath_common+0x7f/0xc0
[  819.193573]  [<ffffffff8105aea6>] warn_slowpath_fmt+0x46/0x50
[  819.200000]  [<ffffffff811f53d1>] sysfs_add_one+0xc1/0xf0
[  819.206025]  [<ffffffff811f5cf5>] sysfs_do_create_link+0x135/0x220
[  819.212944]  [<ffffffff811f7023>] ? sysfs_create_group+0x13/0x20
[  819.219656]  [<ffffffff811f5df3>] sysfs_create_link+0x13/0x20
[  819.226109]  [<ffffffff813b04f6>] bus_add_device+0xe6/0x1b0
[  819.232350]  [<ffffffff813ae7cb>] device_add+0x2db/0x460
[  819.238300]  [<ffffffffa0325634>] edac_create_dimm_object+0x84/0xf0 [edac_core]
[  819.246460]  [<ffffffffa0325e18>] edac_create_sysfs_mci_device+0xe8/0x290 [edac_core]
[  819.255215]  [<ffffffffa0322e2a>] edac_mc_add_mc+0x5a/0x2c0 [edac_core]
[  819.262611]  [<ffffffffa03412df>] sbridge_register_mci+0x1bc/0x279 [sb_edac]
[  819.270493]  [<ffffffffa03417a3>] sbridge_probe+0xef/0x175 [sb_edac]
[  819.277630]  [<ffffffff813ba4e8>] ? pm_runtime_enable+0x58/0x90
[  819.284268]  [<ffffffff812f430c>] local_pci_probe+0x5c/0xd0
[  819.290508]  [<ffffffff812f5ba1>] __pci_device_probe+0xf1/0x100
[  819.297117]  [<ffffffff812f5bea>] pci_device_probe+0x3a/0x60
[  819.303457]  [<ffffffff813b1003>] really_probe+0x73/0x270
[  819.309496]  [<ffffffff813b138e>] driver_probe_device+0x4e/0xb0
[  819.316104]  [<ffffffff813b149b>] __driver_attach+0xab/0xb0
[  819.322337]  [<ffffffff813b13f0>] ? driver_probe_device+0xb0/0xb0
[  819.329151]  [<ffffffff813af5d6>] bus_for_each_dev+0x56/0x90
[  819.335489]  [<ffffffff813b0d7e>] driver_attach+0x1e/0x20
[  819.341534]  [<ffffffff813b0980>] bus_add_driver+0x1b0/0x2a0
[  819.347884]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.353641]  [<ffffffff813b19f6>] driver_register+0x76/0x140
[  819.359980]  [<ffffffff8159f18b>] ? printk+0x51/0x53
[  819.365524]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.371291]  [<ffffffff812f5896>] __pci_register_driver+0x56/0xd0
[  819.378096]  [<ffffffffa0347054>] sbridge_init+0x54/0x1000 [sb_edac]
[  819.385231]  [<ffffffff8100203f>] do_one_initcall+0x3f/0x170
[  819.391577]  [<ffffffff810bcd2e>] sys_init_module+0xbe/0x230
[  819.397926]  [<ffffffff815bb529>] system_call_fastpath+0x16/0x1b
[  819.404633] ---[ end trace 1654fdd39556689f ]---

This happens because the bus is not being properly initialized. Instead of putting the memory sub-devices inside the memory controller, it is putting everything under the same directory:

$ tree /sys/bus/edac/
/sys/bus/edac/
├── devices
│   ├── all_channel_counts -> ../../../devices/system/edac/mc/mc0/all_channel_counts
│   ├── csrow0 -> ../../../devices/system/edac/mc/mc0/csrow0
│   ├── csrow1 -> ../../../devices/system/edac/mc/mc0/csrow1
│   ├── csrow2 -> ../../../devices/system/edac/mc/mc0/csrow2
│   ├── dimm0 -> ../../../devices/system/edac/mc/mc0/dimm0
│   ├── dimm1 -> ../../../devices/system/edac/mc/mc0/dimm1
│   ├── dimm3 -> ../../../devices/system/edac/mc/mc0/dimm3
│   ├── dimm6 -> ../../../devices/system/edac/mc/mc0/dimm6
│   ├── inject_addrmatch -> ../../../devices/system/edac/mc/mc0/inject_addrmatch
│   ├── mc -> ../../../devices/system/edac/mc
│   └── mc0 -> ../../../devices/system/edac/mc/mc0
├── drivers
├── drivers_autoprobe
├── drivers_probe
└── uevent

On a multi-memory controller system, the names "csrow%d" and "dimm%d" should be under "mc%d", and not at the main hierarchy level.

So, we need to create a per-MC bus, in order to have its own namespace.

drivers/edac/edac_mc.c +2 -11
index 538a439..b7b060f 100644
@@ -216,7 +216,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
 	void *pvt, *p, *ptr = NULL;
-	int i, j, err, row, chn, n, len;
+	int i, j, row, chn, n, len;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
@@ -369,15 +369,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	mci->op_state = OP_ALLOC;
 	INIT_LIST_HEAD(&mci->grp_kobj_list);
 
-	/*
-	 * Initialize the 'root' kobj for the edac_mc controller
-	 */
-	err = edac_mc_register_sysfs_main_kobj(mci);
-	if (err) {
-		kfree(mci);
-		return NULL;
-	}
-
 	/* at this point, the root kobj is valid, and in order to
 	 * 'free' the object, then the function:
 	 *      edac_mc_unregister_sysfs_main_kobj() must be called
@@ -398,7 +389,7 @@ void edac_mc_free(struct mem_ctl_info *mci)
 {
 	debugf1("%s()\n", __func__);
 
-	edac_mc_unregister_sysfs_main_kobj(mci);
+	edac_unregister_sysfs(mci);
 
 	/* free the mci instance memory here */
 	kfree(mci);
drivers/edac/edac_mc_sysfs.c +407 -667

1,334 lines not on this page · raw message

drivers/edac/edac_module.c +3 -10
index 5ddaa86..8735a0d 100644
@@ -90,10 +90,7 @@ static int __init edac_init(void)
 	 */
 	edac_pci_clear_parity_errors();
 
-	/*
-	 * now set up the mc_kset under the edac class object
-	 */
-	err = edac_sysfs_setup_mc_kset();
+	err = edac_mc_sysfs_init();
 	if (err)
 		goto error;
 
@@ -101,15 +98,11 @@ static int __init edac_init(void)
 	err = edac_workqueue_setup();
 	if (err) {
 		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
-		goto workq_fail;
+		goto error;
 	}
 
 	return 0;
 
-	/* Error teardown stack */
-workq_fail:
-	edac_sysfs_teardown_mc_kset();
-
 error:
 	return err;
 }
@@ -124,7 +117,7 @@ static void __exit edac_exit(void)
 
 	/* tear down the various subsystems */
 	edac_workqueue_teardown();
-	edac_sysfs_teardown_mc_kset();
+	edac_mc_sysfs_exit();
 }
 
 /*
drivers/edac/edac_module.h +5 -4
index 0ea7d14..1af1367 100644
@@ -19,12 +19,12 @@
  *
  * edac_mc objects
  */
-extern int edac_sysfs_setup_mc_kset(void);
-extern void edac_sysfs_teardown_mc_kset(void);
-extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
-extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+	/* on edac_mc_sysfs.c */
+int edac_mc_sysfs_init(void);
+void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+void edac_unregister_sysfs(struct mem_ctl_info *mci);
 extern int edac_get_log_ue(void);
 extern int edac_get_log_ce(void);
 extern int edac_get_panic_on_ue(void);
@@ -34,6 +34,7 @@ extern int edac_mc_get_panic_on_ue(void);
 extern int edac_get_poll_msec(void);
 extern int edac_mc_get_poll_msec(void);
 
+	/* on edac_device.c */
 extern int edac_device_register_sysfs_main_kobj(
 				struct edac_device_ctl_info *edac_dev);
 extern void edac_device_unregister_sysfs_main_kobj(
include/linux/edac.h +32 -14

93 lines not on this page · raw message

author Reviewed-by Aristeu Rozanski
#40 lore raw

Re: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device

In reply to Borislav Petkov

Em 09-05-2012 09:34, Borislav Petkov escreveu:

Quoted 14 lines

Inserting latest version:

Quoted 12 lines

From e8765894c6d43326c9968a3687f5140708ee163f Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <[email protected]>
Date: Mon, 16 Apr 2012 16:41:11 -0300
Subject: [PATCH] edac: rewrite the sysfs code to use struct device

The EDAC subsystem uses the old struct sysdev approach, creating all nodes using the raw sysfs API. This is bad, as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing code to struct device.

Quoted 20 lines
Quoted 1 line

There's one side-back on this patch: all device-specific sysfs

drawback to

Quoted 1 line

nodes won't be created anymore. While it would be possible to

which device-specific nodes?

Quoted 12 lines

also port the device-specific code, it is easier and nicer to move the code to the drivers, instead, as the core can get rid of some complex logic that just emulates what the device_add() and device_create_file() already does.

The next patches will convert the driver-specific code to use the device-specific calls. Then, the remaining bits of the old sysfs API will be removed.

Forgot to attach. This is the patch with the above comments addressed.

Regards,
Mauro

-

edac: rewrite the sysfs code to use struct device

From: Mauro Carvalho Chehab <[email protected]>

The EDAC subsystem uses the old struct sysdev approach, creating all nodes using the raw sysfs API. This is bad, as the API is deprecated.

As we'll be changing the EDAC API, let's first port the existing code to struct device.

There's one drawback on this patch: driver-specific sysfs nodes, used by mpc85xx_edac, amd64_edac and i7core_edac
won't be created anymore. While it would be possible to
also port the device-specific code, that would mix kobj with struct device, with is not recommended. Also, it is easier and nicer to move the code to the drivers, instead, as the core can get rid of some complex logic that just emulates what the device_add() and device_create_file() already does.

The next patches will convert the driver-specific code to use the device-specific calls. Then, the remaining bits of the old sysfs API will be removed.

drivers/edac/edac_mc.c +2 -11
index e6eed13..7a79cbd 100644
@@ -216,7 +216,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	unsigned size, tot_dimms = 1, count = 1;
 	unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
 	void *pvt, *p, *ptr = NULL;
-	int i, j, err, row, chn, n, len;
+	int i, j, row, chn, n, len;
 	bool per_rank = false;
 
 	BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
@@ -369,15 +369,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 	mci->op_state = OP_ALLOC;
 	INIT_LIST_HEAD(&mci->grp_kobj_list);
 
-	/*
-	 * Initialize the 'root' kobj for the edac_mc controller
-	 */
-	err = edac_mc_register_sysfs_main_kobj(mci);
-	if (err) {
-		kfree(mci);
-		return NULL;
-	}
-
 	/* at this point, the root kobj is valid, and in order to
 	 * 'free' the object, then the function:
 	 *      edac_mc_unregister_sysfs_main_kobj() must be called
@@ -400,7 +391,7 @@ void edac_mc_free(struct mem_ctl_info *mci)
 {
 	debugf1("%s()\n", __func__);
 
-	edac_mc_unregister_sysfs_main_kobj(mci);
+	edac_unregister_sysfs(mci);
 
 	/* free the mci instance memory here */
 	kfree(mci);
drivers/edac/edac_mc_sysfs.c +392 -669

1,319 lines not on this page · raw message

drivers/edac/edac_module.c +3 -10
index 5ddaa86..8735a0d 100644
@@ -90,10 +90,7 @@ static int __init edac_init(void)
 	 */
 	edac_pci_clear_parity_errors();
 
-	/*
-	 * now set up the mc_kset under the edac class object
-	 */
-	err = edac_sysfs_setup_mc_kset();
+	err = edac_mc_sysfs_init();
 	if (err)
 		goto error;
 
@@ -101,15 +98,11 @@ static int __init edac_init(void)
 	err = edac_workqueue_setup();
 	if (err) {
 		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
-		goto workq_fail;
+		goto error;
 	}
 
 	return 0;
 
-	/* Error teardown stack */
-workq_fail:
-	edac_sysfs_teardown_mc_kset();
-
 error:
 	return err;
 }
@@ -124,7 +117,7 @@ static void __exit edac_exit(void)
 
 	/* tear down the various subsystems */
 	edac_workqueue_teardown();
-	edac_sysfs_teardown_mc_kset();
+	edac_mc_sysfs_exit();
 }
 
 /*
drivers/edac/edac_module.h +5 -4
index 0ea7d14..1af1367 100644
@@ -19,12 +19,12 @@
  *
  * edac_mc objects
  */
-extern int edac_sysfs_setup_mc_kset(void);
-extern void edac_sysfs_teardown_mc_kset(void);
-extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
-extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+	/* on edac_mc_sysfs.c */
+int edac_mc_sysfs_init(void);
+void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+void edac_unregister_sysfs(struct mem_ctl_info *mci);
 extern int edac_get_log_ue(void);
 extern int edac_get_log_ce(void);
 extern int edac_get_panic_on_ue(void);
@@ -34,6 +34,7 @@ extern int edac_mc_get_panic_on_ue(void);
 extern int edac_get_poll_msec(void);
 extern int edac_mc_get_poll_msec(void);
 
+	/* on edac_device.c */
 extern int edac_device_register_sysfs_main_kobj(
 				struct edac_device_ctl_info *edac_dev);
 extern void edac_device_unregister_sysfs_main_kobj(
include/linux/edac.h +31 -14

92 lines not on this page · raw message

#41 lore raw

PATCH v13 10/25 mpc85xx_edac: convert sysfs logic to use struct device

In reply to Mauro Carvalho Chehab

Now that the EDAC core supports struct device, there's no sense on having any logic at the EDAC core to simulate it. So, instead of adding such logic there, change the logic at mpc85xx_edac to use it

compile-tested only.

---
 drivers/edac/mpc85xx_edac.c |   93 +++++++++++++++++++++++++-----------------
 1 files changed, 55 insertions(+), 38 deletions(-)
drivers/edac/mpc85xx_edac.c +55 -38
index 6146ab7..c67cca1 100644
@@ -49,34 +49,45 @@ static u32 orig_hid1[2];
 
 /************************ MC SYSFS parts ***********************************/
 
-static ssize_t mpc85xx_mc_inject_data_hi_show(struct mem_ctl_info *mci,
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev,
+					      struct device_attribute *mattr,
 					      char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	return sprintf(data, "0x%08x",
 		       in_be32(pdata->mc_vbase +
 			       MPC85XX_MC_DATA_ERR_INJECT_HI));
 }
 
-static ssize_t mpc85xx_mc_inject_data_lo_show(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev,
+					      struct device_attribute *mattr,
 					      char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	return sprintf(data, "0x%08x",
 		       in_be32(pdata->mc_vbase +
 			       MPC85XX_MC_DATA_ERR_INJECT_LO));
 }
 
-static ssize_t mpc85xx_mc_inject_ctrl_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev,
+					   struct device_attribute *mattr,
+					   char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	return sprintf(data, "0x%08x",
 		       in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT));
 }
 
-static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev,
+					       struct device_attribute *mattr,
 					       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	if (isdigit(*data)) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI,
@@ -86,9 +97,11 @@ static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
 	return 0;
 }
 
-static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev,
+					       struct device_attribute *mattr,
 					       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	if (isdigit(*data)) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO,
@@ -98,9 +111,11 @@ static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
 	return 0;
 }
 
-static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
-					    const char *data, size_t count)
+static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev,
+					       struct device_attribute *mattr,
+					       const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 	if (isdigit(*data)) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT,
@@ -110,38 +125,35 @@ static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
 	return 0;
 }
 
-static struct mcidev_sysfs_attribute mpc85xx_mc_sysfs_attributes[] = {
-	{
-	 .attr = {
-		  .name = "inject_data_hi",
-		  .mode = (S_IRUGO | S_IWUSR)
-		  },
-	 .show = mpc85xx_mc_inject_data_hi_show,
-	 .store = mpc85xx_mc_inject_data_hi_store},
-	{
-	 .attr = {
-		  .name = "inject_data_lo",
-		  .mode = (S_IRUGO | S_IWUSR)
-		  },
-	 .show = mpc85xx_mc_inject_data_lo_show,
-	 .store = mpc85xx_mc_inject_data_lo_store},
-	{
-	 .attr = {
-		  .name = "inject_ctrl",
-		  .mode = (S_IRUGO | S_IWUSR)
-		  },
-	 .show = mpc85xx_mc_inject_ctrl_show,
-	 .store = mpc85xx_mc_inject_ctrl_store},
+DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR,
+	    mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store);
+DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR,
+	    mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store);
+DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR,
+	    mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store);
 
-	/* End of list */
-	{
-	 .attr = {.name = NULL}
-	 }
-};
+static int mpc85xx_create_sysfs_attributes(struct mem_ctl_info *mci)
+{
+	int rc;
+
+	rc = device_create_file(&mci->dev, &dev_attr_inject_data_hi);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_data_lo);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_ctrl);
+	if (rc < 0)
+		return rc;
 
-static void mpc85xx_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+	return 0;
+}
+
+static void mpc85xx_remove_sysfs_attributes(struct mem_ctl_info *mci)
 {
-	mci->mc_driver_sysfs_attributes = mpc85xx_mc_sysfs_attributes;
+	device_remove_file(&mci->dev, &dev_attr_inject_data_hi);
+	device_remove_file(&mci->dev, &dev_attr_inject_data_lo);
+	device_remove_file(&mci->dev, &dev_attr_inject_ctrl);
 }
 
 /**************************** PCI Err device ***************************/
@@ -1041,8 +1053,6 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 
 	mci->scrub_mode = SCRUB_SW_SRC;
 
-	mpc85xx_set_mc_sysfs_attributes(mci);
-
 	mpc85xx_init_csrows(mci);
 
 	/* store the original error disable bits */
@@ -1058,6 +1068,12 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 		goto err;
 	}
 
+	if (mpc85xx_create_sysfs_attributes(mci)) {
+		edac_mc_del_mc(mci->pdev);
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		goto err;
+	}
+
 	if (edac_op_state == EDAC_OPSTATE_INT) {
 		out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN,
 			 DDR_EIE_MBEE | DDR_EIE_SBEE);
@@ -1117,6 +1133,7 @@ static int mpc85xx_mc_err_remove(struct platform_device *op)
 		 orig_ddr_err_disable);
 	out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe);
 
+	mpc85xx_remove_sysfs_attributes(mci);
 	edac_mc_del_mc(&op->dev);
 	edac_mc_free(mci);
 	return 0;
Signature · 1 line
1.7.8
#42 lore raw

PATCH v13 11/25 amd64_edac: convert sysfs logic to use struct device

In reply to Mauro Carvalho Chehab

Now that the EDAC core supports struct device, there's no sense on having any logic at the EDAC core to simulate it. So, instead of adding such logic there, change the logic at amd64_edac to use it.

---
 drivers/edac/amd64_edac.c     |   43 ++++++++------
 drivers/edac/amd64_edac.h     |   29 +++++++--
 drivers/edac/amd64_edac_dbg.c |   89 ++++++++++++++--------------
 drivers/edac/amd64_edac_inj.c |  128 +++++++++++++++++++++++-----------------
 4 files changed, 167 insertions(+), 122 deletions(-)
drivers/edac/amd64_edac.c +26 -17
index b26fc06..321b838 100644
@@ -2434,26 +2434,29 @@ static bool ecc_enabled(struct pci_dev *F3, u8 nid)
 	return true;
 }
 
-struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
-					  ARRAY_SIZE(amd64_inj_attrs) +
-					  1];
-
-struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
-
-static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
+static int set_mc_sysfs_attrs(struct mem_ctl_info *mci)
 {
-	unsigned int i = 0, j = 0;
+	int rc;
 
-	for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
-		sysfs_attrs[i] = amd64_dbg_attrs[i];
+	rc = amd64_create_sysfs_dbg_files(mci);
+	if (rc < 0)
+		return rc;
 
-	if (boot_cpu_data.x86 >= 0x10)
-		for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
-			sysfs_attrs[i] = amd64_inj_attrs[j];
+	if (boot_cpu_data.x86 >= 0x10) {
+		rc = amd64_create_sysfs_inject_files(mci);
+		if (rc < 0)
+			return rc;
+	}
+
+	return 0;
+}
 
-	sysfs_attrs[i] = terminator;
+static void del_mc_sysfs_attrs(struct mem_ctl_info *mci)
+{
+	amd64_remove_sysfs_dbg_files(mci);
 
-	mci->mc_driver_sysfs_attributes = sysfs_attrs;
+	if (boot_cpu_data.x86 >= 0x10)
+		amd64_remove_sysfs_inject_files(mci);
 }
 
 static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
@@ -2579,13 +2582,15 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 	if (init_csrows(mci))
 		mci->edac_cap = EDAC_FLAG_NONE;
 
-	set_mc_sysfs_attrs(mci);
-
 	ret = -ENODEV;
 	if (edac_mc_add_mc(mci)) {
 		debugf1("failed edac_mc_add_mc()\n");
 		goto err_add_mc;
 	}
+	if (set_mc_sysfs_attrs(mci)) {
+		debugf1("failed edac_mc_add_mc()\n");
+		goto err_add_sysfs;
+	}
 
 	/* register stuff with EDAC MCE */
 	if (report_gart_errors)
@@ -2599,6 +2604,8 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 
 	return 0;
 
+err_add_sysfs:
+	edac_mc_del_mc(mci->pdev);
 err_add_mc:
 	edac_mc_free(mci);
 
@@ -2669,6 +2676,8 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
 	struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
 	struct ecc_settings *s = ecc_stngs[nid];
 
+	mci = find_mci_by_dev(&pdev->dev);
+	del_mc_sysfs_attrs(mci);
 	/* Remove from EDAC CORE tracking list */
 	mci = edac_mc_del_mc(&pdev->dev);
 	if (!mci)
drivers/edac/amd64_edac.h +22 -7
index 9a666cb..098f336 100644
@@ -413,20 +413,33 @@ struct ecc_settings {
 };
 
 #ifdef CONFIG_EDAC_DEBUG
-#define NUM_DBG_ATTRS 5
+int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci);
+void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci);
+
 #else
-#define NUM_DBG_ATTRS 0
+static inline int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+	return 0;
+}
+void inline amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+}
 #endif
 
 #ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
-#define NUM_INJ_ATTRS 5
+int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci);
+void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci);
+
 #else
-#define NUM_INJ_ATTRS 0
+static inline int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+	return 0;
+}
+static inline void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+}
 #endif
 
-extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],
-				     amd64_inj_attrs[NUM_INJ_ATTRS];
-
 /*
  * Each of the PCI Device IDs types have their own set of hardware accessor
  * functions and per device encoding/decoding logic.
@@ -460,3 +473,5 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
 
 int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
 			     u64 *hole_offset, u64 *hole_size);
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
drivers/edac/amd64_edac_dbg.c +45 -44

107 lines not on this page · raw message

drivers/edac/amd64_edac_inj.c +74 -54

188 lines not on this page · raw message

Signature · 1 line
1.7.8
#43 lore raw

PATCH v13 12/25 i7core_edac: convert it to use struct device

In reply to Mauro Carvalho Chehab

Instead of relying on a complex logic inside the edac core to create a "device tree-like" sysfs struct, just use device_add.

---
 drivers/edac/i7core_edac.c |  338 +++++++++++++++++++++++++++-----------------
 1 files changed, 209 insertions(+), 129 deletions(-)
drivers/edac/i7core_edac.c +209 -129
index 7f81a04..e6a8efd 100644
@@ -246,6 +246,8 @@ struct i7core_dev {
 };
 
 struct i7core_pvt {
+	struct device addrmatch_dev, chancounts_dev;
+
 	struct pci_dev	*pci_noncore;
 	struct pci_dev	*pci_mcr[MAX_MCR_FUNC + 1];
 	struct pci_dev	*pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
@@ -659,6 +661,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 			Error insertion routines
  ****************************************************************************/
 
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
 /* The i7core has independent error injection features per channel.
    However, to have a simpler code, we don't allow enabling error injection
    on more than one channel.
@@ -688,9 +692,11 @@ static int disable_inject(const struct mem_ctl_info *mci)
  *	bit 0 - refers to the lower 32-byte half cacheline
  *	bit 1 - refers to the upper 32-byte half cacheline
  */
-static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
+static ssize_t i7core_inject_section_store(struct device *dev,
+					   struct device_attribute *mattr,
 					   const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int rc;
@@ -706,9 +712,11 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
-					      char *data)
+static ssize_t i7core_inject_section_show(struct device *dev,
+					  struct device_attribute *mattr,
+					  char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	return sprintf(data, "0x%08x\n", pvt->inject.section);
 }
@@ -721,10 +729,12 @@ static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
  *	bit 1 - inject ECC error
  *	bit 2 - inject parity error
  */
-static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
+static ssize_t i7core_inject_type_store(struct device *dev,
+					struct device_attribute *mattr,
 					const char *data, size_t count)
 {
-	struct i7core_pvt *pvt = mci->pvt_info;
+	struct mem_ctl_info *mci = to_mci(dev);
+struct i7core_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int rc;
 
@@ -739,10 +749,13 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
-					      char *data)
+static ssize_t i7core_inject_type_show(struct device *dev,
+				       struct device_attribute *mattr,
+				       char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
+
 	return sprintf(data, "0x%08x\n", pvt->inject.type);
 }
 
@@ -756,9 +769,11 @@ static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
  *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
  *   uncorrectable error to be injected.
  */
-static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
+static ssize_t i7core_inject_eccmask_store(struct device *dev,
+					   struct device_attribute *mattr,
+					   const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	unsigned long value;
 	int rc;
@@ -774,10 +789,13 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
-					      char *data)
+static ssize_t i7core_inject_eccmask_show(struct device *dev,
+					  struct device_attribute *mattr,
+					  char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
+
 	return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
 }
 
@@ -794,9 +812,11 @@ static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
 
 #define DECLARE_ADDR_MATCH(param, limit)			\
 static ssize_t i7core_inject_store_##param(			\
-		struct mem_ctl_info *mci,			\
-		const char *data, size_t count)			\
+	struct device *dev,					\
+	struct device_attribute *mattr,				\
+	const char *data, size_t count)				\
 {								\
+	struct mem_ctl_info *mci = to_mci(dev);			\
 	struct i7core_pvt *pvt;					\
 	long value;						\
 	int rc;							\
@@ -821,9 +841,11 @@ static ssize_t i7core_inject_store_##param(			\
 }								\
 								\
 static ssize_t i7core_inject_show_##param(			\
-		struct mem_ctl_info *mci,			\
-		char *data)					\
+	struct device *dev,					\
+	struct device_attribute *mattr,				\
+	char *data)						\
 {								\
+	struct mem_ctl_info *mci = to_mci(dev);			\
 	struct i7core_pvt *pvt;					\
 								\
 	pvt = mci->pvt_info;					\
@@ -835,14 +857,9 @@ static ssize_t i7core_inject_show_##param(			\
 }
 
 #define ATTR_ADDR_MATCH(param)					\
-	{							\
-		.attr = {					\
-			.name = #param,				\
-			.mode = (S_IRUGO | S_IWUSR)		\
-		},						\
-		.show  = i7core_inject_show_##param,		\
-		.store = i7core_inject_store_##param,		\
-	}
+	static DEVICE_ATTR(param, S_IRUGO | S_IWUSR,		\
+		    i7core_inject_show_##param,			\
+		    i7core_inject_store_##param)
 
 DECLARE_ADDR_MATCH(channel, 3);
 DECLARE_ADDR_MATCH(dimm, 3);
@@ -851,6 +868,13 @@ DECLARE_ADDR_MATCH(bank, 32);
 DECLARE_ADDR_MATCH(page, 0x10000);
 DECLARE_ADDR_MATCH(col, 0x4000);
 
+ATTR_ADDR_MATCH(channel);
+ATTR_ADDR_MATCH(dimm);
+ATTR_ADDR_MATCH(rank);
+ATTR_ADDR_MATCH(bank);
+ATTR_ADDR_MATCH(page);
+ATTR_ADDR_MATCH(col);
+
 static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
 {
 	u32 read;
@@ -896,9 +920,11 @@ static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
  *    is reliable enough to check if the MC is using the
  *    three channels. However, this is not clear at the datasheet.
  */
-static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
-				       const char *data, size_t count)
+static ssize_t i7core_inject_enable_store(struct device *dev,
+					  struct device_attribute *mattr,
+					  const char *data, size_t count)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	u32 injectmask;
 	u64 mask = 0;
@@ -999,9 +1025,11 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
 	return count;
 }
 
-static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
-					char *data)
+static ssize_t i7core_inject_enable_show(struct device *dev,
+					 struct device_attribute *mattr,
+					 char *data)
 {
+	struct mem_ctl_info *mci = to_mci(dev);
 	struct i7core_pvt *pvt = mci->pvt_info;
 	u32 injectmask;
 
@@ -1021,12 +1049,14 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
 
 #define DECLARE_COUNTER(param)					\
 static ssize_t i7core_show_counter_##param(			\
-		struct mem_ctl_info *mci,			\
-		char *data)					\
+	struct device *dev,					\
+	struct device_attribute *mattr,				\
+	char *data)						\
 {								\
+	struct mem_ctl_info *mci = to_mci(dev);			\
 	struct i7core_pvt *pvt = mci->pvt_info;			\
 								\
-	debugf1("%s() \n", __func__);				\
+	debugf1("%s()\n", __func__);				\
 	if (!pvt->ce_count_available || (pvt->is_registered))	\
 		return sprintf(data, "data unavailable\n");	\
 	return sprintf(data, "%lu\n",				\
@@ -1034,121 +1064,167 @@ static ssize_t i7core_show_counter_##param(			\
 }
 
 #define ATTR_COUNTER(param)					\
-	{							\
-		.attr = {					\
-			.name = __stringify(udimm##param),	\
-			.mode = (S_IRUGO | S_IWUSR)		\
-		},						\
-		.show  = i7core_show_counter_##param		\
-	}
+	static DEVICE_ATTR(udimm##param, S_IRUGO | S_IWUSR,	\
+		    i7core_show_counter_##param,		\
+		    NULL)
 
 DECLARE_COUNTER(0);
 DECLARE_COUNTER(1);
 DECLARE_COUNTER(2);
 
+ATTR_COUNTER(0);
+ATTR_COUNTER(1);
+ATTR_COUNTER(2);
+
 /*
- * Sysfs struct
+ * inject_addrmatch device sysfs struct
  */
 
-static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
-	ATTR_ADDR_MATCH(channel),
-	ATTR_ADDR_MATCH(dimm),
-	ATTR_ADDR_MATCH(rank),
-	ATTR_ADDR_MATCH(bank),
-	ATTR_ADDR_MATCH(page),
-	ATTR_ADDR_MATCH(col),
-	{ } /* End of list */
+static struct attribute *i7core_addrmatch_attrs[] = {
+	&dev_attr_channel.attr,
+	&dev_attr_dimm.attr,
+	&dev_attr_rank.attr,
+	&dev_attr_bank.attr,
+	&dev_attr_page.attr,
+	&dev_attr_col.attr,
+	NULL
 };
 
-static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
-	.name  = "inject_addrmatch",
-	.mcidev_attr = i7core_addrmatch_attrs,
+static struct attribute_group addrmatch_grp = {
+	.attrs	= i7core_addrmatch_attrs,
 };
 
-static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
-	ATTR_COUNTER(0),
-	ATTR_COUNTER(1),
-	ATTR_COUNTER(2),
-	{ .attr = { .name = NULL } }
+static const struct attribute_group *addrmatch_groups[] = {
+	&addrmatch_grp,
+	NULL
 };
 
-static const struct mcidev_sysfs_group i7core_udimm_counters = {
-	.name  = "all_channel_counts",
-	.mcidev_attr = i7core_udimm_counters_attrs,
+static void addrmatch_release(struct device *device)
+{
+	debugf1("Releasing device %s\n", dev_name(device));
+}
+
+static struct device_type addrmatch_type = {
+	.groups		= addrmatch_groups,
+	.release	= addrmatch_release,
 };
 
-static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
-	{
-		.attr = {
-			.name = "inject_section",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_section_show,
-		.store = i7core_inject_section_store,
-	}, {
-		.attr = {
-			.name = "inject_type",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_type_show,
-		.store = i7core_inject_type_store,
-	}, {
-		.attr = {
-			.name = "inject_eccmask",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_eccmask_show,
-		.store = i7core_inject_eccmask_store,
-	}, {
-		.grp = &i7core_inject_addrmatch,
-	}, {
-		.attr = {
-			.name = "inject_enable",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_enable_show,
-		.store = i7core_inject_enable_store,
-	},
-	{ }	/* End of list */
+/*
+ * all_channel_counts sysfs struct
+ */
+
+static struct attribute *i7core_udimm_counters_attrs[] = {
+	&dev_attr_udimm0.attr,
+	&dev_attr_udimm1.attr,
+	&dev_attr_udimm2.attr,
+	NULL
+};
+
+static struct attribute_group all_channel_counts_grp = {
+	.attrs	= i7core_udimm_counters_attrs,
 };
 
-static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
-	{
-		.attr = {
-			.name = "inject_section",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_section_show,
-		.store = i7core_inject_section_store,
-	}, {
-		.attr = {
-			.name = "inject_type",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_type_show,
-		.store = i7core_inject_type_store,
-	}, {
-		.attr = {
-			.name = "inject_eccmask",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_eccmask_show,
-		.store = i7core_inject_eccmask_store,
-	}, {
-		.grp = &i7core_inject_addrmatch,
-	}, {
-		.attr = {
-			.name = "inject_enable",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show  = i7core_inject_enable_show,
-		.store = i7core_inject_enable_store,
-	}, {
-		.grp = &i7core_udimm_counters,
-	},
-	{ }	/* End of list */
+static const struct attribute_group *all_channel_counts_groups[] = {
+	&all_channel_counts_grp,
+	NULL
 };
 
+static void all_channel_counts_release(struct device *device)
+{
+	debugf1("Releasing device %s\n", dev_name(device));
+}
+
+static struct device_type all_channel_counts_type = {
+	.groups		= all_channel_counts_groups,
+	.release	= all_channel_counts_release,
+};
+
+/*
+ * inject sysfs attributes
+ */
+
+static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
+		   i7core_inject_section_show, i7core_inject_section_store);
+
+static DEVICE_ATTR(inject_type, S_IRUGO | S_IWUSR,
+		   i7core_inject_type_show, i7core_inject_type_store);
+
+
+static DEVICE_ATTR(inject_eccmask, S_IRUGO | S_IWUSR,
+		   i7core_inject_eccmask_show, i7core_inject_eccmask_store);
+
+static DEVICE_ATTR(inject_enable, S_IRUGO | S_IWUSR,
+		   i7core_inject_enable_show, i7core_inject_enable_store);
+
+static int i7core_create_sysfs_devices(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+	int rc;
+
+	rc = device_create_file(&mci->dev, &dev_attr_inject_section);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_type);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_eccmask);
+	if (rc < 0)
+		return rc;
+	rc = device_create_file(&mci->dev, &dev_attr_inject_enable);
+	if (rc < 0)
+		return rc;
+
+	pvt->addrmatch_dev.type = &addrmatch_type;
+	pvt->addrmatch_dev.bus = mci->dev.bus;
+	device_initialize(&pvt->addrmatch_dev);
+	pvt->addrmatch_dev.parent = &mci->dev;
+	dev_set_name(&pvt->addrmatch_dev, "inject_addrmatch");
+	dev_set_drvdata(&pvt->addrmatch_dev, mci);
+
+	debugf1("%s(): creating %s\n", __func__,
+		dev_name(&pvt->addrmatch_dev));
+
+	rc = device_add(&pvt->addrmatch_dev);
+	if (rc < 0)
+		return rc;
+
+	if (!pvt->is_registered) {
+		pvt->chancounts_dev.type = &all_channel_counts_type;
+		pvt->chancounts_dev.bus = mci->dev.bus;
+		device_initialize(&pvt->chancounts_dev);
+		pvt->chancounts_dev.parent = &mci->dev;
+		dev_set_name(&pvt->chancounts_dev, "all_channel_counts");
+		dev_set_drvdata(&pvt->chancounts_dev, mci);
+
+		debugf1("%s(): creating %s\n", __func__,
+			dev_name(&pvt->chancounts_dev));
+
+		rc = device_add(&pvt->chancounts_dev);
+		if (rc < 0)
+			return rc;
+	}
+	return 0;
+}
+
+static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
+{
+	struct i7core_pvt *pvt = mci->pvt_info;
+
+	debugf1("\n");
+
+	device_remove_file(&mci->dev, &dev_attr_inject_section);
+	device_remove_file(&mci->dev, &dev_attr_inject_type);
+	device_remove_file(&mci->dev, &dev_attr_inject_eccmask);
+	device_remove_file(&mci->dev, &dev_attr_inject_enable);
+
+	if (!pvt->is_registered) {
+		put_device(&pvt->chancounts_dev);
+		device_del(&pvt->chancounts_dev);
+	}
+	put_device(&pvt->addrmatch_dev);
+	device_del(&pvt->addrmatch_dev);
+}
+
 /****************************************************************************
 	Device initialization routines: put/get, init/exit
  ****************************************************************************/
@@ -2119,6 +2195,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
 	i7core_pci_ctl_release(pvt);
 
 	/* Remove MC sysfs nodes */
+	i7core_delete_sysfs_devices(mci);
 	edac_mc_del_mc(mci->pdev);
 
 	debugf1("%s: free mci struct\n", mci->ctl_name);
@@ -2177,10 +2254,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 	if (unlikely(rc < 0))
 		goto fail0;
 
-	if (pvt->is_registered)
-		mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
-	else
-		mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
 
 	/* Get dimm basic config */
 	get_dimm_config(mci);
@@ -2204,6 +2277,13 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 		rc = -EINVAL;
 		goto fail0;
 	}
+	if (i7core_create_sysfs_devices(mci)) {
+		debugf0("MC: " __FILE__
+			": %s(): failed to create sysfs nodes\n", __func__);
+		edac_mc_del_mc(mci->pdev);
+		rc = -EINVAL;
+		goto fail0;
+	}
 
 	/* Default error mask is any memory */
 	pvt->inject.channel = 0;
Signature · 1 line
1.7.8
#44 lore raw

PATCH v13 13/25 edac: Get rid of the old kobj's from the edac mc code

In reply to Mauro Carvalho Chehab

Now that al users for the old kobj raw access are gone, we can get rid of the legacy kobj-based structures and data.

---
 drivers/edac/edac_mc.c      |    1 -
 drivers/edac/i5000_edac.c   |    3 ---
 drivers/edac/i82875p_edac.c |    4 ----
 include/linux/edac.h        |   30 ------------------------------
 4 files changed, 0 insertions(+), 38 deletions(-)
drivers/edac/edac_mc.c +0 -1
index 019c5bd..35c8f3b 100644
@@ -366,7 +366,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	}
 
 	mci->op_state = OP_ALLOC;
-	INIT_LIST_HEAD(&mci->grp_kobj_list);
 
 	/* at this point, the root kobj is valid, and in order to
 	 * 'free' the object, then the function:
drivers/edac/i5000_edac.c +0 -3
index 60ed0ce..3626225 100644
@@ -1409,7 +1409,6 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 	if (mci == NULL)
 		return -ENOMEM;
 
-	kobject_get(&mci->edac_mci_kobj);
 	debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
 	mci->pdev = &pdev->dev;	/* record ptr  to the generic device */
@@ -1482,7 +1481,6 @@ fail1:
 	i5000_put_devices(mci);
 
 fail0:
-	kobject_put(&mci->edac_mci_kobj);
 	edac_mc_free(mci);
 	return -ENODEV;
 }
@@ -1528,7 +1526,6 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 
 	/* retrieve references to resources, and free those resources */
 	i5000_put_devices(mci);
-	kobject_put(&mci->edac_mci_kobj);
 	edac_mc_free(mci);
 }
 
drivers/edac/i82875p_edac.c +0 -4
index 8de9250..9691449 100644
@@ -426,9 +426,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 		goto fail0;
 	}
 
-	/* Keeps mci available after edac_mc_del_mc() till edac_mc_free() */
-	kobject_get(&mci->edac_mci_kobj);
-
 	debugf3("%s(): init mci\n", __func__);
 	mci->pdev = &pdev->dev;
 	mci->mtype_cap = MEM_FLAG_DDR;
@@ -471,7 +468,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
 	return 0;
 
 fail1:
-	kobject_put(&mci->edac_mci_kobj);
 	edac_mc_free(mci);
 
 fail0:
include/linux/edac.h +0 -30
index 203ee3d..676b893 100644
@@ -430,7 +430,6 @@ struct dimm_info {
 	/* Memory location data */
 	unsigned location[EDAC_MAX_LAYERS];
 
-	struct kobject kobj;		/* sysfs kobject for this csrow */
 	struct mem_ctl_info *mci;	/* the parent */
 
 	u32 grain;		/* granularity of reported error in bytes */
@@ -484,34 +483,11 @@ struct csrow_info {
 
 	struct mem_ctl_info *mci;	/* the parent */
 
-	struct kobject kobj;	/* sysfs kobject for this csrow */
-
 	/* channel information for this csrow */
 	u32 nr_channels;
 	struct rank_info *channels;
 };
 
-struct mcidev_sysfs_group {
-	const char *name;				/* group name */
-	const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
-};
-
-/* mcidev_sysfs_attribute structure
- *	used for driver sysfs attributes and in mem_ctl_info
- * 	sysfs top level entries
- */
-struct mcidev_sysfs_attribute {
-	/* It should use either attr or grp */
-	struct attribute attr;
-	const struct mcidev_sysfs_group *grp;	/* Points to a group of attributes */
-
-	/* Ops for show/store values at the attribute - not used on group */
-	ssize_t (*show)(struct mem_ctl_info *, char *);
-	ssize_t (*store)(struct mem_ctl_info *, const char *, size_t);
-
-	void *priv;
-};
-
 /*
  * struct errcount_attribute - used to store the several error counts
  */
@@ -615,12 +591,6 @@ struct mem_ctl_info {
 
 	struct completion complete;
 
-	/* edac sysfs device control */
-	struct kobject edac_mci_kobj;
-
-	/* list for all grp instances within a mc */
-	struct list_head grp_kobj_list;
-
 	/* Additional top controller level attributes, but specified
 	 * by the low level driver.
 	 *
Signature · 1 line
1.7.8
#45 lore raw

PATCH v13 14/25 edac: add a new per-dimm API and make the old per-virtual-rank API obsolete

In reply to Mauro Carvalho Chehab

The old EDAC API is broken. It only works fine for systems manufatured before 2005 and for AMD 64. The reason is that it forces all memory controller drivers to discover rank info.

Also, it doesn't allow grouping the several ranks into a DIMM.

So, what almost all modern drivers do is to create a fake virtual-rank information, and use it to cheat the EDAC core to accept the driver.

While this works if the user has enough time to discover what DIMM slot corresponds to each "virtual-rank" information, it prevents EDAC usage for users with less available time. It also makes life hard for vendors that may want to provide a table with their motherboards to the userspace tool (edac-utils) as each driver has its own logic for the virtual mapping.

So, the old API should be removed, in favor of a more flexible API that allows newer drivers to not lie to the EDAC core.

Cc Doug Thompson <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Randy Dunlap <[email protected]>
Cc Josh Boyer <[email protected]>
Cc Hui Wang <[email protected]>
---
 drivers/edac/Kconfig         |    8 ++
 drivers/edac/edac_mc.c       |   43 ++++++++----
 drivers/edac/edac_mc_sysfs.c |  165 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 202 insertions(+), 14 deletions(-)
drivers/edac/Kconfig +8 -0
index fdffa1b..3b3f84f 100644
@@ -31,6 +31,14 @@ if EDAC
 
 comment "Reporting subsystems"
 
+config EDAC_LEGACY_SYSFS
+	bool "EDAC legacy sysfs"
+	default y
+	help
+	  Enable the compatibility sysfs nodes.
+	  Use 'Y' if your edac utilities aren't ported to work with the newer
+	  structures.
+
 config EDAC_DEBUG
 	bool "Debugging"
 	help
drivers/edac/edac_mc.c +30 -13

111 lines not on this page · raw message

drivers/edac/edac_mc_sysfs.c +164 -1

201 lines not on this page · raw message

Signature · 1 line
1.7.8
#46 lore raw

PATCH v13 15/25 edac: add a sysfs node to report the maximum location for the system

In reply to Mauro Carvalho Chehab

The userspace tools need to know what's the maximum location on each system, as it helps to create nice maps showing how the memory was filled at the system.

---
 drivers/edac/edac_mc_sysfs.c |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)
drivers/edac/edac_mc_sysfs.c +19 -0
index a4ee4aa..67a07c4 100644
@@ -766,6 +766,23 @@ static ssize_t mci_size_mb_show(struct device *dev,
 	return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
 }
 
+static ssize_t mci_max_location_show(struct device *dev,
+				     struct device_attribute *mattr,
+				     char *data)
+{
+	struct mem_ctl_info *mci = to_mci(dev);
+	int i;
+	char *p = data;
+
+	for (i = 0; i < mci->n_layers; i++) {
+		p += sprintf(p, "%s %d ",
+			     edac_layer_name[mci->layers[i].type],
+			     mci->layers[i].size - 1);
+	}
+
+	return p - data;
+}
+
 /* default Control file */
 DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
 
@@ -777,6 +794,7 @@ DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
 DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
 DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
 DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
 
 /* memory scrubber attribute file */
 DEVICE_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
@@ -792,6 +810,7 @@ static struct attribute *mci_attrs[] = {
 	&dev_attr_ue_count.attr,
 	&dev_attr_ce_count.attr,
 	&dev_attr_sdram_scrub_rate.attr,
+	&dev_attr_max_location.attr,
 	NULL
 };
 
Signature · 1 line
1.7.8
#47 lore raw

PATCH v13 16/25 edac: Add debufs nodes to allow doing fake error inject

In reply to Mauro Carvalho Chehab

Sometimes, it is useful to have a mechanism that generates fake errors, in order to test the EDAC core code, and the userspace tools.

Provide such mechanism by adding a few debugfs nodes.

---
 drivers/edac/edac_mc_sysfs.c |   87 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/edac.h         |    7 +++
 2 files changed, 94 insertions(+), 0 deletions(-)
drivers/edac/edac_mc_sysfs.c +87 -0
index 67a07c4..5f7f0f1 100644
@@ -17,6 +17,7 @@
 #include <linux/edac.h>
 #include <linux/bug.h>
 #include <linux/pm_runtime.h>
+#include <linux/uaccess.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
@@ -783,6 +784,47 @@ static ssize_t mci_max_location_show(struct device *dev,
 	return p - data;
 }
 
+#ifdef CONFIG_EDAC_DEBUG
+static ssize_t edac_fake_inject_write(struct file *file,
+				      const char __user *data,
+				      size_t count, loff_t *ppos)
+{
+	struct device *dev = file->private_data;
+	struct mem_ctl_info *mci = to_mci(dev);
+	static enum hw_event_mc_err_type type;
+
+	type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED
+				   : HW_EVENT_ERR_CORRECTED;
+
+	printk(KERN_DEBUG
+	       "Generating a %s fake error to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n",
+		(type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE",
+		mci->fake_inject_layer[0],
+		mci->fake_inject_layer[1],
+		mci->fake_inject_layer[2]
+	       );
+	edac_mc_handle_error(type, mci, 0, 0, 0,
+			     mci->fake_inject_layer[0],
+			     mci->fake_inject_layer[1],
+			     mci->fake_inject_layer[2],
+			     "FAKE ERROR", "for EDAC testing only", NULL);
+
+	return count;
+}
+
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations debug_fake_inject_fops = {
+	.open = debugfs_open,
+	.write = edac_fake_inject_write,
+	.llseek = generic_file_llseek,
+};
+#endif
+
 /* default Control file */
 DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
 
@@ -833,6 +875,45 @@ static struct device_type mci_attr_type = {
 	.release	= mci_attr_release,
 };
 
+#ifdef CONFIG_EDAC_DEBUG
+int edac_create_debug_nodes(struct mem_ctl_info *mci)
+{
+	struct dentry *d, *parent;
+	char name[80];
+	int i;
+
+	d = debugfs_create_dir(mci->dev.kobj.name, mci->debugfs);
+	if (!d)
+		return -ENOMEM;
+	parent = d;
+
+	for (i = 0; i < mci->n_layers; i++) {
+		sprintf(name, "fake_inject_%s",
+			     edac_layer_name[mci->layers[i].type]);
+		d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent,
+				      &mci->fake_inject_layer[i]);
+		if (!d)
+			goto nomem;
+	}
+
+	d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent,
+				&mci->fake_inject_ue);
+	if (!d)
+		goto nomem;
+
+	d = debugfs_create_file("fake_inject", S_IWUSR, parent,
+				&mci->dev,
+				&debug_fake_inject_fops);
+	if (!d)
+		goto nomem;
+
+	return 0;
+nomem:
+	debugfs_remove(mci->debugfs);
+	return -ENOMEM;
+}
+#endif
+
 /*
  * Create a new Memory Controller kobject instance,
  *	mc<id> under the 'mc' directory
@@ -898,6 +979,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 		goto fail;
 #endif
 
+#ifdef CONFIG_EDAC_DEBUG
+	edac_create_debug_nodes(mci);
+#endif
 	return 0;
 
 fail:
@@ -922,6 +1006,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 
 	debugf0("%s()\n", __func__);
 
+#ifdef CONFIG_EDAC_DEBUG
+	debugfs_remove(mci->debugfs);
+#endif
 #ifdef CONFIG_EDAC_LEGACY_SYSFS
 	edac_delete_csrow_objects(mci);
 #endif
include/linux/edac.h +7 -0
index 676b893..a32ed72 100644
@@ -14,6 +14,7 @@
 
 #include <linux/atomic.h>
 #include <linux/device.h>
+#include <linux/debugfs.h>
 
 #define EDAC_OPSTATE_INVAL	-1
 #define EDAC_OPSTATE_POLL	0
@@ -608,6 +609,12 @@ struct mem_ctl_info {
 
 	/* the internal state of this controller instance */
 	int op_state;
+
+#ifdef CONFIG_EDAC_DEBUG
+	struct dentry *debugfs;
+	u8 fake_inject_layer[EDAC_MAX_LAYERS];
+	u32 fake_inject_ue;
+#endif
 };
 
 #endif
Signature · 1 line
1.7.8
#48 lore raw

PATCH v13 17/25 edac: Create a per-Memory Controller bus

In reply to Mauro Carvalho Chehab

I'm getting this bug on machines with more than one memory controller:

[  819.094946] EDAC DEBUG: find_mci_by_dev: find_mci_by_dev()
[  819.094948] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device() idx=1
[  819.094952] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device(): creating device mc1
[  819.094967] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm0, located at channel 0 slot 0
[  819.094984] ------------[ cut here ]------------
[  819.100142] WARNING: at fs/sysfs/dir.c:481 sysfs_add_one+0xc1/0xf0()
[  819.107282] Hardware name: S2600CP
[  819.111078] sysfs: cannot create duplicate filename '/bus/edac/devices/dimm0'
[  819.119062] Modules linked in: sb_edac(+) edac_core ip6table_filter ip6_tables ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables bridge stp llc sunrpc binfmt_misc dm_mirror dm_region_hash dm_log vhost_net macvtap macvlan tun kvm microcode pcspkr iTCO_wdt iTCO_vendor_support igb i2c_i801 i2c_core sg ioatdma dca sr_mod cdrom sd_mod crc_t10dif ahci libahci isci libsas libata scsi_transport_sas scsi_mod wmi dm_mod [last unloaded: scsi_wait_scan]
[  819.175748] Pid: 10902, comm: modprobe Not tainted 3.3.0-0.11.el7.v12.2.x86_64 #1
[  819.184113] Call Trace:
[  819.186868]  [<ffffffff8105adaf>] warn_slowpath_common+0x7f/0xc0
[  819.193573]  [<ffffffff8105aea6>] warn_slowpath_fmt+0x46/0x50
[  819.200000]  [<ffffffff811f53d1>] sysfs_add_one+0xc1/0xf0
[  819.206025]  [<ffffffff811f5cf5>] sysfs_do_create_link+0x135/0x220
[  819.212944]  [<ffffffff811f7023>] ? sysfs_create_group+0x13/0x20
[  819.219656]  [<ffffffff811f5df3>] sysfs_create_link+0x13/0x20
[  819.226109]  [<ffffffff813b04f6>] bus_add_device+0xe6/0x1b0
[  819.232350]  [<ffffffff813ae7cb>] device_add+0x2db/0x460
[  819.238300]  [<ffffffffa0325634>] edac_create_dimm_object+0x84/0xf0 [edac_core]
[  819.246460]  [<ffffffffa0325e18>] edac_create_sysfs_mci_device+0xe8/0x290 [edac_core]
[  819.255215]  [<ffffffffa0322e2a>] edac_mc_add_mc+0x5a/0x2c0 [edac_core]
[  819.262611]  [<ffffffffa03412df>] sbridge_register_mci+0x1bc/0x279 [sb_edac]
[  819.270493]  [<ffffffffa03417a3>] sbridge_probe+0xef/0x175 [sb_edac]
[  819.277630]  [<ffffffff813ba4e8>] ? pm_runtime_enable+0x58/0x90
[  819.284268]  [<ffffffff812f430c>] local_pci_probe+0x5c/0xd0
[  819.290508]  [<ffffffff812f5ba1>] __pci_device_probe+0xf1/0x100
[  819.297117]  [<ffffffff812f5bea>] pci_device_probe+0x3a/0x60
[  819.303457]  [<ffffffff813b1003>] really_probe+0x73/0x270
[  819.309496]  [<ffffffff813b138e>] driver_probe_device+0x4e/0xb0
[  819.316104]  [<ffffffff813b149b>] __driver_attach+0xab/0xb0
[  819.322337]  [<ffffffff813b13f0>] ? driver_probe_device+0xb0/0xb0
[  819.329151]  [<ffffffff813af5d6>] bus_for_each_dev+0x56/0x90
[  819.335489]  [<ffffffff813b0d7e>] driver_attach+0x1e/0x20
[  819.341534]  [<ffffffff813b0980>] bus_add_driver+0x1b0/0x2a0
[  819.347884]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.353641]  [<ffffffff813b19f6>] driver_register+0x76/0x140
[  819.359980]  [<ffffffff8159f18b>] ? printk+0x51/0x53
[  819.365524]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.371291]  [<ffffffff812f5896>] __pci_register_driver+0x56/0xd0
[  819.378096]  [<ffffffffa0347054>] sbridge_init+0x54/0x1000 [sb_edac]
[  819.385231]  [<ffffffff8100203f>] do_one_initcall+0x3f/0x170
[  819.391577]  [<ffffffff810bcd2e>] sys_init_module+0xbe/0x230
[  819.397926]  [<ffffffff815bb529>] system_call_fastpath+0x16/0x1b
[  819.404633] ---[ end trace 1654fdd39556689f ]---

This is happening because the bus is not being properly initialized. Instead of putting the memory sub-devices inside the memory controller, it is putting everything under the same directory:

$ tree /sys/bus/edac/
/sys/bus/edac/
├── devices
│   ├── all_channel_counts -> ../../../devices/system/edac/mc/mc0/all_channel_counts
│   ├── csrow0 -> ../../../devices/system/edac/mc/mc0/csrow0
│   ├── csrow1 -> ../../../devices/system/edac/mc/mc0/csrow1
│   ├── csrow2 -> ../../../devices/system/edac/mc/mc0/csrow2
│   ├── dimm0 -> ../../../devices/system/edac/mc/mc0/dimm0
│   ├── dimm1 -> ../../../devices/system/edac/mc/mc0/dimm1
│   ├── dimm3 -> ../../../devices/system/edac/mc/mc0/dimm3
│   ├── dimm6 -> ../../../devices/system/edac/mc/mc0/dimm6
│   ├── inject_addrmatch -> ../../../devices/system/edac/mc/mc0/inject_addrmatch
│   ├── mc -> ../../../devices/system/edac/mc
│   └── mc0 -> ../../../devices/system/edac/mc/mc0
├── drivers
├── drivers_autoprobe
├── drivers_probe
└── uevent

On a multi-memory controller system, the names "csrow%d" and "dimm%d" should be under "mc%d", and not at the main hierarchy level.

So, we need to create a per-MC bus, in order to have its own namespace.

---
 drivers/edac/edac_mc_sysfs.c |   25 +++++++++++++++++++++----
 include/linux/edac.h         |    1 +
 2 files changed, 22 insertions(+), 4 deletions(-)
drivers/edac/edac_mc_sysfs.c +21 -4
index 5f7f0f1..38fccf2 100644
@@ -357,7 +357,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
 		return -ENODEV;
 
 	csrow->dev.type = &csrow_attr_type;
-	csrow->dev.bus = mci_pdev.bus;
+	csrow->dev.bus = &mci->bus;
 	device_initialize(&csrow->dev);
 	csrow->dev.parent = &mci->dev;
 	dev_set_name(&csrow->dev, "csrow%d", index);
@@ -580,7 +580,7 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
 	dimm->mci = mci;
 
 	dimm->dev.type = &dimm_attr_type;
-	dimm->dev.bus = mci_pdev.bus;
+	dimm->dev.bus = &mci->bus;
 	device_initialize(&dimm->dev);
 
 	dimm->dev.parent = &mci->dev;
@@ -934,16 +934,29 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 	device_initialize(&mci->dev);
 
 	mci->dev.parent = &mci_pdev;
-	mci->dev.bus = mci_pdev.bus;
+	mci->dev.bus = &mci->bus;
 	dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
 	dev_set_drvdata(&mci->dev, mci);
 	pm_runtime_forbid(&mci->dev);
 
+	/*
+	 * The memory controller needs its own bus, in order to avoid
+	 * namespace conflicts at /sys/bus/edac.
+	 */
+	debugf0("creating bus %s\n",mci->bus.name);
+	mci->bus.name = kstrdup(dev_name(&mci->dev), GFP_KERNEL);
+	err = bus_register(&mci->bus);
+	if (err < 0)
+		return err;
+
 	debugf0("%s(): creating device %s\n", __func__,
 		dev_name(&mci->dev));
 	err = device_add(&mci->dev);
-	if (err < 0)
+	if (err < 0) {
+		bus_unregister(&mci->bus);
+		kfree(mci->bus.name);
 		return err;
+	}
 
 	/*
 	 * Create the dimm/rank devices
@@ -994,6 +1007,8 @@ fail:
 	}
 	put_device(&mci->dev);
 	device_del(&mci->dev);
+	bus_unregister(&mci->bus);
+	kfree(mci->bus.name);
 	return err;
 }
 
@@ -1029,6 +1044,8 @@ void edac_unregister_sysfs(struct mem_ctl_info *mci)
 	debugf1("Unregistering device %s\n", dev_name(&mci->dev));
 	put_device(&mci->dev);
 	device_del(&mci->dev);
+	bus_unregister(&mci->bus);
+	kfree(mci->bus.name);
 }
 
 static void mc_attr_release(struct device *device)
include/linux/edac.h +1 -0
index a32ed72..22c3fca 100644
@@ -507,6 +507,7 @@ struct edac_hierarchy {
  */
 struct mem_ctl_info {
 	struct device			dev;
+	struct bus_type			bus;
 
 	struct list_head link;	/* for global list of mem_ctl_info structs */
 
Signature · 1 line
1.7.8
Acked-by on v13 17/25
#49 lore raw

Re: [EDAC ABI v13 17/25] edac: Create a per-Memory Controller bus

Quoted 71 lines · Mauro Carvalho Chehab

I'm getting this bug on machines with more than one memory controller:

[  819.094946] EDAC DEBUG: find_mci_by_dev: find_mci_by_dev()
[  819.094948] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device() idx=1
[  819.094952] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device(): creating device mc1
[  819.094967] EDAC DEBUG: edac_create_sysfs_mci_device: edac_create_sysfs_mci_device creating dimm0, located at channel 0 slot 0
[  819.094984] ------------[ cut here ]------------
[  819.100142] WARNING: at fs/sysfs/dir.c:481 sysfs_add_one+0xc1/0xf0()
[  819.107282] Hardware name: S2600CP
[  819.111078] sysfs: cannot create duplicate filename '/bus/edac/devices/dimm0'
[  819.119062] Modules linked in: sb_edac(+) edac_core ip6table_filter ip6_tables ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables bridge stp llc sunrpc binfmt_misc dm_mirror dm_region_hash dm_log vhost_net macvtap macvlan tun kvm microcode pcspkr iTCO_wdt iTCO_vendor_support igb i2c_i801 i2c_core sg ioatdma dca sr_mod cdrom sd_mod crc_t10dif ahci libahci isci libsas libata scsi_transport_sas scsi_mod wmi dm_mod [last unloaded: scsi_wait_scan]
[  819.175748] Pid: 10902, comm: modprobe Not tainted 3.3.0-0.11.el7.v12.2.x86_64 #1
[  819.184113] Call Trace:
[  819.186868]  [<ffffffff8105adaf>] warn_slowpath_common+0x7f/0xc0
[  819.193573]  [<ffffffff8105aea6>] warn_slowpath_fmt+0x46/0x50
[  819.200000]  [<ffffffff811f53d1>] sysfs_add_one+0xc1/0xf0
[  819.206025]  [<ffffffff811f5cf5>] sysfs_do_create_link+0x135/0x220
[  819.212944]  [<ffffffff811f7023>] ? sysfs_create_group+0x13/0x20
[  819.219656]  [<ffffffff811f5df3>] sysfs_create_link+0x13/0x20
[  819.226109]  [<ffffffff813b04f6>] bus_add_device+0xe6/0x1b0
[  819.232350]  [<ffffffff813ae7cb>] device_add+0x2db/0x460
[  819.238300]  [<ffffffffa0325634>] edac_create_dimm_object+0x84/0xf0 [edac_core]
[  819.246460]  [<ffffffffa0325e18>] edac_create_sysfs_mci_device+0xe8/0x290 [edac_core]
[  819.255215]  [<ffffffffa0322e2a>] edac_mc_add_mc+0x5a/0x2c0 [edac_core]
[  819.262611]  [<ffffffffa03412df>] sbridge_register_mci+0x1bc/0x279 [sb_edac]
[  819.270493]  [<ffffffffa03417a3>] sbridge_probe+0xef/0x175 [sb_edac]
[  819.277630]  [<ffffffff813ba4e8>] ? pm_runtime_enable+0x58/0x90
[  819.284268]  [<ffffffff812f430c>] local_pci_probe+0x5c/0xd0
[  819.290508]  [<ffffffff812f5ba1>] __pci_device_probe+0xf1/0x100
[  819.297117]  [<ffffffff812f5bea>] pci_device_probe+0x3a/0x60
[  819.303457]  [<ffffffff813b1003>] really_probe+0x73/0x270
[  819.309496]  [<ffffffff813b138e>] driver_probe_device+0x4e/0xb0
[  819.316104]  [<ffffffff813b149b>] __driver_attach+0xab/0xb0
[  819.322337]  [<ffffffff813b13f0>] ? driver_probe_device+0xb0/0xb0
[  819.329151]  [<ffffffff813af5d6>] bus_for_each_dev+0x56/0x90
[  819.335489]  [<ffffffff813b0d7e>] driver_attach+0x1e/0x20
[  819.341534]  [<ffffffff813b0980>] bus_add_driver+0x1b0/0x2a0
[  819.347884]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.353641]  [<ffffffff813b19f6>] driver_register+0x76/0x140
[  819.359980]  [<ffffffff8159f18b>] ? printk+0x51/0x53
[  819.365524]  [<ffffffffa0347000>] ? 0xffffffffa0346fff
[  819.371291]  [<ffffffff812f5896>] __pci_register_driver+0x56/0xd0
[  819.378096]  [<ffffffffa0347054>] sbridge_init+0x54/0x1000 [sb_edac]
[  819.385231]  [<ffffffff8100203f>] do_one_initcall+0x3f/0x170
[  819.391577]  [<ffffffff810bcd2e>] sys_init_module+0xbe/0x230
[  819.397926]  [<ffffffff815bb529>] system_call_fastpath+0x16/0x1b
[  819.404633] ---[ end trace 1654fdd39556689f ]---

This is happening because the bus is not being properly initialized. Instead of putting the memory sub-devices inside the memory controller, it is putting everything under the same directory:

$ tree /sys/bus/edac/
/sys/bus/edac/
├── devices
│   ├── all_channel_counts -> ../../../devices/system/edac/mc/mc0/all_channel_counts
│   ├── csrow0 -> ../../../devices/system/edac/mc/mc0/csrow0
│   ├── csrow1 -> ../../../devices/system/edac/mc/mc0/csrow1
│   ├── csrow2 -> ../../../devices/system/edac/mc/mc0/csrow2
│   ├── dimm0 -> ../../../devices/system/edac/mc/mc0/dimm0
│   ├── dimm1 -> ../../../devices/system/edac/mc/mc0/dimm1
│   ├── dimm3 -> ../../../devices/system/edac/mc/mc0/dimm3
│   ├── dimm6 -> ../../../devices/system/edac/mc/mc0/dimm6
│   ├── inject_addrmatch -> ../../../devices/system/edac/mc/mc0/inject_addrmatch
│   ├── mc -> ../../../devices/system/edac/mc
│   └── mc0 -> ../../../devices/system/edac/mc/mc0
├── drivers
├── drivers_autoprobe
├── drivers_probe
└── uevent
Quoted 8 lines

On a multi-memory controller system, the names "csrow%d" and "dimm%d" should be under "mc%d", and not at the main hierarchy level.

So, we need to create a per-MC bus, in order to have its own namespace.

#50 lore raw

PATCH v13 18/25 edac: Move grain/dtype/edac_type calculus to be out of channel loop

In reply to Mauro Carvalho Chehab

The 3e7bddc changeset (edac: move dimm properties to struct memset_info) moved the calculus inside a loop. However, at those stuff are common to all channels, on several drivers, it is better to put the calculus outside the loop, to optimize the code.

Cc Mark Gross <[email protected]>
Cc Doug Thompson <[email protected]>
Cc Dmitry Eremin-Solenikov <[email protected]>
Cc Benjamin Herrenschmidt <[email protected]>
Cc Michal Marek <[email protected]>
---
 drivers/edac/cpc925_edac.c |   54 ++++++++++++++++++++++----------------------
 drivers/edac/e752x_edac.c  |   31 +++++++++++++------------
 drivers/edac/e7xxx_edac.c  |   32 +++++++++++++------------
 3 files changed, 60 insertions(+), 57 deletions(-)
drivers/edac/cpc925_edac.c +27 -27
index 78881b1..1b26ced 100644
@@ -330,8 +330,9 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 	struct cpc925_mc_pdata *pdata = mci->pvt_info;
 	struct csrow_info *csrow;
 	struct dimm_info *dimm;
+	enum dev_type dtype;
 	int index, j;
-	u32 mbmr, mbbar, bba;
+	u32 mbmr, mbbar, bba, grain;
 	unsigned long row_size, nr_pages, last_nr_pages = 0;
 
 	get_total_mem(pdata);
@@ -355,37 +356,36 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		csrow->last_page = csrow->first_page + nr_pages - 1;
 		last_nr_pages = csrow->last_page + 1;
 
+		switch (csrow->nr_channels) {
+		case 1: /* Single channel */
+			grain = 32; /* four-beat burst of 32 bytes */
+			break;
+		case 2: /* Dual channel */
+		default:
+			grain = 64; /* four-beat burst of 64 bytes */
+			break;
+		}
+		switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
+		case 6: /* 0110, no way to differentiate X8 VS X16 */
+		case 5:	/* 0101 */
+		case 8: /* 1000 */
+			dtype = DEV_X16;
+			break;
+		case 7: /* 0111 */
+		case 9: /* 1001 */
+			dtype = DEV_X8;
+			break;
+		default:
+			dtype = DEV_UNKNOWN;
+		break;
+		}
 		for (j = 0; j < csrow->nr_channels; j++) {
 			dimm = csrow->channels[j].dimm;
-
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 			dimm->mtype = MEM_RDDR;
 			dimm->edac_mode = EDAC_SECDED;
-
-			switch (csrow->nr_channels) {
-			case 1: /* Single channel */
-				dimm->grain = 32; /* four-beat burst of 32 bytes */
-				break;
-			case 2: /* Dual channel */
-			default:
-				dimm->grain = 64; /* four-beat burst of 64 bytes */
-				break;
-			}
-
-			switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
-			case 6: /* 0110, no way to differentiate X8 VS X16 */
-			case 5:	/* 0101 */
-			case 8: /* 1000 */
-				dimm->dtype = DEV_X16;
-				break;
-			case 7: /* 0111 */
-			case 9: /* 1001 */
-				dimm->dtype = DEV_X8;
-				break;
-			default:
-				dimm->dtype = DEV_UNKNOWN;
-				break;
-			}
+			dimm->grain = grain;
+			dimm->dtype = dtype;
 		}
 	}
 }
drivers/edac/e752x_edac.c +16 -15
index 9b252dd..84bb8f6 100644
@@ -1069,6 +1069,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 			u16 ddrcsr)
 {
 	struct csrow_info *csrow;
+	enum edac_type edac_mode;
 	unsigned long last_cumul_size;
 	int index, mem_dev, drc_chan;
 	int drc_drbg;		/* DRB granularity 0=64mb, 1=128mb */
@@ -1111,6 +1112,20 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 		nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
 
+		/*
+		* if single channel or x8 devices then SECDED
+		* if dual channel and x4 then S4ECD4ED
+		*/
+		if (drc_ddim) {
+			if (drc_chan && mem_dev) {
+				edac_mode = EDAC_S4ECD4ED;
+				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+			} else {
+				edac_mode = EDAC_SECDED;
+				mci->edac_cap |= EDAC_FLAG_SECDED;
+			}
+		} else
+			edac_mode = EDAC_NONE;
 		for (i = 0; i < csrow->nr_channels; i++) {
 			struct dimm_info *dimm = csrow->channels[i].dimm;
 
@@ -1119,21 +1134,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
 			dimm->mtype = MEM_RDDR;	/* only one type supported */
 			dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-			/*
-			* if single channel or x8 devices then SECDED
-			* if dual channel and x4 then S4ECD4ED
-			*/
-			if (drc_ddim) {
-				if (drc_chan && mem_dev) {
-					dimm->edac_mode = EDAC_S4ECD4ED;
-					mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-				} else {
-					dimm->edac_mode = EDAC_SECDED;
-					mci->edac_cap |= EDAC_FLAG_SECDED;
-				}
-			} else
-				dimm->edac_mode = EDAC_NONE;
+			dimm->edac_mode = edac_mode;
 		}
 	}
 }
drivers/edac/e7xxx_edac.c +17 -15
index dba87a7..e930dd1 100644
@@ -362,6 +362,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	int drc_chan, drc_drbg, drc_ddim, mem_dev;
 	struct csrow_info *csrow;
 	struct dimm_info *dimm;
+	enum edac_type edac_mode;
 
 	pci_read_config_dword(pdev, E7XXX_DRA, &dra);
 	drc_chan = dual_channel_active(drc, dev_idx);
@@ -392,6 +393,21 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 		nr_pages = cumul_size - last_cumul_size;
 		last_cumul_size = cumul_size;
 
+		/*
+		* if single channel or x8 devices then SECDED
+		* if dual channel and x4 then S4ECD4ED
+		*/
+		if (drc_ddim) {
+			if (drc_chan && mem_dev) {
+				edac_mode = EDAC_S4ECD4ED;
+				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+			} else {
+				edac_mode = EDAC_SECDED;
+				mci->edac_cap |= EDAC_FLAG_SECDED;
+			}
+		} else
+			edac_mode = EDAC_NONE;
+
 		for (j = 0; j < drc_chan + 1; j++) {
 			dimm = csrow->channels[j].dimm;
 
@@ -399,21 +415,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
 			dimm->mtype = MEM_RDDR;	/* only one type supported */
 			dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-			/*
-			* if single channel or x8 devices then SECDED
-			* if dual channel and x4 then S4ECD4ED
-			*/
-			if (drc_ddim) {
-				if (drc_chan && mem_dev) {
-					dimm->edac_mode = EDAC_S4ECD4ED;
-					mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-				} else {
-					dimm->edac_mode = EDAC_SECDED;
-					mci->edac_cap |= EDAC_FLAG_SECDED;
-				}
-			} else
-				dimm->edac_mode = EDAC_NONE;
+			dimm->edac_mode = edac_mode;
 		}
 	}
 }
Signature · 1 line
1.7.8
#51 lore raw

PATCH v13 19/25 i82975x_edac: Test nr_pages earlier to save a few CPU cycles

In reply to Mauro Carvalho Chehab

Avoid test nr_pages twice, and initializing some data that won't be used.

Cleanup patch only.

---
 drivers/edac/i82975x_edac.c |    9 +++------
 1 files changed, 3 insertions(+), 6 deletions(-)
drivers/edac/i82975x_edac.c +3 -6
index ae2a857..df99606 100644
@@ -410,6 +410,9 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 			cumul_size);
 
 		nr_pages = cumul_size - last_cumul_size;
+		if (!nr_pages)
+			continue;
+
 		/*
 		 * Initialise dram labels
 		 * index values:
@@ -420,9 +423,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 		for (chan = 0; chan < csrow->nr_channels; chan++) {
 			dimm = mci->csrows[index].channels[chan].dimm;
 
-			if (!nr_pages)
-				continue;
-
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 			strncpy(csrow->channels[chan].dimm->label,
 					labels[(index >> 1) + (chan * 2)],
@@ -433,9 +433,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 			dimm->edac_mode = EDAC_SECDED; /* only supported */
 		}
 
-		if (!nr_pages)
-			continue;	/* not populated */
-
 		csrow->first_page = last_cumul_size;
 		csrow->last_page = cumul_size - 1;
 		last_cumul_size = cumul_size;
Signature · 1 line
1.7.8
#52 lore raw

PATCH v13 20/25 i5100_edac: Fix a warning when compiled with 32 bits

In reply to Mauro Carvalho Chehab

drivers/edac/i5100_edac.c: In function ‘i5100_init_csrows’:
drivers/edac/i5100_edac.c:862:3: warning: format ‘%zd’ expects argument of type ‘signed size_t’, but argument 5 has type ‘long unsigned int’ [-Wformat]

---
 drivers/edac/i5100_edac.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/edac/i5100_edac.c +2 -2
index 11aba5e..dd260c8 100644
@@ -859,8 +859,8 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
 				i5100_rank_to_slot(mci, chan, rank));
 		}
 
-		debugf2("dimm channel %d, rank %d, size %zd\n",
-			chan, rank, PAGES_TO_MiB(npages));
+		debugf2("dimm channel %d, rank %d, size %ld\n",
+			chan, rank, (long)PAGES_TO_MiB(npages));
 	}
 }
 
Signature · 1 line
1.7.8
#53 lore raw

PATCH v13 21/25 i7300_edac: Get rid of some wrongly-solved rebase conflict

In reply to Mauro Carvalho Chehab

Drivers should not increment tot_dimms manually. This code were there for an older approach that got removed. After one of the several rebases that this code suffered until the final version, the conflict was wrongly merged, and this code returned.

---
 drivers/edac/i7300_edac.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)
drivers/edac/i7300_edac.c +0 -3
index 57f264d..f9a4fa4 100644
@@ -803,9 +803,6 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
 				mtr = decode_mtr(pvt, slot, ch, branch,
 						 dinfo, dimm);
 
-				mci->tot_dimms++;
-				dimm++;
-
 				/* if no DIMMS on this row, continue */
 				if (!MTR_DIMMS_PRESENT(mtr))
 					continue;
Signature · 1 line
1.7.8
#54 lore raw

PATCH v13 22/25 edac: Only expose csrows/channels on legacy API if they're populated

In reply to Mauro Carvalho Chehab

This patch actually fixes a bug with the legacy API, where, at the same csrow, some channels may have different DIMMs. This can happen on FB-DIMM/RAMBUS and modern Intel controllers.

This is the case, for example, of Nehalem machines:

$ ./edac-ctl --layout
       +-----------------------------------+
       |                mc0                |
       | channel0  | channel1  | channel2  |
-------+-----------------------------------+
slot2: |     0 MB  |     0 MB  |     0 MB  |
slot1: |  1024 MB  |     0 MB  |     0 MB  |
slot0: |  1024 MB  |  1024 MB  |  1024 MB  |
-------+-----------------------------------+

Before this patch, non-filled memories were shown. Now, only what's filled is there:

grep . /sys/devices/system/edac/mc/mc0/csrow*/ch?* /sys/devices/system/edac/mc/mc0/csrow0/ch0_ce_count:0 /sys/devices/system/edac/mc/mc0/csrow0/ch0_dimm_label:CPU#0Channel#0_DIMM#0 /sys/devices/system/edac/mc/mc0/csrow0/ch1_ce_count:0 /sys/devices/system/edac/mc/mc0/csrow0/ch1_dimm_label:CPU#0Channel#0_DIMM#1 /sys/devices/system/edac/mc/mc0/csrow1/ch0_ce_count:0 /sys/devices/system/edac/mc/mc0/csrow1/ch0_dimm_label:CPU#0Channel#1_DIMM#0 /sys/devices/system/edac/mc/mc0/csrow2/ch0_ce_count:0 /sys/devices/system/edac/mc/mc0/csrow2/ch0_dimm_label:CPU#0Channel#2_DIMM#0

Thanks-to: Aristeu Rozanski Filho <[email protected]>

---
 drivers/edac/edac_mc_sysfs.c |   24 ++++++++++++++++++++++++
 1 files changed, 24 insertions(+), 0 deletions(-)
drivers/edac/edac_mc_sysfs.c +24 -0
index 38fccf2..354daec 100644
@@ -347,6 +347,16 @@ static struct device_attribute *dynamic_csrow_ce_count_attr[] = {
 	&dev_attr_legacy_ch5_ce_count.attr
 };
 
+static inline int nr_pages_per_csrow(struct csrow_info *csrow)
+{
+	int chan, nr_pages = 0;
+
+	for (chan = 0; chan < csrow->nr_channels; chan++)
+		nr_pages += csrow->channels[chan].dimm->nr_pages;
+
+	return nr_pages;
+}
+
 /* Create a CSROW object under specifed edac_mc_device */
 static int edac_create_csrow_object(struct mem_ctl_info *mci,
 				    struct csrow_info *csrow, int index)
@@ -371,6 +381,9 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
 		return err;
 
 	for (chan = 0; chan < csrow->nr_channels; chan++) {
+		/* Only expose populated DIMMs */
+		if (!csrow->channels[chan].dimm->nr_pages)
+			continue;
 		err = device_create_file(&csrow->dev,
 					 dynamic_csrow_dimm_attr[chan]);
 		if (err < 0)
@@ -405,6 +418,9 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
 	struct csrow_info *csrow;
 
 	for (i = 0; i < mci->nr_csrows; i++) {
+		csrow = &mci->csrows[i];
+		if (!nr_pages_per_csrow(csrow))
+			continue;
 		err = edac_create_csrow_object(mci, &mci->csrows[i], i);
 		if (err < 0)
 			goto error;
@@ -414,7 +430,11 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
 error:
 	for (--i; i >= 0; i--) {
 		csrow = &mci->csrows[i];
+		if (!nr_pages_per_csrow(csrow))
+			continue;
 		for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
+			if (!csrow->channels[chan].dimm->nr_pages)
+				continue;
 			device_remove_file(&csrow->dev,
 						dynamic_csrow_dimm_attr[chan]);
 			device_remove_file(&csrow->dev,
@@ -433,7 +453,11 @@ static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
 
 	for (i = mci->nr_csrows - 1; i >= 0; i--) {
 		csrow = &mci->csrows[i];
+		if (!nr_pages_per_csrow(csrow))
+			continue;
 		for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
+			if (!csrow->channels[chan].dimm->nr_pages)
+				continue;
 			debugf1("Removing csrow %d channel %d sysfs nodes\n",
 				i, chan);
 			device_remove_file(&csrow->dev,
Signature · 1 line
1.7.8
#55 lore raw

PATCH v13 23/25 edac: Fix a typo at edac_mc_sysfs

In reply to Mauro Carvalho Chehab

No functional changes. Just a typo fix on a comment.

---
 drivers/edac/edac_mc_sysfs.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/edac/edac_mc_sysfs.c +1 -1
index 354daec..022f50a 100644
@@ -7,7 +7,7 @@
  *
  * Written Doug Thompson <[email protected]> www.softwarebitmaker.com
  *
- * (c) 2012 - Mauro Carvalho Chehab <[email protected]
+ * (c) 2012 - Mauro Carvalho Chehab <[email protected]>
  *	The entire API were re-written, and ported to use struct device
  *
  */
Signature · 1 line
1.7.8
#56 lore raw

PATCH v13 24/25 edac: change the mem allocation scheme to make Documentation/kobject.txt happy

In reply to Mauro Carvalho Chehab

Kernel kobjects have rigid rules: each container object should be dynamically allocated, and can't be allocated into a single kmalloc.

EDAC never obeyed this rule: it has a single malloc function that allocates all needed data into a single kzalloc.

As this is not accepted anymore, change the allocation schema of the EDAC *_info structs to enforce this Kernel standard.

Cc Aristeu Rozanski <[email protected]>
Cc Doug Thompson <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Mark Gross <[email protected]>
Cc Jason Uhlenkott <[email protected]>
Cc Tim Small <[email protected]>
Cc Ranganathan Desikan <[email protected]>
Cc "Arvind R." <[email protected]>
Cc Olof Johansson <[email protected]>
Cc Egor Martovetsky <[email protected]>
Cc Chris Metcalf <[email protected]>
Cc Michal Marek <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Joe Perches <[email protected]>
Cc Dmitry Eremin-Solenikov <[email protected]>
Cc Benjamin Herrenschmidt <[email protected]>
Cc Hitoshi Mitake <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Shaohui Xie <[email protected]>
---
 drivers/edac/amd64_edac.c      |    8 +-
 drivers/edac/amd76x_edac.c     |    8 +-
 drivers/edac/cell_edac.c       |    8 +-
 drivers/edac/cpc925_edac.c     |    8 +-
 drivers/edac/e752x_edac.c      |    4 +-
 drivers/edac/e7xxx_edac.c      |    4 +-
 drivers/edac/edac_mc.c         |  105 +++++++++++++++++++++------------
 drivers/edac/edac_mc_sysfs.c   |  126 +++++++++++++++++++++++-----------------
 drivers/edac/i3000_edac.c      |    6 +-
 drivers/edac/i3200_edac.c      |    4 +-
 drivers/edac/i5400_edac.c      |    6 +-
 drivers/edac/i82443bxgx_edac.c |    4 +-
 drivers/edac/i82860_edac.c     |    6 +-
 drivers/edac/i82875p_edac.c    |    6 +-
 drivers/edac/i82975x_edac.c    |   10 ++--
 drivers/edac/mpc85xx_edac.c    |    6 +-
 drivers/edac/mv64x60_edac.c    |    4 +-
 drivers/edac/pasemi_edac.c     |    8 +-
 drivers/edac/r82600_edac.c     |    4 +-
 drivers/edac/tile_edac.c       |    4 +-
 drivers/edac/x38_edac.c        |    4 +-
 include/linux/edac.h           |   31 ++++++----
 22 files changed, 216 insertions(+), 158 deletions(-)
drivers/edac/amd64_edac.c +4 -4
index 321b838..ee7c060 100644
@@ -2197,7 +2197,7 @@ static int init_csrows(struct mem_ctl_info *mci)
 		!!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
 
 	for_each_chip_select(i, 0, pvt) {
-		csrow = &mci->csrows[i];
+		csrow = mci->csrows[i];
 
 		if (!csrow_enabled(i, 0, pvt)) {
 			debugf1("----CSROW %d EMPTY for node %d\n", i,
@@ -2228,9 +2228,9 @@ static int init_csrows(struct mem_ctl_info *mci)
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < pvt->channel_count; j++) {
-			csrow->channels[j].dimm->mtype = mtype;
-			csrow->channels[j].dimm->edac_mode = edac_mode;
-			csrow->channels[j].dimm->nr_pages = nr_pages;
+			csrow->channels[j]->dimm->mtype = mtype;
+			csrow->channels[j]->dimm->edac_mode = edac_mode;
+			csrow->channels[j]->dimm->nr_pages = nr_pages;
 		}
 	}
 
drivers/edac/amd76x_edac.c +4 -4
index 9a34c5f..99d8d56 100644
@@ -146,7 +146,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 		if (handle_errors) {
 			row = (info->ecc_mode_status >> 4) & 0xf;
 			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-					     mci->csrows[row].first_page, 0, 0,
+					     mci->csrows[row]->first_page, 0, 0,
 					     row, 0, -1,
 					     mci->ctl_name, "", NULL);
 		}
@@ -161,7 +161,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 		if (handle_errors) {
 			row = info->ecc_mode_status & 0xf;
 			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-					     mci->csrows[row].first_page, 0, 0,
+					     mci->csrows[row]->first_page, 0, 0,
 					     row, 0, -1,
 					     mci->ctl_name, "", NULL);
 		}
@@ -194,8 +194,8 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	int index;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_dword(pdev,
drivers/edac/cell_edac.c +4 -4
index 9e53917..ee61f0d 100644
@@ -33,7 +33,7 @@ struct cell_edac_priv
 static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 {
 	struct cell_edac_priv		*priv = mci->pvt_info;
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	unsigned long			address, pfn, offset, syndrome;
 
 	dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
@@ -56,7 +56,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
 {
 	struct cell_edac_priv		*priv = mci->pvt_info;
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	unsigned long			address, pfn, offset;
 
 	dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
@@ -126,7 +126,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
 
 static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 {
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	struct dimm_info		*dimm;
 	struct cell_edac_priv		*priv = mci->pvt_info;
 	struct device_node		*np;
@@ -150,7 +150,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 		csrow->last_page = csrow->first_page + nr_pages - 1;
 
 		for (j = 0; j < csrow->nr_channels; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 			dimm->mtype = MEM_XDR;
 			dimm->edac_mode = EDAC_SECDED;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
drivers/edac/cpc925_edac.c +4 -4
index 1b26ced..0203089 100644
@@ -348,7 +348,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		if (bba == 0)
 			continue; /* not populated */
 
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		row_size = bba * (1UL << 28);	/* 256M */
 		csrow->first_page = last_nr_pages;
@@ -380,7 +380,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		break;
 		}
 		for (j = 0; j < csrow->nr_channels; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 			dimm->mtype = MEM_RDDR;
 			dimm->edac_mode = EDAC_SECDED;
@@ -463,7 +463,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 	*csrow = rank;
 
 #ifdef CONFIG_EDAC_DEBUG
-	if (mci->csrows[rank].first_page == 0) {
+	if (mci->csrows[rank]->first_page == 0) {
 		cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a "
 			"non-populated csrow, broken hardware?\n");
 		return;
@@ -471,7 +471,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 #endif
 
 	/* Revert csrow number */
-	pa = mci->csrows[rank].first_page << PAGE_SHIFT;
+	pa = mci->csrows[rank]->first_page << PAGE_SHIFT;
 
 	/* Revert column address */
 	col += bcnt;
drivers/edac/e752x_edac.c +2 -2
index 84bb8f6..35f282e 100644
@@ -1096,7 +1096,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 2)) & 0x3;
-		csrow = &mci->csrows[remap_csrow_index(mci, index)];
+		csrow = mci->csrows[remap_csrow_index(mci, index)];
 
 		mem_dev = (mem_dev == 2);
 		pci_read_config_byte(pdev, E752X_DRB + index, &value);
@@ -1127,7 +1127,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 		} else
 			edac_mode = EDAC_NONE;
 		for (i = 0; i < csrow->nr_channels; i++) {
-			struct dimm_info *dimm = csrow->channels[i].dimm;
+			struct dimm_info *dimm = csrow->channels[i]->dimm;
 
 			debugf3("Initializing rank at (%i,%i)\n", index, i);
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
drivers/edac/e7xxx_edac.c +2 -2
index e930dd1..93695e4 100644
@@ -378,7 +378,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	for (index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 3)) & 0x1;
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		pci_read_config_byte(pdev, E7XXX_DRB + index, &value);
 		/* convert a 64 or 32 MiB DRB to a page size. */
@@ -409,7 +409,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < drc_chan + 1; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / (drc_chan + 1);
 			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
drivers/edac/edac_mc.c +68 -37

220 lines not on this page · raw message

drivers/edac/edac_mc_sysfs.c +72 -54

319 lines not on this page · raw message

drivers/edac/i3000_edac.c +3 -3
index 2ee50ab..15df2bc 100644
@@ -236,7 +236,7 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
 	int row, multi_chan, channel;
 	unsigned long pfn, offset;
 
-	multi_chan = mci->csrows[0].nr_channels - 1;
+	multi_chan = mci->csrows[0]->nr_channels - 1;
 
 	if (!(info->errsts & I3000_ERRSTS_BITS))
 		return 0;
@@ -393,7 +393,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
 		u8 value;
 		u32 cumul_size;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		value = drb[i];
 		cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
@@ -410,7 +410,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 		last_cumul_size = cumul_size;
 
 		for (j = 0; j < nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_channels;
 			dimm->grain = I3000_DEAP_GRAIN;
drivers/edac/i3200_edac.c +2 -2
index 798fb65..acb5d39 100644
@@ -379,7 +379,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
 		unsigned long nr_pages;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		nr_pages = drb_to_nr_pages(drbs, stacked,
 			i / I3200_RANKS_PER_CHANNEL,
@@ -389,7 +389,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 			continue;
 
 		for (j = 0; j < nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_channels;
 			dimm->grain = nr_pages << PAGE_SHIFT;
drivers/edac/i5400_edac.c +3 -3
index a16a2b5..74b64c6 100644
@@ -1203,8 +1203,8 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 
 			size_mb =  pvt->dimm_info[slot][channel].megabytes;
 
-			debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n",
-				__func__, dimm - mci->dimms,
+			debugf2("%s: dimm (branch %d channel %d slot %d): %d.%03d GB\n",
+				__func__,
 				channel / 2, channel % 2, slot,
 				size_mb / 1000, size_mb % 1000);
 
@@ -1227,7 +1227,7 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 	 * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+.
 	 */
 	if (ndimms == 1)
-		mci->dimms[0].edac_mode = EDAC_SECDED;
+		mci->dimms[0]->edac_mode = EDAC_SECDED;
 
 	return (ndimms == 0);
 }
drivers/edac/i82443bxgx_edac.c +2 -2
index 4c572545..877ba54 100644
@@ -197,8 +197,8 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
 	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
 	row_high_limit_last = 0;
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
 		debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
drivers/edac/i82860_edac.c +3 -3
index 16a54bb..f493758 100644
@@ -116,7 +116,7 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
 
 	info->eap >>= PAGE_SHIFT;
 	row = edac_mc_find_csrow_by_page(mci, info->eap);
-	dimm = mci->csrows[row].channels[0].dimm;
+	dimm = mci->csrows[row]->channels[0]->dimm;
 
 	if (info->errsts & 0x0002)
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
@@ -161,8 +161,8 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 	 * in all eight rows.
 	 */
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
 		cumul_size = (value & I82860_GBA_MASK) <<
drivers/edac/i82875p_edac.c +3 -3
index 9691449..a42a5bd 100644
@@ -227,7 +227,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 {
 	int row, multi_chan;
 
-	multi_chan = mci->csrows[0].nr_channels - 1;
+	multi_chan = mci->csrows[0]->nr_channels - 1;
 
 	if (!(info->errsts & 0x0081))
 		return 0;
@@ -367,7 +367,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
 	 */
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		value = readb(ovrfl_window + I82875P_DRB + index);
 		cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
@@ -382,7 +382,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
 		last_cumul_size = cumul_size;
 
 		for (j = 0; j < nr_chans; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_chans;
 			dimm->grain = 1 << 12;	/* I82875P_EAP has 4KiB reolution */
drivers/edac/i82975x_edac.c +5 -5
index df99606..717f208 100644
@@ -308,10 +308,10 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
 			(info->xeap & 1) ? 1 : 0, info->eap, (unsigned int) page);
 		return 0;
 	}
-	chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1;
+	chan = (mci->csrows[row]->nr_channels == 1) ? 0 : info->eap & 1;
 	offst = info->eap
 			& ((1 << PAGE_SHIFT) -
-			   (1 << mci->csrows[row].channels[chan].dimm->grain));
+			   (1 << mci->csrows[row]->channels[chan]->dimm->grain));
 
 	if (info->errsts & 0x0002)
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
@@ -394,7 +394,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 	 */
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		value = readb(mch_window + I82975X_DRB + index +
 					((index >= 4) ? 0x80 : 0));
@@ -421,10 +421,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 		 */
 		dtype = i82975x_dram_type(mch_window, index);
 		for (chan = 0; chan < csrow->nr_channels; chan++) {
-			dimm = mci->csrows[index].channels[chan].dimm;
+			dimm = mci->csrows[index]->channels[chan]->dimm;
 
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
-			strncpy(csrow->channels[chan].dimm->label,
+			strncpy(csrow->channels[chan]->dimm->label,
 					labels[(index >> 1) + (chan * 2)],
 					EDAC_MC_LABEL_LEN);
 			dimm->grain = 1 << 7;	/* 128Byte cache-line resolution */
drivers/edac/mpc85xx_edac.c +3 -3
index c67cca1..42e209c 100644
@@ -825,7 +825,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
 	pfn = err_addr >> PAGE_SHIFT;
 
 	for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
-		csrow = &mci->csrows[row_index];
+		csrow = mci->csrows[row_index];
 		if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page))
 			break;
 	}
@@ -945,8 +945,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 		u32 start;
 		u32 end;
 
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
 				  (index * MPC85XX_MC_CS_BNDS_OFS));
drivers/edac/mv64x60_edac.c +2 -2
index ef0e710..87139ca 100644
@@ -670,8 +670,8 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 
 	ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
 
-	csrow = &mci->csrows[0];
-	dimm = csrow->channels[0].dimm;
+	csrow = mci->csrows[0];
+	dimm = csrow->channels[0]->dimm;
 
 	dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
 	dimm->grain = 8;
drivers/edac/pasemi_edac.c +4 -4
index 47542e7..634b919 100644
@@ -111,14 +111,14 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 	if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
 		      MCDEBUG_ERRSTA_RFL_STATUS)) {
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-				     mci->csrows[cs].first_page, 0, 0,
+				     mci->csrows[cs]->first_page, 0, 0,
 				     cs, 0, -1, mci->ctl_name, "", NULL);
 	}
 
 	/* correctable/single-bit errors */
 	if (errsta & MCDEBUG_ERRSTA_SBE_STATUS)
 		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-				     mci->csrows[cs].first_page, 0, 0,
+				     mci->csrows[cs]->first_page, 0, 0,
 				     cs, 0, -1, mci->ctl_name, "", NULL);
 }
 
@@ -141,8 +141,8 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
 	int index;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_dword(pdev,
 				      MCDRAM_RANKCFG + (index * 12),
drivers/edac/r82600_edac.c +2 -2
index 10464c5..6a7a2ce 100644
@@ -230,8 +230,8 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	row_high_limit_last = 0;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
drivers/edac/tile_edac.c +2 -2
index 32cb2c7..4aecb06 100644
@@ -84,10 +84,10 @@ static void tile_edac_check(struct mem_ctl_info *mci)
  */
 static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 {
-	struct csrow_info	*csrow = &mci->csrows[0];
+	struct csrow_info	*csrow = mci->csrows[0];
 	struct tile_edac_priv	*priv = mci->pvt_info;
 	struct mshim_mem_info	mem_info;
-	struct dimm_info *dimm = csrow->channels[0].dimm;
+	struct dimm_info *dimm = csrow->channels[0]->dimm;
 
 	if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
 		sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
drivers/edac/x38_edac.c +2 -2
index dde47e9..c5e54ef 100644
@@ -378,7 +378,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
 		unsigned long nr_pages;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		nr_pages = drb_to_nr_pages(drbs, stacked,
 			i / X38_RANKS_PER_CHANNEL,
@@ -388,7 +388,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 			continue;
 
 		for (j = 0; j < x38_channel_num; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / x38_channel_num;
 			dimm->grain = nr_pages << PAGE_SHIFT;
include/linux/edac.h +20 -11
index 22c3fca..bec5bff 100644
@@ -409,17 +409,28 @@ struct edac_mc_layer {
  * during the memory allocation routine, with would point to the developer
  * that he's doing something wrong.
  */
-#define GET_POS(layers, var, nlayers, lay0, lay1, lay2) ({		\
-	typeof(var) __p;						\
+
+#define GET_OFFSET(layers, nlayers, lay0, lay1, lay2) ({		\
+	int __i;								\
 	if ((nlayers) == 1)						\
-		__p = &var[lay0];					\
+		__i = lay0;						\
 	else if ((nlayers) == 2)					\
-		__p = &var[(lay1) + ((layers[1]).size * (lay0))];	\
+		__i = (lay1) + ((layers[1]).size * (lay0));		\
 	else if ((nlayers) == 3)					\
-		__p = &var[(lay2) + ((layers[2]).size * ((lay1) +	\
-			    ((layers[1]).size * (lay0))))];		\
+		__i = (lay2) + ((layers[2]).size * ((lay1) +		\
+			    ((layers[1]).size * (lay0))));		\
 	else								\
+		__i = -EINVAL;						\
+	__i;								\
+})
+
+#define GET_POS(layers, var, nlayers, lay0, lay1, lay2) ({		\
+	typeof(*var) __p;						\
+	int ___i = GET_OFFSET(layers, nlayers, lay0, lay1, lay2);	\
+	if (___i < 0)							\
 		__p = NULL;						\
+	else								\
+		__p = (var)[___i];					\
 	__p;								\
 })
 
@@ -459,8 +470,6 @@ struct dimm_info {
  *	  patches in this series will fix this issue.
  */
 struct rank_info {
-	struct device dev;
-
 	int chan_idx;
 	struct csrow_info *csrow;
 	struct dimm_info *dimm;
@@ -486,7 +495,7 @@ struct csrow_info {
 
 	/* channel information for this csrow */
 	u32 nr_channels;
-	struct rank_info *channels;
+	struct rank_info **channels;
 };
 
 /*
@@ -550,7 +559,7 @@ struct mem_ctl_info {
 	unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
 					   unsigned long page);
 	int mc_idx;
-	struct csrow_info *csrows;
+	struct csrow_info **csrows;
 	unsigned nr_csrows, num_cschannel;
 
 	/*
@@ -570,7 +579,7 @@ struct mem_ctl_info {
 	 * DIMM info. Will eventually remove the entire csrows_info some day
 	 */
 	unsigned tot_dimms;
-	struct dimm_info *dimms;
+	struct dimm_info **dimms;
 
 	/*
 	 * FIXME - what about controllers on other busses? - IDs must be
Signature · 1 line
1.7.8
#57 lore raw

Re: [EDAC ABI v13 24/25] edac: change the mem allocation scheme to make Documentation/kobject.txt happy

Quoted 8 lines · Mauro Carvalho Chehab

Kernel kobjects have rigid rules: each container object should be dynamically allocated, and can't be allocated into a single kmalloc.

EDAC never obeyed this rule: it has a single malloc function that allocates all needed data into a single kzalloc.

As this is not accepted anymore, change the allocation schema of the EDAC *_info structs to enforce this Kernel standard.

[]

drivers/edac/amd64_edac.c

Quoted 1 line
drivers/edac/amd64_edac.c +0 -0

[]

drivers/edac/amd64_edac.c static int init_csrows(struct mem_ctl_info *mci) · line 2233

Quoted 10 lines
drivers/edac/amd64_edac.c +3 -3
@@ -2228,9 +2228,9 @@ static int init_csrows(struct mem_ctl_info *mci)
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < pvt->channel_count; j++) {
-			csrow->channels[j].dimm->mtype = mtype;
-			csrow->channels[j].dimm->edac_mode = edac_mode;
-			csrow->channels[j].dimm->nr_pages = nr_pages;
+			csrow->channels[j]->dimm->mtype = mtype;
+			csrow->channels[j]->dimm->edac_mode = edac_mode;
+			csrow->channels[j]->dimm->nr_pages = nr_pages;

It might be better to use an automatic for

	typeof foo dimm = csrow->channels[j]->dimm;
	dimm->mtype = mtype;
	etc...

[]

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 291

Quoted 8 lines
drivers/edac/amd64_edac.c +2 -1
@@ -293,39 +286,56 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	mci->mem_is_per_rank = per_rank;
 
 	/*
-	 * Fills the csrow struct
+	 * Alocate and fill the csrow/channels structs
 	 */
+	mci->csrows = kzalloc(sizeof(*mci->csrows) * tot_csrows, GFP_KERNEL);

kcalloc

[]

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 293

Quoted 2 lines
drivers/edac/amd64_edac.c +2 -0
+		csr->channels = kzalloc(sizeof(*csr->channels) * tot_cschannels,
+					GFP_KERNEL);

here too

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 408

Quoted 9 lines
drivers/edac/amd64_edac.c +4 -0
@@ -391,7 +401,31 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 
 	trace_hw_event_init("edac", (unsigned)edac_index);
 
+	debugf1("EDAC MCI allocated\n");
 	return mci;
+
+error:
+	debugf1("Failed to allocate one or more EDAC MCI structs\n");

Generally, it's not necessary to have specific "OOM" messages as allocations without GFP_NOWARN do dump_stack()s

#58 lore raw

Re: [EDAC ABI v13 24/25] edac: change the mem allocation scheme to make Documentation/kobject.txt happy

Hi Joe,

Em 17-04-2012 18:17, Joe Perches escreveu:

Quoted 45 lines · Mauro Carvalho Chehab
Quoted 8 lines

Kernel kobjects have rigid rules: each container object should be dynamically allocated, and can't be allocated into a single kmalloc.

EDAC never obeyed this rule: it has a single malloc function that allocates all needed data into a single kzalloc.

As this is not accepted anymore, change the allocation schema of the EDAC *_info structs to enforce this Kernel standard.

[]

drivers/edac/amd64_edac.c

Quoted 1 line
drivers/edac/amd64_edac.c +0 -0

[]

drivers/edac/amd64_edac.c static int init_csrows(struct mem_ctl_info *mci) · line 2233

Quoted 10 lines
drivers/edac/amd64_edac.c +3 -3
@@ -2228,9 +2228,9 @@ static int init_csrows(struct mem_ctl_info *mci)
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < pvt->channel_count; j++) {
-			csrow->channels[j].dimm->mtype = mtype;
-			csrow->channels[j].dimm->edac_mode = edac_mode;
-			csrow->channels[j].dimm->nr_pages = nr_pages;
+			csrow->channels[j]->dimm->mtype = mtype;
+			csrow->channels[j]->dimm->edac_mode = edac_mode;
+			csrow->channels[j]->dimm->nr_pages = nr_pages;

It might be better to use an automatic for

	typeof foo dimm = csrow->channels[j]->dimm;
	dimm->mtype = mtype;
	etc...

[]

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 291

Quoted 8 lines
drivers/edac/amd64_edac.c +2 -1
@@ -293,39 +286,56 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	mci->mem_is_per_rank = per_rank;
 
 	/*
-	 * Fills the csrow struct
+	 * Alocate and fill the csrow/channels structs
 	 */
+	mci->csrows = kzalloc(sizeof(*mci->csrows) * tot_csrows, GFP_KERNEL);

kcalloc

[]

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 293

Quoted 2 lines
drivers/edac/amd64_edac.c +2 -0
+		csr->channels = kzalloc(sizeof(*csr->channels) * tot_cschannels,
+					GFP_KERNEL);

here too

Quoted 6 lines

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 405

Quoted 6 lines
drivers/edac/amd64_edac.c +1 -0
@@ -391,7 +401,31 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 
 	trace_hw_event_init("edac", (unsigned)edac_index);
 
+	debugf1("EDAC MCI allocated\n");
 	return mci;

Agreed with all above. Fixed.

Quoted 6 lines

drivers/edac/amd64_edac.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 408

Quoted 3 lines
drivers/edac/amd64_edac.c +3 -0
+
+error:
+	debugf1("Failed to allocate one or more EDAC MCI structs\n");

Generally, it's not necessary to have specific "OOM" messages as allocations without GFP_NOWARN do dump_stack()s

There is one error condition on the error path that might potentially happen that it is not related directly to the kalloc stuff: if, there GET_POS() tries to access something out of the allocated range, it bails out. I added this debug printk due to that, while testing the allocation changes. The check could potentially be using a BUG_ON() call, but, as failing here, the edac drivers will not load, I opted to not use BUG_ON, and, instead use the standard error path for it.

That's said, it seems better to remove this debugf1 from this place, and add some printk(KERN_ERR, ...) at this specific condition.

Quoted 6 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-edac" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

I'm folding the enclosed patch on this one, in order to address the comments on your review.

Thanks!
Mauro

-

drivers/edac/amd64_edac.c +5 -3
index 16510a3..08af66c 100644
@@ -2180,6 +2180,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 static int init_csrows(struct mem_ctl_info *mci)
 {
 	struct csrow_info *csrow;
+	struct dimm_info *dimm;
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u64 base, mask;
 	u32 val;
@@ -2228,9 +2229,10 @@ static int init_csrows(struct mem_ctl_info *mci)
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < pvt->channel_count; j++) {
-			csrow->channels[j]->dimm->mtype = mtype;
-			csrow->channels[j]->dimm->edac_mode = edac_mode;
-			csrow->channels[j]->dimm->nr_pages = nr_pages;
+			dimm = csrow->channels[j]->dimm;
+			dimm->mtype = mtype;
+			dimm->edac_mode = edac_mode;
+			dimm->nr_pages = nr_pages;
 		}
 	}
 
drivers/edac/edac_mc.c +6 -6
index fe57684..16f2d3b 100644
@@ -296,7 +296,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	/*
 	 * Alocate and fill the csrow/channels structs
 	 */
-	mci->csrows = kzalloc(sizeof(*mci->csrows) * tot_csrows, GFP_KERNEL);
+	mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL);
 	if (!mci->csrows)
 		goto error;
 	for (row = 0; row < tot_csrows; row++) {
@@ -307,7 +307,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 		csr->csrow_idx = row;
 		csr->mci = mci;
 		csr->nr_channels = tot_cschannels;
-		csr->channels = kzalloc(sizeof(*csr->channels) * tot_cschannels,
+		csr->channels = kcalloc(sizeof(*csr->channels), tot_cschannels,
 					GFP_KERNEL);
 
 		for (chn = 0; chn < tot_cschannels; chn++) {
@@ -323,7 +323,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	/*
 	 * Allocate and fill the dimm structs
 	 */
-	mci->dimms  = kzalloc(sizeof(*mci->dimms) * tot_dimms, GFP_KERNEL);
+	mci->dimms  = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL);
 	if (!mci->dimms)
 		goto error;
 
@@ -335,8 +335,10 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	for (i = 0; i < tot_dimms; i++) {
 		chan = mci->csrows[row]->channels[chn];
 		off = GET_OFFSET(lay, n_layers, pos[0], pos[1], pos[2]);
-		if (off < 0 || off >= tot_dimms)
+		if (off < 0 || off >= tot_dimms) {
+			edac_mc_printk(mci, KERN_ERR, "EDAC core bug: GET_OFFSET is trying to do an illegal data access\n");
 			goto error;
+		}
 
 		dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL);
 		mci->dimms[off] = dimm;
@@ -409,11 +411,9 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 
 	trace_hw_event_init("edac", (unsigned)edac_index);
 
-	debugf1("EDAC MCI allocated\n");
 	return mci;
 
 error:
-	debugf1("Failed to allocate one or more EDAC MCI structs\n");
 	if (mci->dimms) {
 		for (i = 0; i < tot_dimms; i++)
 			kfree(mci->dimms[i]);
#59 lore raw

Re: [EDAC ABI v13 24/25] edac: change the mem allocation scheme to make Documentation/kobject.txt happy

drivers/edac/edac_mc.c

Quoted 1 line · Mauro Carvalho Chehab
drivers/edac/edac_mc.c +0 -0

[]

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 299

Quoted 6 lines
drivers/edac/edac_mc.c +1 -1
@@ -296,7 +296,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	/*
 	 * Alocate and fill the csrow/channels structs
 	 */
-	mci->csrows = kzalloc(sizeof(*mci->csrows) * tot_csrows, GFP_KERNEL);
+	mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL);

trivia: the first 2 args to kcalloc should be swapped.

static inline void *kcalloc(size_t n, size_t size, gfp_t flags)

	kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL);

[]

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 310

Quoted 6 lines
drivers/edac/edac_mc.c +1 -1
@@ -307,7 +307,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 		csr->csrow_idx = row;
 		csr->mci = mci;
 		csr->nr_channels = tot_cschannels;
-		csr->channels = kzalloc(sizeof(*csr->channels) * tot_cschannels,
+		csr->channels = kcalloc(sizeof(*csr->channels), tot_cschannels,

and here.

[]

drivers/edac/edac_mc.c struct mem_ctl_info *edac_mc_alloc(unsigned edac_index, · line 326

Quoted 6 lines
drivers/edac/edac_mc.c +1 -1
@@ -323,7 +323,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
 	/*
 	 * Allocate and fill the dimm structs
 	 */
-	mci->dimms  = kzalloc(sizeof(*mci->dimms) * tot_dimms, GFP_KERNEL);
+	mci->dimms  = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL);

and here too.

#60 lore raw

PATCH 1/1 edac: change the mem allocation scheme to make Documentation/kobject.txt happy

In reply to Joe Perches

Kernel kobjects have rigid rules: each container object should be dynamically allocated, and can't be allocated into a single kmalloc.

EDAC never obeyed this rule: it has a single malloc function that allocates all needed data into a single kzalloc.

As this is not accepted anymore, change the allocation schema of the EDAC *_info structs to enforce this Kernel standard.

Cc Aristeu Rozanski <[email protected]>
Cc Doug Thompson <[email protected]>
Cc Greg K H <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Mark Gross <[email protected]>
Cc Tim Small <[email protected]>
Cc Ranganathan Desikan <[email protected]>
Cc "Arvind R." <[email protected]>
Cc Olof Johansson <[email protected]>
Cc Egor Martovetsky <[email protected]>
Cc Chris Metcalf <[email protected]>
Cc Michal Marek <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Dmitry Eremin-Solenikov <[email protected]>
Cc Benjamin Herrenschmidt <[email protected]>
Cc Hitoshi Mitake <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Shaohui Xie <[email protected]>
---
 drivers/edac/amd64_edac.c      |   10 ++-
 drivers/edac/amd76x_edac.c     |    8 +-
 drivers/edac/cell_edac.c       |    8 +-
 drivers/edac/cpc925_edac.c     |    8 +-
 drivers/edac/e752x_edac.c      |    4 +-
 drivers/edac/e7xxx_edac.c      |    4 +-
 drivers/edac/edac_mc.c         |  105 +++++++++++++++++++++------------
 drivers/edac/edac_mc_sysfs.c   |  126 +++++++++++++++++++++++-----------------
 drivers/edac/i3000_edac.c      |    6 +-
 drivers/edac/i3200_edac.c      |    4 +-
 drivers/edac/i5400_edac.c      |    6 +-
 drivers/edac/i82443bxgx_edac.c |    4 +-
 drivers/edac/i82860_edac.c     |    6 +-
 drivers/edac/i82875p_edac.c    |    6 +-
 drivers/edac/i82975x_edac.c    |   10 ++--
 drivers/edac/mpc85xx_edac.c    |    6 +-
 drivers/edac/mv64x60_edac.c    |    4 +-
 drivers/edac/pasemi_edac.c     |    8 +-
 drivers/edac/r82600_edac.c     |    4 +-
 drivers/edac/tile_edac.c       |    4 +-
 drivers/edac/x38_edac.c        |    4 +-
 include/linux/edac.h           |   31 ++++++----
 22 files changed, 218 insertions(+), 158 deletions(-)
drivers/edac/amd64_edac.c +6 -4
index 5eda2cd..08af66c 100644
@@ -2180,6 +2180,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 static int init_csrows(struct mem_ctl_info *mci)
 {
 	struct csrow_info *csrow;
+	struct dimm_info *dimm;
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u64 base, mask;
 	u32 val;
@@ -2197,7 +2198,7 @@ static int init_csrows(struct mem_ctl_info *mci)
 		!!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
 
 	for_each_chip_select(i, 0, pvt) {
-		csrow = &mci->csrows[i];
+		csrow = mci->csrows[i];
 
 		if (!csrow_enabled(i, 0, pvt)) {
 			debugf1("----CSROW %d EMPTY for node %d\n", i,
@@ -2228,9 +2229,10 @@ static int init_csrows(struct mem_ctl_info *mci)
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < pvt->channel_count; j++) {
-			csrow->channels[j].dimm->mtype = mtype;
-			csrow->channels[j].dimm->edac_mode = edac_mode;
-			csrow->channels[j].dimm->nr_pages = nr_pages;
+			dimm = csrow->channels[j]->dimm;
+			dimm->mtype = mtype;
+			dimm->edac_mode = edac_mode;
+			dimm->nr_pages = nr_pages;
 		}
 	}
 
drivers/edac/amd76x_edac.c +4 -4
index 9a34c5f..99d8d56 100644
@@ -146,7 +146,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 		if (handle_errors) {
 			row = (info->ecc_mode_status >> 4) & 0xf;
 			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-					     mci->csrows[row].first_page, 0, 0,
+					     mci->csrows[row]->first_page, 0, 0,
 					     row, 0, -1,
 					     mci->ctl_name, "", NULL);
 		}
@@ -161,7 +161,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 		if (handle_errors) {
 			row = info->ecc_mode_status & 0xf;
 			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-					     mci->csrows[row].first_page, 0, 0,
+					     mci->csrows[row]->first_page, 0, 0,
 					     row, 0, -1,
 					     mci->ctl_name, "", NULL);
 		}
@@ -194,8 +194,8 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	int index;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_dword(pdev,
drivers/edac/cell_edac.c +4 -4
index 9e53917..ee61f0d 100644
@@ -33,7 +33,7 @@ struct cell_edac_priv
 static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 {
 	struct cell_edac_priv		*priv = mci->pvt_info;
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	unsigned long			address, pfn, offset, syndrome;
 
 	dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
@@ -56,7 +56,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
 {
 	struct cell_edac_priv		*priv = mci->pvt_info;
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	unsigned long			address, pfn, offset;
 
 	dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
@@ -126,7 +126,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
 
 static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 {
-	struct csrow_info		*csrow = &mci->csrows[0];
+	struct csrow_info		*csrow = mci->csrows[0];
 	struct dimm_info		*dimm;
 	struct cell_edac_priv		*priv = mci->pvt_info;
 	struct device_node		*np;
@@ -150,7 +150,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 		csrow->last_page = csrow->first_page + nr_pages - 1;
 
 		for (j = 0; j < csrow->nr_channels; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 			dimm->mtype = MEM_XDR;
 			dimm->edac_mode = EDAC_SECDED;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
drivers/edac/cpc925_edac.c +4 -4
index 1b26ced..0203089 100644
@@ -348,7 +348,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		if (bba == 0)
 			continue; /* not populated */
 
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		row_size = bba * (1UL << 28);	/* 256M */
 		csrow->first_page = last_nr_pages;
@@ -380,7 +380,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 		break;
 		}
 		for (j = 0; j < csrow->nr_channels; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
 			dimm->mtype = MEM_RDDR;
 			dimm->edac_mode = EDAC_SECDED;
@@ -463,7 +463,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 	*csrow = rank;
 
 #ifdef CONFIG_EDAC_DEBUG
-	if (mci->csrows[rank].first_page == 0) {
+	if (mci->csrows[rank]->first_page == 0) {
 		cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a "
 			"non-populated csrow, broken hardware?\n");
 		return;
@@ -471,7 +471,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 #endif
 
 	/* Revert csrow number */
-	pa = mci->csrows[rank].first_page << PAGE_SHIFT;
+	pa = mci->csrows[rank]->first_page << PAGE_SHIFT;
 
 	/* Revert column address */
 	col += bcnt;
drivers/edac/e752x_edac.c +2 -2
index 84bb8f6..35f282e 100644
@@ -1096,7 +1096,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 2)) & 0x3;
-		csrow = &mci->csrows[remap_csrow_index(mci, index)];
+		csrow = mci->csrows[remap_csrow_index(mci, index)];
 
 		mem_dev = (mem_dev == 2);
 		pci_read_config_byte(pdev, E752X_DRB + index, &value);
@@ -1127,7 +1127,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 		} else
 			edac_mode = EDAC_NONE;
 		for (i = 0; i < csrow->nr_channels; i++) {
-			struct dimm_info *dimm = csrow->channels[i].dimm;
+			struct dimm_info *dimm = csrow->channels[i]->dimm;
 
 			debugf3("Initializing rank at (%i,%i)\n", index, i);
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
drivers/edac/e7xxx_edac.c +2 -2
index e930dd1..93695e4 100644
@@ -378,7 +378,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	for (index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 3)) & 0x1;
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		pci_read_config_byte(pdev, E7XXX_DRB + index, &value);
 		/* convert a 64 or 32 MiB DRB to a page size. */
@@ -409,7 +409,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 			edac_mode = EDAC_NONE;
 
 		for (j = 0; j < drc_chan + 1; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / (drc_chan + 1);
 			dimm->grain = 1 << 12;	/* 4KiB - resolution of CELOG */
drivers/edac/edac_mc.c +68 -37

219 lines not on this page · raw message

drivers/edac/edac_mc_sysfs.c +72 -54

319 lines not on this page · raw message

drivers/edac/i3000_edac.c +3 -3
index 2ee50ab..15df2bc 100644
@@ -236,7 +236,7 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
 	int row, multi_chan, channel;
 	unsigned long pfn, offset;
 
-	multi_chan = mci->csrows[0].nr_channels - 1;
+	multi_chan = mci->csrows[0]->nr_channels - 1;
 
 	if (!(info->errsts & I3000_ERRSTS_BITS))
 		return 0;
@@ -393,7 +393,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
 		u8 value;
 		u32 cumul_size;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		value = drb[i];
 		cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
@@ -410,7 +410,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 		last_cumul_size = cumul_size;
 
 		for (j = 0; j < nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_channels;
 			dimm->grain = I3000_DEAP_GRAIN;
drivers/edac/i3200_edac.c +2 -2
index 798fb65..acb5d39 100644
@@ -379,7 +379,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
 		unsigned long nr_pages;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		nr_pages = drb_to_nr_pages(drbs, stacked,
 			i / I3200_RANKS_PER_CHANNEL,
@@ -389,7 +389,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 			continue;
 
 		for (j = 0; j < nr_channels; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_channels;
 			dimm->grain = nr_pages << PAGE_SHIFT;
drivers/edac/i5400_edac.c +3 -3
index a16a2b5..74b64c6 100644
@@ -1203,8 +1203,8 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 
 			size_mb =  pvt->dimm_info[slot][channel].megabytes;
 
-			debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n",
-				__func__, dimm - mci->dimms,
+			debugf2("%s: dimm (branch %d channel %d slot %d): %d.%03d GB\n",
+				__func__,
 				channel / 2, channel % 2, slot,
 				size_mb / 1000, size_mb % 1000);
 
@@ -1227,7 +1227,7 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 	 * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+.
 	 */
 	if (ndimms == 1)
-		mci->dimms[0].edac_mode = EDAC_SECDED;
+		mci->dimms[0]->edac_mode = EDAC_SECDED;
 
 	return (ndimms == 0);
 }
drivers/edac/i82443bxgx_edac.c +2 -2
index 4c572545..877ba54 100644
@@ -197,8 +197,8 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
 	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
 	row_high_limit_last = 0;
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
 		debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
drivers/edac/i82860_edac.c +3 -3
index 16a54bb..f493758 100644
@@ -116,7 +116,7 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
 
 	info->eap >>= PAGE_SHIFT;
 	row = edac_mc_find_csrow_by_page(mci, info->eap);
-	dimm = mci->csrows[row].channels[0].dimm;
+	dimm = mci->csrows[row]->channels[0]->dimm;
 
 	if (info->errsts & 0x0002)
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
@@ -161,8 +161,8 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 	 * in all eight rows.
 	 */
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
 		cumul_size = (value & I82860_GBA_MASK) <<
drivers/edac/i82875p_edac.c +3 -3
index 9691449..a42a5bd 100644
@@ -227,7 +227,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 {
 	int row, multi_chan;
 
-	multi_chan = mci->csrows[0].nr_channels - 1;
+	multi_chan = mci->csrows[0]->nr_channels - 1;
 
 	if (!(info->errsts & 0x0081))
 		return 0;
@@ -367,7 +367,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
 	 */
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		value = readb(ovrfl_window + I82875P_DRB + index);
 		cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
@@ -382,7 +382,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
 		last_cumul_size = cumul_size;
 
 		for (j = 0; j < nr_chans; j++) {
-			dimm = csrow->channels[j].dimm;
+			dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / nr_chans;
 			dimm->grain = 1 << 12;	/* I82875P_EAP has 4KiB reolution */
drivers/edac/i82975x_edac.c +5 -5
index df99606..717f208 100644
@@ -308,10 +308,10 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
 			(info->xeap & 1) ? 1 : 0, info->eap, (unsigned int) page);
 		return 0;
 	}
-	chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1;
+	chan = (mci->csrows[row]->nr_channels == 1) ? 0 : info->eap & 1;
 	offst = info->eap
 			& ((1 << PAGE_SHIFT) -
-			   (1 << mci->csrows[row].channels[chan].dimm->grain));
+			   (1 << mci->csrows[row]->channels[chan]->dimm->grain));
 
 	if (info->errsts & 0x0002)
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
@@ -394,7 +394,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 	 */
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
+		csrow = mci->csrows[index];
 
 		value = readb(mch_window + I82975X_DRB + index +
 					((index >= 4) ? 0x80 : 0));
@@ -421,10 +421,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
 		 */
 		dtype = i82975x_dram_type(mch_window, index);
 		for (chan = 0; chan < csrow->nr_channels; chan++) {
-			dimm = mci->csrows[index].channels[chan].dimm;
+			dimm = mci->csrows[index]->channels[chan]->dimm;
 
 			dimm->nr_pages = nr_pages / csrow->nr_channels;
-			strncpy(csrow->channels[chan].dimm->label,
+			strncpy(csrow->channels[chan]->dimm->label,
 					labels[(index >> 1) + (chan * 2)],
 					EDAC_MC_LABEL_LEN);
 			dimm->grain = 1 << 7;	/* 128Byte cache-line resolution */
drivers/edac/mpc85xx_edac.c +3 -3
index c67cca1..42e209c 100644
@@ -825,7 +825,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
 	pfn = err_addr >> PAGE_SHIFT;
 
 	for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
-		csrow = &mci->csrows[row_index];
+		csrow = mci->csrows[row_index];
 		if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page))
 			break;
 	}
@@ -945,8 +945,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 		u32 start;
 		u32 end;
 
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
 				  (index * MPC85XX_MC_CS_BNDS_OFS));
drivers/edac/mv64x60_edac.c +2 -2
index ef0e710..87139ca 100644
@@ -670,8 +670,8 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 
 	ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
 
-	csrow = &mci->csrows[0];
-	dimm = csrow->channels[0].dimm;
+	csrow = mci->csrows[0];
+	dimm = csrow->channels[0]->dimm;
 
 	dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
 	dimm->grain = 8;
drivers/edac/pasemi_edac.c +4 -4
index 47542e7..634b919 100644
@@ -111,14 +111,14 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 	if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
 		      MCDEBUG_ERRSTA_RFL_STATUS)) {
 		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-				     mci->csrows[cs].first_page, 0, 0,
+				     mci->csrows[cs]->first_page, 0, 0,
 				     cs, 0, -1, mci->ctl_name, "", NULL);
 	}
 
 	/* correctable/single-bit errors */
 	if (errsta & MCDEBUG_ERRSTA_SBE_STATUS)
 		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-				     mci->csrows[cs].first_page, 0, 0,
+				     mci->csrows[cs]->first_page, 0, 0,
 				     cs, 0, -1, mci->ctl_name, "", NULL);
 }
 
@@ -141,8 +141,8 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
 	int index;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		pci_read_config_dword(pdev,
 				      MCDRAM_RANKCFG + (index * 12),
drivers/edac/r82600_edac.c +2 -2
index 10464c5..6a7a2ce 100644
@@ -230,8 +230,8 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 	row_high_limit_last = 0;
 
 	for (index = 0; index < mci->nr_csrows; index++) {
-		csrow = &mci->csrows[index];
-		dimm = csrow->channels[0].dimm;
+		csrow = mci->csrows[index];
+		dimm = csrow->channels[0]->dimm;
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
drivers/edac/tile_edac.c +2 -2
index 32cb2c7..4aecb06 100644
@@ -84,10 +84,10 @@ static void tile_edac_check(struct mem_ctl_info *mci)
  */
 static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 {
-	struct csrow_info	*csrow = &mci->csrows[0];
+	struct csrow_info	*csrow = mci->csrows[0];
 	struct tile_edac_priv	*priv = mci->pvt_info;
 	struct mshim_mem_info	mem_info;
-	struct dimm_info *dimm = csrow->channels[0].dimm;
+	struct dimm_info *dimm = csrow->channels[0]->dimm;
 
 	if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
 		sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
drivers/edac/x38_edac.c +2 -2
index dde47e9..c5e54ef 100644
@@ -378,7 +378,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	 */
 	for (i = 0; i < mci->nr_csrows; i++) {
 		unsigned long nr_pages;
-		struct csrow_info *csrow = &mci->csrows[i];
+		struct csrow_info *csrow = mci->csrows[i];
 
 		nr_pages = drb_to_nr_pages(drbs, stacked,
 			i / X38_RANKS_PER_CHANNEL,
@@ -388,7 +388,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 			continue;
 
 		for (j = 0; j < x38_channel_num; j++) {
-			struct dimm_info *dimm = csrow->channels[j].dimm;
+			struct dimm_info *dimm = csrow->channels[j]->dimm;
 
 			dimm->nr_pages = nr_pages / x38_channel_num;
 			dimm->grain = nr_pages << PAGE_SHIFT;
include/linux/edac.h +20 -11
index 22c3fca..bec5bff 100644
@@ -409,17 +409,28 @@ struct edac_mc_layer {
  * during the memory allocation routine, with would point to the developer
  * that he's doing something wrong.
  */
-#define GET_POS(layers, var, nlayers, lay0, lay1, lay2) ({		\
-	typeof(var) __p;						\
+
+#define GET_OFFSET(layers, nlayers, lay0, lay1, lay2) ({		\
+	int __i;								\
 	if ((nlayers) == 1)						\
-		__p = &var[lay0];					\
+		__i = lay0;						\
 	else if ((nlayers) == 2)					\
-		__p = &var[(lay1) + ((layers[1]).size * (lay0))];	\
+		__i = (lay1) + ((layers[1]).size * (lay0));		\
 	else if ((nlayers) == 3)					\
-		__p = &var[(lay2) + ((layers[2]).size * ((lay1) +	\
-			    ((layers[1]).size * (lay0))))];		\
+		__i = (lay2) + ((layers[2]).size * ((lay1) +		\
+			    ((layers[1]).size * (lay0))));		\
 	else								\
+		__i = -EINVAL;						\
+	__i;								\
+})
+
+#define GET_POS(layers, var, nlayers, lay0, lay1, lay2) ({		\
+	typeof(*var) __p;						\
+	int ___i = GET_OFFSET(layers, nlayers, lay0, lay1, lay2);	\
+	if (___i < 0)							\
 		__p = NULL;						\
+	else								\
+		__p = (var)[___i];					\
 	__p;								\
 })
 
@@ -459,8 +470,6 @@ struct dimm_info {
  *	  patches in this series will fix this issue.
  */
 struct rank_info {
-	struct device dev;
-
 	int chan_idx;
 	struct csrow_info *csrow;
 	struct dimm_info *dimm;
@@ -486,7 +495,7 @@ struct csrow_info {
 
 	/* channel information for this csrow */
 	u32 nr_channels;
-	struct rank_info *channels;
+	struct rank_info **channels;
 };
 
 /*
@@ -550,7 +559,7 @@ struct mem_ctl_info {
 	unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
 					   unsigned long page);
 	int mc_idx;
-	struct csrow_info *csrows;
+	struct csrow_info **csrows;
 	unsigned nr_csrows, num_cschannel;
 
 	/*
@@ -570,7 +579,7 @@ struct mem_ctl_info {
 	 * DIMM info. Will eventually remove the entire csrows_info some day
 	 */
 	unsigned tot_dimms;
-	struct dimm_info *dimms;
+	struct dimm_info **dimms;
 
 	/*
 	 * FIXME - what about controllers on other busses? - IDs must be
Signature · 1 line
1.7.8
Acked-by on v1 1/1
#61 lore raw

Re: [PATCH] edac: change the mem allocation scheme to make Documentation/kobject.txt happy

Quoted 8 lines · Mauro Carvalho Chehab

Kernel kobjects have rigid rules: each container object should be dynamically allocated, and can't be allocated into a single kmalloc.

EDAC never obeyed this rule: it has a single malloc function that allocates all needed data into a single kzalloc.

As this is not accepted anymore, change the allocation schema of the EDAC *_info structs to enforce this Kernel standard.

Very nice work, thanks for doing this:

#62 lore raw

PATCH v13 25/25 i7core_edac: change the mem allocation scheme to make Documentation/kobject.txt happy

In reply to Mauro Carvalho Chehab

Kernel kobjects have rigid rules: each container object should be dynamically allocated, and can't be allocated into a single kmalloc.

EDAC never obeyed this rule: it has a single malloc function that allocates all needed data into a single kzalloc.

As this is not accepted anymore, change the allocation schema of the EDAC *_info structs to enforce this Kernel standard.

---
 drivers/edac/i7core_edac.c |   56 +++++++++++++++++++++++++++----------------
 1 files changed, 35 insertions(+), 21 deletions(-)
drivers/edac/i7core_edac.c +35 -21
index e6a8efd..cf27af8 100644
@@ -246,7 +246,7 @@ struct i7core_dev {
 };
 
 struct i7core_pvt {
-	struct device addrmatch_dev, chancounts_dev;
+	struct device *addrmatch_dev, *chancounts_dev;
 
 	struct pci_dev	*pci_noncore;
 	struct pci_dev	*pci_mcr[MAX_MCR_FUNC + 1];
@@ -1102,6 +1102,7 @@ static const struct attribute_group *addrmatch_groups[] = {
 static void addrmatch_release(struct device *device)
 {
 	debugf1("Releasing device %s\n", dev_name(device));
+	kfree(device);
 }
 
 static struct device_type addrmatch_type = {
@@ -1132,6 +1133,7 @@ static const struct attribute_group *all_channel_counts_groups[] = {
 static void all_channel_counts_release(struct device *device)
 {
 	debugf1("Releasing device %s\n", dev_name(device));
+	kfree(device);
 }
 
 static struct device_type all_channel_counts_type = {
@@ -1174,32 +1176,44 @@ static int i7core_create_sysfs_devices(struct mem_ctl_info *mci)
 	if (rc < 0)
 		return rc;
 
-	pvt->addrmatch_dev.type = &addrmatch_type;
-	pvt->addrmatch_dev.bus = mci->dev.bus;
-	device_initialize(&pvt->addrmatch_dev);
-	pvt->addrmatch_dev.parent = &mci->dev;
-	dev_set_name(&pvt->addrmatch_dev, "inject_addrmatch");
-	dev_set_drvdata(&pvt->addrmatch_dev, mci);
+	pvt->addrmatch_dev = kzalloc(sizeof(*pvt->addrmatch_dev), GFP_KERNEL);
+	if (!pvt->addrmatch_dev)
+		return rc;
+
+	pvt->addrmatch_dev->type = &addrmatch_type;
+	pvt->addrmatch_dev->bus = mci->dev.bus;
+	device_initialize(pvt->addrmatch_dev);
+	pvt->addrmatch_dev->parent = &mci->dev;
+	dev_set_name(pvt->addrmatch_dev, "inject_addrmatch");
+	dev_set_drvdata(pvt->addrmatch_dev, mci);
 
 	debugf1("%s(): creating %s\n", __func__,
-		dev_name(&pvt->addrmatch_dev));
+		dev_name(pvt->addrmatch_dev));
 
-	rc = device_add(&pvt->addrmatch_dev);
+	rc = device_add(pvt->addrmatch_dev);
 	if (rc < 0)
 		return rc;
 
 	if (!pvt->is_registered) {
-		pvt->chancounts_dev.type = &all_channel_counts_type;
-		pvt->chancounts_dev.bus = mci->dev.bus;
-		device_initialize(&pvt->chancounts_dev);
-		pvt->chancounts_dev.parent = &mci->dev;
-		dev_set_name(&pvt->chancounts_dev, "all_channel_counts");
-		dev_set_drvdata(&pvt->chancounts_dev, mci);
+		pvt->chancounts_dev = kzalloc(sizeof(*pvt->chancounts_dev),
+					      GFP_KERNEL);
+		if (!pvt->chancounts_dev) {
+			put_device(pvt->addrmatch_dev);
+			device_del(pvt->addrmatch_dev);
+			return rc;
+		}
+
+		pvt->chancounts_dev->type = &all_channel_counts_type;
+		pvt->chancounts_dev->bus = mci->dev.bus;
+		device_initialize(pvt->chancounts_dev);
+		pvt->chancounts_dev->parent = &mci->dev;
+		dev_set_name(pvt->chancounts_dev, "all_channel_counts");
+		dev_set_drvdata(pvt->chancounts_dev, mci);
 
 		debugf1("%s(): creating %s\n", __func__,
-			dev_name(&pvt->chancounts_dev));
+			dev_name(pvt->chancounts_dev));
 
-		rc = device_add(&pvt->chancounts_dev);
+		rc = device_add(pvt->chancounts_dev);
 		if (rc < 0)
 			return rc;
 	}
@@ -1218,11 +1232,11 @@ static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
 	device_remove_file(&mci->dev, &dev_attr_inject_enable);
 
 	if (!pvt->is_registered) {
-		put_device(&pvt->chancounts_dev);
-		device_del(&pvt->chancounts_dev);
+		put_device(pvt->chancounts_dev);
+		device_del(pvt->chancounts_dev);
 	}
-	put_device(&pvt->addrmatch_dev);
-	device_del(&pvt->addrmatch_dev);
+	put_device(pvt->addrmatch_dev);
+	device_del(pvt->addrmatch_dev);
 }
 
 /****************************************************************************
Signature · 1 line
1.7.8