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