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