so, i discovered a "gotcha" with the existing PCI driver API for
interrupt mapping.
The typical interrupt establishment call in a pci driver front end
includes code which looks like:
if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
pa->pa_intrline, &ih)) {
printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
return;
}
pci_intr_map() is implemented by each port to figure out where the
interrupt actually emerges from the pci interrupt maze so that a
handler can be set up on the correct interrupt controller line.
Now, pci_attach_args contains *two* pci tags:
pa_tag the "real" location of the device
pa_intrtag the tag for the interrupt source.
For devices behind a pci-pci bridge, this is "swizzled"
to the bus/device/pin where the interrupt emerges through
the bridge.
So, pci_intr_map() only gets passed pa_intrtag.
On i386 hardware using the Multiprocessor spec, the BIOS-provided MP
interrupt routing tables describe interrupt sources in terms of the
"real" location (pa_tag), not the swizzled location (pa_intrtag).
It would greatly simplify things if pci_intr_map had pa->pa_tag
available to it.
Rather than bloat the interface with an additional parameter, I'd like
to take the radical step of *simplifying* it in the common case, by
changing the function signature of pci_intr_map() to:
typedef struct pci_attach_args pci_attach_args_t;
int pci_intr_map(pci_attach_args_t *pa, pci_intr_handle_t *ihp);
In the case of a hypothetical driver which has a need to do something
special, it can simply construct a "pci_attach_args" with appropriate
values and feed it to pci_intr_map. (I say hypothetical because at
the moment, it appears that all calls to pci_intr_map in NetBSD simply
pass through values which came from the same pci_attach_args.. i.e.,
no such drivers exist).
Comments?
- Bill