From c668000b692a29b66b3836d8af066d17dccfc779 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Sat, 3 Mar 2012 18:08:57 +0000 Subject: [PATCH] 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 ). - pci_find_htcap() can be used to locate a specific HyperTransport capability (PCIM_HTCAP_* constants in ). - Cache the starting location of the PCI-express capability for PCI-express devices in PCI device ivars. --- sys/dev/pci/hostb_pci.c | 18 +++++++ sys/dev/pci/pci.c | 101 +++++++++++++++++++++++++++++++++++--- sys/dev/pci/pci_if.m | 14 ++++++ sys/dev/pci/pci_private.h | 4 ++ sys/dev/pci/pcivar.h | 15 +++++- sys/dev/pci/vga_pci.c | 18 +++++++ 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 2e1d61144f6a..4e28691d31f9 100644 --- a/sys/dev/pci/hostb_pci.c +++ b/sys/dev/pci/hostb_pci.c @@ -196,6 +196,14 @@ pci_hostb_assign_interrupt(device_t dev, device_t child) return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev)); } +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 6817ef38ff95..e49308e22067 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); @@ -1206,6 +1254,43 @@ pci_find_extcap_method(device_t dev, device_t child, int capability, return (ENOENT); } +/* + * 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. */ @@ -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 05dfa382d96b..e35d79ecbadc 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 c5b2cd895f38..5a083bfa5663 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 fe00cfe9126d..44e940856a29 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 @@ -418,6 +425,12 @@ pci_find_extcap(device_t dev, int capability, int *capreg) return (PCI_FIND_EXTCAP(device_get_parent(dev), dev, capability, 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) { diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c index cb1f8c19bfc7..fc9684828594 100644 --- a/sys/dev/pci/vga_pci.c +++ b/sys/dev/pci/vga_pci.c @@ -313,6 +313,14 @@ vga_pci_assign_interrupt(device_t dev, device_t child) return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev)); } +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) @@ -321,6 +329,14 @@ vga_pci_find_extcap(device_t dev, device_t child, int capability, return (pci_find_extcap(dev, capability, capreg)); } +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) { @@ -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 43c52bd46c4e..278ab9f03abc 100644 --- a/sys/dev/siba/siba_bwn.c +++ b/sys/dev/siba/siba_bwn.c @@ -278,6 +278,14 @@ siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq, return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie)); } +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) @@ -286,6 +294,14 @@ siba_bwn_find_extcap(device_t dev, device_t child, int capability, return (pci_find_extcap(dev, capability, capreg)); } +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) { @@ -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),