From: Sepherosa Ziehau Date: Sat, 4 Jul 2009 09:02:22 +0000 (+0800) Subject: pci: Put back PCI Express related bits X-Git-Tag: v2.3.2~36^2~31 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/d85e7311bf42b96a03082fb78256d729d379d354 pci: Put back PCI Express related bits --- diff --git a/sys/bus/pci/pci.c b/sys/bus/pci/pci.c index 6e3ed0b..414a596 100644 --- a/sys/bus/pci/pci.c +++ b/sys/bus/pci/pci.c @@ -113,6 +113,8 @@ static void pci_unmask_msix(device_t dev, u_int index); static int pci_msi_blacklisted(void); static void pci_resume_msi(device_t dev); static void pci_resume_msix(device_t dev); +static int pcie_slotimpl(const pcicfgregs *); +static void pci_print_verbose_expr(const pcicfgregs *); static void pci_read_cap_pmgt(device_t, int, int, pcicfgregs *); static void pci_read_cap_ht(device_t, int, int, pcicfgregs *); @@ -122,7 +124,7 @@ static void pci_read_cap_vpd(device_t, int, int, pcicfgregs *); static void pci_read_cap_subvendor(device_t, int, int, pcicfgregs *); static void pci_read_cap_pcix(device_t, int, int, pcicfgregs *); -static void pci_read_cap_pcie(device_t, int, int, pcicfgregs *); +static void pci_read_cap_express(device_t, int, int, pcicfgregs *); static device_method_t pci_methods[] = { /* Device interface */ @@ -198,7 +200,7 @@ static const struct pci_read_cap { { PCIY_VPD, pci_read_cap_vpd }, { PCIY_SUBVENDOR, pci_read_cap_subvendor }, { PCIY_PCIX, pci_read_cap_pcix }, - { PCIY_EXPRESS, pci_read_cap_pcie }, + { PCIY_EXPRESS, pci_read_cap_express }, { 0, NULL } /* required last entry */ }; @@ -737,16 +739,73 @@ pci_read_cap_pcix(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg) */ if ((cfg->hdrtype & PCIM_HDRTYPE) == 1) pcix_chipset = 1; + + cfg->pcix.pcix_ptr = ptr; +} + +static int +pcie_slotimpl(const pcicfgregs *cfg) +{ + const struct pcicfg_expr *expr = &cfg->expr; + uint16_t port_type; + + /* + * Only version 1 can be parsed currently + */ + if ((expr->expr_cap & PCIEM_CAP_VER_MASK) != PCIEM_CAP_VER_1) + return 0; + + /* + * - Slot implemented bit is meaningful iff current port is + * root port or down stream port. + * - Testing for root port or down stream port is meanningful + * iff PCI configure has type 1 header. + */ + + if (cfg->hdrtype != 1) + return 0; + + port_type = expr->expr_cap & PCIEM_CAP_PORT_TYPE; + if (port_type != PCIE_ROOT_PORT && port_type != PCIE_DOWN_STREAM_PORT) + return 0; + + if (!(expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) + return 0; + + return 1; } static void -pci_read_cap_pcie(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg) +pci_read_cap_express(device_t pcib, int ptr, int nextptr, pcicfgregs *cfg) { +#define REG(n, w) \ + PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) + + struct pcicfg_expr *expr = &cfg->expr; + /* * Assume we have a PCI-express chipset if we have * at least one PCI-express device. */ pcie_chipset = 1; + + 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's slot is implemented + */ + if (pcie_slotimpl(cfg)) + expr->expr_slotcap = REG(ptr + PCIER_SLOTCAP, 4); + +#undef REG } static void @@ -878,31 +937,42 @@ vpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data) return (0); } +int +pcie_slot_implemented(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + + return pcie_slotimpl(&dinfo->cfg); +} + void pcie_set_max_readrq(device_t dev, uint16_t rqsize) { - int expr_ptr; - uint16_t val; - rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK; - if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) { - panic("%s: invalid max read request size 0x%02x\n", - device_get_nameunit(dev), rqsize); - } -#warning "this code is incorrect, I think" - pci_find_extcap_method(device_get_parent(dev), dev, PCIY_EXPRESS, &expr_ptr); - if(!expr_ptr) - panic("%s: not PCI Express\n", device_get_nameunit(dev)); - val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2); - if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) { - if (bootverbose) - device_printf(dev, "adjust device control 0x%04x", val); - val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK; - val |= rqsize; - pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2); - - if (bootverbose) - kprintf(" -> 0x%04x\n", val); - } + uint8_t expr_ptr; + uint16_t val; + + rqsize &= PCIEM_DEVCTL_MAX_READRQ_MASK; + if (rqsize > PCIEM_DEVCTL_MAX_READRQ_4096) { + panic("%s: invalid max read request size 0x%02x\n", + device_get_nameunit(dev), rqsize); + } + + expr_ptr = pci_get_pciecap_ptr(dev); + if (!expr_ptr) + panic("%s: not PCIe device\n", device_get_nameunit(dev)); + + val = pci_read_config(dev, expr_ptr + PCIER_DEVCTRL, 2); + if ((val & PCIEM_DEVCTL_MAX_READRQ_MASK) != rqsize) { + if (bootverbose) + device_printf(dev, "adjust device control 0x%04x", val); + + val &= ~PCIEM_DEVCTL_MAX_READRQ_MASK; + val |= rqsize; + pci_write_config(dev, expr_ptr + PCIER_DEVCTRL, val, 2); + + if (bootverbose) + kprintf(" -> 0x%04x\n", val); + } } static void @@ -2450,9 +2520,72 @@ pci_print_verbose(struct pci_devinfo *dinfo) cfg->msix.msix_table_bar, cfg->msix.msix_pba_bar); } + pci_print_verbose_expr(cfg); } } +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 PCIE_END_POINT: + port_name = "DEVICE"; + break; + case PCIE_LEG_END_POINT: + port_name = "LEGDEV"; + break; + case PCIE_ROOT_PORT: + port_name = "ROOT"; + break; + case PCIE_UP_STREAM_PORT: + port_name = "UPSTREAM"; + break; + case PCIE_DOWN_STREAM_PORT: + port_name = "DOWNSTRM"; + break; + case PCIE_PCIE2PCI_BRIDGE: + port_name = "PCIE2PCI"; + break; + case PCIE_PCI2PCIE_BRIDGE: + port_name = "PCI2PCIE"; + break; + default: + port_name = NULL; + break; + } + if ((port_type == PCIE_ROOT_PORT || + port_type == PCIE_DOWN_STREAM_PORT) && + !(expr->expr_cap & PCIEM_CAP_SLOT_IMPL)) + port_name = NULL; + if (port_name != NULL) + kprintf("[%s]", port_name); + + if (pcie_slotimpl(cfg)) { + kprintf(", slotcap=0x%08x", expr->expr_slotcap); + if (expr->expr_slotcap & PCIEM_SLTCAP_HP_CAP) + kprintf("[HOTPLUG]"); + } +back: + kprintf("\n"); +} + static int pci_porten(device_t pcib, int b, int s, int f) { @@ -3505,6 +3638,15 @@ pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) case PCI_IVAR_LATTIMER: *result = cfg->lattimer; break; + case PCI_IVAR_PCIXCAP_PTR: + *result = cfg->pcix.pcix_ptr; + break; + case PCI_IVAR_PCIECAP_PTR: + *result = cfg->expr.expr_ptr; + break; + case PCI_IVAR_VPDCAP_PTR: + *result = cfg->vpd.vpd_reg; + break; default: return (ENOENT); } diff --git a/sys/bus/pci/pci_pci.c b/sys/bus/pci/pci_pci.c index 0532cdd..377249a 100644 --- a/sys/bus/pci/pci_pci.c +++ b/sys/bus/pci/pci_pci.c @@ -283,6 +283,30 @@ pcib_attach_common(device_t dev) device_printf(dev, " Subtractively decoded bridge.\n"); } + if (pci_is_pcie(dev) && pcie_slot_implemented(dev)) { + uint16_t slot_ctrl; + uint8_t ptr; + + /* + * XXX + * Before proper PCI Express hot-plug support is in place, + * disable all hot-plug interrupts on the PCI Express root + * port or down stream port for now. + */ +#define HPINTRS (PCIEM_SLTCTL_HPINTR_MASK | PCIEM_SLTCTL_HPINTR_EN) + + ptr = pci_get_pciecap_ptr(dev); + slot_ctrl = pci_read_config(dev, ptr + PCIER_SLOTCTRL, 2); + if (slot_ctrl & HPINTRS) { + device_printf(dev, "Disable PCI Express hot-plug " + "interrupts(0x%04x)\n", slot_ctrl & HPINTRS); + slot_ctrl &= ~HPINTRS; + pci_write_config(dev, ptr + PCIER_SLOTCTRL, slot_ctrl, 2); + } + +#undef HPINTRS + } + /* * XXX If the secondary bus number is zero, we should assign a bus number * since the BIOS hasn't, then initialise the bridge. diff --git a/sys/bus/pci/pcireg.h b/sys/bus/pci/pcireg.h index 15d4325..3a99d08 100644 --- a/sys/bus/pci/pcireg.h +++ b/sys/bus/pci/pcireg.h @@ -603,19 +603,6 @@ typedef u_int32_t pcireg_t; /* ~typical configuration space */ /* PCI-PCI Bridge Subvendor definitions */ #define PCIR_SUBVENDCAP_ID 0x4 -/* PCI Express definitions */ -#define PCIR_EXPRESS_FLAGS 0x2 -#define PCIM_EXP_FLAGS_VERSION 0x000F -#define PCIM_EXP_FLAGS_TYPE 0x00F0 -#define PCIM_EXP_TYPE_ENDPOINT 0x0000 -#define PCIM_EXP_TYPE_LEGACY_ENDPOINT 0x0010 -#define PCIM_EXP_TYPE_ROOT_PORT 0x0040 -#define PCIM_EXP_TYPE_UPSTREAM_PORT 0x0050 -#define PCIM_EXP_TYPE_DOWNSTREAM_PORT 0x0060 -#define PCIM_EXP_TYPE_PCI_BRIDGE 0x0070 -#define PCIM_EXP_FLAGS_SLOT 0x0100 -#define PCIM_EXP_FLAGS_IRQ 0x3e00 -#define PCIER_DEVCTRL 0x08 /* MSI-X definitions */ #define PCIR_MSIX_CTRL 0x2 #define PCIM_MSIXCTRL_MSIX_ENABLE 0x8000 @@ -632,13 +619,60 @@ typedef u_int32_t pcireg_t; /* ~typical configuration space */ #define PCIM_MSIX_BIR_BAR_24 5 #define PCIM_MSIX_VCTRL_MASK 0x1 -#define PCIEM_DEVCTL_MAX_READRQ_4096 0x5000 -#define PCIEM_DEVCTL_MAX_READRQ_MASK 0x7000 /* Max read request size */ -#define PCIEM_DEVCTL_MAX_READRQ_128 0x0000 -#define PCIEM_DEVCTL_MAX_READRQ_256 0x1000 -#define PCIEM_DEVCTL_MAX_READRQ_512 0x2000 -#define PCIEM_DEVCTL_MAX_READRQ_1024 0x3000 -#define PCIEM_DEVCTL_MAX_READRQ_2048 0x4000 -#define PCIEM_DEVCTL_MAX_READRQ_4096 0x5000 +/* + * PCI Express definitions + * According to + * PCI Express base specification, REV. 1.0a + */ + +/* PCI Express capabilities, 16bits */ +#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 PCIE_END_POINT 0x0000 /* Endpoint device */ +#define PCIE_LEG_END_POINT 0x0010 /* Legacy endpoint device */ +#define PCIE_ROOT_PORT 0x0040 /* Root port */ +#define PCIE_UP_STREAM_PORT 0x0050 /* Switch upstream port */ +#define PCIE_DOWN_STREAM_PORT 0x0060 /* Switch downstream port */ +#define PCIE_PCIE2PCI_BRIDGE 0x0070 /* PCI Express to PCI/PCI-X bridge */ +#define PCIE_PCI2PCIE_BRIDGE 0x0080 /* PCI/PCI-X to PCI Express bridge */ + +/* PCI Express device control, 16bits */ +#define PCIER_DEVCTRL 0x08 +#define PCIEM_DEVCTL_MAX_READRQ_MASK 0x7000 /* Max read request size */ +#define PCIEM_DEVCTL_MAX_READRQ_128 0x0000 +#define PCIEM_DEVCTL_MAX_READRQ_256 0x1000 +#define PCIEM_DEVCTL_MAX_READRQ_512 0x2000 +#define PCIEM_DEVCTL_MAX_READRQ_1024 0x3000 +#define PCIEM_DEVCTL_MAX_READRQ_2048 0x4000 +#define PCIEM_DEVCTL_MAX_READRQ_4096 0x5000 + +/* PCI Express slot capabilities, 32bits */ +#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 */ + +/* PCI Express slot control, 16bits */ +#define PCIER_SLOTCTRL 0x18 +#define PCIEM_SLTCTL_HPINTR_MASK 0x001f /* Hot-plug interrupts mask */ +#define PCIEM_SLTCTL_HPINTR_EN 0x0020 /* Enable hot-plug interrupts */ + /* PCI Expres hot-plug interrupts */ +#define PCIE_HPINTR_ATTEN_BTN 0x0001 /* Attention button intr */ +#define PCIE_HPINTR_PWR_FAULT 0x0002 /* Power fault intr */ +#define PCIE_HPINTR_MRL_SNS 0x0004 /* MRL sensor changed intr */ +#define PCIE_HPINTR_PRSN_DETECT 0x0008 /* Presence detect intr */ +#define PCIE_HPINTR_CMD_COMPL 0x0010 /* Command completed intr */ #endif diff --git a/sys/bus/pci/pcivar.h b/sys/bus/pci/pcivar.h index 89192b8..f54e92b 100644 --- a/sys/bus/pci/pcivar.h +++ b/sys/bus/pci/pcivar.h @@ -34,8 +34,6 @@ #include #endif -#include - extern const char *pcib_owner; /* arbitrate who owns the pci device arch */ /* some PCI bus constants */ @@ -128,6 +126,18 @@ struct pcicfg_ht { uint64_t ht_msiaddr; /* MSI mapping base address */ }; +/* Interesting 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 */ +}; + +/* Interesting values for PCI-X */ +struct pcicfg_pcix { + uint8_t pcix_ptr; +}; + /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ @@ -170,6 +180,8 @@ typedef struct pcicfg { struct pcicfg_msi msi; /* pci msi */ struct pcicfg_msix msix; /* pci msi-x */ struct pcicfg_ht ht; /* HyperTransport */ + struct pcicfg_expr expr; /* PCI Express */ + struct pcicfg_pcix pcix; /* PCI-X */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */ @@ -253,6 +265,9 @@ enum pci_device_ivars { PCI_IVAR_MINGNT, PCI_IVAR_MAXLAT, PCI_IVAR_LATTIMER, + PCI_IVAR_PCIXCAP_PTR, + PCI_IVAR_PCIECAP_PTR, + PCI_IVAR_VPDCAP_PTR }; /* @@ -282,6 +297,9 @@ PCI_ACCESSOR(cachelnsz, CACHELNSZ, uint8_t) PCI_ACCESSOR(mingnt, MINGNT, uint8_t) PCI_ACCESSOR(maxlat, MAXLAT, uint8_t) PCI_ACCESSOR(lattimer, LATTIMER, uint8_t) +PCI_ACCESSOR(pcixcap_ptr, PCIXCAP_PTR, uint8_t) +PCI_ACCESSOR(pciecap_ptr, PCIECAP_PTR, uint8_t) +PCI_ACCESSOR(vpdcap_ptr, VPDCAP_PTR, uint8_t) #undef PCI_ACCESSOR @@ -386,7 +404,9 @@ pci_is_vga_memory_range(u_long start, u_long end) return ((start >= 0xa0000 && end <= 0xbffff) ? 1 : 0); } +int pcie_slot_implemented(device_t); void pcie_set_max_readrq(device_t, uint16_t); + /* * PCI power states are as defined by ACPI: * @@ -429,44 +449,15 @@ pci_find_extcap(device_t dev, int capability, int *capreg) static __inline int pci_is_pcie(device_t dev) { - int reg; - return (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0); + return (pci_get_pciecap_ptr(dev) != 0); } static __inline int pci_is_pcix(device_t dev) { - int reg; - return (pci_find_extcap(dev, PCIY_PCIX, ®) == 0); -} - -#warning "this code is probably incorrect" -static __inline int* -pci_get_vpdcap_ptr(device_t dev) -{ - int *reg; - pci_find_extcap(dev, PCIY_VPD, reg); - return reg; + return (pci_get_pcixcap_ptr(dev) != 0); } -static __inline int* -pci_get_pciecap_ptr(device_t dev) -{ - int *reg; - pci_find_extcap(dev, PCIY_EXPRESS, reg); - return reg; -} - - -static __inline int* -pci_get_pcixcap_ptr(device_t dev) -{ - int *reg; - pci_find_extcap(dev, PCIY_PCIX, reg); - return reg; -} - - static __inline int pci_alloc_msi(device_t dev, int *count) {