Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66607706 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

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.
parent a55456f3
Loading
Loading
Loading
Loading
+114 −61
Original line number Diff line number Diff line
@@ -195,7 +195,6 @@ struct pci_id_descr {
	int			dev;
	int			func;
	int 			dev_id;
	struct pci_dev	*pdev[NUM_SOCKETS];
};

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);
}