PCI, pci_conf_read, pci_conf_write, pci_conf_print, pci_find_device,
pci_get_capability, pci_mapreg_type, pci_mapreg_map, pci_mapreg_info,
pci_intr_map, pci_intr_string, pci_intr_evcnt, pci_intr_establish,
pci_intr_disestablish, pci_make_tag, pci_decompose_tag, pci_findvendor,
pci_devinfo, PCI_VENDOR, PCI_PRODUCT, PCI_REVISION - Peripheral Component
Interconnect
#include <machine/bus.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
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 *));
int
pci_find_device(struct pci_attach_args *pa,
int (*func)(struct pci_attach_args *));
int
pci_get_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(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_intr_map(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_disestablish(pci_chipset_tag_t pc, void *ih);
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);
int
PCI_VENDOR(pcireg_t id);
int
PCI_PRODUCT(pcireg_t id);
int
PCI_REVISION(pcireg_t id);
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 PowerPCbased
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.
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;
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_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 LKMs (see
lkm(4)) 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_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.
The argument tag is the PCI tag for the current device attached
to PCI chipset pc.
pci_mapreg_map( 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.
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_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_disestablish(pc, ih)
See pci_intr(9).
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)
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 argument show specifies whether
the PCI subsystem should report the string to the console.
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.
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).
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 shutdownhook_establish(9)).
This section describes places within the NetBSD source tree where actual
code implementing or utilising the machine-independent PCI subsystem can
be found. All pathnames are relative to /usr/src.
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.
pci(4), autoconf(9), bus_dma(9), bus_space(9), driver(9),
pci_configure_bus(9), pci_intr(9), shutdownhook_establish(9)
The machine-independent PCI subsystem appeared in NetBSD 1.2.
BSD June 19, 2001 BSD
[ Back ] |