Merge branch 'master' into x86_64
Conflicts: build/jam/HaikuImage src/add-ons/kernel/generic/Jamfile
This commit is contained in:
@@ -248,7 +248,7 @@ AddFilesToHaikuImage system add-ons kernel file_systems
|
|||||||
: $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ;
|
: $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ;
|
||||||
AddFilesToHaikuImage system add-ons kernel generic
|
AddFilesToHaikuImage system add-ons kernel generic
|
||||||
: $(ATA_ONLY)ata_adapter $(X86_ONLY)bios dpc $(IDE_ONLY)ide_adapter
|
: $(ATA_ONLY)ata_adapter $(X86_ONLY)bios dpc $(IDE_ONLY)ide_adapter
|
||||||
locked_pool mpu401 scsi_periph <module>tty ;
|
locked_pool mpu401 scsi_periph <module>tty ; #$(X86_ONLY)cpuidle ;
|
||||||
AddFilesToHaikuImage system add-ons kernel partitioning_systems
|
AddFilesToHaikuImage system add-ons kernel partitioning_systems
|
||||||
: amiga_rdb apple efi_gpt intel session ;
|
: amiga_rdb apple efi_gpt intel session ;
|
||||||
AddFilesToHaikuImage system add-ons kernel interrupt_controllers
|
AddFilesToHaikuImage system add-ons kernel interrupt_controllers
|
||||||
@@ -262,6 +262,7 @@ if $(TARGET_ARCH) = x86 {
|
|||||||
AddNewDriversToHaikuImage disk scsi : scsi_cd scsi_disk ;
|
AddNewDriversToHaikuImage disk scsi : scsi_cd scsi_disk ;
|
||||||
AddNewDriversToHaikuImage power : $(X86_ONLY)enhanced_speedstep ;
|
AddNewDriversToHaikuImage power : $(X86_ONLY)enhanced_speedstep ;
|
||||||
AddNewDriversToHaikuImage power : $(X86_ONLY)acpi_battery ;
|
AddNewDriversToHaikuImage power : $(X86_ONLY)acpi_battery ;
|
||||||
|
#AddNewDriversToHaikuImage power : $(X86_ONLY)x86_cpuidle ;
|
||||||
|
|
||||||
# legacy drivers
|
# legacy drivers
|
||||||
AddDriversToHaikuImage : console dprintf null
|
AddDriversToHaikuImage : console dprintf null
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ typedef struct acpi_data {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
ACPI_ALLOCATE_BUFFER = -1,
|
ACPI_ALLOCATE_BUFFER = -1,
|
||||||
|
ACPI_ALLOCATE_LOCAL_BUFFER = -2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -261,6 +262,10 @@ struct acpi_module_info {
|
|||||||
/* Table Access */
|
/* Table Access */
|
||||||
status_t (*get_table)(const char *signature, uint32 instance,
|
status_t (*get_table)(const char *signature, uint32 instance,
|
||||||
void **tableHeader);
|
void **tableHeader);
|
||||||
|
|
||||||
|
/* Register Access */
|
||||||
|
status_t (*read_bit_register)(uint32 regid, uint32 *val);
|
||||||
|
status_t (*write_bit_register)(uint32 regid, uint32 val);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _CPUIDLE_MODULE_H
|
||||||
|
#define _CPUIDLE_MODULE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <module.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CPUIDLE_CSTATE_MAX 8
|
||||||
|
#define CSTATE_NAME_LENGTH 32
|
||||||
|
#define B_CPUIDLE_MODULE_NAME "generic/cpuidle/v1"
|
||||||
|
|
||||||
|
|
||||||
|
struct CpuidleStat {
|
||||||
|
uint64 usageCount;
|
||||||
|
bigtime_t usageTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct CpuidleInfo {
|
||||||
|
int32 cstateSleep;
|
||||||
|
CpuidleStat stats[CPUIDLE_CSTATE_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CpuidleDevice;
|
||||||
|
|
||||||
|
struct CpuidleCstate {
|
||||||
|
char name[CSTATE_NAME_LENGTH];
|
||||||
|
int32 latency;
|
||||||
|
int32 (*EnterIdle)(int32 state, CpuidleDevice *device);
|
||||||
|
void *pData;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct CpuidleDevice {
|
||||||
|
CpuidleCstate cStates[CPUIDLE_CSTATE_MAX];
|
||||||
|
int32 cStateCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct CpuidleModuleInfo {
|
||||||
|
module_info info;
|
||||||
|
status_t (*AddDevice)(CpuidleDevice *device);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _CPUIDLE_MODULE_H
|
||||||
@@ -715,6 +715,20 @@ get_table(const char* signature, uint32 instance, void** tableHeader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
read_bit_register(uint32 regid, uint32 *val)
|
||||||
|
{
|
||||||
|
return AcpiReadBitRegister(regid, (UINT32 *)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
write_bit_register(uint32 regid, uint32 val)
|
||||||
|
{
|
||||||
|
return AcpiWriteBitRegister(regid, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct acpi_module_info gACPIModule = {
|
struct acpi_module_info gACPIModule = {
|
||||||
{
|
{
|
||||||
B_ACPI_MODULE_NAME,
|
B_ACPI_MODULE_NAME,
|
||||||
@@ -759,5 +773,7 @@ struct acpi_module_info gACPIModule = {
|
|||||||
prepare_sleep_state,
|
prepare_sleep_state,
|
||||||
enter_sleep_state,
|
enter_sleep_state,
|
||||||
reboot,
|
reboot,
|
||||||
get_table
|
get_table,
|
||||||
|
read_bit_register,
|
||||||
|
write_bit_register
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_button ;
|
|||||||
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_lid ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_lid ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_thermal ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_thermal ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel drivers power enhanced_speedstep ;
|
SubInclude HAIKU_TOP src add-ons kernel drivers power enhanced_speedstep ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel drivers power x86_cpuidle ;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel drivers power x86_cpuidle ;
|
||||||
|
|
||||||
|
UsePrivateKernelHeaders ;
|
||||||
|
|
||||||
|
KernelAddon x86_cpuidle :
|
||||||
|
acpi_cpuidle.cpp
|
||||||
|
intel_cpuidle.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
Depends x86_cpuidle : acpi ;
|
||||||
@@ -0,0 +1,583 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Haiku, Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Yongcong Du <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <Drivers.h>
|
||||||
|
#include <Errors.h>
|
||||||
|
#include <smp.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <arch_system_info.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <ACPI.h>
|
||||||
|
#include <cpuidle.h>
|
||||||
|
|
||||||
|
#include "x86_cpuidle.h"
|
||||||
|
|
||||||
|
#define ACPI_PDC_REVID 0x1
|
||||||
|
#define ACPI_OSC_QUERY (1 << 0)
|
||||||
|
|
||||||
|
#define ACPI_PDC_P_FFH (1 << 0)
|
||||||
|
#define ACPI_PDC_C_C1_HALT (1 << 1)
|
||||||
|
#define ACPI_PDC_T_FFH (1 << 2)
|
||||||
|
#define ACPI_PDC_SMP_C1PT (1 << 3)
|
||||||
|
#define ACPI_PDC_SMP_C2C3 (1 << 4)
|
||||||
|
#define ACPI_PDC_SMP_P_SW (1 << 5)
|
||||||
|
#define ACPI_PDC_SMP_C_SW (1 << 6)
|
||||||
|
#define ACPI_PDC_SMP_T_SW (1 << 7)
|
||||||
|
#define ACPI_PDC_C_C1_FFH (1 << 8)
|
||||||
|
#define ACPI_PDC_C_C2C3_FFH (1 << 9)
|
||||||
|
#define ACPI_PDC_P_HWCOORD (1 << 11)
|
||||||
|
|
||||||
|
// Bus Master check required
|
||||||
|
#define ACPI_PDC_GAS_BM (1 << 1)
|
||||||
|
|
||||||
|
#define ACPI_CSTATE_HALT 0x1
|
||||||
|
#define ACPI_CSTATE_SYSIO 0x2
|
||||||
|
#define ACPI_CSTATE_FFH 0x3
|
||||||
|
|
||||||
|
// Bus Master Check
|
||||||
|
#define ACPI_FLAG_C_BM (1 << 0)
|
||||||
|
// Bus master arbitration
|
||||||
|
#define ACPI_FLAG_C_ARB (1 << 1)
|
||||||
|
|
||||||
|
// Copied from acpica's actypes.h, where's the best place to put?
|
||||||
|
#define ACPI_BITREG_BUS_MASTER_STATUS 0x01
|
||||||
|
#define ACPI_BITREG_BUS_MASTER_RLD 0x0F
|
||||||
|
#define ACPI_BITREG_ARB_DISABLE 0x13
|
||||||
|
|
||||||
|
#define ACPI_STATE_C0 (uint8) 0
|
||||||
|
#define ACPI_STATE_C1 (uint8) 1
|
||||||
|
#define ACPI_STATE_C2 (uint8) 2
|
||||||
|
#define ACPI_STATE_C3 (uint8) 3
|
||||||
|
#define ACPI_C_STATES_MAX ACPI_STATE_C3
|
||||||
|
#define ACPI_C_STATE_COUNT 4
|
||||||
|
|
||||||
|
|
||||||
|
#define ACPI_CPUIDLE_MODULE_NAME "drivers/power/x86_cpuidle/acpi/driver_v1"
|
||||||
|
|
||||||
|
struct acpicpu_reg {
|
||||||
|
uint8 reg_desc;
|
||||||
|
uint16 reg_reslen;
|
||||||
|
uint8 reg_spaceid;
|
||||||
|
uint8 reg_bitwidth;
|
||||||
|
uint8 reg_bitoffset;
|
||||||
|
uint8 reg_accesssize;
|
||||||
|
uint64 reg_addr;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct acpi_cpuidle_driver_info {
|
||||||
|
device_node *node;
|
||||||
|
acpi_device_module_info *acpi;
|
||||||
|
acpi_device acpi_cookie;
|
||||||
|
uint32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct acpi_cstate_info {
|
||||||
|
uint32 address;
|
||||||
|
uint8 skip_bm_sts;
|
||||||
|
uint8 method;
|
||||||
|
uint8 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static acpi_cpuidle_driver_info *acpi_processor[B_MAX_CPU_COUNT];
|
||||||
|
static CpuidleDevice sAcpiDevice;
|
||||||
|
static device_manager_info *sDeviceManager;
|
||||||
|
static acpi_module_info *sAcpi;
|
||||||
|
CpuidleModuleInfo *gIdle;
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_eval_pdc(acpi_cpuidle_driver_info *device)
|
||||||
|
{
|
||||||
|
acpi_objects arg;
|
||||||
|
acpi_object_type obj;
|
||||||
|
uint32 cap[3];
|
||||||
|
|
||||||
|
arg.count = 1;
|
||||||
|
arg.pointer = &obj;
|
||||||
|
cap[0] = 1;
|
||||||
|
cap[1] = 1;
|
||||||
|
cap[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_SMP_C1PT | ACPI_PDC_SMP_C2C3;
|
||||||
|
cap[2] |= ACPI_PDC_SMP_P_SW | ACPI_PDC_SMP_C_SW | ACPI_PDC_SMP_T_SW;
|
||||||
|
cap[2] |= ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH;
|
||||||
|
cap[2] |= ACPI_PDC_SMP_T_SW | ACPI_PDC_P_FFH | ACPI_PDC_P_HWCOORD | ACPI_PDC_T_FFH;
|
||||||
|
obj.object_type = ACPI_TYPE_BUFFER;
|
||||||
|
obj.data.buffer.length = sizeof(cap);
|
||||||
|
obj.data.buffer.buffer = cap;
|
||||||
|
status_t status = device->acpi->evaluate_method(device->acpi_cookie, "_PDC", &arg, NULL);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_eval_osc(acpi_cpuidle_driver_info *device)
|
||||||
|
{
|
||||||
|
// guid for intel platform
|
||||||
|
dprintf("%s@%p\n", __func__, device->acpi_cookie);
|
||||||
|
static uint8 uuid[] = {
|
||||||
|
0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47,
|
||||||
|
0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53
|
||||||
|
};
|
||||||
|
uint32 cap[2];
|
||||||
|
cap[0] = 0;
|
||||||
|
cap[1] = ACPI_PDC_C_C1_HALT | ACPI_PDC_SMP_C1PT | ACPI_PDC_SMP_C2C3;
|
||||||
|
cap[1] |= ACPI_PDC_SMP_P_SW | ACPI_PDC_SMP_C_SW | ACPI_PDC_SMP_T_SW;
|
||||||
|
cap[1] |= ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH;
|
||||||
|
cap[1] |= ACPI_PDC_SMP_T_SW | ACPI_PDC_P_FFH | ACPI_PDC_P_HWCOORD | ACPI_PDC_T_FFH;
|
||||||
|
|
||||||
|
acpi_objects arg;
|
||||||
|
acpi_object_type obj[4];
|
||||||
|
|
||||||
|
arg.count = 4;
|
||||||
|
arg.pointer = obj;
|
||||||
|
|
||||||
|
obj[0].object_type = ACPI_TYPE_BUFFER;
|
||||||
|
obj[0].data.buffer.length = sizeof(uuid);
|
||||||
|
obj[0].data.buffer.buffer = uuid;
|
||||||
|
obj[1].object_type = ACPI_TYPE_INTEGER;
|
||||||
|
obj[1].data.integer = ACPI_PDC_REVID;
|
||||||
|
obj[2].object_type = ACPI_TYPE_INTEGER;
|
||||||
|
obj[2].data.integer = sizeof(cap)/sizeof(cap[0]);
|
||||||
|
obj[3].object_type = ACPI_TYPE_BUFFER;
|
||||||
|
obj[3].data.buffer.length = sizeof(cap);
|
||||||
|
obj[3].data.buffer.buffer = (void *)cap;
|
||||||
|
|
||||||
|
acpi_data buf;
|
||||||
|
buf.pointer = NULL;
|
||||||
|
buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
|
||||||
|
status_t status = device->acpi->evaluate_method(device->acpi_cookie, "_OSC", &arg, &buf);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
acpi_object_type *osc = (acpi_object_type *)buf.pointer;
|
||||||
|
if (osc->object_type != ACPI_TYPE_BUFFER)
|
||||||
|
return B_BAD_TYPE;
|
||||||
|
if (osc->data.buffer.length != sizeof(cap))
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
acpi_cstate_bm_check(void)
|
||||||
|
{
|
||||||
|
uint32 val;
|
||||||
|
sAcpi->read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &val);
|
||||||
|
if (!val)
|
||||||
|
return false;
|
||||||
|
sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
acpi_cstate_ffh_enter(CpuidleCstate *cState)
|
||||||
|
{
|
||||||
|
cpu_ent *cpu = get_cpu_struct();
|
||||||
|
if (cpu->invoke_scheduler)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x86_monitor((void *)&cpu->invoke_scheduler, 0, 0);
|
||||||
|
if (!cpu->invoke_scheduler)
|
||||||
|
x86_mwait((unsigned long)cState->pData, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
acpi_cstate_halt(void)
|
||||||
|
{
|
||||||
|
cpu_ent *cpu = get_cpu_struct();
|
||||||
|
if (cpu->invoke_scheduler)
|
||||||
|
return;
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
acpi_cstate_enter(CpuidleCstate *cState)
|
||||||
|
{
|
||||||
|
acpi_cstate_info *ci = (acpi_cstate_info *)cState->pData;
|
||||||
|
if (ci->method == ACPI_CSTATE_FFH)
|
||||||
|
acpi_cstate_ffh_enter(cState);
|
||||||
|
else if (ci->method == ACPI_CSTATE_SYSIO)
|
||||||
|
in8(ci->address);
|
||||||
|
else
|
||||||
|
acpi_cstate_halt();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int32
|
||||||
|
acpi_cstate_idle(int32 state, CpuidleDevice *device)
|
||||||
|
{
|
||||||
|
CpuidleCstate *cState = &device->cStates[state];
|
||||||
|
acpi_cstate_info *ci = (acpi_cstate_info *)cState->pData;
|
||||||
|
if (!ci->skip_bm_sts) {
|
||||||
|
// we fall back to C1 if there's bus master activity
|
||||||
|
if (acpi_cstate_bm_check())
|
||||||
|
state = 1;
|
||||||
|
}
|
||||||
|
if (ci->type != ACPI_STATE_C3)
|
||||||
|
acpi_cstate_enter(cState);
|
||||||
|
|
||||||
|
// set BM_RLD for Bus Master to activity to wake the system from C3
|
||||||
|
// With Newer chipsets BM_RLD is a NOP Since DMA is automatically handled
|
||||||
|
// during C3 State
|
||||||
|
acpi_cpuidle_driver_info *pi = acpi_processor[smp_get_current_cpu()];
|
||||||
|
if (pi->flags & ACPI_FLAG_C_BM)
|
||||||
|
sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
|
||||||
|
|
||||||
|
// disable bus master arbitration during C3
|
||||||
|
if (pi->flags & ACPI_FLAG_C_ARB)
|
||||||
|
sAcpi->write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
|
||||||
|
|
||||||
|
acpi_cstate_enter(cState);
|
||||||
|
|
||||||
|
// clear BM_RLD and re-enable the arbiter
|
||||||
|
if (pi->flags & ACPI_FLAG_C_BM)
|
||||||
|
sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
|
||||||
|
|
||||||
|
if (pi->flags & ACPI_FLAG_C_ARB)
|
||||||
|
sAcpi->write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_cstate_add(acpi_object_type *object, CpuidleCstate *cState)
|
||||||
|
{
|
||||||
|
acpi_cstate_info *ci = (acpi_cstate_info *)malloc(sizeof(acpi_cstate_info));
|
||||||
|
if (!ci)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (object->object_type != ACPI_TYPE_PACKAGE) {
|
||||||
|
dprintf("invalid _CST object\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object->data.package.count != 4) {
|
||||||
|
dprintf("invalid _CST number\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// type
|
||||||
|
acpi_object_type * pointer = &object->data.package.objects[1];
|
||||||
|
if (pointer->object_type != ACPI_TYPE_INTEGER) {
|
||||||
|
dprintf("invalid _CST elem type\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
uint32 n = pointer->data.integer;
|
||||||
|
if (n < 1 || n > 3) {
|
||||||
|
dprintf("invalid _CST elem value\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
ci->type = n;
|
||||||
|
dprintf("C%" B_PRId32 "\n", n);
|
||||||
|
snprintf(cState->name, sizeof(cState->name), "C%"B_PRId32, n);
|
||||||
|
|
||||||
|
// Latency
|
||||||
|
pointer = &object->data.package.objects[2];
|
||||||
|
if (pointer->object_type != ACPI_TYPE_INTEGER) {
|
||||||
|
dprintf("invalid _CST elem type\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
n = pointer->data.integer;
|
||||||
|
cState->latency = n;
|
||||||
|
dprintf("Latency: %" B_PRId32 "\n", n);
|
||||||
|
|
||||||
|
// power
|
||||||
|
pointer = &object->data.package.objects[3];
|
||||||
|
if (pointer->object_type != ACPI_TYPE_INTEGER) {
|
||||||
|
dprintf("invalid _CST elem type\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
n = pointer->data.integer;
|
||||||
|
dprintf("power: %" B_PRId32 "\n", n);
|
||||||
|
|
||||||
|
// register
|
||||||
|
pointer = &object->data.package.objects[0];
|
||||||
|
if (pointer->object_type != ACPI_TYPE_BUFFER) {
|
||||||
|
dprintf("invalid _CST elem type\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
if (pointer->data.buffer.length < 15) {
|
||||||
|
dprintf("invalid _CST elem length\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct acpicpu_reg *reg = (struct acpicpu_reg *)pointer->data.buffer.buffer;
|
||||||
|
switch (reg->reg_spaceid) {
|
||||||
|
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||||
|
dprintf("IO method\n");
|
||||||
|
if (reg->reg_addr == 0) {
|
||||||
|
dprintf("illegal address\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
if (reg->reg_bitwidth != 8) {
|
||||||
|
dprintf("invalid source length\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
ci->address = reg->reg_addr;
|
||||||
|
ci->method = ACPI_CSTATE_SYSIO;
|
||||||
|
break;
|
||||||
|
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||||
|
{
|
||||||
|
dprintf("FFH method\n");
|
||||||
|
ci->method = ACPI_CSTATE_FFH;
|
||||||
|
ci->address = reg->reg_addr;
|
||||||
|
|
||||||
|
// skip checking BM_STS if ACPI_PDC_GAS_BM is cleared
|
||||||
|
cpu_ent *cpu = get_cpu_struct();
|
||||||
|
if ((cpu->arch.vendor == VENDOR_INTEL) &&
|
||||||
|
!(reg->reg_accesssize & ACPI_PDC_GAS_BM))
|
||||||
|
ci->skip_bm_sts = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dprintf("invalid spaceid %" B_PRId8 "\n", reg->reg_spaceid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cState->pData = ci;
|
||||||
|
cState->EnterIdle = acpi_cstate_idle;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
acpi_cstate_quirks(acpi_cpuidle_driver_info *device)
|
||||||
|
{
|
||||||
|
cpu_ent *cpu = get_cpu_struct();
|
||||||
|
// Calculated Model Value: M = (Extended Model << 4) + Model
|
||||||
|
uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model;
|
||||||
|
|
||||||
|
// On all recent Intel platforms, ARB_DIS is not necessary
|
||||||
|
if (cpu->arch.vendor != VENDOR_INTEL)
|
||||||
|
return;
|
||||||
|
if (cpu->arch.family > 0xf || (cpu->arch.family == 6 && model >= 0xf))
|
||||||
|
device->flags &= ~ACPI_FLAG_C_ARB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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("faile 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 status_t
|
||||||
|
acpi_cpuidle_init(void)
|
||||||
|
{
|
||||||
|
dprintf("acpi_cpuidle_init\n");
|
||||||
|
|
||||||
|
for (int32 i = 0; i < smp_get_num_cpus(); i++)
|
||||||
|
if (acpi_cpuidle_setup(acpi_processor[i]) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
status_t status = gIdle->AddDevice(&sAcpiDevice);
|
||||||
|
if (status == B_OK)
|
||||||
|
dprintf("using acpi idle\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_processor_init(acpi_cpuidle_driver_info *device)
|
||||||
|
{
|
||||||
|
status_t status = B_ERROR;
|
||||||
|
|
||||||
|
acpi_data buffer;
|
||||||
|
buffer.pointer = NULL;
|
||||||
|
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||||
|
dprintf("get acpi processor @%p\n", device->acpi_cookie);
|
||||||
|
status = device->acpi->evaluate_method(device->acpi_cookie, NULL, NULL,
|
||||||
|
&buffer);
|
||||||
|
if (status != B_OK) {
|
||||||
|
dprintf("failed to get processor obj\n");
|
||||||
|
return B_IO_ERROR;
|
||||||
|
}
|
||||||
|
acpi_object_type *object = (acpi_object_type *)buffer.pointer;
|
||||||
|
dprintf("acpi cpu%"B_PRId32": P_BLK at %#x/%lu\n",
|
||||||
|
object->data.processor.cpu_id,
|
||||||
|
object->data.processor.pblk_address,
|
||||||
|
object->data.processor.pblk_length);
|
||||||
|
int32 cpuid = object->data.processor.cpu_id;
|
||||||
|
free(buffer.pointer);
|
||||||
|
if (cpuid > smp_get_num_cpus())
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (smp_get_num_cpus() == 1)
|
||||||
|
cpuid = 1;
|
||||||
|
|
||||||
|
acpi_processor[cpuid-1] = device;
|
||||||
|
|
||||||
|
if (cpuid == 1) {
|
||||||
|
if (intel_cpuidle_init() != B_OK)
|
||||||
|
return acpi_cpuidle_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float
|
||||||
|
acpi_cpuidle_support(device_node *parent)
|
||||||
|
{
|
||||||
|
const char *bus;
|
||||||
|
uint32 device_type;
|
||||||
|
|
||||||
|
dprintf("acpi_cpuidle_support\n");
|
||||||
|
// make sure parent is really the ACPI bus manager
|
||||||
|
if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strcmp(bus, "acpi"))
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
// check whether it's really a cpu Device
|
||||||
|
if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK
|
||||||
|
|| device_type != ACPI_TYPE_PROCESSOR) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_cpuidle_register_device(device_node *node)
|
||||||
|
{
|
||||||
|
device_attr attrs[] = {
|
||||||
|
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI CPU IDLE" }},
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
dprintf("acpi_cpuidle_register_device\n");
|
||||||
|
return sDeviceManager->register_node(node, ACPI_CPUIDLE_MODULE_NAME, attrs,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
acpi_cpuidle_init_driver(device_node *node, void **driverCookie)
|
||||||
|
{
|
||||||
|
dprintf("acpi_cpuidle_init_driver\n");
|
||||||
|
acpi_cpuidle_driver_info *device;
|
||||||
|
device = (acpi_cpuidle_driver_info *)calloc(1, sizeof(*device));
|
||||||
|
if (device == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
*driverCookie = device;
|
||||||
|
|
||||||
|
device->node = node;
|
||||||
|
|
||||||
|
device_node *parent;
|
||||||
|
parent = sDeviceManager->get_parent_node(node);
|
||||||
|
sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
|
||||||
|
(void **)&device->acpi_cookie);
|
||||||
|
sDeviceManager->put_node(parent);
|
||||||
|
|
||||||
|
return acpi_processor_init(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
acpi_cpuidle_uninit_driver(void *driverCookie)
|
||||||
|
{
|
||||||
|
dprintf("acpi_cpuidle_uninit_driver");
|
||||||
|
acpi_cpuidle_driver_info *device = (acpi_cpuidle_driver_info *)driverCookie;
|
||||||
|
free(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module_dependency module_dependencies[] = {
|
||||||
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
|
||||||
|
{ B_ACPI_MODULE_NAME, (module_info **)&sAcpi},
|
||||||
|
{ B_CPUIDLE_MODULE_NAME, (module_info **)&gIdle },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static driver_module_info sAcpiidleModule = {
|
||||||
|
{
|
||||||
|
ACPI_CPUIDLE_MODULE_NAME,
|
||||||
|
0,
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
|
||||||
|
acpi_cpuidle_support,
|
||||||
|
acpi_cpuidle_register_device,
|
||||||
|
acpi_cpuidle_init_driver,
|
||||||
|
acpi_cpuidle_uninit_driver,
|
||||||
|
NULL,
|
||||||
|
NULL, // rescan
|
||||||
|
NULL, // removed
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module_info *modules[] = {
|
||||||
|
(module_info *)&sAcpiidleModule,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Yongcong Du <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <arch_system_info.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <cpuidle.h>
|
||||||
|
|
||||||
|
#include "x86_cpuidle.h"
|
||||||
|
|
||||||
|
static CpuidleDevice sIntelDevice;
|
||||||
|
|
||||||
|
static void *kMwaitEax[] = {
|
||||||
|
// C0, we never use it
|
||||||
|
(void *)0x00,
|
||||||
|
// MWAIT C1
|
||||||
|
(void *)0x00,
|
||||||
|
// MWAIT C2
|
||||||
|
(void *)0x10,
|
||||||
|
// MWAIT C3
|
||||||
|
(void *)0x20,
|
||||||
|
// MWAIT C4
|
||||||
|
(void *)0x30,
|
||||||
|
// MWAIT C5
|
||||||
|
(void *)0x40,
|
||||||
|
// MWAIT C6, 0x2 is used to fully shrink L2 cache
|
||||||
|
(void *)0x52
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int32
|
||||||
|
IntelCstateIdleEnter(int32 state, CpuidleDevice *device)
|
||||||
|
{
|
||||||
|
cpu_ent *cpu = get_cpu_struct();
|
||||||
|
if (cpu->invoke_scheduler)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
CpuidleCstate *cState = &device->cStates[state];
|
||||||
|
x86_monitor((void *)&cpu->invoke_scheduler, 0, 0);
|
||||||
|
if (!cpu->invoke_scheduler)
|
||||||
|
x86_mwait((unsigned long)cState->pData, 1);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static CpuidleCstate sSnbcStates[CPUIDLE_CSTATE_MAX] = {
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
"C1-SNB",
|
||||||
|
1,
|
||||||
|
IntelCstateIdleEnter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"C3-SNB",
|
||||||
|
80,
|
||||||
|
IntelCstateIdleEnter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"C6-SNB",
|
||||||
|
104,
|
||||||
|
IntelCstateIdleEnter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"C7-SNB",
|
||||||
|
109,
|
||||||
|
IntelCstateIdleEnter,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
intel_cpuidle_init(void)
|
||||||
|
{
|
||||||
|
dprintf("intel idle init\n");
|
||||||
|
cpu_ent *cpu = get_cpu_struct();
|
||||||
|
if (cpu->arch.vendor != VENDOR_INTEL || cpu->arch.family != 6)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
// Calculated Model Value: M = (Extended Model << 4) + Model
|
||||||
|
uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model;
|
||||||
|
if (model != 0x2a && model != 0x2d)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
cpuid_info cpuid;
|
||||||
|
get_current_cpuid(&cpuid, 5);
|
||||||
|
/* ecx[0] monitor/mwait extension supported
|
||||||
|
* ecx[1] support for treating interrupts as break-events for mwait
|
||||||
|
* edx number of sub-states
|
||||||
|
*/
|
||||||
|
if ((cpuid.regs.ecx & 0x1) == 0 ||
|
||||||
|
(cpuid.regs.ecx & 0x2) == 0 ||
|
||||||
|
cpuid.regs.edx == 0) {
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sIntelDevice.cStateCount = 1;
|
||||||
|
for (int32 i = 1; i < CPUIDLE_CSTATE_MAX; i++) {
|
||||||
|
int32 subStates = (cpuid.regs.edx >> ((i) * 4)) & 0xf;
|
||||||
|
// no sub-states means the state is not available
|
||||||
|
if (!subStates)
|
||||||
|
continue;
|
||||||
|
sIntelDevice.cStates[sIntelDevice.cStateCount] =
|
||||||
|
sSnbcStates[i];
|
||||||
|
sIntelDevice.cStates[sIntelDevice.cStateCount].pData =
|
||||||
|
kMwaitEax[i];
|
||||||
|
sIntelDevice.cStateCount++;
|
||||||
|
}
|
||||||
|
status_t status = gIdle->AddDevice(&sIntelDevice);
|
||||||
|
if (status == B_OK)
|
||||||
|
dprintf("using intel idle\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern CpuidleModuleInfo *gIdle;
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
x86_monitor(const void *addr, unsigned long ecx, unsigned long edx)
|
||||||
|
{
|
||||||
|
asm volatile("monitor"
|
||||||
|
:: "a" (addr), "c" (ecx), "d"(edx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
x86_mwait(unsigned long eax, unsigned long ecx)
|
||||||
|
{
|
||||||
|
asm volatile("mwait"
|
||||||
|
:: "a" (eax), "c" (ecx));
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t intel_cpuidle_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel generic ;
|
|||||||
SubInclude HAIKU_TOP src add-ons kernel generic ata_adapter ;
|
SubInclude HAIKU_TOP src add-ons kernel generic ata_adapter ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic atomizer ;
|
SubInclude HAIKU_TOP src add-ons kernel generic atomizer ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic bios ;
|
SubInclude HAIKU_TOP src add-ons kernel generic bios ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel generic cpuidle ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic dpc ;
|
SubInclude HAIKU_TOP src add-ons kernel generic dpc ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
|
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel generic cpuidle ;
|
||||||
|
|
||||||
|
UsePrivateKernelHeaders ;
|
||||||
|
|
||||||
|
KernelAddon cpuidle :
|
||||||
|
cpuidle.cpp
|
||||||
|
;
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Yongcong Du <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <smp.h>
|
||||||
|
#include <cpuidle.h>
|
||||||
|
|
||||||
|
|
||||||
|
static CpuidleInfo sPerCPU[B_MAX_CPU_COUNT];
|
||||||
|
static CpuidleDevice *sDevice;
|
||||||
|
extern void (*gCpuIdleFunc)(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* next cstate selection algorithm is based on NetBSD's
|
||||||
|
* it's simple, stupid
|
||||||
|
*/
|
||||||
|
static int32
|
||||||
|
SelectCstate(CpuidleInfo *info)
|
||||||
|
{
|
||||||
|
static const int32 csFactor = 3;
|
||||||
|
|
||||||
|
for (int32 i = sDevice->cStateCount - 1; i > 0; i--) {
|
||||||
|
CpuidleCstate *cState = &sDevice->cStates[i];
|
||||||
|
if (info->cstateSleep > cState->latency * csFactor)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choose C1 if there's no state found */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
EnterCstate(int32 state, CpuidleInfo *info)
|
||||||
|
{
|
||||||
|
CpuidleCstate *cstate = &sDevice->cStates[state];
|
||||||
|
bigtime_t now = system_time();
|
||||||
|
int32 finalState = cstate->EnterIdle(state, sDevice);
|
||||||
|
if (finalState > 0) {
|
||||||
|
bigtime_t diff = system_time() - now;
|
||||||
|
info->cstateSleep = diff;
|
||||||
|
info->stats[finalState].usageCount++;
|
||||||
|
info->stats[finalState].usageTime += diff;
|
||||||
|
} else {
|
||||||
|
info->cstateSleep = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
CpuCstateIdle(void)
|
||||||
|
{
|
||||||
|
CpuidleInfo *info = &sPerCPU[smp_get_current_cpu()];
|
||||||
|
int32 state = SelectCstate(info);
|
||||||
|
EnterCstate(state, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
std_ops(int32 op, ...)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case B_MODULE_INIT:
|
||||||
|
return B_OK;
|
||||||
|
case B_MODULE_UNINIT:
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t AddDevice(CpuidleDevice *device)
|
||||||
|
{
|
||||||
|
sDevice = device;
|
||||||
|
memory_write_barrier();
|
||||||
|
gCpuIdleFunc = CpuCstateIdle;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static CpuidleModuleInfo sCpuidleModule = {
|
||||||
|
{
|
||||||
|
B_CPUIDLE_MODULE_NAME,
|
||||||
|
0,
|
||||||
|
std_ops
|
||||||
|
},
|
||||||
|
|
||||||
|
AddDevice,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module_info *modules[] = {
|
||||||
|
(module_info *)&sCpuidleModule,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
@@ -55,7 +55,8 @@ enum {
|
|||||||
MSG_INSPECT_ADDRESS = 'isad',
|
MSG_INSPECT_ADDRESS = 'isad',
|
||||||
MSG_SHOW_TYPECAST_NODE_PROMPT = 'stnp',
|
MSG_SHOW_TYPECAST_NODE_PROMPT = 'stnp',
|
||||||
MSG_TYPECAST_NODE = 'tyno',
|
MSG_TYPECAST_NODE = 'tyno',
|
||||||
MSG_SHOW_WATCH_VARIABLE_PROMPT = 'swvp'
|
MSG_SHOW_WATCH_VARIABLE_PROMPT = 'swvp',
|
||||||
|
MSG_GENERATE_DEBUG_REPORT = 'gdrp'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,11 @@
|
|||||||
#include "UiUtils.h"
|
#include "UiUtils.h"
|
||||||
|
|
||||||
|
|
||||||
DebugReportGenerator::DebugReportGenerator(::Team* team,
|
DebugReportGenerator::DebugReportGenerator(::Team* team)
|
||||||
Architecture* architecture)
|
|
||||||
:
|
:
|
||||||
BReferenceable(),
|
BReferenceable(),
|
||||||
fTeam(team),
|
fTeam(team),
|
||||||
fArchitecture(architecture)
|
fArchitecture(team->GetArchitecture())
|
||||||
{
|
{
|
||||||
fArchitecture->AcquireReference();
|
fArchitecture->AcquireReference();
|
||||||
}
|
}
|
||||||
@@ -38,19 +37,21 @@ DebugReportGenerator::~DebugReportGenerator()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
status_t
|
||||||
DebugReportGenerator::Init()
|
DebugReportGenerator::Init()
|
||||||
{
|
{
|
||||||
|
// TODO: anything needed here?
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DebugReportGenerator*
|
DebugReportGenerator*
|
||||||
DebugReportGenerator::Create(::Team* team, Architecture* architecture)
|
DebugReportGenerator::Create(::Team* team)
|
||||||
{
|
{
|
||||||
DebugReportGenerator* self = new DebugReportGenerator(team, architecture);
|
DebugReportGenerator* self = new DebugReportGenerator(team);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self->_Init();
|
self->Init();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
delete self;
|
delete self;
|
||||||
throw;
|
throw;
|
||||||
@@ -89,16 +90,15 @@ DebugReportGenerator::GenerateReport(const entry_ref& outputPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
DebugReportGenerator::_Init()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DebugReportGenerator::_GenerateReportHeader(BString& _output)
|
DebugReportGenerator::_GenerateReportHeader(BString& _output)
|
||||||
{
|
{
|
||||||
|
AutoLocker<Team> locker(fTeam);
|
||||||
|
|
||||||
|
BString data;
|
||||||
|
data.SetToFormat("Debug information for team %s (%" B_PRId32 "):\n\n");
|
||||||
|
_output << data;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,20 +18,16 @@ class Thread;
|
|||||||
class DebugReportGenerator : public BReferenceable
|
class DebugReportGenerator : public BReferenceable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebugReportGenerator(::Team* team,
|
DebugReportGenerator(::Team* team);
|
||||||
Architecture* architecture);
|
|
||||||
~DebugReportGenerator();
|
~DebugReportGenerator();
|
||||||
|
|
||||||
void Init();
|
status_t Init();
|
||||||
|
|
||||||
static DebugReportGenerator* Create(::Team* team,
|
static DebugReportGenerator* Create(::Team* team);
|
||||||
Architecture* architecture);
|
|
||||||
|
|
||||||
status_t GenerateReport(const entry_ref& outputPath);
|
status_t GenerateReport(const entry_ref& outputPath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _Init();
|
|
||||||
|
|
||||||
status_t _GenerateReportHeader(BString& output);
|
status_t _GenerateReportHeader(BString& output);
|
||||||
status_t _DumpLoadedImages(BString& output);
|
status_t _DumpLoadedImages(BString& output);
|
||||||
status_t _DumpRunningThreads(BString& output);
|
status_t _DumpRunningThreads(BString& output);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
#include <Entry.h>
|
||||||
#include <Message.h>
|
#include <Message.h>
|
||||||
|
|
||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include "BreakpointSetting.h"
|
#include "BreakpointSetting.h"
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
|
#include "DebugReportGenerator.h"
|
||||||
#include "FileManager.h"
|
#include "FileManager.h"
|
||||||
#include "Function.h"
|
#include "Function.h"
|
||||||
#include "FunctionID.h"
|
#include "FunctionID.h"
|
||||||
@@ -146,6 +148,7 @@ TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface,
|
|||||||
fBreakpointManager(NULL),
|
fBreakpointManager(NULL),
|
||||||
fWatchpointManager(NULL),
|
fWatchpointManager(NULL),
|
||||||
fMemoryBlockManager(NULL),
|
fMemoryBlockManager(NULL),
|
||||||
|
fReportGenerator(NULL),
|
||||||
fDebugEventListener(-1),
|
fDebugEventListener(-1),
|
||||||
fUserInterface(userInterface),
|
fUserInterface(userInterface),
|
||||||
fTerminating(false),
|
fTerminating(false),
|
||||||
@@ -204,6 +207,7 @@ TeamDebugger::~TeamDebugger()
|
|||||||
delete fBreakpointManager;
|
delete fBreakpointManager;
|
||||||
delete fWatchpointManager;
|
delete fWatchpointManager;
|
||||||
delete fMemoryBlockManager;
|
delete fMemoryBlockManager;
|
||||||
|
delete fReportGenerator;
|
||||||
delete fWorker;
|
delete fWorker;
|
||||||
delete fTeam;
|
delete fTeam;
|
||||||
delete fFileManager;
|
delete fFileManager;
|
||||||
@@ -327,6 +331,15 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
// create the debug report generator
|
||||||
|
fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam);
|
||||||
|
if (fReportGenerator == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
error = fReportGenerator->Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
// set team debugging flags
|
// set team debugging flags
|
||||||
fDebuggerInterface->SetTeamDebuggingFlags(
|
fDebuggerInterface->SetTeamDebuggingFlags(
|
||||||
B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES);
|
B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES);
|
||||||
@@ -535,6 +548,14 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MSG_GENERATE_DEBUG_REPORT:
|
||||||
|
{
|
||||||
|
entry_ref ref;
|
||||||
|
if (message->FindRef("target", &ref) == B_OK)
|
||||||
|
_HandleGenerateDebugReport(ref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MSG_THREAD_STATE_CHANGED:
|
case MSG_THREAD_STATE_CHANGED:
|
||||||
{
|
{
|
||||||
int32 threadID;
|
int32 threadID;
|
||||||
@@ -809,6 +830,15 @@ TeamDebugger::InspectRequested(target_addr_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamDebugger::DebugReportRequested(entry_ref* targetPath)
|
||||||
|
{
|
||||||
|
BMessage message(MSG_GENERATE_DEBUG_REPORT);
|
||||||
|
message.AddRef("target", targetPath);
|
||||||
|
PostMessage(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
|
TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
|
||||||
{
|
{
|
||||||
@@ -1502,6 +1532,13 @@ TeamDebugger::_HandleInspectAddress(target_addr_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamDebugger::_HandleGenerateDebugReport(const entry_ref& ref)
|
||||||
|
{
|
||||||
|
fReportGenerator->GenerateReport(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ThreadHandler*
|
ThreadHandler*
|
||||||
TeamDebugger::_GetThreadHandler(thread_id threadID)
|
TeamDebugger::_GetThreadHandler(thread_id threadID)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
|
class DebugReportGenerator;
|
||||||
class FileManager;
|
class FileManager;
|
||||||
class SettingsManager;
|
class SettingsManager;
|
||||||
class TeamDebugInfo;
|
class TeamDebugInfo;
|
||||||
@@ -78,6 +79,9 @@ private:
|
|||||||
|
|
||||||
virtual void InspectRequested(target_addr_t address,
|
virtual void InspectRequested(target_addr_t address,
|
||||||
TeamMemoryBlock::Listener* listener);
|
TeamMemoryBlock::Listener* listener);
|
||||||
|
|
||||||
|
virtual void DebugReportRequested(entry_ref* targetPath);
|
||||||
|
|
||||||
virtual bool UserInterfaceQuitRequested(
|
virtual bool UserInterfaceQuitRequested(
|
||||||
QuitOption quitOption);
|
QuitOption quitOption);
|
||||||
|
|
||||||
@@ -143,6 +147,9 @@ private:
|
|||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
TeamMemoryBlock::Listener* listener);
|
TeamMemoryBlock::Listener* listener);
|
||||||
|
|
||||||
|
void _HandleGenerateDebugReport(
|
||||||
|
const entry_ref& target);
|
||||||
|
|
||||||
ThreadHandler* _GetThreadHandler(thread_id threadID);
|
ThreadHandler* _GetThreadHandler(thread_id threadID);
|
||||||
|
|
||||||
status_t _AddImage(const ImageInfo& imageInfo,
|
status_t _AddImage(const ImageInfo& imageInfo,
|
||||||
@@ -170,6 +177,8 @@ private:
|
|||||||
WatchpointManager* fWatchpointManager;
|
WatchpointManager* fWatchpointManager;
|
||||||
TeamMemoryBlockManager*
|
TeamMemoryBlockManager*
|
||||||
fMemoryBlockManager;
|
fMemoryBlockManager;
|
||||||
|
DebugReportGenerator*
|
||||||
|
fReportGenerator;
|
||||||
thread_id fDebugEventListener;
|
thread_id fDebugEventListener;
|
||||||
UserInterface* fUserInterface;
|
UserInterface* fUserInterface;
|
||||||
volatile bool fTerminating;
|
volatile bool fTerminating;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
|
|
||||||
|
class entry_ref;
|
||||||
|
|
||||||
class CpuState;
|
class CpuState;
|
||||||
class FunctionInstance;
|
class FunctionInstance;
|
||||||
class Image;
|
class Image;
|
||||||
@@ -116,6 +118,8 @@ public:
|
|||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
TeamMemoryBlock::Listener* listener) = 0;
|
TeamMemoryBlock::Listener* listener) = 0;
|
||||||
|
|
||||||
|
virtual void DebugReportRequested(entry_ref* path) = 0;
|
||||||
|
|
||||||
virtual bool UserInterfaceQuitRequested(
|
virtual bool UserInterfaceQuitRequested(
|
||||||
QuitOption quitOption
|
QuitOption quitOption
|
||||||
= QUIT_OPTION_ASK_USER) = 0;
|
= QUIT_OPTION_ASK_USER) = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user