diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-04-24 14:05:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-11 12:23:45 -0400 |
commit | de3910eb79ac8c0f29a11224661c0ebaaf813039 (patch) | |
tree | 44584d6691588b2c18823260be0e44f0c9872d02 | |
parent | e39f4ea9b01f137f9e6fa631f3e9088fb9175e91 (diff) |
edac: change the mem allocation scheme to make Documentation/kobject.txt happy
Kernel kobjects have rigid rules: each container object should be
dynamically allocated, and can't be allocated into a single kmalloc.
EDAC never obeyed this rule: it has a single malloc function that
allocates all needed data into a single kzalloc.
As this is not accepted anymore, change the allocation schema of the
EDAC *_info structs to enforce this Kernel standard.
Acked-by: Chris Metcalf <cmetcalf@tilera.com>
Cc: Aristeu Rozanski <arozansk@redhat.com>
Cc: Doug Thompson <norsk5@yahoo.com>
Cc: Greg K H <gregkh@linuxfoundation.org>
Cc: Borislav Petkov <borislav.petkov@amd.com>
Cc: Mark Gross <mark.gross@intel.com>
Cc: Tim Small <tim@buttersideup.com>
Cc: Ranganathan Desikan <ravi@jetztechnologies.com>
Cc: "Arvind R." <arvino55@gmail.com>
Cc: Olof Johansson <olof@lixom.net>
Cc: Egor Martovetsky <egor@pasemi.com>
Cc: Michal Marek <mmarek@suse.cz>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Hitoshi Mitake <h.mitake@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Shaohui Xie <Shaohui.Xie@freescale.com>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/edac/amd64_edac.c | 10 | ||||
-rw-r--r-- | drivers/edac/amd76x_edac.c | 8 | ||||
-rw-r--r-- | drivers/edac/cell_edac.c | 8 | ||||
-rw-r--r-- | drivers/edac/cpc925_edac.c | 8 | ||||
-rw-r--r-- | drivers/edac/e752x_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/e7xxx_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 107 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 126 | ||||
-rw-r--r-- | drivers/edac/i3000_edac.c | 6 | ||||
-rw-r--r-- | drivers/edac/i3200_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/i5400_edac.c | 6 | ||||
-rw-r--r-- | drivers/edac/i82443bxgx_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/i82860_edac.c | 6 | ||||
-rw-r--r-- | drivers/edac/i82875p_edac.c | 6 | ||||
-rw-r--r-- | drivers/edac/i82975x_edac.c | 10 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 6 | ||||
-rw-r--r-- | drivers/edac/mv64x60_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/pasemi_edac.c | 8 | ||||
-rw-r--r-- | drivers/edac/r82600_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/tile_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/x38_edac.c | 4 | ||||
-rw-r--r-- | include/linux/edac.h | 59 |
22 files changed, 242 insertions, 164 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 9905834b560f..9fbced7f65ee 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -2205,6 +2205,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) | |||
2205 | static int init_csrows(struct mem_ctl_info *mci) | 2205 | static int init_csrows(struct mem_ctl_info *mci) |
2206 | { | 2206 | { |
2207 | struct csrow_info *csrow; | 2207 | struct csrow_info *csrow; |
2208 | struct dimm_info *dimm; | ||
2208 | struct amd64_pvt *pvt = mci->pvt_info; | 2209 | struct amd64_pvt *pvt = mci->pvt_info; |
2209 | u64 base, mask; | 2210 | u64 base, mask; |
2210 | u32 val; | 2211 | u32 val; |
@@ -2222,7 +2223,7 @@ static int init_csrows(struct mem_ctl_info *mci) | |||
2222 | !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); | 2223 | !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); |
2223 | 2224 | ||
2224 | for_each_chip_select(i, 0, pvt) { | 2225 | for_each_chip_select(i, 0, pvt) { |
2225 | csrow = &mci->csrows[i]; | 2226 | csrow = mci->csrows[i]; |
2226 | 2227 | ||
2227 | if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) { | 2228 | if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) { |
2228 | debugf1("----CSROW %d EMPTY for node %d\n", i, | 2229 | debugf1("----CSROW %d EMPTY for node %d\n", i, |
@@ -2257,9 +2258,10 @@ static int init_csrows(struct mem_ctl_info *mci) | |||
2257 | edac_mode = EDAC_NONE; | 2258 | edac_mode = EDAC_NONE; |
2258 | 2259 | ||
2259 | for (j = 0; j < pvt->channel_count; j++) { | 2260 | for (j = 0; j < pvt->channel_count; j++) { |
2260 | csrow->channels[j].dimm->mtype = mtype; | 2261 | dimm = csrow->channels[j]->dimm; |
2261 | csrow->channels[j].dimm->edac_mode = edac_mode; | 2262 | dimm->mtype = mtype; |
2262 | csrow->channels[j].dimm->nr_pages = nr_pages; | 2263 | dimm->edac_mode = edac_mode; |
2264 | dimm->nr_pages = nr_pages; | ||
2263 | } | 2265 | } |
2264 | } | 2266 | } |
2265 | 2267 | ||
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 7439786f3bef..a0c9f82875cd 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c | |||
@@ -146,7 +146,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, | |||
146 | if (handle_errors) { | 146 | if (handle_errors) { |
147 | row = (info->ecc_mode_status >> 4) & 0xf; | 147 | row = (info->ecc_mode_status >> 4) & 0xf; |
148 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, | 148 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, |
149 | mci->csrows[row].first_page, 0, 0, | 149 | mci->csrows[row]->first_page, 0, 0, |
150 | row, 0, -1, | 150 | row, 0, -1, |
151 | mci->ctl_name, "", NULL); | 151 | mci->ctl_name, "", NULL); |
152 | } | 152 | } |
@@ -161,7 +161,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, | |||
161 | if (handle_errors) { | 161 | if (handle_errors) { |
162 | row = info->ecc_mode_status & 0xf; | 162 | row = info->ecc_mode_status & 0xf; |
163 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, | 163 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, |
164 | mci->csrows[row].first_page, 0, 0, | 164 | mci->csrows[row]->first_page, 0, 0, |
165 | row, 0, -1, | 165 | row, 0, -1, |
166 | mci->ctl_name, "", NULL); | 166 | mci->ctl_name, "", NULL); |
167 | } | 167 | } |
@@ -194,8 +194,8 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
194 | int index; | 194 | int index; |
195 | 195 | ||
196 | for (index = 0; index < mci->nr_csrows; index++) { | 196 | for (index = 0; index < mci->nr_csrows; index++) { |
197 | csrow = &mci->csrows[index]; | 197 | csrow = mci->csrows[index]; |
198 | dimm = csrow->channels[0].dimm; | 198 | dimm = csrow->channels[0]->dimm; |
199 | 199 | ||
200 | /* find the DRAM Chip Select Base address and mask */ | 200 | /* find the DRAM Chip Select Base address and mask */ |
201 | pci_read_config_dword(pdev, | 201 | pci_read_config_dword(pdev, |
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index 2e5b95374dc6..478d8ee434df 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c | |||
@@ -33,7 +33,7 @@ struct cell_edac_priv | |||
33 | static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar) | 33 | static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar) |
34 | { | 34 | { |
35 | struct cell_edac_priv *priv = mci->pvt_info; | 35 | struct cell_edac_priv *priv = mci->pvt_info; |
36 | struct csrow_info *csrow = &mci->csrows[0]; | 36 | struct csrow_info *csrow = mci->csrows[0]; |
37 | unsigned long address, pfn, offset, syndrome; | 37 | unsigned long address, pfn, offset, syndrome; |
38 | 38 | ||
39 | dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n", | 39 | 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) | |||
56 | static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar) | 56 | static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar) |
57 | { | 57 | { |
58 | struct cell_edac_priv *priv = mci->pvt_info; | 58 | struct cell_edac_priv *priv = mci->pvt_info; |
59 | struct csrow_info *csrow = &mci->csrows[0]; | 59 | struct csrow_info *csrow = mci->csrows[0]; |
60 | unsigned long address, pfn, offset; | 60 | unsigned long address, pfn, offset; |
61 | 61 | ||
62 | dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n", | 62 | 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) | |||
126 | 126 | ||
127 | static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci) | 127 | static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci) |
128 | { | 128 | { |
129 | struct csrow_info *csrow = &mci->csrows[0]; | 129 | struct csrow_info *csrow = mci->csrows[0]; |
130 | struct dimm_info *dimm; | 130 | struct dimm_info *dimm; |
131 | struct cell_edac_priv *priv = mci->pvt_info; | 131 | struct cell_edac_priv *priv = mci->pvt_info; |
132 | struct device_node *np; | 132 | struct device_node *np; |
@@ -150,7 +150,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci) | |||
150 | csrow->last_page = csrow->first_page + nr_pages - 1; | 150 | csrow->last_page = csrow->first_page + nr_pages - 1; |
151 | 151 | ||
152 | for (j = 0; j < csrow->nr_channels; j++) { | 152 | for (j = 0; j < csrow->nr_channels; j++) { |
153 | dimm = csrow->channels[j].dimm; | 153 | dimm = csrow->channels[j]->dimm; |
154 | dimm->mtype = MEM_XDR; | 154 | dimm->mtype = MEM_XDR; |
155 | dimm->edac_mode = EDAC_SECDED; | 155 | dimm->edac_mode = EDAC_SECDED; |
156 | dimm->nr_pages = nr_pages / csrow->nr_channels; | 156 | dimm->nr_pages = nr_pages / csrow->nr_channels; |
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index 3510aa446297..534491d67159 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c | |||
@@ -348,7 +348,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci) | |||
348 | if (bba == 0) | 348 | if (bba == 0) |
349 | continue; /* not populated */ | 349 | continue; /* not populated */ |
350 | 350 | ||
351 | csrow = &mci->csrows[index]; | 351 | csrow = mci->csrows[index]; |
352 | 352 | ||
353 | row_size = bba * (1UL << 28); /* 256M */ | 353 | row_size = bba * (1UL << 28); /* 256M */ |
354 | csrow->first_page = last_nr_pages; | 354 | csrow->first_page = last_nr_pages; |
@@ -380,7 +380,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci) | |||
380 | break; | 380 | break; |
381 | } | 381 | } |
382 | for (j = 0; j < csrow->nr_channels; j++) { | 382 | for (j = 0; j < csrow->nr_channels; j++) { |
383 | dimm = csrow->channels[j].dimm; | 383 | dimm = csrow->channels[j]->dimm; |
384 | dimm->nr_pages = nr_pages / csrow->nr_channels; | 384 | dimm->nr_pages = nr_pages / csrow->nr_channels; |
385 | dimm->mtype = MEM_RDDR; | 385 | dimm->mtype = MEM_RDDR; |
386 | dimm->edac_mode = EDAC_SECDED; | 386 | dimm->edac_mode = EDAC_SECDED; |
@@ -463,7 +463,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear, | |||
463 | *csrow = rank; | 463 | *csrow = rank; |
464 | 464 | ||
465 | #ifdef CONFIG_EDAC_DEBUG | 465 | #ifdef CONFIG_EDAC_DEBUG |
466 | if (mci->csrows[rank].first_page == 0) { | 466 | if (mci->csrows[rank]->first_page == 0) { |
467 | cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a " | 467 | cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a " |
468 | "non-populated csrow, broken hardware?\n"); | 468 | "non-populated csrow, broken hardware?\n"); |
469 | return; | 469 | return; |
@@ -471,7 +471,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear, | |||
471 | #endif | 471 | #endif |
472 | 472 | ||
473 | /* Revert csrow number */ | 473 | /* Revert csrow number */ |
474 | pa = mci->csrows[rank].first_page << PAGE_SHIFT; | 474 | pa = mci->csrows[rank]->first_page << PAGE_SHIFT; |
475 | 475 | ||
476 | /* Revert column address */ | 476 | /* Revert column address */ |
477 | col += bcnt; | 477 | col += bcnt; |
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index d1142ed8bd88..7cde7f1aafb7 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c | |||
@@ -1096,7 +1096,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
1096 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { | 1096 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { |
1097 | /* mem_dev 0=x8, 1=x4 */ | 1097 | /* mem_dev 0=x8, 1=x4 */ |
1098 | mem_dev = (dra >> (index * 4 + 2)) & 0x3; | 1098 | mem_dev = (dra >> (index * 4 + 2)) & 0x3; |
1099 | csrow = &mci->csrows[remap_csrow_index(mci, index)]; | 1099 | csrow = mci->csrows[remap_csrow_index(mci, index)]; |
1100 | 1100 | ||
1101 | mem_dev = (mem_dev == 2); | 1101 | mem_dev = (mem_dev == 2); |
1102 | pci_read_config_byte(pdev, E752X_DRB + index, &value); | 1102 | 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, | |||
1127 | } else | 1127 | } else |
1128 | edac_mode = EDAC_NONE; | 1128 | edac_mode = EDAC_NONE; |
1129 | for (i = 0; i < csrow->nr_channels; i++) { | 1129 | for (i = 0; i < csrow->nr_channels; i++) { |
1130 | struct dimm_info *dimm = csrow->channels[i].dimm; | 1130 | struct dimm_info *dimm = csrow->channels[i]->dimm; |
1131 | 1131 | ||
1132 | debugf3("Initializing rank at (%i,%i)\n", index, i); | 1132 | debugf3("Initializing rank at (%i,%i)\n", index, i); |
1133 | dimm->nr_pages = nr_pages / csrow->nr_channels; | 1133 | dimm->nr_pages = nr_pages / csrow->nr_channels; |
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index bab31aab983d..c6c0ebaca371 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c | |||
@@ -378,7 +378,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
378 | for (index = 0; index < mci->nr_csrows; index++) { | 378 | for (index = 0; index < mci->nr_csrows; index++) { |
379 | /* mem_dev 0=x8, 1=x4 */ | 379 | /* mem_dev 0=x8, 1=x4 */ |
380 | mem_dev = (dra >> (index * 4 + 3)) & 0x1; | 380 | mem_dev = (dra >> (index * 4 + 3)) & 0x1; |
381 | csrow = &mci->csrows[index]; | 381 | csrow = mci->csrows[index]; |
382 | 382 | ||
383 | pci_read_config_byte(pdev, E7XXX_DRB + index, &value); | 383 | pci_read_config_byte(pdev, E7XXX_DRB + index, &value); |
384 | /* convert a 64 or 32 MiB DRB to a page size. */ | 384 | /* 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, | |||
409 | edac_mode = EDAC_NONE; | 409 | edac_mode = EDAC_NONE; |
410 | 410 | ||
411 | for (j = 0; j < drc_chan + 1; j++) { | 411 | for (j = 0; j < drc_chan + 1; j++) { |
412 | dimm = csrow->channels[j].dimm; | 412 | dimm = csrow->channels[j]->dimm; |
413 | 413 | ||
414 | dimm->nr_pages = nr_pages / (drc_chan + 1); | 414 | dimm->nr_pages = nr_pages / (drc_chan + 1); |
415 | dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */ | 415 | dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */ |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 4a6fdc03740e..db2ba31ba2b1 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -210,15 +210,15 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
210 | { | 210 | { |
211 | struct mem_ctl_info *mci; | 211 | struct mem_ctl_info *mci; |
212 | struct edac_mc_layer *layer; | 212 | struct edac_mc_layer *layer; |
213 | struct csrow_info *csi, *csr; | 213 | struct csrow_info *csr; |
214 | struct rank_info *chi, *chp, *chan; | 214 | struct rank_info *chan; |
215 | struct dimm_info *dimm; | 215 | struct dimm_info *dimm; |
216 | u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; | 216 | u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; |
217 | unsigned pos[EDAC_MAX_LAYERS]; | 217 | unsigned pos[EDAC_MAX_LAYERS]; |
218 | unsigned size, tot_dimms = 1, count = 1; | 218 | unsigned size, tot_dimms = 1, count = 1; |
219 | unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; | 219 | unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; |
220 | void *pvt, *p, *ptr = NULL; | 220 | void *pvt, *p, *ptr = NULL; |
221 | int i, j, row, chn, n, len; | 221 | int i, j, row, chn, n, len, off; |
222 | bool per_rank = false; | 222 | bool per_rank = false; |
223 | 223 | ||
224 | BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0); | 224 | BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0); |
@@ -244,9 +244,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
244 | */ | 244 | */ |
245 | mci = edac_align_ptr(&ptr, sizeof(*mci), 1); | 245 | mci = edac_align_ptr(&ptr, sizeof(*mci), 1); |
246 | layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); | 246 | layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); |
247 | csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows); | ||
248 | chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_channels); | ||
249 | dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms); | ||
250 | for (i = 0; i < n_layers; i++) { | 247 | for (i = 0; i < n_layers; i++) { |
251 | count *= layers[i].size; | 248 | count *= layers[i].size; |
252 | debugf4("%s: errcount layer %d size %d\n", __func__, i, count); | 249 | debugf4("%s: errcount layer %d size %d\n", __func__, i, count); |
@@ -264,6 +261,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
264 | tot_dimms, | 261 | tot_dimms, |
265 | per_rank ? "ranks" : "dimms", | 262 | per_rank ? "ranks" : "dimms", |
266 | tot_csrows * tot_channels); | 263 | tot_csrows * tot_channels); |
264 | |||
267 | mci = kzalloc(size, GFP_KERNEL); | 265 | mci = kzalloc(size, GFP_KERNEL); |
268 | if (mci == NULL) | 266 | if (mci == NULL) |
269 | return NULL; | 267 | return NULL; |
@@ -272,9 +270,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
272 | * rather than an imaginary chunk of memory located at address 0. | 270 | * rather than an imaginary chunk of memory located at address 0. |
273 | */ | 271 | */ |
274 | layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer)); | 272 | layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer)); |
275 | csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); | ||
276 | chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi)); | ||
277 | dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm)); | ||
278 | for (i = 0; i < n_layers; i++) { | 273 | for (i = 0; i < n_layers; i++) { |
279 | mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i])); | 274 | mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i])); |
280 | mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i])); | 275 | mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i])); |
@@ -283,8 +278,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
283 | 278 | ||
284 | /* setup index and various internal pointers */ | 279 | /* setup index and various internal pointers */ |
285 | mci->mc_idx = mc_num; | 280 | mci->mc_idx = mc_num; |
286 | mci->csrows = csi; | ||
287 | mci->dimms = dimm; | ||
288 | mci->tot_dimms = tot_dimms; | 281 | mci->tot_dimms = tot_dimms; |
289 | mci->pvt_info = pvt; | 282 | mci->pvt_info = pvt; |
290 | mci->n_layers = n_layers; | 283 | mci->n_layers = n_layers; |
@@ -295,39 +288,60 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
295 | mci->mem_is_per_rank = per_rank; | 288 | mci->mem_is_per_rank = per_rank; |
296 | 289 | ||
297 | /* | 290 | /* |
298 | * Fill the csrow struct | 291 | * Alocate and fill the csrow/channels structs |
299 | */ | 292 | */ |
293 | mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL); | ||
294 | if (!mci->csrows) | ||
295 | goto error; | ||
300 | for (row = 0; row < tot_csrows; row++) { | 296 | for (row = 0; row < tot_csrows; row++) { |
301 | csr = &csi[row]; | 297 | csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL); |
298 | if (!csr) | ||
299 | goto error; | ||
300 | mci->csrows[row] = csr; | ||
302 | csr->csrow_idx = row; | 301 | csr->csrow_idx = row; |
303 | csr->mci = mci; | 302 | csr->mci = mci; |
304 | csr->nr_channels = tot_channels; | 303 | csr->nr_channels = tot_channels; |
305 | chp = &chi[row * tot_channels]; | 304 | csr->channels = kcalloc(sizeof(*csr->channels), tot_channels, |
306 | csr->channels = chp; | 305 | GFP_KERNEL); |
306 | if (!csr->channels) | ||
307 | goto error; | ||
307 | 308 | ||
308 | for (chn = 0; chn < tot_channels; chn++) { | 309 | for (chn = 0; chn < tot_channels; chn++) { |
309 | chan = &chp[chn]; | 310 | chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL); |
311 | if (!chan) | ||
312 | goto error; | ||
313 | csr->channels[chn] = chan; | ||
310 | chan->chan_idx = chn; | 314 | chan->chan_idx = chn; |
311 | chan->csrow = csr; | 315 | chan->csrow = csr; |
312 | } | 316 | } |
313 | } | 317 | } |
314 | 318 | ||
315 | /* | 319 | /* |
316 | * Fill the dimm struct | 320 | * Allocate and fill the dimm structs |
317 | */ | 321 | */ |
322 | mci->dimms = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL); | ||
323 | if (!mci->dimms) | ||
324 | goto error; | ||
325 | |||
318 | memset(&pos, 0, sizeof(pos)); | 326 | memset(&pos, 0, sizeof(pos)); |
319 | row = 0; | 327 | row = 0; |
320 | chn = 0; | 328 | chn = 0; |
321 | debugf4("%s: initializing %d %s\n", __func__, tot_dimms, | 329 | debugf4("%s: initializing %d %s\n", __func__, tot_dimms, |
322 | per_rank ? "ranks" : "dimms"); | 330 | per_rank ? "ranks" : "dimms"); |
323 | for (i = 0; i < tot_dimms; i++) { | 331 | for (i = 0; i < tot_dimms; i++) { |
324 | chan = &csi[row].channels[chn]; | 332 | chan = mci->csrows[row]->channels[chn]; |
325 | dimm = EDAC_DIMM_PTR(layer, mci->dimms, n_layers, | 333 | off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]); |
326 | pos[0], pos[1], pos[2]); | 334 | if (off < 0 || off >= tot_dimms) { |
335 | edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access\n"); | ||
336 | goto error; | ||
337 | } | ||
338 | |||
339 | dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL); | ||
340 | mci->dimms[off] = dimm; | ||
327 | dimm->mci = mci; | 341 | dimm->mci = mci; |
328 | 342 | ||
329 | debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__, | 343 | debugf2("%s: %d: %s%i (%d:%d:%d): row %d, chan %d\n", __func__, |
330 | i, per_rank ? "rank" : "dimm", (dimm - mci->dimms), | 344 | i, per_rank ? "rank" : "dimm", off, |
331 | pos[0], pos[1], pos[2], row, chn); | 345 | pos[0], pos[1], pos[2], row, chn); |
332 | 346 | ||
333 | /* | 347 | /* |
@@ -381,6 +395,28 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
381 | */ | 395 | */ |
382 | 396 | ||
383 | return mci; | 397 | return mci; |
398 | |||
399 | error: | ||
400 | if (mci->dimms) { | ||
401 | for (i = 0; i < tot_dimms; i++) | ||
402 | kfree(mci->dimms[i]); | ||
403 | kfree(mci->dimms); | ||
404 | } | ||
405 | if (mci->csrows) { | ||
406 | for (chn = 0; chn < tot_channels; chn++) { | ||
407 | csr = mci->csrows[chn]; | ||
408 | if (csr) { | ||
409 | for (chn = 0; chn < tot_channels; chn++) | ||
410 | kfree(csr->channels[chn]); | ||
411 | kfree(csr); | ||
412 | } | ||
413 | kfree(mci->csrows[i]); | ||
414 | } | ||
415 | kfree(mci->csrows); | ||
416 | } | ||
417 | kfree(mci); | ||
418 | |||
419 | return NULL; | ||
384 | } | 420 | } |
385 | EXPORT_SYMBOL_GPL(edac_mc_alloc); | 421 | EXPORT_SYMBOL_GPL(edac_mc_alloc); |
386 | 422 | ||
@@ -393,10 +429,8 @@ void edac_mc_free(struct mem_ctl_info *mci) | |||
393 | { | 429 | { |
394 | debugf1("%s()\n", __func__); | 430 | debugf1("%s()\n", __func__); |
395 | 431 | ||
432 | /* the mci instance is freed here, when the sysfs object is dropped */ | ||
396 | edac_unregister_sysfs(mci); | 433 | edac_unregister_sysfs(mci); |
397 | |||
398 | /* free the mci instance memory here */ | ||
399 | kfree(mci); | ||
400 | } | 434 | } |
401 | EXPORT_SYMBOL_GPL(edac_mc_free); | 435 | EXPORT_SYMBOL_GPL(edac_mc_free); |
402 | 436 | ||
@@ -668,13 +702,12 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) | |||
668 | for (i = 0; i < mci->nr_csrows; i++) { | 702 | for (i = 0; i < mci->nr_csrows; i++) { |
669 | int j; | 703 | int j; |
670 | 704 | ||
671 | edac_mc_dump_csrow(&mci->csrows[i]); | 705 | edac_mc_dump_csrow(mci->csrows[i]); |
672 | for (j = 0; j < mci->csrows[i].nr_channels; j++) | 706 | for (j = 0; j < mci->csrows[i]->nr_channels; j++) |
673 | edac_mc_dump_channel(&mci->csrows[i]. | 707 | edac_mc_dump_channel(mci->csrows[i]->channels[j]); |
674 | channels[j]); | ||
675 | } | 708 | } |
676 | for (i = 0; i < mci->tot_dimms; i++) | 709 | for (i = 0; i < mci->tot_dimms; i++) |
677 | edac_mc_dump_dimm(&mci->dimms[i]); | 710 | edac_mc_dump_dimm(mci->dimms[i]); |
678 | } | 711 | } |
679 | #endif | 712 | #endif |
680 | mutex_lock(&mem_ctls_mutex); | 713 | mutex_lock(&mem_ctls_mutex); |
@@ -793,17 +826,17 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset, | |||
793 | /* FIXME - should return -1 */ | 826 | /* FIXME - should return -1 */ |
794 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) | 827 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) |
795 | { | 828 | { |
796 | struct csrow_info *csrows = mci->csrows; | 829 | struct csrow_info **csrows = mci->csrows; |
797 | int row, i, j, n; | 830 | int row, i, j, n; |
798 | 831 | ||
799 | debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); | 832 | debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); |
800 | row = -1; | 833 | row = -1; |
801 | 834 | ||
802 | for (i = 0; i < mci->nr_csrows; i++) { | 835 | for (i = 0; i < mci->nr_csrows; i++) { |
803 | struct csrow_info *csrow = &csrows[i]; | 836 | struct csrow_info *csrow = csrows[i]; |
804 | n = 0; | 837 | n = 0; |
805 | for (j = 0; j < csrow->nr_channels; j++) { | 838 | for (j = 0; j < csrow->nr_channels; j++) { |
806 | struct dimm_info *dimm = csrow->channels[j].dimm; | 839 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
807 | n += dimm->nr_pages; | 840 | n += dimm->nr_pages; |
808 | } | 841 | } |
809 | if (n == 0) | 842 | if (n == 0) |
@@ -1062,7 +1095,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
1062 | p = label; | 1095 | p = label; |
1063 | *p = '\0'; | 1096 | *p = '\0'; |
1064 | for (i = 0; i < mci->tot_dimms; i++) { | 1097 | for (i = 0; i < mci->tot_dimms; i++) { |
1065 | struct dimm_info *dimm = &mci->dimms[i]; | 1098 | struct dimm_info *dimm = mci->dimms[i]; |
1066 | 1099 | ||
1067 | if (top_layer >= 0 && top_layer != dimm->location[0]) | 1100 | if (top_layer >= 0 && top_layer != dimm->location[0]) |
1068 | continue; | 1101 | continue; |
@@ -1120,13 +1153,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, | |||
1120 | strcpy(label, "unknown memory"); | 1153 | strcpy(label, "unknown memory"); |
1121 | if (type == HW_EVENT_ERR_CORRECTED) { | 1154 | if (type == HW_EVENT_ERR_CORRECTED) { |
1122 | if (row >= 0) { | 1155 | if (row >= 0) { |
1123 | mci->csrows[row].ce_count++; | 1156 | mci->csrows[row]->ce_count++; |
1124 | if (chan >= 0) | 1157 | if (chan >= 0) |
1125 | mci->csrows[row].channels[chan].ce_count++; | 1158 | mci->csrows[row]->channels[chan]->ce_count++; |
1126 | } | 1159 | } |
1127 | } else | 1160 | } else |
1128 | if (row >= 0) | 1161 | if (row >= 0) |
1129 | mci->csrows[row].ue_count++; | 1162 | mci->csrows[row]->ue_count++; |
1130 | } | 1163 | } |
1131 | 1164 | ||
1132 | /* Fill the RAM location data */ | 1165 | /* Fill the RAM location data */ |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 0f671907c90b..87b8d7d6385f 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -82,7 +82,7 @@ module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int, | |||
82 | &edac_mc_poll_msec, 0644); | 82 | &edac_mc_poll_msec, 0644); |
83 | MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); | 83 | MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds"); |
84 | 84 | ||
85 | static struct device mci_pdev; | 85 | static struct device *mci_pdev; |
86 | 86 | ||
87 | /* | 87 | /* |
88 | * various constants for Memory Controllers | 88 | * various constants for Memory Controllers |
@@ -181,7 +181,7 @@ static ssize_t csrow_size_show(struct device *dev, | |||
181 | u32 nr_pages = 0; | 181 | u32 nr_pages = 0; |
182 | 182 | ||
183 | for (i = 0; i < csrow->nr_channels; i++) | 183 | for (i = 0; i < csrow->nr_channels; i++) |
184 | nr_pages += csrow->channels[i].dimm->nr_pages; | 184 | nr_pages += csrow->channels[i]->dimm->nr_pages; |
185 | return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages)); | 185 | return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages)); |
186 | } | 186 | } |
187 | 187 | ||
@@ -190,7 +190,7 @@ static ssize_t csrow_mem_type_show(struct device *dev, | |||
190 | { | 190 | { |
191 | struct csrow_info *csrow = to_csrow(dev); | 191 | struct csrow_info *csrow = to_csrow(dev); |
192 | 192 | ||
193 | return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]); | 193 | return sprintf(data, "%s\n", mem_types[csrow->channels[0]->dimm->mtype]); |
194 | } | 194 | } |
195 | 195 | ||
196 | static ssize_t csrow_dev_type_show(struct device *dev, | 196 | static ssize_t csrow_dev_type_show(struct device *dev, |
@@ -198,7 +198,7 @@ static ssize_t csrow_dev_type_show(struct device *dev, | |||
198 | { | 198 | { |
199 | struct csrow_info *csrow = to_csrow(dev); | 199 | struct csrow_info *csrow = to_csrow(dev); |
200 | 200 | ||
201 | return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]); | 201 | return sprintf(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]); |
202 | } | 202 | } |
203 | 203 | ||
204 | static ssize_t csrow_edac_mode_show(struct device *dev, | 204 | static ssize_t csrow_edac_mode_show(struct device *dev, |
@@ -207,7 +207,7 @@ static ssize_t csrow_edac_mode_show(struct device *dev, | |||
207 | { | 207 | { |
208 | struct csrow_info *csrow = to_csrow(dev); | 208 | struct csrow_info *csrow = to_csrow(dev); |
209 | 209 | ||
210 | return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]); | 210 | return sprintf(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]); |
211 | } | 211 | } |
212 | 212 | ||
213 | /* show/store functions for DIMM Label attributes */ | 213 | /* show/store functions for DIMM Label attributes */ |
@@ -217,7 +217,7 @@ static ssize_t channel_dimm_label_show(struct device *dev, | |||
217 | { | 217 | { |
218 | struct csrow_info *csrow = to_csrow(dev); | 218 | struct csrow_info *csrow = to_csrow(dev); |
219 | unsigned chan = to_channel(mattr); | 219 | unsigned chan = to_channel(mattr); |
220 | struct rank_info *rank = &csrow->channels[chan]; | 220 | struct rank_info *rank = csrow->channels[chan]; |
221 | 221 | ||
222 | /* if field has not been initialized, there is nothing to send */ | 222 | /* if field has not been initialized, there is nothing to send */ |
223 | if (!rank->dimm->label[0]) | 223 | if (!rank->dimm->label[0]) |
@@ -233,7 +233,7 @@ static ssize_t channel_dimm_label_store(struct device *dev, | |||
233 | { | 233 | { |
234 | struct csrow_info *csrow = to_csrow(dev); | 234 | struct csrow_info *csrow = to_csrow(dev); |
235 | unsigned chan = to_channel(mattr); | 235 | unsigned chan = to_channel(mattr); |
236 | struct rank_info *rank = &csrow->channels[chan]; | 236 | struct rank_info *rank = csrow->channels[chan]; |
237 | 237 | ||
238 | ssize_t max_size = 0; | 238 | ssize_t max_size = 0; |
239 | 239 | ||
@@ -250,7 +250,7 @@ static ssize_t channel_ce_count_show(struct device *dev, | |||
250 | { | 250 | { |
251 | struct csrow_info *csrow = to_csrow(dev); | 251 | struct csrow_info *csrow = to_csrow(dev); |
252 | unsigned chan = to_channel(mattr); | 252 | unsigned chan = to_channel(mattr); |
253 | struct rank_info *rank = &csrow->channels[chan]; | 253 | struct rank_info *rank = csrow->channels[chan]; |
254 | 254 | ||
255 | return sprintf(data, "%u\n", rank->ce_count); | 255 | return sprintf(data, "%u\n", rank->ce_count); |
256 | } | 256 | } |
@@ -283,9 +283,12 @@ static const struct attribute_group *csrow_attr_groups[] = { | |||
283 | NULL | 283 | NULL |
284 | }; | 284 | }; |
285 | 285 | ||
286 | static void csrow_attr_release(struct device *device) | 286 | static void csrow_attr_release(struct device *dev) |
287 | { | 287 | { |
288 | debugf1("Releasing csrow device %s\n", dev_name(device)); | 288 | struct csrow_info *csrow = container_of(dev, struct csrow_info, dev); |
289 | |||
290 | debugf1("Releasing csrow device %s\n", dev_name(dev)); | ||
291 | kfree(csrow); | ||
289 | } | 292 | } |
290 | 293 | ||
291 | static struct device_type csrow_attr_type = { | 294 | static struct device_type csrow_attr_type = { |
@@ -352,7 +355,7 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow) | |||
352 | int chan, nr_pages = 0; | 355 | int chan, nr_pages = 0; |
353 | 356 | ||
354 | for (chan = 0; chan < csrow->nr_channels; chan++) | 357 | for (chan = 0; chan < csrow->nr_channels; chan++) |
355 | nr_pages += csrow->channels[chan].dimm->nr_pages; | 358 | nr_pages += csrow->channels[chan]->dimm->nr_pages; |
356 | 359 | ||
357 | return nr_pages; | 360 | return nr_pages; |
358 | } | 361 | } |
@@ -382,7 +385,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, | |||
382 | 385 | ||
383 | for (chan = 0; chan < csrow->nr_channels; chan++) { | 386 | for (chan = 0; chan < csrow->nr_channels; chan++) { |
384 | /* Only expose populated DIMMs */ | 387 | /* Only expose populated DIMMs */ |
385 | if (!csrow->channels[chan].dimm->nr_pages) | 388 | if (!csrow->channels[chan]->dimm->nr_pages) |
386 | continue; | 389 | continue; |
387 | err = device_create_file(&csrow->dev, | 390 | err = device_create_file(&csrow->dev, |
388 | dynamic_csrow_dimm_attr[chan]); | 391 | dynamic_csrow_dimm_attr[chan]); |
@@ -418,10 +421,10 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci) | |||
418 | struct csrow_info *csrow; | 421 | struct csrow_info *csrow; |
419 | 422 | ||
420 | for (i = 0; i < mci->nr_csrows; i++) { | 423 | for (i = 0; i < mci->nr_csrows; i++) { |
421 | csrow = &mci->csrows[i]; | 424 | csrow = mci->csrows[i]; |
422 | if (!nr_pages_per_csrow(csrow)) | 425 | if (!nr_pages_per_csrow(csrow)) |
423 | continue; | 426 | continue; |
424 | err = edac_create_csrow_object(mci, &mci->csrows[i], i); | 427 | err = edac_create_csrow_object(mci, mci->csrows[i], i); |
425 | if (err < 0) | 428 | if (err < 0) |
426 | goto error; | 429 | goto error; |
427 | } | 430 | } |
@@ -429,18 +432,18 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci) | |||
429 | 432 | ||
430 | error: | 433 | error: |
431 | for (--i; i >= 0; i--) { | 434 | for (--i; i >= 0; i--) { |
432 | csrow = &mci->csrows[i]; | 435 | csrow = mci->csrows[i]; |
433 | if (!nr_pages_per_csrow(csrow)) | 436 | if (!nr_pages_per_csrow(csrow)) |
434 | continue; | 437 | continue; |
435 | for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { | 438 | for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { |
436 | if (!csrow->channels[chan].dimm->nr_pages) | 439 | if (!csrow->channels[chan]->dimm->nr_pages) |
437 | continue; | 440 | continue; |
438 | device_remove_file(&csrow->dev, | 441 | device_remove_file(&csrow->dev, |
439 | dynamic_csrow_dimm_attr[chan]); | 442 | dynamic_csrow_dimm_attr[chan]); |
440 | device_remove_file(&csrow->dev, | 443 | device_remove_file(&csrow->dev, |
441 | dynamic_csrow_ce_count_attr[chan]); | 444 | dynamic_csrow_ce_count_attr[chan]); |
442 | } | 445 | } |
443 | put_device(&mci->csrows[i].dev); | 446 | put_device(&mci->csrows[i]->dev); |
444 | } | 447 | } |
445 | 448 | ||
446 | return err; | 449 | return err; |
@@ -452,11 +455,11 @@ static void edac_delete_csrow_objects(struct mem_ctl_info *mci) | |||
452 | struct csrow_info *csrow; | 455 | struct csrow_info *csrow; |
453 | 456 | ||
454 | for (i = mci->nr_csrows - 1; i >= 0; i--) { | 457 | for (i = mci->nr_csrows - 1; i >= 0; i--) { |
455 | csrow = &mci->csrows[i]; | 458 | csrow = mci->csrows[i]; |
456 | if (!nr_pages_per_csrow(csrow)) | 459 | if (!nr_pages_per_csrow(csrow)) |
457 | continue; | 460 | continue; |
458 | for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { | 461 | for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { |
459 | if (!csrow->channels[chan].dimm->nr_pages) | 462 | if (!csrow->channels[chan]->dimm->nr_pages) |
460 | continue; | 463 | continue; |
461 | debugf1("Removing csrow %d channel %d sysfs nodes\n", | 464 | debugf1("Removing csrow %d channel %d sysfs nodes\n", |
462 | i, chan); | 465 | i, chan); |
@@ -465,8 +468,8 @@ static void edac_delete_csrow_objects(struct mem_ctl_info *mci) | |||
465 | device_remove_file(&csrow->dev, | 468 | device_remove_file(&csrow->dev, |
466 | dynamic_csrow_ce_count_attr[chan]); | 469 | dynamic_csrow_ce_count_attr[chan]); |
467 | } | 470 | } |
468 | put_device(&mci->csrows[i].dev); | 471 | put_device(&mci->csrows[i]->dev); |
469 | device_del(&mci->csrows[i].dev); | 472 | device_del(&mci->csrows[i]->dev); |
470 | } | 473 | } |
471 | } | 474 | } |
472 | #endif | 475 | #endif |
@@ -585,9 +588,12 @@ static const struct attribute_group *dimm_attr_groups[] = { | |||
585 | NULL | 588 | NULL |
586 | }; | 589 | }; |
587 | 590 | ||
588 | static void dimm_attr_release(struct device *device) | 591 | static void dimm_attr_release(struct device *dev) |
589 | { | 592 | { |
590 | debugf1("Releasing dimm device %s\n", dev_name(device)); | 593 | struct dimm_info *dimm = container_of(dev, struct dimm_info, dev); |
594 | |||
595 | debugf1("Releasing dimm device %s\n", dev_name(dev)); | ||
596 | kfree(dimm); | ||
591 | } | 597 | } |
592 | 598 | ||
593 | static struct device_type dimm_attr_type = { | 599 | static struct device_type dimm_attr_type = { |
@@ -641,13 +647,13 @@ static ssize_t mci_reset_counters_store(struct device *dev, | |||
641 | mci->ce_noinfo_count = 0; | 647 | mci->ce_noinfo_count = 0; |
642 | 648 | ||
643 | for (row = 0; row < mci->nr_csrows; row++) { | 649 | for (row = 0; row < mci->nr_csrows; row++) { |
644 | struct csrow_info *ri = &mci->csrows[row]; | 650 | struct csrow_info *ri = mci->csrows[row]; |
645 | 651 | ||
646 | ri->ue_count = 0; | 652 | ri->ue_count = 0; |
647 | ri->ce_count = 0; | 653 | ri->ce_count = 0; |
648 | 654 | ||
649 | for (chan = 0; chan < ri->nr_channels; chan++) | 655 | for (chan = 0; chan < ri->nr_channels; chan++) |
650 | ri->channels[chan].ce_count = 0; | 656 | ri->channels[chan]->ce_count = 0; |
651 | } | 657 | } |
652 | 658 | ||
653 | cnt = 1; | 659 | cnt = 1; |
@@ -779,10 +785,10 @@ static ssize_t mci_size_mb_show(struct device *dev, | |||
779 | int total_pages = 0, csrow_idx, j; | 785 | int total_pages = 0, csrow_idx, j; |
780 | 786 | ||
781 | for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) { | 787 | for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) { |
782 | struct csrow_info *csrow = &mci->csrows[csrow_idx]; | 788 | struct csrow_info *csrow = mci->csrows[csrow_idx]; |
783 | 789 | ||
784 | for (j = 0; j < csrow->nr_channels; j++) { | 790 | for (j = 0; j < csrow->nr_channels; j++) { |
785 | struct dimm_info *dimm = csrow->channels[j].dimm; | 791 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
786 | 792 | ||
787 | total_pages += dimm->nr_pages; | 793 | total_pages += dimm->nr_pages; |
788 | } | 794 | } |
@@ -889,9 +895,12 @@ static const struct attribute_group *mci_attr_groups[] = { | |||
889 | NULL | 895 | NULL |
890 | }; | 896 | }; |
891 | 897 | ||
892 | static void mci_attr_release(struct device *device) | 898 | static void mci_attr_release(struct device *dev) |
893 | { | 899 | { |
894 | debugf1("Releasing mci device %s\n", dev_name(device)); | 900 | struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev); |
901 | |||
902 | debugf1("Releasing csrow device %s\n", dev_name(dev)); | ||
903 | kfree(mci); | ||
895 | } | 904 | } |
896 | 905 | ||
897 | static struct device_type mci_attr_type = { | 906 | static struct device_type mci_attr_type = { |
@@ -950,29 +959,28 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
950 | { | 959 | { |
951 | int i, err; | 960 | int i, err; |
952 | 961 | ||
953 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | 962 | /* |
963 | * The memory controller needs its own bus, in order to avoid | ||
964 | * namespace conflicts at /sys/bus/edac. | ||
965 | */ | ||
966 | mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); | ||
967 | if (!mci->bus.name) | ||
968 | return -ENOMEM; | ||
969 | debugf0("creating bus %s\n",mci->bus.name); | ||
970 | err = bus_register(&mci->bus); | ||
971 | if (err < 0) | ||
972 | return err; | ||
954 | 973 | ||
955 | /* get the /sys/devices/system/edac subsys reference */ | 974 | /* get the /sys/devices/system/edac subsys reference */ |
956 | |||
957 | mci->dev.type = &mci_attr_type; | 975 | mci->dev.type = &mci_attr_type; |
958 | device_initialize(&mci->dev); | 976 | device_initialize(&mci->dev); |
959 | 977 | ||
960 | mci->dev.parent = &mci_pdev; | 978 | mci->dev.parent = mci_pdev; |
961 | mci->dev.bus = &mci->bus; | 979 | mci->dev.bus = &mci->bus; |
962 | dev_set_name(&mci->dev, "mc%d", mci->mc_idx); | 980 | dev_set_name(&mci->dev, "mc%d", mci->mc_idx); |
963 | dev_set_drvdata(&mci->dev, mci); | 981 | dev_set_drvdata(&mci->dev, mci); |
964 | pm_runtime_forbid(&mci->dev); | 982 | pm_runtime_forbid(&mci->dev); |
965 | 983 | ||
966 | /* | ||
967 | * The memory controller needs its own bus, in order to avoid | ||
968 | * namespace conflicts at /sys/bus/edac. | ||
969 | */ | ||
970 | debugf0("creating bus %s\n",mci->bus.name); | ||
971 | mci->bus.name = kstrdup(dev_name(&mci->dev), GFP_KERNEL); | ||
972 | err = bus_register(&mci->bus); | ||
973 | if (err < 0) | ||
974 | return err; | ||
975 | |||
976 | debugf0("%s(): creating device %s\n", __func__, | 984 | debugf0("%s(): creating device %s\n", __func__, |
977 | dev_name(&mci->dev)); | 985 | dev_name(&mci->dev)); |
978 | err = device_add(&mci->dev); | 986 | err = device_add(&mci->dev); |
@@ -986,7 +994,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
986 | * Create the dimm/rank devices | 994 | * Create the dimm/rank devices |
987 | */ | 995 | */ |
988 | for (i = 0; i < mci->tot_dimms; i++) { | 996 | for (i = 0; i < mci->tot_dimms; i++) { |
989 | struct dimm_info *dimm = &mci->dimms[i]; | 997 | struct dimm_info *dimm = mci->dimms[i]; |
990 | /* Only expose populated DIMMs */ | 998 | /* Only expose populated DIMMs */ |
991 | if (dimm->nr_pages == 0) | 999 | if (dimm->nr_pages == 0) |
992 | continue; | 1000 | continue; |
@@ -1023,7 +1031,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
1023 | 1031 | ||
1024 | fail: | 1032 | fail: |
1025 | for (i--; i >= 0; i--) { | 1033 | for (i--; i >= 0; i--) { |
1026 | struct dimm_info *dimm = &mci->dimms[i]; | 1034 | struct dimm_info *dimm = mci->dimms[i]; |
1027 | if (dimm->nr_pages == 0) | 1035 | if (dimm->nr_pages == 0) |
1028 | continue; | 1036 | continue; |
1029 | put_device(&dimm->dev); | 1037 | put_device(&dimm->dev); |
@@ -1053,7 +1061,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
1053 | #endif | 1061 | #endif |
1054 | 1062 | ||
1055 | for (i = 0; i < mci->tot_dimms; i++) { | 1063 | for (i = 0; i < mci->tot_dimms; i++) { |
1056 | struct dimm_info *dimm = &mci->dimms[i]; | 1064 | struct dimm_info *dimm = mci->dimms[i]; |
1057 | if (dimm->nr_pages == 0) | 1065 | if (dimm->nr_pages == 0) |
1058 | continue; | 1066 | continue; |
1059 | debugf0("%s(): removing device %s\n", __func__, | 1067 | debugf0("%s(): removing device %s\n", __func__, |
@@ -1072,9 +1080,15 @@ void edac_unregister_sysfs(struct mem_ctl_info *mci) | |||
1072 | kfree(mci->bus.name); | 1080 | kfree(mci->bus.name); |
1073 | } | 1081 | } |
1074 | 1082 | ||
1075 | static void mc_attr_release(struct device *device) | 1083 | static void mc_attr_release(struct device *dev) |
1076 | { | 1084 | { |
1077 | debugf1("Releasing device %s\n", dev_name(device)); | 1085 | /* |
1086 | * There's no container structure here, as this is just the mci | ||
1087 | * parent device, used to create the /sys/devices/mc sysfs node. | ||
1088 | * So, there are no attributes on it. | ||
1089 | */ | ||
1090 | debugf1("Releasing device %s\n", dev_name(dev)); | ||
1091 | kfree(dev); | ||
1078 | } | 1092 | } |
1079 | 1093 | ||
1080 | static struct device_type mc_attr_type = { | 1094 | static struct device_type mc_attr_type = { |
@@ -1095,21 +1109,25 @@ int __init edac_mc_sysfs_init(void) | |||
1095 | return -EINVAL; | 1109 | return -EINVAL; |
1096 | } | 1110 | } |
1097 | 1111 | ||
1098 | mci_pdev.bus = edac_subsys; | 1112 | mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); |
1099 | mci_pdev.type = &mc_attr_type; | 1113 | |
1100 | device_initialize(&mci_pdev); | 1114 | mci_pdev->bus = edac_subsys; |
1101 | dev_set_name(&mci_pdev, "mc"); | 1115 | mci_pdev->type = &mc_attr_type; |
1116 | device_initialize(mci_pdev); | ||
1117 | dev_set_name(mci_pdev, "mc"); | ||
1102 | 1118 | ||
1103 | err = device_add(&mci_pdev); | 1119 | err = device_add(mci_pdev); |
1104 | if (err < 0) | 1120 | if (err < 0) |
1105 | return err; | 1121 | return err; |
1106 | 1122 | ||
1123 | debugf0("device %s created\n", dev_name(mci_pdev)); | ||
1124 | |||
1107 | return 0; | 1125 | return 0; |
1108 | } | 1126 | } |
1109 | 1127 | ||
1110 | void __exit edac_mc_sysfs_exit(void) | 1128 | void __exit edac_mc_sysfs_exit(void) |
1111 | { | 1129 | { |
1112 | put_device(&mci_pdev); | 1130 | put_device(mci_pdev); |
1113 | device_del(&mci_pdev); | 1131 | device_del(mci_pdev); |
1114 | edac_put_sysfs_subsys(); | 1132 | edac_put_sysfs_subsys(); |
1115 | } | 1133 | } |
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index d1ebd9b9ad6f..812213da7f91 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c | |||
@@ -236,7 +236,7 @@ static int i3000_process_error_info(struct mem_ctl_info *mci, | |||
236 | int row, multi_chan, channel; | 236 | int row, multi_chan, channel; |
237 | unsigned long pfn, offset; | 237 | unsigned long pfn, offset; |
238 | 238 | ||
239 | multi_chan = mci->csrows[0].nr_channels - 1; | 239 | multi_chan = mci->csrows[0]->nr_channels - 1; |
240 | 240 | ||
241 | if (!(info->errsts & I3000_ERRSTS_BITS)) | 241 | if (!(info->errsts & I3000_ERRSTS_BITS)) |
242 | return 0; | 242 | return 0; |
@@ -393,7 +393,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) | |||
393 | for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) { | 393 | for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) { |
394 | u8 value; | 394 | u8 value; |
395 | u32 cumul_size; | 395 | u32 cumul_size; |
396 | struct csrow_info *csrow = &mci->csrows[i]; | 396 | struct csrow_info *csrow = mci->csrows[i]; |
397 | 397 | ||
398 | value = drb[i]; | 398 | value = drb[i]; |
399 | cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT); | 399 | cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT); |
@@ -410,7 +410,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) | |||
410 | last_cumul_size = cumul_size; | 410 | last_cumul_size = cumul_size; |
411 | 411 | ||
412 | for (j = 0; j < nr_channels; j++) { | 412 | for (j = 0; j < nr_channels; j++) { |
413 | struct dimm_info *dimm = csrow->channels[j].dimm; | 413 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
414 | 414 | ||
415 | dimm->nr_pages = nr_pages / nr_channels; | 415 | dimm->nr_pages = nr_pages / nr_channels; |
416 | dimm->grain = I3000_DEAP_GRAIN; | 416 | dimm->grain = I3000_DEAP_GRAIN; |
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index 600a05df3759..c5f0fb31d5e0 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c | |||
@@ -379,7 +379,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) | |||
379 | */ | 379 | */ |
380 | for (i = 0; i < mci->nr_csrows; i++) { | 380 | for (i = 0; i < mci->nr_csrows; i++) { |
381 | unsigned long nr_pages; | 381 | unsigned long nr_pages; |
382 | struct csrow_info *csrow = &mci->csrows[i]; | 382 | struct csrow_info *csrow = mci->csrows[i]; |
383 | 383 | ||
384 | nr_pages = drb_to_nr_pages(drbs, stacked, | 384 | nr_pages = drb_to_nr_pages(drbs, stacked, |
385 | i / I3200_RANKS_PER_CHANNEL, | 385 | i / I3200_RANKS_PER_CHANNEL, |
@@ -389,7 +389,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) | |||
389 | continue; | 389 | continue; |
390 | 390 | ||
391 | for (j = 0; j < nr_channels; j++) { | 391 | for (j = 0; j < nr_channels; j++) { |
392 | struct dimm_info *dimm = csrow->channels[j].dimm; | 392 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
393 | 393 | ||
394 | dimm->nr_pages = nr_pages / nr_channels; | 394 | dimm->nr_pages = nr_pages / nr_channels; |
395 | dimm->grain = nr_pages << PAGE_SHIFT; | 395 | dimm->grain = nr_pages << PAGE_SHIFT; |
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index ba60694437bd..0570cf3d2563 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c | |||
@@ -1203,8 +1203,8 @@ static int i5400_init_dimms(struct mem_ctl_info *mci) | |||
1203 | 1203 | ||
1204 | size_mb = pvt->dimm_info[slot][channel].megabytes; | 1204 | size_mb = pvt->dimm_info[slot][channel].megabytes; |
1205 | 1205 | ||
1206 | debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n", | 1206 | debugf2("%s: dimm (branch %d channel %d slot %d): %d.%03d GB\n", |
1207 | __func__, dimm - mci->dimms, | 1207 | __func__, |
1208 | channel / 2, channel % 2, slot, | 1208 | channel / 2, channel % 2, slot, |
1209 | size_mb / 1000, size_mb % 1000); | 1209 | size_mb / 1000, size_mb % 1000); |
1210 | 1210 | ||
@@ -1227,7 +1227,7 @@ static int i5400_init_dimms(struct mem_ctl_info *mci) | |||
1227 | * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+. | 1227 | * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+. |
1228 | */ | 1228 | */ |
1229 | if (ndimms == 1) | 1229 | if (ndimms == 1) |
1230 | mci->dimms[0].edac_mode = EDAC_SECDED; | 1230 | mci->dimms[0]->edac_mode = EDAC_SECDED; |
1231 | 1231 | ||
1232 | return (ndimms == 0); | 1232 | return (ndimms == 0); |
1233 | } | 1233 | } |
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 65fd2e1eceb8..0f2751bf3ffe 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c | |||
@@ -197,8 +197,8 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, | |||
197 | pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); | 197 | pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); |
198 | row_high_limit_last = 0; | 198 | row_high_limit_last = 0; |
199 | for (index = 0; index < mci->nr_csrows; index++) { | 199 | for (index = 0; index < mci->nr_csrows; index++) { |
200 | csrow = &mci->csrows[index]; | 200 | csrow = mci->csrows[index]; |
201 | dimm = csrow->channels[0].dimm; | 201 | dimm = csrow->channels[0]->dimm; |
202 | 202 | ||
203 | pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar); | 203 | pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar); |
204 | debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n", | 204 | debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n", |
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index 8f3350000942..06a3c8d26d19 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c | |||
@@ -116,7 +116,7 @@ static int i82860_process_error_info(struct mem_ctl_info *mci, | |||
116 | 116 | ||
117 | info->eap >>= PAGE_SHIFT; | 117 | info->eap >>= PAGE_SHIFT; |
118 | row = edac_mc_find_csrow_by_page(mci, info->eap); | 118 | row = edac_mc_find_csrow_by_page(mci, info->eap); |
119 | dimm = mci->csrows[row].channels[0].dimm; | 119 | dimm = mci->csrows[row]->channels[0]->dimm; |
120 | 120 | ||
121 | if (info->errsts & 0x0002) | 121 | if (info->errsts & 0x0002) |
122 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, | 122 | 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) | |||
161 | * in all eight rows. | 161 | * in all eight rows. |
162 | */ | 162 | */ |
163 | for (index = 0; index < mci->nr_csrows; index++) { | 163 | for (index = 0; index < mci->nr_csrows; index++) { |
164 | csrow = &mci->csrows[index]; | 164 | csrow = mci->csrows[index]; |
165 | dimm = csrow->channels[0].dimm; | 165 | dimm = csrow->channels[0]->dimm; |
166 | 166 | ||
167 | pci_read_config_word(pdev, I82860_GBA + index * 2, &value); | 167 | pci_read_config_word(pdev, I82860_GBA + index * 2, &value); |
168 | cumul_size = (value & I82860_GBA_MASK) << | 168 | cumul_size = (value & I82860_GBA_MASK) << |
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index a47c6b25db31..97fd6b769c84 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c | |||
@@ -227,7 +227,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci, | |||
227 | { | 227 | { |
228 | int row, multi_chan; | 228 | int row, multi_chan; |
229 | 229 | ||
230 | multi_chan = mci->csrows[0].nr_channels - 1; | 230 | multi_chan = mci->csrows[0]->nr_channels - 1; |
231 | 231 | ||
232 | if (!(info->errsts & 0x0081)) | 232 | if (!(info->errsts & 0x0081)) |
233 | return 0; | 233 | return 0; |
@@ -367,7 +367,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci, | |||
367 | */ | 367 | */ |
368 | 368 | ||
369 | for (index = 0; index < mci->nr_csrows; index++) { | 369 | for (index = 0; index < mci->nr_csrows; index++) { |
370 | csrow = &mci->csrows[index]; | 370 | csrow = mci->csrows[index]; |
371 | 371 | ||
372 | value = readb(ovrfl_window + I82875P_DRB + index); | 372 | value = readb(ovrfl_window + I82875P_DRB + index); |
373 | cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT); | 373 | cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT); |
@@ -382,7 +382,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci, | |||
382 | last_cumul_size = cumul_size; | 382 | last_cumul_size = cumul_size; |
383 | 383 | ||
384 | for (j = 0; j < nr_chans; j++) { | 384 | for (j = 0; j < nr_chans; j++) { |
385 | dimm = csrow->channels[j].dimm; | 385 | dimm = csrow->channels[j]->dimm; |
386 | 386 | ||
387 | dimm->nr_pages = nr_pages / nr_chans; | 387 | dimm->nr_pages = nr_pages / nr_chans; |
388 | dimm->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ | 388 | dimm->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ |
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 8b26401efa19..4d239ab31e34 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c | |||
@@ -308,10 +308,10 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci, | |||
308 | (info->xeap & 1) ? 1 : 0, info->eap, (unsigned int) page); | 308 | (info->xeap & 1) ? 1 : 0, info->eap, (unsigned int) page); |
309 | return 0; | 309 | return 0; |
310 | } | 310 | } |
311 | chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1; | 311 | chan = (mci->csrows[row]->nr_channels == 1) ? 0 : info->eap & 1; |
312 | offst = info->eap | 312 | offst = info->eap |
313 | & ((1 << PAGE_SHIFT) - | 313 | & ((1 << PAGE_SHIFT) - |
314 | (1 << mci->csrows[row].channels[chan].dimm->grain)); | 314 | (1 << mci->csrows[row]->channels[chan]->dimm->grain)); |
315 | 315 | ||
316 | if (info->errsts & 0x0002) | 316 | if (info->errsts & 0x0002) |
317 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, | 317 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, |
@@ -394,7 +394,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, | |||
394 | */ | 394 | */ |
395 | 395 | ||
396 | for (index = 0; index < mci->nr_csrows; index++) { | 396 | for (index = 0; index < mci->nr_csrows; index++) { |
397 | csrow = &mci->csrows[index]; | 397 | csrow = mci->csrows[index]; |
398 | 398 | ||
399 | value = readb(mch_window + I82975X_DRB + index + | 399 | value = readb(mch_window + I82975X_DRB + index + |
400 | ((index >= 4) ? 0x80 : 0)); | 400 | ((index >= 4) ? 0x80 : 0)); |
@@ -421,10 +421,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, | |||
421 | */ | 421 | */ |
422 | dtype = i82975x_dram_type(mch_window, index); | 422 | dtype = i82975x_dram_type(mch_window, index); |
423 | for (chan = 0; chan < csrow->nr_channels; chan++) { | 423 | for (chan = 0; chan < csrow->nr_channels; chan++) { |
424 | dimm = mci->csrows[index].channels[chan].dimm; | 424 | dimm = mci->csrows[index]->channels[chan]->dimm; |
425 | 425 | ||
426 | dimm->nr_pages = nr_pages / csrow->nr_channels; | 426 | dimm->nr_pages = nr_pages / csrow->nr_channels; |
427 | strncpy(csrow->channels[chan].dimm->label, | 427 | strncpy(csrow->channels[chan]->dimm->label, |
428 | labels[(index >> 1) + (chan * 2)], | 428 | labels[(index >> 1) + (chan * 2)], |
429 | EDAC_MC_LABEL_LEN); | 429 | EDAC_MC_LABEL_LEN); |
430 | dimm->grain = 1 << 7; /* 128Byte cache-line resolution */ | 430 | dimm->grain = 1 << 7; /* 128Byte cache-line resolution */ |
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index d132dbbd9bd7..0db6f1e84656 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c | |||
@@ -825,7 +825,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) | |||
825 | pfn = err_addr >> PAGE_SHIFT; | 825 | pfn = err_addr >> PAGE_SHIFT; |
826 | 826 | ||
827 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { | 827 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { |
828 | csrow = &mci->csrows[row_index]; | 828 | csrow = mci->csrows[row_index]; |
829 | if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) | 829 | if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) |
830 | break; | 830 | break; |
831 | } | 831 | } |
@@ -945,8 +945,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci) | |||
945 | u32 start; | 945 | u32 start; |
946 | u32 end; | 946 | u32 end; |
947 | 947 | ||
948 | csrow = &mci->csrows[index]; | 948 | csrow = mci->csrows[index]; |
949 | dimm = csrow->channels[0].dimm; | 949 | dimm = csrow->channels[0]->dimm; |
950 | 950 | ||
951 | cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + | 951 | cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + |
952 | (index * MPC85XX_MC_CS_BNDS_OFS)); | 952 | (index * MPC85XX_MC_CS_BNDS_OFS)); |
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index ff6b8e248e89..3a58ba9158db 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c | |||
@@ -670,8 +670,8 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci, | |||
670 | 670 | ||
671 | ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); | 671 | ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); |
672 | 672 | ||
673 | csrow = &mci->csrows[0]; | 673 | csrow = mci->csrows[0]; |
674 | dimm = csrow->channels[0].dimm; | 674 | dimm = csrow->channels[0]->dimm; |
675 | 675 | ||
676 | dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT; | 676 | dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT; |
677 | dimm->grain = 8; | 677 | dimm->grain = 8; |
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 92becaa8722a..44f73b00df01 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c | |||
@@ -111,14 +111,14 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta) | |||
111 | if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS | | 111 | if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS | |
112 | MCDEBUG_ERRSTA_RFL_STATUS)) { | 112 | MCDEBUG_ERRSTA_RFL_STATUS)) { |
113 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, | 113 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, |
114 | mci->csrows[cs].first_page, 0, 0, | 114 | mci->csrows[cs]->first_page, 0, 0, |
115 | cs, 0, -1, mci->ctl_name, "", NULL); | 115 | cs, 0, -1, mci->ctl_name, "", NULL); |
116 | } | 116 | } |
117 | 117 | ||
118 | /* correctable/single-bit errors */ | 118 | /* correctable/single-bit errors */ |
119 | if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) | 119 | if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) |
120 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, | 120 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, |
121 | mci->csrows[cs].first_page, 0, 0, | 121 | mci->csrows[cs]->first_page, 0, 0, |
122 | cs, 0, -1, mci->ctl_name, "", NULL); | 122 | cs, 0, -1, mci->ctl_name, "", NULL); |
123 | } | 123 | } |
124 | 124 | ||
@@ -141,8 +141,8 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci, | |||
141 | int index; | 141 | int index; |
142 | 142 | ||
143 | for (index = 0; index < mci->nr_csrows; index++) { | 143 | for (index = 0; index < mci->nr_csrows; index++) { |
144 | csrow = &mci->csrows[index]; | 144 | csrow = mci->csrows[index]; |
145 | dimm = csrow->channels[0].dimm; | 145 | dimm = csrow->channels[0]->dimm; |
146 | 146 | ||
147 | pci_read_config_dword(pdev, | 147 | pci_read_config_dword(pdev, |
148 | MCDRAM_RANKCFG + (index * 12), | 148 | MCDRAM_RANKCFG + (index * 12), |
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index cf4ccbdba85d..445c9ff27b88 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c | |||
@@ -230,8 +230,8 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, | |||
230 | row_high_limit_last = 0; | 230 | row_high_limit_last = 0; |
231 | 231 | ||
232 | for (index = 0; index < mci->nr_csrows; index++) { | 232 | for (index = 0; index < mci->nr_csrows; index++) { |
233 | csrow = &mci->csrows[index]; | 233 | csrow = mci->csrows[index]; |
234 | dimm = csrow->channels[0].dimm; | 234 | dimm = csrow->channels[0]->dimm; |
235 | 235 | ||
236 | /* find the DRAM Chip Select Base address and mask */ | 236 | /* find the DRAM Chip Select Base address and mask */ |
237 | pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); | 237 | pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); |
diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c index 604bc4df653a..fc77f77fa065 100644 --- a/drivers/edac/tile_edac.c +++ b/drivers/edac/tile_edac.c | |||
@@ -84,10 +84,10 @@ static void tile_edac_check(struct mem_ctl_info *mci) | |||
84 | */ | 84 | */ |
85 | static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci) | 85 | static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci) |
86 | { | 86 | { |
87 | struct csrow_info *csrow = &mci->csrows[0]; | 87 | struct csrow_info *csrow = mci->csrows[0]; |
88 | struct tile_edac_priv *priv = mci->pvt_info; | 88 | struct tile_edac_priv *priv = mci->pvt_info; |
89 | struct mshim_mem_info mem_info; | 89 | struct mshim_mem_info mem_info; |
90 | struct dimm_info *dimm = csrow->channels[0].dimm; | 90 | struct dimm_info *dimm = csrow->channels[0]->dimm; |
91 | 91 | ||
92 | if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info, | 92 | if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info, |
93 | sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) != | 93 | sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) != |
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index f9506f26e2bf..ae699be78b24 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c | |||
@@ -378,7 +378,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) | |||
378 | */ | 378 | */ |
379 | for (i = 0; i < mci->nr_csrows; i++) { | 379 | for (i = 0; i < mci->nr_csrows; i++) { |
380 | unsigned long nr_pages; | 380 | unsigned long nr_pages; |
381 | struct csrow_info *csrow = &mci->csrows[i]; | 381 | struct csrow_info *csrow = mci->csrows[i]; |
382 | 382 | ||
383 | nr_pages = drb_to_nr_pages(drbs, stacked, | 383 | nr_pages = drb_to_nr_pages(drbs, stacked, |
384 | i / X38_RANKS_PER_CHANNEL, | 384 | i / X38_RANKS_PER_CHANNEL, |
@@ -388,7 +388,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) | |||
388 | continue; | 388 | continue; |
389 | 389 | ||
390 | for (j = 0; j < x38_channel_num; j++) { | 390 | for (j = 0; j < x38_channel_num; j++) { |
391 | struct dimm_info *dimm = csrow->channels[j].dimm; | 391 | struct dimm_info *dimm = csrow->channels[j]->dimm; |
392 | 392 | ||
393 | dimm->nr_pages = nr_pages / x38_channel_num; | 393 | dimm->nr_pages = nr_pages / x38_channel_num; |
394 | dimm->grain = nr_pages << PAGE_SHIFT; | 394 | dimm->grain = nr_pages << PAGE_SHIFT; |
diff --git a/include/linux/edac.h b/include/linux/edac.h index 64ae0c5cf62e..6677af853e30 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h | |||
@@ -412,23 +412,21 @@ struct edac_mc_layer { | |||
412 | #define EDAC_MAX_LAYERS 3 | 412 | #define EDAC_MAX_LAYERS 3 |
413 | 413 | ||
414 | /** | 414 | /** |
415 | * EDAC_DIMM_PTR - Macro responsible to find a pointer inside a pointer array | 415 | * EDAC_DIMM_OFF - Macro responsible to get a pointer offset inside a pointer array |
416 | * for the element given by [layer0,layer1,layer2] position | 416 | * for the element given by [layer0,layer1,layer2] position |
417 | * | 417 | * |
418 | * @layers: a struct edac_mc_layer array, describing how many elements | 418 | * @layers: a struct edac_mc_layer array, describing how many elements |
419 | * were allocated for each layer | 419 | * were allocated for each layer |
420 | * @var: name of the var where we want to get the pointer | ||
421 | * (like mci->dimms) | ||
422 | * @n_layers: Number of layers at the @layers array | 420 | * @n_layers: Number of layers at the @layers array |
423 | * @layer0: layer0 position | 421 | * @layer0: layer0 position |
424 | * @layer1: layer1 position. Unused if n_layers < 2 | 422 | * @layer1: layer1 position. Unused if n_layers < 2 |
425 | * @layer2: layer2 position. Unused if n_layers < 3 | 423 | * @layer2: layer2 position. Unused if n_layers < 3 |
426 | * | 424 | * |
427 | * For 1 layer, this macro returns &var[layer0] | 425 | * For 1 layer, this macro returns &var[layer0] - &var |
428 | * For 2 layers, this macro is similar to allocate a bi-dimensional array | 426 | * For 2 layers, this macro is similar to allocate a bi-dimensional array |
429 | * and to return "&var[layer0][layer1]" | 427 | * and to return "&var[layer0][layer1] - &var" |
430 | * For 3 layers, this macro is similar to allocate a tri-dimensional array | 428 | * For 3 layers, this macro is similar to allocate a tri-dimensional array |
431 | * and to return "&var[layer0][layer1][layer2]" | 429 | * and to return "&var[layer0][layer1][layer2] - &var" |
432 | * | 430 | * |
433 | * A loop could be used here to make it more generic, but, as we only have | 431 | * A loop could be used here to make it more generic, but, as we only have |
434 | * 3 layers, this is a little faster. | 432 | * 3 layers, this is a little faster. |
@@ -436,17 +434,46 @@ struct edac_mc_layer { | |||
436 | * a NULL is returned, causing an OOPS during the memory allocation routine, | 434 | * a NULL is returned, causing an OOPS during the memory allocation routine, |
437 | * with would point to the developer that he's doing something wrong. | 435 | * with would point to the developer that he's doing something wrong. |
438 | */ | 436 | */ |
439 | #define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \ | 437 | #define EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2) ({ \ |
440 | typeof(var) __p; \ | 438 | int __i; \ |
441 | if ((nlayers) == 1) \ | 439 | if ((nlayers) == 1) \ |
442 | __p = &var[layer0]; \ | 440 | __i = layer0; \ |
443 | else if ((nlayers) == 2) \ | 441 | else if ((nlayers) == 2) \ |
444 | __p = &var[(layer1) + ((layers[1]).size * (layer0))]; \ | 442 | __i = (layer1) + ((layers[1]).size * (layer0)); \ |
445 | else if ((nlayers) == 3) \ | 443 | else if ((nlayers) == 3) \ |
446 | __p = &var[(layer2) + ((layers[2]).size * ((layer1) + \ | 444 | __i = (layer2) + ((layers[2]).size * ((layer1) + \ |
447 | ((layers[1]).size * (layer0))))]; \ | 445 | ((layers[1]).size * (layer0)))); \ |
448 | else \ | 446 | else \ |
447 | __i = -EINVAL; \ | ||
448 | __i; \ | ||
449 | }) | ||
450 | |||
451 | /** | ||
452 | * EDAC_DIMM_PTR - Macro responsible to get a pointer inside a pointer array | ||
453 | * for the element given by [layer0,layer1,layer2] position | ||
454 | * | ||
455 | * @layers: a struct edac_mc_layer array, describing how many elements | ||
456 | * were allocated for each layer | ||
457 | * @var: name of the var where we want to get the pointer | ||
458 | * (like mci->dimms) | ||
459 | * @n_layers: Number of layers at the @layers array | ||
460 | * @layer0: layer0 position | ||
461 | * @layer1: layer1 position. Unused if n_layers < 2 | ||
462 | * @layer2: layer2 position. Unused if n_layers < 3 | ||
463 | * | ||
464 | * For 1 layer, this macro returns &var[layer0] | ||
465 | * For 2 layers, this macro is similar to allocate a bi-dimensional array | ||
466 | * and to return "&var[layer0][layer1]" | ||
467 | * For 3 layers, this macro is similar to allocate a tri-dimensional array | ||
468 | * and to return "&var[layer0][layer1][layer2]" | ||
469 | */ | ||
470 | #define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \ | ||
471 | typeof(*var) __p; \ | ||
472 | int ___i = EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2); \ | ||
473 | if (___i < 0) \ | ||
449 | __p = NULL; \ | 474 | __p = NULL; \ |
475 | else \ | ||
476 | __p = (var)[___i]; \ | ||
450 | __p; \ | 477 | __p; \ |
451 | }) | 478 | }) |
452 | 479 | ||
@@ -486,8 +513,6 @@ struct dimm_info { | |||
486 | * patches in this series will fix this issue. | 513 | * patches in this series will fix this issue. |
487 | */ | 514 | */ |
488 | struct rank_info { | 515 | struct rank_info { |
489 | struct device dev; | ||
490 | |||
491 | int chan_idx; | 516 | int chan_idx; |
492 | struct csrow_info *csrow; | 517 | struct csrow_info *csrow; |
493 | struct dimm_info *dimm; | 518 | struct dimm_info *dimm; |
@@ -513,7 +538,7 @@ struct csrow_info { | |||
513 | 538 | ||
514 | /* channel information for this csrow */ | 539 | /* channel information for this csrow */ |
515 | u32 nr_channels; | 540 | u32 nr_channels; |
516 | struct rank_info *channels; | 541 | struct rank_info **channels; |
517 | }; | 542 | }; |
518 | 543 | ||
519 | /* | 544 | /* |
@@ -572,7 +597,7 @@ struct mem_ctl_info { | |||
572 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, | 597 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, |
573 | unsigned long page); | 598 | unsigned long page); |
574 | int mc_idx; | 599 | int mc_idx; |
575 | struct csrow_info *csrows; | 600 | struct csrow_info **csrows; |
576 | unsigned nr_csrows, num_cschannel; | 601 | unsigned nr_csrows, num_cschannel; |
577 | 602 | ||
578 | /* | 603 | /* |
@@ -592,7 +617,7 @@ struct mem_ctl_info { | |||
592 | * DIMM info. Will eventually remove the entire csrows_info some day | 617 | * DIMM info. Will eventually remove the entire csrows_info some day |
593 | */ | 618 | */ |
594 | unsigned tot_dimms; | 619 | unsigned tot_dimms; |
595 | struct dimm_info *dimms; | 620 | struct dimm_info **dimms; |
596 | 621 | ||
597 | /* | 622 | /* |
598 | * FIXME - what about controllers on other busses? - IDs must be | 623 | * FIXME - what about controllers on other busses? - IDs must be |