/* * Include the apic definitions for x86 to have the APIC timer related defines * available also for UP (on SMP it gets magically included via linux/smp.h). * asm/acpi.h is not an option, as it would require more include magic. Also * creating an empty asm-ia64/apic.h would just trade pest vs. cholera.
*/ #ifdef CONFIG_X86 #include <asm/apic.h> #include <asm/cpu.h> #endif
/* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * For now disable this. Probably a bug somewhere else. * * To skip this limit, boot/load with a large max_cstate limit.
*/ staticint set_max_cstate(conststruct dmi_system_id *id)
{ if (max_cstate > ACPI_PROCESSOR_MAX_POWER) return 0;
pr_notice("%s detected - limiting to C%ld max_cstate." " Override with \"processor.max_cstate=%d\"\n", id->ident,
(long)id->driver_data, ACPI_PROCESSOR_MAX_POWER + 1);
/* * Callers should disable interrupts before the call and enable * interrupts after return.
*/ staticvoid __cpuidle acpi_safe_halt(void)
{ if (!tif_need_resched()) {
raw_safe_halt();
raw_local_irq_disable();
}
}
#ifdef ARCH_APICTIMER_STOPS_ON_C3
/* * Some BIOS implementations switch to C3 in the published C2 state. * This seems to be a common problem on AMD boxen, but other vendors * are affected too. We pick the most conservative approach: we assume * that the local APIC stops in both C2 and C3.
*/ staticvoid lapic_timer_check_state(int state, struct acpi_processor *pr, struct acpi_processor_cx *cx)
{ struct acpi_processor_power *pwr = &pr->power;
u8 type = local_apic_timer_c2_ok ? ACPI_STATE_C3 : ACPI_STATE_C2;
if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT)) return;
if (boot_cpu_has_bug(X86_BUG_AMD_APIC_C1E))
type = ACPI_STATE_C1;
/* * Check, if one of the previous states already marked the lapic * unstable
*/ if (pwr->timer_broadcast_on_state < state) return;
if (cx->type >= type)
pr->power.timer_broadcast_on_state = state;
}
#ifdefined(CONFIG_X86) staticvoid tsc_check_state(int state)
{ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_HYGON: case X86_VENDOR_AMD: case X86_VENDOR_INTEL: case X86_VENDOR_CENTAUR: case X86_VENDOR_ZHAOXIN: /* * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set.
*/ if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) return;
fallthrough; default: /* TSC could halt in idle, so notify users */ if (state > ACPI_STATE_C1)
mark_tsc_unstable("TSC halts in idle");
}
} #else staticvoid tsc_check_state(int state) { return; } #endif
/* if info is obtained from pblk/fadt, type equals state */
pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;
pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3;
#ifndef CONFIG_HOTPLUG_CPU /* * Check for P_LVL2_UP flag before entering C2 and above on * an SMP system.
*/ if ((num_online_cpus() > 1) &&
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) return -ENODEV; #endif
/* determine C2 and C3 address from pblk */
pr->power.states[ACPI_STATE_C2].address = pr->pblk + 4;
pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
/* * FADT specified C2 latency must be less than or equal to * 100 microseconds.
*/ if (acpi_gbl_FADT.c2_latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
acpi_handle_debug(pr->handle, "C2 latency too large [%d]\n",
acpi_gbl_FADT.c2_latency); /* invalidate C2 */
pr->power.states[ACPI_STATE_C2].address = 0;
}
/* * FADT supplied C3 latency must be less than or equal to * 1000 microseconds.
*/ if (acpi_gbl_FADT.c3_latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
acpi_handle_debug(pr->handle, "C3 latency too large [%d]\n",
acpi_gbl_FADT.c3_latency); /* invalidate C3 */
pr->power.states[ACPI_STATE_C3].address = 0;
}
if (!pr->power.states[ACPI_STATE_C2].address &&
!pr->power.states[ACPI_STATE_C3].address) return -ENODEV;
return 0;
}
staticint acpi_processor_get_power_info_default(struct acpi_processor *pr)
{ if (!pr->power.states[ACPI_STATE_C1].valid) { /* set the first C-State to C1 */ /* all processors need to support C1 */
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
pr->power.states[ACPI_STATE_C1].valid = 1;
pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT;
snprintf(pr->power.states[ACPI_STATE_C1].desc,
ACPI_CX_DESC_LEN, "ACPI HLT");
} /* the C0 state only exists as a filler in our array */
pr->power.states[ACPI_STATE_C0].valid = 1; return 0;
}
staticint acpi_processor_get_power_info_cst(struct acpi_processor *pr)
{ int ret;
if (nocst) return -ENODEV;
ret = acpi_processor_evaluate_cst(pr->handle, pr->id, &pr->power); if (ret) return ret;
/* * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) * DMA transfers are used by any ISA device to avoid livelock. * Note that we could disable Type-F DMA (as recommended by * the erratum), but this is known to disrupt certain ISA * devices thus we take the conservative approach.
*/ if (errata.piix4.fdma) {
acpi_handle_debug(pr->handle, "C3 not supported on PIIX4 with Type-F DMA\n"); return;
}
/* All the logic here assumes flags.bm_check is same across all CPUs */ if (bm_check_flag == -1) { /* Determine whether bm_check is needed based on CPU */
acpi_processor_power_init_bm_check(&(pr->flags), pr->id);
bm_check_flag = pr->flags.bm_check;
bm_control_flag = pr->flags.bm_control;
} else {
pr->flags.bm_check = bm_check_flag;
pr->flags.bm_control = bm_control_flag;
}
if (pr->flags.bm_check) { if (!pr->flags.bm_control) { if (pr->flags.has_cst != 1) { /* bus mastering control is necessary */
acpi_handle_debug(pr->handle, "C3 support requires BM control\n"); return;
} else { /* Here we enter C3 without bus mastering */
acpi_handle_debug(pr->handle, "C3 support without BM control\n");
}
}
} else { /* * WBINVD should be set in fadt, for C3 state to be * supported on when bm_check is not required.
*/ if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) {
acpi_handle_debug(pr->handle, "Cache invalidation should work properly" " for C3 to be enabled on SMP systems\n"); return;
}
}
/* * Otherwise we've met all of our C3 requirements. * Normalize the C3 latency to expidite policy. Enable * checking of bus mastering status (bm_check) so we can * use this in our C3 policy
*/
cx->valid = 1;
/* * On older chipsets, BM_RLD needs to be set * in order for Bus Master activity to wake the * system from C3. Newer chipsets handle DMA * during C3 automatically and BM_RLD is a NOP. * In either case, the proper way to * handle BM_RLD is to set it and leave it set.
*/
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
}
staticvoid acpi_cst_latency_sort(struct acpi_processor_cx *states, size_t length)
{ int i, j, k;
for (i = 1; i < length; i++) { if (!states[i].valid) continue;
for (j = i - 1, k = i; j >= 0; j--) { if (!states[j].valid) continue;
if (states[j].latency > states[k].latency)
swap(states[j].latency, states[k].latency);
if (buggy_latency) {
pr_notice("FW issue: working around C-state latencies out of order\n");
acpi_cst_latency_sort(&pr->power.states[1], max_cstate);
}
lapic_timer_propagate_broadcast(pr);
return working;
}
staticint acpi_processor_get_cstate_info(struct acpi_processor *pr)
{ int result;
/* NOTE: the idle thread may not be running while calling
* this function */
/* Zero initialize all the C-states info. */
memset(pr->power.states, 0, sizeof(pr->power.states));
result = acpi_processor_get_power_info_cst(pr); if (result == -ENODEV)
result = acpi_processor_get_power_info_fadt(pr);
/** * acpi_idle_bm_check - checks if bus master activity was detected
*/ staticint acpi_idle_bm_check(void)
{
u32 bm_status = 0;
if (bm_check_disable) return 0;
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); if (bm_status)
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); /* * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect * the true state of bus mastering activity; forcing us to * manually check the BMIDEA bit of each IDE channel.
*/ elseif (errata.piix4.bmisx) { if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
|| (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
bm_status = 1;
} return bm_status;
}
static __cpuidle void io_idle(unsignedlong addr)
{ /* IO port based C-state */
inb(addr);
#ifdef CONFIG_X86 /* No delay is needed if we are in guest */ if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) return; /* * Modern (>=Nehalem) Intel systems use ACPI via intel_idle, * not this code. Assume that any Intel systems using this * are ancient and may need the dummy wait. This also assumes * that the motivating chipset issue was Intel-only.
*/ if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) return; #endif /* * Dummy wait op - must do something useless after P_LVL2 read * because chipsets cannot guarantee that STPCLK# signal gets * asserted in time to freeze execution properly * * This workaround has been in place since the original ACPI * implementation was merged, circa 2002. * * If a profile is pointing to this instruction, please first * consider moving your system to a more modern idle * mechanism.
*/
inl(acpi_gbl_FADT.xpm_timer_block.address);
}
/** * acpi_idle_do_entry - enter idle state using the appropriate method * @cx: cstate data * * Caller disables interrupt before call and enables interrupt after return.
*/ staticvoid __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
perf_lopwr_cb(true);
if (cx->entry_method == ACPI_CSTATE_FFH) { /* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx);
} elseif (cx->entry_method == ACPI_CSTATE_HALT) {
acpi_safe_halt();
} else {
io_idle(cx->address);
}
perf_lopwr_cb(false);
}
/** * acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining) * @dev: the target CPU * @index: the index of suggested state
*/ staticvoid acpi_idle_play_dead(struct cpuidle_device *dev, int index)
{ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
/** * acpi_idle_enter_bm - enters C3 with proper BM handling * @drv: cpuidle driver * @pr: Target processor * @cx: Target state context * @index: index of target state
*/ staticint __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, struct acpi_processor *pr, struct acpi_processor_cx *cx, int index)
{ staticstruct acpi_processor_cx safe_cx = {
.entry_method = ACPI_CSTATE_HALT,
};
/* * disable bus master * bm_check implies we need ARB_DIS * bm_control implies whether we can do ARB_DIS * * That leaves a case where bm_check is set and bm_control is not set. * In that case we cannot do much, we enter C3 without doing anything.
*/ bool dis_bm = pr->flags.bm_control;
instrumentation_begin();
/* If we can skip BM, demote to a safe state. */ if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
dis_bm = false;
index = drv->safe_state_index; if (index >= 0) {
cx = this_cpu_read(acpi_cstate[index]);
} else {
cx = &safe_cx;
index = -EBUSY;
}
}
if (dis_bm) {
raw_spin_lock(&c3_lock);
c3_cpu_count++; /* Disable bus master arbitration when all CPUs are in C3 */ if (c3_cpu_count == num_online_cpus())
acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
raw_spin_unlock(&c3_lock);
}
ct_cpuidle_enter();
acpi_idle_do_entry(cx);
ct_cpuidle_exit();
/* Re-enable bus master arbitration */ if (dis_bm) {
raw_spin_lock(&c3_lock);
acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
c3_cpu_count--;
raw_spin_unlock(&c3_lock);
}
/* * Halt-induced C1 is not good for ->enter_s2idle, because it * re-enables interrupts on exit. Moreover, C1 is generally not * particularly interesting from the suspend-to-idle angle, so * avoid C1 and the situations in which we may need to fall back * to it altogether.
*/ if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
state->enter_s2idle = acpi_idle_enter_s2idle;
if (first_run) return;
dmi_check_system(processor_power_dmi_table);
max_cstate = acpi_processor_cstate_check(max_cstate); if (max_cstate < ACPI_C_STATES_MAX)
pr_notice("processor limited to max C-state %d\n", max_cstate);
staticint acpi_processor_evaluate_lpi(acpi_handle handle, struct acpi_lpi_states_array *info)
{
acpi_status status; int ret = 0; int pkg_count, state_idx = 1, loop; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *lpi_data; struct acpi_lpi_state *lpi_state;
status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer); if (ACPI_FAILURE(status)) {
acpi_handle_debug(handle, "No _LPI, giving up\n"); return -ENODEV;
}
lpi_data = buffer.pointer;
/* There must be at least 4 elements = 3 elements + 1 package */ if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
lpi_data->package.count < 4) {
pr_debug("not enough elements in _LPI\n");
ret = -ENODATA; goto end;
}
/* Validate number of power states. */ if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) {
pr_debug("count given by _LPI is not valid\n");
ret = -ENODATA; goto end;
}
lpi_state = kcalloc(pkg_count, sizeof(*lpi_state), GFP_KERNEL); if (!lpi_state) {
ret = -ENOMEM; goto end;
}
/* LPI States start at index 3 */ for (loop = 3; state_idx <= pkg_count; loop++, state_idx++, lpi_state++) { union acpi_object *element, *pkg_elem, *obj;
element = &lpi_data->package.elements[loop]; if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 7) continue;
/* * flat_state_cnt - the number of composite LPI states after the process of flattening
*/ staticint flat_state_cnt;
/** * combine_lpi_states - combine local and parent LPI states to form a composite LPI state * * @local: local LPI state * @parent: parent LPI state * @result: composite LPI state
*/ staticbool combine_lpi_states(struct acpi_lpi_state *local, struct acpi_lpi_state *parent, struct acpi_lpi_state *result)
{ if (parent->entry_method == ACPI_CSTATE_INTEGER) { if (!parent->address) /* 0 means autopromotable */ returnfalse;
result->address = local->address + parent->address;
} else {
result->address = parent->address;
}
if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED)) continue;
if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) {
pr_warn("Limiting number of LPI states to max (%d)\n",
ACPI_PROCESSOR_MAX_POWER);
pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); break;
}
status = acpi_get_parent(handle, &pr_ahandle); while (ACPI_SUCCESS(status)) {
d = acpi_fetch_acpi_dev(pr_ahandle); if (!d) break;
handle = pr_ahandle;
if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) break;
/* can be optional ? */ if (!acpi_has_method(handle, "_LPI")) break;
ret = acpi_processor_evaluate_lpi(handle, curr); if (ret) break;
/* flatten all the LPI states in this level of hierarchy */
flatten_lpi_states(pr, curr, prev);
tmp = prev, prev = curr, curr = tmp;
status = acpi_get_parent(handle, &pr_ahandle);
}
pr->power.count = flat_state_cnt; /* reset the index after flattening */ for (i = 0; i < pr->power.count; i++)
pr->power.lpi_states[i].index = i;
/* Tell driver that _LPI is supported. */
pr->flags.has_lpi = 1;
pr->flags.power = 1;
return 0;
}
int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
{ return -ENODEV;
}
/** * acpi_idle_lpi_enter - enters an ACPI any LPI state * @dev: the target CPU * @drv: cpuidle driver containing cpuidle state info * @index: index of target state * * Return: 0 for success or negative value for error
*/ staticint acpi_idle_lpi_enter(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
{ struct acpi_processor *pr; struct acpi_lpi_state *lpi;
pr = __this_cpu_read(processors);
if (unlikely(!pr)) return -EINVAL;
lpi = &pr->power.lpi_states[index]; if (lpi->entry_method == ACPI_CSTATE_FFH) return acpi_processor_ffh_lpi_enter(lpi);
/** * acpi_processor_setup_cpuidle_states- prepares and configures cpuidle * global state data i.e. idle routines * * @pr: the ACPI processor
*/ staticint acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
{ int i; struct cpuidle_driver *drv = &acpi_idle_driver;
if (!pr->flags.power_setup_done || !pr->flags.power) return -EINVAL;
drv->safe_state_index = -1; for (i = ACPI_IDLE_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
drv->states[i].name[0] = '\0';
drv->states[i].desc[0] = '\0';
}
if (pr->flags.has_lpi) return acpi_processor_setup_lpi_states(pr);
return acpi_processor_setup_cstates(pr);
}
/** * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE * device i.e. per-cpu data * * @pr: the ACPI processor * @dev : the cpuidle device
*/ staticint acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr, struct cpuidle_device *dev)
{ if (!pr->flags.power_setup_done || !pr->flags.power || !dev) return -EINVAL;
dev->cpu = pr->id; if (pr->flags.has_lpi) return acpi_processor_ffh_lpi_probe(pr->id);
staticint acpi_processor_get_power_info(struct acpi_processor *pr)
{ int ret;
ret = acpi_processor_get_lpi_info(pr); if (ret)
ret = acpi_processor_get_cstate_info(pr);
return ret;
}
int acpi_processor_hotplug(struct acpi_processor *pr)
{ int ret = 0; struct cpuidle_device *dev;
if (disabled_by_idle_boot_param()) return 0;
if (!pr->flags.power_setup_done) return -ENODEV;
dev = per_cpu(acpi_cpuidle_device, pr->id);
cpuidle_pause_and_lock();
cpuidle_disable_device(dev);
ret = acpi_processor_get_power_info(pr); if (!ret && pr->flags.power) {
acpi_processor_setup_cpuidle_dev(pr, dev);
ret = cpuidle_enable_device(dev);
}
cpuidle_resume_and_unlock();
return ret;
}
int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
{ int cpu; struct acpi_processor *_pr; struct cpuidle_device *dev;
if (disabled_by_idle_boot_param()) return 0;
if (!pr->flags.power_setup_done) return -ENODEV;
/* * FIXME: Design the ACPI notification to make it once per * system instead of once per-cpu. This condition is a hack * to make the code that updates C-States be called once.
*/
if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
/* Protect against cpu-hotplug */
cpus_read_lock();
cpuidle_pause_and_lock();
/* Disable all cpuidle devices */
for_each_online_cpu(cpu) {
_pr = per_cpu(processors, cpu); if (!_pr || !_pr->flags.power_setup_done) continue;
dev = per_cpu(acpi_cpuidle_device, cpu);
cpuidle_disable_device(dev);
}
/* Populate Updated C-state information */
acpi_processor_get_power_info(pr);
acpi_processor_setup_cpuidle_states(pr);
/* Enable all cpuidle devices */
for_each_online_cpu(cpu) {
_pr = per_cpu(processors, cpu); if (!_pr || !_pr->flags.power_setup_done) continue;
acpi_processor_get_power_info(_pr); if (_pr->flags.power) {
dev = per_cpu(acpi_cpuidle_device, cpu);
acpi_processor_setup_cpuidle_dev(_pr, dev);
cpuidle_enable_device(dev);
}
}
cpuidle_resume_and_unlock();
cpus_read_unlock();
}
return 0;
}
staticint acpi_processor_registered;
int acpi_processor_power_init(struct acpi_processor *pr)
{ int retval; struct cpuidle_device *dev;
if (disabled_by_idle_boot_param()) return 0;
acpi_processor_cstate_first_run_checks();
if (!acpi_processor_get_power_info(pr))
pr->flags.power_setup_done = 1;
/* * Install the idle handler if processor power management is supported. * Note that we use previously set idle handler will be used on * platforms that only support C1.
*/ if (pr->flags.power) { /* Register acpi_idle_driver if not already registered */ if (!acpi_processor_registered) {
acpi_processor_setup_cpuidle_states(pr);
retval = cpuidle_register_driver(&acpi_idle_driver); if (retval) return retval;
pr_debug("%s registered with cpuidle\n",
acpi_idle_driver.name);
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM;
per_cpu(acpi_cpuidle_device, pr->id) = dev;
acpi_processor_setup_cpuidle_dev(pr, dev);
/* Register per-cpu cpuidle_device. Cpuidle driver * must already be registered before registering device
*/
retval = cpuidle_register_device(dev); if (retval) { if (acpi_processor_registered == 0)
cpuidle_unregister_driver(&acpi_idle_driver);
if (pr->flags.power) {
cpuidle_unregister_device(dev);
acpi_processor_registered--; if (acpi_processor_registered == 0)
cpuidle_unregister_driver(&acpi_idle_driver);
kfree(dev);
}
pr->flags.power_setup_done = 0; return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.