FreeBSD/Linux Kernel Cross Reference
sys/ppc/devirq.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "m8260.h"
7 #include "../port/error.h"
8
9 enum{
10 IRQ0 = 18,
11 Level = 0,
12 Edge = 1,
13 };
14
15 enum{
16 Qdir,
17 Qirq1,
18 Qirq2,
19 Qirq3,
20 Qirq4,
21 Qirq5,
22 Qirq6,
23 Qirq7,
24 Qmstimer,
25 Qfpgareset,
26 NIRQ,
27 };
28
29 static Dirtab irqdir[]={
30 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
31 "irq1", {Qirq1}, 0, 0666,
32 "irq2", {Qirq2}, 0, 0666,
33 "irq3", {Qirq1}, 0, 0666,
34 "irq4", {Qirq1}, 0, 0666,
35 "irq5", {Qirq1}, 0, 0666,
36 "irq6", {Qirq1}, 0, 0666,
37 "irq7", {Qirq1}, 0, 0666,
38 "mstimer", {Qmstimer}, 0, 0666,
39 "fpgareset", {Qfpgareset}, 0, 0222,
40 };
41
42 enum
43 {
44 CMinterrupt,
45 CMmode,
46 CMreset,
47 CMwait,
48 CMdebug,
49 };
50
51 Cmdtab irqmsg[] =
52 {
53 CMinterrupt, "interrupt", 2,
54 CMmode, "mode", 2,
55 CMreset, "reset", 1,
56 CMwait, "wait", 1,
57 CMdebug, "debug", 1,
58 };
59
60 typedef struct Irqconfig Irqconfig;
61 struct Irqconfig {
62 int intenable; /* Interrupts are enabled */
63 int mode; /* level == 0; edge == 1 */
64 ulong interrupts; /* Count interrupts */
65 ulong sleepints; /* interrupt count when waiting */
66 Rendez r; /* Rendez-vous point for interrupt waiting */
67 Irqconfig *next;
68 Timer;
69 };
70
71 Irqconfig *irqconfig[NIRQ]; /* irqconfig[0] is not used */
72 Lock irqlock;
73
74 static void interrupt(Ureg*, void*);
75 void dumpvno(void);
76
77 static void
78 ticmstimer(Ureg*, Timer *t)
79 {
80 Irqconfig *ic;
81
82 ic = t->ta;
83 ic->interrupts++;
84 wakeup(&ic->r);
85 }
86
87 void
88 irqenable(Irqconfig *ic, int irq)
89 {
90 /* call with ilock(&irqlock) held */
91
92 if (ic->intenable)
93 return;
94 if (irq == Qmstimer){
95 if (ic->tnext == nil)
96 ic->tns = MS2NS(ic->mode);
97 ic->tmode = Tperiodic;
98 timeradd(&ic->Timer);
99 }else{
100 if (irqconfig[irq]){
101 ic->next = irqconfig[irq];
102 irqconfig[irq] = ic;
103 }else{
104 ic->next = nil;
105 irqconfig[irq] = ic;
106 intrenable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
107 }
108 }
109 ic->intenable = 1;
110 }
111
112 void
113 irqdisable(Irqconfig *ic, int irq)
114 {
115 Irqconfig **pic;
116
117 /* call with ilock(&irqlock) held */
118
119 if (ic->intenable == 0)
120 return;
121 if (irq == Qmstimer){
122 timerdel(&ic->Timer);
123 }else{
124 for(pic = &irqconfig[irq]; *pic != ic; pic = &(*pic)->next)
125 assert(*pic);
126 *pic = (*pic)->next;
127 if (irqconfig[irq] == nil)
128 intrdisable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
129 }
130 ic->intenable = 0;
131 }
132
133 static Chan*
134 irqattach(char *spec)
135 {
136 return devattach('b', spec);
137 }
138
139 static Walkqid*
140 irqwalk(Chan *c, Chan *nc, char **name, int nname)
141 {
142 return devwalk(c, nc, name,nname, irqdir, nelem(irqdir), devgen);
143 }
144
145 static int
146 irqstat(Chan *c, uchar *dp, int n)
147 {
148 return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
149 }
150
151 static Chan*
152 irqopen(Chan *c, int omode)
153 {
154 Irqconfig *ic;
155 int irq;
156
157 irq = (ulong)c->qid.path;
158 if(irq != Qdir){
159 ic = mallocz(sizeof(Irqconfig), 1);
160 ic->tf = ticmstimer;
161 ic->ta = ic;
162 if (irq == Qmstimer)
163 ic->mode = 1000;
164 c->aux = ic;
165 }
166 return devopen(c, omode, irqdir, nelem(irqdir), devgen);
167 }
168
169 static void
170 irqclose(Chan *c)
171 {
172 int irq;
173 Irqconfig *ic;
174
175 irq = (ulong)c->qid.path;
176 if(irq == Qdir)
177 return;
178 ic = c->aux;
179 if (irq > Qmstimer)
180 return;
181 ilock(&irqlock);
182 irqdisable(ic, irq);
183 iunlock(&irqlock);
184 free(ic);
185 }
186
187 static int
188 irqtfn(void *arg)
189 {
190 Irqconfig *ic;
191
192 ic = arg;
193 return ic->sleepints != ic->interrupts;
194 }
195
196 static long
197 irqread(Chan *c, void *buf, long n, vlong)
198 {
199 int irq;
200 Irqconfig *ic;
201 char tmp[24];
202
203 if(n <= 0)
204 return n;
205 irq = (ulong)c->qid.path;
206 if(irq == Qdir)
207 return devdirread(c, buf, n, irqdir, nelem(irqdir), devgen);
208 if(irq > Qmstimer){
209 print("irqread 0x%llux\n", c->qid.path);
210 error(Egreg);
211 }
212 ic = c->aux;
213 if (ic->intenable == 0)
214 error("disabled");
215 ic->sleepints = ic->interrupts;
216 sleep(&ic->r, irqtfn, ic);
217 if (irq == Qmstimer)
218 snprint(tmp, sizeof tmp, "%11lud %d", ic->interrupts, ic->mode);
219 else
220 snprint(tmp, sizeof tmp, "%11lud %s", ic->interrupts, ic->mode ?"edge":"level");
221 n = readstr(0, buf, n, tmp);
222 return n;
223 }
224
225 static long
226 irqwrite(Chan *c, void *a, long n, vlong)
227 {
228 int irq;
229 Irqconfig *ic;
230 Cmdbuf *cb;
231 Cmdtab *ct;
232
233 if(n <= 0)
234 return n;
235
236 irq = (ulong)c->qid.path;
237 if(irq <= 0 || irq >= nelem(irqdir)){
238 print("irqwrite 0x%llux\n", c->qid.path);
239 error(Egreg);
240 }
241 if (irq == Qfpgareset){
242 if (strncmp(a, "reset", 5) == 0)
243 fpgareset();
244 else
245 error(Egreg);
246 return n;
247 }
248 ic = c->aux;
249
250 cb = parsecmd(a, n);
251
252 if(waserror()) {
253 free(cb);
254 nexterror();
255 }
256 ct = lookupcmd(cb, irqmsg, nelem(irqmsg));
257 switch(ct->index) {
258 case CMinterrupt:
259 /* Turn interrupts on or off */
260 if (strcmp(cb->f[1], "on") == 0){
261 ilock(&irqlock);
262 irqenable(ic, irq);
263 iomem->siprr = 0x65009770;
264 iunlock(&irqlock);
265 }else if (strcmp(cb->f[1], "off") == 0){
266 ilock(&irqlock);
267 irqdisable(ic, irq);
268 iunlock(&irqlock);
269 }else
270 error(Ebadarg);
271 break;
272 case CMmode:
273 /* Set mode */
274 if (irq == Qmstimer){
275 ic->mode = strtol(cb->f[1], nil, 0);
276 if (ic->mode <= 0){
277 ic->tns = MS2NS(1000);
278 ic->mode = 1000;
279 error(Ebadarg);
280 }
281 ic->tns = MS2NS(ic->mode);
282 }else if (strcmp(cb->f[1], "level") == 0){
283 ic->mode = Level;
284 iomem->siexr &= ~(0x8000 >> irq);
285 }else if (strcmp(cb->f[1], "edge") == 0){
286 ic->mode = Edge;
287 iomem->siexr |= 0x8000 >> irq;
288 }else
289 error(Ebadarg);
290 break;
291 case CMreset:
292 ic->interrupts = 0;
293 break;
294 case CMwait:
295 if (ic->intenable == 0)
296 error("interrupts are off");
297 ic->sleepints = ic->interrupts;
298 sleep(&ic->r, irqtfn, ic);
299 break;
300 case CMdebug:
301 print("simr h/l 0x%lux/0x%lux, sipnr h/l 0x%lux/0x%lux, siexr 0x%lux, siprr 0x%lux\n",
302 iomem->simr_h, iomem->simr_l,
303 iomem->sipnr_h, iomem->sipnr_l,
304 iomem->siexr, iomem->siprr);
305 dumpvno();
306 }
307 poperror();
308 free(cb);
309
310 /* Irqi */
311 return n;
312 }
313
314 static void
315 interrupt(Ureg*, void *arg)
316 {
317 Irqconfig **pic, *ic;
318 int irq;
319
320 pic = arg;
321 irq = pic - irqconfig;
322 if (irq <= 0 || irq > nelem(irqdir)){
323 print("Unexpected interrupt: %d\n", irq);
324 return;
325 }
326 ilock(&irqlock);
327 if (irq <= Qirq7)
328 iomem->sipnr_h |= 0x8000 >> irq; /* Clear the interrupt */
329 for(ic = *pic; ic; ic = ic->next){
330 ic->interrupts++;
331 wakeup(&ic->r);
332 }
333 iunlock(&irqlock);
334 }
335
336 Dev irqdevtab = {
337 'b',
338 "irq",
339
340 devreset,
341 devinit,
342 devshutdown,
343 irqattach,
344 irqwalk,
345 irqstat,
346 irqopen,
347 devcreate,
348 irqclose,
349 irqread,
350 devbread,
351 irqwrite,
352 devbwrite,
353 devremove,
354 devwstat,
355 };
Cache object: 3440b257d1b5f86414c41cef139aacda
|