arch/x86/pci/xen.c

Source file repositories/reference/linux-study-clean/arch/x86/pci/xen.c

File Facts

System
Linux kernel
Corpus path
arch/x86/pci/xen.c
Extension
.c
Size
14973 bytes
Lines
588
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xen_msi_ops {
	int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
	void (*teardown_msi_irqs)(struct pci_dev *dev);
};

static struct xen_msi_ops xen_msi_ops __ro_after_init;

static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
	int irq, ret, i;
	struct msi_desc *msidesc;
	int *v;

	if (type == PCI_CAP_ID_MSI && nvec > 1)
		return 1;

	v = kzalloc_objs(int, max(1, nvec));
	if (!v)
		return -ENOMEM;

	if (type == PCI_CAP_ID_MSIX)
		ret = xen_pci_frontend_enable_msix(dev, v, nvec);
	else
		ret = xen_pci_frontend_enable_msi(dev, v);
	if (ret)
		goto error;
	i = 0;
	msi_for_each_desc(msidesc, &dev->dev, MSI_DESC_NOTASSOCIATED) {
		irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
					       (type == PCI_CAP_ID_MSI) ? nvec : 1,
					       (type == PCI_CAP_ID_MSIX) ?
					       "pcifront-msi-x" :
					       "pcifront-msi",
						DOMID_SELF);
		if (irq < 0) {
			ret = irq;
			goto free;
		}
		i++;
	}
	kfree(v);
	return msi_device_populate_sysfs(&dev->dev);

error:
	if (ret == -ENOSYS)
		dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
	else if (ret)
		dev_err(&dev->dev, "Xen PCI frontend error: %d!\n", ret);
free:
	kfree(v);
	return ret;
}

static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
		struct msi_msg *msg)
{
	/*
	 * We set vector == 0 to tell the hypervisor we don't care about
	 * it, but we want a pirq setup instead.  We use the dest_id fields
	 * to pass the pirq that we want.
	 */
	memset(msg, 0, sizeof(*msg));
	msg->address_hi = X86_MSI_BASE_ADDRESS_HIGH;
	msg->arch_addr_hi.destid_8_31 = pirq >> 8;
	msg->arch_addr_lo.destid_0_7 = pirq & 0xFF;
	msg->arch_addr_lo.base_address = X86_MSI_BASE_ADDRESS_LOW;
	msg->arch_data.delivery_mode = APIC_DELIVERY_MODE_EXTINT;
}

static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
	int irq, pirq;
	struct msi_desc *msidesc;
	struct msi_msg msg;

	if (type == PCI_CAP_ID_MSI && nvec > 1)
		return 1;

	msi_for_each_desc(msidesc, &dev->dev, MSI_DESC_NOTASSOCIATED) {
		pirq = xen_allocate_pirq_msi(dev, msidesc);
		if (pirq < 0) {
			irq = -ENODEV;
			goto error;
		}
		xen_msi_compose_msg(dev, pirq, &msg);
		__pci_write_msi_msg(msidesc, &msg);
		dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
		irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
					       (type == PCI_CAP_ID_MSI) ? nvec : 1,
					       (type == PCI_CAP_ID_MSIX) ?

Annotation

Implementation Notes