]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/devirq.c
ether82563: add 0x15bd i219-lm variant (thanks crab1)
[plan9front.git] / sys / src / 9 / 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 };