changeset 9970:565d92d48652

6766472 MSIs do not function on most Nvidia boards
author Jimmy Vetayases <Jimmy.Vetayases@Sun.COM>
date Thu, 25 Jun 2009 12:35:31 -0700
parents e49d96e3e430
children e29752cf7b71
files usr/src/uts/common/io/pci_cap.c usr/src/uts/common/os/sunpci.c usr/src/uts/common/sys/ddi_impldefs.h usr/src/uts/common/sys/pci.h usr/src/uts/common/sys/pci_cap.h usr/src/uts/common/sys/pci_impl.h usr/src/uts/i86pc/io/pciex/npe.c usr/src/uts/i86pc/io/pciex/npe_misc.c usr/src/uts/intel/io/pci/pci_pci.c
diffstat 9 files changed, 424 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- 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 <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);
 		}
--- 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 <sys/types.h>
 #include <sys/sunndi.h>
 #include <sys/sysmacros.h>
@@ -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)
--- 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);
--- 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 */
--- 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 */
--- 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))
 
--- 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);
--- 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);
+}
--- 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 <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_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 <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;
+	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);