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