in cpuidle-pseries.c [346:400]
static void __init fixup_cede0_latency(void)
{
struct xcede_latency_payload *payload;
u64 min_xcede_latency_us = UINT_MAX;
int i;
if (parse_cede_parameters())
return;
pr_info("cpuidle: Skipping the %d Extended CEDE idle states\n",
nr_xcede_records);
payload = &xcede_latency_parameter.payload;
/*
* The CEDE idle state maps to CEDE(0). While the hypervisor
* does not advertise CEDE(0) exit latency values, it does
* advertise the latency values of the extended CEDE states.
* We use the lowest advertised exit latency value as a proxy
* for the exit latency of CEDE(0).
*/
for (i = 0; i < nr_xcede_records; i++) {
struct xcede_latency_record *record = &payload->records[i];
u8 hint = record->hint;
u64 latency_tb = be64_to_cpu(record->latency_ticks);
u64 latency_us = DIV_ROUND_UP_ULL(tb_to_ns(latency_tb), NSEC_PER_USEC);
/*
* We expect the exit latency of an extended CEDE
* state to be non-zero, it to since it takes at least
* a few nanoseconds to wakeup the idle CPU and
* dispatch the virtual processor into the Linux
* Guest.
*
* So we consider only non-zero value for performing
* the fixup of CEDE(0) latency.
*/
if (latency_us == 0) {
pr_warn("cpuidle: Skipping xcede record %d [hint=%d]. Exit latency = 0us\n",
i, hint);
continue;
}
if (latency_us < min_xcede_latency_us)
min_xcede_latency_us = latency_us;
}
if (min_xcede_latency_us != UINT_MAX) {
dedicated_states[1].exit_latency = min_xcede_latency_us;
dedicated_states[1].target_residency = 10 * (min_xcede_latency_us);
pr_info("cpuidle: Fixed up CEDE exit latency to %llu us\n",
min_xcede_latency_us);
}
}