PCI Manager
Document version 0.13a, Thursday the 30th of June, 2005
RISC OS 5 supports 32-bit and 64-bit PCI cards via the new PCI Manager, which provides a number of common services to the device driver modules for specific PCI cards.
It is envisaged that third parties will supply PCI cards bundled with the necessary RISC OS device drivers and the information supplied here should help developers to write those drivers.
A PCI device driver will normally be supplied as a RISC OS module which provides a set of SWIs and other interfaces to the PCI card. Applications should access the PCI card using SWI calls provided by this device driver module.
Driver source code for many PCI devices which is publicly available on the Internet for NetBSD and Linux may be useful in developing the corresponding RISC OS device driver.
In RISC OS, PCI devices can be identified in one of two ways. Users generally need only be aware of the PCI system when expansion cards are added to the machine, and will use the PCI slot number, in commands like *Unplug or *PCIDevices.
Slot numbers are fixed for a given system.
Device drivers use a PCI handle - each function of each PCI device in the system is given a unique, permanent non-zero handle when it is discovered. Handles remain constant as long as the device remains present in the system, but can change when the system is rebooted, or if a card is removed and reinserted (if the system supports hot-plugging). Handles do not change if the PCI Manager is reloaded. Handles are assigned from 1 upwards, so can be searched linearly, much like Expansion Cards.
| In: | | R3 = | | function handle
| | Out: | | R0 = | | vendor ID (bits 0-15)
| | | | | device ID (bits 16-31)
| | | R1 = | | subsystem vendor ID (bits 0-15)
| | | | | subsystem ID (bits 16-31)
|
| In: | | R3 = | | function handle
| | | R1 -> | | buffer
| | | R2 = | | number of bytes to read (4-256, must be multiple of 4)
| | Out: | | Buffer | | updated
|
The length of the buffer is assumed to be at least R2 bytes long
| In: | | No arguments
| | Out: | | R0 = number of function handles that have been used
|
This SWI returns the number of function handles that have been used.
Device drivers may search handles 1 to R0 inclusive to find a device.
| In: | | R3 = | | 0 to start enumeration
| | | | | or last value from EnumerateFunctions
| | Out: | | R0 = | | vendor ID (bits 0-15)
| | | | | device ID (bits 16-31)
| | | R1 = | | subsystem vendor ID (bits 0-15)
| | | | | subsystem ID (bits 16-31)
| | | R2 = | | class code
| | | R3 = | | function handle
|
| In: | | R0 = | | PCI address (found with PCI_HardwareAddress)
| | | R2 = | | access size (1, 2 or 4 for byte/half word/word)
| | Out: | | R1 = | | value read
|
| In: | | R0 = | | PCI address (found with PCI_HardwareAddress)
| | | R1 = | | value to write
| | | R2 = | | access size (1, 2 or 4 for byte/half word/word)
|
| In: | | R0 = | | PCI address (found with PCI_HardwareAddress)
| | | R1 = | | length (whole number of words)
| | | R2 -> | | buffer
| | | R4 = | | flags (bit 3 => prefetchable)
| | Out: | | Buffer | | updated
|
The length of the buffer is assumed to be at least R1 bytes long.
| In: | | R0 = | | PCI address (found with PCI_HardwareAddress)
| | | R1 = | | length (whole number of words)
| | | R2 -> | | buffer
| | | R4 = | | flags
|
| In: | | R0 = | | configuration space address (0-255) or bus/dev/fn/addr
| | | R2 = | | access size (1, 2 or 4 for byte/half word/word)
| | | R3 = | | function handle or 0
| | Out: | | R1 = | | value
|
| In: | | R0 = | | configuration space address (0-255) or bus/dev/fn/addr
| | | R1 = | | value
| | | R2 = | | access size (1, 2 or 4 for byte/half word/word)
| | | R3 = | | function handle or 0
|
| In: | | R0 = flags:
| | | bits 3..0 = access privileges (if bit 9 set)
| | | bit 4 => bufferable
| | | bit 5 => cacheable
| | | bits 8-6 => policy (see OS_DynamicArea)
| | | bit 9 => access privileges specified
| | | bit 31 => don't map, query PCI address only
| | | R1 = address index
| | | (0-5 correspond to first 6 Base Address Registers;
| | | a device with 3 64-bit addresses would use
| | | indexes 0,2,4 only. &100 corresponds to ROM)
| | | other values reserved
| | | R3 = function handle
| | Out: | | error if address not available
| | | R0 = flags:
| | | bit 0 => IO if set, memory if clear
| | | bit 3 => prefetchable
| | | R1 = PCI address
| | | R2 = area size
| | | R4 = logical address (if R0
| | | bit 31 clear)
|
| In: | | R0 = bitmask of required results
| | | R1 = pointer to buffer
| | | R2 = length of buffer
| | | R3 = function handle
| | Out: | | R2 = length of results
|
| Bit 0: | | Device/Function Number
| | 1: | | Bus number
| | 2: | | Function handle of parent bridge
| | 3: | | Slot number
| | 4: | | Vendor/device ID
| | 5: | | Revision ID
| | 6: | | Subsystem vendor/subsystem ID
| | 7: | | Class code (24 bits)
| | 8: | | CMOS address
| | 9: | | CMOS size in bytes
| | 10: | | Pointer to description (0 for none)
| | 11: | | Device vector number
| | 12: | | Ethernet address (low 32 bits) (?)
| | 13: | | Ethernet address (high 16 bits) (?)
| | 14: | | Logical DMA channel
| | 15: | | Pointer to vendor description (0 for none)
|
Anlogous to Podule_ReadInfo, for a given R3.
| In: | | R0 = | | bus
| | | R1 = | | message/data
|
Issues a special cycle on the PCI bus.
The value in R1 will be call specific.
| In: R0 = | | bus
| | R1 = | | dev/fn
| | Out: R3 = | | function handle
|
Finds the function handle based on the topology passed in R0 and R1.This
topology will be platform specific and could vary if backplanes with
bridges are inserted into the system.
| In: | | R3 = | | 0 to start, or R3 last found
| | | R0 = | | vendor ID (or -1)
| | | R1 = | | device ID (or -1)
| | | R2 = | | subsystem vendor ID (or -1)
| | | R4 = | | subsystem ID (or -1)
| | Out: | | R3 = | | function handle
|
Finds the function handle based on the wildcarded information passed in.
| In: | | R3 = | | 0 to start, or R3 last found
| | | R0 = | | class code (24-bit)
| | | R1 = | | mask (matches if (function_class AND R1) = R0)
| | Out: | | R3 = | | function handle
|
Finds the function handle based on the class passed.Only the bits in R1 of the
class code will be checked so a mask of -1 will search for an exact match.
| In: | | R0 = | | size required
| | | R1 = | | alignment required (eg &1000 if must be 4K aligned - 0 if none)
| | | R2 = | | boundary limitation (eg &10000 if mustn't cross 64K boundary - 0 if none)
| | Out: | | R0 = | | logical address
| | | R1 = | | PCI address
|
Allocates memory from a fixed, contiguous memory pool, suitable for access
by other bus masters. This is provided for the convenience of drivers that
only need a few simple data structures for communication with their PCI
device, and don't want the complexity of dealing with cache coherency,
memory fragmentation and physical page moving (Service_PagesUnsafe et al).
Memory will be uncachable but bufferable - you must ensure that any writes
you perform have taken place before another bus master reads the memory, by
calling OS_MMUControl 1 with bit 28 of R0 set. The memory is not accessible
from user mode.
In: R0 = logical address
Returns the block of memory pointed to by R0 (claimed earlier with PCI_RAMAlloc)
to the PCI memory pool for others to use.
| In: | | R0 = | | flags: bit 4 => bufferable
| | | | | bit 5 => cacheable
| | | | | bits 8-6 => policy
| | | | | bit 30 => IO else Memory
| | | R1 = | | PCI address
| | | R2 = | | length
| | Out: | | R4 = | | logical address
|
This call maps in the given PCI address (found with PCI_HardwareAddress) into
the logical memory map subject to the flags in bits 8 to 4 of R0.
If bit 30 is set it will be marked as IO,else marked as Memory.
Service_PCI is defined as &C3
| R1 = | | &C3 (the reason code)
| | R2 = | | subreason
| | => | | 0 - lookup description
| | | R3 = function handle to convert
| | | Return R1 = 0 to claim
| | | R2 = pointer to zero terminated string
| | | R3 = preserved
| | => | | 1 - lookup vendor description
| | | R0 = vendor ID
| | | Return R0 = preserved
| | | R1 = 0 to claim
| | | R2 = pointer to zero terminated string
| | => | | others - reserved for future expansion
|
Since PCI interrupt lines are shared by multiple devices, the interrupt handling mechanism is a little different from that used by traditional expansion cards. To find the device vector number that will be called for a particular card, use PCI_ReadInfo with bit 11 set in the R0 bitmask. To install a device driver, use OS_ClaimDeviceVector and pass in this vector number with bit 31 set to indicate that the call may be passed on to other vector claimants. You must also ensure that interrupts for this vector are enabled by calling the HAL routine HAL_IRQEnable (HAL entry number 1) with this vector number as the parameter. Note however that when you remove a device driver, you should not disable interrupts for this vector.
When your device driver routine is called, check whether your card is interrupting. If it is, perform the necessary interrupt processing and claim the vector by pulling the return address from the stack. If it is not, pass on the call by returning to the address in R14. If you are writing a device driver in C, use the CMHG 'vector-handlers' veneer and return 0 to claim the call or 1 to pass it on.
When the interrupt processing code needs to clear the interrupt on the PCI card, there are two things that must be done before interrupts are re-enabled or you return from the handler. Firstly, if clearing the interrupt involves writing to a register on the PCI card, you must ensure that the write has been flushed out to the card. This can be achieved by simply performing a read operation from a safe area or register on the card. Secondly, you should then call the HAL routine HAL_IRQClear (HAL entry number 3) with the vector number as the parameter. Note that this is not actually required for the Iyonix hardware, but should be included for compatibility with possible future hardware platforms.
If no handler claims a vector for a particular interrupt, the kernel will disable that interrupt line. For correct operation of the system it is vital that vector claiming and interrupt clearing are performed correctly.
 |
| © 2006 IYONIX Ltd |
32-bit RISC OS |
|