Commit | Line | Data |
---|---|---|
53a5409e | 1 | /* if_en.c 4.7 81/11/14 */ |
11720282 BJ |
2 | |
3 | #include "en.h" | |
4 | /* | |
5 | * Ethernet interface driver | |
6 | */ | |
7 | ||
8 | #include "../h/param.h" | |
9 | #include "../h/systm.h" | |
10 | #include "../h/mbuf.h" | |
d52566dd BJ |
11 | #include "../net/inet.h" |
12 | #include "../net/inet_systm.h" | |
13 | #include "../net/imp.h" | |
14 | #include "../net/ip.h" | |
53a5409e | 15 | #include "../net/tcp.h" /* XXX */ |
11720282 BJ |
16 | #include "../h/map.h" |
17 | #include "../h/pte.h" | |
18 | #include "../h/buf.h" | |
19 | #include "../h/ubareg.h" | |
20 | #include "../h/ubavar.h" | |
21 | #include "../h/conf.h" | |
22 | #include "../h/dir.h" | |
23 | #include "../h/user.h" | |
24 | #include "../h/proc.h" | |
25 | #include "../h/enreg.h" | |
26 | #include "../h/mtpr.h" | |
27 | #include "../h/cpu.h" | |
28 | #include "../h/cmap.h" | |
29 | ||
30 | int enrswaps, enwswaps; | |
31 | int enprobe(), enattach(), enrint(), enxint(), encollide(); | |
32 | struct uba_device *eninfo[NEN]; | |
33 | u_short enstd[] = { 0 }; | |
34 | struct uba_driver endriver = | |
35 | { enprobe, 0, enattach, 0, enstd, "en", eninfo }; | |
36 | ||
37 | #define ENUNIT(x) minor(x) | |
38 | ||
39 | struct en_packet *xpkt, *rpkt; | |
40 | struct en_prefix { | |
41 | struct en_header enp_h; | |
53a5409e | 42 | struct tcpiphdr enp_th; |
11720282 BJ |
43 | }; |
44 | struct uba_regs *enuba; | |
ae348eea | 45 | struct pte *enrmr, *enxmr; |
11720282 BJ |
46 | int enrbdp, enwbdp; |
47 | int enrproto, enwproto; | |
ae348eea BJ |
48 | struct pte enxmap[2]; |
49 | int enxswapd; | |
11720282 BJ |
50 | |
51 | enprobe(reg) | |
52 | caddr_t reg; | |
53 | { | |
54 | register int br, cvec; | |
55 | register struct endevice *addr = (struct endevice *)reg; | |
56 | ||
57 | #ifdef lint | |
58 | br = 0; cvec = br; br = cvec; | |
59 | #endif | |
60 | ||
61 | addr->en_istat = 0; | |
62 | addr->en_ostat = 0; | |
63 | addr->en_owc = -1; | |
64 | addr->en_oba = 0; | |
941ee7ef | 65 | addr->en_ostat = EN_IEN|EN_GO; |
11720282 BJ |
66 | DELAY(100000); |
67 | addr->en_ostat = 0; | |
68 | printf("ethernet address %d\n", ~addr->en_addr&0xff); | |
69 | return (1); | |
70 | } | |
71 | ||
72 | enattach(ui) | |
73 | struct uba_device *ui; | |
74 | { | |
ae348eea | 75 | |
11720282 BJ |
76 | } |
77 | ||
ae348eea | 78 | eninit(unit) |
11720282 BJ |
79 | int unit; |
80 | { | |
81 | register struct endevice *addr; | |
82 | register struct uba_device *ui; | |
83 | int uban, x; | |
84 | static reenter; | |
85 | ||
86 | if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) { | |
87 | printf("en%d: not alive\n", unit); | |
88 | return; | |
89 | } | |
90 | x = splimp(); | |
91 | if (reenter == 0) { | |
92 | int n, j, i, k; char *cp; | |
93 | reenter = 1; | |
94 | n = 10; | |
95 | k = n<<1; | |
d52566dd | 96 | i = rmalloc(mbmap, n*2); |
11720282 | 97 | if (i == 0) |
ae348eea | 98 | panic("eninit"); |
11720282 BJ |
99 | j = i << 1; |
100 | cp = (char *)pftom(i); | |
d52566dd | 101 | if (memall(&Mbmap[j], k, proc, CSYS) == 0) |
11720282 | 102 | return (0); |
d52566dd | 103 | vmaccess(&Mbmap[j], (caddr_t)cp, k); |
11720282 BJ |
104 | rpkt = (struct en_packet *) |
105 | (cp + 1024 - sizeof (struct en_prefix)); | |
106 | xpkt = (struct en_packet *) | |
107 | (cp + 5 * 1024 + 1024 - sizeof (struct en_prefix)); | |
108 | for (j = 0; j < n; j++) | |
109 | mprefcnt[i+j] = 1; | |
110 | } | |
111 | uban = ui->ui_ubanum; | |
112 | addr = (struct endevice *)ui->ui_addr; | |
113 | addr->en_istat = 0; | |
114 | addr->en_ostat = 0; | |
115 | imp_stat.iaddr = | |
116 | uballoc(uban, (caddr_t)rpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP); | |
117 | imp_stat.oaddr = | |
118 | uballoc(uban, (caddr_t)xpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP); | |
119 | enuba = ui->ui_hd->uh_uba; | |
120 | enrbdp = (imp_stat.iaddr >> 28) & 0xf; | |
121 | enwbdp = (imp_stat.oaddr >> 28) & 0xf; | |
122 | enrproto = UBAMR_MRV | (enrbdp << 21); | |
123 | enwproto = UBAMR_MRV | (enwbdp << 21); | |
124 | enrmr = &enuba->uba_map[((imp_stat.iaddr>>9)&0x1ff) + 1]; | |
ae348eea BJ |
125 | enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1]; |
126 | enxmap[0] = enxmr[0]; | |
127 | enxmap[1] = enxmr[1]; | |
128 | enxswapd = 0; | |
11720282 BJ |
129 | printf("enrbdp %x enrproto %x enrmr %x imp_stat.iaddr %x\n", |
130 | enrbdp, enrproto, enrmr, imp_stat.iaddr); | |
131 | imp_stat.impopen = 1; | |
132 | imp_stat.flush = 0; | |
133 | splx(x); | |
134 | #ifdef IMPDEBUG | |
135 | printf("eninit(%d): iaddr = %x, oaddr = %x\n", | |
136 | unit, imp_stat.iaddr, imp_stat.oaddr); | |
137 | #endif | |
138 | } | |
139 | ||
140 | enreset(uban) | |
141 | int uban; | |
142 | { | |
143 | register int unit; | |
144 | struct uba_device *ui; | |
145 | ||
146 | for (unit = 0; unit < NEN; unit++) { | |
147 | ui = eninfo[unit]; | |
148 | if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0) | |
149 | continue; | |
150 | if (imp_stat.iaddr) | |
151 | ubarelse(uban, imp_stat.iaddr); | |
152 | if (imp_stat.oaddr) | |
153 | ubarelse(uban, imp_stat.oaddr); | |
ae348eea | 154 | eninit(unit); |
11720282 BJ |
155 | printf("en%d ", unit); |
156 | } | |
157 | } | |
158 | ||
3552a746 BJ |
159 | int enlastdel = 25; |
160 | int enlastx = 0; | |
ae348eea | 161 | enstart(dev) |
11720282 BJ |
162 | dev_t dev; |
163 | { | |
164 | register struct mbuf *m, *mp; | |
165 | register struct endevice *addr; | |
166 | register caddr_t cp, top; | |
167 | int unit; | |
168 | register int len; | |
169 | u_short uaddr; | |
170 | struct uba_device *ui; | |
ae348eea BJ |
171 | int enxswapnow = 0; |
172 | COUNT(ENSTART); | |
11720282 BJ |
173 | |
174 | unit = ENUNIT(dev); | |
175 | ui = eninfo[unit]; | |
176 | if (ui == 0 || ui->ui_alive == 0) { | |
177 | printf("en%d (imp_output): not alive\n", unit); | |
178 | return; | |
179 | } | |
180 | addr = (struct endevice *)ui->ui_addr; | |
181 | if (!imp_stat.outactive) { | |
182 | if ((m = imp_stat.outq_head) == NULL) | |
183 | return; | |
184 | imp_stat.outactive = 1; /* set myself active */ | |
185 | imp_stat.outq_head = m->m_act; /* -> next packet chain */ | |
186 | /* | |
187 | * Pack mbufs into ethernet packet. | |
188 | */ | |
189 | cp = (caddr_t)xpkt; | |
190 | top = (caddr_t)xpkt + sizeof(struct en_packet); | |
191 | while (m != NULL) { | |
ae348eea | 192 | char *dp; |
11720282 BJ |
193 | if (cp + m->m_len > top) { |
194 | printf("imp_snd: my packet runneth over\n"); | |
195 | m_freem(m); | |
196 | return; | |
197 | } | |
ae348eea BJ |
198 | dp = mtod(m, char *); |
199 | if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) { | |
d52566dd | 200 | struct pte *pte = &Mbmap[mtopf(dp)*2]; |
ae348eea BJ |
201 | *(int *)enxmr = enwproto | pte++->pg_pfnum; |
202 | *(int *)(enxmr+1) = enwproto | pte->pg_pfnum; | |
203 | enxswapd = enxswapnow = 1; | |
204 | } else | |
205 | bcopy((int)m + m->m_off, cp, m->m_len); | |
11720282 | 206 | cp += m->m_len; |
ae348eea | 207 | /* too soon! */ |
11720282 BJ |
208 | MFREE(m, mp); |
209 | m = mp; | |
210 | } | |
3552a746 BJ |
211 | if (enxswapnow == 0 && enxswapd) { |
212 | enxmr[0] = enxmap[0]; | |
213 | enxmr[1] = enxmap[1]; | |
214 | } | |
215 | if (enlastx && enlastx == xpkt->Header.en_dhost) | |
216 | imp_stat.endelay = enlastdel; | |
217 | else | |
218 | enlastx = xpkt->Header.en_dhost; | |
ae348eea | 219 | } |
11720282 BJ |
220 | len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822; |
221 | if (len > sizeof(struct en_packet)) { | |
222 | printf("imp_output: ridiculous IP length %d\n", len); | |
223 | return; | |
224 | } | |
225 | #if defined(VAX780) || defined(VAX750) | |
226 | switch (cpu) { | |
227 | #if defined(VAX780) | |
228 | case VAX_780: | |
ae348eea | 229 | UBA_PURGE780(enuba, enwbdp); |
11720282 BJ |
230 | break; |
231 | #endif | |
232 | #if defined(VAX750) | |
233 | case VAX_750: | |
ae348eea | 234 | UBA_PURGE750(enuba, enwbdp); |
11720282 BJ |
235 | break; |
236 | #endif | |
237 | } | |
238 | #endif | |
239 | addr->en_oba = imp_stat.oaddr; | |
240 | addr->en_odelay = imp_stat.endelay; | |
241 | addr->en_owc = -((len + 1) >> 1); | |
242 | #ifdef IMPDEBUG | |
243 | printf("en%d: sending packet (%d bytes)\n", unit, len); | |
244 | prt_byte(xpkt, len); | |
245 | #endif | |
941ee7ef | 246 | addr->en_ostat = EN_IEN|EN_GO; |
11720282 BJ |
247 | } |
248 | ||
249 | /* | |
ae348eea | 250 | * Setup for a read |
11720282 | 251 | */ |
ae348eea | 252 | ensetup(dev) |
11720282 BJ |
253 | dev_t dev; |
254 | { | |
255 | register struct endevice *addr; | |
256 | register struct uba_device *ui; | |
257 | register unsigned ubaddr; | |
258 | register int sps; | |
ae348eea | 259 | COUNT(ENSETUP); |
11720282 BJ |
260 | |
261 | ui = eninfo[ENUNIT(dev)]; | |
262 | if (ui == 0 || ui->ui_alive == 0) { | |
263 | printf("en%d (imp_read): not alive\n", ENUNIT(dev)); | |
264 | return; | |
265 | } | |
266 | addr = (struct endevice *)ui->ui_addr; | |
267 | addr->en_iba = imp_stat.iaddr; | |
268 | addr->en_iwc = -600; /* a little extra to avoid hardware bugs */ | |
941ee7ef | 269 | addr->en_istat = EN_IEN|EN_GO; |
11720282 BJ |
270 | } |
271 | ||
272 | /* | |
273 | * Output interrupt handler. | |
274 | */ | |
275 | enxint(unit) | |
276 | int unit; | |
277 | { | |
278 | register struct endevice *addr; | |
279 | register struct uba_device *ui; | |
280 | COUNT(ENXINT); | |
281 | ||
282 | ui = eninfo[unit]; | |
283 | addr = (struct endevice *)ui->ui_addr; | |
284 | ||
285 | #ifdef IMPDEBUG | |
286 | printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS); | |
287 | #endif | |
288 | if (!imp_stat.outactive) { | |
289 | printf("en%d: phantom output intr ostat=%b\n", | |
290 | unit, addr->en_ostat, EN_BITS); | |
291 | return; | |
292 | } | |
293 | imp_stat.endelay = 0; | |
294 | imp_stat.enmask = ~0; | |
941ee7ef | 295 | if (addr->en_ostat&EN_OERROR) |
11720282 BJ |
296 | printf("en%d: output error ostat=%b\n", unit, |
297 | addr->en_ostat, EN_BITS); | |
298 | imp_stat.outactive = 0; | |
ae348eea BJ |
299 | if (imp_stat.outq_head) |
300 | enstart(unit); | |
3552a746 BJ |
301 | else |
302 | enlastx = 0; | |
11720282 BJ |
303 | } |
304 | ||
3552a746 | 305 | int collisions; |
11720282 BJ |
306 | encollide(unit) |
307 | int unit; | |
308 | { | |
309 | register struct endevice *addr; | |
310 | register struct uba_device *ui; | |
311 | COUNT(ENCOLLIDE); | |
312 | ||
3552a746 | 313 | collisions++; |
11720282 BJ |
314 | ui = eninfo[unit]; |
315 | addr = (struct endevice *)ui->ui_addr; | |
316 | ||
317 | #ifdef IMPDEBUG | |
318 | printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS); | |
319 | #endif | |
320 | if (!imp_stat.outactive) { | |
321 | printf("en%d: phantom collision intr ostat=%b\n", | |
322 | unit, addr->en_ostat, EN_BITS); | |
323 | return; | |
324 | } | |
325 | if (imp_stat.enmask == 0) { | |
326 | printf("en%d: output error ostat=%b\n", unit, | |
327 | addr->en_ostat, EN_BITS); | |
328 | } else { | |
329 | imp_stat.enmask <<= 1; | |
3552a746 | 330 | imp_stat.endelay = mfpr(ICR) & ~imp_stat.enmask; |
11720282 | 331 | } |
ae348eea | 332 | enstart(unit); |
11720282 BJ |
333 | } |
334 | ||
335 | enrint(unit) | |
336 | int unit; | |
337 | { | |
338 | register struct mbuf *m; | |
339 | struct mbuf *mp; | |
340 | register struct endevice *addr; | |
341 | register struct uba_device *ui; | |
342 | register int len; | |
343 | register caddr_t cp; | |
344 | struct mbuf *p, *top = 0; | |
345 | struct ip *ip; | |
346 | int j, hlen; | |
347 | COUNT(ENRINT); | |
348 | ||
349 | ui = eninfo[unit]; | |
350 | addr = (struct endevice *)ui->ui_addr; | |
351 | #ifdef IMPDEBUG | |
352 | printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS); | |
353 | #endif | |
354 | if (imp_stat.flush) | |
355 | goto flush; | |
941ee7ef | 356 | if (addr->en_istat&EN_IERROR) { |
11720282 BJ |
357 | #ifdef notdef |
358 | printf("en%d: input error istat=%b\n", unit, | |
359 | addr->en_istat, EN_BITS); | |
360 | #endif | |
361 | goto flush; | |
362 | } | |
363 | #if defined(VAX780) || defined(VAX750) | |
364 | switch (cpu) { | |
365 | #if defined(VAX780) | |
366 | case VAX_780: | |
367 | UBA_PURGE780(enuba, enrbdp); | |
368 | break; | |
369 | #endif | |
370 | #if defined(VAX750) | |
371 | case VAX_750: | |
372 | UBA_PURGE750(enuba, enrbdp); | |
373 | break; | |
374 | #endif | |
375 | } | |
376 | #endif | |
377 | ip = (struct ip *)((int)rpkt + L1822); | |
378 | len = ntohs(ip->ip_len) + L1822; | |
379 | if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) { | |
380 | printf("enrint: bad ip length %d\n", len); | |
381 | goto flush; | |
382 | } | |
383 | hlen = L1822 + sizeof (struct ip); | |
384 | switch (ip->ip_p) { | |
385 | ||
e1506033 | 386 | case IPPROTO_TCP: |
53a5409e | 387 | hlen += ((struct tcpiphdr *)ip)->t_off * 4; |
11720282 BJ |
388 | break; |
389 | } | |
390 | MGET(m, 0); | |
391 | if (m == 0) | |
392 | goto flush; | |
393 | top = m; | |
394 | m->m_off = MMINOFF; | |
395 | m->m_len = hlen; | |
396 | bcopy(rpkt, mtod(m, caddr_t), hlen); | |
397 | len -= hlen; | |
398 | cp = (caddr_t)rpkt + hlen; | |
399 | mp = m; | |
400 | while (len > 0) { | |
401 | MGET(m, 0); | |
402 | if (m == NULL) | |
403 | goto flush; | |
404 | if (len >= PGSIZE) { | |
405 | MPGET(p, 1); | |
406 | if (p == 0) | |
407 | goto nopage; | |
408 | m->m_len = PGSIZE; | |
409 | m->m_off = (int)p - (int)m; | |
410 | if (((int)cp & 0x3ff) == 0) { | |
d52566dd BJ |
411 | struct pte *cpte = &Mbmap[mtopf(cp)*2]; |
412 | struct pte *ppte = &Mbmap[mtopf(p)*2]; | |
11720282 BJ |
413 | struct pte t; |
414 | enrswaps++; | |
415 | t = *ppte; *ppte++ = *cpte; *cpte++ = t; | |
416 | t = *ppte; *ppte = *cpte; *cpte = t; | |
417 | mtpr(TBIS, (caddr_t)cp); | |
418 | mtpr(TBIS, (caddr_t)cp+512); | |
419 | mtpr(TBIS, (caddr_t)p); | |
420 | mtpr(TBIS, (caddr_t)p+512); | |
421 | *(int *)(enrmr+1) = | |
422 | cpte[0].pg_pfnum | enrproto; | |
423 | *(int *)(enrmr) = | |
424 | cpte[-1].pg_pfnum | enrproto; | |
425 | goto nocopy; | |
426 | } | |
427 | } else { | |
428 | nopage: | |
429 | m->m_len = MIN(MLEN, len); | |
430 | m->m_off = MMINOFF; | |
431 | } | |
432 | bcopy(cp, (int)m + m->m_off, m->m_len); | |
433 | nocopy: | |
434 | cp += m->m_len; | |
435 | len -= m->m_len; | |
436 | mp->m_next = m; | |
437 | mp = m; | |
438 | } | |
439 | m = top; | |
440 | if (imp_stat.inq_head != NULL) | |
441 | imp_stat.inq_tail->m_act = m; | |
442 | else | |
443 | imp_stat.inq_head = m; | |
444 | imp_stat.inq_tail = m; | |
445 | #ifdef IMPDEBUG | |
446 | printf("en%d: received packet (%d bytes)\n", unit, len); | |
447 | prt_byte(rpkt, len); | |
448 | #endif | |
449 | setsoftnet(); | |
ae348eea | 450 | goto setup; |
11720282 BJ |
451 | flush: |
452 | m_freem(top); | |
453 | #ifdef IMPDEBUG | |
454 | printf("en%d: flushing packet %x\n", unit, top); | |
455 | #endif | |
ae348eea BJ |
456 | setup: |
457 | addr->en_iba = imp_stat.iaddr; | |
458 | addr->en_iwc = -600; | |
941ee7ef | 459 | addr->en_istat = EN_IEN|EN_GO; |
ae348eea | 460 | } |
11720282 BJ |
461 | |
462 | #ifdef IMPDEBUG | |
463 | prt_byte(s, ct) | |
464 | register char *s; | |
465 | int ct; | |
466 | { | |
467 | register i, j, c; | |
468 | ||
469 | for (i=0; i<ct; i++) { | |
470 | c = *s++; | |
471 | for (j=0; j<2 ; j++) | |
472 | putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]); | |
473 | putchar(' '); | |
474 | } | |
475 | putchar('\n'); | |
476 | } | |
477 | #endif IMPDEBUG |