| PCI(9) | Kernel Developer's Manual | PCI(9) | 
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_get_segment,
  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 —
#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);
u_int
  
  pci_get_segment(pci_chipset_tag_t
    pc);
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);
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.
PCI will make use of
  the following data types:
	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;
    
    
	pcireg_t reg[16];			/* pci conf register */
    
    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 *);
    
    pci_bus_devorder(pc,
    bus, devs,
    maxdevs)pci_bus_devorder() will not copy more than
      maxdevs device numbers to
      devs.pci_activate(pc,
    tag, dev,
    fun)NULL then restoring
      from state D3 is going to fail.pci_chipset_tag_create(opc,
    present, ov,
    ctx, pcp)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_READPCI_OVERRIDE_CONF_WRITEPCI_OVERRIDE_INTR_MAPPCI_OVERRIDE_INTR_STRINGPCI_OVERRIDE_INTR_EVCNTPCI_OVERRIDE_INTR_ESTABLISHPCI_OVERRIDE_INTR_DISESTABLISHPCI_OVERRIDE_MAKE_TAGPCI_OVERRIDE_DECOMPOSE_TAGpci_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)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)pci_conf_write(pc,
    tag, reg,
    val)pci_conf_print(pc,
    tag, func)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)pci_conf_restore(pc,
    tag, pcs)pci_find_device(pa,
    func)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)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)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)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_get_segment(pc)__HAVE_PCI_GET_SEGMENT is defined in the header
      <machine/pci_machdep.h>.pci_mapreg_type(pc,
    tag, reg)PCI_MAPREG_TYPE_IOPCI_MAPREG_TYPE_MEMPCI_MAPREG_TYPE_MEM
        |
        PCI_MAPREG_MEM_TYPE_64BITPCI_MAPREG_TYPE_ROMPCI_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)pci_mapreg_type(), are:
    PCI_MAPREG_TYPE_IOPCI_MAPREG_TYPE_MEMPCI_MAPREG_TYPE_MEM
        |
        PCI_MAPREG_MEM_TYPE_64BITPCI_MAPREG_TYPE_ROMPCI_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)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)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_X86PCI_ROM_CODE_TYPE_OFWPCI_ROM_CODE_TYPE_HPPAThe 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)pci_intr_string(pc,
    ih)pci_intr_evcnt(pc,
    ih)pci_intr_establish(pc,
    ih, level,
    handler, arg)pci_intr_establish_xname(pc,
    ih, level,
    handler, arg,
    xname)pci_intr_disestablish(pc,
    ih)pci_intr_type(pc,
    ih)pci_intr_setattr(pc,
    ih, attr,
    data)pci_set_powerstate(pc,
    tag, newstate)pci_get_powerstate(pc,
    tag, state)pci_vpd_read(pc,
    tag, offset,
    count, data)pci_vpd_write(pc,
    tag, offset,
    count, data)pci_make_tag(pc,
    bus, device,
    function)pci_decompose_tag(pc,
    tag, busp,
    devicep, fnp)pci_make_tag() into its ⟨bus, device,
      function⟩ tuple.pci_findvendor(id)pci_devinfo(id,
    class, show,
    cp, len)pci_aprint_devinfo(pa,
    naive)PCI_VENDOR(id)PCI_PRODUCT(id)PCI_REVISION(id)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).
During system shutdown, it is necessary to abort any DMA transfers in progress by registering a shutdown hook (see pmf(9)).
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.
| November 2, 2018 | NetBSD 9.4 |