NAME
PCI,
pci_activate,
pci_bus_devorder,
pci_chipset_tag_create,
pci_chipset_tag_destroy,
pci_conf_read,
pci_conf_write,
pci_conf_print,
pci_conf_capture,
pci_conf_restore,
pci_find_device,
pci_get_capability,
pci_get_ht_capability,
pci_get_ext_capability,
pci_mapreg_type,
pci_mapreg_map,
pci_mapreg_info,
pci_intr_map,
pci_intr_string,
pci_intr_evcnt,
pci_intr_establish,
pci_intr_establish_xname,
pci_intr_disestablish,
pci_intr_type,
pci_intr_setattr,
pci_get_powerstate,
pci_set_powerstate,
pci_vpd_read,
pci_vpd_write,
pci_make_tag,
pci_decompose_tag,
pci_findvendor,
pci_devinfo,
PCI_VENDOR,
PCI_PRODUCT,
PCI_REVISION —
Peripheral Component Interconnect
SYNOPSIS
#include <sys/bus.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
int
pci_bus_devorder(
pci_chipset_tag_t
pc,
int bus,
uint8_t *devs,
int maxdevs);
int
pci_activate(
pci_chipset_tag_t
pc,
pcitag_t tag,
device_t dev,
int (*wakeup)(pci_chipset_tag_t
pc, pcitag_t tag, device_t dev, pcireg_t reg));
int
pci_chipset_tag_create(
pci_chipset_tag_t
opc,
uint64_t
present,
const struct
pci_overrides *ov,
void
*ctx,
pci_chipset_tag_t
*pcp);
void
pci_chipset_tag_destroy(
pci_chipset_tag_t
pc);
pcireg_t
pci_conf_read(
pci_chipset_tag_t
pc,
pcitag_t tag,
int reg);
void
pci_conf_write(
pci_chipset_tag_t
pc,
pcitag_t tag,
int reg,
pcireg_t val);
void
pci_conf_print(
pci_chipset_tag_t
pc,
pcitag_t tag,
void (*func)(pci_chipset_tag_t,
pcitag_t, const pcireg_t *));
void
pci_conf_capture(
pci_chipset_tag_t
pc,
pcitag_t tag,
struct pci_conf_state *);
void
pci_conf_restore(
pci_chipset_tag_t
pc,
pcitag_t tag,
struct pci_conf_state *);
int
pci_find_device(
struct
pci_attach_args *pa,
int
(*func)(const struct pci_attach_args *));
int
pci_get_capability(
pci_chipset_tag_t
pc,
pcitag_t tag,
int capid,
int *offsetp,
pcireg_t *valuep);
int
pci_get_ht_capability(
pci_chipset_tag_t
pc,
pcitag_t tag,
int capid,
int *offsetp,
pcireg_t *valuep);
int
pci_get_ext_capability(
pci_chipset_tag_t
pc,
pcitag_t tag,
int capid,
int *offsetp,
pcireg_t *valuep);
pcireg_t
pci_mapreg_type(
pci_chipset_tag_t
pc,
pcitag_t tag,
int reg);
int
pci_mapreg_map(
const
struct pci_attach_args *pa,
int reg,
pcireg_t type,
int busflags,
bus_space_tag_t *tagp,
bus_space_handle_t
*handlep,
bus_addr_t
*basep,
bus_size_t
*sizep);
int
pci_mapreg_info(
pci_chipset_tag_t
pc,
pcitag_t tag,
int reg,
pcireg_t type,
bus_addr_t *basep,
bus_size_t *sizep,
int *flagsp);
int
pci_find_rom(
const
struct pci_attach_args *pa,
bus_space_tag_t bst,
bus_space_handle_t bsh,
int code,
bus_space_handle_t
*handlep,
bus_space_size_t
*sizep);
int
pci_intr_map(
const
struct pci_attach_args *pa,
pci_intr_handle_t *ih);
const char *
pci_intr_string(
pci_chipset_tag_t
pc,
pci_intr_handle_t
ih);
const struct evcnt *
pci_intr_evcnt(
pci_chipset_tag_t
pc,
pci_intr_handle_t
ih);
void *
pci_intr_establish(
pci_chipset_tag_t
pc,
pci_intr_handle_t
ih,
int level,
int (*handler)(void *),
void *arg);
void *
pci_intr_establish_xname(
pci_chipset_tag_t
pc,
pci_intr_handle_t
ih,
int level,
int (*handler)(void *),
void *arg,
const char *xname);
void
pci_intr_disestablish(
pci_chipset_tag_t
pc,
void *ih);
pci_intr_type_t
pci_intr_type(
pci_chipset_tag_t
pc,
pci_intr_handle_t
ih);
int
pci_intr_setattr(
pci_chipset_tag_t
pc,
pci_intr_handle_t
*ih,
int attr,
uint64_t data);
int
pci_set_powerstate(
pci_chipset_tag_t
pc,
pcitag_t tag,
pcireg_t newstate);
int
pci_get_powerstate(
pci_chipset_tag_t
pc,
pcitag_t tag,
pcireg_t *state);
int
pci_vpd_read(
pci_chipset_tag_t
pc,
pcitag_t tag,
int offset,
int count,
pcireg_t *data);
int
pci_vpd_write(
pci_chipset_tag_t
pc,
pcitag_t tag,
int offset,
int count,
pcireg_t *data);
pcitag_t
pci_make_tag(
pci_chipset_tag_t
pc,
int bus,
int device,
int function);
void
pci_decompose_tag(
pci_chipset_tag_t
pc,
pcitag_t tag,
int *busp,
int *devicep,
int *functionp);
char *
pci_findvendor(
pcireg_t
id);
void
pci_devinfo(
pcireg_t
id,
pcireg_t class,
int show,
char *cp,
size_t len);
void
pci_aprint_devinfo(
struct
pci_attach_args *pa,
const
char *naive);
int
PCI_VENDOR(
pcireg_t
id);
int
PCI_PRODUCT(
pcireg_t
id);
int
PCI_REVISION(
pcireg_t
id);
DESCRIPTION
The machine-independent
PCI subsystem provides support for PCI
devices.
The PCI bus was initially developed by Intel in the early 1990's to replace the
ISA bus for interfacing with their Pentium processor. The PCI specification is
widely regarded as well designed, and the PCI bus has found widespread
acceptance in machines ranging from Apple's PowerPC-based systems to Sun's
UltraSPARC-based machines.
The PCI bus is a multiplexed bus, allowing addresses and data on the same pins
for a reduced number of pins. Data transfers can be 8-bit, 16-bit or 32-bit. A
64-bit extended PCI bus is also defined. Multi-byte transfers are
little-endian. The PCI bus operates up to 33MHz and any device on the bus can
be the bus master.
AGP is a version of PCI optimised for high-throughput data rates, particularly
for accelerated frame buffers.
The PCI bus is a "plug and play" bus, in the sense that devices can be
configured dynamically by software. The PCI interface chip on a PCI device bus
presents a small window of registers into the PCI configuration space. These
registers contain information about the device such as the vendor and a
product ID. The configuration registers can also be written to by software to
alter how the device interfaces to the PCI bus. An important register in the
configuration space is the Base Address Register (BAR). The BAR is written to
by software to map the device registers into a window of processor address
space. Once this mapping is done, the device registers can be accessed
relative to the base address.
DATA TYPES
Drivers for devices attached to the
PCI will make use of the
following data types:
-
-
- pcireg_t
- Configuration space register.
-
-
- pci_chipset_tag_t
- Chipset tag for the PCI bus.
-
-
- pcitag_t
- Configuration tag describing the location and function of
the PCI device. It contains the tuple ⟨bus, device,
function⟩.
-
-
- pci_intr_handle_t
- The opaque handle describing an established interrupt
handler.
-
-
- struct
pci_attach_args
- Devices have their identity recorded in this structure. It
contains the following members:
bus_space_tag_t pa_iot; /* pci i/o space tag */
bus_space_tag_t pa_memt; /* pci mem space tag */
bus_dma_tag_t pa_dmat; /* DMA tag */
pci_chipset_tag_t pa_pc;
int pa_flags; /* flags */
pcitag_t pa_tag;
pcireg_t pa_id;
pcireg_t pa_class;
-
-
- struct
pci_conf_state
- Stores the PCI configuration state of a device. It contains
the following member:
pcireg_t reg[16]; /* pci conf register */
-
-
- struct
pci_overrides
- Stores pointers to functions that override the
architecture's default PCI and
pci_intr(9)
implementation. It contains the following members:
pcireg_t (*ov_conf_read)(void *,
pci_chipset_tag_t, pcitag_t, int);
void (*ov_conf_write)(void *,
pci_chipset_tag_t, pcitag_t, int, pcireg_t);
int (*ov_intr_map)(void *,
const struct pci_attach_args *, pci_intr_handle_t *);
const char *(*ov_intr_string)(void *,
pci_chipset_tag_t, pci_intr_handle_t);
const struct evcnt *(*ov_intr_evcnt)(void *,
pci_chipset_tag_t, pci_intr_handle_t);
void *(*ov_intr_establish)(void *,
pci_chipset_tag_t, pci_intr_handle_t,
int, int (*)(void *), void *);
void (*ov_intr_disestablish)(void *,
pci_chipset_tag_t, void *);
pcitag_t (*ov_make_tag)(void *,
pci_chipset_tag_t, int, int, int);
void (*ov_decompose_tag)(void *,
pci_chipset_tag_t, pcitag_t, int *, int *, int *);
FUNCTIONS
-
-
- pci_bus_devorder(pc,
bus, devs,
maxdevs)
- Tell how many devices a PCI bus driver should probe and in
what order. If maxdevs is less than or equal to
zero, return 0 and do not modify devs. Otherwise,
return maxdevs or the number of devices on
bus to probe, whichever is less, and copy to
devs each of the PCI device numbers to probe in the
order that they should be probed. pci_bus_devorder()
will not copy more than maxdevs device numbers to
devs.
-
-
- pci_activate(pc,
tag, dev,
fun)
- Attempt to bring the device to state D0. If the device is
not in the D0 state call fun to restore its state.
If fun is
NULL
then
restoring from state D3 is going to fail.
-
-
- pci_chipset_tag_create(opc,
present, ov,
ctx, pcp)
- Create a copy of the tag opc at
*pcp. Except for the behavior overridden by
ov, *pcp inherits the behavior
of opc under PCI calls.
ov contains function pointers corresponding to
PCI routines. Each function pointer has a corresponding
bit in present, and if that bit is 1, the function
pointer overrides the corresponding PCI call for the new
tag. Any combination of these bits may be set in
present:
PCI_OVERRIDE_CONF_READ
-
PCI_OVERRIDE_CONF_WRITE
-
PCI_OVERRIDE_INTR_MAP
-
PCI_OVERRIDE_INTR_STRING
-
PCI_OVERRIDE_INTR_EVCNT
-
PCI_OVERRIDE_INTR_ESTABLISH
-
PCI_OVERRIDE_INTR_DISESTABLISH
-
PCI_OVERRIDE_MAKE_TAG
-
PCI_OVERRIDE_DECOMPOSE_TAG
-
pci_chipset_tag_create() does not copy
ov. After a new tag is created by
pci_chipset_tag_create(), ov must
not be destroyed until after the tag is destroyed by
pci_chipset_tag_destroy().
The first argument of every override-function is a void
*, and ctx is passed in that argument.
Return 0 if the call succeeds. Return EOPNOTSUPP
if
the architecture does not support overrides. Return
EINVAL
if present is 0, if
ov is NULL
, or if
present indicates that an override is present, but
the corresponding override in ov is
NULL
.
If the call does not succeed, *pcp is undefined.
-
-
- pci_chipset_tag_destroy(pc)
- Destroy a tag, pc, created by a prior
call to pci_chipset_tag_create(). If
pc was not created by
pci_chipset_tag_create(), results are undefined. If
pc was already destroyed, results are
undefined.
-
-
- pci_conf_read(pc,
tag, reg)
- Read from register reg in PCI
configuration space. The argument tag is the PCI tag
for the current device attached to PCI chipset
pc.
-
-
- pci_conf_write(pc,
tag, reg,
val)
- Write to register reg in PCI
configuration space. The argument tag is the PCI tag
for the current device attached to PCI chipset
pc.
-
-
- pci_conf_print(pc,
tag, func)
- Print out most of the registers in the PCI configuration
for the device. The argument tag is the PCI tag for
the current device attached to PCI chipset pc. The
argument func is a function called by
pci_conf_print() to print the device-dependent
registers. This function is only useful for driver development and is
usually wrapped in pre-processor declarations.
-
-
- pci_conf_capture(pc,
tag, pcs)
- Capture PCI configuration space into structure
pcs. The argument tag is the
PCI tag for the current device attached to the PCI chipset
pc.
-
-
- pci_conf_restore(pc,
tag, pcs)
- Restores PCI configuration space from structure
pcs. The argument tag is the
PCI tag for the current device attached to the PCI chipset
pc.
-
-
- pci_find_device(pa,
func)
- Find a device using a match function on all probed busses.
The argument func is called by
pci_find_device() to match a device. The argument
pa is filled in if the device is matched.
pci_find_device() returns 1 if the device is matched,
and zero otherwise. This function is specifically for use by kernel
modules and its use otherwise is strongly discouraged.
-
-
- pci_get_capability(pc,
tag, capid,
offsetp, valuep)
- Parse the device capability list in configuration space
looking for capability capid. If
offsetp is not
NULL
, the
register offset in configuration space is returned in
offsetp. If valuep is not
NULL
, the value of the capability is returned in
valuep. The argument tag is
the PCI tag for the current device attached to PCI chipset
pc. This function returns 1 if the capability was
found. If the capability was not found, it returns zero, and
offsetp and valuep remain
unchanged.
-
-
- pci_get_ht_capability(pc,
tag, capid,
offsetp, valuep)
- Parse the device capability list in HyperTransport
configuration space looking for capability capid. If
offsetp is not
NULL
, the
register offset in configuration space is returned in
offsetp. If valuep is not
NULL
, the value of the capability is returned in
valuep. The argument tag is
the PCI tag for the current device attached to PCI chipset
pc. This function returns 1 if the capability was
found. If the capability was not found, it returns zero, and
offsetp and valuep remain
unchanged.
-
-
- pci_get_ext_capability(pc,
tag, capid,
offsetp, valuep)
- Parse the device capability list in extended configuration
space looking for capability capid. If
offsetp is not
NULL
, the
register offset in extended configuration space is returned in
offsetp. If valuep is not
NULL
, the value of the capability is returned in
valuep. The argument tag is
the PCI tag for the current device attached to PCI chipset
pc. This function returns 1 if the capability was
found. If the capability was not found, it returns zero, and
offsetp and valuep remain
unchanged.
-
-
- pci_mapreg_type(pc,
tag, reg)
- Interrogates the Base Address Register (BAR) in
configuration space specified by reg and returns the
default (or current) mapping type. Valid returns values are:
-
-
PCI_MAPREG_TYPE_IO
- The mapping is to I/O address space.
-
-
PCI_MAPREG_TYPE_MEM
- The mapping is to memory address space.
-
-
PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_64BIT
- The mapping is to 64-bit memory address space.
-
-
PCI_MAPREG_TYPE_ROM
- The mapping is to ROM. Note that in the current
implementation,
PCI_MAPREG_TYPE_ROM
has the
same numeric value as
PCI_MAPREG_TYPE_MEM
.
The argument tag is the PCI tag for the current device
attached to PCI chipset pc.
-
-
- pci_mapreg_map(pa,
reg, type,
busflags, tagp,
handlep, basep,
sizep)
- Maps the register windows for the device into kernel
virtual address space. This function is generally only called during the
driver attach step and takes a pointer to the struct
pci_attach_args in pa. The physical address of
the mapping is in the Base Address Register (BAR) in configuration space
specified by reg. Valid values for the type of
mapping type are:
-
-
PCI_MAPREG_TYPE_IO
- The mapping should be to I/O address space.
-
-
PCI_MAPREG_TYPE_MEM
- The mapping should be to memory address space.
-
-
PCI_MAPREG_TYPE_ROM
- The mapping is to access ROM. This type of mapping is
only permitted when the value for reg is
PCI_MAPREG_ROM
.
The argument busflags are bus-space flags passed to
bus_space_map() to perform the mapping (see
bus_space(9)). The
bus-space tag and handle for the mapped register window are returned in
tagp and handlep respectively.
The bus-address and size of the mapping are returned in
basep and sizep respectively.
If any of tagp, handlep,
basep, or sizep are
NULL
then pci_mapreg_map() does
not define their return value. This function returns zero on success and
non-zero on error.
-
-
- pci_mapreg_info(pc,
tag, reg,
type, basep,
sizep, flagsp)
- Performs the same operations as
pci_mapreg_map() but doesn't actually map the register
window into kernel virtual address space. Returns the bus-address, size
and bus flags in basep, sizep
and flagsp respectively. These return values can be
used by bus_space_map() to actually map the register
window into kernel virtual address space. This function is useful for
setting up the registers in configuration space and deferring the mapping
to a later time, such as in a bus-independent attachment routine.
pci_mapreg_info returns zero on success and non-zero
on failure.
-
-
- pci_find_rom(pa,
bst, bsh,
code, handlep,
sizep)
- Locates a suitable ROM image within a PCI expansion ROM
previously mapped with pci_mapreg_map() and creates a
subregion for it with bus_space_subregion(). The
bst and bsh arguments are the
bus tag and handle obtained with the prior call to
pci_mapreg_map(). Valid values for the image type
code are:
-
-
PCI_ROM_CODE_TYPE_X86
- Find a ROM image containing i386 executable code for
use by PC BIOS.
-
-
PCI_ROM_CODE_TYPE_OFW
- Find a ROM image containing Forth code for use by Open
Firmware.
-
-
PCI_ROM_CODE_TYPE_HPPA
- Find a ROM image containing HP PA/RISC executable
code.
The created subregion will cover the entire selected ROM image, including
header data. The handle to this subregion is returned in
handlep. The size of the image (and the
corresponding subregion) is returned in sizep. This
function can only be used with expansion ROMs located at the
PCI_MAPREG_ROM
base address register (BAR).
-
-
- pci_intr_map(pa,
ih)
- See
pci_intr(9).
-
-
- pci_intr_string(pc,
ih)
- See
pci_intr(9).
-
-
- pci_intr_evcnt(pc,
ih)
- See
pci_intr(9).
-
-
- pci_intr_establish(pc,
ih, level,
handler, arg)
- See
pci_intr(9).
-
-
- pci_intr_establish_xname(pc,
ih, level,
handler, arg,
xname)
- See
pci_intr(9).
-
-
- pci_intr_disestablish(pc,
ih)
- See
pci_msi(9).
-
-
- pci_intr_type(pc,
ih)
- See
pci_intr(9).
-
-
- pci_intr_setattr(pc,
ih, attr,
data)
- See
pci_intr(9).
-
-
- pci_set_powerstate(pc,
tag, newstate)
- Set power state of the device to newstate. Valid values for
newstate are:
PCI_PMCSR_STATE_D0
-
PCI_PMCSR_STATE_D1
-
PCI_PMCSR_STATE_D2
-
PCI_PMCSR_STATE_D3
-
-
-
- pci_get_powerstate(pc,
tag, state)
- Get current power state of the device.
-
-
- pci_vpd_read(pc,
tag, offset,
count, data)
- Read count 32-bit words of Vital
Product Data for the device starting at offset
offset into the buffer pointed to by
data. Returns 0 on success or non-zero if the device
has no Vital Product Data capability or if reading the Vital Product Data
fails.
-
-
- pci_vpd_write(pc,
tag, offset,
count, data)
- Write count 32-bit words of Vital
Product Data for the device starting at offset
offset from the buffer pointed to by
data. Returns 0 on success or non-zero if the device
has no Vital Product Data capability of if writing the Vital Product Data
fails.
-
-
- pci_make_tag(pc,
bus, device,
function)
- Create a new PCI tag for the PCI device specified by the
tuple ⟨bus, device, function⟩. This function is not useful
to the usual PCI device driver. It is generally used by drivers of
multi-function devices when attaching other PCI device drivers to each
function.
-
-
- pci_decompose_tag(pc,
tag, busp,
devicep, fnp)
- Decompose the PCI tag tag generated
by pci_make_tag() into its ⟨bus, device,
function⟩ tuple.
-
-
- pci_findvendor(id)
- Return the string of the vendor name for the device
specified by id.
-
-
- pci_devinfo(id,
class, show,
cp, len)
- Returns the description string from the in-kernel PCI
database for the device described by id and
class. The description string is returned in
cp; the size of that storage is given in
len. The argument show
specifies whether the PCI subsystem should report the string to the
console.
-
-
- pci_aprint_devinfo(pa,
naive)
- Print device information to the console and system log,
using the
aprint_normal(9) and
aprint_naive(9)
functions. For the device information, the “pci_devinfo”
function above is used, or the naive argument in the
“AB_QUIET” case. This function is intended to be used early in
device attach.
-
-
- PCI_VENDOR(id)
- Return the PCI vendor id for device
id.
-
-
- PCI_PRODUCT(id)
- Return the PCI product id for device
id.
-
-
- PCI_REVISION(id)
- Return the PCI product revision for device
id.
AUTOCONFIGURATION
During autoconfiguration, a
PCI driver will receive a pointer
to
struct pci_attach_args describing the device attaches
to the PCI bus. Drivers match the device using the
pa_id
member using
PCI_VENDOR().
PCI_PRODUCT()
and
PCI_REVISION().
During the driver attach step, drivers can read the device configuration space
using
pci_conf_read(). The meaning attached to registers in
the PCI configuration space are device-dependent, but will usually contain
physical addresses of the device register windows. Device options can also be
stored into the PCI configuration space using
pci_conf_write(). For example, the driver can request
support for bus-mastering DMA by writing the option to the PCI configuration
space.
Device capabilities can be queried using
pci_get_capability(),
and returns device-specific information which can be found in the PCI
configuration space to alter device operation.
After reading the physical addresses of the device register windows from
configuration space, these windows must be mapped into kernel virtual address
space using
pci_mapreg_map(). Device registers can now be
accessed using the standard bus-space API (see
bus_space(9)).
Details of using PCI interrupts is described in
pci_intr(9).
DMA SUPPORT
The PCI bus supports bus-mastering operations from any device on the bus. The
DMA facilities are accessed through the standard
bus_dma(9) interface. To
support DMA transfers from the device to the host, it is necessary to enable
bus-mastering in the PCI configuration space for the device.
During system shutdown, it is necessary to abort any DMA transfers in progress
by registering a shutdown hook (see
pmf(9)).
CODE REFERENCES
The PCI subsystem itself is implemented within the files
sys/dev/pci/pci.c,
sys/dev/pci/pci_subr.c,
sys/dev/pci/pci_map.c,
sys/dev/pci/pci_quirks.c, and
sys/dev/pci/pciconf.c. Machine-dependent portions are
implemented within the file
sys/arch/<arch>/pci/pci_machdep.c.
The database of known devices exists within the file
sys/dev/pci/pcidevs_data.h and is generated automatically
from the file
sys/dev/pci/pcidevs. New vendor and product
identifiers should be added to this file. The database can be regenerated
using the Makefile
sys/dev/pci/Makefile.pcidevs.
SEE ALSO
pci(4),
autoconf(9),
bus_dma(9),
bus_space(9),
driver(9),
pci_configure_bus(9),
pci_intr(9),
pci_msi(9),
pmf(9)
HISTORY
The machine-independent PCI subsystem appeared in
NetBSD
1.2.