Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 16 May 2010 15:57:00 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r208152 - in head/sys: dev/ofw powerpc/aim powerpc/ofw
Message-ID:  <201005161557.o4GFv0Lf046659@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Sun May 16 15:56:59 2010
New Revision: 208152
URL: http://svn.freebsd.org/changeset/base/208152

Log:
  On PowerMac11,2 and (presumably) PowerMac12,1, we need to quiesce the
  firmware in order to take over control of the SMU. Without doing this,
  the firmware background process doing fan control will run amok as we
  take over the system and crash the management chip.
  
  This is limited to these two machines because our kernel is heavily
  dependent on firmware accesses, and so quiescing firmware can cause
  nasty problems.

Modified:
  head/sys/dev/ofw/ofw_if.m
  head/sys/dev/ofw/ofw_standard.c
  head/sys/dev/ofw/openfirm.c
  head/sys/dev/ofw/openfirm.h
  head/sys/powerpc/aim/ofw_machdep.c
  head/sys/powerpc/ofw/ofw_real.c

Modified: head/sys/dev/ofw/ofw_if.m
==============================================================================
--- head/sys/dev/ofw/ofw_if.m	Sun May 16 15:22:42 2010	(r208151)
+++ head/sys/dev/ofw/ofw_if.m	Sun May 16 15:56:59 2010	(r208152)
@@ -340,6 +340,13 @@ METHOD void release {
 # Commands for returning control to the firmware
 
 /**
+ * @brief Turn off firmware background activities
+ */
+METHOD void quiesce {
+	ofw_t		_ofw;
+};
+
+/**
  * @brief Temporarily return control to firmware.
  */
 METHOD void enter {

Modified: head/sys/dev/ofw/ofw_standard.c
==============================================================================
--- head/sys/dev/ofw/ofw_standard.c	Sun May 16 15:22:42 2010	(r208151)
+++ head/sys/dev/ofw/ofw_standard.c	Sun May 16 15:56:59 2010	(r208152)
@@ -105,6 +105,7 @@ static ssize_t ofw_std_write(ofw_t ofw, 
 static int ofw_std_seek(ofw_t ofw, ihandle_t instance, uint64_t pos);
 static caddr_t ofw_std_claim(ofw_t ofw, void *virt, size_t size, u_int align);
 static void ofw_std_release(ofw_t ofw, void *virt, size_t size);
+static void ofw_std_quiesce(ofw_t ofw);
 static void ofw_std_enter(ofw_t ofw);
 static void ofw_std_exit(ofw_t ofw);
 
@@ -133,6 +134,7 @@ static ofw_method_t ofw_std_methods[] = 
 	OFWMETHOD(ofw_seek,			ofw_std_seek),
 	OFWMETHOD(ofw_claim,			ofw_std_claim),
 	OFWMETHOD(ofw_release,			ofw_std_release),
+	OFWMETHOD(ofw_quiesce,			ofw_std_quiesce),
 	OFWMETHOD(ofw_enter,			ofw_std_enter),
 	OFWMETHOD(ofw_exit,			ofw_std_exit),
 
@@ -730,6 +732,23 @@ ofw_std_release(ofw_t ofw, void *virt, s
  * Control transfer functions
  */
 
+/* Turn off OF background tasks */
+static void
+ofw_std_quiesce(ofw_t ofw)
+{
+	struct {
+		cell_t name;
+		cell_t nargs;
+		cell_t nreturns;
+	} args = {
+		(cell_t)"quiesce",
+		0,
+		0,
+	};
+
+	openfirmware(&args);
+}
+
 /* Suspend and drop back to the Open Firmware interface. */
 static void
 ofw_std_enter(ofw_t ofw)

Modified: head/sys/dev/ofw/openfirm.c
==============================================================================
--- head/sys/dev/ofw/openfirm.c	Sun May 16 15:22:42 2010	(r208151)
+++ head/sys/dev/ofw/openfirm.c	Sun May 16 15:56:59 2010	(r208152)
@@ -409,6 +409,15 @@ OF_release(void *virt, size_t size)
  * Control transfer functions
  */
 
+/* Turn off OF background tasks */
+void
+OF_quiesce()
+{
+
+	OFW_QUIESCE(ofw_obj);
+}
+
+
 /* Suspend and drop back to the Open Firmware interface. */
 void
 OF_enter()

Modified: head/sys/dev/ofw/openfirm.h
==============================================================================
--- head/sys/dev/ofw/openfirm.h	Sun May 16 15:22:42 2010	(r208151)
+++ head/sys/dev/ofw/openfirm.h	Sun May 16 15:56:59 2010	(r208152)
@@ -133,6 +133,7 @@ void		*OF_claim(void *virtrequest, size_
 void		OF_release(void *virt, size_t size);
 
 /* Control transfer functions */
+void		OF_quiesce(void);
 void		OF_enter(void);
 void		OF_exit(void) __attribute__((noreturn));
 

Modified: head/sys/powerpc/aim/ofw_machdep.c
==============================================================================
--- head/sys/powerpc/aim/ofw_machdep.c	Sun May 16 15:22:42 2010	(r208151)
+++ head/sys/powerpc/aim/ofw_machdep.c	Sun May 16 15:56:59 2010	(r208152)
@@ -281,6 +281,8 @@ OF_initial_setup(void *fdt_ptr, void *ju
 boolean_t
 OF_bootstrap()
 {
+	char model[32];
+	phandle_t rootnode;
 	boolean_t status = FALSE;
 
 	mtx_init(&ofw_mutex, "open firmware", NULL, MTX_DEF);
@@ -295,6 +297,17 @@ OF_bootstrap()
 			return status;
 
 		OF_init(openfirmware);
+
+		/*
+		 * On some machines, we need to quiesce OF to turn off
+		 * background processes.
+		 */
+		rootnode = OF_finddevice("/");
+		if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
+			if (strcmp(model, "PowerMac11,2") == 0 ||
+			    strcmp(model, "PowerMac12,1") == 0)
+				OF_quiesce();
+		}
 	} else {
 		status = OF_install(OFW_FDT, 0);
 

Modified: head/sys/powerpc/ofw/ofw_real.c
==============================================================================
--- head/sys/powerpc/ofw/ofw_real.c	Sun May 16 15:22:42 2010	(r208151)
+++ head/sys/powerpc/ofw/ofw_real.c	Sun May 16 15:56:59 2010	(r208152)
@@ -106,6 +106,7 @@ static ssize_t ofw_real_write(ofw_t, iha
 static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos);
 static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align);
 static void ofw_real_release(ofw_t, void *virt, size_t size);
+static void ofw_real_quiesce(ofw_t);
 static void ofw_real_enter(ofw_t);
 static void ofw_real_exit(ofw_t);
 
@@ -133,6 +134,7 @@ static ofw_method_t ofw_real_methods[] =
 	OFWMETHOD(ofw_seek,			ofw_real_seek),
 	OFWMETHOD(ofw_claim,			ofw_real_claim),
 	OFWMETHOD(ofw_release,			ofw_real_release),
+	OFWMETHOD(ofw_quiesce,			ofw_real_quiesce),
 	OFWMETHOD(ofw_enter,			ofw_real_enter),
 	OFWMETHOD(ofw_exit,			ofw_real_exit),
 
@@ -889,6 +891,27 @@ ofw_real_release(ofw_t ofw, void *virt, 
  * Control transfer functions
  */
 
+/* Turn off OF background tasks */
+static void
+ofw_real_quiesce(ofw_t ofw)
+{
+	vm_offset_t argsptr;
+	struct {
+		cell_t name;
+		cell_t nargs;
+		cell_t nreturns;
+	} args;
+
+	args.name = (cell_t)(uintptr_t)"quiesce";
+	args.nargs = 0;
+	args.nreturns = 0;
+
+	ofw_real_start();
+	argsptr = ofw_real_map(&args, sizeof(args));
+	openfirmware((void *)argsptr);
+	ofw_real_stop();
+}
+
 /* Suspend and drop back to the Open Firmware interface. */
 static void
 ofw_real_enter(ofw_t ofw)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005161557.o4GFv0Lf046659>