Module Name:    src
Committed By:   jruoho
Date:           Fri Aug 27 02:44:05 UTC 2010

Modified Files:
        src/sys/dev/acpi: acpi_cpu.c acpireg.h

Log Message:
>From jmcneill@: fix and rework the obscure _OSC evaluation.


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/acpi/acpi_cpu.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/acpi/acpireg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpi_cpu.c
diff -u src/sys/dev/acpi/acpi_cpu.c:1.20 src/sys/dev/acpi/acpi_cpu.c:1.21
--- src/sys/dev/acpi/acpi_cpu.c:1.20	Thu Aug 19 05:09:53 2010
+++ src/sys/dev/acpi/acpi_cpu.c	Fri Aug 27 02:44:05 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_cpu.c,v 1.20 2010/08/19 05:09:53 jruoho Exp $ */
+/* $NetBSD: acpi_cpu.c,v 1.21 2010/08/27 02:44:05 jruoho Exp $ */
 
 /*-
  * Copyright (c) 2010 Jukka Ruohonen <jruoho...@iki.fi>
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_cpu.c,v 1.20 2010/08/19 05:09:53 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_cpu.c,v 1.21 2010/08/27 02:44:05 jruoho Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -57,10 +57,9 @@
 static int		  acpicpu_object(ACPI_HANDLE, struct acpicpu_object *);
 static cpuid_t		  acpicpu_id(uint32_t);
 static uint32_t		  acpicpu_cap(struct acpicpu_softc *);
-static ACPI_OBJECT	 *acpicpu_cap_init(void);
-static ACPI_STATUS	  acpicpu_cap_pdc(ACPI_HANDLE);
-static ACPI_STATUS	  acpicpu_cap_osc(ACPI_HANDLE, uint32_t *);
-static const char	 *acpicpu_cap_oscerr(uint32_t);
+static ACPI_STATUS	  acpicpu_cap_pdc(struct acpicpu_softc *, uint32_t);
+static ACPI_STATUS	  acpicpu_cap_osc(struct acpicpu_softc *,
+					  uint32_t, uint32_t *);
 static void		  acpicpu_notify(ACPI_HANDLE, uint32_t, void *);
 static bool		  acpicpu_suspend(device_t, const pmf_qual_t *);
 static bool		  acpicpu_resume(device_t, const pmf_qual_t *);
@@ -132,6 +131,9 @@
 		return;
 	}
 
+	aprint_naive("\n");
+	aprint_normal(": ACPI CPU\n");
+
 	acpicpu_sc[sc->sc_cpuid] = sc;
 
 	sc->sc_cap = acpicpu_cap(sc);
@@ -139,9 +141,6 @@
 
 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
 
-	aprint_naive("\n");
-	aprint_normal(": ACPI CPU\n");
-
 	/*
 	 * We should claim the bus space. However, we do this only
 	 * to announce that the space is in use. As is noted in
@@ -334,150 +333,171 @@
 static uint32_t
 acpicpu_cap(struct acpicpu_softc *sc)
 {
-	uint32_t cap[3] = { 0 };
+	uint32_t flags, cap = 0;
+	const char *str;
 	ACPI_STATUS rv;
-	int err;
 
 	/*
-	 * Set machine-dependent processor capabilities.
-	 *
-	 * The _PDC was deprecated in ACPI 3.0 in favor of the _OSC,
-	 * but firmware may expect that we evaluate it nevertheless.
+	 * Query and set machine-dependent capabilities.
+	 * Note that the Intel-specific _PDC method was
+	 * deprecated in the ACPI 3.0 in favor of _OSC.
 	 */
-	rv = acpicpu_cap_pdc(sc->sc_node->ad_handle);
+	flags = acpicpu_md_cap();
+	rv = acpicpu_cap_osc(sc, flags, &cap);
 
-	if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
-		aprint_error_dev(sc->sc_dev, "failed to evaluate _PDC: "
-		    "%s\n", AcpiFormatException(rv));
+	if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) {
+		str = "_OSC";
+		goto fail;
+	}
 
-	rv = acpicpu_cap_osc(sc->sc_node->ad_handle, cap);
+	rv = acpicpu_cap_pdc(sc, flags);
 
-	if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
-		aprint_error_dev(sc->sc_dev, "failed to evaluate _OSC: "
-		    "%s\n", AcpiFormatException(rv));
+	if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) {
+		str = "_PDC";
+		goto fail;
+	}
 
-	if (ACPI_SUCCESS(rv)) {
+	if (cap == 0)
+		cap = flags;
 
-		err = cap[0] & ~__BIT(0);
+	return cap;
 
-		if (err != 0) {
-			aprint_error_dev(sc->sc_dev, "errors in "
-			    "_OSC: %s\n", acpicpu_cap_oscerr(err));
-			cap[2] = 0;
-		}
-	}
+fail:
+	aprint_error_dev(sc->sc_dev, "failed to evaluate "
+	    "%s: %s\n", str, AcpiFormatException(rv));
 
-	return cap[2];
+	return 0;
 }
 
-static ACPI_OBJECT *
-acpicpu_cap_init(void)
+static ACPI_STATUS
+acpicpu_cap_pdc(struct acpicpu_softc *sc, uint32_t flags)
 {
-	static uint32_t cap[3];
-	static ACPI_OBJECT obj;
+	ACPI_OBJECT_LIST arg;
+	ACPI_OBJECT obj;
+	uint32_t cap[3];
+
+	arg.Count = 1;
+	arg.Pointer = &obj;
 
 	cap[0] = ACPICPU_PDC_REVID;
 	cap[1] = 1;
-	cap[2] = acpicpu_md_cap();
+	cap[2] = flags;
 
 	obj.Type = ACPI_TYPE_BUFFER;
 	obj.Buffer.Length = sizeof(cap);
-	obj.Buffer.Pointer = (uint8_t *)cap;
+	obj.Buffer.Pointer = (void *)cap;
 
-	return &obj;
+	return AcpiEvaluateObject(sc->sc_node->ad_handle, "_PDC", &arg, NULL);
 }
 
 static ACPI_STATUS
-acpicpu_cap_pdc(ACPI_HANDLE hdl)
+acpicpu_cap_osc(struct acpicpu_softc *sc, uint32_t flags, uint32_t *val)
 {
-	ACPI_OBJECT_LIST arg_list;
-
-	arg_list.Count = 1;
-	arg_list.Pointer = acpicpu_cap_init();
-
-	return AcpiEvaluateObject(hdl, "_PDC", &arg_list, NULL);
-}
-
-static ACPI_STATUS
-acpicpu_cap_osc(ACPI_HANDLE hdl, uint32_t *val)
-{
-	ACPI_OBJECT_LIST arg_list;
-	ACPI_OBJECT *cap, *obj;
-	ACPI_OBJECT arg[4];
+	ACPI_OBJECT_LIST arg;
+	ACPI_OBJECT obj[4];
+	ACPI_OBJECT *osc;
 	ACPI_BUFFER buf;
 	ACPI_STATUS rv;
+	uint32_t cap[2];
+	uint32_t *ptr;
+	int i = 5;
 
-	/* Intel. */
-	static uint8_t cpu_oscuuid[16] = {
+	static uint8_t intel_uuid[16] = {
 		0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47,
 		0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53
 	};
 
-	cap = acpicpu_cap_init();
-
-	arg_list.Count = 4;
-	arg_list.Pointer = arg;
-
-	arg[0].Type = ACPI_TYPE_BUFFER;
-	arg[0].Buffer.Length = sizeof(cpu_oscuuid);
-	arg[0].Buffer.Pointer = cpu_oscuuid;
+	cap[0] = ACPI_OSC_QUERY;
+	cap[1] = flags;
 
-	arg[1].Type = ACPI_TYPE_INTEGER;
-	arg[1].Integer.Value = ACPICPU_PDC_REVID;
-
-	arg[2].Type = ACPI_TYPE_INTEGER;
-	arg[2].Integer.Value = cap->Buffer.Length / sizeof(uint32_t);
-
-	arg[3] = *cap;
+again:
+	arg.Count = 4;
+	arg.Pointer = obj;
+
+	obj[0].Type = ACPI_TYPE_BUFFER;
+	obj[0].Buffer.Length = sizeof(intel_uuid);
+	obj[0].Buffer.Pointer = intel_uuid;
+
+	obj[1].Type = ACPI_TYPE_INTEGER;
+	obj[1].Integer.Value = ACPICPU_PDC_REVID;
+
+	obj[2].Type = ACPI_TYPE_INTEGER;
+	obj[2].Integer.Value = __arraycount(cap);
+
+	obj[3].Type = ACPI_TYPE_BUFFER;
+	obj[3].Buffer.Length = sizeof(cap);
+	obj[3].Buffer.Pointer = (void *)cap;
 
 	buf.Pointer = NULL;
 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
 
-	rv = AcpiEvaluateObject(hdl, "_OSC", &arg_list, &buf);
+	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "_OSC", &arg, &buf);
 
 	if (ACPI_FAILURE(rv))
-		return rv;
+		goto out;
 
-	obj = buf.Pointer;
+	osc = buf.Pointer;
 
-	if (obj->Type != ACPI_TYPE_BUFFER) {
+	if (osc->Type != ACPI_TYPE_BUFFER) {
 		rv = AE_TYPE;
 		goto out;
 	}
 
-	if (obj->Buffer.Length != cap->Buffer.Length) {
+	if (osc->Buffer.Length != sizeof(cap)) {
 		rv = AE_BUFFER_OVERFLOW;
 		goto out;
 	}
 
-	(void)memcpy(val, obj->Buffer.Pointer, obj->Buffer.Length);
+	ptr = (uint32_t *)osc->Buffer.Pointer;
 
-out:
-	if (buf.Pointer != NULL)
-		ACPI_FREE(buf.Pointer);
+	if ((ptr[0] & ACPI_OSC_ERROR) != 0) {
+		rv = AE_ERROR;
+		goto out;
+	}
 
-	return rv;
-}
+	if ((ptr[0] & (ACPI_OSC_ERROR_REV | ACPI_OSC_ERROR_UUID)) != 0) {
+		rv = AE_BAD_PARAMETER;
+		goto out;
+	}
 
-static const char *
-acpicpu_cap_oscerr(uint32_t err)
-{
+	/*
+	 * "It is strongly recommended that the OS evaluate
+	 *  _OSC with the Query Support Flag set until _OSC
+	 *  returns the Capabilities Masked bit clear, to
+	 *  negotiate the set of features to be granted to
+	 *  the OS for native support (ACPI 4.0, 6.2.10)."
+	 */
+	if ((ptr[0] & ACPI_OSC_ERROR_MASKED) != 0 && i >= 0) {
 
-	KASSERT((err & __BIT(0)) == 0);
+		ACPI_FREE(buf.Pointer);
+		i--;
 
-	if ((err & __BIT(1)) != 0)
-		return "_OSC failure";
+		goto again;
+	}
 
-	if ((err & __BIT(2)) != 0)
-		return "unrecognized UUID";
+	if ((cap[0] & ACPI_OSC_QUERY) != 0) {
 
-	if ((err & __BIT(3)) != 0)
-		return "unrecognized revision";
+		ACPI_FREE(buf.Pointer);
+		cap[0] &= ~ACPI_OSC_QUERY;
 
-	if ((err & __BIT(4)) != 0)
-		return "capabilities masked";
+		goto again;
+	}
 
-	return "unknown error";
+	/*
+	 * It is permitted for _OSC to return all
+	 * bits cleared, but this is specified to
+	 * vary on per-device basis. Assume that
+	 * everything rather than nothing will be
+	 * supported in thise case; we do not need
+	 * the firmware to know the CPU features.
+	 */
+	*val = (ptr[1] != 0) ? ptr[1] : cap[1];
+
+out:
+	if (buf.Pointer != NULL)
+		ACPI_FREE(buf.Pointer);
+
+	return rv;
 }
 
 static void

Index: src/sys/dev/acpi/acpireg.h
diff -u src/sys/dev/acpi/acpireg.h:1.9 src/sys/dev/acpi/acpireg.h:1.10
--- src/sys/dev/acpi/acpireg.h:1.9	Tue Apr 27 05:57:43 2010
+++ src/sys/dev/acpi/acpireg.h	Fri Aug 27 02:44:05 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: acpireg.h,v 1.9 2010/04/27 05:57:43 jruoho Exp $	*/
+/*	$NetBSD: acpireg.h,v 1.10 2010/08/27 02:44:05 jruoho Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -44,6 +44,16 @@
 #define ACPI_STA_OK		(ACPI_STA_DEVICE_PRESENT	|	\
 				 ACPI_STA_DEVICE_ENABLED	|	\
 				 ACPI_STA_DEVICE_FUNCTIONING)
+
+/*
+ * Operating System Capabilities, _OSC.
+ */
+#define ACPI_OSC_QUERY		__BIT(0)
+#define ACPI_OSC_ERROR		__BIT(1)
+#define ACPI_OSC_ERROR_UUID	__BIT(2)
+#define ACPI_OSC_ERROR_REV	__BIT(3)
+#define ACPI_OSC_ERROR_MASKED	__BIT(4)
+
 /*
  * PCI functions.
  */

Reply via email to