regulator: cpr3-regulator: add support for configuring CPR IRQ affinity

Add support to configure the CPR interrupt affinity via a CPR3
controller device tree node.  This can be used to avoid servicing
CPR interrupts triggered by a CPU enterring power collapse on the
CPU that just power collapsed.

Change-Id: I4c04a2c255a6bd249c888c0dd0dbda19b8436be2
CRs-Fixed: 949650
Signed-off-by: David Collins <collinsd@codeaurora.org>
This commit is contained in:
David Collins 2015-12-01 16:49:41 -08:00 committed by Jeevan Shriram
parent 666151fd60
commit d9a90463d3
5 changed files with 91 additions and 0 deletions

View file

@ -313,6 +313,7 @@ apcc_cpr: cpr3-ctrl@99e8000 {
clock-names = "core_clk";
interrupts = <0 48 0>, <0 47 0>;
interrupt-names = "cpr", "ceiling";
qcom,cpr-interrupt-affinity = <&CPU0 &CPU1>;
qcom,cpr-ctrl-name = "apcc";
qcom,cpr-sensor-time = <1000>;

View file

@ -104,6 +104,12 @@ Platform independent properties:
must be specified. "ceiling" may be specified for some
platforms.
- qcom,cpr-interrupt-affinity
Usage: optional
Value type: <prop-encoded-array>
Definition: A list of CPU phandles which correspond to the cores that
the "cpr" interrupt should have affinity for.
- qcom,cpr-sensor-time
Usage: required
Value type: <u32>

View file

@ -5778,6 +5778,31 @@ int cpr3_regulator_resume(struct cpr3_controller *ctrl)
return 0;
}
/**
* cpr3_regulator_cpu_hotplug_callback() - reset CPR IRQ affinity when a CPU is
* brought online via hotplug
* @nb: Pointer to the notifier block
* @action: hotplug action
* @hcpu: long value corresponding to the CPU number
*
* Return: NOTIFY_OK
*/
static int cpr3_regulator_cpu_hotplug_callback(struct notifier_block *nb,
unsigned long action, void *hcpu)
{
struct cpr3_controller *ctrl = container_of(nb, struct cpr3_controller,
cpu_hotplug_notifier);
int cpu = (long)hcpu;
action &= ~CPU_TASKS_FROZEN;
if (action == CPU_ONLINE
&& cpumask_test_cpu(cpu, &ctrl->irq_affinity_mask))
irq_set_affinity(ctrl->irq, &ctrl->irq_affinity_mask);
return NOTIFY_OK;
}
/**
* cpr3_regulator_validate_controller() - verify the data passed in via the
* cpr3_controller data structure
@ -5975,6 +6000,14 @@ int cpr3_regulator_register(struct platform_device *pdev,
}
}
if (ctrl->irq && !cpumask_empty(&ctrl->irq_affinity_mask)) {
irq_set_affinity(ctrl->irq, &ctrl->irq_affinity_mask);
ctrl->cpu_hotplug_notifier.notifier_call
= cpr3_regulator_cpu_hotplug_callback;
register_hotcpu_notifier(&ctrl->cpu_hotplug_notifier);
}
mutex_lock(&cpr3_controller_list_mutex);
cpr3_regulator_debugfs_ctrl_add(ctrl);
list_add(&ctrl->list, &cpr3_controller_list);

View file

@ -535,6 +535,10 @@ struct cpr3_aging_sensor_info {
* @iface_clk: Pointer to the CPR3 interface clock (platform specific)
* @bus_clk: Pointer to the CPR3 bus clock (platform specific)
* @irq: CPR interrupt number
* @irq_affinity_mask: The cpumask for the CPUs which the CPR interrupt should
* have affinity for
* @cpu_hotplug_notifier: CPU hotplug notifier used to reset IRQ affinity when a
* CPU is brought back online
* @ceiling_irq: Interrupt number for the interrupt that is triggered
* when hardware closed-loop attempts to exceed the ceiling
* voltage
@ -695,6 +699,8 @@ struct cpr3_controller {
struct clk *iface_clk;
struct clk *bus_clk;
int irq;
struct cpumask irq_affinity_mask;
struct notifier_block cpu_hotplug_notifier;
int ceiling_irq;
struct msm_apm_ctrl_dev *apm;
int apm_threshold_volt;

View file

@ -18,6 +18,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/cpumask.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -979,6 +980,46 @@ int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
return rc;
}
/**
* cpr3_parse_irq_affinity() - parse CPR IRQ affinity information
* @ctrl: Pointer to the CPR3 controller
*
* Return: 0 on success, errno on failure
*/
static int cpr3_parse_irq_affinity(struct cpr3_controller *ctrl)
{
struct device_node *cpu_node;
int i, cpu;
int len = 0;
if (!of_find_property(ctrl->dev->of_node, "qcom,cpr-interrupt-affinity",
&len)) {
/* No IRQ affinity required */
return 0;
}
len /= sizeof(u32);
for (i = 0; i < len; i++) {
cpu_node = of_parse_phandle(ctrl->dev->of_node,
"qcom,cpr-interrupt-affinity", i);
if (!cpu_node) {
cpr3_err(ctrl, "could not find CPU node %d\n", i);
return -EINVAL;
}
for_each_possible_cpu(cpu) {
if (of_get_cpu_node(cpu, NULL) == cpu_node) {
cpumask_set_cpu(cpu, &ctrl->irq_affinity_mask);
break;
}
}
of_node_put(cpu_node);
}
return 0;
}
/**
* cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from
* device tree
@ -1045,6 +1086,10 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
ctrl->cpr_allowed_sw = of_property_read_bool(ctrl->dev->of_node,
"qcom,cpr-enable");
rc = cpr3_parse_irq_affinity(ctrl);
if (rc)
return rc;
/* Aging reference voltage is optional */
ctrl->aging_ref_volt = 0;
of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage",