while (!need_resched()) {
HMT_low();
HMT_very_low(); if (likely(snooze_timeout_en) && get_tb() > snooze_exit_time) { /* * Task has not woken up but we are exiting the polling * loop anyway. Require a barrier after polling is * cleared to order subsequent test of need_resched().
*/
dev->poll_time_limit = true;
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb(); break;
}
}
static __cpuidle void check_and_cede_processor(void)
{ /* * Ensure our interrupt state is properly tracked, * also checks if no interrupt has occurred while we * were soft-disabled
*/ if (prep_irq_for_idle()) {
cede_processor(); #ifdef CONFIG_TRACE_IRQFLAGS /* Ensure that H_CEDE returns with IRQs on */ if (WARN_ON(!(mfmsr() & MSR_EE)))
__hard_irq_enable(); #endif
}
}
/* * XCEDE: Extended CEDE states discovered through the * "ibm,get-systems-parameter" RTAS call with the token * CEDE_LATENCY_TOKEN
*/
/* * Section 7.3.16 System Parameters Option of PAPR version 2.8.1 has a * table with all the parameters to ibm,get-system-parameters. * CEDE_LATENCY_TOKEN corresponds to the token value for Cede Latency * Settings Information.
*/ #define CEDE_LATENCY_TOKEN 45
/* * If the platform supports the cede latency settings information system * parameter it must provide the following information in the NULL terminated * parameter string: * * a. The first byte is the length “N” of each cede latency setting record minus * one (zero indicates a length of 1 byte). * * b. For each supported cede latency setting a cede latency setting record * consisting of the first “N” bytes as per the following table. * * ----------------------------- * | Field | Field | * | Name | Length | * ----------------------------- * | Cede Latency | 1 Byte | * | Specifier Value | | * ----------------------------- * | Maximum wakeup | | * | latency in | 8 Bytes | * | tb-ticks | | * ----------------------------- * | Responsive to | | * | external | 1 Byte | * | interrupts | | * ----------------------------- * * This version has cede latency record size = 10. * * The structure xcede_latency_payload represents a) and b) with * xcede_latency_record representing the table in b). * * xcede_latency_parameter is what gets returned by * ibm,get-systems-parameter RTAS call when made with * CEDE_LATENCY_TOKEN. * * These structures are only used to represent the data obtained by the RTAS * call. The data is in big-endian.
*/ struct xcede_latency_record {
u8 hint;
__be64 latency_ticks;
u8 wake_on_irqs;
} __packed;
// Make space for 16 records, which "should be enough". struct xcede_latency_payload {
u8 record_size; struct xcede_latency_record records[16];
} __packed;
/* * Since the payload_size includes the last NULL byte and the * xcede_record_size, the remaining bytes correspond to array of all * cede_latency settings.
*/
total_xcede_records_size = payload_size - 2;
nr_xcede_records = total_xcede_records_size / xcede_record_size;
for (i = 0; i < nr_xcede_records; i++) { struct xcede_latency_record *record = &payload->records[i];
u64 latency_ticks = be64_to_cpu(record->latency_ticks);
u8 wake_on_irqs = record->wake_on_irqs;
u8 hint = record->hint;
pr_info("xcede: Record %d : hint = %u, latency = 0x%llx tb ticks, Wake-on-irq = %u\n",
i, hint, latency_ticks, wake_on_irqs);
}
static __cpuidle int shared_cede_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
{
pseries_idle_prolog();
/* * Yield the processor to the hypervisor. We return if * an external interrupt occurs (which are driven prior * to returning here) or if a prod occurs from another * processor. When returning here, external interrupts * are enabled.
*/
check_and_cede_processor();
for (idle_state = 0; idle_state < max_idle_state; ++idle_state) { /* Is the state not enabled? */ if (cpuidle_state_table[idle_state].enter == NULL) continue;
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);
}
}
/* * pseries_idle_probe() * Choose state table for shared versus dedicated partition
*/ staticint __init pseries_idle_probe(void)
{
if (cpuidle_disable != IDLE_NO_OVERRIDE) return -ENODEV;
if (firmware_has_feature(FW_FEATURE_SPLPAR)) { if (lppaca_shared_proc()) {
cpuidle_state_table = shared_states;
max_idle_state = ARRAY_SIZE(shared_states);
} else { /* * Use firmware provided latency values * starting with POWER10 platforms. In the * case that we are running on a POWER10 * platform but in an earlier compat mode, we * can still use the firmware provided values. * * However, on platforms prior to POWER10, we * cannot rely on the accuracy of the firmware * provided latency values. On such platforms, * go with the conservative default estimate * of 10us.
*/ if (cpu_has_feature(CPU_FTR_ARCH_31) || pvr_version_is(PVR_POWER10))
fixup_cede0_latency();
cpuidle_state_table = dedicated_states;
max_idle_state = NR_DEDICATED_STATES;
}
} else return -ENODEV;
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.