drivers/powercap/idle_inject.c

Source file repositories/reference/linux-study-clean/drivers/powercap/idle_inject.c

File Facts

System
Linux kernel
Corpus path
drivers/powercap/idle_inject.c
Extension
.c
Size
13282 bytes
Lines
421
Domain
Driver Families
Bucket
drivers/powercap
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_inject_thread {
	struct task_struct *tsk;
	int should_run;
};

/**
 * struct idle_inject_device - idle injection data
 * @timer: idle injection period timer
 * @idle_duration_us: duration of CPU idle time to inject
 * @run_duration_us: duration of CPU run time to allow
 * @latency_us: max allowed latency
 * @update: Optional callback deciding whether or not to skip idle
 *		injection in the given cycle.
 * @cpumask: mask of CPUs affected by idle injection
 *
 * This structure is used to define per instance idle inject device data. Each
 * instance has an idle duration, a run duration and mask of CPUs to inject
 * idle.
 *
 * Actual CPU idle time is injected by calling kernel scheduler interface
 * play_idle_precise(). There is one optional callback that can be registered
 * by calling idle_inject_register_full():
 *
 * update() - This callback is invoked just before waking up CPUs to inject
 * idle. If it returns false, CPUs are not woken up to inject idle in the given
 * cycle. It also allows the caller to readjust the idle and run duration by
 * calling idle_inject_set_duration() for the next cycle.
 */
struct idle_inject_device {
	struct hrtimer timer;
	unsigned int idle_duration_us;
	unsigned int run_duration_us;
	unsigned int latency_us;
	bool (*update)(void);
	unsigned long cpumask[];
};

static DEFINE_PER_CPU(struct idle_inject_thread, idle_inject_thread);
static DEFINE_PER_CPU(struct idle_inject_device *, idle_inject_device);

/**
 * idle_inject_wakeup - Wake up idle injection threads
 * @ii_dev: target idle injection device
 *
 * Every idle injection task associated with the given idle injection device
 * and running on an online CPU will be woken up.
 */
static void idle_inject_wakeup(struct idle_inject_device *ii_dev)
{
	struct idle_inject_thread *iit;
	unsigned int cpu;

	for_each_cpu_and(cpu, to_cpumask(ii_dev->cpumask), cpu_online_mask) {
		iit = per_cpu_ptr(&idle_inject_thread, cpu);
		iit->should_run = 1;
		wake_up_process(iit->tsk);
	}
}

/**
 * idle_inject_timer_fn - idle injection timer function
 * @timer: idle injection hrtimer
 *
 * This function is called when the idle injection timer expires.  It wakes up
 * idle injection tasks associated with the timer and they, in turn, invoke
 * play_idle_precise() to inject a specified amount of CPU idle time.
 *
 * Return: HRTIMER_RESTART.
 */
static enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer)
{
	unsigned int duration_us;
	struct idle_inject_device *ii_dev =
		container_of(timer, struct idle_inject_device, timer);

	if (!ii_dev->update || ii_dev->update())
		idle_inject_wakeup(ii_dev);

	duration_us = READ_ONCE(ii_dev->run_duration_us);
	duration_us += READ_ONCE(ii_dev->idle_duration_us);

	hrtimer_forward_now(timer, us_to_ktime(duration_us));

	return HRTIMER_RESTART;
}

/**
 * idle_inject_fn - idle injection work function
 * @cpu: the CPU owning the task
 *

Annotation

Implementation Notes