1241675Suqs/* 2241675Suqs * Copyright 2012, Haiku, Inc. All Rights Reserved. 3241675Suqs * 4241675Suqs * Distributed under the terms of the MIT License. 5241675Suqs * 6241675Suqs * Authors: 7241675Suqs * Yongcong Du <ycdu.vmcore@gmail.com> 8241675Suqs */ 9241675Suqs 10241675Suqs 11241675Suqs#include <stdio.h> 12241675Suqs#include <stdlib.h> 13241675Suqs#include <string.h> 14241675Suqs 15241675Suqs#include <ACPI.h> 16241675Suqs#include <Drivers.h> 17241675Suqs#include <Errors.h> 18241675Suqs#include <KernelExport.h> 19241675Suqs 20241675Suqs#include <arch_system_info.h> 21241675Suqs#include <cpu.h> 22241675Suqs#include <cpuidle.h> 23241675Suqs#include <smp.h> 24241675Suqs 25241675Suqs#include "x86_cpuidle.h" 26241675Suqs 27241675Suqs 28241675Suqs#define ACPI_PDC_REVID 0x1 29241675Suqs#define ACPI_OSC_QUERY (1 << 0) 30241675Suqs 31241675Suqs#define ACPI_PDC_P_FFH (1 << 0) 32241675Suqs#define ACPI_PDC_C_C1_HALT (1 << 1) 33241675Suqs#define ACPI_PDC_T_FFH (1 << 2) 34241675Suqs#define ACPI_PDC_SMP_C1PT (1 << 3) 35241675Suqs#define ACPI_PDC_SMP_C2C3 (1 << 4) 36241675Suqs#define ACPI_PDC_SMP_P_SW (1 << 5) 37241675Suqs#define ACPI_PDC_SMP_C_SW (1 << 6) 38241675Suqs#define ACPI_PDC_SMP_T_SW (1 << 7) 39241675Suqs#define ACPI_PDC_C_C1_FFH (1 << 8) 40241675Suqs#define ACPI_PDC_C_C2C3_FFH (1 << 9) 41241675Suqs#define ACPI_PDC_P_HWCOORD (1 << 11) 42241675Suqs 43241675Suqs// Bus Master check required 44241675Suqs#define ACPI_PDC_GAS_BM (1 << 1) 45241675Suqs 46241675Suqs#define ACPI_CSTATE_HALT 0x1 47241675Suqs#define ACPI_CSTATE_SYSIO 0x2 48241675Suqs#define ACPI_CSTATE_FFH 0x3 49241675Suqs 50241675Suqs// Bus Master Check 51241675Suqs#define ACPI_FLAG_C_BM (1 << 0) 52241675Suqs// Bus master arbitration 53241675Suqs#define ACPI_FLAG_C_ARB (1 << 1) 54241675Suqs 55241675Suqs// Copied from acpica's actypes.h, where's the best place to put? 56241675Suqs#define ACPI_BITREG_BUS_MASTER_STATUS 0x01 57241675Suqs#define ACPI_BITREG_BUS_MASTER_RLD 0x0F 58241675Suqs#define ACPI_BITREG_ARB_DISABLE 0x13 59241675Suqs 60241675Suqs#define ACPI_STATE_C0 (uint8) 0 61241675Suqs#define ACPI_STATE_C1 (uint8) 1 62241675Suqs#define ACPI_STATE_C2 (uint8) 2 63241675Suqs#define ACPI_STATE_C3 (uint8) 3 64241675Suqs#define ACPI_C_STATES_MAX ACPI_STATE_C3 65241675Suqs#define ACPI_C_STATE_COUNT 4 66241675Suqs 67241675Suqs 68241675Suqs#define ACPI_CPUIDLE_MODULE_NAME "drivers/power/x86_cpuidle/acpi/driver_v1" 69241675Suqs 70241675Suqs 71241675Suqsstruct acpicpu_reg { 72241675Suqs uint8 reg_desc; 73241675Suqs uint16 reg_reslen; 74241675Suqs uint8 reg_spaceid; 75241675Suqs uint8 reg_bitwidth; 76241675Suqs uint8 reg_bitoffset; 77241675Suqs uint8 reg_accesssize; 78241675Suqs uint64 reg_addr; 79241675Suqs} __attribute__((packed)); 80241675Suqs 81241675Suqsstruct acpi_cpuidle_driver_info { 82241675Suqs device_node *node; 83241675Suqs acpi_device_module_info *acpi; 84241675Suqs acpi_device acpi_cookie; 85241675Suqs uint32 flags; 86241675Suqs int32 cpuIndex; 87241675Suqs}; 88241675Suqs 89241675Suqsstruct acpi_cstate_info { 90241675Suqs uint32 address; 91241675Suqs uint8 skip_bm_sts; 92241675Suqs uint8 method; 93241675Suqs uint8 type; 94241675Suqs}; 95241675Suqs 96241675Suqs 97241675Suqsstatic acpi_cpuidle_driver_info *sAcpiProcessor[SMP_MAX_CPUS]; 98241675Suqsstatic CpuidleDevice sAcpiDevice; 99241675Suqsstatic device_manager_info *sDeviceManager; 100241675Suqsstatic acpi_module_info *sAcpi; 101241675Suqs 102241675SuqsCpuidleModuleInfo *gIdle; 103241675Suqs 104241675Suqs 105241675Suqsstatic status_t 106241675Suqsacpi_eval_pdc(acpi_cpuidle_driver_info *device) 107241675Suqs{ 108241675Suqs acpi_objects arg; 109241675Suqs acpi_object_type obj; 110241675Suqs uint32 cap[3]; 111241675Suqs 112241675Suqs arg.count = 1; 113241675Suqs arg.pointer = &obj; 114241675Suqs cap[0] = 1; 115241675Suqs cap[1] = 1; 116241675Suqs cap[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_SMP_C1PT | ACPI_PDC_SMP_C2C3; 117241675Suqs cap[2] |= ACPI_PDC_SMP_P_SW | ACPI_PDC_SMP_C_SW | ACPI_PDC_SMP_T_SW; 118241675Suqs cap[2] |= ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH; 119241675Suqs cap[2] |= ACPI_PDC_SMP_T_SW | ACPI_PDC_P_FFH | ACPI_PDC_P_HWCOORD 120241675Suqs | ACPI_PDC_T_FFH; 121241675Suqs obj.object_type = ACPI_TYPE_BUFFER; 122241675Suqs obj.data.buffer.length = sizeof(cap); 123241675Suqs obj.data.buffer.buffer = cap; 124241675Suqs status_t status = device->acpi->evaluate_method(device->acpi_cookie, "_PDC", 125241675Suqs &arg, NULL); 126241675Suqs return status; 127241675Suqs} 128241675Suqs 129241675Suqs 130241675Suqsstatic status_t 131241675Suqsacpi_eval_osc(acpi_cpuidle_driver_info *device) 132241675Suqs{ 133241675Suqs // guid for intel platform 134241675Suqs dprintf("%s@%p\n", __func__, device->acpi_cookie); 135241675Suqs static uint8 uuid[] = { 136241675Suqs 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47, 137241675Suqs 0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53 138241675Suqs }; 139241675Suqs uint32 cap[2]; 140241675Suqs cap[0] = 0; 141241675Suqs cap[1] = ACPI_PDC_C_C1_HALT | ACPI_PDC_SMP_C1PT | ACPI_PDC_SMP_C2C3; 142241675Suqs cap[1] |= ACPI_PDC_SMP_P_SW | ACPI_PDC_SMP_C_SW | ACPI_PDC_SMP_T_SW; 143241675Suqs cap[1] |= ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH; 144241675Suqs cap[1] |= ACPI_PDC_SMP_T_SW | ACPI_PDC_P_FFH | ACPI_PDC_P_HWCOORD 145241675Suqs | ACPI_PDC_T_FFH; 146241675Suqs 147241675Suqs acpi_objects arg; 148241675Suqs acpi_object_type obj[4]; 149241675Suqs 150241675Suqs arg.count = 4; 151241675Suqs arg.pointer = obj; 152241675Suqs 153241675Suqs obj[0].object_type = ACPI_TYPE_BUFFER; 154241675Suqs obj[0].data.buffer.length = sizeof(uuid); 155241675Suqs obj[0].data.buffer.buffer = uuid; 156241675Suqs obj[1].object_type = ACPI_TYPE_INTEGER; 157241675Suqs obj[1].data.integer = ACPI_PDC_REVID; 158241675Suqs obj[2].object_type = ACPI_TYPE_INTEGER; 159241675Suqs obj[2].data.integer = sizeof(cap)/sizeof(cap[0]); 160241675Suqs obj[3].object_type = ACPI_TYPE_BUFFER; 161241675Suqs obj[3].data.buffer.length = sizeof(cap); 162241675Suqs obj[3].data.buffer.buffer = (void *)cap; 163241675Suqs 164241675Suqs acpi_data buf; 165241675Suqs buf.pointer = NULL; 166241675Suqs buf.length = ACPI_ALLOCATE_LOCAL_BUFFER; 167241675Suqs status_t status = device->acpi->evaluate_method(device->acpi_cookie, "_OSC", 168241675Suqs &arg, &buf); 169241675Suqs if (status != B_OK) 170241675Suqs return status; 171241675Suqs acpi_object_type *osc = (acpi_object_type *)buf.pointer; 172241675Suqs if (osc->object_type != ACPI_TYPE_BUFFER) 173241675Suqs return B_BAD_TYPE; 174241675Suqs if (osc->data.buffer.length != sizeof(cap)) 175241675Suqs return B_BUFFER_OVERFLOW; 176241675Suqs return status; 177241675Suqs} 178241675Suqs 179241675Suqs 180241675Suqsstatic inline bool 181241675Suqsacpi_cstate_bm_check(void) 182241675Suqs{ 183241675Suqs uint32 val; 184241675Suqs sAcpi->read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &val); 185241675Suqs if (!val) 186241675Suqs return false; 187241675Suqs sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); 188241675Suqs 189241675Suqs return true; 190241675Suqs} 191241675Suqs 192241675Suqs 193241675Suqsstatic inline void 194241675Suqsacpi_cstate_ffh_enter(CpuidleCstate *cState) 195241675Suqs{ 196241675Suqs cpu_ent *cpu = get_cpu_struct(); 197241675Suqs if (cpu->invoke_scheduler) 198241675Suqs return; 199241675Suqs 200241675Suqs x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); 201241675Suqs if (!cpu->invoke_scheduler) 202241675Suqs x86_mwait((unsigned long)cState->pData, 1); 203241675Suqs} 204241675Suqs 205241675Suqs 206241675Suqsstatic inline void 207241675Suqsacpi_cstate_halt(void) 208241675Suqs{ 209241675Suqs cpu_ent *cpu = get_cpu_struct(); 210241675Suqs if (cpu->invoke_scheduler) 211241675Suqs return; 212241675Suqs asm("hlt"); 213241675Suqs} 214241675Suqs 215241675Suqs 216241675Suqsstatic void 217241675Suqsacpi_cstate_enter(CpuidleCstate *cState) 218241675Suqs{ 219241675Suqs acpi_cstate_info *ci = (acpi_cstate_info *)cState->pData; 220241675Suqs if (ci->method == ACPI_CSTATE_FFH) 221241675Suqs acpi_cstate_ffh_enter(cState); 222241675Suqs else if (ci->method == ACPI_CSTATE_SYSIO) 223241675Suqs in8(ci->address); 224241675Suqs else 225241675Suqs acpi_cstate_halt(); 226241675Suqs} 227241675Suqs 228241675Suqs 229241675Suqsstatic int32 230241675Suqsacpi_cstate_idle(int32 state, CpuidleDevice *device) 231241675Suqs{ 232241675Suqs CpuidleCstate *cState = &device->cStates[state]; 233241675Suqs acpi_cstate_info *ci = (acpi_cstate_info *)cState->pData; 234241675Suqs if (!ci->skip_bm_sts) { 235241675Suqs // we fall back to C1 if there's bus master activity 236241675Suqs if (acpi_cstate_bm_check()) 237241675Suqs state = 1; 238241675Suqs } 239241675Suqs if (ci->type != ACPI_STATE_C3) 240241675Suqs acpi_cstate_enter(cState); 241241675Suqs 242241675Suqs // set BM_RLD for Bus Master to activity to wake the system from C3 243241675Suqs // With Newer chipsets BM_RLD is a NOP Since DMA is automatically handled 244241675Suqs // during C3 State 245241675Suqs acpi_cpuidle_driver_info *pi = sAcpiProcessor[smp_get_current_cpu()]; 246241675Suqs if (pi->flags & ACPI_FLAG_C_BM) 247241675Suqs sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1); 248241675Suqs 249241675Suqs // disable bus master arbitration during C3 250241675Suqs if (pi->flags & ACPI_FLAG_C_ARB) 251241675Suqs sAcpi->write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); 252241675Suqs 253241675Suqs acpi_cstate_enter(cState); 254241675Suqs 255241675Suqs // clear BM_RLD and re-enable the arbiter 256241675Suqs if (pi->flags & ACPI_FLAG_C_BM) 257241675Suqs sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0); 258241675Suqs 259241675Suqs if (pi->flags & ACPI_FLAG_C_ARB) 260241675Suqs sAcpi->write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); 261241675Suqs 262241675Suqs return state; 263241675Suqs} 264241675Suqs 265241675Suqs 266241675Suqsstatic status_t 267241675Suqsacpi_cstate_add(acpi_object_type *object, CpuidleCstate *cState) 268241675Suqs{ 269241675Suqs acpi_cstate_info *ci = (acpi_cstate_info *)malloc(sizeof(acpi_cstate_info)); 270241675Suqs if (!ci) 271241675Suqs return B_NO_MEMORY; 272241675Suqs 273241675Suqs if (object->object_type != ACPI_TYPE_PACKAGE) { 274241675Suqs dprintf("invalid _CST object\n"); 275241675Suqs goto error; 276241675Suqs } 277241675Suqs 278241675Suqs if (object->data.package.count != 4) { 279241675Suqs dprintf("invalid _CST number\n"); 280241675Suqs goto error; 281241675Suqs } 282241675Suqs 283241675Suqs // type 284241675Suqs acpi_object_type * pointer = &object->data.package.objects[1]; 285241675Suqs if (pointer->object_type != ACPI_TYPE_INTEGER) { 286241675Suqs dprintf("invalid _CST elem type\n"); 287241675Suqs goto error; 288241675Suqs } 289241675Suqs uint32 n = pointer->data.integer; 290241675Suqs if (n < 1 || n > 3) { 291241675Suqs dprintf("invalid _CST elem value\n"); 292241675Suqs goto error; 293241675Suqs } 294241675Suqs ci->type = n; 295241675Suqs dprintf("C%" B_PRId32 "\n", n); 296241675Suqs snprintf(cState->name, sizeof(cState->name), "C%" B_PRId32, n); 297241675Suqs 298241675Suqs // Latency 299241675Suqs pointer = &object->data.package.objects[2]; 300241675Suqs if (pointer->object_type != ACPI_TYPE_INTEGER) { 301241675Suqs dprintf("invalid _CST elem type\n"); 302241675Suqs goto error; 303241675Suqs } 304241675Suqs n = pointer->data.integer; 305241675Suqs cState->latency = n; 306241675Suqs dprintf("Latency: %" B_PRId32 "\n", n); 307241675Suqs 308241675Suqs // power 309241675Suqs pointer = &object->data.package.objects[3]; 310241675Suqs if (pointer->object_type != ACPI_TYPE_INTEGER) { 311241675Suqs dprintf("invalid _CST elem type\n"); 312241675Suqs goto error; 313241675Suqs } 314241675Suqs n = pointer->data.integer; 315241675Suqs dprintf("power: %" B_PRId32 "\n", n); 316241675Suqs 317241675Suqs // register 318241675Suqs pointer = &object->data.package.objects[0]; 319241675Suqs if (pointer->object_type != ACPI_TYPE_BUFFER) { 320241675Suqs dprintf("invalid _CST elem type\n"); 321241675Suqs goto error; 322241675Suqs } 323241675Suqs if (pointer->data.buffer.length < 15) { 324241675Suqs dprintf("invalid _CST elem length\n"); 325241675Suqs goto error; 326241675Suqs } 327241675Suqs 328241675Suqs struct acpicpu_reg *reg = (struct acpicpu_reg *)pointer->data.buffer.buffer; 329241675Suqs switch (reg->reg_spaceid) { 330241675Suqs case ACPI_ADR_SPACE_SYSTEM_IO: 331241675Suqs dprintf("IO method\n"); 332241675Suqs if (reg->reg_addr == 0) { 333241675Suqs dprintf("illegal address\n"); 334241675Suqs goto error; 335241675Suqs } 336241675Suqs if (reg->reg_bitwidth != 8) { 337241675Suqs dprintf("invalid source length\n"); 338241675Suqs goto error; 339241675Suqs } 340241675Suqs ci->address = reg->reg_addr; 341241675Suqs ci->method = ACPI_CSTATE_SYSIO; 342241675Suqs break; 343241675Suqs case ACPI_ADR_SPACE_FIXED_HARDWARE: 344241675Suqs { 345241675Suqs dprintf("FFH method\n"); 346241675Suqs ci->method = ACPI_CSTATE_FFH; 347241675Suqs ci->address = reg->reg_addr; 348241675Suqs 349241675Suqs // skip checking BM_STS if ACPI_PDC_GAS_BM is cleared 350241675Suqs cpu_ent *cpu = get_cpu_struct(); 351241675Suqs if ((cpu->arch.vendor == VENDOR_INTEL) && 352241675Suqs !(reg->reg_accesssize & ACPI_PDC_GAS_BM)) 353241675Suqs ci->skip_bm_sts = 1; 354241675Suqs break; 355241675Suqs } 356241675Suqs default: 357241675Suqs dprintf("invalid spaceid %" B_PRId8 "\n", reg->reg_spaceid); 358241675Suqs break; 359241675Suqs } 360241675Suqs cState->pData = ci; 361241675Suqs cState->EnterIdle = acpi_cstate_idle; 362241675Suqs 363241675Suqs return B_OK; 364241675Suqserror: 365241675Suqs free(ci); 366241675Suqs return B_ERROR; 367241675Suqs} 368241675Suqs 369241675Suqs 370241675Suqsstatic void 371241675Suqsacpi_cstate_quirks(acpi_cpuidle_driver_info *device) 372241675Suqs{ 373241675Suqs cpu_ent *cpu = get_cpu_struct(); 374241675Suqs // Calculated Model Value: M = (Extended Model << 4) + Model 375241675Suqs uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; 376241675Suqs 377241675Suqs // On all recent Intel platforms, ARB_DIS is not necessary 378241675Suqs if (cpu->arch.vendor != VENDOR_INTEL) 379241675Suqs return; 380241675Suqs if (cpu->arch.family > 0xf || (cpu->arch.family == 6 && model >= 0xf)) 381241675Suqs device->flags &= ~ACPI_FLAG_C_ARB; 382241675Suqs} 383241675Suqs 384241675Suqs 385241675Suqsstatic status_t 386241675Suqsacpi_cpuidle_setup(acpi_cpuidle_driver_info *device) 387241675Suqs{ 388241675Suqs // _PDC is deprecated in the ACPI 3.0, we will try _OSC firstly 389241675Suqs // and fall back to _PDC if _OSC fail 390241675Suqs status_t status = acpi_eval_osc(device); 391241675Suqs if (status != B_OK) 392241675Suqs status = acpi_eval_pdc(device); 393241675Suqs if (status != B_OK) { 394241675Suqs dprintf("failed to eval _OSC and _PDC\n"); 395241675Suqs return status; 396241675Suqs } 397241675Suqs 398241675Suqs acpi_data buffer; 399241675Suqs buffer.pointer = NULL; 400241675Suqs buffer.length = ACPI_ALLOCATE_BUFFER; 401241675Suqs 402241675Suqs dprintf("evaluate _CST @%p\n", device->acpi_cookie); 403241675Suqs status = device->acpi->evaluate_method(device->acpi_cookie, "_CST", NULL, 404241675Suqs &buffer); 405241675Suqs if (status != B_OK) { 406241675Suqs dprintf("failed to get _CST\n"); 407241675Suqs return B_IO_ERROR; 408241675Suqs } 409241675Suqs 410241675Suqs acpi_object_type *object = (acpi_object_type *)buffer.pointer; 411241675Suqs if (object->object_type != ACPI_TYPE_PACKAGE) 412241675Suqs dprintf("invalid _CST type\n"); 413241675Suqs if (object->data.package.count < 2) 414241675Suqs dprintf("invalid _CST count\n"); 415241675Suqs 416241675Suqs acpi_object_type *pointer = object->data.package.objects; 417241675Suqs if (pointer[0].object_type != ACPI_TYPE_INTEGER) 418241675Suqs dprintf("invalid _CST type 2\n"); 419241675Suqs uint32 n = pointer[0].data.integer; 420241675Suqs if (n != object->data.package.count - 1) 421241675Suqs dprintf("invalid _CST count 2\n"); 422241675Suqs if (n > 8) 423241675Suqs dprintf("_CST has too many states\n"); 424241675Suqs dprintf("cpuidle found %" B_PRId32 " cstates\n", n); 425241675Suqs uint32 count = 1; 426241675Suqs for (uint32 i = 1; i <= n; i++) { 427241675Suqs pointer = &object->data.package.objects[i]; 428241675Suqs if (acpi_cstate_add(pointer, &sAcpiDevice.cStates[count]) == B_OK) 429241675Suqs ++count; 430241675Suqs } 431241675Suqs sAcpiDevice.cStateCount = count; 432241675Suqs free(buffer.pointer); 433241675Suqs 434241675Suqs // TODO we assume BM is a must and ARB_DIS is always available 435241675Suqs device->flags |= ACPI_FLAG_C_ARB | ACPI_FLAG_C_BM; 436241675Suqs 437241675Suqs acpi_cstate_quirks(device); 438241675Suqs 439241675Suqs return B_OK; 440241675Suqs} 441241675Suqs 442241675Suqs 443241675Suqsstatic status_t 444241675Suqsacpi_cpuidle_init(void) 445241675Suqs{ 446241675Suqs dprintf("acpi_cpuidle_init\n"); 447241675Suqs 448241675Suqs for (int32 i = 0; i < smp_get_num_cpus(); i++) 449241675Suqs if (acpi_cpuidle_setup(sAcpiProcessor[i]) != B_OK) 450241675Suqs return B_ERROR; 451241675Suqs 452241675Suqs status_t status = gIdle->AddDevice(&sAcpiDevice); 453241675Suqs if (status == B_OK) 454241675Suqs dprintf("using acpi idle\n"); 455241675Suqs return status; 456241675Suqs} 457241675Suqs 458241675Suqs 459241675Suqsstatic status_t 460241675Suqsacpi_processor_init(acpi_cpuidle_driver_info *device) 461241675Suqs{ 462241675Suqs // get the CPU index 463241675Suqs dprintf("get acpi processor @%p\n", device->acpi_cookie); 464241675Suqs 465241675Suqs acpi_data buffer; 466241675Suqs buffer.pointer = NULL; 467241675Suqs buffer.length = ACPI_ALLOCATE_BUFFER; 468241675Suqs status_t status = device->acpi->evaluate_method(device->acpi_cookie, NULL, 469241675Suqs NULL, &buffer); 470241675Suqs if (status != B_OK) { 471241675Suqs dprintf("failed to get processor obj\n"); 472241675Suqs return status; 473241675Suqs } 474241675Suqs 475241675Suqs acpi_object_type *object = (acpi_object_type *)buffer.pointer; 476241675Suqs dprintf("acpi cpu%" B_PRId32 ": P_BLK at %#x/%lu\n", 477241675Suqs object->data.processor.cpu_id, 478241675Suqs object->data.processor.pblk_address, 479241675Suqs object->data.processor.pblk_length); 480241675Suqs 481241675Suqs int32 cpuIndex = object->data.processor.cpu_id; 482241675Suqs free(buffer.pointer); 483241675Suqs 484241675Suqs if (cpuIndex < 0 || cpuIndex >= smp_get_num_cpus()) 485241675Suqs return B_ERROR; 486241675Suqs 487241675Suqs device->cpuIndex = cpuIndex; 488241675Suqs sAcpiProcessor[cpuIndex] = device; 489241675Suqs 490241675Suqs // If nodes for all processors have been registered, init the idle callback. 491241675Suqs for (int32 i = smp_get_num_cpus() - 1; i >= 0; i--) { 492241675Suqs if (sAcpiProcessor[i] == NULL) 493241675Suqs return B_OK; 494241675Suqs } 495241675Suqs 496241675Suqs if (intel_cpuidle_init() == B_OK) 497241675Suqs return B_OK; 498241675Suqs 499241675Suqs status = acpi_cpuidle_init(); 500241675Suqs if (status != B_OK) 501241675Suqs sAcpiProcessor[cpuIndex] = NULL; 502241675Suqs 503241675Suqs return status; 504241675Suqs} 505241675Suqs 506241675Suqs 507241675Suqsstatic float 508241675Suqsacpi_cpuidle_support(device_node *parent) 509241675Suqs{ 510241675Suqs const char *bus; 511241675Suqs uint32 device_type; 512241675Suqs 513241675Suqs dprintf("acpi_cpuidle_support\n"); 514241675Suqs // make sure parent is really the ACPI bus manager 515241675Suqs if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 516241675Suqs return -1; 517241675Suqs 518241675Suqs if (strcmp(bus, "acpi") != 0) 519241675Suqs return 0.0; 520241675Suqs 521241675Suqs // check whether it's really a cpu Device 522241675Suqs if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, 523241675Suqs &device_type, false) != B_OK 524241675Suqs || device_type != ACPI_TYPE_PROCESSOR) { 525241675Suqs return 0.0; 526241675Suqs } 527241675Suqs 528241675Suqs return 0.6; 529241675Suqs} 530241675Suqs 531241675Suqs 532241675Suqsstatic status_t 533241675Suqsacpi_cpuidle_register_device(device_node *node) 534241675Suqs{ 535241675Suqs device_attr attrs[] = { 536241675Suqs { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI CPU IDLE" }}, 537241675Suqs { NULL } 538241675Suqs }; 539241675Suqs 540241675Suqs dprintf("acpi_cpuidle_register_device\n"); 541241675Suqs return sDeviceManager->register_node(node, ACPI_CPUIDLE_MODULE_NAME, attrs, 542241675Suqs NULL, NULL); 543241675Suqs} 544241675Suqs 545241675Suqs 546241675Suqsstatic status_t 547241675Suqsacpi_cpuidle_init_driver(device_node *node, void **driverCookie) 548241675Suqs{ 549241675Suqs dprintf("acpi_cpuidle_init_driver\n"); 550241675Suqs acpi_cpuidle_driver_info *device; 551241675Suqs device = (acpi_cpuidle_driver_info *)calloc(1, sizeof(*device)); 552241675Suqs if (device == NULL) 553241675Suqs return B_NO_MEMORY; 554241675Suqs 555241675Suqs device->node = node; 556241675Suqs 557241675Suqs device_node *parent; 558241675Suqs parent = sDeviceManager->get_parent_node(node); 559241675Suqs sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi, 560241675Suqs (void **)&device->acpi_cookie); 561241675Suqs sDeviceManager->put_node(parent); 562241675Suqs 563241675Suqs status_t status = acpi_processor_init(device); 564241675Suqs if (status != B_OK) { 565241675Suqs free(device); 566241675Suqs return status; 567241675Suqs } 568241675Suqs 569241675Suqs *driverCookie = device; 570241675Suqs return B_OK; 571241675Suqs} 572241675Suqs 573241675Suqs 574241675Suqsstatic void 575241675Suqsacpi_cpuidle_uninit_driver(void *driverCookie) 576241675Suqs{ 577241675Suqs dprintf("acpi_cpuidle_uninit_driver"); 578241675Suqs acpi_cpuidle_driver_info *device = (acpi_cpuidle_driver_info *)driverCookie; 579241675Suqs // TODO: When the first device to be unregistered, we'd need to balance the 580241675Suqs // gIdle->AddDevice() call, but ATM isn't any API for that. 581241675Suqs sAcpiProcessor[device->cpuIndex] = NULL; 582241675Suqs free(device); 583241675Suqs} 584241675Suqs 585241675Suqs 586241675Suqsmodule_dependency module_dependencies[] = { 587241675Suqs { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, 588241675Suqs { B_ACPI_MODULE_NAME, (module_info **)&sAcpi}, 589241675Suqs { B_CPUIDLE_MODULE_NAME, (module_info **)&gIdle }, 590241675Suqs {} 591241675Suqs}; 592241675Suqs 593241675Suqs 594241675Suqsstatic driver_module_info sAcpiidleModule = { 595241675Suqs { 596241675Suqs ACPI_CPUIDLE_MODULE_NAME, 597241675Suqs 0, 598241675Suqs NULL 599241675Suqs }, 600241675Suqs 601241675Suqs acpi_cpuidle_support, 602241675Suqs acpi_cpuidle_register_device, 603241675Suqs acpi_cpuidle_init_driver, 604241675Suqs acpi_cpuidle_uninit_driver, 605241675Suqs NULL, 606241675Suqs NULL, // rescan 607241675Suqs NULL, // removed 608241675Suqs}; 609241675Suqs 610241675Suqs 611241675Suqsmodule_info *modules[] = { 612241675Suqs (module_info *)&sAcpiidleModule, 613241675Suqs NULL 614241675Suqs}; 615241675Suqs