Documentation Archive Developer
Search

ADC Home > Reference Library > Technical Q&As > Hardware & Drivers > Performance >

How can I tell if a PCI device has on board I/O space?


Q: How can I tell if a PCI device has onboard I/O space?

A: One way to determine if a PCI device has I/O space, or memory space for that matter, is to understand what a reg property is and how Open Firmware constructs a PCI device reg property. Here is a terse introduction.

A reg property is defined by the PCI Bus Supplement to Open Firmware. It is a required property that specifies the PCI device onboard memory requirements. In fact it is an array of individual memory spaces. PCI devices have three types of possible memory space. It is required the every PCI device support Configuration Space. Most, if not all will have Memory Space and some may have I/O Space. I/O Space supports Intel processors, hence can be found on some older types of PCI devices. Here is part of the PCI Bus supplement that shows the format of the reg property. Remember that this property will be an array of members. We will see this fact later when we decode a reg property.

2.2.1.1. Numerical Representation

(The Numerical Representation of an address is the format that Open Firmware uses for storing an address within a property value and on the stack, as an argument to a package method.) The numerical representation of a PCI address consists of three cells, encoded as follows. For this purpose, the least-significant 32 bits of a cell is used; if the cell size is larger than 32 bits, any additional high-order bits are zero. Bit# 0 refers to the least-significant bit.


         Bit#  33222222 22221111 11111100 00000000
               10987654 32109876 54321098 76543210
phys.hi cell:  npt000ss bbbbbbbb dddddfff rrrrrrrr
phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
phys.lo cell:  llllllll llllllll llllllll llllllll
where:
n is 0 if the address is relocatable, 1 otherwise
p is 1 if the addressable region is "prefetchable", 0 otherwise
t is 1 if the address is aliased (for non-relocatable I/O),
below 1 MB (for Memory),
or below 64 KB (for relocatable I/O).
ss is the space code, denoting the address space
bbbbbbbb is the 8-bit Bus Number
ddddd is the 5-bit Device Number
fff is the 3-bit Function Number
rrrrrrrr is the 8-bit Register Number
hhhhhhhh hhhhhhhh hhhhhhhh is a 32-bit unsigned number
llllllll llllllll llllllll llllllll is a 32-bit unsigned number
We now see that the numerical representation of a PCI address consists of three cells and that the ss field is the address space code. Here is that format.

Encoding of type code "ss":

00 denotes Configuration Space

01 denotes I/O Space

10 denotes 32-bit-address Memory Space

11 denotes 64-bit-address Memory Space

A reg property consists of these address cells plus two additional cells to specify the address size. Here then is that format.

reg = {1st member:    phys.hi, phys.mid, phys.lo, size.hi, size.lo
       2nd member:    phys.hi, phys.mid, phys.lo, size.hi, size.lo
            .
            .
       nth member:    phys.hi, phys.mid, phys.lo, size.hi, size.lo}
Now we are ready to find a reg property in the IORegistry using the ioreg tool from the Termimal application. The ioreg tool however yields a lot of output text which is cumbersome. Here are two examples using ioreg. The first example dumps the entire registry while the second example dumps one plane of the registry. That plane is the IODeviceTree plane which contains a reg property. Both examples are piped to the wc tool to show the amount of output.

Last login: Wed Sep 10 08:36:53 on ttyp1

Welcome to Darwin!

[flanwa:~] flansbur% ioreg | wc -l

238

[flanwa:~] flansbur% ioreg -p IODeviceTree | wc -l

73

Here is the output from the latter example which has its output snipped for brievty.

+-o Root  <class IORegistryEntry>
  +-o device-tree  <class IOPlatformExpertDevice>
    +-o chosen  <class IOService>
    | +-o memory-map  <class IOService>
    +-o memory@0  <class IOService>
    +-o openprom  <class IOService>
    | +-o client-services  <class IOService>

    |   | +-o ata-3@20000  <class AppleMacIODevice>
    |   | +-o ata-3@21000  <class AppleMacIODevice>
    |   +-o AAPL,NCR8250S@3  <class IOPCIDevice>
We will look at the AAPL,NCR8250S PCI device. In particular we want to see the properties of this device. Once again there are two ways to accomplish this. The first way is to tell ioreg to dump properties based on provider and the second is to dump properties based on device name.

[flanwa:~] flansbur% ioreg -p IODeviceTree -n AAPL,NCR8250S -w 0 | wc -l

101

[flanwa:~] flansbur% ioreg -p IODeviceTree -c IOPCIDevice -w 0 | wc -l

385

We will choose to dump on name to reduce the amount of output. But first a word about PCI names is in order. Note that in the above dump (ioreg -p IODeviceTree) the name is AAPL,NCR8250S@3, but in the above example piped to wc the name is AAPL,NCR8250S without the @3. @3 is the unit-address of the PCI device AAPL,NCR8250S. We need to append a unit-address to a name to handle the case of multiple PCI devices that are exactly the same device. Two network devices perhaps. Here is the former dump.

[flanwa:~] flansbur% ioreg -p IODeviceTree -n AAPL,NCR8250S -w 0

+-o Root  <class IORegistryEntry>
  +-o device-tree  <:class IOPlatformExpertDevice>:
    +-o chosen  <:class IOService>:
    | +-o memory-map  <:class IOService>:
    +-o memory@0  <:class IOService>:
.
.
.

    |   +-o AAPL,NCR8250S@3  <:class IOPCIDevice>:
    |   |   {
    |   |     "fcode-rom-offset" = <:00000000>:
    |   |     "IOChildIndex" = 1
    |   |     "model" = <:"8250S">:
    |   |     "reg" = <:000118000000000000000000000
00000000000000201183000000000
00000000000000000000800002011814
00000000000000000000000000000100>:
    |   |     "devsel-speed" = <:00000001>:
As you can see we have the reg property for AAPL,NCR8250S, but the output is not an array, it's a very long line of text. The text was split on three line to make it more readable. This text won't do so the next step is to turn this long line of text into an array per the reg property format. Here is the reg property reformatted. The radix is 16.

First we start with the original line from above.

"reg" = &lt:000118000000000000000000000

00000000000000201183000000000

00000000000000000000800002011814

00000000000000000000000000000100&gt:

and then remove all text but the numerics.

000118000000000000000000000

00000000000000201183000000000

00000000000000000000800002011814

00000000000000000000000000000100

Now we delimit the text into 32-bit numbers as such.

00011800|00000000|00000000|

00000000|00000000|02011830|00000000|

00000000|00000000|00008000|02011814|

00000000|00000000|00000000|00000100|

Finally, we build the array with 5 32-bit numbers per entry. Each array member has a memory description and a size. Here is the array.

phy.hi   phy.mid  phy.lo      size.hi  size.lo
00011800 00000000 00000000    00000000 00000000
02011830 00000000 00000000    00000000 00008000
02011814 00000000 00000000    00000000 00000100
So the three phy.hi hex numbers are:

00011800

02011830

02011814

and the ss space codes are, also radix 16:

00

02

02

with 00 being Configuration Space and the other two values (02) being 32-bit Memory Space. This device does not have any I/O Space on board. Had there been I/O Space the either 02011830 would have been 01011830 and/or 02011814 would have been 01011814. I.e an inclusive, not exclusive, logical OR.



[Sep 24, 2003]