From b4c0a84530e055bbe21616cd0e2b59bd24373cb3 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 25 Nov 2007 04:08:42 +0000 Subject: [PATCH] Cache following information for PCI Express capability: - Capability PTR - PCI Express Capabilities register - Slot Capabilities register Print them if 'bootverbose'. Above information should be enough for identifying PCI Express hot-plug support, e.g. ExpressCard --- sys/bus/pci/pci.c | 116 ++++++++++++++++++++++++++++++++++++++++++- sys/bus/pci/pcireg.h | 31 +++++++++++- sys/bus/pci/pcivar.h | 14 ++++-- 3 files changed, 156 insertions(+), 5 deletions(-) diff --git a/sys/bus/pci/pci.c b/sys/bus/pci/pci.c index 97c83c4224..9c358ac0fc 100644 --- a/sys/bus/pci/pci.c +++ b/sys/bus/pci/pci.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/pci/pci.c,v 1.141.2.15 2002/04/30 17:48:18 tmm Exp $ - * $DragonFly: src/sys/bus/pci/pci.c,v 1.47 2007/11/25 02:17:56 sephe Exp $ + * $DragonFly: src/sys/bus/pci/pci.c,v 1.48 2007/11/25 04:08:42 sephe Exp $ * */ @@ -485,6 +485,51 @@ pci_read_cap_pmgt(device_t pcib, int ptr, pcicfgregs *cfg) #undef REG } +static void +pci_read_cap_expr(device_t pcib, int ptr, pcicfgregs *cfg) +{ +#define REG(n, w) \ + PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) + + struct pcicfg_expr *expr = &cfg->expr; + uint16_t port_type; + + expr->expr_ptr = ptr; + expr->expr_cap = REG(ptr + PCIER_CAPABILITY, 2); + + /* + * Only version 1 can be parsed currently + */ + if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1) + return; + + /* + * Read slot capabilities + * + * Slot capabilities exists iff current port is root port or + * down stream port, and the slot is implemented. + * + * - Testing for root port or down stream port is meanningful + * iff PCI configure has type 1 header. + * - Slot implemented bit is meaningful iff current port is + * root port or down stream port. + */ + if (cfg->hdrtype != 1) + return; + + port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE; + if (port_type != PCIEM_ROOT_PORT && + port_type != PCIEM_DOWN_STREAM_PORT) + return; + + if (!(expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) + return; + + expr->expr_slotcap = REG(ptr + PCIER_SLOTCAP, 4); + +#undef REG +} + static void pci_read_capabilities(device_t pcib, pcicfgregs *cfg) { @@ -522,6 +567,9 @@ pci_read_capabilities(device_t pcib, pcicfgregs *cfg) case PCIY_PMG: /* PCI power management */ pci_read_cap_pmgt(pcib, ptr, cfg); break; + case PCIY_EXPRESS: /* PCI Express */ + pci_read_cap_expr(pcib, ptr, cfg); + break; default: break; } @@ -1288,6 +1336,70 @@ pci_class_to_string(int baseclass) return(name); } +static void +pci_print_verbose_expr(const pcicfgregs *cfg) +{ + const struct pcicfg_expr *expr = &cfg->expr; + const char *port_name; + uint16_t port_type; + + if (!bootverbose) + return; + + if (expr->expr_ptr == 0) /* No PCI Express capability */ + return; + + kprintf("\tPCI Express ver.%d cap=0x%04x", + expr->expr_cap & PCIEM_CAP_VER_MASK, expr->expr_cap); + if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1) + goto back; + + port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE; + + switch (port_type) { + case PCIEM_END_POINT: + port_name = "DEVICE"; + break; + case PCIEM_LEG_END_POINT: + port_name = "LEGDEV"; + break; + case PCIEM_ROOT_PORT: + port_name = "ROOT"; + break; + case PCIEM_UP_STREAM_PORT: + port_name = "UPSTREAM"; + break; + case PCIEM_DOWN_STREAM_PORT: + port_name = "DOWNSTRM"; + break; + case PCIEM_PCIE2PCI_BRIDGE: + port_name = "PCIE2PCI"; + break; + case PCIEM_PCI2PCIE_BRIDGE: + port_name = "PCI2PCIE"; + break; + default: + port_name = NULL; + break; + } + if ((port_type == PCIEM_ROOT_PORT || + port_type == PCIEM_DOWN_STREAM_PORT) && + !(expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) + port_name = NULL; + if (port_name != NULL) + kprintf("[%s]", port_name); + + if ((port_type == PCIEM_ROOT_PORT || + port_type == PCIEM_DOWN_STREAM_PORT) && + (expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) { + kprintf(", slotcap=0x%08x", expr->expr_slotcap); + if (expr->expr_slotcap & PCIEM_SLTCAP_HP_CAP) + kprintf("[HOTPLUG]"); + } +back: + kprintf("\n"); +} + void pci_print_verbose(struct pci_devinfo *dinfo) { @@ -1313,6 +1425,8 @@ pci_print_verbose(struct pci_devinfo *dinfo) #endif /* PCI_DEBUG */ if (cfg->intpin > 0) kprintf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + + pci_print_verbose_expr(cfg); } } diff --git a/sys/bus/pci/pcireg.h b/sys/bus/pci/pcireg.h index 453c37a389..33864eecd7 100644 --- a/sys/bus/pci/pcireg.h +++ b/sys/bus/pci/pcireg.h @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/pci/pcireg.h,v 1.24.2.5 2002/08/31 10:06:51 gibbs Exp $ - * $DragonFly: src/sys/bus/pci/pcireg.h,v 1.14 2007/11/23 13:40:58 sephe Exp $ + * $DragonFly: src/sys/bus/pci/pcireg.h,v 1.15 2007/11/25 04:08:42 sephe Exp $ * */ @@ -422,6 +422,35 @@ #define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ #define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ +/* PCI Express definitions */ + +#define PCIER_CAPABILITY 0x2 +#define PCIEM_CAP_VER_MASK 0x000f /* Version */ +#define PCIEM_CAP_VER_1 0x0001 +#define PCIEM_CAP_PORT_TYPE 0x00f0 /* Port type mask */ +#define PCIEM_CAP_SLOT_IMPL 0x0100 /* Slot implemented, + * valid only for root port and + * switch downstream port + */ + /* PCI Express port types */ +#define PCIEM_END_POINT 0x0000 /* Endpoint device */ +#define PCIEM_LEG_END_POINT 0x0010 /* Legacy endpoint device */ +#define PCIEM_ROOT_PORT 0x0040 /* Root port */ +#define PCIEM_UP_STREAM_PORT 0x0050 /* Switch upstream port */ +#define PCIEM_DOWN_STREAM_PORT 0x0060 /* Switch downstream port */ +#define PCIEM_PCIE2PCI_BRIDGE 0x0070 /* PCI Express to PCI/PCI-X bridge */ +#define PCIEM_PCI2PCIE_BRIDGE 0x0080 /* PCI/PCI-X to PCI Express bridge */ + +#define PCIER_SLOTCAP 0x14 +#define PCIEM_SLTCAP_ATTEN_BTN 0x00000001 /* Attention button present */ +#define PCIEM_SLTCAP_PWR_CTRL 0x00000002 /* Power controller present */ +#define PCIEM_SLTCAP_MRL_SNS 0x00000004 /* MRL sensor present */ +#define PCIEM_SLTCAP_ATTEN_IND 0x00000008 /* Attention indicator present */ +#define PCIEM_SLTCAP_PWR_IND 0x00000010 /* Power indicator present */ +#define PCIEM_SLTCAP_HP_SURP 0x00000020 /* Hot-Plug surprise */ +#define PCIEM_SLTCAP_HP_CAP 0x00000040 /* Hot-Plug capable */ +#define PCIEM_SLTCAP_HP_MASK 0x0000007f /* Hot-Plug related bits */ + /* for compatibility to FreeBSD-2.2 and 3.x versions of PCI code */ #if defined(_KERNEL) && !defined(KLD_MODULE) diff --git a/sys/bus/pci/pcivar.h b/sys/bus/pci/pcivar.h index fbc3e15d46..26f31ce3ab 100644 --- a/sys/bus/pci/pcivar.h +++ b/sys/bus/pci/pcivar.h @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/pci/pcivar.h,v 1.48 2000/09/28 00:37:32 peter Exp $ - * $DragonFly: src/sys/bus/pci/pcivar.h,v 1.12 2007/11/23 14:41:56 sephe Exp $ + * $DragonFly: src/sys/bus/pci/pcivar.h,v 1.13 2007/11/25 04:08:42 sephe Exp $ * */ @@ -52,7 +52,7 @@ typedef u_int64_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ typedef u_int32_t pci_addr_t; /* u_int64_t for system with 64bit addresses */ #endif -/* config values for PCI power management */ +/* config values for PCI power management capability */ struct pcicfg_pmgt { u_int16_t pp_cap; /* PCI power management capabilities */ u_int8_t pp_status; /* config space address of PCI power status reg */ @@ -60,6 +60,13 @@ struct pcicfg_pmgt { u_int8_t pp_data; /* config space address of PCI power data reg */ }; +/* config values for PCI Express capability */ +struct pcicfg_expr { + uint8_t expr_ptr; /* capability ptr */ + uint16_t expr_cap; /* capabilities */ + uint32_t expr_slotcap; /* slot capabilities */ +}; + /* config header information common to all header types */ typedef struct pcicfg { @@ -98,7 +105,8 @@ typedef struct pcicfg { u_int8_t secondarybus; /* bus on secondary side of bridge, if any */ u_int8_t subordinatebus; /* topmost bus number behind bridge, if any */ - struct pcicfg_pmgt pmgt; /* power management */ + struct pcicfg_pmgt pmgt; /* power management capability */ + struct pcicfg_expr expr; /* PCI Express capability */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */ -- 2.41.0