drivers/idle/intel_idle.c

Source file repositories/reference/linux-study-clean/drivers/idle/intel_idle.c

File Facts

System
Linux kernel
Corpus path
drivers/idle/intel_idle.c
Extension
.c
Size
75218 bytes
Lines
2845
Domain
Driver Families
Bucket
drivers/idle
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct idle_cpu {
	struct cpuidle_state *state_table;

	/*
	 * Hardware C-state auto-demotion may not always be optimal.
	 * Indicate which enable bits to clear here.
	 */
	unsigned long auto_demotion_disable_flags;
	bool disable_promotion_to_c1e;
	bool c1_demotion_supported;
	bool use_acpi;
};

static bool c1_demotion_supported;
static DEFINE_MUTEX(c1_demotion_mutex);

static struct device *sysfs_root __initdata;

static const struct idle_cpu *icpu __initdata;
static struct cpuidle_state *cpuidle_state_table __initdata;

/* C-states data from the 'intel_idle.table' cmdline parameter */
static struct cpuidle_state cmdline_states[CPUIDLE_STATE_MAX] __initdata;

static unsigned int mwait_substates __initdata;

/*
 * Enable interrupts before entering the C-state. On some platforms and for
 * some C-states, this may measurably decrease interrupt latency.
 */
#define CPUIDLE_FLAG_IRQ_ENABLE		BIT(14)

/*
 * Enable this state by default even if the ACPI _CST does not list it.
 */
#define CPUIDLE_FLAG_ALWAYS_ENABLE	BIT(15)

/*
 * Disable IBRS across idle (when KERNEL_IBRS), is exclusive vs IRQ_ENABLE
 * above.
 */
#define CPUIDLE_FLAG_IBRS		BIT(16)

/*
 * Initialize large xstate for the C6-state entrance.
 */
#define CPUIDLE_FLAG_INIT_XSTATE	BIT(17)

/*
 * Ignore the sub-state when matching mwait hints between the ACPI _CST and
 * custom tables.
 */
#define CPUIDLE_FLAG_PARTIAL_HINT_MATCH	BIT(18)

/*
 * MWAIT takes an 8-bit "hint" in EAX "suggesting"
 * the C-state (top nibble) and sub-state (bottom nibble)
 * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
 *
 * We store the hint at the top of our "flags" for each state.
 */
#define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
#define MWAIT2flg(eax) ((eax & 0xFF) << 24)

static __always_inline int __intel_idle(struct cpuidle_device *dev,
					struct cpuidle_driver *drv,
					int index, bool irqoff)
{
	struct cpuidle_state *state = &drv->states[index];
	unsigned int eax = flg2MWAIT(state->flags);
	unsigned int ecx = 1*irqoff; /* break on interrupt flag */

	mwait_idle_with_hints(eax, ecx);

	return index;
}

/**
 * intel_idle - Ask the processor to enter the given idle state.
 * @dev: cpuidle device of the target CPU.
 * @drv: cpuidle driver (assumed to point to intel_idle_driver).
 * @index: Target idle state index.
 *
 * Use the MWAIT instruction to notify the processor that the CPU represented by
 * @dev is idle and it can try to enter the idle state corresponding to @index.
 *
 * If the local APIC timer is not known to be reliable in the target idle state,
 * enable one-shot tick broadcasting for the target CPU before executing MWAIT.
 *
 * Must be called under local_irq_disable().

Annotation

Implementation Notes