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