changeset 938:2d438f28c673

6336786 time doesn't fly when CPUs are not having fun 6347678 lgrp_plat_init() should use routines available from pci_cfgspace.h
author esaxe
date Wed, 16 Nov 2005 18:13:48 -0800
parents e808c6c8cf8e
children ba7313ba6568
files usr/src/uts/i86pc/Makefile.workarounds usr/src/uts/i86pc/os/cpuid.c usr/src/uts/i86pc/os/lgrpplat.c usr/src/uts/i86pc/os/mp_startup.c
diffstat 4 files changed, 70 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/i86pc/Makefile.workarounds	Wed Nov 16 17:14:14 2005 -0800
+++ b/usr/src/uts/i86pc/Makefile.workarounds	Wed Nov 16 18:13:48 2005 -0800
@@ -90,3 +90,8 @@
 # Probe Response
 #
 WORKAROUND_DEFS += -DOPTERON_ERRATUM_131
+
+#
+# TSC may drift when C1-Clock ramping enabled
+#
+WORKAROUND_DEFS += -DOPTERON_WORKAROUND_6336786
--- a/usr/src/uts/i86pc/os/cpuid.c	Wed Nov 16 17:14:14 2005 -0800
+++ b/usr/src/uts/i86pc/os/cpuid.c	Wed Nov 16 18:13:48 2005 -0800
@@ -1700,7 +1700,7 @@
 cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum)
 {
 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
-	uint_t eax;
+	uint_t eax, edx, junk;
 
 	if (cpi->cpi_vendor != X86_VENDOR_AMD)
 		return (0);
@@ -1854,7 +1854,16 @@
 		return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax));
 	case 131:
 		return (1);
-
+	case 6336786:
+		/*
+		 * Test for AdvPowerMgmtInfo.TscPStateInvariant
+		 * if this is a K8 family processor
+		 */
+		if (CPI_FAMILY(cpi) == 0xf) {
+			(void) __cpuid_insn(0x80000007, &junk, &junk, &edx);
+			return (!(edx & 0x100));
+		}
+		return (0);
 	default:
 		return (-1);
 	}
--- a/usr/src/uts/i86pc/os/lgrpplat.c	Wed Nov 16 17:14:14 2005 -0800
+++ b/usr/src/uts/i86pc/os/lgrpplat.c	Wed Nov 16 18:13:48 2005 -0800
@@ -36,7 +36,8 @@
 #include <sys/memlist.h>
 #include <sys/memnode.h>
 #include <sys/mman.h>
-#include <sys/pci_impl.h>	/* for PCI configuration space macros */
+#include <sys/pci_cfgspace.h>
+#include <sys/pci_impl.h>
 #include <sys/param.h>
 #include <sys/promif.h>		/* for prom_printf() */
 #include <sys/systm.h>
@@ -516,9 +517,8 @@
 	/*
 	 * Read node ID register for node 0 to get node count
 	 */
-	outl(PCI_CONFADD, PCI_CADDR1(bus, dev, OPT_PCS_FUNC_HT,
-	    OPT_PCS_OFF_NODEID));
-	opt_node_info[0] = inl(PCI_CONFDATA);
+	opt_node_info[0] = pci_getl_func(bus, dev, OPT_PCS_FUNC_HT,
+	    OPT_PCS_OFF_NODEID);
 	lgrp_plat_node_cnt = OPT_NODE_CNT(opt_node_info[0]) + 1;
 
 	for (node = 0; node < lgrp_plat_node_cnt; node++) {
@@ -526,25 +526,22 @@
 		 * Read node ID register (except for node 0 which we just read)
 		 */
 		if (node > 0) {
-			outl(PCI_CONFADD, PCI_CADDR1(bus, dev,
-			    OPT_PCS_FUNC_HT, OPT_PCS_OFF_NODEID));
-			opt_node_info[node] = inl(PCI_CONFDATA);
+			opt_node_info[node] = pci_getl_func(bus, dev,
+			    OPT_PCS_FUNC_HT, OPT_PCS_OFF_NODEID);
 		}
 
 		/*
 		 * Read DRAM base and limit registers which specify
 		 * physical memory range of each node
 		 */
-		outl(PCI_CONFADD, PCI_CADDR1(bus, dev, OPT_PCS_FUNC_ADDRMAP,
-		    off));
-		opt_dram_map[node].base = inl(PCI_CONFDATA);
+		opt_dram_map[node].base = pci_getl_func(bus, dev,
+		    OPT_PCS_FUNC_ADDRMAP, off);
 		if (opt_dram_map[node].base & OPT_DRAMBASE_MASK_INTRLVEN)
 			lgrp_plat_mem_intrlv++;
 
 		off += 4;	/* limit register offset */
-		outl(PCI_CONFADD, PCI_CADDR1(bus, dev, OPT_PCS_FUNC_ADDRMAP,
-		    off));
-		opt_dram_map[node].limit = inl(PCI_CONFDATA);
+		opt_dram_map[node].limit = pci_getl_func(bus, dev,
+		    OPT_PCS_FUNC_ADDRMAP, off);
 
 		/*
 		 * Increment device number to next node and register offset for
--- a/usr/src/uts/i86pc/os/mp_startup.c	Wed Nov 16 17:14:14 2005 -0800
+++ b/usr/src/uts/i86pc/os/mp_startup.c	Wed Nov 16 18:13:48 2005 -0800
@@ -63,6 +63,7 @@
 #include <sys/kdi.h>
 #include <vm/hat_i86.h>
 #include <sys/memnode.h>
+#include <sys/pci_cfgspace.h>
 
 struct cpu	cpus[1];			/* CPU data */
 struct cpu	*cpu[NCPU] = {&cpus[0]};	/* pointers to all CPUs */
@@ -503,6 +504,12 @@
  * pessimal set of workarounds needed to cope with *any* of the CPUs in the
  * system.
  *
+ * workaround_errata is invoked early in mlsetup() for CPU 0, and in
+ * mp_startup() for all slave CPUs. Slaves process workaround_errata prior
+ * to acknowledging their readiness to the master, so this routine will
+ * never be executed by multiple CPUs in parallel, thus making updates to
+ * global data safe.
+ *
  * These workarounds are based on Rev 3.57 of the Revision Guide for
  * AMD Athlon(tm) 64 and AMD Opteron(tm) Processors, August 2005.
  */
@@ -539,6 +546,11 @@
 int opteron_erratum_131;	/* if non-zero -> at least one cpu has it */
 #endif
 
+#if defined(OPTERON_WORKAROUND_6336786)
+int opteron_workaround_6336786;	/* non-zero -> WA relevant and applied */
+int opteron_workaround_6336786_UP = 0;	/* Not needed for UP */
+#endif
+
 #define	WARNING(cpu, n)						\
 	cmn_err(CE_WARN, "cpu%d: no workaround for erratum %d",	\
 	    (cpu)->cpu_id, (n))
@@ -775,8 +787,40 @@
 			if (!(rdmsr(MSR_AMD_NB_CFG) & AMD_NB_CFG_SRQ_HEARTBEAT))
 				opteron_erratum_131++;
 		}
+	}
 #endif
+
+#if defined(OPTERON_WORKAROUND_6336786)
+	/*
+	 * This isn't really erratum, but for convenience the
+	 * detection/workaround code lives here and in cpuid_opteron_erratum.
+	 */
+	if (cpuid_opteron_erratum(cpu, 6336786) > 0) {
+		int	node;
+		uint8_t data;
+
+		/*
+		 * Disable C1-Clock ramping on multi-core/multi-processor
+		 * K8 platforms to guard against TSC drift.
+		 */
+		if (opteron_workaround_6336786) {
+			opteron_workaround_6336786++;
+		} else if ((lgrp_plat_node_cnt *
+		    cpuid_get_ncpu_per_chip(cpu) >= 2) ||
+		    opteron_workaround_6336786_UP) {
+			for (node = 0; node < lgrp_plat_node_cnt; node++) {
+				/*
+				 * Clear PMM7[1:0] (function 3, offset 0x87)
+				 * Northbridge device is the node id + 24.
+				 */
+				data = pci_getb_func(0, node + 24, 3, 0x87);
+				data &= 0xFC;
+				pci_putb_func(0, node + 24, 3, 0x87, data);
+			}
+			opteron_workaround_6336786++;
+		}
 	}
+#endif
 	return (missing);
 }