arch/x86/hyperv/irqdomain.c

Source file repositories/reference/linux-study-clean/arch/x86/hyperv/irqdomain.c

File Facts

System
Linux kernel
Corpus path
arch/x86/hyperv/irqdomain.c
Extension
.c
Size
11267 bytes
Lines
429
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 rid_data {
	struct pci_dev *bridge;
	u32 rid;
};

static int get_rid_cb(struct pci_dev *pdev, u16 alias, void *data)
{
	struct rid_data *rd = data;
	u8 bus = PCI_BUS_NUM(rd->rid);

	if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus) {
		rd->bridge = pdev;
		rd->rid = alias;
	}

	return 0;
}

static union hv_device_id hv_build_devid_type_pci(struct pci_dev *pdev)
{
	int pos;
	union hv_device_id hv_devid;
	struct rid_data data = {
		.bridge = NULL,
		.rid = PCI_DEVID(pdev->bus->number, pdev->devfn)
	};

	pci_for_each_dma_alias(pdev, get_rid_cb, &data);

	hv_devid.as_uint64 = 0;
	hv_devid.device_type = HV_DEVICE_TYPE_PCI;
	hv_devid.pci.segment = pci_domain_nr(pdev->bus);

	hv_devid.pci.bdf.bus = PCI_BUS_NUM(data.rid);
	hv_devid.pci.bdf.device = PCI_SLOT(data.rid);
	hv_devid.pci.bdf.function = PCI_FUNC(data.rid);
	hv_devid.pci.source_shadow = HV_SOURCE_SHADOW_NONE;

	if (data.bridge == NULL)
		goto out;

	/*
	 * Microsoft Hypervisor requires a bus range when the bridge is
	 * running in PCI-X mode.
	 *
	 * To distinguish conventional vs PCI-X bridge, we can check
	 * the bridge's PCI-X Secondary Status Register, Secondary Bus
	 * Mode and Frequency bits. See PCI Express to PCI/PCI-X Bridge
	 * Specification Revision 1.0 5.2.2.1.3.
	 *
	 * Value zero means it is in conventional mode, otherwise it is
	 * in PCI-X mode.
	 */

	pos = pci_find_capability(data.bridge, PCI_CAP_ID_PCIX);
	if (pos) {
		u16 status;

		pci_read_config_word(data.bridge, pos + PCI_X_BRIDGE_SSTATUS,
				     &status);

		if (status & PCI_X_SSTATUS_FREQ) {
			/* Non-zero, PCI-X mode */
			u8 sec_bus, sub_bus;

			hv_devid.pci.source_shadow =
					     HV_SOURCE_SHADOW_BRIDGE_BUS_RANGE;

			pci_read_config_byte(data.bridge, PCI_SECONDARY_BUS,
					     &sec_bus);
			hv_devid.pci.shadow_bus_range.secondary_bus = sec_bus;
			pci_read_config_byte(data.bridge, PCI_SUBORDINATE_BUS,
					     &sub_bus);
			hv_devid.pci.shadow_bus_range.subordinate_bus = sub_bus;
		}
	}

out:
	return hv_devid;
}

/*
 * hv_map_msi_interrupt() - Map the MSI IRQ in the hypervisor.
 * @data:      Describes the IRQ
 * @out_entry: Hypervisor (MSI) interrupt entry (can be NULL)
 *
 * Map the IRQ in the hypervisor by issuing a MAP_DEVICE_INTERRUPT hypercall.
 *
 * Return: 0 on success, -errno on failure
 */

Annotation

Implementation Notes