static status_t acpi_cpuidle_setup(acpi_cpuidle_driver_info *device) { // _PDC is deprecated in the ACPI 3.0, we will try _OSC firstly // and fall back to _PDC if _OSC fail status_t status = acpi_eval_osc(device); if (status != B_OK) status = acpi_eval_pdc(device); if (status != B_OK) { dprintf("failed to eval _OSC and _PDC\n"); return status; } acpi_data buffer; buffer.pointer = NULL; buffer.length = ACPI_ALLOCATE_BUFFER; dprintf("evaluate _CST @%p\n", device->acpi_cookie); status = device->acpi->evaluate_method(device->acpi_cookie, "_CST", NULL, &buffer); if (status != B_OK) { dprintf("failed to get _CST\n"); return B_IO_ERROR; } acpi_object_type *object = (acpi_object_type *)buffer.pointer; if (object->object_type != ACPI_TYPE_PACKAGE) dprintf("invalid _CST type\n"); if (object->data.package.count < 2) dprintf("invalid _CST count\n"); acpi_object_type *pointer = object->data.package.objects; if (pointer[0].object_type != ACPI_TYPE_INTEGER) dprintf("invalid _CST type 2\n"); uint32 n = pointer[0].data.integer; if (n != object->data.package.count - 1) dprintf("invalid _CST count 2\n"); if (n > 8) dprintf("_CST has too many states\n"); dprintf("cpuidle found %" B_PRId32 " cstates\n", n); uint32 count = 1; for (uint32 i = 1; i <= n; i++) { pointer = &object->data.package.objects[i]; if (acpi_cstate_add(pointer, &sAcpiDevice.cStates[count]) == B_OK) ++count; } sAcpiDevice.cStateCount = count; free(buffer.pointer); // TODO we assume BM is a must and ARB_DIS is always available device->flags |= ACPI_FLAG_C_ARB | ACPI_FLAG_C_BM; acpi_cstate_quirks(device); return B_OK; }
static int acpi_cpu_attach(device_t dev) { struct acpi_cpu_softc *sc = device_get_softc(dev); ACPI_HANDLE handle; device_t child; int cpu_id, cpu_features; struct acpi_softc *acpi_sc; sc->cpu_dev = dev; handle = acpi_get_handle(dev); cpu_id = acpi_get_magic(dev); acpi_sc = acpi_device_get_parent_softc(dev); if (cpu_id == 0) { sysctl_ctx_init(&sc->glob_sysctl_ctx); sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "cpu", CTLFLAG_RD, 0, "node for CPU global settings"); if (sc->glob_sysctl_tree == NULL) return ENOMEM; } sysctl_ctx_init(&sc->pcpu_sysctl_ctx); sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0, "node for per-CPU settings"); if (sc->pcpu_sysctl_tree == NULL) { sysctl_ctx_free(&sc->glob_sysctl_ctx); return ENOMEM; } /* * Before calling any CPU methods, collect child driver feature hints * and notify ACPI of them. We support unified SMP power control * so advertise this ourselves. Note this is not the same as independent * SMP control where each CPU can have different settings. */ cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3; cpu_features |= acpi_cpu_md_features(); /* * CPU capabilities are specified as a buffer of 32-bit integers: * revision, count, and one or more capabilities. */ if (cpu_features) { uint32_t cap_set[3]; ACPI_STATUS status; cap_set[0] = 0; cap_set[1] = cpu_features; status = acpi_eval_osc(dev, handle, "4077A616-290C-47BE-9EBD-D87058713953", 1, cap_set, 2); if (ACPI_FAILURE(status)) { ACPI_OBJECT_LIST arglist; ACPI_OBJECT arg[4]; if (bootverbose) device_printf(dev, "_OSC failed, using _PDC\n"); arglist.Pointer = arg; arglist.Count = 1; arg[0].Type = ACPI_TYPE_BUFFER; arg[0].Buffer.Length = sizeof(cap_set); arg[0].Buffer.Pointer = (uint8_t *)cap_set; cap_set[0] = 1; /* revision */ cap_set[1] = 1; /* # of capabilities integers */ cap_set[2] = cpu_features; AcpiEvaluateObject(handle, "_PDC", &arglist, NULL); } } ksnprintf(sc->cpu_sensdev.xname, sizeof(sc->cpu_sensdev.xname), "%s", device_get_nameunit(dev)); sensordev_install(&sc->cpu_sensdev); child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); if (child == NULL) return ENXIO; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpu_cst = child; child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1); if (child == NULL) return ENXIO; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpu_pst = child; bus_generic_probe(dev); bus_generic_attach(dev); AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc); return 0; }