aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2015-11-05 21:26:06 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2015-11-05 21:26:06 +0000
commitec603c729718833fbce3b91ed477d961a393c14a (patch)
tree8c409df6aaf8e0cc9b8b82131928b46509d8b572 /sys/dev/pci
parent34f2f73c8454544d741fed3be4777f2910987174 (diff)
downloadsrc-ec603c729718833fbce3b91ed477d961a393c14a.tar.gz
src-ec603c729718833fbce3b91ed477d961a393c14a.zip
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
Notes
Notes: svn path=/head/; revision=290414
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c57
-rw-r--r--sys/dev/pci/pcivar.h4
2 files changed, 61 insertions, 0 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 39d311f65095..5116a4fa579a 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 7f2e95836a30..242201b13390 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