Commit 5d1d9a29 authored by Mark Rutland's avatar Mark Rutland Committed by Thomas Gleixner

clockevents: Fix generic broadcast for FEAT_C3STOP

Commit 12ad1000: "clockevents: Add generic timer broadcast function"
made tick_device_uses_broadcast set up the generic broadcast function
for dummy devices (where !tick_device_is_functional(dev)), but neglected
to set up the broadcast function for devices that stop in low power
states (with the CLOCK_EVT_FEAT_C3STOP flag).

When these devices enter low power states they will not have the generic
broadcast function assigned, and will bring down the system when an
attempt is made to broadcast to them.

This patch ensures that the broadcast function is also assigned for
devices which require broadcast in low power states.
Reported-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: nico@linaro.org
Cc: Marc.Zyngier@arm.com
Cc: Will.Deacon@arm.com
Cc: santosh.shilimkar@ti.com
Cc: john.stultz@linaro.org
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 12ad1000
...@@ -92,6 +92,17 @@ static void err_broadcast(const struct cpumask *mask) ...@@ -92,6 +92,17 @@ static void err_broadcast(const struct cpumask *mask)
pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n"); pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
} }
static void tick_device_setup_broadcast_func(struct clock_event_device *dev)
{
if (!dev->broadcast)
dev->broadcast = tick_broadcast;
if (!dev->broadcast) {
pr_warn_once("%s depends on broadcast, but no broadcast function available\n",
dev->name);
dev->broadcast = err_broadcast;
}
}
/* /*
* Check, if the device is disfunctional and a place holder, which * Check, if the device is disfunctional and a place holder, which
* needs to be handled by the broadcast device. * needs to be handled by the broadcast device.
...@@ -111,13 +122,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) ...@@ -111,13 +122,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
*/ */
if (!tick_device_is_functional(dev)) { if (!tick_device_is_functional(dev)) {
dev->event_handler = tick_handle_periodic; dev->event_handler = tick_handle_periodic;
if (!dev->broadcast) tick_device_setup_broadcast_func(dev);
dev->broadcast = tick_broadcast;
if (!dev->broadcast) {
pr_warn_once("%s depends on broadcast, but no broadcast function available\n",
dev->name);
dev->broadcast = err_broadcast;
}
cpumask_set_cpu(cpu, tick_get_broadcast_mask()); cpumask_set_cpu(cpu, tick_get_broadcast_mask());
tick_broadcast_start_periodic(tick_broadcast_device.evtdev); tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
ret = 1; ret = 1;
...@@ -129,9 +134,10 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) ...@@ -129,9 +134,10 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
*/ */
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
cpumask_clear_cpu(cpu, tick_get_broadcast_mask()); cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
tick_broadcast_clear_oneshot(cpu); tick_broadcast_clear_oneshot(cpu);
} else {
tick_device_setup_broadcast_func(dev);
} }
} }
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment