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;
                !!(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) && !csrow_enabled(i, 1, pvt)) {
                        debugf1("----CSROW %d EMPTY for node %d\n", i,
                        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;
                }
        }
 
 
                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);
                }
                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);
                }
        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,
 
 static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 {
        struct cell_edac_priv           *priv = mci->pvt_info;
-       struct csrow_info               *csrow = &mci->csrows[0];
+       struct csrow_info               *csrow = mci->csrows[0];
        unsigned long                   address, pfn, offset, syndrome;
 
        dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
 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",
 
 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;
                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;
 
                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;
                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;
        *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;
 #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;
 
        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);
                } 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;
 
        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. */
                        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 */
 
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer *layer;
-       struct csrow_info *csi, *csr;
-       struct rank_info *chi, *chp, *chan;
+       struct csrow_info *csr;
+       struct rank_info *chan;
        struct dimm_info *dimm;
        u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
        unsigned pos[EDAC_MAX_LAYERS];
        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, row, chn, n, len;
+       int i, j, row, chn, n, len, off;
        bool per_rank = false;
 
        BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
         */
        mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
        layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
-       csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows);
-       chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_channels);
-       dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms);
        for (i = 0; i < n_layers; i++) {
                count *= layers[i].size;
                debugf4("%s: errcount layer %d size %d\n", __func__, i, count);
                tot_dimms,
                per_rank ? "ranks" : "dimms",
                tot_csrows * tot_channels);
+
        mci = kzalloc(size, GFP_KERNEL);
        if (mci == NULL)
                return NULL;
         * rather than an imaginary chunk of memory located at address 0.
         */
        layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
-       csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
-       chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
-       dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
        for (i = 0; i < n_layers; i++) {
                mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
                mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i]));
 
        /* setup index and various internal pointers */
        mci->mc_idx = mc_num;
-       mci->csrows = csi;
-       mci->dimms  = dimm;
        mci->tot_dimms = tot_dimms;
        mci->pvt_info = pvt;
        mci->n_layers = n_layers;
        mci->mem_is_per_rank = per_rank;
 
        /*
-        * Fill the csrow struct
+        * Alocate and fill the csrow/channels structs
         */
+       mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL);
+       if (!mci->csrows)
+               goto error;
        for (row = 0; row < tot_csrows; row++) {
-               csr = &csi[row];
+               csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL);
+               if (!csr)
+                       goto error;
+               mci->csrows[row] = csr;
                csr->csrow_idx = row;
                csr->mci = mci;
                csr->nr_channels = tot_channels;
-               chp = &chi[row * tot_channels];
-               csr->channels = chp;
+               csr->channels = kcalloc(sizeof(*csr->channels), tot_channels,
+                                       GFP_KERNEL);
+               if (!csr->channels)
+                       goto error;
 
                for (chn = 0; chn < tot_channels; chn++) {
-                       chan = &chp[chn];
+                       chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL);
+                       if (!chan)
+                               goto error;
+                       csr->channels[chn] = chan;
                        chan->chan_idx = chn;
                        chan->csrow = csr;
                }
        }
 
        /*
-        * Fill the dimm struct
+        * Allocate and fill the dimm structs
         */
+       mci->dimms  = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL);
+       if (!mci->dimms)
+               goto error;
+
        memset(&pos, 0, sizeof(pos));
        row = 0;
        chn = 0;
        debugf4("%s: initializing %d %s\n", __func__, tot_dimms,
                per_rank ? "ranks" : "dimms");
        for (i = 0; i < tot_dimms; i++) {
-               chan = &csi[row].channels[chn];
-               dimm = EDAC_DIMM_PTR(layer, mci->dimms, n_layers,
-                              pos[0], pos[1], pos[2]);
+               chan = mci->csrows[row]->channels[chn];
+               off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]);
+               if (off < 0 || off >= tot_dimms) {
+                       edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access\n");
+                       goto error;
+               }
+
+               dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL);
+               mci->dimms[off] = dimm;
                dimm->mci = mci;
 
-               debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__,
-                       i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
+               debugf2("%s: %d: %s%i (%d:%d:%d): row %d, chan %d\n", __func__,
+                       i, per_rank ? "rank" : "dimm", off,
                        pos[0], pos[1], pos[2], row, chn);
 
                /*
         */
 
        return mci;
+
+error:
+       if (mci->dimms) {
+               for (i = 0; i < tot_dimms; i++)
+                       kfree(mci->dimms[i]);
+               kfree(mci->dimms);
+       }
+       if (mci->csrows) {
+               for (chn = 0; chn < tot_channels; chn++) {
+                       csr = mci->csrows[chn];
+                       if (csr) {
+                               for (chn = 0; chn < tot_channels; chn++)
+                                       kfree(csr->channels[chn]);
+                               kfree(csr);
+                       }
+                       kfree(mci->csrows[i]);
+               }
+               kfree(mci->csrows);
+       }
+       kfree(mci);
+
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
 {
        debugf1("%s()\n", __func__);
 
+       /* the mci instance is freed here, when the sysfs object is dropped */
        edac_unregister_sysfs(mci);
-
-       /* free the mci instance memory here */
-       kfree(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
                for (i = 0; i < mci->nr_csrows; i++) {
                        int j;
 
-                       edac_mc_dump_csrow(&mci->csrows[i]);
-                       for (j = 0; j < mci->csrows[i].nr_channels; j++)
-                               edac_mc_dump_channel(&mci->csrows[i].
-                                               channels[j]);
+                       edac_mc_dump_csrow(mci->csrows[i]);
+                       for (j = 0; j < mci->csrows[i]->nr_channels; j++)
+                               edac_mc_dump_channel(mci->csrows[i]->channels[j]);
                }
                for (i = 0; i < mci->tot_dimms; i++)
-                       edac_mc_dump_dimm(&mci->dimms[i]);
+                       edac_mc_dump_dimm(mci->dimms[i]);
        }
 #endif
        mutex_lock(&mem_ctls_mutex);
 /* FIXME - should return -1 */
 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 {
-       struct csrow_info *csrows = mci->csrows;
+       struct csrow_info **csrows = mci->csrows;
        int row, i, j, n;
 
        debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page);
        row = -1;
 
        for (i = 0; i < mci->nr_csrows; i++) {
-               struct csrow_info *csrow = &csrows[i];
+               struct csrow_info *csrow = csrows[i];
                n = 0;
                for (j = 0; j < csrow->nr_channels; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
                        n += dimm->nr_pages;
                }
                if (n == 0)
        p = label;
        *p = '\0';
        for (i = 0; i < mci->tot_dimms; i++) {
-               struct dimm_info *dimm = &mci->dimms[i];
+               struct dimm_info *dimm = mci->dimms[i];
 
                if (top_layer >= 0 && top_layer != dimm->location[0])
                        continue;
                        strcpy(label, "unknown memory");
                if (type == HW_EVENT_ERR_CORRECTED) {
                        if (row >= 0) {
-                               mci->csrows[row].ce_count++;
+                               mci->csrows[row]->ce_count++;
                                if (chan >= 0)
-                                       mci->csrows[row].channels[chan].ce_count++;
+                                       mci->csrows[row]->channels[chan]->ce_count++;
                        }
                } else
                        if (row >= 0)
-                               mci->csrows[row].ue_count++;
+                               mci->csrows[row]->ue_count++;
        }
 
        /* Fill the RAM location data */
 
                  &edac_mc_poll_msec, 0644);
 MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
 
-static struct device mci_pdev;
+static struct device *mci_pdev;
 
 /*
  * various constants for Memory Controllers
        u32 nr_pages = 0;
 
        for (i = 0; i < csrow->nr_channels; i++)
-               nr_pages += csrow->channels[i].dimm->nr_pages;
+               nr_pages += csrow->channels[i]->dimm->nr_pages;
        return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
 }
 
 {
        struct csrow_info *csrow = to_csrow(dev);
 
-       return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]);
+       return sprintf(data, "%s\n", mem_types[csrow->channels[0]->dimm->mtype]);
 }
 
 static ssize_t csrow_dev_type_show(struct device *dev,
 {
        struct csrow_info *csrow = to_csrow(dev);
 
-       return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]);
+       return sprintf(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]);
 }
 
 static ssize_t csrow_edac_mode_show(struct device *dev,
 {
        struct csrow_info *csrow = to_csrow(dev);
 
-       return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]);
+       return sprintf(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]);
 }
 
 /* show/store functions for DIMM Label attributes */
 {
        struct csrow_info *csrow = to_csrow(dev);
        unsigned chan = to_channel(mattr);
-       struct rank_info *rank = &csrow->channels[chan];
+       struct rank_info *rank = csrow->channels[chan];
 
        /* if field has not been initialized, there is nothing to send */
        if (!rank->dimm->label[0])
 {
        struct csrow_info *csrow = to_csrow(dev);
        unsigned chan = to_channel(mattr);
-       struct rank_info *rank = &csrow->channels[chan];
+       struct rank_info *rank = csrow->channels[chan];
 
        ssize_t max_size = 0;
 
 {
        struct csrow_info *csrow = to_csrow(dev);
        unsigned chan = to_channel(mattr);
-       struct rank_info *rank = &csrow->channels[chan];
+       struct rank_info *rank = csrow->channels[chan];
 
        return sprintf(data, "%u\n", rank->ce_count);
 }
        NULL
 };
 
-static void csrow_attr_release(struct device *device)
+static void csrow_attr_release(struct device *dev)
 {
-       debugf1("Releasing csrow device %s\n", dev_name(device));
+       struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
+
+       debugf1("Releasing csrow device %s\n", dev_name(dev));
+       kfree(csrow);
 }
 
 static struct device_type csrow_attr_type = {
        int chan, nr_pages = 0;
 
        for (chan = 0; chan < csrow->nr_channels; chan++)
-               nr_pages += csrow->channels[chan].dimm->nr_pages;
+               nr_pages += csrow->channels[chan]->dimm->nr_pages;
 
        return nr_pages;
 }
 
        for (chan = 0; chan < csrow->nr_channels; chan++) {
                /* Only expose populated DIMMs */
-               if (!csrow->channels[chan].dimm->nr_pages)
+               if (!csrow->channels[chan]->dimm->nr_pages)
                        continue;
                err = device_create_file(&csrow->dev,
                                         dynamic_csrow_dimm_attr[chan]);
        struct csrow_info *csrow;
 
        for (i = 0; i < mci->nr_csrows; i++) {
-               csrow = &mci->csrows[i];
+               csrow = mci->csrows[i];
                if (!nr_pages_per_csrow(csrow))
                        continue;
-               err = edac_create_csrow_object(mci, &mci->csrows[i], i);
+               err = edac_create_csrow_object(mci, mci->csrows[i], i);
                if (err < 0)
                        goto error;
        }
 
 error:
        for (--i; i >= 0; i--) {
-               csrow = &mci->csrows[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)
+                       if (!csrow->channels[chan]->dimm->nr_pages)
                                continue;
                        device_remove_file(&csrow->dev,
                                                dynamic_csrow_dimm_attr[chan]);
                        device_remove_file(&csrow->dev,
                                                dynamic_csrow_ce_count_attr[chan]);
                }
-               put_device(&mci->csrows[i].dev);
+               put_device(&mci->csrows[i]->dev);
        }
 
        return err;
        struct csrow_info *csrow;
 
        for (i = mci->nr_csrows - 1; i >= 0; i--) {
-               csrow = &mci->csrows[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)
+                       if (!csrow->channels[chan]->dimm->nr_pages)
                                continue;
                        debugf1("Removing csrow %d channel %d sysfs nodes\n",
                                i, chan);
                        device_remove_file(&csrow->dev,
                                                dynamic_csrow_ce_count_attr[chan]);
                }
-               put_device(&mci->csrows[i].dev);
-               device_del(&mci->csrows[i].dev);
+               put_device(&mci->csrows[i]->dev);
+               device_del(&mci->csrows[i]->dev);
        }
 }
 #endif
        NULL
 };
 
-static void dimm_attr_release(struct device *device)
+static void dimm_attr_release(struct device *dev)
 {
-       debugf1("Releasing dimm device %s\n", dev_name(device));
+       struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
+
+       debugf1("Releasing dimm device %s\n", dev_name(dev));
+       kfree(dimm);
 }
 
 static struct device_type dimm_attr_type = {
        mci->ce_noinfo_count = 0;
 
        for (row = 0; row < mci->nr_csrows; row++) {
-               struct csrow_info *ri = &mci->csrows[row];
+               struct csrow_info *ri = mci->csrows[row];
 
                ri->ue_count = 0;
                ri->ce_count = 0;
 
                for (chan = 0; chan < ri->nr_channels; chan++)
-                       ri->channels[chan].ce_count = 0;
+                       ri->channels[chan]->ce_count = 0;
        }
 
        cnt = 1;
        int total_pages = 0, csrow_idx, j;
 
        for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
-               struct csrow_info *csrow = &mci->csrows[csrow_idx];
+               struct csrow_info *csrow = mci->csrows[csrow_idx];
 
                for (j = 0; j < csrow->nr_channels; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
 
                        total_pages += dimm->nr_pages;
                }
        NULL
 };
 
-static void mci_attr_release(struct device *device)
+static void mci_attr_release(struct device *dev)
 {
-       debugf1("Releasing mci device %s\n", dev_name(device));
+       struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
+
+       debugf1("Releasing csrow device %s\n", dev_name(dev));
+       kfree(mci);
 }
 
 static struct device_type mci_attr_type = {
 {
        int i, err;
 
-       debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+       /*
+        * The memory controller needs its own bus, in order to avoid
+        * namespace conflicts at /sys/bus/edac.
+        */
+       mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+       if (!mci->bus.name)
+               return -ENOMEM;
+       debugf0("creating bus %s\n",mci->bus.name);
+       err = bus_register(&mci->bus);
+       if (err < 0)
+               return err;
 
        /* get the /sys/devices/system/edac subsys reference */
-
        mci->dev.type = &mci_attr_type;
        device_initialize(&mci->dev);
 
-       mci->dev.parent = &mci_pdev;
+       mci->dev.parent = mci_pdev;
        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);
         * Create the dimm/rank devices
         */
        for (i = 0; i < mci->tot_dimms; i++) {
-               struct dimm_info *dimm = &mci->dimms[i];
+               struct dimm_info *dimm = mci->dimms[i];
                /* Only expose populated DIMMs */
                if (dimm->nr_pages == 0)
                        continue;
 
 fail:
        for (i--; i >= 0; i--) {
-               struct dimm_info *dimm = &mci->dimms[i];
+               struct dimm_info *dimm = mci->dimms[i];
                if (dimm->nr_pages == 0)
                        continue;
                put_device(&dimm->dev);
 #endif
 
        for (i = 0; i < mci->tot_dimms; i++) {
-               struct dimm_info *dimm = &mci->dimms[i];
+               struct dimm_info *dimm = mci->dimms[i];
                if (dimm->nr_pages == 0)
                        continue;
                debugf0("%s(): removing device %s\n", __func__,
        kfree(mci->bus.name);
 }
 
-static void mc_attr_release(struct device *device)
+static void mc_attr_release(struct device *dev)
 {
-       debugf1("Releasing device %s\n", dev_name(device));
+       /*
+        * There's no container structure here, as this is just the mci
+        * parent device, used to create the /sys/devices/mc sysfs node.
+        * So, there are no attributes on it.
+        */
+       debugf1("Releasing device %s\n", dev_name(dev));
+       kfree(dev);
 }
 
 static struct device_type mc_attr_type = {
                return -EINVAL;
        }
 
-       mci_pdev.bus = edac_subsys;
-       mci_pdev.type = &mc_attr_type;
-       device_initialize(&mci_pdev);
-       dev_set_name(&mci_pdev, "mc");
+       mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
+
+       mci_pdev->bus = edac_subsys;
+       mci_pdev->type = &mc_attr_type;
+       device_initialize(mci_pdev);
+       dev_set_name(mci_pdev, "mc");
 
-       err = device_add(&mci_pdev);
+       err = device_add(mci_pdev);
        if (err < 0)
                return err;
 
+       debugf0("device %s created\n", dev_name(mci_pdev));
+
        return 0;
 }
 
 void __exit edac_mc_sysfs_exit(void)
 {
-       put_device(&mci_pdev);
-       device_del(&mci_pdev);
+       put_device(mci_pdev);
+       device_del(mci_pdev);
        edac_put_sysfs_subsys();
 }
 
        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;
        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);
                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;
 
         */
        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,
                        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;
 
 
                        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);
 
         * 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);
 }
 
        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",
 
 
        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,
         * 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) <<
 
 {
        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;
         */
 
        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);
                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 */
 
                        (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,
         */
 
        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));
                 */
                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 */
 
        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;
        }
                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));
 
 
        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;
 
        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);
 }
 
        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),
 
        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);
 
  */
 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) !=
 
         */
        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,
                        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;
 
 #define EDAC_MAX_LAYERS                3
 
 /**
- * EDAC_DIMM_PTR - Macro responsible to find a pointer inside a pointer array
+ * EDAC_DIMM_OFF - Macro responsible to get a pointer offset inside a pointer array
  *                for the element given by [layer0,layer1,layer2] position
  *
  * @layers:    a struct edac_mc_layer array, describing how many elements
  *             were allocated for each layer
- * @var:       name of the var where we want to get the pointer
- *             (like mci->dimms)
  * @n_layers:  Number of layers at the @layers array
  * @layer0:    layer0 position
  * @layer1:    layer1 position. Unused if n_layers < 2
  * @layer2:    layer2 position. Unused if n_layers < 3
  *
- * For 1 layer, this macro returns &var[layer0]
+ * For 1 layer, this macro returns &var[layer0] - &var
  * For 2 layers, this macro is similar to allocate a bi-dimensional array
- *             and to return "&var[layer0][layer1]"
+ *             and to return "&var[layer0][layer1] - &var"
  * For 3 layers, this macro is similar to allocate a tri-dimensional array
- *             and to return "&var[layer0][layer1][layer2]"
+ *             and to return "&var[layer0][layer1][layer2] - &var"
  *
  * A loop could be used here to make it more generic, but, as we only have
  * 3 layers, this is a little faster.
  * a NULL is returned, causing an OOPS during the memory allocation routine,
  * with would point to the developer that he's doing something wrong.
  */
-#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \
-       typeof(var) __p;                                                \
+#define EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2) ({              \
+       int __i;                                                        \
        if ((nlayers) == 1)                                             \
-               __p = &var[layer0];                                     \
+               __i = layer0;                                           \
        else if ((nlayers) == 2)                                        \
-               __p = &var[(layer1) + ((layers[1]).size * (layer0))];   \
+               __i = (layer1) + ((layers[1]).size * (layer0));         \
        else if ((nlayers) == 3)                                        \
-               __p = &var[(layer2) + ((layers[2]).size * ((layer1) +   \
-                           ((layers[1]).size * (layer0))))];           \
+               __i = (layer2) + ((layers[2]).size * ((layer1) +        \
+                           ((layers[1]).size * (layer0))));            \
        else                                                            \
+               __i = -EINVAL;                                          \
+       __i;                                                            \
+})
+
+/**
+ * EDAC_DIMM_PTR - Macro responsible to get a pointer inside a pointer array
+ *                for the element given by [layer0,layer1,layer2] position
+ *
+ * @layers:    a struct edac_mc_layer array, describing how many elements
+ *             were allocated for each layer
+ * @var:       name of the var where we want to get the pointer
+ *             (like mci->dimms)
+ * @n_layers:  Number of layers at the @layers array
+ * @layer0:    layer0 position
+ * @layer1:    layer1 position. Unused if n_layers < 2
+ * @layer2:    layer2 position. Unused if n_layers < 3
+ *
+ * For 1 layer, this macro returns &var[layer0]
+ * For 2 layers, this macro is similar to allocate a bi-dimensional array
+ *             and to return "&var[layer0][layer1]"
+ * For 3 layers, this macro is similar to allocate a tri-dimensional array
+ *             and to return "&var[layer0][layer1][layer2]"
+ */
+#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \
+       typeof(*var) __p;                                               \
+       int ___i = EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2);      \
+       if (___i < 0)                                                   \
                __p = NULL;                                             \
+       else                                                            \
+               __p = (var)[___i];                                      \
        __p;                                                            \
 })
 
  *       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;
 
        /* channel information for this csrow */
        u32 nr_channels;
-       struct rank_info *channels;
+       struct rank_info **channels;
 };
 
 /*
        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;
 
        /*
         * 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