Commit dbb3c260 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power management fixes from Rafael Wysocki:
 "These remove a stale DT entry left behind after recent removal of a
  cpufreq driver without users, fix up error handling in the imx6q
  cpufreq driver, fix two issues in the cpufreq documentation, and
  update the ARM cpufreq driver.

  Specifics:

   - Drop stale DT binding for the arm_big_little_dt driver removed
     recently (Sudeep Holla).

   - Fix up error handling in the imx6q cpufreq driver to make it report
     voltage scaling failures (Anson Huang).

   - Fix two issues in the cpufreq documentation (Viresh Kumar, Zhao Wei
     Liew).

   - Fix ARM cpuidle driver initialization regression from the 4.19 time
     frame and rework the driver registration part of it to simplify
     code (Ulf Hansson)"

* tag 'pm-4.20-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ARM: cpuidle: Convert to use cpuidle_register|unregister()
  ARM: cpuidle: Don't register the driver when back-end init returns -ENXIO
  dt-bindings: cpufreq: remove stale arm_big_little_dt entry
  Documentation: cpufreq: Correct a typo
  cpufreq: imx6q: add return value check for voltage scale
  Documentation: cpu-freq: Frequencies aren't always sorted
parents 4e4490d4 97dc6c03
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -150,7 +150,7 @@ data structures necessary to handle the given policy and, possibly, to add
a governor ``sysfs`` interface to it.  Next, the governor is started by
a governor ``sysfs`` interface to it.  Next, the governor is started by
invoking its ``->start()`` callback.
invoking its ``->start()`` callback.


That callback it expected to register per-CPU utilization update callbacks for
That callback is expected to register per-CPU utilization update callbacks for
all of the online CPUs belonging to the given policy with the CPU scheduler.
all of the online CPUs belonging to the given policy with the CPU scheduler.
The utilization update callbacks will be invoked by the CPU scheduler on
The utilization update callbacks will be invoked by the CPU scheduler on
important events, like task enqueue and dequeue, on every iteration of the
important events, like task enqueue and dequeue, on every iteration of the
+5 −3
Original line number Original line Diff line number Diff line
@@ -86,9 +86,11 @@ transitions.
This will give a fine grained information about all the CPU frequency
This will give a fine grained information about all the CPU frequency
transitions. The cat output here is a two dimensional matrix, where an entry
transitions. The cat output here is a two dimensional matrix, where an entry
<i,j> (row i, column j) represents the count of number of transitions from 
<i,j> (row i, column j) represents the count of number of transitions from 
Freq_i to Freq_j. Freq_i is in descending order with increasing rows and 
Freq_i to Freq_j. Freq_i rows and Freq_j columns follow the sorting order in
Freq_j is in descending order with increasing columns. The output here also 
which the driver has provided the frequency table initially to the cpufreq core
contains the actual freq values for each row and column for better readability.
and so can be sorted (ascending or descending) or unsorted.  The output here
also contains the actual freq values for each row and column for better
readability.


If the transition table is bigger than PAGE_SIZE, reading this will
If the transition table is bigger than PAGE_SIZE, reading this will
return an -EFBIG error.
return an -EFBIG error.
+0 −65
Original line number Original line Diff line number Diff line
Generic ARM big LITTLE cpufreq driver's DT glue
-----------------------------------------------

This is DT specific glue layer for generic cpufreq driver for big LITTLE
systems.

Both required and optional properties listed below must be defined
under node /cpus/cpu@x. Where x is the first cpu inside a cluster.

FIXME: Cpus should boot in the order specified in DT and all cpus for a cluster
must be present contiguously. Generic DT driver will check only node 'x' for
cpu:x.

Required properties:
- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt
  for details

Optional properties:
- clock-latency: Specify the possible maximum transition latency for clock,
  in unit of nanoseconds.

Examples:

cpus {
	#address-cells = <1>;
	#size-cells = <0>;

	cpu@0 {
		compatible = "arm,cortex-a15";
		reg = <0>;
		next-level-cache = <&L2>;
		operating-points = <
			/* kHz    uV */
			792000  1100000
			396000  950000
			198000  850000
		>;
		clock-latency = <61036>; /* two CLK32 periods */
	};

	cpu@1 {
		compatible = "arm,cortex-a15";
		reg = <1>;
		next-level-cache = <&L2>;
	};

	cpu@100 {
		compatible = "arm,cortex-a7";
		reg = <100>;
		next-level-cache = <&L2>;
		operating-points = <
			/* kHz    uV */
			792000  950000
			396000  750000
			198000  450000
		>;
		clock-latency = <61036>; /* two CLK32 periods */
	};

	cpu@101 {
		compatible = "arm,cortex-a7";
		reg = <101>;
		next-level-cache = <&L2>;
	};
};
+6 −1
Original line number Original line Diff line number Diff line
@@ -160,8 +160,13 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
	/* Ensure the arm clock divider is what we expect */
	/* Ensure the arm clock divider is what we expect */
	ret = clk_set_rate(clks[ARM].clk, new_freq * 1000);
	ret = clk_set_rate(clks[ARM].clk, new_freq * 1000);
	if (ret) {
	if (ret) {
		int ret1;

		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
		regulator_set_voltage_tol(arm_reg, volt_old, 0);
		ret1 = regulator_set_voltage_tol(arm_reg, volt_old, 0);
		if (ret1)
			dev_warn(cpu_dev,
				 "failed to restore vddarm voltage: %d\n", ret1);
		return ret;
		return ret;
	}
	}


+7 −33
Original line number Original line Diff line number Diff line
@@ -82,7 +82,6 @@ static int __init arm_idle_init_cpu(int cpu)
{
{
	int ret;
	int ret;
	struct cpuidle_driver *drv;
	struct cpuidle_driver *drv;
	struct cpuidle_device *dev;


	drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);
	drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);
	if (!drv)
	if (!drv)
@@ -103,13 +102,6 @@ static int __init arm_idle_init_cpu(int cpu)
		goto out_kfree_drv;
		goto out_kfree_drv;
	}
	}


	ret = cpuidle_register_driver(drv);
	if (ret) {
		if (ret != -EBUSY)
			pr_err("Failed to register cpuidle driver\n");
		goto out_kfree_drv;
	}

	/*
	/*
	 * Call arch CPU operations in order to initialize
	 * Call arch CPU operations in order to initialize
	 * idle states suspend back-end specific data
	 * idle states suspend back-end specific data
@@ -117,37 +109,21 @@ static int __init arm_idle_init_cpu(int cpu)
	ret = arm_cpuidle_init(cpu);
	ret = arm_cpuidle_init(cpu);


	/*
	/*
	 * Skip the cpuidle device initialization if the reported
	 * Allow the initialization to continue for other CPUs, if the reported
	 * failure is a HW misconfiguration/breakage (-ENXIO).
	 * failure is a HW misconfiguration/breakage (-ENXIO).
	 */
	 */
	if (ret == -ENXIO)
		return 0;

	if (ret) {
	if (ret) {
		pr_err("CPU %d failed to init idle CPU ops\n", cpu);
		pr_err("CPU %d failed to init idle CPU ops\n", cpu);
		goto out_unregister_drv;
		ret = ret == -ENXIO ? 0 : ret;
	}
		goto out_kfree_drv;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		ret = -ENOMEM;
		goto out_unregister_drv;
	}
	}
	dev->cpu = cpu;


	ret = cpuidle_register_device(dev);
	ret = cpuidle_register(drv, NULL);
	if (ret) {
	if (ret)
		pr_err("Failed to register cpuidle device for CPU %d\n",
		goto out_kfree_drv;
		       cpu);
		goto out_kfree_dev;
	}


	return 0;
	return 0;


out_kfree_dev:
	kfree(dev);
out_unregister_drv:
	cpuidle_unregister_driver(drv);
out_kfree_drv:
out_kfree_drv:
	kfree(drv);
	kfree(drv);
	return ret;
	return ret;
@@ -178,9 +154,7 @@ out_fail:
	while (--cpu >= 0) {
	while (--cpu >= 0) {
		dev = per_cpu(cpuidle_devices, cpu);
		dev = per_cpu(cpuidle_devices, cpu);
		drv = cpuidle_get_cpu_driver(dev);
		drv = cpuidle_get_cpu_driver(dev);
		cpuidle_unregister_device(dev);
		cpuidle_unregister(drv);
		cpuidle_unregister_driver(drv);
		kfree(dev);
		kfree(drv);
		kfree(drv);
	}
	}