Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fixes from Thomas Gleixner: "This update from the timer departement contains: - A series of patches which address a shortcoming in the tick broadcast code. If the broadcast device is not available or an hrtimer emulated broadcast device, some of the original assumptions lead to boot failures. I rather plugged all of the corner cases instead of only addressing the issue reported, so the change got a little larger. Has been extensivly tested on x86 and arm. - Get rid of the last holdouts using do_posix_clock_monotonic_gettime() - A regression fix for the imx clocksource driver - An update to the new state callbacks mechanism for clockevents. This is required to simplify the conversion, which will take place in 4.3" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: tick/broadcast: Prevent NULL pointer dereference time: Get rid of do_posix_clock_monotonic_gettime cris: Replace do_posix_clock_monotonic_gettime() tick/broadcast: Unbreak CONFIG_GENERIC_CLOCKEVENTS=n build tick/broadcast: Handle spurious interrupts gracefully tick/broadcast: Check for hrtimer broadcast active early tick/broadcast: Return busy when IPI is pending tick/broadcast: Return busy if periodic mode and hrtimer broadcast tick/broadcast: Move the check for periodic mode inside state handling tick/broadcast: Prevent deep idle if no broadcast device available tick/broadcast: Make idle check independent from mode and config tick/broadcast: Sanity check the shutdown of the local clock_event tick/broadcast: Prevent hrtimer recursion clockevents: Allow set-state callbacks to be optional clocksource/imx: Define clocksource for mx27
This commit is contained in:
Коммит
7b732169e9
|
@ -1464,7 +1464,7 @@ static inline void handle_rx_packet(struct sync_port *port)
|
||||||
if (port->write_ts_idx == NBR_IN_DESCR)
|
if (port->write_ts_idx == NBR_IN_DESCR)
|
||||||
port->write_ts_idx = 0;
|
port->write_ts_idx = 0;
|
||||||
idx = port->write_ts_idx++;
|
idx = port->write_ts_idx++;
|
||||||
do_posix_clock_monotonic_gettime(&port->timestamp[idx]);
|
ktime_get_ts(&port->timestamp[idx]);
|
||||||
port->in_buffer_len += port->inbufchunk;
|
port->in_buffer_len += port->inbufchunk;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
|
|
@ -529,6 +529,7 @@ static void __init imx6dl_timer_init_dt(struct device_node *np)
|
||||||
|
|
||||||
CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
|
CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
|
||||||
CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
|
CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
|
||||||
|
CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
|
||||||
CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
|
CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
|
||||||
CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
|
CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
|
||||||
CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
|
CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
|
||||||
|
|
|
@ -67,10 +67,13 @@ extern void tick_broadcast_control(enum tick_broadcast_mode mode);
|
||||||
static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { }
|
static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { }
|
||||||
#endif /* BROADCAST */
|
#endif /* BROADCAST */
|
||||||
|
|
||||||
#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
|
#ifdef CONFIG_GENERIC_CLOCKEVENTS
|
||||||
extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state);
|
extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state);
|
||||||
#else
|
#else
|
||||||
static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state) { return 0; }
|
static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void tick_broadcast_enable(void)
|
static inline void tick_broadcast_enable(void)
|
||||||
|
|
|
@ -145,7 +145,6 @@ static inline void getboottime(struct timespec *ts)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
|
|
||||||
#define ktime_get_real_ts64(ts) getnstimeofday64(ts)
|
#define ktime_get_real_ts64(ts) getnstimeofday64(ts)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -120,19 +120,25 @@ static int __clockevents_switch_state(struct clock_event_device *dev,
|
||||||
/* The clockevent device is getting replaced. Shut it down. */
|
/* The clockevent device is getting replaced. Shut it down. */
|
||||||
|
|
||||||
case CLOCK_EVT_STATE_SHUTDOWN:
|
case CLOCK_EVT_STATE_SHUTDOWN:
|
||||||
|
if (dev->set_state_shutdown)
|
||||||
return dev->set_state_shutdown(dev);
|
return dev->set_state_shutdown(dev);
|
||||||
|
return 0;
|
||||||
|
|
||||||
case CLOCK_EVT_STATE_PERIODIC:
|
case CLOCK_EVT_STATE_PERIODIC:
|
||||||
/* Core internal bug */
|
/* Core internal bug */
|
||||||
if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
|
if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
if (dev->set_state_periodic)
|
||||||
return dev->set_state_periodic(dev);
|
return dev->set_state_periodic(dev);
|
||||||
|
return 0;
|
||||||
|
|
||||||
case CLOCK_EVT_STATE_ONESHOT:
|
case CLOCK_EVT_STATE_ONESHOT:
|
||||||
/* Core internal bug */
|
/* Core internal bug */
|
||||||
if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
|
if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
if (dev->set_state_oneshot)
|
||||||
return dev->set_state_oneshot(dev);
|
return dev->set_state_oneshot(dev);
|
||||||
|
return 0;
|
||||||
|
|
||||||
case CLOCK_EVT_STATE_ONESHOT_STOPPED:
|
case CLOCK_EVT_STATE_ONESHOT_STOPPED:
|
||||||
/* Core internal bug */
|
/* Core internal bug */
|
||||||
|
@ -471,18 +477,6 @@ static int clockevents_sanity_check(struct clock_event_device *dev)
|
||||||
if (dev->features & CLOCK_EVT_FEAT_DUMMY)
|
if (dev->features & CLOCK_EVT_FEAT_DUMMY)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* New state-specific callbacks */
|
|
||||||
if (!dev->set_state_shutdown)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
|
|
||||||
!dev->set_state_periodic)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) &&
|
|
||||||
!dev->set_state_oneshot)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
|
||||||
{
|
{
|
||||||
struct clock_event_device *bc = tick_broadcast_device.evtdev;
|
struct clock_event_device *bc = tick_broadcast_device.evtdev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||||
|
|
||||||
|
@ -221,13 +221,14 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
|
||||||
* If we kept the cpu in the broadcast mask,
|
* If we kept the cpu in the broadcast mask,
|
||||||
* tell the caller to leave the per cpu device
|
* tell the caller to leave the per cpu device
|
||||||
* in shutdown state. The periodic interrupt
|
* in shutdown state. The periodic interrupt
|
||||||
* is delivered by the broadcast device.
|
* is delivered by the broadcast device, if
|
||||||
|
* the broadcast device exists and is not
|
||||||
|
* hrtimer based.
|
||||||
*/
|
*/
|
||||||
|
if (bc && !(bc->features & CLOCK_EVT_FEAT_HRTIMER))
|
||||||
ret = cpumask_test_cpu(cpu, tick_broadcast_mask);
|
ret = cpumask_test_cpu(cpu, tick_broadcast_mask);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Nothing to do */
|
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,8 +266,22 @@ static bool tick_do_broadcast(struct cpumask *mask)
|
||||||
* Check, if the current cpu is in the mask
|
* Check, if the current cpu is in the mask
|
||||||
*/
|
*/
|
||||||
if (cpumask_test_cpu(cpu, mask)) {
|
if (cpumask_test_cpu(cpu, mask)) {
|
||||||
|
struct clock_event_device *bc = tick_broadcast_device.evtdev;
|
||||||
|
|
||||||
cpumask_clear_cpu(cpu, mask);
|
cpumask_clear_cpu(cpu, mask);
|
||||||
local = true;
|
/*
|
||||||
|
* We only run the local handler, if the broadcast
|
||||||
|
* device is not hrtimer based. Otherwise we run into
|
||||||
|
* a hrtimer recursion.
|
||||||
|
*
|
||||||
|
* local timer_interrupt()
|
||||||
|
* local_handler()
|
||||||
|
* expire_hrtimers()
|
||||||
|
* bc_handler()
|
||||||
|
* local_handler()
|
||||||
|
* expire_hrtimers()
|
||||||
|
*/
|
||||||
|
local = !(bc->features & CLOCK_EVT_FEAT_HRTIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpumask_empty(mask)) {
|
if (!cpumask_empty(mask)) {
|
||||||
|
@ -301,6 +316,13 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
|
||||||
bool bc_local;
|
bool bc_local;
|
||||||
|
|
||||||
raw_spin_lock(&tick_broadcast_lock);
|
raw_spin_lock(&tick_broadcast_lock);
|
||||||
|
|
||||||
|
/* Handle spurious interrupts gracefully */
|
||||||
|
if (clockevent_state_shutdown(tick_broadcast_device.evtdev)) {
|
||||||
|
raw_spin_unlock(&tick_broadcast_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bc_local = tick_do_periodic_broadcast();
|
bc_local = tick_do_periodic_broadcast();
|
||||||
|
|
||||||
if (clockevent_state_oneshot(dev)) {
|
if (clockevent_state_oneshot(dev)) {
|
||||||
|
@ -359,8 +381,16 @@ void tick_broadcast_control(enum tick_broadcast_mode mode)
|
||||||
case TICK_BROADCAST_ON:
|
case TICK_BROADCAST_ON:
|
||||||
cpumask_set_cpu(cpu, tick_broadcast_on);
|
cpumask_set_cpu(cpu, tick_broadcast_on);
|
||||||
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
|
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
|
||||||
if (tick_broadcast_device.mode ==
|
/*
|
||||||
TICKDEV_MODE_PERIODIC)
|
* Only shutdown the cpu local device, if:
|
||||||
|
*
|
||||||
|
* - the broadcast device exists
|
||||||
|
* - the broadcast device is not a hrtimer based one
|
||||||
|
* - the broadcast device is in periodic mode to
|
||||||
|
* avoid a hickup during switch to oneshot mode
|
||||||
|
*/
|
||||||
|
if (bc && !(bc->features & CLOCK_EVT_FEAT_HRTIMER) &&
|
||||||
|
tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
|
||||||
clockevents_shutdown(dev);
|
clockevents_shutdown(dev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -379,6 +409,7 @@ void tick_broadcast_control(enum tick_broadcast_mode mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bc) {
|
||||||
if (cpumask_empty(tick_broadcast_mask)) {
|
if (cpumask_empty(tick_broadcast_mask)) {
|
||||||
if (!bc_stopped)
|
if (!bc_stopped)
|
||||||
clockevents_shutdown(bc);
|
clockevents_shutdown(bc);
|
||||||
|
@ -388,6 +419,7 @@ void tick_broadcast_control(enum tick_broadcast_mode mode)
|
||||||
else
|
else
|
||||||
tick_broadcast_setup_oneshot(bc);
|
tick_broadcast_setup_oneshot(bc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
raw_spin_unlock(&tick_broadcast_lock);
|
raw_spin_unlock(&tick_broadcast_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tick_broadcast_control);
|
EXPORT_SYMBOL_GPL(tick_broadcast_control);
|
||||||
|
@ -662,71 +694,82 @@ static void broadcast_shutdown_local(struct clock_event_device *bc,
|
||||||
clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
|
clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
||||||
* tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
|
|
||||||
* @state: The target state (enter/exit)
|
|
||||||
*
|
|
||||||
* The system enters/leaves a state, where affected devices might stop
|
|
||||||
* Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
|
|
||||||
*
|
|
||||||
* Called with interrupts disabled, so clockevents_lock is not
|
|
||||||
* required here because the local clock event device cannot go away
|
|
||||||
* under us.
|
|
||||||
*/
|
|
||||||
int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
|
||||||
{
|
{
|
||||||
struct clock_event_device *bc, *dev;
|
struct clock_event_device *bc, *dev;
|
||||||
struct tick_device *td;
|
|
||||||
int cpu, ret = 0;
|
int cpu, ret = 0;
|
||||||
ktime_t now;
|
ktime_t now;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Periodic mode does not care about the enter/exit of power
|
* If there is no broadcast device, tell the caller not to go
|
||||||
* states
|
* into deep idle.
|
||||||
*/
|
*/
|
||||||
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
|
if (!tick_broadcast_device.evtdev)
|
||||||
return 0;
|
return -EBUSY;
|
||||||
|
|
||||||
/*
|
dev = this_cpu_ptr(&tick_cpu_device)->evtdev;
|
||||||
* We are called with preemtion disabled from the depth of the
|
|
||||||
* idle code, so we can't be moved away.
|
|
||||||
*/
|
|
||||||
td = this_cpu_ptr(&tick_cpu_device);
|
|
||||||
dev = td->evtdev;
|
|
||||||
|
|
||||||
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
raw_spin_lock(&tick_broadcast_lock);
|
raw_spin_lock(&tick_broadcast_lock);
|
||||||
bc = tick_broadcast_device.evtdev;
|
bc = tick_broadcast_device.evtdev;
|
||||||
cpu = smp_processor_id();
|
cpu = smp_processor_id();
|
||||||
|
|
||||||
if (state == TICK_BROADCAST_ENTER) {
|
if (state == TICK_BROADCAST_ENTER) {
|
||||||
|
/*
|
||||||
|
* If the current CPU owns the hrtimer broadcast
|
||||||
|
* mechanism, it cannot go deep idle and we do not add
|
||||||
|
* the CPU to the broadcast mask. We don't have to go
|
||||||
|
* through the EXIT path as the local timer is not
|
||||||
|
* shutdown.
|
||||||
|
*/
|
||||||
|
ret = broadcast_needs_cpu(bc, cpu);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the broadcast device is in periodic mode, we
|
||||||
|
* return.
|
||||||
|
*/
|
||||||
|
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
|
||||||
|
/* If it is a hrtimer based broadcast, return busy */
|
||||||
|
if (bc->features & CLOCK_EVT_FEAT_HRTIMER)
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
|
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
|
||||||
WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
|
WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
|
||||||
|
|
||||||
|
/* Conditionally shut down the local timer. */
|
||||||
broadcast_shutdown_local(bc, dev);
|
broadcast_shutdown_local(bc, dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only reprogram the broadcast timer if we
|
* We only reprogram the broadcast timer if we
|
||||||
* did not mark ourself in the force mask and
|
* did not mark ourself in the force mask and
|
||||||
* if the cpu local event is earlier than the
|
* if the cpu local event is earlier than the
|
||||||
* broadcast event. If the current CPU is in
|
* broadcast event. If the current CPU is in
|
||||||
* the force mask, then we are going to be
|
* the force mask, then we are going to be
|
||||||
* woken by the IPI right away.
|
* woken by the IPI right away; we return
|
||||||
|
* busy, so the CPU does not try to go deep
|
||||||
|
* idle.
|
||||||
*/
|
*/
|
||||||
if (!cpumask_test_cpu(cpu, tick_broadcast_force_mask) &&
|
if (cpumask_test_cpu(cpu, tick_broadcast_force_mask)) {
|
||||||
dev->next_event.tv64 < bc->next_event.tv64)
|
ret = -EBUSY;
|
||||||
|
} else if (dev->next_event.tv64 < bc->next_event.tv64) {
|
||||||
tick_broadcast_set_event(bc, cpu, dev->next_event);
|
tick_broadcast_set_event(bc, cpu, dev->next_event);
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* If the current CPU owns the hrtimer broadcast
|
* In case of hrtimer broadcasts the
|
||||||
* mechanism, it cannot go deep idle and we remove the
|
* programming might have moved the
|
||||||
* CPU from the broadcast mask. We don't have to go
|
* timer to this cpu. If yes, remove
|
||||||
* through the EXIT path as the local timer is not
|
* us from the broadcast mask and
|
||||||
* shutdown.
|
* return busy.
|
||||||
*/
|
*/
|
||||||
ret = broadcast_needs_cpu(bc, cpu);
|
ret = broadcast_needs_cpu(bc, cpu);
|
||||||
if (ret)
|
if (ret) {
|
||||||
cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
|
cpumask_clear_cpu(cpu,
|
||||||
|
tick_broadcast_oneshot_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
|
if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
|
||||||
clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
|
clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
|
||||||
|
@ -938,6 +981,16 @@ bool tick_broadcast_oneshot_available(void)
|
||||||
return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false;
|
return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
||||||
|
{
|
||||||
|
struct clock_event_device *bc = tick_broadcast_device.evtdev;
|
||||||
|
|
||||||
|
if (!bc || (bc->features & CLOCK_EVT_FEAT_HRTIMER))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __init tick_broadcast_init(void)
|
void __init tick_broadcast_init(void)
|
||||||
|
|
|
@ -343,6 +343,27 @@ out_bc:
|
||||||
tick_install_broadcast_device(newdev);
|
tick_install_broadcast_device(newdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
|
||||||
|
* @state: The target state (enter/exit)
|
||||||
|
*
|
||||||
|
* The system enters/leaves a state, where affected devices might stop
|
||||||
|
* Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
|
||||||
|
*
|
||||||
|
* Called with interrupts disabled, so clockevents_lock is not
|
||||||
|
* required here because the local clock event device cannot go away
|
||||||
|
* under us.
|
||||||
|
*/
|
||||||
|
int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
||||||
|
{
|
||||||
|
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
|
||||||
|
|
||||||
|
if (!(td->evtdev->features & CLOCK_EVT_FEAT_C3STOP))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return __tick_broadcast_oneshot_control(state);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
/*
|
/*
|
||||||
* Transfer the do_timer job away from a dying cpu.
|
* Transfer the do_timer job away from a dying cpu.
|
||||||
|
|
|
@ -71,4 +71,14 @@ extern void tick_cancel_sched_timer(int cpu);
|
||||||
static inline void tick_cancel_sched_timer(int cpu) { }
|
static inline void tick_cancel_sched_timer(int cpu) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||||
|
extern int __tick_broadcast_oneshot_control(enum tick_broadcast_state state);
|
||||||
|
#else
|
||||||
|
static inline int
|
||||||
|
__tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
||||||
|
{
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче