Fix EDAC userspace ABI
Subsystems (17)
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
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
@@ -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
@@ -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
@@ -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
Re: [EDAC ABI v13 01/25] edac: Initialize the dimm label with the known information
Adding latest version here:
Quoted 8 lines
From
50e9a89aad7045909780d635d73ab2893f8c1f90Mon 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 informationWhile 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]>Signed-off-by Mauro Carvalho Chehab <[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@@ -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
-1dimm->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
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
50e9a89aad7045909780d635d73ab2893f8c1f90Mon 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 informationWhile 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_PartNum0Quoted 2 lines
After this patch, the memory label will be filled with:
/sys/devices/system/edac/mc/mc0/dimm0/dimm_label:mc#0channel#0slot#0This 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: DIMM02nd 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 A3rd 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 Band 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]>Signed-off-by Mauro Carvalho Chehab <[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@@ -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
-1dimm->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
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
50e9a89aad7045909780d635d73ab2893f8c1f90Mon 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 informationWhile 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#0This 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: DIMM02nd 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 A3rd 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]>Signed-off-by Mauro Carvalho Chehab <[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@@ -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
-0dimm->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).
drivers/edac/edac_mc.c +22 -6
@@ -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
@@ -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
@@ -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;
PATCH v13 2/25 edac: Cleanup the logs for i7core and sb edac drivers
In reply to Mauro Carvalho ChehabRemove 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
@@ -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
@@ -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
PATCH v13 3/25 i5400_edac: improve debug messages to better represent the filled memory
In reply to Mauro Carvalho ChehabImproves 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
@@ -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
PATCH v13 4/25 events/hw_event: Create a Hardware Events Report Mecanism (HERM)
In reply to Mauro Carvalho ChehabAdds 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.
--- 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
@@ -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
@@ -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
Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)
Inserting the latest version:
Quoted 5 lines
From
4afb0250415e87b983f5937d456c83407fe96264Mon 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 usingprintk();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
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Cc Steven Rostedt <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Ingo Molnar <[email protected]>Signed-off-by Mauro Carvalho Chehab <[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.hdrivers/edac/edac_core.h +1
-1@@ -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@@ -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@@ -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
Mauro Carvalho Chehab
Reviewed-by Aristeu RozanskiRe: [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
4afb0250415e87b983f5937d456c83407fe96264Mon 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_errortracepoint, 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 usingprintk();
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
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Cc Steven Rostedt <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Ingo Molnar <[email protected]>Signed-off-by Mauro Carvalho Chehab <[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.hdrivers/edac/edac_core.h +1
-1@@ -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@@ -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@@ -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.
drivers/edac/edac_core.h +1 -1
@@ -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
@@ -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
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
4afb0250415e87b983f5937d456c83407fe96264Mon 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_errortracepoint, 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@@ -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
Mauro Carvalho Chehab
Reviewed-by Aristeu RozanskiRe: [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
4afb0250415e87b983f5937d456c83407fe96264Mon 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_errortracepoint, 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.hor 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@@ -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_wakeupandsched_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.
drivers/edac/edac_core.h +1 -1
@@ -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
@@ -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
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.hor 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 underinclude/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 usingprintk();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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Cc Steven Rostedt <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Ingo Molnar <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>drivers/edac/edac_core.h +1
-1@@ -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@@ -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@@ -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
Mauro Carvalho Chehab
Reviewed-by Aristeu RozanskiRe: [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.hor 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 underinclude/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) eventsand 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.
drivers/edac/edac_core.h +1 -1
@@ -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
@@ -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
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.hor 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 underinclude/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 usingprintk();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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Cc Steven Rostedt <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Ingo Molnar <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>drivers/edac/edac_core.h +1
-1@@ -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@@ -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@@ -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
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.hor 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 underinclude/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
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
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.
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
Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)
In reply to Mauro Carvalho ChehabEm 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
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
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.
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
@@ -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
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.
Signed-off-by Mauro Carvalho Chehab <[email protected]>
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
Steven Rostedt
maintainerRe: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)
In reply to Borislav PetkovQuoted 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
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
Re: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)
In reply to Steven RostedtEm 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
Steven Rostedt
maintainerRe: [EDAC ABI v13 04/25] events/hw_event: Create a Hardware Events Report Mecanism (HERM)
In reply to Mauro Carvalho ChehabQuoted 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 insamples/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
Mauro Carvalho Chehab
Reviewed-by Aristeu RozanskiRe: [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/eventsdirectory.
*
* I could specify a path from thedefine_trace.hfile back to this
* file.
*
* #defineTRACE_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 theMakefile:
*
* CFLAGS_trace-events-sample.o := -I$(src)
*
* This will make sure the current path is part of the include
* structure for our file so thatdefine_trace.hcan 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 theTRACE_INCLUDE_PATH:
*
* #defineTRACE_INCLUDE_PATHsamples/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.hOr 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.
drivers/edac/edac_core.h +1 -1
@@ -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
@@ -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
PATCH v13 5/25 i5000_edac: Fix the logic that retrieves memory information
In reply to Mauro Carvalho ChehabThe 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
@@ -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
PATCH v13 6/25 e752x_edac: provide more info about how DIMMS/ranks are mapped
In reply to Mauro Carvalho ChehabNo 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
@@ -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
PATCH v13 7/25 edac: Rename the parent dev to pdev
In reply to Mauro Carvalho ChehabAs 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.
--- 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v13 8/25 edac: use Documentation-nano format for some data structs
In reply to Mauro Carvalho ChehabNo functional changes. Just comment improvements.
--- include/linux/edac.h | 80 +++++++++++++++++++++++++++++++++++-------------- 1 files changed, 57 insertions(+), 23 deletions(-)
include/linux/edac.h +57 -23
@@ -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
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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>--- include/linux/edac.h | 80 +++++++++++++++++++++++++++++++++++-------------- 1 files changed, 57 insertions(+), 23 deletions(-)include/linux/edac.h +13
-1@@ -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
Mauro Carvalho Chehab
Reviewed-by Aristeu RozanskiRe: [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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>--- include/linux/edac.h | 80 +++++++++++++++++++++++++++++++++++-------------- 1 files changed, 57 insertions(+), 23 deletions(-)include/linux/edac.h +13
-1@@ -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-typewith 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
@@ -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)
PATCH v13 9/25 edac: rewrite the sysfs code to use struct device
In reply to Mauro Carvalho ChehabThe 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
@@ -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
@@ -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
@@ -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
Re: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device
Inserting latest version:
Quoted 5 lines
From
e8765894c6d43326c9968a3687f5140708ee163fMon 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()anddevice_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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>
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
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
e8765894c6d43326c9968a3687f5140708ee163fMon 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 deviceThe 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()anddevice_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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>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
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/a2c90149c2e87e51908003b1ba504f92d749f74bBasically, 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
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
@@ -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
@@ -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
@@ -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
Mauro Carvalho Chehab
Reviewed-by Aristeu RozanskiRe: [EDAC ABI v13 09/25] edac: rewrite the sysfs code to use struct device
In reply to Borislav PetkovEm 09-05-2012 09:34, Borislav Petkov escreveu:
Quoted 14 lines
Inserting latest version:
Quoted 12 lines
From
e8765894c6d43326c9968a3687f5140708ee163fMon 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 deviceThe 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()anddevice_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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Signed-off-by Mauro Carvalho Chehab <[email protected]>
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
@@ -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
@@ -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
@@ -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
PATCH v13 10/25 mpc85xx_edac: convert sysfs logic to use struct device
In reply to Mauro Carvalho ChehabNow 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
@@ -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
PATCH v13 11/25 amd64_edac: convert sysfs logic to use struct device
In reply to Mauro Carvalho ChehabNow 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
@@ -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
@@ -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
PATCH v13 12/25 i7core_edac: convert it to use struct device
In reply to Mauro Carvalho ChehabInstead 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
@@ -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
PATCH v13 13/25 edac: Get rid of the old kobj's from the edac mc code
In reply to Mauro Carvalho ChehabNow 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
@@ -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
@@ -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
@@ -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
@@ -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
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 ChehabThe 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.
--- 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
@@ -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
PATCH v13 15/25 edac: add a sysfs node to report the maximum location for the system
In reply to Mauro Carvalho ChehabThe 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
@@ -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
PATCH v13 16/25 edac: Add debufs nodes to allow doing fake error inject
In reply to Mauro Carvalho ChehabSometimes, 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
@@ -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
@@ -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
PATCH v13 17/25 edac: Create a per-Memory Controller bus
In reply to Mauro Carvalho ChehabI'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
@@ -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
@@ -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
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.
Reviewed-by Aristeu Rozanski <[email protected]>Cc Doug Thompson <[email protected]>Cc Greg K H <[email protected]>
PATCH v13 18/25 edac: Move grain/dtype/edac_type calculus to be out of channel loop
In reply to Mauro Carvalho ChehabThe 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.
--- 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
@@ -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
@@ -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
@@ -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
PATCH v13 19/25 i82975x_edac: Test nr_pages earlier to save a few CPU cycles
In reply to Mauro Carvalho ChehabAvoid 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
@@ -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
PATCH v13 20/25 i5100_edac: Fix a warning when compiled with 32 bits
In reply to Mauro Carvalho Chehabdrivers/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
@@ -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
PATCH v13 21/25 i7300_edac: Get rid of some wrongly-solved rebase conflict
In reply to Mauro Carvalho ChehabDrivers 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
@@ -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
PATCH v13 22/25 edac: Only expose csrows/channels on legacy API if they're populated
In reply to Mauro Carvalho ChehabThis 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
@@ -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
PATCH v13 23/25 edac: Fix a typo at edac_mc_sysfs
In reply to Mauro Carvalho ChehabNo 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
@@ -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
PATCH v13 24/25 edac: change the mem allocation scheme to make Documentation/kobject.txt happy
In reply to Mauro Carvalho ChehabKernel 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 | 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
@@ -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
@@ -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
@@ -33,7 +33,7 @@ struct cell_edac_privstatic 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
*_infostructs 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
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
*_infostructs 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_NOWARNdo 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
@@ -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
@@ -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]);
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.
PATCH 1/1 edac: change the mem allocation scheme to make Documentation/kobject.txt happy
In reply to Joe PerchesKernel 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 | 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
@@ -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
@@ -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
@@ -33,7 +33,7 @@ struct cell_edac_privstatic 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
*_infostructs to enforce this Kernel standard.
Very nice work, thanks for doing this:
PATCH v13 25/25 i7core_edac: change the mem allocation scheme to make Documentation/kobject.txt happy
In reply to Mauro Carvalho ChehabKernel 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
@@ -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