pciio_config(D3)pciio_config(D3)NAME
pciio_config: pciio_config_get, pciio_config_set - access PCI
Configuration register
SYNOPSIS
#include <sys/PCI/pciio.h>
#include <sys/PCI/PCI_defs.h>
uint64_t
pciio_config_get(
vertex_hdl_t vhdl,
unsigned reg,
unsigned size)
void
pciio_config_set(
vertex_hdl_t vhdl,
unsigned reg,
unsigned size,
uint64_t value )
Arguments
vhdl The connection point of the PCI device, as passed to the driver's
attach() entry point.
reg Byte offset of the register of interest in the PCI address space.
size Width of the target register in bytes.
value Value to be written to the specified register.
DESCRIPTION
Various SGI platforms introduce complexities and restrictions in how
Configuration Space cycles are generated on the PCI bus. For instance,
some platforms may require all PCI Configuration accesses to be done
using 32-bit wide accesses. Other platforms may require more than a
simple load or store to trigger the actual cycle, so that configuration
access cannot be performed using simple PIO loads and stores. The
functions described here allow the hardware differences to be
encapsulated behind a single interface, so PCI drivers do not have to
know the details of each platform.
The reg value specifies the offset of the target value in configuration
space. The size value specifies the width of the target value.
Registers defined by the standard are 1, 2, 3, 4, or 8 bytes, but the
functions permit any size from 1-8 bytes. Eight-byte registers are
returned in proper byte and word order.
Some implementations must access configuration space in 32-bit units on
32-bit boundaries, while other implementations may do this for
performance reasons. When reg and size specify a standard PCI
configuration register, pciio_config_get() shifts and masks appropriately
Page 1
pciio_config(D3)pciio_config(D3)
to return just the value of the register. Similarly, pciio_config_set()
executes a read-merge-write operation to place the data in the correct
portion of the word.
Standard PCI Configuration Registers
To access vendor-specific registers, specify the base address in PCI
configuration space, bearing in mind that PCI places the least
significant data in the lowest offset.
The following constants are used as the reg value to specify a standard
register in the Type 00 PCI configuration space:
PCI_CFG_VENDOR_ID
PCI_CFG_DEVICE_ID
PCI_CFG_COMMAND
PCI_CFG_STATUS
PCI_CFG_REV_ID
PCI_CFG_BASE_CLASS
PCI_CFG_SUB_CLASS
PCI_CFG_PROG_IF
PCI_CFG_CACHE_LINE
PCI_CFG_LATENCY_TIMER
PCI_CFG_HEADER_TYPE
PCI_CFG_BIST
PCI_CFG_BASE_ADDR(0)PCI_CFG_BASE_ADDR(1)PCI_CFG_BASE_ADDR(2)PCI_CFG_BASE_ADDR(3)PCI_CFG_BASE_ADDR(4)PCI_CFG_BASE_ADDR(5)
PCI_CFG_CARDBUS_CIS
PCI_CFG_SUBSYS_VEND_ID
PCI_CFG_SUBSYS_ID
PCI_CFG_PCI_EXPANSION_ROM
PCI_INTR_LINE
PCI_INTR_PIN
PCI_MIN_GNT
PCI_MAX_LAT
Use PCI_CFG_VEND_SPECIFIC to specify the first vendor-specific
register word.
EXAMPLES
Most things that drivers might think they need to set up in their
configuration space have already been taken care of by the
infrastructure, including checking the VENDOR and DEVICE identifiers,
allocating PCI space appropriately and assigning values to the BASE
Page 2
pciio_config(D3)pciio_config(D3)
registers, enabling DMA, Memory and I/O decode, and setting up the
system-specific values for other registers as appropriate; so we expect
that many PCI drivers will never actually need to worry about their
configuration space at all.
This example reflects a driver that is supporting multiple revisions of a
card, where the revision code needs to be stored for later use.
pcifoo_attach(vertex_hdl_t conn)
{
...
/* retrieve current device revision */
foo_soft->fs_revision =
pciio_config_get(conn, PCI_CFG_REV_ID, 1);
...
/* write 0x5555AAAA test pattern to first
** vendor specific register */
pciio_config_set(conn, PCI_CFG_VEND_SPECIFIC, 4,
0x5555AAAA);
}
NOTES
Access to sizes or alignments not directly supported by the processor or
any bus or bus adapter between the processor and the PCI device may
result in multiple CFG cycles being used to construct the access.
A number of SGI-built PCI peripherals require all CFG space accesses to
use all byte lanes. In support of this, all current pciio_config_get()
provider implementations always read the entire 32-bit wide word, then
extract the register of interest using shift and mask operations. This
is also faster than switching between various load sequences based on the
size and alignment of the register.
On systems that are unable to initiate store cycles with only some byte
lanes enabled, support code may synthesize the transaction effect by
reading the word containing the register, modifying the proper bits in
the word, then rewriting the entire bus word. This synthesis code knows
about the special handling of the STATUS register. However, if other
registers in your card's configuration space are sensitive to being
rewritten, you should access other registers in the same word as the
sensitive ones using full four-byte-wide accesses, manipulating the word
data appropriately.
Previous Releases
In IRIX 6.3, the functions with the names pciio_config_get and
pciio_config_set took different arguments than these functions do, and
had more restrictions. When porting from IRIX 6.3, some recoding of
configuration access is needed.
Page 3
pciio_config(D3)pciio_config(D3)
All systems supported by IRIX 6.4 permitted direct PIO access to
configuration space. Accordingly, IRIX 6.4 included no configuration
access functions. When porting from IRIX 6.4, configuration access must
be recoded to use these functions in order to avoid being platform-
dependent.
It is possible to code configuration access call macros so that they
compile properly in all releases from 6.3 onward. The macro code would
be similar to the following:
/* PCI Config Space Access Macros
** for source compatibility in drivers
** that need to use the same source
** for IRIX 6.3, IRIX 6.4, and IRIX 6.5
**
** PCI_CFG_BASE(conn)
** PCI_CFG_GET(conn,base,offset,type)
** PCI_CFG_SET(conn,base,offset,type,value)
**
** Use PCI_CFG_BASE once during attach to get the
** base value to be used for the specific device.
** Later, use PCI_CFG_GET to read and PCI_CFG_SET
** to write config registers.
**
** NOTE: Irix 6.3 determines the size of the register
** directly on its own, based on the layout of a Type 00
** PCI Configuration Space Header. If you specify a
** nonstandard size, you will get different results
** depending on the system revision number.
*/
#if IRIX6_3
#define PCI_CFG_BASE(c) pciio_piotrans_addr(c,0,PCIIO_SPACE_CFG,0,256,0)
#define PCI_CFG_GET(c,b,o,t) pciio_config_get(b,o)
#define PCI_CFG_SET(c,b,o,t,v) pciio_config_set(b,o,v)
#elif IRIX6_4
#define PCI_CFG_BASE(c) pciio_piotrans_addr(c,0,PCIIO_SPACE_CFG,0,256,0)
#define PCI_CFG_GET(c,b,o,t) ((*(t *)((char *)(b)+(o))))
#define PCI_CFG_SET(c,b,o,t,v) ((*(t *)((char *)(b)+(o))) = v)
#else /* starting in IRIX 6.5 */
#define PCI_CFG_BASE(c) NULL
#define PCI_CFG_GET(c,b,o,t) pciio_config_get(c,o,sizeof(t))
#define PCI_CFG_SET(c,b,o,t,v) pciio_config_set(c,o,sizeof(t),v)
#endif
The macros would be used approximately as follows (repeating the example
from the preceding section):
pcifoo_attach(vertex_hdl_t conn)
{
void * config_base = PCI_CFG_BASE(conn);
...
/* retrieve current device revision */
Page 4
pciio_config(D3)pciio_config(D3)
foo_soft->fs_revision =
PCI_CFG_GET(conn, config_base, PCI_CFG_REV_ID, uchar);
...
/* write 0x5555AAAA test pattern to first
** vendor specific register */
PCI_CFG_SET(conn, config_base, PCI_CFG_VEND_SPECIFIC, uint32_t,
0x5555AAAA);
}
SEE ALSOpciio(D3), pciio_config(D3), pciio_dma(D3), pciio_error(D3),
pciio_get(D3), pciio_intr(D3). pciio_pio(D3).
Page 5