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