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