Commit | Line | Data |
---|---|---|
ae348eea | 1 | /* if_en.c 4.2 81/10/31 */ |
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" | |
11 | #include "../inet/inet.h" | |
12 | #include "../inet/inet_systm.h" | |
13 | #include "../inet/imp.h" | |
14 | #include "../inet/ip.h" | |
15 | #include "../inet/tcp.h" /* ### */ | |
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; | |
42 | struct th enp_th; | |
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; | |
65 | addr->en_ostat = IEN|GO; | |
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; | |
96 | i = rmalloc(netmap, n*2); | |
97 | if (i == 0) | |
ae348eea | 98 | panic("eninit"); |
11720282 BJ |
99 | j = i << 1; |
100 | cp = (char *)pftom(i); | |
101 | if (memall(&Netmap[j], k, proc, CSYS) == 0) | |
102 | return (0); | |
103 | vmaccess(&Netmap[j], (caddr_t)cp, k); | |
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 | ||
ae348eea | 159 | enstart(dev) |
11720282 BJ |
160 | dev_t dev; |
161 | { | |
162 | register struct mbuf *m, *mp; | |
163 | register struct endevice *addr; | |
164 | register caddr_t cp, top; | |
165 | int unit; | |
166 | register int len; | |
167 | u_short uaddr; | |
168 | struct uba_device *ui; | |
ae348eea BJ |
169 | int enxswapnow = 0; |
170 | COUNT(ENSTART); | |
11720282 BJ |
171 | |
172 | unit = ENUNIT(dev); | |
173 | ui = eninfo[unit]; | |
174 | if (ui == 0 || ui->ui_alive == 0) { | |
175 | printf("en%d (imp_output): not alive\n", unit); | |
176 | return; | |
177 | } | |
178 | addr = (struct endevice *)ui->ui_addr; | |
179 | if (!imp_stat.outactive) { | |
180 | if ((m = imp_stat.outq_head) == NULL) | |
181 | return; | |
182 | imp_stat.outactive = 1; /* set myself active */ | |
183 | imp_stat.outq_head = m->m_act; /* -> next packet chain */ | |
184 | /* | |
185 | * Pack mbufs into ethernet packet. | |
186 | */ | |
187 | cp = (caddr_t)xpkt; | |
188 | top = (caddr_t)xpkt + sizeof(struct en_packet); | |
189 | while (m != NULL) { | |
ae348eea | 190 | char *dp; |
11720282 BJ |
191 | if (cp + m->m_len > top) { |
192 | printf("imp_snd: my packet runneth over\n"); | |
193 | m_freem(m); | |
194 | return; | |
195 | } | |
ae348eea BJ |
196 | dp = mtod(m, char *); |
197 | if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) { | |
198 | struct pte *pte = &Netmap[mtopf(dp)*2]; | |
199 | *(int *)enxmr = enwproto | pte++->pg_pfnum; | |
200 | *(int *)(enxmr+1) = enwproto | pte->pg_pfnum; | |
201 | enxswapd = enxswapnow = 1; | |
202 | } else | |
203 | bcopy((int)m + m->m_off, cp, m->m_len); | |
11720282 | 204 | cp += m->m_len; |
ae348eea | 205 | /* too soon! */ |
11720282 BJ |
206 | MFREE(m, mp); |
207 | m = mp; | |
208 | } | |
209 | } | |
ae348eea BJ |
210 | if (enxswapnow == 0 && enxswapd) { |
211 | enxmr[0] = enxmap[0]; | |
212 | enxmr[1] = enxmap[1]; | |
213 | } | |
11720282 BJ |
214 | len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822; |
215 | if (len > sizeof(struct en_packet)) { | |
216 | printf("imp_output: ridiculous IP length %d\n", len); | |
217 | return; | |
218 | } | |
219 | #if defined(VAX780) || defined(VAX750) | |
220 | switch (cpu) { | |
221 | #if defined(VAX780) | |
222 | case VAX_780: | |
ae348eea | 223 | UBA_PURGE780(enuba, enwbdp); |
11720282 BJ |
224 | break; |
225 | #endif | |
226 | #if defined(VAX750) | |
227 | case VAX_750: | |
ae348eea | 228 | UBA_PURGE750(enuba, enwbdp); |
11720282 BJ |
229 | break; |
230 | #endif | |
231 | } | |
232 | #endif | |
233 | addr->en_oba = imp_stat.oaddr; | |
234 | addr->en_odelay = imp_stat.endelay; | |
235 | addr->en_owc = -((len + 1) >> 1); | |
236 | #ifdef IMPDEBUG | |
237 | printf("en%d: sending packet (%d bytes)\n", unit, len); | |
238 | prt_byte(xpkt, len); | |
239 | #endif | |
240 | addr->en_ostat = IEN|GO; | |
241 | } | |
242 | ||
243 | /* | |
ae348eea | 244 | * Setup for a read |
11720282 | 245 | */ |
ae348eea | 246 | ensetup(dev) |
11720282 BJ |
247 | dev_t dev; |
248 | { | |
249 | register struct endevice *addr; | |
250 | register struct uba_device *ui; | |
251 | register unsigned ubaddr; | |
252 | register int sps; | |
ae348eea | 253 | COUNT(ENSETUP); |
11720282 BJ |
254 | |
255 | ui = eninfo[ENUNIT(dev)]; | |
256 | if (ui == 0 || ui->ui_alive == 0) { | |
257 | printf("en%d (imp_read): not alive\n", ENUNIT(dev)); | |
258 | return; | |
259 | } | |
260 | addr = (struct endevice *)ui->ui_addr; | |
261 | addr->en_iba = imp_stat.iaddr; | |
262 | addr->en_iwc = -600; /* a little extra to avoid hardware bugs */ | |
263 | addr->en_istat = IEN|GO; | |
264 | } | |
265 | ||
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; | |
289 | if (addr->en_ostat&ERROR) | |
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); | |
11720282 BJ |
295 | } |
296 | ||
297 | encollide(unit) | |
298 | int unit; | |
299 | { | |
300 | register struct endevice *addr; | |
301 | register struct uba_device *ui; | |
302 | COUNT(ENCOLLIDE); | |
303 | ||
304 | ui = eninfo[unit]; | |
305 | addr = (struct endevice *)ui->ui_addr; | |
306 | ||
307 | #ifdef IMPDEBUG | |
308 | printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS); | |
309 | #endif | |
310 | if (!imp_stat.outactive) { | |
311 | printf("en%d: phantom collision intr ostat=%b\n", | |
312 | unit, addr->en_ostat, EN_BITS); | |
313 | return; | |
314 | } | |
315 | if (imp_stat.enmask == 0) { | |
316 | printf("en%d: output error ostat=%b\n", unit, | |
317 | addr->en_ostat, EN_BITS); | |
318 | } else { | |
319 | imp_stat.enmask <<= 1; | |
320 | imp_stat.endelay = time & ~imp_stat.enmask; | |
321 | } | |
ae348eea | 322 | enstart(unit); |
11720282 BJ |
323 | } |
324 | ||
325 | enrint(unit) | |
326 | int unit; | |
327 | { | |
328 | register struct mbuf *m; | |
329 | struct mbuf *mp; | |
330 | register struct endevice *addr; | |
331 | register struct uba_device *ui; | |
332 | register int len; | |
333 | register caddr_t cp; | |
334 | struct mbuf *p, *top = 0; | |
335 | struct ip *ip; | |
336 | int j, hlen; | |
337 | COUNT(ENRINT); | |
338 | ||
339 | ui = eninfo[unit]; | |
340 | addr = (struct endevice *)ui->ui_addr; | |
341 | #ifdef IMPDEBUG | |
342 | printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS); | |
343 | #endif | |
344 | if (imp_stat.flush) | |
345 | goto flush; | |
346 | if (addr->en_istat&ERROR) { | |
347 | #ifdef notdef | |
348 | printf("en%d: input error istat=%b\n", unit, | |
349 | addr->en_istat, EN_BITS); | |
350 | #endif | |
351 | goto flush; | |
352 | } | |
353 | #if defined(VAX780) || defined(VAX750) | |
354 | switch (cpu) { | |
355 | #if defined(VAX780) | |
356 | case VAX_780: | |
357 | UBA_PURGE780(enuba, enrbdp); | |
358 | break; | |
359 | #endif | |
360 | #if defined(VAX750) | |
361 | case VAX_750: | |
362 | UBA_PURGE750(enuba, enrbdp); | |
363 | break; | |
364 | #endif | |
365 | } | |
366 | #endif | |
367 | ip = (struct ip *)((int)rpkt + L1822); | |
368 | len = ntohs(ip->ip_len) + L1822; | |
369 | if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) { | |
370 | printf("enrint: bad ip length %d\n", len); | |
371 | goto flush; | |
372 | } | |
373 | hlen = L1822 + sizeof (struct ip); | |
374 | switch (ip->ip_p) { | |
375 | ||
376 | case TCPROTO: | |
377 | hlen += ((struct th *)ip)->t_off * 4; | |
378 | break; | |
379 | } | |
380 | MGET(m, 0); | |
381 | if (m == 0) | |
382 | goto flush; | |
383 | top = m; | |
384 | m->m_off = MMINOFF; | |
385 | m->m_len = hlen; | |
386 | bcopy(rpkt, mtod(m, caddr_t), hlen); | |
387 | len -= hlen; | |
388 | cp = (caddr_t)rpkt + hlen; | |
389 | mp = m; | |
390 | while (len > 0) { | |
391 | MGET(m, 0); | |
392 | if (m == NULL) | |
393 | goto flush; | |
394 | if (len >= PGSIZE) { | |
395 | MPGET(p, 1); | |
396 | if (p == 0) | |
397 | goto nopage; | |
398 | m->m_len = PGSIZE; | |
399 | m->m_off = (int)p - (int)m; | |
400 | if (((int)cp & 0x3ff) == 0) { | |
401 | struct pte *cpte = &Netmap[mtopf(cp)*2]; | |
402 | struct pte *ppte = &Netmap[mtopf(p)*2]; | |
403 | struct pte t; | |
404 | enrswaps++; | |
405 | t = *ppte; *ppte++ = *cpte; *cpte++ = t; | |
406 | t = *ppte; *ppte = *cpte; *cpte = t; | |
407 | mtpr(TBIS, (caddr_t)cp); | |
408 | mtpr(TBIS, (caddr_t)cp+512); | |
409 | mtpr(TBIS, (caddr_t)p); | |
410 | mtpr(TBIS, (caddr_t)p+512); | |
411 | *(int *)(enrmr+1) = | |
412 | cpte[0].pg_pfnum | enrproto; | |
413 | *(int *)(enrmr) = | |
414 | cpte[-1].pg_pfnum | enrproto; | |
415 | goto nocopy; | |
416 | } | |
417 | } else { | |
418 | nopage: | |
419 | m->m_len = MIN(MLEN, len); | |
420 | m->m_off = MMINOFF; | |
421 | } | |
422 | bcopy(cp, (int)m + m->m_off, m->m_len); | |
423 | nocopy: | |
424 | cp += m->m_len; | |
425 | len -= m->m_len; | |
426 | mp->m_next = m; | |
427 | mp = m; | |
428 | } | |
429 | m = top; | |
430 | if (imp_stat.inq_head != NULL) | |
431 | imp_stat.inq_tail->m_act = m; | |
432 | else | |
433 | imp_stat.inq_head = m; | |
434 | imp_stat.inq_tail = m; | |
435 | #ifdef IMPDEBUG | |
436 | printf("en%d: received packet (%d bytes)\n", unit, len); | |
437 | prt_byte(rpkt, len); | |
438 | #endif | |
439 | setsoftnet(); | |
ae348eea | 440 | goto setup; |
11720282 BJ |
441 | flush: |
442 | m_freem(top); | |
443 | #ifdef IMPDEBUG | |
444 | printf("en%d: flushing packet %x\n", unit, top); | |
445 | #endif | |
ae348eea BJ |
446 | setup: |
447 | addr->en_iba = imp_stat.iaddr; | |
448 | addr->en_iwc = -600; | |
449 | addr->en_istat = IEN|GO; | |
450 | } | |
11720282 BJ |
451 | |
452 | #ifdef IMPDEBUG | |
453 | prt_byte(s, ct) | |
454 | register char *s; | |
455 | int ct; | |
456 | { | |
457 | register i, j, c; | |
458 | ||
459 | for (i=0; i<ct; i++) { | |
460 | c = *s++; | |
461 | for (j=0; j<2 ; j++) | |
462 | putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]); | |
463 | putchar(' '); | |
464 | } | |
465 | putchar('\n'); | |
466 | } | |
467 | #endif IMPDEBUG |