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