Commit 3c05acc3 authored by Philippe Gerum's avatar Philippe Gerum

ipipe: tick: perform per-cpu ops in the target CPU context

parent 932b8347
...@@ -390,30 +390,35 @@ static int do_set_shutdown(struct clock_event_device *cdev) ...@@ -390,30 +390,35 @@ static int do_set_shutdown(struct clock_event_device *cdev)
int clockevents_program_event(struct clock_event_device *dev, int clockevents_program_event(struct clock_event_device *dev,
ktime_t expires, bool force); ktime_t expires, bool force);
int ipipe_timer_start(void (*tick_handler)(void), struct grab_timer_data {
void (*emumode)(enum clock_event_mode mode, void (*tick_handler)(void);
struct clock_event_device *cdev), void (*emumode)(enum clock_event_mode mode,
int (*emutick)(unsigned long evt, struct clock_event_device *cdev);
struct clock_event_device *cdev), int (*emutick)(unsigned long evt,
unsigned cpu) struct clock_event_device *cdev);
int retval;
};
static void grab_timer(void *arg)
{ {
struct grab_timer_data *data = arg;
struct clock_event_device *evtdev; struct clock_event_device *evtdev;
struct ipipe_timer *timer; struct ipipe_timer *timer;
struct irq_desc *desc; struct irq_desc *desc;
unsigned long flags; unsigned long flags;
int steal, ret; int steal, ret;
timer = per_cpu(percpu_timer, cpu); flags = hard_local_irq_save();
evtdev = timer->host_timer;
flags = ipipe_critical_enter(NULL);
timer = this_cpu_read(percpu_timer);
evtdev = timer->host_timer;
ret = ipipe_request_irq(ipipe_head_domain, timer->irq, ret = ipipe_request_irq(ipipe_head_domain, timer->irq,
(ipipe_irq_handler_t)tick_handler, (ipipe_irq_handler_t)data->tick_handler,
NULL, __ipipe_ack_hrtimer_irq); NULL, __ipipe_ack_hrtimer_irq);
if (ret < 0 && ret != -EBUSY) { if (ret < 0 && ret != -EBUSY) {
ipipe_critical_exit(flags); hard_local_irq_restore(flags);
return ret; data->retval = ret;
return;
} }
steal = evtdev != NULL && !clockevent_state_detached(evtdev); steal = evtdev != NULL && !clockevent_state_detached(evtdev);
...@@ -425,7 +430,7 @@ int ipipe_timer_start(void (*tick_handler)(void), ...@@ -425,7 +430,7 @@ int ipipe_timer_start(void (*tick_handler)(void),
timer->orig_set_state_oneshot_stopped = evtdev->set_state_oneshot_stopped; timer->orig_set_state_oneshot_stopped = evtdev->set_state_oneshot_stopped;
timer->orig_set_state_shutdown = evtdev->set_state_shutdown; timer->orig_set_state_shutdown = evtdev->set_state_shutdown;
timer->orig_set_next_event = evtdev->set_next_event; timer->orig_set_next_event = evtdev->set_next_event;
timer->mode_handler = emumode; timer->mode_handler = data->emumode;
evtdev->mult = 1; evtdev->mult = 1;
evtdev->shift = 0; evtdev->shift = 0;
evtdev->max_delta_ns = UINT_MAX; evtdev->max_delta_ns = UINT_MAX;
...@@ -433,60 +438,83 @@ int ipipe_timer_start(void (*tick_handler)(void), ...@@ -433,60 +438,83 @@ int ipipe_timer_start(void (*tick_handler)(void),
evtdev->set_state_oneshot = do_set_oneshot; evtdev->set_state_oneshot = do_set_oneshot;
evtdev->set_state_oneshot_stopped = do_set_oneshot; evtdev->set_state_oneshot_stopped = do_set_oneshot;
evtdev->set_state_shutdown = do_set_shutdown; evtdev->set_state_shutdown = do_set_shutdown;
evtdev->set_next_event = emutick; evtdev->set_next_event = data->emutick;
evtdev->ipipe_stolen = 1; evtdev->ipipe_stolen = 1;
} }
ret = get_dev_mode(evtdev); hard_local_irq_restore(flags);
ipipe_critical_exit(flags); data->retval = get_dev_mode(evtdev);
desc = irq_to_desc(timer->irq); desc = irq_to_desc(timer->irq);
if (desc && irqd_irq_disabled(&desc->irq_data)) if (desc && irqd_irq_disabled(&desc->irq_data))
ipipe_enable_irq(timer->irq); ipipe_enable_irq(timer->irq);
local_irq_save(flags); if (evtdev->ipipe_stolen && clockevent_state_oneshot(evtdev)) {
if (evtdev->ipipe_stolen && clockevent_state_oneshot(evtdev))
ret = clockevents_program_event(evtdev, ret = clockevents_program_event(evtdev,
evtdev->next_event, true); evtdev->next_event, true);
local_irq_restore(flags); if (ret)
data->retval = ret;
}
}
return ret; int ipipe_timer_start(void (*tick_handler)(void),
void (*emumode)(enum clock_event_mode mode,
struct clock_event_device *cdev),
int (*emutick)(unsigned long evt,
struct clock_event_device *cdev),
unsigned int cpu)
{
struct grab_timer_data data;
int ret;
data.tick_handler = tick_handler;
data.emutick = emutick;
data.emumode = emumode;
data.retval = -EINVAL;
ret = smp_call_function_single(cpu, grab_timer, &data, true);
return ret ?: data.retval;
} }
void ipipe_timer_stop(unsigned cpu) static void release_timer(void *arg)
{ {
unsigned long __maybe_unused flags;
struct clock_event_device *evtdev; struct clock_event_device *evtdev;
struct ipipe_timer *timer; struct ipipe_timer *timer;
struct irq_desc *desc; struct irq_desc *desc;
unsigned long flags;
timer = per_cpu(percpu_timer, cpu); flags = hard_local_irq_save();
evtdev = timer->host_timer;
timer = this_cpu_read(percpu_timer);
desc = irq_to_desc(timer->irq); desc = irq_to_desc(timer->irq);
if (desc && irqd_irq_disabled(&desc->irq_data)) if (desc && irqd_irq_disabled(&desc->irq_data))
ipipe_disable_irq(timer->irq); ipipe_disable_irq(timer->irq);
if (evtdev) { ipipe_free_irq(ipipe_head_domain, timer->irq);
flags = ipipe_critical_enter(NULL);
if (evtdev->ipipe_stolen) {
evtdev->mult = timer->real_mult;
evtdev->shift = timer->real_shift;
evtdev->set_state_periodic = timer->orig_set_state_periodic;
evtdev->set_state_oneshot = timer->orig_set_state_oneshot;
evtdev->set_state_oneshot_stopped = timer->orig_set_state_oneshot_stopped;
evtdev->set_state_shutdown = timer->orig_set_state_shutdown;
evtdev->set_next_event = timer->orig_set_next_event;
evtdev->ipipe_stolen = 0;
}
ipipe_critical_exit(flags); evtdev = timer->host_timer;
} if (evtdev && evtdev->ipipe_stolen) {
evtdev->mult = timer->real_mult;
evtdev->shift = timer->real_shift;
evtdev->set_state_periodic = timer->orig_set_state_periodic;
evtdev->set_state_oneshot = timer->orig_set_state_oneshot;
evtdev->set_state_oneshot_stopped = timer->orig_set_state_oneshot_stopped;
evtdev->set_state_shutdown = timer->orig_set_state_shutdown;
evtdev->set_next_event = timer->orig_set_next_event;
evtdev->ipipe_stolen = 0;
hard_local_irq_restore(flags);
if (clockevent_state_oneshot(evtdev))
clockevents_program_event(evtdev,
evtdev->next_event, true);
} else
hard_local_irq_restore(flags);
}
ipipe_free_irq(ipipe_head_domain, timer->irq); void ipipe_timer_stop(unsigned int cpu)
{
smp_call_function_single(cpu, release_timer, NULL, true);
} }
void ipipe_timer_set(unsigned long cdelay) void ipipe_timer_set(unsigned long cdelay)
......
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