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