PCI devices identification
==========================

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. 

PCI manager SWIs
================
SWI PCI_ReadID
--------------
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)

SWI PCI_ReadHeader
------------------
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 long

SWI PCI_ReturnNumber
--------------------
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.

SWI PCI_EnumerateFunctions
--------------------------
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

SWI PCI_IORead
--------------
In:  R0 = PCI address (found with PCI_HardwareAddress)
     R2 = access size (1, 2 or 4 for byte/half word/word)
Out: R1 = value read

SWI PCI_IOWrite
---------------
In: R0 = PCI address (found with PCI_HardwareAddress)
    R1 = value to write
    R2 = access size (1, 2 or 4 for byte/half word/word)

SWI PCI_MemoryRead
------------------
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 long
    
SWI PCI_MemoryWrite
-------------------
In:  R0 = PCI address (found with PCI_HardwareAddress)
     R1 = length (whole number of words)
     R2 -> buffer
     R4 = flags (bits 0-31 reserved => 0)

SWI PCI_ConfigurationRead
-------------------------
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

SWI PCI_ConfigurationWrite
--------------------------
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

SWI PCI_HardwareAddress
-----------------------
In:   R0 = flags:     bits 0-3 = access privileges (if bit 9 set)
                      bit 4 => bufferable
                      bit 5 => cacheable
                      bits 6-8 => 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)
    
SWI PCI_ReadInfo
----------------
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)
      16: Number of MSI messages (0 if MSI not available)

Analogous to Podule_ReadInfo, for a given R3.

SWI PCI_SpecialCycle
--------------------
  In: R0 = bus
      R1 = message/data

Issues a special cycle on the PCI bus.
The value in R1 will be call specific.

SWI PCI_FindByLocation
----------------------
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.

SWI PCI_FindByID
----------------
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.

SWI PCI_FindByClass
-------------------
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.

SWI PCI_RAMAlloc
----------------
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, e.g.
by using the barrier routines available via OS_MMUControl 2, or by calling
OS_MMUControl 1 with bit 29 of R0 set. The memory is not accessible from user
mode.

SWI PCI_RAMFree
---------------
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.

SWI PCI_LogicalAddress
----------------------
In:  R0 = flags:  bit 4 => bufferable
                  bit 5 => cacheable
                  bits 6-8 => 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 4 to 8 of R0.
If bit 30 is set it will be marked as IO, else marked as Memory.

SWI PCI_ClaimDeviceVector
-------------------------
In:  R0 = flags (must be 0)
     R1 -> handler routine
     R2 = handler R12 value
     R3 = function handle

Out: R1 = flags
           bit 0 => Unshared interrupt (ie if handler called, it was definitely
                                        your function interrupting)
           bit 1 => MSI
     R0 = device number (to use when masking or unmasking)
     R2 = number of messages being used by device (= PCI_ReadInfo 16)

In the simplest case, this call is analogous using OS_ClaimDeviceVector with the
device vector number provided by PCI_ReadInfo 11, and bit 31 set. But using this
call allows Message Signalled Interrupts (MSI) to be activated. MSI has the
advantage that interrupt routing is faster - all MSI interrupts are effectively
unshared, and there are no synchronisation issues with the PCI bus - it is
no longer necessary to do a device read to ensure write buffers have been flushed.

A device is automatically put into MSI mode when this call is made, if both
the host system and the PCI device support it. If so, bit 1 of R1 is set on
exit, and R2 indicates the number of messages being used by the device.

Entry and exit conditions for the handler are the same as for OS_ClaimDeviceVector
with bit 31 of R0 set, except that when using MSI, R0 on entry to the handler will
be the message number (between 0 and <R2 on exit from PCI_ClaimDeviceVector>-1).
MSI interrupt conditions are automatically cleared before the handler is called.

Multiple claims per function operate in the same way as with OS_ClaimDeviceVector.
It would thus be possible (though not efficient) to have multiple chained handlers
to handle each message for an MSI device.

The device number in R0 on exit from this call is what should be used to unmask
(and mask temporarily, if necessary) the interrupt, as you would do with
OS_ClaimDeviceVector. In the MSI case, this will most likely be a separate
top-level MSI interrupt, rather than the value returned by PCI_ReadInfo. In
both cases, masking the interrupt will potentially mask out other devices'
interrupts as well as your own.


SWI PCI_ReleaseDeviceVector
-------------------------
In:  R0 = flags (must be 0)
     R1 -> handler routine
     R2 = handler R12 value
     R3 = function handle

Analogous to OS_ReleaseDeviceVector - see PCI_ClaimDeviceVector above.
After the last claimant for a function is released, MSI mode will be disabled,
for backwards compatibility with device drivers that don't use these calls.


PCI manager service calls
=========================
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





