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:
parent
666151fd60
commit
d9a90463d3
5 changed files with 91 additions and 0 deletions
|
@ -313,6 +313,7 @@ apcc_cpr: cpr3-ctrl@99e8000 {
|
||||||
clock-names = "core_clk";
|
clock-names = "core_clk";
|
||||||
interrupts = <0 48 0>, <0 47 0>;
|
interrupts = <0 48 0>, <0 47 0>;
|
||||||
interrupt-names = "cpr", "ceiling";
|
interrupt-names = "cpr", "ceiling";
|
||||||
|
qcom,cpr-interrupt-affinity = <&CPU0 &CPU1>;
|
||||||
qcom,cpr-ctrl-name = "apcc";
|
qcom,cpr-ctrl-name = "apcc";
|
||||||
|
|
||||||
qcom,cpr-sensor-time = <1000>;
|
qcom,cpr-sensor-time = <1000>;
|
||||||
|
|
|
@ -104,6 +104,12 @@ Platform independent properties:
|
||||||
must be specified. "ceiling" may be specified for some
|
must be specified. "ceiling" may be specified for some
|
||||||
platforms.
|
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
|
- qcom,cpr-sensor-time
|
||||||
Usage: required
|
Usage: required
|
||||||
Value type: <u32>
|
Value type: <u32>
|
||||||
|
|
|
@ -5778,6 +5778,31 @@ int cpr3_regulator_resume(struct cpr3_controller *ctrl)
|
||||||
return 0;
|
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_regulator_validate_controller() - verify the data passed in via the
|
||||||
* cpr3_controller data structure
|
* 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);
|
mutex_lock(&cpr3_controller_list_mutex);
|
||||||
cpr3_regulator_debugfs_ctrl_add(ctrl);
|
cpr3_regulator_debugfs_ctrl_add(ctrl);
|
||||||
list_add(&ctrl->list, &cpr3_controller_list);
|
list_add(&ctrl->list, &cpr3_controller_list);
|
||||||
|
|
|
@ -535,6 +535,10 @@ struct cpr3_aging_sensor_info {
|
||||||
* @iface_clk: Pointer to the CPR3 interface clock (platform specific)
|
* @iface_clk: Pointer to the CPR3 interface clock (platform specific)
|
||||||
* @bus_clk: Pointer to the CPR3 bus clock (platform specific)
|
* @bus_clk: Pointer to the CPR3 bus clock (platform specific)
|
||||||
* @irq: CPR interrupt number
|
* @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
|
* @ceiling_irq: Interrupt number for the interrupt that is triggered
|
||||||
* when hardware closed-loop attempts to exceed the ceiling
|
* when hardware closed-loop attempts to exceed the ceiling
|
||||||
* voltage
|
* voltage
|
||||||
|
@ -695,6 +699,8 @@ struct cpr3_controller {
|
||||||
struct clk *iface_clk;
|
struct clk *iface_clk;
|
||||||
struct clk *bus_clk;
|
struct clk *bus_clk;
|
||||||
int irq;
|
int irq;
|
||||||
|
struct cpumask irq_affinity_mask;
|
||||||
|
struct notifier_block cpu_hotplug_notifier;
|
||||||
int ceiling_irq;
|
int ceiling_irq;
|
||||||
struct msm_apm_ctrl_dev *apm;
|
struct msm_apm_ctrl_dev *apm;
|
||||||
int apm_threshold_volt;
|
int apm_threshold_volt;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||||
|
|
||||||
|
#include <linux/cpumask.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -979,6 +980,46 @@ int cpr3_parse_common_thread_data(struct cpr3_thread *thread)
|
||||||
return rc;
|
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
|
* cpr3_parse_common_ctrl_data() - parse common CPR3 controller properties from
|
||||||
* device tree
|
* 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,
|
ctrl->cpr_allowed_sw = of_property_read_bool(ctrl->dev->of_node,
|
||||||
"qcom,cpr-enable");
|
"qcom,cpr-enable");
|
||||||
|
|
||||||
|
rc = cpr3_parse_irq_affinity(ctrl);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
/* Aging reference voltage is optional */
|
/* Aging reference voltage is optional */
|
||||||
ctrl->aging_ref_volt = 0;
|
ctrl->aging_ref_volt = 0;
|
||||||
of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage",
|
of_property_read_u32(ctrl->dev->of_node, "qcom,cpr-aging-ref-voltage",
|
||||||
|
|
Loading…
Add table
Reference in a new issue