diff options
Diffstat (limited to 'drivers/edac/edac_mc.c')
-rw-r--r-- | drivers/edac/edac_mc.c | 57 |
1 files changed, 39 insertions, 18 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 616d90bcb3a4..d5dc9da7f99f 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -199,6 +199,36 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems) | |||
199 | return (void *)(((unsigned long)ptr) + align - r); | 199 | return (void *)(((unsigned long)ptr) + align - r); |
200 | } | 200 | } |
201 | 201 | ||
202 | static void _edac_mc_free(struct mem_ctl_info *mci) | ||
203 | { | ||
204 | int i, chn, row; | ||
205 | struct csrow_info *csr; | ||
206 | const unsigned int tot_dimms = mci->tot_dimms; | ||
207 | const unsigned int tot_channels = mci->num_cschannel; | ||
208 | const unsigned int tot_csrows = mci->nr_csrows; | ||
209 | |||
210 | if (mci->dimms) { | ||
211 | for (i = 0; i < tot_dimms; i++) | ||
212 | kfree(mci->dimms[i]); | ||
213 | kfree(mci->dimms); | ||
214 | } | ||
215 | if (mci->csrows) { | ||
216 | for (row = 0; row < tot_csrows; row++) { | ||
217 | csr = mci->csrows[row]; | ||
218 | if (csr) { | ||
219 | if (csr->channels) { | ||
220 | for (chn = 0; chn < tot_channels; chn++) | ||
221 | kfree(csr->channels[chn]); | ||
222 | kfree(csr->channels); | ||
223 | } | ||
224 | kfree(csr); | ||
225 | } | ||
226 | } | ||
227 | kfree(mci->csrows); | ||
228 | } | ||
229 | kfree(mci); | ||
230 | } | ||
231 | |||
202 | /** | 232 | /** |
203 | * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure | 233 | * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure |
204 | * @mc_num: Memory controller number | 234 | * @mc_num: Memory controller number |
@@ -413,24 +443,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
413 | return mci; | 443 | return mci; |
414 | 444 | ||
415 | error: | 445 | error: |
416 | if (mci->dimms) { | 446 | _edac_mc_free(mci); |
417 | for (i = 0; i < tot_dimms; i++) | ||
418 | kfree(mci->dimms[i]); | ||
419 | kfree(mci->dimms); | ||
420 | } | ||
421 | if (mci->csrows) { | ||
422 | for (chn = 0; chn < tot_channels; chn++) { | ||
423 | csr = mci->csrows[chn]; | ||
424 | if (csr) { | ||
425 | for (chn = 0; chn < tot_channels; chn++) | ||
426 | kfree(csr->channels[chn]); | ||
427 | kfree(csr); | ||
428 | } | ||
429 | kfree(mci->csrows[i]); | ||
430 | } | ||
431 | kfree(mci->csrows); | ||
432 | } | ||
433 | kfree(mci); | ||
434 | 447 | ||
435 | return NULL; | 448 | return NULL; |
436 | } | 449 | } |
@@ -445,6 +458,14 @@ void edac_mc_free(struct mem_ctl_info *mci) | |||
445 | { | 458 | { |
446 | edac_dbg(1, "\n"); | 459 | edac_dbg(1, "\n"); |
447 | 460 | ||
461 | /* If we're not yet registered with sysfs free only what was allocated | ||
462 | * in edac_mc_alloc(). | ||
463 | */ | ||
464 | if (!device_is_registered(&mci->dev)) { | ||
465 | _edac_mc_free(mci); | ||
466 | return; | ||
467 | } | ||
468 | |||
448 | /* the mci instance is freed here, when the sysfs object is dropped */ | 469 | /* the mci instance is freed here, when the sysfs object is dropped */ |
449 | edac_unregister_sysfs(mci); | 470 | edac_unregister_sysfs(mci); |
450 | } | 471 | } |