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