summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJimmy Vetayases <Jimmy.Vetayases@Sun.COM>2009-06-25 12:35:31 -0700
committerJimmy Vetayases <Jimmy.Vetayases@Sun.COM>2009-06-25 12:35:31 -0700
commitcb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0 (patch)
treeafa13d7e36f833e8fe052abb22bd7a80fba40b9b /usr/src
parent9fae04d87fb57bd267ff2fb7d3fbf75f423a71c8 (diff)
downloadillumos-gate-cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0.tar.gz
6766472 MSIs do not function on most Nvidia boards
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/pci_cap.c74
-rw-r--r--usr/src/uts/common/os/sunpci.c128
-rw-r--r--usr/src/uts/common/sys/ddi_impldefs.h2
-rw-r--r--usr/src/uts/common/sys/pci.h87
-rw-r--r--usr/src/uts/common/sys/pci_cap.h6
-rw-r--r--usr/src/uts/common/sys/pci_impl.h16
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe.c28
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe_misc.c102
-rw-r--r--usr/src/uts/intel/io/pci/pci_pci.c71
9 files changed, 424 insertions, 90 deletions
diff --git a/usr/src/uts/common/io/pci_cap.c b/usr/src/uts/common/io/pci_cap.c
index 84015a40ae..538d362f64 100644
--- a/usr/src/uts/common/io/pci_cap.c
+++ b/usr/src/uts/common/io/pci_cap.c
@@ -65,8 +65,8 @@ pci_cap_probe(ddi_acc_handle_t h, uint16_t index,
/* 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 @@ pci_cap_probe(ddi_acc_handle_t h, uint16_t index,
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 @@ pci_cap_probe(ddi_acc_handle_t h, uint16_t index,
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 @@ pci_cap_probe(ddi_acc_handle_t h, uint16_t index,
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 @@ pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p)
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 @@ pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p)
*base_p = PCI_CAP_NEXT_PTR_NULL;
return (DDI_FAILURE);
-
-
}
/*
@@ -178,13 +176,63 @@ pci_xcap_locate(ddi_acc_handle_t h, uint16_t id, uint16_t *base_p)
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 <reg_val> after masking the value
+ * with <reg_mask>; if both <reg_mask> and <reg_val> 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 --git a/usr/src/uts/common/os/sunpci.c b/usr/src/uts/common/os/sunpci.c
index b0b4b7f3fb..6dc4ae2040 100644
--- a/usr/src/uts/common/os/sunpci.c
+++ b/usr/src/uts/common/os/sunpci.c
@@ -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 <sys/types.h>
#include <sys/sunndi.h>
#include <sys/sysmacros.h>
@@ -278,6 +276,10 @@ static uint32_t pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
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 @@ static void pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf,
* 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 @@ static pci_cap_entry_t pci_cap_table[] = {
{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 @@ cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf,
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 @@ cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf,
*/
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 @@ pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
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 --git a/usr/src/uts/common/sys/ddi_impldefs.h b/usr/src/uts/common/sys/ddi_impldefs.h
index 1f178911d3..7be6c896ad 100644
--- a/usr/src/uts/common/sys/ddi_impldefs.h
+++ b/usr/src/uts/common/sys/ddi_impldefs.h
@@ -1172,6 +1172,8 @@ typedef struct pci_cap_save_desc {
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 --git a/usr/src/uts/common/sys/pci.h b/usr/src/uts/common/sys/pci.h
index e7c6b0be49..efb19097e9 100644
--- a/usr/src/uts/common/sys/pci.h
+++ b/usr/src/uts/common/sys/pci.h
@@ -860,6 +860,93 @@ typedef struct pcix_attr {
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 --git a/usr/src/uts/common/sys/pci_cap.h b/usr/src/uts/common/sys/pci_cap.h
index 43b0974f83..730e10d77b 100644
--- a/usr/src/uts/common/sys/pci_cap.h
+++ b/usr/src/uts/common/sys/pci_cap.h
@@ -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 @@ extern "C" {
/* 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 --git a/usr/src/uts/common/sys/pci_impl.h b/usr/src/uts/common/sys/pci_impl.h
index 788c804a6e..608ce07875 100644
--- a/usr/src/uts/common/sys/pci_impl.h
+++ b/usr/src/uts/common/sys/pci_impl.h
@@ -152,6 +152,22 @@ extern int memlist_count(struct memlist *);
#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 --git a/usr/src/uts/i86pc/io/pciex/npe.c b/usr/src/uts/i86pc/io/pciex/npe.c
index 67bc215c55..81485cf798 100644
--- a/usr/src/uts/i86pc/io/pciex/npe.c
+++ b/usr/src/uts/i86pc/io/pciex/npe.c
@@ -182,6 +182,9 @@ extern int npe_disable_empty_bridges_workaround(dev_info_t *child);
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 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
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 @@ npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
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 --git a/usr/src/uts/i86pc/io/pciex/npe_misc.c b/usr/src/uts/i86pc/io/pciex/npe_misc.c
index 99cc2b9c41..676a5b9b4a 100644
--- a/usr/src/uts/i86pc/io/pciex/npe_misc.c
+++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c
@@ -309,3 +309,105 @@ npe_is_mmcfg_supported(dev_info_t *dip)
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 --git a/usr/src/uts/intel/io/pci/pci_pci.c b/usr/src/uts/intel/io/pci/pci_pci.c
index 23c174ac7c..be461462bd 100644
--- a/usr/src/uts/intel/io/pci/pci_pci.c
+++ b/usr/src/uts/intel/io/pci/pci_pci.c
@@ -44,6 +44,7 @@
#include <sys/hotplug/pci/pcihp.h>
#include <sys/pci_intr_lib.h>
#include <sys/psm.h>
+#include <sys/pci_cap.h>
/*
* The variable controls the default setting of the command register
@@ -83,15 +84,6 @@ int ppb_support_msi = 0;
*/
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 void ppb_removechild(dev_info_t *);
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 @@ ppb_restore_config_regs(ppb_devstate_t *ppb_p)
}
-/*
- * returns the location of a hypertransport capability whose upper 16-bit
- * register of the cap header matches <reg_val> after masking the register
- * with <reg_mask>; if both <reg_mask> and <reg_val> 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;
-
- 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);
+ uint16_t ptr;
- 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 @@ ppb_ht_msimap_check(ddi_acc_handle_t cfg_hdl)
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);