summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2012-03-03 18:08:57 +0000
committerjhb <jhb@FreeBSD.org>2012-03-03 18:08:57 +0000
commitdb63f69541c624629331258004b800e1929a9140 (patch)
tree327afe671bfb97e2bc7f889c317c4b18da45a8e2
parent5794e3ef03066c06566d80796cdb60efbe337733 (diff)
downloadFreeBSD-src-db63f69541c624629331258004b800e1929a9140.zip
FreeBSD-src-db63f69541c624629331258004b800e1929a9140.tar.gz
Expand the set of APIs available for locating PCI capabilities:
- pci_find_extcap() is repurposed to be used for fetching PCI-express extended capabilities (PCIZ_* constants in <dev/pci/pcireg.h>). - pci_find_htcap() can be used to locate a specific HyperTransport capability (PCIM_HTCAP_* constants in <dev/pci/pcireg.h>). - Cache the starting location of the PCI-express capability for PCI-express devices in PCI device ivars.
-rw-r--r--sys/dev/pci/hostb_pci.c18
-rw-r--r--sys/dev/pci/pci.c101
-rw-r--r--sys/dev/pci/pci_if.m14
-rw-r--r--sys/dev/pci/pci_private.h4
-rw-r--r--sys/dev/pci/pcivar.h15
-rw-r--r--sys/dev/pci/vga_pci.c18
-rw-r--r--sys/dev/siba/siba_bwn.c18
7 files changed, 181 insertions, 7 deletions
diff --git a/sys/dev/pci/hostb_pci.c b/sys/dev/pci/hostb_pci.c
index 2e1d611..4e28691 100644
--- a/sys/dev/pci/hostb_pci.c
+++ b/sys/dev/pci/hostb_pci.c
@@ -197,6 +197,14 @@ pci_hostb_assign_interrupt(device_t dev, device_t child)
}
static int
+pci_hostb_find_cap(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+
+ return (pci_find_cap(dev, capability, capreg));
+}
+
+static int
pci_hostb_find_extcap(device_t dev, device_t child, int capability,
int *capreg)
{
@@ -204,6 +212,14 @@ pci_hostb_find_extcap(device_t dev, device_t child, int capability,
return (pci_find_extcap(dev, capability, capreg));
}
+static int
+pci_hostb_find_htcap(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+
+ return (pci_find_htcap(dev, capability, capreg));
+}
+
static device_method_t pci_hostb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pci_hostb_probe),
@@ -233,7 +249,9 @@ static device_method_t pci_hostb_methods[] = {
DEVMETHOD(pci_get_powerstate, pci_hostb_get_powerstate),
DEVMETHOD(pci_set_powerstate, pci_hostb_set_powerstate),
DEVMETHOD(pci_assign_interrupt, pci_hostb_assign_interrupt),
+ DEVMETHOD(pci_find_cap, pci_hostb_find_cap),
DEVMETHOD(pci_find_extcap, pci_hostb_find_extcap),
+ DEVMETHOD(pci_find_htcap, pci_hostb_find_htcap),
{ 0, 0 }
};
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 6817ef3..e49308e 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -177,7 +177,9 @@ static device_method_t pci_methods[] = {
DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method),
DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method),
DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
+ DEVMETHOD(pci_find_cap, pci_find_cap_method),
DEVMETHOD(pci_find_extcap, pci_find_extcap_method),
+ DEVMETHOD(pci_find_htcap, pci_find_htcap_method),
DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method),
DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method),
DEVMETHOD(pci_remap_msix, pci_remap_msix_method),
@@ -737,6 +739,9 @@ pci_read_cap(device_t pcib, pcicfgregs *cfg)
* at least one PCI-express device.
*/
pcie_chipset = 1;
+ cfg->pcie.pcie_location = ptr;
+ val = REG(ptr + PCIR_EXPRESS_FLAGS, 2);
+ cfg->pcie.pcie_type = val & PCIM_EXP_FLAGS_TYPE;
break;
default:
break;
@@ -1154,12 +1159,55 @@ pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw,
}
/*
- * Find the requested extended capability and return the offset in
- * configuration space via the pointer provided. The function returns
- * 0 on success and error code otherwise.
+ * Find the requested HyperTransport capability and return the offset
+ * in configuration space via the pointer provided. The function
+ * returns 0 on success and an error code otherwise.
*/
int
-pci_find_extcap_method(device_t dev, device_t child, int capability,
+pci_find_htcap_method(device_t dev, device_t child, int capability, int *capreg)
+{
+ int ptr, error;
+ uint16_t val;
+
+ error = pci_find_cap(child, PCIY_HT, &ptr);
+ if (error)
+ return (error);
+
+ /*
+ * Traverse the capabilities list checking each HT capability
+ * to see if it matches the requested HT capability.
+ */
+ while (ptr != 0) {
+ val = pci_read_config(child, ptr + PCIR_HT_COMMAND, 2);
+ if (capability == PCIM_HTCAP_SLAVE ||
+ capability == PCIM_HTCAP_HOST)
+ val &= 0xe000;
+ else
+ val &= PCIM_HTCMD_CAP_MASK;
+ if (val == capability) {
+ if (capreg != NULL)
+ *capreg = ptr;
+ return (0);
+ }
+
+ /* Skip to the next HT capability. */
+ while (ptr != 0) {
+ ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1);
+ if (pci_read_config(child, ptr + PCICAP_ID, 1) ==
+ PCIY_HT)
+ break;
+ }
+ }
+ return (ENOENT);
+}
+
+/*
+ * Find the requested capability and return the offset in
+ * configuration space via the pointer provided. The function returns
+ * 0 on success and an error code otherwise.
+ */
+int
+pci_find_cap_method(device_t dev, device_t child, int capability,
int *capreg)
{
struct pci_devinfo *dinfo = device_get_ivars(child);
@@ -1207,6 +1255,43 @@ pci_find_extcap_method(device_t dev, device_t child, int capability,
}
/*
+ * Find the requested extended capability and return the offset in
+ * configuration space via the pointer provided. The function returns
+ * 0 on success and an error code otherwise.
+ */
+int
+pci_find_extcap_method(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+ struct pci_devinfo *dinfo = device_get_ivars(child);
+ pcicfgregs *cfg = &dinfo->cfg;
+ uint32_t ecap;
+ uint16_t ptr;
+
+ /* Only supported for PCI-express devices. */
+ if (cfg->pcie.pcie_location == 0)
+ return (ENXIO);
+
+ ptr = PCIR_EXTCAP;
+ ecap = pci_read_config(child, ptr, 4);
+ if (ecap == 0xffffffff || ecap == 0)
+ return (ENOENT);
+ for (;;) {
+ if (PCI_EXTCAP_ID(ecap) == capability) {
+ if (capreg != NULL)
+ *capreg = ptr;
+ return (0);
+ }
+ ptr = PCI_EXTCAP_NEXTPTR(ecap);
+ if (ptr == 0)
+ break;
+ ecap = pci_read_config(child, ptr, 4);
+ }
+
+ return (ENOENT);
+}
+
+/*
* Support for MSI-X message interrupts.
*/
void
@@ -1696,10 +1781,12 @@ pci_ht_map_msi(device_t dev, uint64_t addr)
int
pci_get_max_read_req(device_t dev)
{
+ struct pci_devinfo *dinfo = device_get_ivars(dev);
int cap;
uint16_t val;
- if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
+ cap = dinfo->cfg.pcie.pcie_location;
+ if (cap == 0)
return (0);
val = pci_read_config(dev, cap + PCIR_EXPRESS_DEVICE_CTL, 2);
val &= PCIM_EXP_CTL_MAX_READ_REQUEST;
@@ -1710,10 +1797,12 @@ pci_get_max_read_req(device_t dev)
int
pci_set_max_read_req(device_t dev, int size)
{
+ struct pci_devinfo *dinfo = device_get_ivars(dev);
int cap;
uint16_t val;
- if (pci_find_cap(dev, PCIY_EXPRESS, &cap) != 0)
+ cap = dinfo->cfg.pcie.pcie_location;
+ if (cap == 0)
return (0);
if (size < 128)
size = 128;
diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m
index 05dfa38..e35d79e 100644
--- a/sys/dev/pci/pci_if.m
+++ b/sys/dev/pci/pci_if.m
@@ -105,6 +105,13 @@ METHOD int assign_interrupt {
device_t child;
};
+METHOD int find_cap {
+ device_t dev;
+ device_t child;
+ int capability;
+ int *capreg;
+};
+
METHOD int find_extcap {
device_t dev;
device_t child;
@@ -112,6 +119,13 @@ METHOD int find_extcap {
int *capreg;
};
+METHOD int find_htcap {
+ device_t dev;
+ device_t child;
+ int capability;
+ int *capreg;
+};
+
METHOD int alloc_msi {
device_t dev;
device_t child;
diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h
index c5b2cd8..5a083bf 100644
--- a/sys/dev/pci/pci_private.h
+++ b/sys/dev/pci/pci_private.h
@@ -80,8 +80,12 @@ int pci_enable_busmaster_method(device_t dev, device_t child);
int pci_disable_busmaster_method(device_t dev, device_t child);
int pci_enable_io_method(device_t dev, device_t child, int space);
int pci_disable_io_method(device_t dev, device_t child, int space);
+int pci_find_cap_method(device_t dev, device_t child,
+ int capability, int *capreg);
int pci_find_extcap_method(device_t dev, device_t child,
int capability, int *capreg);
+int pci_find_htcap_method(device_t dev, device_t child,
+ int capability, int *capreg);
int pci_alloc_msi_method(device_t dev, device_t child, int *count);
int pci_alloc_msix_method(device_t dev, device_t child, int *count);
int pci_remap_msix_method(device_t dev, device_t child,
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index fe00cfe..44e9408 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -123,6 +123,12 @@ struct pcicfg_ht {
uint64_t ht_msiaddr; /* MSI mapping base address */
};
+/* Interesting values for PCI-express */
+struct pcicfg_pcie {
+ uint8_t pcie_location; /* Offset of PCI-e capability registers. */
+ uint8_t pcie_type; /* Device type. */
+};
+
/* config header information common to all header types */
typedef struct pcicfg {
struct device *dev; /* device which owns this */
@@ -164,6 +170,7 @@ typedef struct pcicfg {
struct pcicfg_msi msi; /* PCI MSI */
struct pcicfg_msix msix; /* PCI MSI-X */
struct pcicfg_ht ht; /* HyperTransport */
+ struct pcicfg_pcie pcie; /* PCI Express */
} pcicfgregs;
/* additional type 1 device config header information (PCI to PCI bridge) */
@@ -409,7 +416,7 @@ pci_get_powerstate(device_t dev)
static __inline int
pci_find_cap(device_t dev, int capability, int *capreg)
{
- return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, capreg));
+ return (PCI_FIND_CAP(device_get_parent(dev), dev, capability, capreg));
}
static __inline int
@@ -419,6 +426,12 @@ pci_find_extcap(device_t dev, int capability, int *capreg)
}
static __inline int
+pci_find_htcap(device_t dev, int capability, int *capreg)
+{
+ return (PCI_FIND_HTCAP(device_get_parent(dev), dev, capability, capreg));
+}
+
+static __inline int
pci_alloc_msi(device_t dev, int *count)
{
return (PCI_ALLOC_MSI(device_get_parent(dev), dev, count));
diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c
index cb1f8c1..fc96848 100644
--- a/sys/dev/pci/vga_pci.c
+++ b/sys/dev/pci/vga_pci.c
@@ -314,6 +314,14 @@ vga_pci_assign_interrupt(device_t dev, device_t child)
}
static int
+vga_pci_find_cap(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+
+ return (pci_find_cap(dev, capability, capreg));
+}
+
+static int
vga_pci_find_extcap(device_t dev, device_t child, int capability,
int *capreg)
{
@@ -322,6 +330,14 @@ vga_pci_find_extcap(device_t dev, device_t child, int capability,
}
static int
+vga_pci_find_htcap(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+
+ return (pci_find_htcap(dev, capability, capreg));
+}
+
+static int
vga_pci_alloc_msi(device_t dev, device_t child, int *count)
{
struct vga_pci_softc *sc;
@@ -422,7 +438,9 @@ static device_method_t vga_pci_methods[] = {
DEVMETHOD(pci_get_powerstate, vga_pci_get_powerstate),
DEVMETHOD(pci_set_powerstate, vga_pci_set_powerstate),
DEVMETHOD(pci_assign_interrupt, vga_pci_assign_interrupt),
+ DEVMETHOD(pci_find_cap, vga_pci_find_cap),
DEVMETHOD(pci_find_extcap, vga_pci_find_extcap),
+ DEVMETHOD(pci_find_htcap, vga_pci_find_htcap),
DEVMETHOD(pci_alloc_msi, vga_pci_alloc_msi),
DEVMETHOD(pci_alloc_msix, vga_pci_alloc_msix),
DEVMETHOD(pci_remap_msix, vga_pci_remap_msix),
diff --git a/sys/dev/siba/siba_bwn.c b/sys/dev/siba/siba_bwn.c
index 43c52bd..278ab9f 100644
--- a/sys/dev/siba/siba_bwn.c
+++ b/sys/dev/siba/siba_bwn.c
@@ -279,6 +279,14 @@ siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq,
}
static int
+siba_bwn_find_cap(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+
+ return (pci_find_cap(dev, capability, capreg));
+}
+
+static int
siba_bwn_find_extcap(device_t dev, device_t child, int capability,
int *capreg)
{
@@ -287,6 +295,14 @@ siba_bwn_find_extcap(device_t dev, device_t child, int capability,
}
static int
+siba_bwn_find_htcap(device_t dev, device_t child, int capability,
+ int *capreg)
+{
+
+ return (pci_find_htcap(dev, capability, capreg));
+}
+
+static int
siba_bwn_alloc_msi(device_t dev, device_t child, int *count)
{
struct siba_bwn_softc *ssc;
@@ -405,7 +421,9 @@ static device_method_t siba_bwn_methods[] = {
DEVMETHOD(bus_teardown_intr, siba_bwn_teardown_intr),
/* PCI interface */
+ DEVMETHOD(pci_find_cap, siba_bwn_find_cap),
DEVMETHOD(pci_find_extcap, siba_bwn_find_extcap),
+ DEVMETHOD(pci_find_htcap, siba_bwn_find_htcap),
DEVMETHOD(pci_alloc_msi, siba_bwn_alloc_msi),
DEVMETHOD(pci_release_msi, siba_bwn_release_msi),
DEVMETHOD(pci_msi_count, siba_bwn_msi_count),
OpenPOWER on IntegriCloud