[openfirmware] PCI devices: IRQ table and vendor/device ID

Mitch Bradley wmb at laptop.org
Thu May 29 21:45:32 CEST 2008


Here's how PCI interrupt mapping works in OFW + x86 Linux:

The basic (Geode-independent) mechanism:

There is a platform-specific function named "assign-int-line" that lives
in the file cpu/x86/<platform>/pcinode.fth .  Its arguments are the
base PCI config address of the device/function and the interrupt pin number
(the value from the device's "interrupt pin" register at config offset 3d).
The arguments thus tell you which PCI slot and which of the four possible
PCI INTx lines from that slot.  The return value is the IRQ number.

So the purpose of "assign-int-line" is to describe the platform-specific
routing from PCI slots to CPU interrupt channels (IRQs in the legacy PC 
world).

The generic PCI probing code calls assign-int-line to determine the IRQ,
then puts the return value in the device's "interrupt line" register at 
config
offset 3c.  Linux later reads that hardware register to find the IRQ 
that the
device interrupts on.   (But see below for Geode-specific additions...)

The implementation of assign-int-line depends on how the platform hardware
routes interrupt lines to IRQs.  In the early days of PCI, motherboards 
often
had fixed routing, wiring specific PCI INT signals to specific IRQs.
Nowadays, most chipsets (including Geode) have "interrupt mapper" hardware
that lets software direct each PCI INT to a dynamically-choosable IRQ.
But even if an interrupt mapper is present, you don't have to implement
dynamic assigment.  If the system hardware configuration is fixed or has
only a small number of PCI slots, it often makes sense to simplify the
model by choosing the interrupt routing in advance, initializing the
mapper to that routing, and implementing "assign-int-line" to report the
fixed mapping.

The actual coding technique for assign-int-line could be a case statement,
a table lookup, or a dynamic assignment algorithm, depending on what
makes sense for your system.  For a very simple system, a case statement
is probably easiest.  For a moderately large PCI slot farm with fixed int
wiring, a table lookup is appropriate.  For a large system with lots of 
slots
and dynamic routing assignment, you would need the algorithmic approach
(and assign-int-line would dynamically reprogram the interrupt mapper to
reflect the dynamic assignment).


Geode-specific PCI config register spoofing:

Some of the Geode "PCI devices" aren't really PCI devices.  The graphics
display is inside the CPU chip, accessed at the hardware level via an 
internal
bus that has nothing to do with PCI.  The USB and AC97 devices are inside
the CS5536 companion chip, which is connected to the CPU chip via a
"real" PCI bus, but those devices don't really have PCI configuration 
registers
at the hardware level.

But since software is harder to change than hardware, PC operating systems
expect everything to look just like a conventional PC at the hardware level.
Geode traditionally copes with this using a magic wad of bits called "VSA".
VSA virtualizes the hardware by trapping certain I/O ports, including
the PCI config access ports, then running System Management Mode code
that emulates what PCI hardware is supposed to do.  (System Management
Mode is a special kind of trap handler that uses resources outside the 
normal
domain of the x86 instruction set.)

For OLPC, we decided not to use the VSA mechanism, because

a) Some of the VSA source code was encumbered so we didn't have access to it

b) The parts of the VSA code that we did have couldn't be compiled because
it depended on a toolchain that is no longer available

Instead of using VSA to emulate the nonexistent PCI config registers, OLPC
took advantage of the fact that the implementations of PCI configuration
access primitives are modular both in Open Firmware and in Linux.  So 
instead
of just going directly to the normal CF8/CFC I/O ports for config cycles,
we substituted a procedure that

a) For slots with "real" PCI hardware (just the CaFe chip on OLPC), it does
the normal CF8/CFC thing.

b) For other "slots" - i.e. the devices that really aren't on the PCI 
bus - it
looks up the appropriate value in a table.

The code for this alternate approach is a factor of 20 smaller than the code
for VSA-style virtualization (I know because I recently had to write the
virtualization code in order to make Windows XP run on OLPC).

There is a separate copy of this "PCI spoofing" code in OFW (vsapci.fth) 
and Linux

  http://dev.laptop.org/git?p=olpc-2.6;a=blob_plain;f=arch/x86/pci/olpc.c

The tables therein contain platform-specific base address register 
values, but the
overall structure of the tables - i.e. the list of virtualized devices 
and their static
characteristics - depends mainly on fixed characteristics of the Geode 
chipset
(but you might have to add in a device or two that OLPC doesn't use, 
such as the
IDE function).

Note that it is still possible to dynamically-assign base addresses to 
real plug-in
PCI devices, because the spoofing only applies to the Geode-internal 
devices.
Real PCI devices are accessed using the normal hardware mechanisms.

OLPC PCI config.

OLPC has no pluggable PCI slots.  Everything on the PCI bus is soldered 
down,
so dynamic configuration is pointless.  OLPC early init code stuffs a
preassigned value into the interrupt line register of the only real PCI 
device
(the CaFe chip).  The OLPC implementation of assign-int-line is just a stub
that returns the value that has already been stuffed into that interrupt 
line register.

In addition to the one real PCI device, OLPC also has the "spoofed" 
Geode PCI
devices as described above.  For those devices, the spoofing code discards
writes to the (virtual) interrupt line register (reads return the 
preassigned value
that is already in the table), so it doesn't actually matter what IRQ number
that assign-int-line returns for those devices.  (The generic PCI code calls
assign-int-line to get the IRQ number, then writes it to the interrupt line
register, but the write doesn't actually do anything.)

So the OLPC implementation of assign-int-line is not a good model for an
arbitrary PC, but it might be a useful template for Geode-based systems that
have no pluggable slots.



Andrea wrote:
> Dear OFW developers,
>
> I'm going to a "new" PCI device on our custom (Geode LX based) board.
>
> I already add standard PCI support to our build (${BP}/dev/pcibus.fth), 
> plus enabling some debugging stuff:
>
> true value pcimsg?
> true value probemsg?
>
> Is it possible to see its vendor/device ID from OFW? (we are going to 
> create a custom OFW driver soon, but it will be enough to see it IDs for 
> debugging purpose)
>
> AFAIK I also have to add "something" on PCI IRQ table to let the OS (in 
> our case Linux) to attach its driver to the right IRQ.
> I found something like that inside vsapci.fth source 
> (cpu/x86/pc/*/vsapci.fth) but it seems that this is used only for Geode 
> companion chip devices.
>
> Any clue in how enumerate and assign IRQ to PCI devices with OFW?
>
> Thanks in advance and best regards,
>
>   




More information about the openfirmware mailing list