Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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*
151
irqattach(char *spec)
152
{
153
	return devattach('b', spec);
154
}
155
 
156
static Walkqid*
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
163
irqstat(Chan *c, uchar *dp, int n)
164
{
165
	return devstat(c, dp, n, irqdir, nelem(irqdir), devgen);
166
}
167
 
168
static Chan*
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
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
205
irqtfn(void *arg)
206
{
207
	Irqconfig *ic;
208
 
209
	ic = arg;
210
	return ic->sleepints != ic->interrupts;
211
}
212
 
213
static long
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
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
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
};