static int i7core_get_onedevice()

in i7core_edac.c [1304:1420]


static int i7core_get_onedevice(struct pci_dev **prev,
				const struct pci_id_table *table,
				const unsigned devno,
				const unsigned last_bus)
{
	struct i7core_dev *i7core_dev;
	const struct pci_id_descr *dev_descr = &table->descr[devno];

	struct pci_dev *pdev = NULL;
	u8 bus = 0;
	u8 socket = 0;

	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
			      dev_descr->dev_id, *prev);

	/*
	 * On Xeon 55xx, the Intel QuickPath 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 (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
		pci_dev_get(*prev);	/* pci_get_device will put it */
		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
				      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
	}

	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
	    !pdev) {
		pci_dev_get(*prev);	/* pci_get_device will put it */
		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
				      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
				      *prev);
	}

	if (!pdev) {
		if (*prev) {
			*prev = pdev;
			return 0;
		}

		if (dev_descr->optional)
			return 0;

		if (devno == 0)
			return -ENODEV;

		i7core_printk(KERN_INFO,
			"Device not found: dev %02x.%d PCI ID %04x:%04x\n",
			dev_descr->dev, dev_descr->func,
			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);

		/* End of list, leave */
		return -ENODEV;
	}
	bus = pdev->bus->number;

	socket = last_bus - bus;

	i7core_dev = get_i7core_dev(socket);
	if (!i7core_dev) {
		i7core_dev = alloc_i7core_dev(socket, table);
		if (!i7core_dev) {
			pci_dev_put(pdev);
			return -ENOMEM;
		}
	}

	if (i7core_dev->pdev[devno]) {
		i7core_printk(KERN_ERR,
			"Duplicated device for "
			"dev %02x:%02x.%d PCI ID %04x:%04x\n",
			bus, dev_descr->dev, dev_descr->func,
			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
		pci_dev_put(pdev);
		return -ENODEV;
	}

	i7core_dev->pdev[devno] = pdev;

	/* Sanity check */
	if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
			PCI_FUNC(pdev->devfn) != dev_descr->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, dev_descr->dev_id,
			bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
			bus, dev_descr->dev, dev_descr->func);
		return -ENODEV;
	}

	/* Be sure that the device is enabled */
	if (unlikely(pci_enable_device(pdev) < 0)) {
		i7core_printk(KERN_ERR,
			"Couldn't enable "
			"dev %02x:%02x.%d PCI ID %04x:%04x\n",
			bus, dev_descr->dev, dev_descr->func,
			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
		return -ENODEV;
	}

	edac_dbg(0, "Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
		 socket, bus, dev_descr->dev,
		 dev_descr->func,
		 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);

	/*
	 * As stated on drivers/pci/search.c, the reference count for
	 * @from is always decremented if it is not %NULL. So, as we need
	 * to get all devices up to null, we need to do a get for the device
	 */
	pci_dev_get(pdev);

	*prev = pdev;

	return 0;
}