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