summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/pci.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 587881a..65f315d 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/syslog.h>
+#include <sys/errno.h>
#include <dev/pci/pci.h>
#include <dev/pci/pciregs.h>
#include <vm/dynalloc.h>
@@ -58,6 +59,47 @@ pci_dev_exists(uint8_t bus, uint8_t slot, uint8_t func)
}
/*
+ * Attempt to search for a capability within the device
+ * capability list if it supports one.
+ *
+ * @dev: Target device.
+ * @id: Requested capability ID.
+ *
+ * The offset is returned if found, otherwise 0.
+ * A value less than zero is returned on error.
+ */
+static int
+pci_get_cap(struct pci_device *dev, uint8_t id)
+{
+ uint16_t status;
+ uint32_t cap;
+ uint8_t curid;
+ uint8_t cap_ptr;
+
+ /* Does the device even support this? */
+ status = pci_readl(dev, PCIREG_CMDSTATUS) >> 16;
+ if (!ISSET(status, PCI_STATUS_CAPLIST)) {
+ return -ENOTSUP;
+ }
+
+ cap_ptr = pci_readl(dev, PCIREG_CAPPTR) & 0xFF;
+
+ /* Go through the capability list */
+ while (cap_ptr != 0) {
+ cap = pci_readl(dev, cap_ptr);
+ curid = cap & 0xFF;
+
+ if (curid == id) {
+ return cap_ptr;
+ }
+
+ cap_ptr = (cap >> 8) & 0xFF;
+ }
+
+ return 0;
+}
+
+/*
* Sets other device information (device id, vendor id, etc)
*
* @dev: Device descriptor to set up.
@@ -85,6 +127,7 @@ pci_set_device_info(struct pci_device *dev)
dev->bar[5] = pci_readl(dev, PCIREG_BAR5);
dev->irq_line = pci_readl(dev, PCIREG_IRQLINE) & 0xFF;
+ dev->msix_capoff = pci_get_cap(dev, PCI_CAP_MSIX);
}
/*