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. */