xref: /plan9-contrib/sys/src/9/vt4/intr.c (revision d6dfd9ef91cf0fa8514a249d5f2a550978c19369)
1*d6dfd9efSDavid du Colombier /* Xilink XPS interrupt controller */
2*d6dfd9efSDavid du Colombier 
3*d6dfd9efSDavid du Colombier #include "u.h"
4*d6dfd9efSDavid du Colombier #include "../port/lib.h"
5*d6dfd9efSDavid du Colombier #include "mem.h"
6*d6dfd9efSDavid du Colombier #include "dat.h"
7*d6dfd9efSDavid du Colombier #include "fns.h"
8*d6dfd9efSDavid du Colombier 
9*d6dfd9efSDavid du Colombier #include "ethermii.h"
10*d6dfd9efSDavid du Colombier #include "../port/netif.h"
11*d6dfd9efSDavid du Colombier 
12*d6dfd9efSDavid du Colombier #include "io.h"
13*d6dfd9efSDavid du Colombier 
14*d6dfd9efSDavid du Colombier enum {
15*d6dfd9efSDavid du Colombier 	/* mer bits */
16*d6dfd9efSDavid du Colombier 	Merme	= 1<<0,		/* master enable */
17*d6dfd9efSDavid du Colombier 	Merhie	= 1<<1,		/* hw intr enable */
18*d6dfd9efSDavid du Colombier 
19*d6dfd9efSDavid du Colombier 	Maxintrs = 32,
20*d6dfd9efSDavid du Colombier 	Ntimevec = 20,		/* # of time buckets for each intr */
21*d6dfd9efSDavid du Colombier };
22*d6dfd9efSDavid du Colombier 
23*d6dfd9efSDavid du Colombier typedef struct {
24*d6dfd9efSDavid du Colombier 	ulong	isr;		/* status */
25*d6dfd9efSDavid du Colombier 	ulong	ipr;		/* pending (ro) */
26*d6dfd9efSDavid du Colombier 	ulong	ier;		/* enable */
27*d6dfd9efSDavid du Colombier 	ulong	iar;		/* acknowledge (wo) */
28*d6dfd9efSDavid du Colombier 	ulong	sieb;		/* set ie bits; avoid */
29*d6dfd9efSDavid du Colombier 	ulong	cieb;		/* clear ie bits; avoid */
30*d6dfd9efSDavid du Colombier 	ulong	ivr;		/* vector; silly */
31*d6dfd9efSDavid du Colombier 	ulong	mer;		/* master enable */
32*d6dfd9efSDavid du Colombier } Intregs;
33*d6dfd9efSDavid du Colombier 
34*d6dfd9efSDavid du Colombier typedef struct {
35*d6dfd9efSDavid du Colombier 	ulong	bit;
36*d6dfd9efSDavid du Colombier 	int	(*svc)(ulong);
37*d6dfd9efSDavid du Colombier 	char	*name;
38*d6dfd9efSDavid du Colombier 	uvlong	count;
39*d6dfd9efSDavid du Colombier } Intr;
40*d6dfd9efSDavid du Colombier 
41*d6dfd9efSDavid du Colombier static Intregs *irp = (Intregs *)Intctlr;
42*d6dfd9efSDavid du Colombier static Intr intrs[Maxintrs];
43*d6dfd9efSDavid du Colombier static Intr *nextintr;
44*d6dfd9efSDavid du Colombier static int tmoutok;
45*d6dfd9efSDavid du Colombier 
46*d6dfd9efSDavid du Colombier ulong intrs1sec;			/* count interrupts in this second */
47*d6dfd9efSDavid du Colombier ulong intrtimes[256][Ntimevec];
48*d6dfd9efSDavid du Colombier 
49*d6dfd9efSDavid du Colombier static Intr *
bit2intr(ulong bit)50*d6dfd9efSDavid du Colombier bit2intr(ulong bit)
51*d6dfd9efSDavid du Colombier {
52*d6dfd9efSDavid du Colombier 	Intr *ip;
53*d6dfd9efSDavid du Colombier 
54*d6dfd9efSDavid du Colombier 	for (ip = intrs; ip->bit != 0 && ip->bit != bit; ip++)
55*d6dfd9efSDavid du Colombier 		;
56*d6dfd9efSDavid du Colombier 	if (ip->bit == 0)
57*d6dfd9efSDavid du Colombier 		return nil;
58*d6dfd9efSDavid du Colombier 	return ip;
59*d6dfd9efSDavid du Colombier }
60*d6dfd9efSDavid du Colombier 
61*d6dfd9efSDavid du Colombier /*
62*d6dfd9efSDavid du Colombier  *  keep histogram of interrupt service times
63*d6dfd9efSDavid du Colombier  */
64*d6dfd9efSDavid du Colombier void
intrtime(Mach *,int vno)65*d6dfd9efSDavid du Colombier intrtime(Mach*, int vno)
66*d6dfd9efSDavid du Colombier {
67*d6dfd9efSDavid du Colombier 	ulong diff, x;
68*d6dfd9efSDavid du Colombier 
69*d6dfd9efSDavid du Colombier 	x = perfticks();
70*d6dfd9efSDavid du Colombier 	diff = x - m->perf.intrts;
71*d6dfd9efSDavid du Colombier 	m->perf.intrts = x;
72*d6dfd9efSDavid du Colombier 
73*d6dfd9efSDavid du Colombier 	m->perf.inintr += diff;
74*d6dfd9efSDavid du Colombier 	if(up == nil && m->perf.inidle > diff)
75*d6dfd9efSDavid du Colombier 		m->perf.inidle -= diff;
76*d6dfd9efSDavid du Colombier 
77*d6dfd9efSDavid du Colombier 	diff /= (m->cpuhz/1000000)*100;		/* quantum = 100µsec */
78*d6dfd9efSDavid du Colombier 	if(diff >= Ntimevec)
79*d6dfd9efSDavid du Colombier 		diff = Ntimevec-1;
80*d6dfd9efSDavid du Colombier 	intrtimes[vno][diff]++;
81*d6dfd9efSDavid du Colombier }
82*d6dfd9efSDavid du Colombier 
83*d6dfd9efSDavid du Colombier void
intrfmtcounts(char * s,char * se)84*d6dfd9efSDavid du Colombier intrfmtcounts(char *s, char *se)
85*d6dfd9efSDavid du Colombier {
86*d6dfd9efSDavid du Colombier 	Intr *ip;
87*d6dfd9efSDavid du Colombier 
88*d6dfd9efSDavid du Colombier 	for (ip = intrs; ip->bit != 0; ip++)
89*d6dfd9efSDavid du Colombier 		s = seprint(s, se, "bit %#lux %s\t%llud intrs\n",
90*d6dfd9efSDavid du Colombier 			ip->bit, ip->name, ip->count);
91*d6dfd9efSDavid du Colombier }
92*d6dfd9efSDavid du Colombier 
93*d6dfd9efSDavid du Colombier static void
dumpcounts(void)94*d6dfd9efSDavid du Colombier dumpcounts(void)
95*d6dfd9efSDavid du Colombier {
96*d6dfd9efSDavid du Colombier 	Intr *ip;
97*d6dfd9efSDavid du Colombier 
98*d6dfd9efSDavid du Colombier 	for (ip = intrs; ip->bit != 0; ip++)
99*d6dfd9efSDavid du Colombier 		iprint("bit %#lux %s\t%llud intrs\n",
100*d6dfd9efSDavid du Colombier 			ip->bit, ip->name, ip->count);
101*d6dfd9efSDavid du Colombier 	delay(100);
102*d6dfd9efSDavid du Colombier }
103*d6dfd9efSDavid du Colombier 
104*d6dfd9efSDavid du Colombier extern Ureg *gureg;
105*d6dfd9efSDavid du Colombier 
106*d6dfd9efSDavid du Colombier /*
107*d6dfd9efSDavid du Colombier  * called from trap on external (non-clock) interrupts
108*d6dfd9efSDavid du Colombier  * to poll interrupt handlers.
109*d6dfd9efSDavid du Colombier  */
110*d6dfd9efSDavid du Colombier void
intr(Ureg * ureg)111*d6dfd9efSDavid du Colombier intr(Ureg *ureg)
112*d6dfd9efSDavid du Colombier {
113*d6dfd9efSDavid du Colombier 	int handled;
114*d6dfd9efSDavid du Colombier 	ulong pend;
115*d6dfd9efSDavid du Colombier 	Intr *ip;
116*d6dfd9efSDavid du Colombier 
117*d6dfd9efSDavid du Colombier 	if (m->machno != 0)		/* only 1st cpu handles interrupts */
118*d6dfd9efSDavid du Colombier 		return;
119*d6dfd9efSDavid du Colombier 	gureg = ureg;
120*d6dfd9efSDavid du Colombier 	while ((pend = irp->ipr) != 0) {
121*d6dfd9efSDavid du Colombier 		for (ip = intrs; pend != 0 && ip->bit != 0; ip++)
122*d6dfd9efSDavid du Colombier 			if (pend & ip->bit) {
123*d6dfd9efSDavid du Colombier 				handled = ip->svc(ip->bit);
124*d6dfd9efSDavid du Colombier 				splhi();   /* in case handler went spllo() */
125*d6dfd9efSDavid du Colombier 				if (handled) {
126*d6dfd9efSDavid du Colombier 					intrtime(m, ip - intrs);
127*d6dfd9efSDavid du Colombier 					ip->count++;
128*d6dfd9efSDavid du Colombier 					pend &= ~ip->bit;
129*d6dfd9efSDavid du Colombier 				}
130*d6dfd9efSDavid du Colombier 			}
131*d6dfd9efSDavid du Colombier 		if (pend != 0) {
132*d6dfd9efSDavid du Colombier 			dumpcounts();
133*d6dfd9efSDavid du Colombier 			iprint("interrupt with no handler; ipr %#lux\n", pend);
134*d6dfd9efSDavid du Colombier 		}
135*d6dfd9efSDavid du Colombier 		if (++intrs1sec > 960*2 + 3*30000 + 1000) {
136*d6dfd9efSDavid du Colombier 			intrs1sec = 0;
137*d6dfd9efSDavid du Colombier 			dumpcounts();
138*d6dfd9efSDavid du Colombier 			panic("too many intrs in one second");
139*d6dfd9efSDavid du Colombier 		}
140*d6dfd9efSDavid du Colombier 	}
141*d6dfd9efSDavid du Colombier }
142*d6dfd9efSDavid du Colombier 
143*d6dfd9efSDavid du Colombier void
intrinit(void)144*d6dfd9efSDavid du Colombier intrinit(void)
145*d6dfd9efSDavid du Colombier {
146*d6dfd9efSDavid du Colombier 	/* disable and neuter the intr controller */
147*d6dfd9efSDavid du Colombier 	intrack(~0);
148*d6dfd9efSDavid du Colombier 	clrmchk();
149*d6dfd9efSDavid du Colombier 	barriers();
150*d6dfd9efSDavid du Colombier 	irp->ier = 0;
151*d6dfd9efSDavid du Colombier 	barriers();
152*d6dfd9efSDavid du Colombier 	intrack(~0);
153*d6dfd9efSDavid du Colombier 	barriers();
154*d6dfd9efSDavid du Colombier 
155*d6dfd9efSDavid du Colombier 	nextintr = intrs;
156*d6dfd9efSDavid du Colombier 	nextintr->bit = 0;
157*d6dfd9efSDavid du Colombier 	barriers();
158*d6dfd9efSDavid du Colombier 
159*d6dfd9efSDavid du Colombier 	/* turn on the intr controller, initially with no intrs enabled */
160*d6dfd9efSDavid du Colombier 	irp->mer = Merme | Merhie;
161*d6dfd9efSDavid du Colombier 	barriers();
162*d6dfd9efSDavid du Colombier 
163*d6dfd9efSDavid du Colombier //	intrack(~0);
164*d6dfd9efSDavid du Colombier //	clrmchk();
165*d6dfd9efSDavid du Colombier 	tmoutok = 1;
166*d6dfd9efSDavid du Colombier 	barriers();
167*d6dfd9efSDavid du Colombier }
168*d6dfd9efSDavid du Colombier 
169*d6dfd9efSDavid du Colombier /* register func as the interrupt-service routine for bit */
170*d6dfd9efSDavid du Colombier void
intrenable(ulong bit,int (* func)(ulong),char * name)171*d6dfd9efSDavid du Colombier intrenable(ulong bit, int (*func)(ulong), char *name)
172*d6dfd9efSDavid du Colombier {
173*d6dfd9efSDavid du Colombier 	Intr *ip;
174*d6dfd9efSDavid du Colombier 
175*d6dfd9efSDavid du Colombier 	for (ip = intrs; ip->bit != 0; ip++)
176*d6dfd9efSDavid du Colombier 		if (bit == ip->bit) {
177*d6dfd9efSDavid du Colombier 			assert(func == ip->svc);
178*d6dfd9efSDavid du Colombier 			return;		/* already registered */
179*d6dfd9efSDavid du Colombier 		}
180*d6dfd9efSDavid du Colombier 
181*d6dfd9efSDavid du Colombier 	assert(nextintr < intrs + nelem(intrs));
182*d6dfd9efSDavid du Colombier 	assert(bit != 0);
183*d6dfd9efSDavid du Colombier 	assert(func != nil);
184*d6dfd9efSDavid du Colombier 	ip = nextintr++;
185*d6dfd9efSDavid du Colombier 	ip->bit = bit;
186*d6dfd9efSDavid du Colombier 	ip->svc = func;
187*d6dfd9efSDavid du Colombier 	ip->name = name;
188*d6dfd9efSDavid du Colombier 	sync();
189*d6dfd9efSDavid du Colombier 	irp->ier |= bit;
190*d6dfd9efSDavid du Colombier 	barriers();
191*d6dfd9efSDavid du Colombier }
192*d6dfd9efSDavid du Colombier 
193*d6dfd9efSDavid du Colombier void
intrack(ulong bit)194*d6dfd9efSDavid du Colombier intrack(ulong bit)
195*d6dfd9efSDavid du Colombier {
196*d6dfd9efSDavid du Colombier 	irp->iar = bit;
197*d6dfd9efSDavid du Colombier 	barriers();
198*d6dfd9efSDavid du Colombier }
199*d6dfd9efSDavid du Colombier 
200*d6dfd9efSDavid du Colombier void
intrshutdown(void)201*d6dfd9efSDavid du Colombier intrshutdown(void)
202*d6dfd9efSDavid du Colombier {
203*d6dfd9efSDavid du Colombier 	irp->ier = 0;
204*d6dfd9efSDavid du Colombier 	irp->mer = 0;
205*d6dfd9efSDavid du Colombier 	barriers();
206*d6dfd9efSDavid du Colombier 	intrack(~0);
207*d6dfd9efSDavid du Colombier }
208