decoding sparc pci addresses
By timatworkhomeandinbetween on Apr 25, 2005
All modern Sparc Sun machines use the PCI bus to connect peripherals to the system. A PCI bus is a physically addressed bus that can best be represented as an inverted tree. Each level of bus is connected to the next using pci bridge device. The bridge knows the phyical addresses of the devices below itself so it accepts transactions from the higher bus and passes them down. The root of the bus is the host-to-pci bus bridge.
This means that physical PCI bus addresses must be unique within a
tree of buses but can be duplicated between seperate trees. This means
that there must be a unique way of identifying which tree a pci command
is being sent to. Solaris does this by assigning segment of the SPARC
chips physical addressable space to each host-to-pci bridge.
If you use prtconf -vp
you can find the host-to-pci bus devices and all their properties.
On modern SPARC machine look for schizo devices, on slightly older ones
look for psycho nodes. You will find the ranges property , this is in 4
segments , one for configuration space, one for i/o space, one for 32
bit memory and one for 64 bit memory. Encoded in each is the base
address and the size.
ranges: base address size
config 00000000.00000000. 00000000.00000402.00000000. 00000000.01000000.
i/o 01000000.00000000. 00000000.00000402.01000000. 00000000.01000000.
mem32 02000000.00000000. 00000000.0000041c.00000000. 00000000.80000000.
mem64 03000000.00000000. 00000000.0000041c.00000000. 00000000.80000000
So when the PCI bus goes wrong the machine may panic with a PCI Bus
Error/BERR which causes the system to print out a fault address AFAR.
This is the SPARC physical address that caused the error, so to decide
on which bus the fault happenned match the AFAR to a segment supplied
by the ranges property of a host-to-pci bridge.
The next problem is to work out which device on that tree of buses was being accessed. So subtract the base of the host-to-pci bus segment we found above to get the PCI bus physical address that is unique on this tree of PCI buses. You then have to add the matching assigned-addresses property and the regs property then using the size from the assigned-addresses property you get a base and length to try and match.
type address sizeassigned-addresses: 82010010. 00000000.08000000. 00000000.01000000...
reg: 02010010. 00000000.00002000. 00000000.00800000...
sum 10 = mem32 00000000.08002000. 00000000.01000000
so this mem32 segment runs from PCI physical address 0x08002000 for length 0x01000000
It sounds easy but I have been writting code to automate this
for a couple of days now!