Dynamically allocate memory for PCI devices
authorMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 5 Sep 2009 03:52:11 +0000 (00:52 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 10 May 2010 14:44:58 +0000 (11:44 -0300)
Instead of using a static table assuming always 2 CPU sockets, allocate
space dynamically for Nehalem PCI devs.

This patch is part of a series of patches that changes i7core_edac to
allow more than 2 sockets and to properly report one memory controller
per socket.

drivers/edac/i7core_edac.c

index af222ff..7bcb599 100644 (file)
@@ -192,10 +192,9 @@ struct i7core_channel {
 };
 
 struct pci_id_descr {
-       int             dev;
-       int             func;
-       int             dev_id;
-       struct pci_dev  *pdev[NUM_SOCKETS];
+       int                     dev;
+       int                     func;
+       int                     dev_id;
 };
 
 struct i7core_pvt {
@@ -229,6 +228,17 @@ struct i7core_pvt {
        spinlock_t              mce_lock;
 };
 
+struct i7core_dev {
+       struct list_head           list;
+
+       int socket;
+       struct pci_dev **pdev;
+};
+
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+
 /* Device name and register DID (Device ID) */
 struct i7core_dev_info {
        const char *ctl_name;   /* name for this device */
@@ -240,7 +250,7 @@ struct i7core_dev_info {
        .func = (function),                     \
        .dev_id = (device_id)
 
-struct pci_id_descr pci_devs[] = {
+struct pci_id_descr pci_dev_descr[] = {
                /* Memory controller */
        { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR)     },
        { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD)  },
@@ -275,11 +285,10 @@ struct pci_id_descr pci_devs[] = {
        { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NOCORE)  },
 
 };
-#define N_DEVS ARRAY_SIZE(pci_devs)
+#define N_DEVS ARRAY_SIZE(pci_dev_descr)
 
 /*
  *     pci_device_id   table for which devices we are looking for
- * This should match the first device at pci_devs table
  */
 static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
@@ -288,7 +297,7 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
 
 
 /* Table of devices attributes supported by this driver */
-static const struct i7core_dev_info i7core_devs[] = {
+static const struct i7core_dev_info i7core_probe_devs[] = {
        {
                .ctl_name = "i7 Core",
                .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR,
@@ -347,21 +356,37 @@ static inline int numcol(u32 col)
        return cols[col & 0x3];
 }
 
+static struct i7core_dev *get_i7core_dev(int socket)
+{
+       struct i7core_dev *i7core_dev;
+
+       list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+               if (i7core_dev->socket == socket)
+                       return i7core_dev;
+       }
+
+       return NULL;
+}
+
 /****************************************************************************
                        Memory check routines
  ****************************************************************************/
 static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
                                          unsigned func)
 {
+       struct i7core_dev *i7core_dev = get_i7core_dev(socket);
        int i;
 
+       if (!i7core_dev)
+               return NULL;
+
        for (i = 0; i < N_DEVS; i++) {
-               if (!pci_devs[i].pdev[socket])
+               if (!i7core_dev->pdev[i])
                        continue;
 
-               if (PCI_SLOT(pci_devs[i].pdev[socket]->devfn) == slot &&
-                   PCI_FUNC(pci_devs[i].pdev[socket]->devfn) == func) {
-                       return pci_devs[i].pdev[socket];
+               if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot &&
+                   PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) {
+                       return i7core_dev->pdev[i];
                }
        }
 
@@ -1153,9 +1178,18 @@ static void i7core_put_devices(void)
 {
        int i, j;
 
-       for (i = 0; i < NUM_SOCKETS; i++)
+       for (i = 0; i < NUM_SOCKETS; i++) {
+               struct i7core_dev *i7core_dev = get_i7core_dev(i);
+               if (!i7core_dev)
+                       continue;
+
                for (j = 0; j < N_DEVS; j++)
-                       pci_dev_put(pci_devs[j].pdev[i]);
+                       pci_dev_put(i7core_dev->pdev[j]);
+
+               list_del(&i7core_dev->list);
+               kfree(i7core_dev->pdev);
+               kfree(i7core_dev);
+       }
 }
 
 static void i7core_xeon_pci_fixup(void)
@@ -1168,7 +1202,7 @@ static void i7core_xeon_pci_fixup(void)
         * to detect them
         */
        pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                             pci_devs[0].dev_id, NULL);
+                             pci_dev_descr[0].dev_id, NULL);
        if (unlikely(!pdev)) {
                for (i = 0; i < NUM_SOCKETS; i ++)
                        pcibios_scan_specific_bus(255-i);
@@ -1183,19 +1217,21 @@ static void i7core_xeon_pci_fixup(void)
  */
 int i7core_get_onedevice(struct pci_dev **prev, int devno)
 {
+       struct i7core_dev *i7core_dev;
+
        struct pci_dev *pdev = NULL;
        u8 bus = 0;
        u8 socket = 0;
 
        pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                             pci_devs[devno].dev_id, *prev);
+                             pci_dev_descr[devno].dev_id, *prev);
 
        /*
         * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
         * is at addr 8086:2c40, instead of 8086:2c41. So, we need
         * to probe for the alternate address in case of failure
         */
-       if (pci_devs[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev)
+       if (pci_dev_descr[devno].dev_id == PCI_DEVICE_ID_INTEL_I7_NOCORE && !pdev)
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_I7_NOCORE_ALT, *prev);
 
@@ -1209,15 +1245,15 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno)
                 * Dev 3 function 2 only exists on chips with RDIMMs
                 * so, it is ok to not found it
                 */
-               if ((pci_devs[devno].dev == 3) && (pci_devs[devno].func == 2)) {
+               if ((pci_dev_descr[devno].dev == 3) && (pci_dev_descr[devno].func == 2)) {
                        *prev = pdev;
                        return 0;
                }
 
                i7core_printk(KERN_ERR,
                        "Device not found: dev %02x.%d PCI ID %04x:%04x\n",
-                       pci_devs[devno].dev, pci_devs[devno].func,
-                       PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id);
+                       pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
+                       PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
 
                /* End of list, leave */
                return -ENODEV;
@@ -1229,37 +1265,40 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno)
        else
                socket = 255 - bus;
 
-       if (socket >= NUM_SOCKETS) {
-               i7core_printk(KERN_ERR,
-                       "Unexpected socket for "
-                       "dev %02x:%02x.%d PCI ID %04x:%04x\n",
-                       bus, pci_devs[devno].dev, pci_devs[devno].func,
-                       PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id);
-               pci_dev_put(pdev);
-               return -ENODEV;
+       i7core_dev = get_i7core_dev(socket);
+       if (!i7core_dev) {
+               i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
+               if (!i7core_dev)
+                       return -ENOMEM;
+               i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * N_DEVS,
+                                          GFP_KERNEL);
+               if (!i7core_dev->pdev)
+                       return -ENOMEM;
+               i7core_dev->socket = socket;
+               list_add_tail(&i7core_dev->list, &i7core_edac_list);
        }
 
-       if (pci_devs[devno].pdev[socket]) {
+       if (i7core_dev->pdev[devno]) {
                i7core_printk(KERN_ERR,
                        "Duplicated device for "
                        "dev %02x:%02x.%d PCI ID %04x:%04x\n",
-                       bus, pci_devs[devno].dev, pci_devs[devno].func,
-                       PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id);
+                       bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
+                       PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
                pci_dev_put(pdev);
                return -ENODEV;
        }
 
-       pci_devs[devno].pdev[socket] = pdev;
+       i7core_dev->pdev[devno] = pdev;
 
        /* Sanity check */
-       if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[devno].dev ||
-                       PCI_FUNC(pdev->devfn) != pci_devs[devno].func)) {
+       if (unlikely(PCI_SLOT(pdev->devfn) != pci_dev_descr[devno].dev ||
+                       PCI_FUNC(pdev->devfn) != pci_dev_descr[devno].func)) {
                i7core_printk(KERN_ERR,
                        "Device PCI ID %04x:%04x "
                        "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n",
-                       PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id,
+                       PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id,
                        bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                       bus, pci_devs[devno].dev, pci_devs[devno].func);
+                       bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func);
                return -ENODEV;
        }
 
@@ -1268,27 +1307,29 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno)
                i7core_printk(KERN_ERR,
                        "Couldn't enable "
                        "dev %02x:%02x.%d PCI ID %04x:%04x\n",
-                       bus, pci_devs[devno].dev, pci_devs[devno].func,
-                       PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id);
+                       bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
+                       PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
                return -ENODEV;
        }
 
        i7core_printk(KERN_INFO,
                        "Registered socket %d "
                        "dev %02x:%02x.%d PCI ID %04x:%04x\n",
-                       socket, bus, pci_devs[devno].dev, pci_devs[devno].func,
-                       PCI_VENDOR_ID_INTEL, pci_devs[devno].dev_id);
+                       socket, bus, pci_dev_descr[devno].dev, pci_dev_descr[devno].func,
+                       PCI_VENDOR_ID_INTEL, pci_dev_descr[devno].dev_id);
 
        *prev = pdev;
 
        return 0;
 }
 
-static int i7core_get_devices(void)
+static int i7core_get_devices(u8 *sockets)
 {
        int i;
        struct pci_dev *pdev = NULL;
+       struct i7core_dev *i7core_dev = NULL;
 
+       *sockets = 0;
        for (i = 0; i < N_DEVS; i++) {
                pdev = NULL;
                do {
@@ -1298,6 +1339,12 @@ static int i7core_get_devices(void)
                        }
                } while (pdev);
        }
+
+       list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+               if (i7core_dev->socket + 1 > *sockets)
+                       *sockets = i7core_dev->socket + 1;
+       }
+
        return 0;
 }
 
@@ -1307,11 +1354,15 @@ static int mci_bind_devs(struct mem_ctl_info *mci)
        struct pci_dev *pdev;
        int i, j, func, slot;
 
-
        for (i = 0; i < pvt->sockets; i++) {
+               struct i7core_dev *i7core_dev = get_i7core_dev(i);
+
+               if (!i7core_dev)
+                       continue;
+
                pvt->is_registered[i] = 0;
                for (j = 0; j < N_DEVS; j++) {
-                       pdev = pci_devs[j].pdev[i];
+                       pdev = i7core_dev->pdev[j];
                        if (!pdev)
                                continue;
 
@@ -1723,20 +1774,17 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
        int rc, i;
        u8 sockets;
 
-       if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs)))
+       /*
+        * FIXME: All memory controllers are allocated at the first pass.
+        */
+       if (unlikely(dev_idx >= 1))
                return -EINVAL;
 
        /* get the pci devices we want to reserve for our use */
-       rc = i7core_get_devices();
+       mutex_lock(&i7core_edac_lock);
+       rc = i7core_get_devices(&sockets);
        if (unlikely(rc < 0))
-               return rc;
-
-       sockets = 1;
-       for (i = NUM_SOCKETS - 1; i > 0; i--)
-               if (pci_devs[0].pdev[i]) {
-                       sockets = i + 1;
-                       break;
-               }
+               goto fail0;
 
        for (i = 0; i < sockets; i++) {
                int channels;
@@ -1745,7 +1793,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
                /* Check the number of active and not disabled channels */
                rc = i7core_get_active_channels(i, &channels, &csrows);
                if (unlikely(rc < 0))
-                       goto fail0;
+                       goto fail1;
 
                num_channels += channels;
                num_csrows += csrows;
@@ -1755,7 +1803,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
        mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
        if (unlikely(!mci)) {
                rc = -ENOMEM;
-               goto fail0;
+               goto fail1;
        }
 
        debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
@@ -1776,7 +1824,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
        mci->edac_cap = EDAC_FLAG_NONE;
        mci->mod_name = "i7core_edac.c";
        mci->mod_ver = I7CORE_REVISION;
-       mci->ctl_name = i7core_devs[dev_idx].ctl_name;
+       mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name;
        mci->dev_name = pci_name(pdev);
        mci->ctl_page_to_phys = NULL;
        mci->mc_driver_sysfs_attributes = i7core_inj_attrs;
@@ -1786,7 +1834,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
        /* Store pci devices at mci for faster access */
        rc = mci_bind_devs(mci);
        if (unlikely(rc < 0))
-               goto fail1;
+               goto fail2;
 
        /* Get dimm basic config */
        for (i = 0; i < sockets; i++)
@@ -1801,7 +1849,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
                 */
 
                rc = -EINVAL;
-               goto fail1;
+               goto fail2;
        }
 
        /* allocating generic PCI control info */
@@ -1832,18 +1880,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev,
        if (unlikely(rc < 0)) {
                debugf0("MC: " __FILE__
                        ": %s(): failed edac_mce_register()\n", __func__);
-               goto fail1;
+               goto fail2;
        }
 
        i7core_printk(KERN_INFO, "Driver loaded.\n");
 
+       mutex_unlock(&i7core_edac_lock);
        return 0;
 
-fail1:
+fail2:
        edac_mc_free(mci);
 
-fail0:
+fail1:
        i7core_put_devices();
+fail0:
+       mutex_unlock(&i7core_edac_lock);
        return rc;
 }
 
@@ -1871,7 +1922,9 @@ static void __devexit i7core_remove(struct pci_dev *pdev)
        edac_mce_unregister(&pvt->edac_mce);
 
        /* retrieve references to resources, and free those resources */
+       mutex_lock(&i7core_edac_lock);
        i7core_put_devices();
+       mutex_unlock(&i7core_edac_lock);
 
        edac_mc_free(mci);
 }