Commit b753c320 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'cpufreq-arm-updates-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm

Pull CPUFreq Arm updates for 7.0 from Viresh Kumar:

"- Update cpufreq-dt-platdev list for tegra, qcom, TI (Aaron Kling,
   Dhruva Gole, and Konrad Dybcio).

 - Minor improvements to the cpufreq / cpumask rust implementation
   (Alexandre Courbot, Alice Ryhl, Tamir Duberstein, and Yilin Chen).

 - Add support for AM62L3 SoC to ti-cpufreq driver (Dhruva Gole).

 - Update FIE arch_freq_scale in ticks for non-PCC regs (Jie Zhan).

 - Other minor cleanups / improvements (Felix Gu, Juan Martinez, Luca
   Weiss, and Sergey Shtylyov)."

* tag 'cpufreq-arm-updates-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  cpufreq: scmi: Fix device_node reference leak in scmi_cpu_domain_id()
  cpufreq: ti-cpufreq: add support for AM62L3 SoC
  cpufreq: dt-platdev: Add ti,am62l3 to blocklist
  cpufreq/amd-pstate: Add comment explaining nominal_perf usage for performance policy
  cpufreq: scmi: correct SCMI explanation
  cpufreq: dt-platdev: Block the driver from probing on more QC platforms
  rust: cpumask: rename methods of Cpumask for clarity and consistency
  cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs
  cpufreq: CPPC: Factor out cppc_fie_kworker_init()
  ACPI: CPPC: Factor out and export per-cpu cppc_perf_ctrs_in_pcc_cpu()
  rust: cpufreq: replace `kernel::c_str!` with C-Strings
  cpufreq: Add Tegra186 and Tegra194 to cpufreq-dt-platdev blocklist
  dt-bindings: cpufreq: qcom-hw: document Milos CPUFREQ Hardware
  rust: cpufreq: add __rust_helper to helpers
  rust: cpufreq: always inline functions using build_assert with arguments
parents 39385cbd 0b7fbf93
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ properties:
      - description: v2 of CPUFREQ HW (EPSS)
        items:
          - enum:
              - qcom,milos-cpufreq-epss
              - qcom,qcs8300-cpufreq-epss
              - qcom,qdu1000-cpufreq-epss
              - qcom,sa8255p-cpufreq-epss
@@ -169,6 +170,7 @@ allOf:
        compatible:
          contains:
            enum:
              - qcom,milos-cpufreq-epss
              - qcom,qcs8300-cpufreq-epss
              - qcom,sc7280-cpufreq-epss
              - qcom,sm8250-cpufreq-epss
+27 −21
Original line number Diff line number Diff line
@@ -1423,6 +1423,32 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
}
EXPORT_SYMBOL_GPL(cppc_get_perf_caps);

/**
 * cppc_perf_ctrs_in_pcc_cpu - Check if any perf counters of a CPU are in PCC.
 * @cpu: CPU on which to check perf counters.
 *
 * Return: true if any of the counters are in PCC regions, false otherwise
 */
bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
{
	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
	struct cpc_register_resource *ref_perf_reg;

	/*
	 * If reference perf register is not supported then we should use the
	 * nominal perf value
	 */
	ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
	if (!CPC_SUPPORTED(ref_perf_reg))
		ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];

	return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
		CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
		CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
		CPC_IN_PCC(ref_perf_reg);
}
EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);

/**
 * cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
 *
@@ -1437,27 +1463,7 @@ bool cppc_perf_ctrs_in_pcc(void)
	int cpu;

	for_each_online_cpu(cpu) {
		struct cpc_register_resource *ref_perf_reg;
		struct cpc_desc *cpc_desc;

		cpc_desc = per_cpu(cpc_desc_ptr, cpu);

		if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
		    CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
		    CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
			return true;


		ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];

		/*
		 * If reference perf register is not supported then we should
		 * use the nominal perf value
		 */
		if (!CPC_SUPPORTED(ref_perf_reg))
			ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];

		if (CPC_IN_PCC(ref_perf_reg))
		if (cppc_perf_ctrs_in_pcc_cpu(cpu))
			return true;
	}

+13 −0
Original line number Diff line number Diff line
@@ -636,6 +636,19 @@ static void amd_pstate_update_min_max_limit(struct cpufreq_policy *policy)
	WRITE_ONCE(cpudata->max_limit_freq, policy->max);

	if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
		/*
		 * For performance policy, set MinPerf to nominal_perf rather than
		 * highest_perf or lowest_nonlinear_perf.
		 *
		 * Per commit 0c411b39e4f4c, using highest_perf was observed
		 * to cause frequency throttling on power-limited platforms, leading to
		 * performance regressions. Using lowest_nonlinear_perf would limit
		 * performance too much for HPC workloads requiring high frequency
		 * operation and minimal wakeup latency from idle states.
		 *
		 * nominal_perf therefore provides a balance by avoiding throttling
		 * while still maintaining enough performance for HPC workloads.
		 */
		perf.min_limit_perf = min(perf.nominal_perf, perf.max_limit_perf);
		WRITE_ONCE(cpudata->min_limit_freq, min(cpudata->nominal_freq, cpudata->max_limit_freq));
	} else {
+64 −32
Original line number Diff line number Diff line
@@ -54,31 +54,24 @@ static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
				 struct cppc_perf_fb_ctrs *fb_ctrs_t1);

/**
 * cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance
 * @work: The work item.
 * __cppc_scale_freq_tick - CPPC arch_freq_scale updater for frequency invariance
 * @cppc_fi: per-cpu CPPC FIE data.
 *
 * The CPPC driver register itself with the topology core to provide its own
 * The CPPC driver registers itself with the topology core to provide its own
 * implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which
 * gets called by the scheduler on every tick.
 *
 * Note that the arch specific counters have higher priority than CPPC counters,
 * if available, though the CPPC driver doesn't need to have any special
 * handling for that.
 *
 * On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we
 * reach here from hard-irq context), which then schedules a normal work item
 * and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable
 * based on the counter updates since the last tick.
 */
static void cppc_scale_freq_workfn(struct kthread_work *work)
static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
{
	struct cppc_freq_invariance *cppc_fi;
	struct cppc_perf_fb_ctrs fb_ctrs = {0};
	struct cppc_cpudata *cpu_data;
	unsigned long local_freq_scale;
	u64 perf;

	cppc_fi = container_of(work, struct cppc_freq_invariance, work);
	cpu_data = cppc_fi->cpu_data;

	if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) {
@@ -102,6 +95,24 @@ static void cppc_scale_freq_workfn(struct kthread_work *work)
	per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale;
}

static void cppc_scale_freq_tick(void)
{
	__cppc_scale_freq_tick(&per_cpu(cppc_freq_inv, smp_processor_id()));
}

static struct scale_freq_data cppc_sftd = {
	.source = SCALE_FREQ_SOURCE_CPPC,
	.set_freq_scale = cppc_scale_freq_tick,
};

static void cppc_scale_freq_workfn(struct kthread_work *work)
{
	struct cppc_freq_invariance *cppc_fi;

	cppc_fi = container_of(work, struct cppc_freq_invariance, work);
	__cppc_scale_freq_tick(cppc_fi);
}

static void cppc_irq_work(struct irq_work *irq_work)
{
	struct cppc_freq_invariance *cppc_fi;
@@ -110,7 +121,14 @@ static void cppc_irq_work(struct irq_work *irq_work)
	kthread_queue_work(kworker_fie, &cppc_fi->work);
}

static void cppc_scale_freq_tick(void)
/*
 * Reading perf counters may sleep if the CPC regs are in PCC.  Thus, we
 * schedule an irq work in scale_freq_tick (since we reach here from hard-irq
 * context), which then schedules a normal work item cppc_scale_freq_workfn()
 * that updates the per_cpu arch_freq_scale variable based on the counter
 * updates since the last tick.
 */
static void cppc_scale_freq_tick_pcc(void)
{
	struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id());

@@ -121,13 +139,14 @@ static void cppc_scale_freq_tick(void)
	irq_work_queue(&cppc_fi->irq_work);
}

static struct scale_freq_data cppc_sftd = {
static struct scale_freq_data cppc_sftd_pcc = {
	.source = SCALE_FREQ_SOURCE_CPPC,
	.set_freq_scale = cppc_scale_freq_tick,
	.set_freq_scale = cppc_scale_freq_tick_pcc,
};

static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
{
	struct scale_freq_data *sftd = &cppc_sftd;
	struct cppc_freq_invariance *cppc_fi;
	int cpu, ret;

@@ -138,8 +157,11 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
		cppc_fi = &per_cpu(cppc_freq_inv, cpu);
		cppc_fi->cpu = cpu;
		cppc_fi->cpu_data = policy->driver_data;
		if (cppc_perf_ctrs_in_pcc_cpu(cpu)) {
			kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
			init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
			sftd = &cppc_sftd_pcc;
		}

		ret = cppc_get_perf_ctrs(cpu, &cppc_fi->prev_perf_fb_ctrs);

@@ -155,7 +177,7 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
	}

	/* Register for freq-invariance */
	topology_set_scale_freq_source(&cppc_sftd, policy->cpus);
	topology_set_scale_freq_source(sftd, policy->cpus);
}

/*
@@ -178,13 +200,15 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
	topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, policy->related_cpus);

	for_each_cpu(cpu, policy->related_cpus) {
		if (!cppc_perf_ctrs_in_pcc_cpu(cpu))
			continue;
		cppc_fi = &per_cpu(cppc_freq_inv, cpu);
		irq_work_sync(&cppc_fi->irq_work);
		kthread_cancel_work_sync(&cppc_fi->work);
	}
}

static void __init cppc_freq_invariance_init(void)
static void cppc_fie_kworker_init(void)
{
	struct sched_attr attr = {
		.size		= sizeof(struct sched_attr),
@@ -201,22 +225,12 @@ static void __init cppc_freq_invariance_init(void)
	};
	int ret;

	if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
		fie_disabled = FIE_ENABLED;
		if (cppc_perf_ctrs_in_pcc()) {
			pr_info("FIE not enabled on systems with registers in PCC\n");
			fie_disabled = FIE_DISABLED;
		}
	}

	if (fie_disabled)
		return;

	kworker_fie = kthread_run_worker(0, "cppc_fie");
	if (IS_ERR(kworker_fie)) {
		pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
			PTR_ERR(kworker_fie));
		fie_disabled = FIE_DISABLED;
		kworker_fie = NULL;
		return;
	}

@@ -226,14 +240,32 @@ static void __init cppc_freq_invariance_init(void)
			ret);
		kthread_destroy_worker(kworker_fie);
		fie_disabled = FIE_DISABLED;
		kworker_fie = NULL;
	}
}

static void cppc_freq_invariance_exit(void)
static void __init cppc_freq_invariance_init(void)
{
	if (fie_disabled)
	bool perf_ctrs_in_pcc = cppc_perf_ctrs_in_pcc();

	if (fie_disabled == FIE_UNSET) {
		if (perf_ctrs_in_pcc) {
			pr_info("FIE not enabled on systems with registers in PCC\n");
			fie_disabled = FIE_DISABLED;
		} else {
			fie_disabled = FIE_ENABLED;
		}
	}

	if (fie_disabled || !perf_ctrs_in_pcc)
		return;

	cppc_fie_kworker_init();
}

static void cppc_freq_invariance_exit(void)
{
	if (kworker_fie)
		kthread_destroy_worker(kworker_fie);
}

+6 −0
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@ static const struct of_device_id blocklist[] __initconst = {
	{ .compatible = "nvidia,tegra30", },
	{ .compatible = "nvidia,tegra114", },
	{ .compatible = "nvidia,tegra124", },
	{ .compatible = "nvidia,tegra186", },
	{ .compatible = "nvidia,tegra194", },
	{ .compatible = "nvidia,tegra210", },
	{ .compatible = "nvidia,tegra234", },

@@ -169,8 +171,11 @@ static const struct of_device_id blocklist[] __initconst = {
	{ .compatible = "qcom,sdm845", },
	{ .compatible = "qcom,sdx75", },
	{ .compatible = "qcom,sm6115", },
	{ .compatible = "qcom,sm6125", },
	{ .compatible = "qcom,sm6150", },
	{ .compatible = "qcom,sm6350", },
	{ .compatible = "qcom,sm6375", },
	{ .compatible = "qcom,sm7125", },
	{ .compatible = "qcom,sm7225", },
	{ .compatible = "qcom,sm7325", },
	{ .compatible = "qcom,sm8150", },
@@ -191,6 +196,7 @@ static const struct of_device_id blocklist[] __initconst = {
	{ .compatible = "ti,am625", },
	{ .compatible = "ti,am62a7", },
	{ .compatible = "ti,am62d2", },
	{ .compatible = "ti,am62l3", },
	{ .compatible = "ti,am62p5", },

	{ .compatible = "qcom,ipq5332", },
Loading