diff options
author | jhb <jhb@FreeBSD.org> | 2012-03-03 18:08:57 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2012-03-03 18:08:57 +0000 |
commit | db63f69541c624629331258004b800e1929a9140 (patch) | |
tree | 327afe671bfb97e2bc7f889c317c4b18da45a8e2 | |
parent | 5794e3ef03066c06566d80796cdb60efbe337733 (diff) | |
download | FreeBSD-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.c | 18 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 101 | ||||
-rw-r--r-- | sys/dev/pci/pci_if.m | 14 | ||||
-rw-r--r-- | sys/dev/pci/pci_private.h | 4 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 15 | ||||
-rw-r--r-- | sys/dev/pci/vga_pci.c | 18 | ||||
-rw-r--r-- | sys/dev/siba/siba_bwn.c | 18 |
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), |