drivers/powercap/dtpm_cpu.c

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

File Facts

System
Linux kernel
Corpus path
drivers/powercap/dtpm_cpu.c
Extension
.c
Size
7310 bytes
Lines
320
Domain
Driver Families
Bucket
drivers/powercap
Inferred role
Driver Families: implementation source
Status
source 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 dtpm_cpu {
	struct dtpm dtpm;
	struct freq_qos_request qos_req;
	int cpu;
};

static DEFINE_PER_CPU(struct dtpm_cpu *, dtpm_per_cpu);

static struct dtpm_cpu *to_dtpm_cpu(struct dtpm *dtpm)
{
	return container_of(dtpm, struct dtpm_cpu, dtpm);
}

static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
{
	struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm);
	struct em_perf_domain *pd = em_cpu_get(dtpm_cpu->cpu);
	struct em_perf_state *table;
	unsigned long freq;
	u64 power;
	int i, nr_cpus;

	nr_cpus = cpumask_weight_and(cpu_online_mask, to_cpumask(pd->cpus));

	rcu_read_lock();
	table = em_perf_state_from_pd(pd);
	for (i = 0; i < pd->nr_perf_states; i++) {

		power = table[i].power * nr_cpus;

		if (power > power_limit)
			break;
	}

	freq = table[i - 1].frequency;
	power_limit = table[i - 1].power * nr_cpus;
	rcu_read_unlock();

	freq_qos_update_request(&dtpm_cpu->qos_req, freq);

	return power_limit;
}

static u64 scale_pd_power_uw(struct cpumask *pd_mask, u64 power)
{
	unsigned long max, sum_util = 0;
	int cpu;

	/*
	 * The capacity is the same for all CPUs belonging to
	 * the same perf domain.
	 */
	max = arch_scale_cpu_capacity(cpumask_first(pd_mask));

	for_each_cpu_and(cpu, pd_mask, cpu_online_mask)
		sum_util += sched_cpu_util(cpu);

	return (power * ((sum_util << 10) / max)) >> 10;
}

static u64 get_pd_power_uw(struct dtpm *dtpm)
{
	struct dtpm_cpu *dtpm_cpu = to_dtpm_cpu(dtpm);
	struct em_perf_state *table;
	struct em_perf_domain *pd;
	struct cpumask *pd_mask;
	unsigned long freq;
	u64 power = 0;
	int i;

	pd = em_cpu_get(dtpm_cpu->cpu);
	if (!pd)
		return 0;

	pd_mask = em_span_cpus(pd);

	freq = cpufreq_quick_get(dtpm_cpu->cpu);

	rcu_read_lock();
	table = em_perf_state_from_pd(pd);
	for (i = 0; i < pd->nr_perf_states; i++) {

		if (table[i].frequency < freq)
			continue;

		power = scale_pd_power_uw(pd_mask, table[i].power);
		break;
	}
	rcu_read_unlock();

Annotation

Implementation Notes