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