~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/xtensa/kernel/time.c

Version: ~ [ linux-6.2-rc3 ] ~ [ linux-6.1.5 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.87 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.162 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.228 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.269 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.302 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/xtensa/kernel/time.c
  3  *
  4  * Timer and clock support.
  5  *
  6  * This file is subject to the terms and conditions of the GNU General Public
  7  * License.  See the file "COPYING" in the main directory of this archive
  8  * for more details.
  9  *
 10  * Copyright (C) 2005 Tensilica Inc.
 11  *
 12  * Chris Zankel <chris@zankel.net>
 13  */
 14 
 15 #include <linux/errno.h>
 16 #include <linux/sched.h>
 17 #include <linux/time.h>
 18 #include <linux/clocksource.h>
 19 #include <linux/clockchips.h>
 20 #include <linux/interrupt.h>
 21 #include <linux/module.h>
 22 #include <linux/init.h>
 23 #include <linux/irq.h>
 24 #include <linux/profile.h>
 25 #include <linux/delay.h>
 26 #include <linux/irqdomain.h>
 27 #include <linux/sched_clock.h>
 28 
 29 #include <asm/timex.h>
 30 #include <asm/platform.h>
 31 
 32 unsigned long ccount_freq;              /* ccount Hz */
 33 EXPORT_SYMBOL(ccount_freq);
 34 
 35 static cycle_t ccount_read(struct clocksource *cs)
 36 {
 37         return (cycle_t)get_ccount();
 38 }
 39 
 40 static u64 notrace ccount_sched_clock_read(void)
 41 {
 42         return get_ccount();
 43 }
 44 
 45 static struct clocksource ccount_clocksource = {
 46         .name = "ccount",
 47         .rating = 200,
 48         .read = ccount_read,
 49         .mask = CLOCKSOURCE_MASK(32),
 50         .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 51 };
 52 
 53 static int ccount_timer_set_next_event(unsigned long delta,
 54                 struct clock_event_device *dev);
 55 static void ccount_timer_set_mode(enum clock_event_mode mode,
 56                 struct clock_event_device *evt);
 57 struct ccount_timer {
 58         struct clock_event_device evt;
 59         int irq_enabled;
 60         char name[24];
 61 };
 62 static DEFINE_PER_CPU(struct ccount_timer, ccount_timer);
 63 
 64 static int ccount_timer_set_next_event(unsigned long delta,
 65                 struct clock_event_device *dev)
 66 {
 67         unsigned long flags, next;
 68         int ret = 0;
 69 
 70         local_irq_save(flags);
 71         next = get_ccount() + delta;
 72         set_linux_timer(next);
 73         if (next - get_ccount() > delta)
 74                 ret = -ETIME;
 75         local_irq_restore(flags);
 76 
 77         return ret;
 78 }
 79 
 80 static void ccount_timer_set_mode(enum clock_event_mode mode,
 81                 struct clock_event_device *evt)
 82 {
 83         struct ccount_timer *timer =
 84                 container_of(evt, struct ccount_timer, evt);
 85 
 86         /*
 87          * There is no way to disable the timer interrupt at the device level,
 88          * only at the intenable register itself. Since enable_irq/disable_irq
 89          * calls are nested, we need to make sure that these calls are
 90          * balanced.
 91          */
 92         switch (mode) {
 93         case CLOCK_EVT_MODE_SHUTDOWN:
 94         case CLOCK_EVT_MODE_UNUSED:
 95                 if (timer->irq_enabled) {
 96                         disable_irq(evt->irq);
 97                         timer->irq_enabled = 0;
 98                 }
 99                 break;
100         case CLOCK_EVT_MODE_RESUME:
101         case CLOCK_EVT_MODE_ONESHOT:
102                 if (!timer->irq_enabled) {
103                         enable_irq(evt->irq);
104                         timer->irq_enabled = 1;
105                 }
106         default:
107                 break;
108         }
109 }
110 
111 static irqreturn_t timer_interrupt(int irq, void *dev_id);
112 static struct irqaction timer_irqaction = {
113         .handler =      timer_interrupt,
114         .flags =        IRQF_TIMER,
115         .name =         "timer",
116 };
117 
118 void local_timer_setup(unsigned cpu)
119 {
120         struct ccount_timer *timer = &per_cpu(ccount_timer, cpu);
121         struct clock_event_device *clockevent = &timer->evt;
122 
123         timer->irq_enabled = 1;
124         clockevent->name = timer->name;
125         snprintf(timer->name, sizeof(timer->name), "ccount_clockevent_%u", cpu);
126         clockevent->features = CLOCK_EVT_FEAT_ONESHOT;
127         clockevent->rating = 300;
128         clockevent->set_next_event = ccount_timer_set_next_event;
129         clockevent->set_mode = ccount_timer_set_mode;
130         clockevent->cpumask = cpumask_of(cpu);
131         clockevent->irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
132         if (WARN(!clockevent->irq, "error: can't map timer irq"))
133                 return;
134         clockevents_config_and_register(clockevent, ccount_freq,
135                                         0xf, 0xffffffff);
136 }
137 
138 void __init time_init(void)
139 {
140 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
141         printk("Calibrating CPU frequency ");
142         platform_calibrate_ccount();
143         printk("%d.%02d MHz\n", (int)ccount_freq/1000000,
144                         (int)(ccount_freq/10000)%100);
145 #else
146         ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL;
147 #endif
148         clocksource_register_hz(&ccount_clocksource, ccount_freq);
149         local_timer_setup(0);
150         setup_irq(this_cpu_ptr(&ccount_timer)->evt.irq, &timer_irqaction);
151         sched_clock_register(ccount_sched_clock_read, 32, ccount_freq);
152         clocksource_of_init();
153 }
154 
155 /*
156  * The timer interrupt is called HZ times per second.
157  */
158 
159 irqreturn_t timer_interrupt(int irq, void *dev_id)
160 {
161         struct clock_event_device *evt = &this_cpu_ptr(&ccount_timer)->evt;
162 
163         set_linux_timer(get_linux_timer());
164         evt->event_handler(evt);
165 
166         /* Allow platform to do something useful (Wdog). */
167         platform_heartbeat();
168 
169         return IRQ_HANDLED;
170 }
171 
172 #ifndef CONFIG_GENERIC_CALIBRATE_DELAY
173 void calibrate_delay(void)
174 {
175         loops_per_jiffy = ccount_freq / HZ;
176         printk("Calibrating delay loop (skipped)... "
177                "%lu.%02lu BogoMIPS preset\n",
178                loops_per_jiffy/(1000000/HZ),
179                (loops_per_jiffy/(10000/HZ)) % 100);
180 }
181 #endif
182 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp