Path: blob/master/arch/mn10300/kernel/cevt-mn10300.c
10817 views
/* MN10300 clockevents1*2* Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.3* Written by Mark Salter ([email protected])4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public Licence7* as published by the Free Software Foundation; either version8* 2 of the Licence, or (at your option) any later version.9*/10#include <linux/clockchips.h>11#include <linux/interrupt.h>12#include <linux/percpu.h>13#include <linux/smp.h>14#include <asm/timex.h>15#include "internal.h"1617#ifdef CONFIG_SMP18#if (CONFIG_NR_CPUS > 2) && !defined(CONFIG_GEENERIC_CLOCKEVENTS_BROADCAST)19#error "This doesn't scale well! Need per-core local timers."20#endif21#else /* CONFIG_SMP */22#define stop_jiffies_counter1()23#define reload_jiffies_counter1(x)24#define TMJC1IRQ TMJCIRQ25#endif262728static int next_event(unsigned long delta,29struct clock_event_device *evt)30{31unsigned int cpu = smp_processor_id();3233if (cpu == 0) {34stop_jiffies_counter();35reload_jiffies_counter(delta - 1);36} else {37stop_jiffies_counter1();38reload_jiffies_counter1(delta - 1);39}40return 0;41}4243static void set_clock_mode(enum clock_event_mode mode,44struct clock_event_device *evt)45{46/* Nothing to do ... */47}4849static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device);50static DEFINE_PER_CPU(struct irqaction, timer_irq);5152static irqreturn_t timer_interrupt(int irq, void *dev_id)53{54struct clock_event_device *cd;55unsigned int cpu = smp_processor_id();5657if (cpu == 0)58stop_jiffies_counter();59else60stop_jiffies_counter1();6162cd = &per_cpu(mn10300_clockevent_device, cpu);63cd->event_handler(cd);6465return IRQ_HANDLED;66}6768static void event_handler(struct clock_event_device *dev)69{70}7172int __init init_clockevents(void)73{74struct clock_event_device *cd;75struct irqaction *iact;76unsigned int cpu = smp_processor_id();7778cd = &per_cpu(mn10300_clockevent_device, cpu);7980if (cpu == 0) {81stop_jiffies_counter();82cd->irq = TMJCIRQ;83} else {84stop_jiffies_counter1();85cd->irq = TMJC1IRQ;86}8788cd->name = "Timestamp";89cd->features = CLOCK_EVT_FEAT_ONESHOT;9091/* Calculate shift/mult. We want to spawn at least 1 second */92clockevents_calc_mult_shift(cd, MN10300_JCCLK, 1);9394/* Calculate the min / max delta */95cd->max_delta_ns = clockevent_delta2ns(TMJCBR_MAX, cd);96cd->min_delta_ns = clockevent_delta2ns(100, cd);9798cd->rating = 200;99cd->cpumask = cpumask_of(smp_processor_id());100cd->set_mode = set_clock_mode;101cd->event_handler = event_handler;102cd->set_next_event = next_event;103104iact = &per_cpu(timer_irq, cpu);105iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;106iact->handler = timer_interrupt;107108clockevents_register_device(cd);109110#if defined(CONFIG_SMP) && !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)111/* setup timer irq affinity so it only runs on this cpu */112{113struct irq_data *data;114data = irq_get_irq_data(cd->irq);115cpumask_copy(data->affinity, cpumask_of(cpu));116iact->flags |= IRQF_NOBALANCING;117}118#endif119120if (cpu == 0) {121reload_jiffies_counter(MN10300_JC_PER_HZ - 1);122iact->name = "CPU0 Timer";123} else {124reload_jiffies_counter1(MN10300_JC_PER_HZ - 1);125iact->name = "CPU1 Timer";126}127128setup_jiffies_interrupt(cd->irq, iact);129130return 0;131}132133134