PCI_INTR_MAP(9) Kernel Developer's Manual PCI_INTR_MAP(9)

pci_intr_map, pci_intr_map_msi, pci_intr_map_msix, pci_intr_line, pci_intr_string, pci_intr_establish, pci_intr_disestablishPCI interrupts

#include <alpha/pci/pci_machdep.h>
#include <i386/pci/pci_machdep.h>
#include <powerpc/pci/pci_machdep.h>
#include <machine/pci_machdep.h>

pci_intr_map(struct pci_attach_args *paa, pci_intr_handle_t *ih);

pci_intr_map_msi(struct pci_attach_args *paa, pci_intr_handle_t *ih);

pci_intr_map_msix(struct pci_attach_args *paa, int vector, pci_intr_handle_t *ih);

pci_intr_line(pci_intr_handle_t ih);

const char *
pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih);

void *
pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, int (*func)(void *), void *arg, const char *name);

pci_intr_disestablish(pci_chipset_tag_t pc, void *v);

These functions are provided by the machine-dependent implementation for attaching handler functions to the interrupts of PCI devices.

An architect type is provided by the machine-dependent code pci_intr_handle_t, to be initialised by (), pci_intr_map_msi(), or pci_intr_map_msix().

The () function should be called first to establish a mapping between a PCI pin and the interrupt controller's interrupt vector. This process may include resolving the mapping through firmware-provided information.

For devices that support Message Signaled Interrupts (MSI) the () function should be called instead. This function can fail if the system does not support MSI. In that case pci_intr_map() should be called to fall back on classic PCI interrupts.

For devices that support Extended Message Signaled Interrupts (MSI-X) the () function can be called instead. This function can fail if the system does not support MSI-X. In that case pci_intr_map_msi() or pci_intr_map() can be called to fall back on Message Signalled Interrupts or classic PCI interrupts respectively. MSI-X can provide multiple interrupt vectors per device. For each vector, a separate call to pci_intr_map_msix() is made with the vector argument specifying which interrupt vector to map.

Having initialised the pci_intr_handle_t in the previous step, an interrupt handler can be established using (). An established interrupt handler is always called with the system interrupt priority level set equal to, or higher than, level.

A printable string representation of an initialised interrupt mapping can be generated with ().

() provides the interrupt line extracted from the MD interrupt handle. Upon device detachment, () should be used to disassociate the handler from the interrupt.

See spl(9) for an explanation of the ipl “interrupt priority levels”.

A typical code sequence for establishing a handler for a device interrupt in the driver might be:

xxxattach(struct device *parent, struct device *self, void *aux)
	struct xxx_softc *sc = (struct xxx_softc *)self;
	struct pci_attach_args *pa = aux;
	pci_intr_handle_t ih;
	const char *intrstr;
	bus_size_t size;


	if (pci_intr_map_msi(pa, &ih) && pci_intr_map(pa, &ih)) {
		printf(": can't map interrupt\n");
		bus_space_unmap(sc->iot, sc->ioh, size);
	intrstr = pci_intr_string(pa->pa_pc, ih);
	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
	    xxx_intr, sc, sc->sc_dev.dv_xname);
	if (!sc->sc_ih) {
		printf(": can't establish interrupt");
		if (intrstr)
			printf(" at %s", intrstr);
		bus_space_unmap(sc->iot, sc->ioh, size);

	printf(": %s\n", intrstr);


cardbus(4), pci(4), pcibios(4), pci_conf_read(9), spl(9)

These functions first appeared in OpenBSD 1.2.

May 1, 2021 OpenBSD 7.5