summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2015-11-05 21:26:06 +0000
committerjhb <jhb@FreeBSD.org>2015-11-05 21:26:06 +0000
commit0c12e4753ba6951c7105eee5418f69cfda826f9c (patch)
tree8c409df6aaf8e0cc9b8b82131928b46509d8b572
parent42d9b66898a9a9cbc2e8113e8c44b5acebc7109b (diff)
downloadFreeBSD-src-0c12e4753ba6951c7105eee5418f69cfda826f9c.zip
FreeBSD-src-0c12e4753ba6951c7105eee5418f69cfda826f9c.tar.gz
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
-rw-r--r--share/man/man9/Makefile5
-rw-r--r--share/man/man9/pci.961
-rw-r--r--sys/dev/pci/pci.c57
-rw-r--r--sys/dev/pci/pcivar.h4
4 files changed, 124 insertions, 3 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 516d6c3..5ae857e 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -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 \
diff --git a/share/man/man9/pci.9 b/share/man/man9/pci.9
index 5d98e9c..2321638 100644
--- a/share/man/man9/pci.9
+++ b/share/man/man9/pci.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
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 39d311f..5116a4f 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -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.
*/
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 7f2e958..242201b 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -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
OpenPOWER on IntegriCloud