drivers/xen/xen-pciback/pci_stub.c

Source file repositories/reference/linux-study-clean/drivers/xen/xen-pciback/pci_stub.c

File Facts

System
Linux kernel
Corpus path
drivers/xen/xen-pciback/pci_stub.c
Extension
.c
Size
43859 bytes
Lines
1767
Domain
Driver Families
Bucket
drivers/xen
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static struct pci_driver xen_pcibk_pci_driver;

/* Called when 'bind'. This means we must _NOT_ call pci_reset_function or
 * other functions that take the sysfs lock. */
static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	int err = 0, match;
	struct pcistub_device_id *pci_dev_id = NULL;

	dev_dbg(&dev->dev, "probing...\n");

	match = pcistub_match(dev);

	if (device_match_driver_override(&dev->dev,
					 &xen_pcibk_pci_driver.driver) > 0 ||
	    match) {

		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
			dev_err(&dev->dev, "can't export pci devices that "
				"don't have a normal (0) or bridge (1) "
				"header type!\n");
			err = -ENODEV;
			goto out;
		}

		if (!match) {
			pci_dev_id = kmalloc_obj(*pci_dev_id);
			if (!pci_dev_id) {
				err = -ENOMEM;
				goto out;
			}
		}

		dev_info(&dev->dev, "seizing device\n");
		err = pcistub_seize(dev, pci_dev_id);
	} else
		/* Didn't find the device */
		err = -ENODEV;

out:
	return err;
}

/* Called when 'unbind'. This means we must _NOT_ call pci_reset_function or
 * other functions that take the sysfs lock. */
static void pcistub_remove(struct pci_dev *dev)
{
	struct pcistub_device *psdev, *found_psdev = NULL;
	unsigned long flags;

	dev_dbg(&dev->dev, "removing\n");

	spin_lock_irqsave(&pcistub_devices_lock, flags);

	xen_pcibk_config_quirk_release(dev);

	list_for_each_entry(psdev, &pcistub_devices, dev_list) {
		if (psdev->dev == dev) {
			found_psdev = psdev;
			break;
		}
	}

	spin_unlock_irqrestore(&pcistub_devices_lock, flags);

	if (found_psdev) {
		dev_dbg(&dev->dev, "found device to remove %s\n",
			found_psdev->pdev ? "- in-use" : "");

		if (found_psdev->pdev) {
			int domid = xen_find_device_domain_owner(dev);

			dev_warn(&dev->dev, "****** removing device %s while still in-use by domain %d! ******\n",
			       pci_name(found_psdev->dev), domid);
			dev_warn(&dev->dev, "****** driver domain may still access this device's i/o resources!\n");
			dev_warn(&dev->dev, "****** shutdown driver domain before binding device\n");
			dev_warn(&dev->dev, "****** to other drivers or domains\n");

			/* N.B. This ends up calling pcistub_put_pci_dev which ends up
			 * doing the FLR. */
			xen_pcibk_release_pci_dev(found_psdev->pdev,
						found_psdev->dev,
						false /* caller holds the lock. */);
		}

		spin_lock_irqsave(&pcistub_devices_lock, flags);
		list_del(&found_psdev->dev_list);
		spin_unlock_irqrestore(&pcistub_devices_lock, flags);

Annotation

Implementation Notes