]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/clock.c
io.h: fis comment PciSID (alphapc, kw, mtx, teg2) (thanks qeed!)
[plan9front.git] / sys / src / 9 / kw / clock.c
1 /*
2  * kirkwood clocks
3  *
4  * timers count down to zero.
5  */
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12
13 #include "ureg.h"
14
15 enum {
16         Tcycles         = CLOCKFREQ / HZ,       /* cycles per clock tick */
17         Dogperiod       = 15 * CLOCKFREQ, /* at most 21 s.; must fit in ulong */
18         MaxPeriod       = Tcycles,
19         MinPeriod       = MaxPeriod / 100,
20
21         /* timer ctl bits */
22         Tmr0enable      = 1<<0,
23         Tmr0reload      = 1<<1, /* at 0 count, load timer0 from reload0 */
24         Tmr1enable      = 1<<2,
25         Tmr1reload      = 1<<3, /* at 0 count, load timer1 from reload1 */
26         TmrWDenable     = 1<<4,
27         TmrWDreload     = 1<<5,
28 };
29
30 typedef struct TimerReg TimerReg;
31 struct TimerReg
32 {
33         ulong   ctl;
34         ulong   pad[3];
35         ulong   reload0;
36         ulong   timer0;                 /* cycles until zero */
37         ulong   reload1;
38         ulong   timer1;                 /* cycles until zero */
39         ulong   reloadwd;
40         ulong   timerwd;
41 };
42
43 static int ticks; /* for sanity checking; m->ticks doesn't always get updated */
44
45 static void
46 clockintr(Ureg *ureg, void *arg)
47 {
48         TimerReg *tmr = arg;
49         static int nesting;
50
51         tmr->timerwd = Dogperiod;               /* reassure the watchdog */
52         ticks++;
53         coherence();
54
55         if (nesting == 0) {     /* if the clock interrupted itself, bail out */
56                 ++nesting;
57                 timerintr(ureg, 0);
58                 --nesting;
59         }
60
61         intrclear(Irqbridge, IRQcputimer0);
62 }
63
64 /* stop clock interrupts and disable the watchdog timer */
65 void
66 clockshutdown(void)
67 {
68         TimerReg *tmr = (TimerReg *)soc.clock;
69
70         tmr->ctl = 0;
71         coherence();
72 }
73
74 void
75 clockinit(void)
76 {
77         int i, s;
78         CpucsReg *cpu = (CpucsReg *)soc.cpu;
79         TimerReg *tmr = (TimerReg *)soc.clock;
80
81         clockshutdown();
82
83         /*
84          * verify sanity of timer0
85          */
86
87         intrenable(Irqbridge, IRQcputimer0, clockintr, tmr, "clock0");
88         s = spllo();                    /* risky */
89         /* take any deferred clock (& other) interrupts here */
90         splx(s);
91
92         /* adjust m->bootdelay, used by delay()? */
93         m->ticks = ticks = 0;
94         m->fastclock = 0;
95
96         tmr->timer0 = 1;
97         tmr->ctl = Tmr0enable;          /* just once */
98         coherence();
99
100         s = spllo();                    /* risky */
101         for (i = 0; i < 10 && ticks == 0; i++) {
102                 delay(1);
103                 coherence();
104         }
105         splx(s);
106         if (ticks == 0) {
107                 serialputc('?');
108                 if (tmr->timer0 == 0)
109                         panic("clock not interrupting");
110                 else if (tmr->timer0 == tmr->reload0)
111                         panic("clock not ticking");
112                 else
113                         panic("clock running very slowly");
114         }
115
116         /*
117          * configure all timers
118          */
119         clockshutdown();
120         tmr->reload0 = tmr->timer0 = Tcycles;   /* tick clock */
121         tmr->reload1 = tmr->timer1 = ~0;        /* cycle clock */
122         tmr->timerwd = Dogperiod;               /* watch dog timer */
123         coherence();
124         tmr->ctl = Tmr0enable | Tmr0reload | Tmr1enable | Tmr1reload |
125                 TmrWDenable;
126         cpu->rstout |= RstoutWatchdog;
127         coherence();
128 }
129
130 void
131 timerset(Tval next)
132 {
133         int offset;
134         TimerReg *tmr = (TimerReg *)soc.clock;
135
136         offset = next - fastticks(nil);
137         if(offset < MinPeriod)
138                 offset = MinPeriod;
139         else if(offset > MaxPeriod)
140                 offset = MaxPeriod;
141         tmr->timer0 = offset;
142         coherence();
143 }
144
145 uvlong
146 fastticks(uvlong *hz)
147 {
148         uvlong now;
149         int s;
150
151         if(hz)
152                 *hz = CLOCKFREQ;
153         s = splhi();
154         /* zero low ulong of fastclock */
155         now = (m->fastclock & ~(uvlong)~0ul) | perfticks();
156         if(now < m->fastclock)          /* low bits must have wrapped */
157                 now += 1ll << 32;
158         m->fastclock = now;
159         splx(s);
160         return now;
161 }
162
163 ulong
164 perfticks(void)
165 {
166         TimerReg *tmr = (TimerReg *)soc.clock;
167
168         return ~tmr->timer1;
169 }
170
171 long
172 lcycles(void)
173 {
174         return perfticks();
175 }
176
177 ulong
178 µs(void)
179 {
180         return fastticks2us(fastticks(nil));
181 }
182
183 void
184 microdelay(int l)
185 {
186         int i;
187
188         l *= m->delayloop;
189         l /= 1000;
190         if(l <= 0)
191                 l = 1;
192         for(i = 0; i < l; i++)
193                 ;
194 }
195
196 void
197 delay(int l)
198 {
199         ulong i, j;
200
201         j = m->delayloop;
202         while(l-- > 0)
203                 for(i=0; i < j; i++)
204                         ;
205 }