# HG changeset patch # User Jimmy Vetayases # Date 1245958531 25200 # Node ID 565d92d486520e1f9f417c50903445909ac7c4c4 # Parent e49d96e3e4309e92066821939780c068a4774d62 6766472 MSIs do not function on most Nvidia boards diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/common/io/pci_cap.c --- a/usr/src/uts/common/io/pci_cap.c Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/common/io/pci_cap.c Thu Jun 25 12:35:31 2009 -0700 @@ -65,8 +65,8 @@ /* PCIE and PCIX Version 2 contain Extended Config Space */ for (i = 0, base = pci_config_get8(h, PCI_CONF_CAP_PTR); - base && i < index; base = pci_config_get8(h, base - + PCI_CAP_NEXT_PTR), i++) { + base && i < index; base = pci_config_get8(h, base + + PCI_CAP_NEXT_PTR), i++) { if ((id = pci_config_get8(h, base)) == 0xff) break; @@ -75,7 +75,7 @@ search_ext = 1; else if (id == PCI_CAP_ID_PCIX) { if ((pcix_cmd = pci_config_get16(h, base + - PCI_PCIX_COMMAND)) != PCI_CAP_EINVAL16) + PCI_PCIX_COMMAND)) != PCI_CAP_EINVAL16) continue; if ((pcix_cmd & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2) search_ext = 1; @@ -95,9 +95,9 @@ break; id = (xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) - & PCIE_EXT_CAP_ID_MASK; + & PCIE_EXT_CAP_ID_MASK; base = (xcaps_hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) - & PCIE_EXT_CAP_NEXT_PTR_MASK; + & PCIE_EXT_CAP_NEXT_PTR_MASK; } if (!base || i < index) @@ -107,10 +107,10 @@ return (DDI_FAILURE); id = ((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) | - PCI_CAP_XCFG_FLAG; + PCI_CAP_XCFG_FLAG; found: PCI_CAP_DBG("pci_cap_probe: index=%x, id=%x, base=%x\n", - index, id, base); + index, id, base); *id_p = id; *base_p = base; @@ -145,12 +145,12 @@ break; default: cmn_err(CE_WARN, "%s: unexpected pci header type:%x", - __func__, header); + __func__, header); return (DDI_FAILURE); } for (base = pci_config_get8(h, base); base; - base = pci_config_get8(h, base + PCI_CAP_NEXT_PTR)) { + base = pci_config_get8(h, base + PCI_CAP_NEXT_PTR)) { if (pci_config_get8(h, base) == id) { *base_p = base; return (DDI_SUCCESS); @@ -159,8 +159,6 @@ *base_p = PCI_CAP_NEXT_PTR_NULL; return (DDI_FAILURE); - - } /* @@ -178,13 +176,63 @@ return (DDI_FAILURE); for (base = PCIE_EXT_CAP; base; base = (xcaps_hdr >> - PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { + PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { if ((xcaps_hdr = pci_config_get32(h, base)) == PCI_CAP_EINVAL32) break; if (((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & - PCIE_EXT_CAP_ID_MASK) == id) { + PCIE_EXT_CAP_ID_MASK) == id) { + *base_p = base; + return (DDI_SUCCESS); + } + } + + *base_p = PCI_CAP_NEXT_PTR_NULL; + return (DDI_FAILURE); +} + +/* + * There can be multiple pci caps with a Hypertransport technology cap ID + * Each is distiguished by a type register in the upper half of the cap + * header (the "command" register part). + * + * This returns the location of a hypertransport capability whose upper + * 16-bits of the cap header matches after masking the value + * with ; if both and are 0, it will return + * the first HT cap found + */ +int +pci_htcap_locate(ddi_acc_handle_t h, uint16_t reg_mask, uint16_t reg_val, + uint16_t *base_p) +{ + uint8_t header; + uint16_t status, base; + + status = pci_config_get16(h, PCI_CONF_STAT); + + if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP)) + return (DDI_FAILURE); + + header = pci_config_get8(h, PCI_CONF_HEADER); + switch (header & PCI_HEADER_TYPE_M) { + case PCI_HEADER_ZERO: + base = PCI_CONF_CAP_PTR; + break; + case PCI_HEADER_PPB: + base = PCI_BCNF_CAP_PTR; + break; + default: + cmn_err(CE_WARN, "%s: unexpected pci header type:%x", + __func__, header); + return (DDI_FAILURE); + } + + for (base = pci_config_get8(h, base); base; + base = pci_config_get8(h, base + PCI_CAP_NEXT_PTR)) { + if (pci_config_get8(h, base) == PCI_CAP_ID_HT && + (pci_config_get16(h, base + PCI_CAP_ID_REGS_OFF) & + reg_mask) == reg_val) { *base_p = base; return (DDI_SUCCESS); } diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/common/os/sunpci.c --- a/usr/src/uts/common/os/sunpci.c Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/common/os/sunpci.c Thu Jun 25 12:35:31 2009 -0700 @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -278,6 +276,10 @@ uint32_t *regbuf, uint32_t notused); static uint32_t pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, uint32_t notused); +static uint32_t pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, + uint32_t *regbuf, uint32_t notused); +static uint32_t pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, + uint32_t *regbuf, uint32_t notused); static void pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, uint32_t nwords); static uint32_t cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf, @@ -297,13 +299,56 @@ * size words. */ static pci_cap_entry_t pci_cap_table[] = { - {PCI_CAP_ID_PM, PCI_PMCAP_NDWORDS, pci_generic_save}, - {PCI_CAP_ID_AGP, PCI_AGP_NDWORDS, pci_generic_save}, - {PCI_CAP_ID_SLOT_ID, PCI_SLOTID_NDWORDS, pci_generic_save}, - {PCI_CAP_ID_MSI_X, PCI_MSIX_NDWORDS, pci_generic_save}, - {PCI_CAP_ID_MSI, PCI_CAP_SZUNKNOWN, pci_msi_save}, - {PCI_CAP_ID_PCIX, PCI_CAP_SZUNKNOWN, pci_pcix_save}, - {PCI_CAP_ID_PCI_E, PCI_CAP_SZUNKNOWN, pci_pcie_save}, + {PCI_CAP_ID_PM, 0, 0, PCI_PMCAP_NDWORDS, pci_generic_save}, + {PCI_CAP_ID_AGP, 0, 0, PCI_AGP_NDWORDS, pci_generic_save}, + {PCI_CAP_ID_SLOT_ID, 0, 0, PCI_SLOTID_NDWORDS, pci_generic_save}, + {PCI_CAP_ID_MSI_X, 0, 0, PCI_MSIX_NDWORDS, pci_generic_save}, + {PCI_CAP_ID_MSI, 0, 0, PCI_CAP_SZUNKNOWN, pci_msi_save}, + {PCI_CAP_ID_PCIX, 0, 0, PCI_CAP_SZUNKNOWN, pci_pcix_save}, + {PCI_CAP_ID_PCI_E, 0, 0, PCI_CAP_SZUNKNOWN, pci_pcie_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_SLPRI_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK, + PCI_HTCAP_SLPRI_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_HOSTSEC_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK, + PCI_HTCAP_HOSTSEC_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_INTCONF_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_INTCONF_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_REVID_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_REVID_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_UNITID_CLUMP_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_UNITID_CLUMP_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_ECFG_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_ECFG_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_ADDRMAP_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_CAP_SZUNKNOWN, pci_ht_addrmap_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_MSIMAP_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_MSIMAP_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_DIRROUTE_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_DIRROUTE_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_VCSET_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_VCSET_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_RETRYMODE_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_RETRYMODE_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_GEN3_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_GEN3_NDWORDS, pci_generic_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_FUNCEXT_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_CAP_SZUNKNOWN, pci_ht_funcext_save}, + + {PCI_CAP_ID_HT, PCI_HTCAP_PM_TYPE, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_PM_NDWORDS, pci_generic_save}, + /* * {PCI_CAP_ID_cPCI_CRC, 0, NULL}, * {PCI_CAP_ID_VPD, 0, NULL}, @@ -315,6 +360,7 @@ {PCI_CAP_NEXT_PTR_NULL, 0, NULL} }; + /* * Save the configuration registers for cdip as a property * so that it persists after detach/uninitchild. @@ -537,6 +583,7 @@ uint16_t cap_id, offset, status; uint32_t words_saved = 0, nwords = 0; uint16_t cap_ptr = PCI_CAP_NEXT_PTR_NULL; + uint16_t cap_reg; *ncapsp = 0; @@ -555,12 +602,22 @@ */ while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { cap_id = CAP_ID(confhdl, cap_ptr, xspace); + /* Search for this cap id in our table */ - if (!xspace) + if (!xspace) { pci_cap_entp = pci_cap_table; - while (pci_cap_entp->cap_id != PCI_CAP_NEXT_PTR_NULL && - pci_cap_entp->cap_id != cap_id) + cap_reg = pci_config_get16(confhdl, + cap_ptr + PCI_CAP_ID_REGS_OFF); + } + + while (pci_cap_entp->cap_id != PCI_CAP_NEXT_PTR_NULL) { + if (pci_cap_entp->cap_id == cap_id && + (cap_reg & pci_cap_entp->cap_mask) == + pci_cap_entp->cap_reg) + break; + pci_cap_entp++; + } offset = cap_ptr; cap_ptr = NEXT_CAP(confhdl, cap_ptr, xspace); @@ -656,6 +713,51 @@ return (0); } +/*ARGSUSED*/ +static uint32_t +pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, + uint32_t *regbuf, uint32_t notused) +{ + uint32_t nwords = 0; + uint16_t reg; + + reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF); + + switch ((reg & PCI_HTCAP_ADDRMAP_MAPTYPE_MASK) >> + PCI_HTCAP_ADDRMAP_MAPTYPE_SHIFT) { + case PCI_HTCAP_ADDRMAP_40BIT_ID: + /* HT3.1 spec, ch 7.7, 40-bit dma */ + nwords = 3 + ((reg & PCI_HTCAP_ADDRMAP_NUMMAP_MASK) * 2); + break; + case PCI_HTCAP_ADDRMAP_64BIT_ID: + /* HT3.1 spec, ch 7.8, 64-bit dma */ + nwords = 4; + break; + default: + nwords = 0; + } + + pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); + return (nwords); +} + +/*ARGSUSED*/ +static uint32_t +pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, + uint32_t *regbuf, uint32_t notused) +{ + uint32_t nwords; + uint16_t reg; + + reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF); + + /* HT3.1 spec, ch 7.17 */ + nwords = 1 + (reg & PCI_HTCAP_FUNCEXT_LEN_MASK); + + pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); + return (nwords); +} + static void pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf, uint16_t pmcap_offset) diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/common/sys/ddi_impldefs.h --- a/usr/src/uts/common/sys/ddi_impldefs.h Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/common/sys/ddi_impldefs.h Thu Jun 25 12:35:31 2009 -0700 @@ -1172,6 +1172,8 @@ typedef struct pci_cap_entry { uint16_t cap_id; + uint16_t cap_reg; + uint16_t cap_mask; uint32_t cap_ndwords; uint32_t (*cap_save_func)(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, uint32_t ndwords); diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/common/sys/pci.h --- a/usr/src/uts/common/sys/pci.h Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/common/sys/pci.h Thu Jun 25 12:35:31 2009 -0700 @@ -860,6 +860,93 @@ PCI_CAPSLOT_ESR_NSLOTS_MASK) /* + * HyperTransport Capabilities; each HT cap uses the same PCI cap id of + * PCI_CAP_ID_HT. The header's upper 16-bits (command reg) contains an HT + * cap type reg at bits [15:11]. For Slave/Pri Interface and Host/Sec + * Interface types, only bits [15:13] are used. + */ +#define PCI_HTCAP_TYPE_MASK 0xF800 +#define PCI_HTCAP_TYPE_SLHOST_MASK 0xE000 /* SLPRI and HOSTSEC types */ +#define PCI_HTCAP_TYPE_SHIFT 11 + +#define PCI_HTCAP_SLPRI_ID 0x00 +#define PCI_HTCAP_HOSTSEC_ID 0x04 +#define PCI_HTCAP_SWITCH_ID 0x08 +#define PCI_HTCAP_INTCONF_ID 0x10 +#define PCI_HTCAP_REVID_ID 0x11 +#define PCI_HTCAP_UNITID_CLUMP_ID 0x12 +#define PCI_HTCAP_ECFG_ID 0x13 +#define PCI_HTCAP_ADDRMAP_ID 0x14 +#define PCI_HTCAP_MSIMAP_ID 0x15 +#define PCI_HTCAP_DIRROUTE_ID 0x16 +#define PCI_HTCAP_VCSET_ID 0x17 +#define PCI_HTCAP_RETRYMODE_ID 0x18 +#define PCI_HTCAP_X86ENC_ID 0x19 +#define PCI_HTCAP_GEN3_ID 0x1A +#define PCI_HTCAP_FUNCEXT_ID 0x1B +#define PCI_HTCAP_PM_ID 0x1C + +#define PCI_HTCAP_SLPRI_TYPE /* 0x0000 */ \ + (PCI_HTCAP_SLPRI_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_HOSTSEC_TYPE /* 0x2000 */ \ + (PCI_HTCAP_HOSTSEC_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_SWITCH_TYPE /* 0x4000 */ \ + (PCI_HTCAP_SWITCH_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_INTCONF_TYPE /* 0x8000 */ \ + (PCI_HTCAP_INTCONF_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_REVID_TYPE /* 0x8800 */ \ + (PCI_HTCAP_REVID_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_UNITID_CLUMP_TYPE /* 0x9000 */ \ + (PCI_HTCAP_UNITID_CLUMP_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_ECFG_TYPE /* 0x9800 */ \ + (PCI_HTCAP_ECFG_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_ADDRMAP_TYPE /* 0xA000 */ \ + (PCI_HTCAP_ADDRMAP_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_MSIMAP_TYPE /* 0xA800 */ \ + (PCI_HTCAP_MSIMAP_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_DIRROUTE_TYPE /* 0xB000 */ \ + (PCI_HTCAP_DIRROUTE_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_VCSET_TYPE /* 0xB800 */ \ + (PCI_HTCAP_VCSET_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_RETRYMODE_TYPE /* 0xC000 */ \ + (PCI_HTCAP_RETRYMODE_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_X86ENC_TYPE /* 0xC800 */ \ + (PCI_HTCAP_X86ENC_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_GEN3_TYPE /* 0xD000 */ \ + (PCI_HTCAP_GEN3_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_FUNCEXT_TYPE /* 0xD800 */ \ + (PCI_HTCAP_FUNCEXT_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_PM_TYPE /* 0xE000 */ \ + (PCI_HTCAP_PM_ID << PCI_HTCAP_TYPE_SHIFT) + +#define PCI_HTCAP_MSIMAP_ENABLE 0x0001 +#define PCI_HTCAP_MSIMAP_ENABLE_MASK 0x0001 + +#define PCI_HTCAP_ADDRMAP_MAPTYPE_MASK 0x600 +#define PCI_HTCAP_ADDRMAP_MAPTYPE_SHIFT 9 +#define PCI_HTCAP_ADDRMAP_NUMMAP_MASK 0xF +#define PCI_HTCAP_ADDRMAP_40BIT_ID 0x0 +#define PCI_HTCAP_ADDRMAP_64BIT_ID 0x1 + +#define PCI_HTCAP_FUNCEXT_LEN_MASK 0xFF + + +/* * other interesting PCI constants */ #define PCI_BASE_NUM 6 /* num of base regs in configuration header */ diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/common/sys/pci_cap.h --- a/usr/src/uts/common/sys/pci_cap.h Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/common/sys/pci_cap.h Thu Jun 25 12:35:31 2009 -0700 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_PCI_CAP_H #define _SYS_PCI_CAP_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -38,6 +36,8 @@ /* Function Prototypes */ int pci_xcap_locate(ddi_acc_handle_t h, uint16_t id, uint16_t *base_p); int pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p); +int pci_htcap_locate(ddi_acc_handle_t h, uint16_t reg_mask, uint16_t reg_val, + uint16_t *base_p); /* Extract the lower 16 bits Extended CFG SPACE */ diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/common/sys/pci_impl.h --- a/usr/src/uts/common/sys/pci_impl.h Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/common/sys/pci_impl.h Thu Jun 25 12:35:31 2009 -0700 @@ -152,6 +152,22 @@ #define PCI_MSIX_NDWORDS 3 #define PCI_CAP_SZUNKNOWN 0 +#define PCI_HTCAP_SLPRI_NDWORDS 7 +#define PCI_HTCAP_HOSTSEC_NDWORDS 6 +#define PCI_HTCAP_INTCONF_NDWORDS 2 +#define PCI_HTCAP_REVID_NDWORDS 1 +#define PCI_HTCAP_UNITID_CLUMP_NDWORDS 3 +#define PCI_HTCAP_ECFG_NDWORDS 3 +#define PCI_HTCAP_ADDRMAP_NDWORDS PCI_CAP_SZUNKNOWN /* variable */ +#define PCI_HTCAP_MSIMAP_NDWORDS 3 +#define PCI_HTCAP_DIRROUTE_NDWORDS 3 +#define PCI_HTCAP_VCSET_NDWORDS 3 +#define PCI_HTCAP_RETRYMODE_NDWORDS 3 +#define PCI_HTCAP_GEN3_NDWORDS 10 +#define PCI_HTCAP_FUNCEXT_NDWORDS PCI_CAP_SZUNKNOWN /* variable */ +#define PCI_HTCAP_PM_NDWORDS 2 + + #define CAP_ID(confhdl, cap_ptr, xspace) \ ((xspace) ? 0 : pci_config_get8((confhdl), (cap_ptr) + PCI_CAP_ID)) diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/i86pc/io/pciex/npe.c --- a/usr/src/uts/i86pc/io/pciex/npe.c Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/i86pc/io/pciex/npe.c Thu Jun 25 12:35:31 2009 -0700 @@ -182,6 +182,9 @@ extern void npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl); extern void npe_intel_error_mask(ddi_acc_handle_t cfg_hdl); extern boolean_t npe_is_mmcfg_supported(dev_info_t *dip); +extern void npe_enable_htmsi_children(dev_info_t *dip); +extern int npe_save_htconfig_children(dev_info_t *dip); +extern int npe_restore_htconfig_children(dev_info_t *dip); /* * Module linkage information for the kernel. @@ -251,8 +254,26 @@ int instance = ddi_get_instance(devi); pci_state_t *pcip = NULL; - if (cmd == DDI_RESUME) + if (cmd == DDI_RESUME) { + /* + * the system might still be able to resume even if this fails + */ + (void) npe_restore_htconfig_children(devi); return (DDI_SUCCESS); + } + + /* + * We must do this here in order to ensure that all top level devices + * get their HyperTransport MSI mapping regs programmed first. + * "Memory controller" and "hostbridge" class devices are leaf devices + * that may affect MSI translation functionality for devices + * connected to the same link/bus. + * + * This will also program HT MSI mapping registers on root buses + * devices (basically sitting on an HT bus) that are not dependent + * on the aforementioned HT devices for MSI translation. + */ + npe_enable_htmsi_children(devi); if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pciex") != DDI_PROP_SUCCESS) { @@ -337,6 +358,11 @@ return (DDI_SUCCESS); case DDI_SUSPEND: + /* + * the system might still be able to suspend/resume even if + * this fails + */ + (void) npe_save_htconfig_children(devi); return (DDI_SUCCESS); default: return (DDI_FAILURE); diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/i86pc/io/pciex/npe_misc.c --- a/usr/src/uts/i86pc/io/pciex/npe_misc.c Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c Thu Jun 25 12:35:31 2009 -0700 @@ -309,3 +309,105 @@ return !(npe_child_is_pci(dip) || IS_BAD_AMD_NTBRIDGE(vendor_id, device_id)); } + +int +npe_enable_htmsi(ddi_acc_handle_t cfg_hdl) +{ + uint16_t ptr; + uint16_t reg; + + if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS) + return (DDI_FAILURE); + + reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF); + reg |= PCI_HTCAP_MSIMAP_ENABLE; + + pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg); + return (DDI_SUCCESS); +} + +void +npe_enable_htmsi_children(dev_info_t *dip) +{ + dev_info_t *cdip = ddi_get_child(dip); + ddi_acc_handle_t cfg_hdl; + + for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { + if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) { + cmn_err(CE_NOTE, "!npe_enable_htmsi_children: " + "pci_config_setup failed for %s", + ddi_node_name(cdip)); + } + + (void) npe_enable_htmsi(cfg_hdl); + pci_config_teardown(&cfg_hdl); + } +} + +/* + * save config regs for HyperTransport devices without drivers of classes: + * memory controller and hostbridge + */ +int +npe_save_htconfig_children(dev_info_t *dip) +{ + dev_info_t *cdip = ddi_get_child(dip); + ddi_acc_handle_t cfg_hdl; + uint16_t ptr; + int rval = DDI_SUCCESS; + uint8_t cl, scl; + + for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { + if (ddi_driver_major(cdip) != DDI_MAJOR_T_NONE) + continue; + + if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) + return (DDI_FAILURE); + + cl = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS); + scl = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS); + + if (((cl == PCI_CLASS_MEM && scl == PCI_MEM_RAM) || + (cl == PCI_CLASS_BRIDGE && scl == PCI_BRIDGE_HOST)) && + pci_htcap_locate(cfg_hdl, 0, 0, &ptr) == DDI_SUCCESS) { + + if (pci_save_config_regs(cdip) != DDI_SUCCESS) { + cmn_err(CE_WARN, "Failed to save HT config " + "regs for %s\n", ddi_node_name(cdip)); + rval = DDI_FAILURE; + + } else if (ddi_prop_update_int(DDI_DEV_T_NONE, cdip, + "htconfig-saved", 1) != DDI_SUCCESS) { + cmn_err(CE_WARN, "Failed to set htconfig-saved " + "property for %s\n", ddi_node_name(cdip)); + rval = DDI_FAILURE; + } + } + + pci_config_teardown(&cfg_hdl); + } + + return (rval); +} + +int +npe_restore_htconfig_children(dev_info_t *dip) +{ + dev_info_t *cdip = ddi_get_child(dip); + int rval = DDI_SUCCESS; + + for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { + if (ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, + "htconfig-saved", 0) == 0) + continue; + + if (pci_restore_config_regs(cdip) != DDI_SUCCESS) { + cmn_err(CE_WARN, "Failed to restore HT config " + "regs for %s\n", ddi_node_name(cdip)); + rval = DDI_FAILURE; + } + } + + return (rval); +} diff -r e49d96e3e430 -r 565d92d48652 usr/src/uts/intel/io/pci/pci_pci.c --- a/usr/src/uts/intel/io/pci/pci_pci.c Thu Jun 25 11:48:20 2009 -0700 +++ b/usr/src/uts/intel/io/pci/pci_pci.c Thu Jun 25 12:35:31 2009 -0700 @@ -44,6 +44,7 @@ #include #include #include +#include /* * The variable controls the default setting of the command register @@ -83,15 +84,6 @@ */ int ppb_support_ht_msimap = 0; -/* - * masks and values for the upper 16-bits of hypertransport cap headers - */ -#define PCI_CAP_HT_MSIMAP_TYPE 0xA800 -#define PCI_CAP_HT_MSIMAP_TYPE_MASK 0xFF00 -#define PCI_CAP_HT_MSIMAP_ENABLE 0x0001 -#define PCI_CAP_HT_MSIMAP_ENABLE_MASK 0x0001 - - struct bus_ops ppb_bus_ops = { BUSO_REV, ppb_bus_map, @@ -230,8 +222,6 @@ static int ppb_initchild(dev_info_t *child); static void ppb_save_config_regs(ppb_devstate_t *ppb_p); static void ppb_restore_config_regs(ppb_devstate_t *ppb_p); -static uint8_t ppb_find_ht_cap(ddi_acc_handle_t cfg_hdl, uint16_t reg_mask, - uint16_t reg_val); static boolean_t ppb_ht_msimap_check(ddi_acc_handle_t cfg_hdl); static int ppb_ht_msimap_set(ddi_acc_handle_t cfg_hdl, int cmd); @@ -795,53 +785,15 @@ } -/* - * returns the location of a hypertransport capability whose upper 16-bit - * register of the cap header matches after masking the register - * with ; if both and are 0, it will return the - * first HT cap found - */ -static uint8_t -ppb_find_ht_cap(ddi_acc_handle_t cfg_hdl, uint16_t reg_mask, uint16_t reg_val) -{ - uint16_t status, reg; - uint8_t ptr, id; - - status = pci_config_get16(cfg_hdl, PCI_CONF_STAT); - if (status == 0xffff || !((status & PCI_STAT_CAP))) - return (PCI_CAP_NEXT_PTR_NULL); - - ptr = pci_config_get8(cfg_hdl, PCI_CONF_CAP_PTR); - while (ptr != 0xFF && - ptr != PCI_CAP_NEXT_PTR_NULL && - ptr >= PCI_CAP_PTR_OFF) { - - ptr &= PCI_CAP_PTR_MASK; - id = pci_config_get8(cfg_hdl, ptr + PCI_CAP_ID); - - if (id == PCI_CAP_ID_HT) { - reg = pci_config_get16(cfg_hdl, - ptr + PCI_CAP_ID_REGS_OFF); - if ((reg & reg_mask) == reg_val) - return (ptr); - } - ptr = pci_config_get8(cfg_hdl, ptr + PCI_CAP_NEXT_PTR); - } - - return (PCI_CAP_NEXT_PTR_NULL); -} - - static boolean_t ppb_ht_msimap_check(ddi_acc_handle_t cfg_hdl) { - uint8_t ptr; + uint16_t ptr; - ptr = ppb_find_ht_cap(cfg_hdl, - PCI_CAP_HT_MSIMAP_TYPE_MASK | PCI_CAP_HT_MSIMAP_ENABLE_MASK, - PCI_CAP_HT_MSIMAP_TYPE | PCI_CAP_HT_MSIMAP_ENABLE); - - if (ptr == PCI_CAP_NEXT_PTR_NULL) + if (pci_htcap_locate(cfg_hdl, + PCI_HTCAP_TYPE_MASK | PCI_HTCAP_MSIMAP_ENABLE_MASK, + PCI_HTCAP_MSIMAP_TYPE | PCI_HTCAP_MSIMAP_ENABLE, &ptr) != + DDI_SUCCESS) return (B_FALSE); return (B_TRUE); @@ -851,22 +803,21 @@ static int ppb_ht_msimap_set(ddi_acc_handle_t cfg_hdl, int cmd) { - uint8_t ptr; + uint16_t ptr; uint16_t reg; - ptr = ppb_find_ht_cap(cfg_hdl, PCI_CAP_HT_MSIMAP_TYPE_MASK, - PCI_CAP_HT_MSIMAP_TYPE); - if (ptr == PCI_CAP_NEXT_PTR_NULL) + if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK, + PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS) return (0); reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF); switch (cmd) { case HT_MSIMAP_ENABLE: - reg |= PCI_CAP_HT_MSIMAP_ENABLE; + reg |= PCI_HTCAP_MSIMAP_ENABLE; break; case HT_MSIMAP_DISABLE: default: - reg &= ~(uint16_t)PCI_CAP_HT_MSIMAP_ENABLE; + reg &= ~(uint16_t)PCI_HTCAP_MSIMAP_ENABLE; } pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg);