diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-05 07:52:11 +0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-10 18:44:58 +0400 |
commit | 66607706cee7b6901aa0509198f075859c93ec6a (patch) | |
tree | b55e025bd7149ed9d00f38e596dc94e1f3909b95 /drivers/edac | |
parent | a55456f3446d19853af54b64b3840312f46b6ea5 (diff) | |
download | linux-66607706cee7b6901aa0509198f075859c93ec6a.tar.xz |
Dynamically allocate memory for PCI devices
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.
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/i7core_edac.c | 175 |
1 files changed, 114 insertions, 61 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index af222ffcfdfc..7bcb5993b501 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -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); } |