Пример #1
0
static int epit_set_oneshot(struct clock_event_device *evt)
{
	unsigned long flags;

	/*
	 * The timer interrupt generation is disabled at least
	 * for enough time to call epit_set_next_event()
	 */
	local_irq_save(flags);

	/* Disable interrupt in GPT module */
	epit_irq_disable();

	/* Clear pending interrupt, only while switching mode */
	if (!clockevent_state_oneshot(evt))
		epit_irq_acknowledge();

	/*
	 * Do not put overhead of interrupt enable/disable into
	 * epit_set_next_event(), the core has about 4 minutes
	 * to call epit_set_next_event() or shutdown clock after
	 * mode switching
	 */
	epit_irq_enable();
	local_irq_restore(flags);

	return 0;
}
Пример #2
0
/*
 * Event handler for periodic broadcast ticks
 */
static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
{
	struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
	bool bc_local;

	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();

	if (clockevent_state_oneshot(dev)) {
		ktime_t next = ktime_add(dev->next_event, tick_period);

		clockevents_program_event(dev, next, true);
	}
	raw_spin_unlock(&tick_broadcast_lock);

	/*
	 * We run the handler of the local cpu after dropping
	 * tick_broadcast_lock because the handler might deadlock when
	 * trying to switch to oneshot mode.
	 */
	if (bc_local)
		td->evtdev->event_handler(td->evtdev);
}
Пример #3
0
static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
{
    struct clock_event_device *evt = dev_id;

    if (!(readl_relaxed(gt_base + GT_INT_STATUS) &
            GT_INT_STATUS_EVENT_FLAG))
        return IRQ_NONE;

    /**
     * ERRATA 740657( Global Timer can send 2 interrupts for
     * the same event in single-shot mode)
     * Workaround:
     *	Either disable single-shot mode.
     *	Or
     *	Modify the Interrupt Handler to avoid the
     *	offending sequence. This is achieved by clearing
     *	the Global Timer flag _after_ having incremented
     *	the Comparator register	value to a higher value.
     */
    if (clockevent_state_oneshot(evt))
        gt_compare_set(ULONG_MAX, 0);

    writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
    evt->event_handler(evt);

    return IRQ_HANDLED;
}
Пример #4
0
static void tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
				     ktime_t expires)
{
	if (!clockevent_state_oneshot(bc))
		clockevents_switch_state(bc, CLOCK_EVT_STATE_ONESHOT);

	clockevents_program_event(bc, expires, 1);
	tick_broadcast_set_affinity(bc, cpumask_of(cpu));
}
Пример #5
0
static int timer8_clock_event_next(unsigned long delta,
				   struct clock_event_device *ced)
{
	struct timer8_priv *p = ced_to_priv(ced);

	BUG_ON(!clockevent_state_oneshot(ced));
	timer8_set_next(p, delta - 1);

	return 0;
}
Пример #6
0
static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = dev_id;
	/* Stop the timer tick */
	if (clockevent_state_oneshot(evt)) {
		u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
		ctrl &= ~TIMER_ENABLE_EN;
		writel_relaxed(ctrl, event_base + TIMER_ENABLE);
	}
	evt->event_handler(evt);
	return IRQ_HANDLED;
}
Пример #7
0
static irqreturn_t timer8_interrupt(int irq, void *dev_id)
{
	struct timer8_priv *p = dev_id;

	if (clockevent_state_oneshot(&p->ced))
		iowrite16be(0x0000, p->mapbase + _8TCR);

	p->ced.event_handler(&p->ced);

	bclr(CMFA, p->mapbase + _8TCSR);

	return IRQ_HANDLED;
}
Пример #8
0
static int xen_timerop_set_next_event(unsigned long delta,
				      struct clock_event_device *evt)
{
	WARN_ON(!clockevent_state_oneshot(evt));

	if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
		BUG();

	/* We may have missed the deadline, but there's no real way of
	   knowing for sure.  If the event was in the past, then we'll
	   get an immediate interrupt. */

	return 0;
}
Пример #9
0
static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = dev_id;

	ftm_irq_acknowledge(priv->clkevt_base);

	if (likely(clockevent_state_oneshot(evt))) {
		ftm_irq_disable(priv->clkevt_base);
		ftm_counter_disable(priv->clkevt_base);
	}

	evt->event_handler(evt);

	return IRQ_HANDLED;
}
Пример #10
0
/* timer interrupt handler */
static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *ce = dev_id;
	int cpu = smp_processor_id();

	/* clear timer interrupt */
	writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);

	if (clockevent_state_oneshot(ce))
		sirfsoc_timer_count_disable(cpu);

	ce->event_handler(ce);

	return IRQ_HANDLED;
}
Пример #11
0
static int xen_vcpuop_set_next_event(unsigned long delta,
				     struct clock_event_device *evt)
{
	int cpu = smp_processor_id();
	struct vcpu_set_singleshot_timer single;
	int ret;

	WARN_ON(!clockevent_state_oneshot(evt));

	single.timeout_abs_ns = get_abs_timeout(delta);
	single.flags = VCPU_SSHOTTMR_future;

	ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);

	BUG_ON(ret != 0 && ret != -ETIME);

	return ret;
}
Пример #12
0
static int xen_vcpuop_set_next_event(unsigned long delta,
				     struct clock_event_device *evt)
{
	int cpu = smp_processor_id();
	struct vcpu_set_singleshot_timer single;
	int ret;

	WARN_ON(!clockevent_state_oneshot(evt));

	single.timeout_abs_ns = get_abs_timeout(delta);
	/* Get an event anyway, even if the timeout is already expired */
	single.flags = 0;

	ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
	BUG_ON(ret != 0);

	return ret;
}
Пример #13
0
static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
{
    struct clock_event_device *evt = dev_id;

    pit_irq_acknowledge();

    /*
     * pit hardware doesn't support oneshot, it will generate an interrupt
     * and reload the counter value from PITLDVAL when PITCVAL reach zero,
     * and start the counter again. So software need to disable the timer
     * to stop the counter loop in ONESHOT mode.
     */
    if (likely(clockevent_state_oneshot(evt)))
        pit_timer_disable();

    evt->event_handler(evt);

    return IRQ_HANDLED;
}
Пример #14
0
/*
 * Event handler for periodic ticks
 */
void tick_handle_periodic(struct clock_event_device *dev)
{
	int cpu = smp_processor_id();
	ktime_t next = dev->next_event;

	tick_periodic(cpu);

#if defined(CONFIG_HIGH_RES_TIMERS) || defined(CONFIG_NO_HZ_COMMON)
	/*
	 * The cpu might have transitioned to HIGHRES or NOHZ mode via
	 * update_process_times() -> run_local_timers() ->
	 * hrtimer_run_queues().
	 */
	if (dev->event_handler != tick_handle_periodic)
		return;
#endif

	if (!clockevent_state_oneshot(dev))
		return;
	for (;;) {
		/*
		 * Setup the next period for devices, which do not have
		 * periodic mode:
		 */
		next = ktime_add(next, tick_period);

		if (!clockevents_program_event(dev, next, false))
			return;
		/*
		 * Have to be careful here. If we're in oneshot mode,
		 * before we call tick_periodic() in a loop, we need
		 * to be sure we're using a real hardware clocksource.
		 * Otherwise we could get trapped in an infinite
		 * loop, as the tick_periodic() increments jiffies,
		 * which then will increment time, possibly causing
		 * the loop to trigger again and again.
		 */
		if (timekeeping_valid_for_hres())
			tick_periodic(cpu);
	}
}