Add helper routines for PCI device drivers to read, write, and modify
PCI-Express capability registers (that is, PCI config registers in the standard PCI config space belonging to the PCI-Express capability register set). Note that all of the current PCI-e registers are either 16 or 32-bits, so only widths of 2 or 4 bytes are supported. Reviewed by: imp MFC after: 1 week Sponsored by: Chelsio Differential Revision: https://reviews.freebsd.org/D4088
This commit is contained in:
parent
42d9b66898
commit
0c12e4753b
@ -1290,7 +1290,10 @@ MLINKS+=pci.9 pci_alloc_msi.9 \
|
||||
pci.9 pci_save_state.9 \
|
||||
pci.9 pci_set_powerstate.9 \
|
||||
pci.9 pci_set_max_read_req.9 \
|
||||
pci.9 pci_write_config.9
|
||||
pci.9 pci_write_config.9 \
|
||||
pci.9 pcie_adjust_config.9 \
|
||||
pci.9 pcie_read_config.9 \
|
||||
pci.9 pcie_write_config.9 \
|
||||
MLINKS+=pci_iov_schema.9 pci_iov_schema_alloc_node.9 \
|
||||
pci_iov_schema.9 pci_iov_schema_add_bool.9 \
|
||||
pci_iov_schema.9 pci_iov_schema_add_string.9 \
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 8, 2015
|
||||
.Dd November 5, 2015
|
||||
.Dt PCI 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -58,7 +58,10 @@
|
||||
.Nm pci_save_state ,
|
||||
.Nm pci_set_max_read_req ,
|
||||
.Nm pci_set_powerstate ,
|
||||
.Nm pci_write_config
|
||||
.Nm pci_write_config ,
|
||||
.Nm pcie_adjust_config ,
|
||||
.Nm pcie_read_config ,
|
||||
.Nm pcie_write_config
|
||||
.Nd PCI bus interface
|
||||
.Sh SYNOPSIS
|
||||
.In sys/bus.h
|
||||
@ -118,6 +121,18 @@
|
||||
.Fn pci_set_powerstate "device_t dev" "int state"
|
||||
.Ft void
|
||||
.Fn pci_write_config "device_t dev" "int reg" "uint32_t val" "int width"
|
||||
.Ft uint32_t
|
||||
.Fo pcie_adjust_config
|
||||
.Fa "device_t dev"
|
||||
.Fa "int reg"
|
||||
.Fa "uint32_t mask"
|
||||
.Fa "uint32_t val"
|
||||
.Fa "int width"
|
||||
.Fc
|
||||
.Ft uint32_t
|
||||
.Fn pcie_read_config "device_t dev" "int reg" "int width"
|
||||
.Ft void
|
||||
.Fn pcie_write_config "device_t dev" "int reg" "uint32_t val" "int width"
|
||||
.In dev/pci/pci_iov.h
|
||||
.Ft int
|
||||
.Fn pci_iov_attach "device_t dev" "nvlist_t *pf_schema" "nvlist_t *vf_schema"
|
||||
@ -159,6 +174,48 @@ with
|
||||
.Fa width
|
||||
specifying the size of the access.
|
||||
.Pp
|
||||
The
|
||||
.Fn pcie_adjust_config
|
||||
function is used to modify the value of a register in the PCI-express
|
||||
capability register set of device
|
||||
.Fa dev .
|
||||
The offset
|
||||
.Fa reg
|
||||
specifies a relative offset in the register set with
|
||||
.Fa width
|
||||
specifying the size of the access.
|
||||
The new value of the register is computed by modifying bits set in
|
||||
.Fa mask
|
||||
to the value in
|
||||
.Fa val .
|
||||
Any bits not specified in
|
||||
.Fa mask
|
||||
are preserved.
|
||||
The previous value of the register is returned.
|
||||
.Pp
|
||||
The
|
||||
.Fn pcie_read_config
|
||||
function is used to read the value of a register in the PCI-express
|
||||
capability register set of device
|
||||
.Fa dev .
|
||||
The offset
|
||||
.Fa reg
|
||||
specifies a relative offset in the register set with
|
||||
.Fa width
|
||||
specifying the size of the access.
|
||||
.Pp
|
||||
The
|
||||
.Fn pcie_write_config
|
||||
function is used to write the value
|
||||
.Fa val
|
||||
to a register in the PCI-express capability register set of device
|
||||
.Fa dev .
|
||||
The offset
|
||||
.Fa reg
|
||||
specifies a relative offset in the register set with
|
||||
.Fa width
|
||||
specifying the size of the access.
|
||||
.Pp
|
||||
.Em NOTE :
|
||||
Device drivers should only use these functions for functionality that
|
||||
is not available via another
|
||||
|
@ -1917,6 +1917,63 @@ pci_set_max_read_req(device_t dev, int size)
|
||||
return (size);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pcie_read_config(device_t dev, int reg, int width)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(dev);
|
||||
int cap;
|
||||
|
||||
cap = dinfo->cfg.pcie.pcie_location;
|
||||
if (cap == 0) {
|
||||
if (width == 2)
|
||||
return (0xffff);
|
||||
return (0xffffffff);
|
||||
}
|
||||
|
||||
return (pci_read_config(dev, cap + reg, width));
|
||||
}
|
||||
|
||||
void
|
||||
pcie_write_config(device_t dev, int reg, uint32_t value, int width)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(dev);
|
||||
int cap;
|
||||
|
||||
cap = dinfo->cfg.pcie.pcie_location;
|
||||
if (cap == 0)
|
||||
return;
|
||||
pci_write_config(dev, cap + reg, value, width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjusts a PCI-e capability register by clearing the bits in mask
|
||||
* and setting the bits in (value & mask). Bits not set in mask are
|
||||
* not adjusted.
|
||||
*
|
||||
* Returns the old value on success or all ones on failure.
|
||||
*/
|
||||
uint32_t
|
||||
pcie_adjust_config(device_t dev, int reg, uint32_t mask, uint32_t value,
|
||||
int width)
|
||||
{
|
||||
struct pci_devinfo *dinfo = device_get_ivars(dev);
|
||||
uint32_t old, new;
|
||||
int cap;
|
||||
|
||||
cap = dinfo->cfg.pcie.pcie_location;
|
||||
if (cap == 0) {
|
||||
if (width == 2)
|
||||
return (0xffff);
|
||||
return (0xffffffff);
|
||||
}
|
||||
|
||||
old = pci_read_config(dev, cap + reg, width);
|
||||
new = old & ~mask;
|
||||
new |= (value & mask);
|
||||
pci_write_config(dev, cap + reg, new, width);
|
||||
return (old);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for MSI message signalled interrupts.
|
||||
*/
|
||||
|
@ -551,6 +551,10 @@ int pci_get_max_read_req(device_t dev);
|
||||
void pci_restore_state(device_t dev);
|
||||
void pci_save_state(device_t dev);
|
||||
int pci_set_max_read_req(device_t dev, int size);
|
||||
uint32_t pcie_read_config(device_t dev, int reg, int width);
|
||||
void pcie_write_config(device_t dev, int reg, uint32_t value, int width);
|
||||
uint32_t pcie_adjust_config(device_t dev, int reg, uint32_t mask,
|
||||
uint32_t value, int width);
|
||||
|
||||
|
||||
#ifdef BUS_SPACE_MAXADDR
|
||||
|
Loading…
x
Reference in New Issue
Block a user