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