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