faster imp code...
[unix-history] / usr / src / sys / vax / if / if_en.c
CommitLineData
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
30int enrswaps, enwswaps;
31int enprobe(), enattach(), enrint(), enxint(), encollide();
32struct uba_device *eninfo[NEN];
33u_short enstd[] = { 0 };
34struct uba_driver endriver =
35 { enprobe, 0, enattach, 0, enstd, "en", eninfo };
36
37#define ENUNIT(x) minor(x)
38
39struct en_packet *xpkt, *rpkt;
40struct en_prefix {
41 struct en_header enp_h;
42 struct th enp_th;
43};
44struct uba_regs *enuba;
ae348eea 45struct pte *enrmr, *enxmr;
11720282
BJ
46int enrbdp, enwbdp;
47int enrproto, enwproto;
ae348eea
BJ
48struct pte enxmap[2];
49int enxswapd;
11720282
BJ
50
51enprobe(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
72enattach(ui)
73 struct uba_device *ui;
74{
ae348eea 75
11720282
BJ
76}
77
ae348eea 78eninit(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
140enreset(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 159enstart(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;
170COUNT(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 246ensetup(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 253COUNT(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 */
269enxint(unit)
270 int unit;
271{
272 register struct endevice *addr;
273 register struct uba_device *ui;
274COUNT(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
297encollide(unit)
298 int unit;
299{
300 register struct endevice *addr;
301 register struct uba_device *ui;
302COUNT(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
325enrint(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;
337COUNT(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 {
418nopage:
419 m->m_len = MIN(MLEN, len);
420 m->m_off = MMINOFF;
421 }
422 bcopy(cp, (int)m + m->m_off, m->m_len);
423nocopy:
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
441flush:
442 m_freem(top);
443#ifdef IMPDEBUG
444 printf("en%d: flushing packet %x\n", unit, top);
445#endif
ae348eea
BJ
446setup:
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
453prt_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