xref: /plan9/sys/src/9/ppc/devirq.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
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 #ifdef notdef
78 ulong multiplier;
79 
80 ulong
s(void)81 µs(void)
82 {
83 	uvlong x;
84 
85 	if(multiplier == 0){
86 		multiplier = (uvlong)(1000000LL << 16) / m->cyclefreq;
87 		print("µs: multiplier %ld, cyclefreq %lld, shifter %d\n", multiplier, m->cyclefreq, 16);
88 	}
89 	cycles(&x);
90 	return (x*multiplier) >> 16;
91 }
92 #endif
93 
94 static void
ticmstimer(Ureg *,Timer * t)95 ticmstimer(Ureg*, Timer *t)
96 {
97 	Irqconfig *ic;
98 
99 	ic = t->ta;
100  	ic->interrupts++;
101 	wakeup(&ic->r);
102 }
103 
104 void
irqenable(Irqconfig * ic,int irq)105 irqenable(Irqconfig *ic, int irq)
106 {
107 	/* call with ilock(&irqlock) held */
108 
109 	if (ic->intenable)
110 		return;
111 	if (irq == Qmstimer){
112 		if (ic->tnext == nil)
113 			ic->tns = MS2NS(ic->mode);
114 		ic->tmode = Tperiodic;
115 		timeradd(&ic->Timer);
116 	}else{
117 		if (irqconfig[irq]){
118 			ic->next = irqconfig[irq];
119 			irqconfig[irq] = ic;
120 		}else{
121 			ic->next = nil;
122 			irqconfig[irq] = ic;
123 			intrenable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
124 		}
125 	}
126 	ic->intenable = 1;
127 }
128 
129 void
irqdisable(Irqconfig * ic,int irq)130 irqdisable(Irqconfig *ic, int irq)
131 {
132 	Irqconfig **pic;
133 
134 	/* call with ilock(&irqlock) held */
135 
136 	if (ic->intenable == 0)
137 		return;
138 	if (irq == Qmstimer){
139 		timerdel(&ic->Timer);
140 	}else{
141 		for(pic = &irqconfig[irq]; *pic != ic; pic = &(*pic)->next)
142 			assert(*pic);
143 		*pic = (*pic)->next;
144 		if (irqconfig[irq] == nil)
145 			intrdisable(IRQ0 + irq, interrupt, &irqconfig[irq], irqdir[irq].name);
146 	}
147 	ic->intenable = 0;
148 }
149 
150 static Chan*
irqattach(char * spec)151 irqattach(char *spec)
152 {
153 	return devattach('b', spec);
154 }
155 
156 static Walkqid*
irqwalk(Chan * c,Chan * nc,char ** name,int nname)157 irqwalk(Chan *c, Chan *nc, char **name, int nname)
158 {
159 	return devwalk(c, nc, name,nname, irqdir, nelem(irqdir), devgen);
160 }
161 
162 static int
irqstat(Chan * c,uchar * dp,int n)163 irqstat(Chan *c, uchar *dp, int n)
164 {
165 	return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
166 }
167 
168 static Chan*
irqopen(Chan * c,int omode)169 irqopen(Chan *c, int omode)
170 {
171 	Irqconfig *ic;
172 	int irq;
173 
174 	irq = (ulong)c->qid.path;
175 	if(irq != Qdir){
176 		ic = mallocz(sizeof(Irqconfig), 1);
177 		ic->tf = ticmstimer;
178 		ic->ta = ic;
179 		if (irq == Qmstimer)
180 			ic->mode = 1000;
181 		c->aux = ic;
182 	}
183 	return devopen(c, omode, irqdir, nelem(irqdir), devgen);
184 }
185 
186 static void
irqclose(Chan * c)187 irqclose(Chan *c)
188 {
189 	int irq;
190 	Irqconfig *ic;
191 
192 	irq = (ulong)c->qid.path;
193 	if(irq == Qdir)
194 		return;
195 	ic = c->aux;
196 	if (irq > Qmstimer)
197 		return;
198 	ilock(&irqlock);
199 	irqdisable(ic, irq);
200 	iunlock(&irqlock);
201 	free(ic);
202 }
203 
204 static int
irqtfn(void * arg)205 irqtfn(void *arg)
206 {
207 	Irqconfig *ic;
208 
209 	ic = arg;
210 	return ic->sleepints != ic->interrupts;
211 }
212 
213 static long
irqread(Chan * c,void * buf,long n,vlong)214 irqread(Chan *c, void *buf, long n, vlong)
215 {
216 	int irq;
217 	Irqconfig *ic;
218 	char tmp[24];
219 
220 	if(n <= 0)
221 		return n;
222 	irq = (ulong)c->qid.path;
223 	if(irq == Qdir)
224 		return devdirread(c, buf, n, irqdir, nelem(irqdir), devgen);
225 	if(irq > Qmstimer){
226 		print("irqread 0x%llux\n", c->qid.path);
227 		error(Egreg);
228 	}
229 	ic = c->aux;
230 	if (ic->intenable == 0)
231 		error("disabled");
232 	ic->sleepints = ic->interrupts;
233 	sleep(&ic->r, irqtfn, ic);
234 	if (irq == Qmstimer)
235 		snprint(tmp, sizeof tmp, "%11lud %d", ic->interrupts, ic->mode);
236 	else
237 		snprint(tmp, sizeof tmp, "%11lud %s", ic->interrupts, ic->mode ?"edge":"level");
238 	n = readstr(0, buf, n, tmp);
239 	return n;
240 }
241 
242 static long
irqwrite(Chan * c,void * a,long n,vlong)243 irqwrite(Chan *c, void *a, long n, vlong)
244 {
245 	int irq;
246 	Irqconfig *ic;
247 	Cmdbuf *cb;
248 	Cmdtab *ct;
249 
250 	if(n <= 0)
251 		return n;
252 
253 	irq = (ulong)c->qid.path;
254 	if(irq <= 0 || irq >= nelem(irqdir)){
255 		print("irqwrite 0x%llux\n", c->qid.path);
256 		error(Egreg);
257 	}
258 	if (irq == Qfpgareset){
259 		if (strncmp(a, "reset", 5) == 0)
260 			fpgareset();
261 		else
262 			error(Egreg);
263 		return n;
264 	}
265 	ic = c->aux;
266 
267 	cb = parsecmd(a, n);
268 
269 	if(waserror()) {
270 		free(cb);
271 		nexterror();
272 	}
273 	ct = lookupcmd(cb, irqmsg, nelem(irqmsg));
274 	switch(ct->index) {
275 	case 	CMinterrupt:
276 		/* Turn interrupts on or off */
277 		if (strcmp(cb->f[1], "on") == 0){
278 			ilock(&irqlock);
279 			irqenable(ic, irq);
280 			iomem->siprr = 0x65009770;
281 			iunlock(&irqlock);
282 		}else if (strcmp(cb->f[1], "off") == 0){
283 			ilock(&irqlock);
284 			irqdisable(ic, irq);
285 			iunlock(&irqlock);
286 		}else
287 			error(Ebadarg);
288 		break;
289 	case CMmode:
290 		/* Set mode */
291 		if (irq == Qmstimer){
292 			ic->mode = strtol(cb->f[1], nil, 0);
293 			if (ic->mode <= 0){
294 				ic->tns = MS2NS(1000);
295 				ic->mode = 1000;
296 				error(Ebadarg);
297 			}
298 			ic->tns = MS2NS(ic->mode);
299 		}else if (strcmp(cb->f[1], "level") == 0){
300 			ic->mode = Level;
301 			iomem->siexr &= ~(0x8000 >> irq);
302 		}else if (strcmp(cb->f[1], "edge") == 0){
303 			ic->mode = Edge;
304 			iomem->siexr |= 0x8000 >> irq;
305 		}else
306 			error(Ebadarg);
307 		break;
308 	case CMreset:
309 		ic->interrupts = 0;
310 		break;
311 	case CMwait:
312 		if (ic->intenable == 0)
313 			error("interrupts are off");
314 		ic->sleepints = ic->interrupts;
315 		sleep(&ic->r, irqtfn, ic);
316 		break;
317 	case CMdebug:
318 		print("simr h/l 0x%lux/0x%lux, sipnr h/l 0x%lux/0x%lux, siexr 0x%lux, siprr 0x%lux\n",
319 			iomem->simr_h, iomem->simr_l,
320 			iomem->sipnr_h, iomem->sipnr_l,
321 			iomem->siexr, iomem->siprr);
322 //		dumpvno();
323 	}
324 	poperror();
325 	free(cb);
326 
327 	/* Irqi */
328 	return n;
329 }
330 
331 static void
interrupt(Ureg *,void * arg)332 interrupt(Ureg*, void *arg)
333 {
334 	Irqconfig **pic, *ic;
335 	int irq;
336 
337 	pic = arg;
338 	irq = pic - irqconfig;
339 	if (irq <= 0 || irq > nelem(irqdir)){
340 		print("Unexpected interrupt: %d\n", irq);
341 		return;
342 	}
343 	ilock(&irqlock);
344 	if (irq <= Qirq7)
345 		iomem->sipnr_h |= 0x8000 >> irq;	/* Clear the interrupt */
346 	for(ic = *pic; ic; ic = ic->next){
347 		ic->interrupts++;
348 		wakeup(&ic->r);
349 	}
350 	iunlock(&irqlock);
351 }
352 
353 Dev irqdevtab = {
354 	'b',
355 	"irq",
356 
357 	devreset,
358 	devinit,
359 	devshutdown,
360 	irqattach,
361 	irqwalk,
362 	irqstat,
363 	irqopen,
364 	devcreate,
365 	irqclose,
366 	irqread,
367 	devbread,
368 	irqwrite,
369 	devbwrite,
370 	devremove,
371 	devwstat,
372 };
373