xref: /csrg-svn/sys/vax/if/if_en.c (revision 4688)
1*4688Swnj /* if_en.c 4.2 81/10/31 */
24686Swnj 
34686Swnj #include "en.h"
44686Swnj /*
54686Swnj  * Ethernet interface driver
64686Swnj  */
74686Swnj 
84686Swnj #include "../h/param.h"
94686Swnj #include "../h/systm.h"
104686Swnj #include "../h/mbuf.h"
114686Swnj #include "../inet/inet.h"
124686Swnj #include "../inet/inet_systm.h"
134686Swnj #include "../inet/imp.h"
144686Swnj #include "../inet/ip.h"
154686Swnj #include "../inet/tcp.h"			/* ### */
164686Swnj #include "../h/map.h"
174686Swnj #include "../h/pte.h"
184686Swnj #include "../h/buf.h"
194686Swnj #include "../h/ubareg.h"
204686Swnj #include "../h/ubavar.h"
214686Swnj #include "../h/conf.h"
224686Swnj #include "../h/dir.h"
234686Swnj #include "../h/user.h"
244686Swnj #include "../h/proc.h"
254686Swnj #include "../h/enreg.h"
264686Swnj #include "../h/mtpr.h"
274686Swnj #include "../h/cpu.h"
284686Swnj #include "../h/cmap.h"
294686Swnj 
304686Swnj int	enrswaps, enwswaps;
314686Swnj int	enprobe(), enattach(), enrint(), enxint(), encollide();
324686Swnj struct	uba_device *eninfo[NEN];
334686Swnj u_short enstd[] = { 0 };
344686Swnj struct	uba_driver endriver =
354686Swnj 	{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
364686Swnj 
374686Swnj #define	ENUNIT(x)	minor(x)
384686Swnj 
394686Swnj struct	en_packet *xpkt, *rpkt;
404686Swnj struct	en_prefix {
414686Swnj 	struct en_header enp_h;
424686Swnj 	struct th enp_th;
434686Swnj };
444686Swnj struct	uba_regs *enuba;
45*4688Swnj struct	pte *enrmr, *enxmr;
464686Swnj int	enrbdp, enwbdp;
474686Swnj int	enrproto, enwproto;
48*4688Swnj struct	pte enxmap[2];
49*4688Swnj int	enxswapd;
504686Swnj 
514686Swnj enprobe(reg)
524686Swnj 	caddr_t reg;
534686Swnj {
544686Swnj 	register int br, cvec;
554686Swnj 	register struct endevice *addr = (struct endevice *)reg;
564686Swnj 
574686Swnj #ifdef lint
584686Swnj 	br = 0; cvec = br; br = cvec;
594686Swnj #endif
604686Swnj 
614686Swnj 	addr->en_istat = 0;
624686Swnj 	addr->en_ostat = 0;
634686Swnj 	addr->en_owc = -1;
644686Swnj 	addr->en_oba = 0;
654686Swnj 	addr->en_ostat = IEN|GO;
664686Swnj 	DELAY(100000);
674686Swnj 	addr->en_ostat = 0;
684686Swnj 	printf("ethernet address %d\n", ~addr->en_addr&0xff);
694686Swnj 	return (1);
704686Swnj }
714686Swnj 
724686Swnj enattach(ui)
734686Swnj 	struct uba_device *ui;
744686Swnj {
75*4688Swnj 
764686Swnj }
774686Swnj 
78*4688Swnj eninit(unit)
794686Swnj 	int unit;
804686Swnj {
814686Swnj 	register struct endevice *addr;
824686Swnj 	register struct uba_device *ui;
834686Swnj 	int uban, x;
844686Swnj 	static reenter;
854686Swnj 
864686Swnj 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
874686Swnj 		printf("en%d: not alive\n", unit);
884686Swnj 		return;
894686Swnj 	}
904686Swnj 	x = splimp();
914686Swnj 	if (reenter == 0) {
924686Swnj 		int n, j, i, k; char *cp;
934686Swnj 		reenter = 1;
944686Swnj 		n = 10;
954686Swnj 		k = n<<1;
964686Swnj 		i = rmalloc(netmap, n*2);
974686Swnj 		if (i == 0)
98*4688Swnj 			panic("eninit");
994686Swnj 		j = i << 1;
1004686Swnj 		cp = (char *)pftom(i);
1014686Swnj 		if (memall(&Netmap[j], k, proc, CSYS) == 0)
1024686Swnj 			return (0);
1034686Swnj 		vmaccess(&Netmap[j], (caddr_t)cp, k);
1044686Swnj 		rpkt = (struct en_packet *)
1054686Swnj 		    (cp + 1024 - sizeof (struct en_prefix));
1064686Swnj 		xpkt = (struct en_packet *)
1074686Swnj 		    (cp + 5 * 1024 + 1024 - sizeof (struct en_prefix));
1084686Swnj 		for (j = 0; j < n; j++)
1094686Swnj 			mprefcnt[i+j] = 1;
1104686Swnj 	}
1114686Swnj 	uban = ui->ui_ubanum;
1124686Swnj 	addr = (struct endevice *)ui->ui_addr;
1134686Swnj 	addr->en_istat = 0;
1144686Swnj 	addr->en_ostat = 0;
1154686Swnj 	imp_stat.iaddr =
1164686Swnj 	    uballoc(uban, (caddr_t)rpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
1174686Swnj 	imp_stat.oaddr =
1184686Swnj 	    uballoc(uban, (caddr_t)xpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
1194686Swnj 	enuba = ui->ui_hd->uh_uba;
1204686Swnj 	enrbdp = (imp_stat.iaddr >> 28) & 0xf;
1214686Swnj 	enwbdp = (imp_stat.oaddr >> 28) & 0xf;
1224686Swnj 	enrproto = UBAMR_MRV | (enrbdp << 21);
1234686Swnj 	enwproto = UBAMR_MRV | (enwbdp << 21);
1244686Swnj 	enrmr = &enuba->uba_map[((imp_stat.iaddr>>9)&0x1ff) + 1];
125*4688Swnj 	enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1];
126*4688Swnj 	enxmap[0] = enxmr[0];
127*4688Swnj 	enxmap[1] = enxmr[1];
128*4688Swnj 	enxswapd = 0;
1294686Swnj 	printf("enrbdp %x enrproto %x enrmr %x imp_stat.iaddr %x\n",
1304686Swnj 	    enrbdp, enrproto, enrmr, imp_stat.iaddr);
1314686Swnj 	imp_stat.impopen = 1;
1324686Swnj 	imp_stat.flush = 0;
1334686Swnj 	splx(x);
1344686Swnj #ifdef IMPDEBUG
1354686Swnj 	printf("eninit(%d): iaddr = %x, oaddr = %x\n",
1364686Swnj 		unit, imp_stat.iaddr, imp_stat.oaddr);
1374686Swnj #endif
1384686Swnj }
1394686Swnj 
1404686Swnj enreset(uban)
1414686Swnj 	int uban;
1424686Swnj {
1434686Swnj 	register int unit;
1444686Swnj 	struct uba_device *ui;
1454686Swnj 
1464686Swnj 	for (unit = 0; unit < NEN; unit++) {
1474686Swnj 		ui = eninfo[unit];
1484686Swnj 		if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
1494686Swnj 			continue;
1504686Swnj 		if (imp_stat.iaddr)
1514686Swnj 			ubarelse(uban, imp_stat.iaddr);
1524686Swnj 		if (imp_stat.oaddr)
1534686Swnj 			ubarelse(uban, imp_stat.oaddr);
154*4688Swnj 		eninit(unit);
1554686Swnj 		printf("en%d ", unit);
1564686Swnj 	}
1574686Swnj }
1584686Swnj 
159*4688Swnj enstart(dev)
1604686Swnj 	dev_t dev;
1614686Swnj {
1624686Swnj 	register struct mbuf *m, *mp;
1634686Swnj 	register struct endevice *addr;
1644686Swnj 	register caddr_t cp, top;
1654686Swnj         int unit;
1664686Swnj         register int len;
1674686Swnj 	u_short uaddr;
1684686Swnj 	struct uba_device *ui;
169*4688Swnj 	int enxswapnow = 0;
170*4688Swnj COUNT(ENSTART);
1714686Swnj 
1724686Swnj 	unit = ENUNIT(dev);
1734686Swnj 	ui = eninfo[unit];
1744686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
1754686Swnj 		printf("en%d (imp_output): not alive\n", unit);
1764686Swnj 		return;
1774686Swnj 	}
1784686Swnj 	addr = (struct endevice *)ui->ui_addr;
1794686Swnj 	if (!imp_stat.outactive) {
1804686Swnj 		if ((m = imp_stat.outq_head) == NULL)
1814686Swnj 			return;
1824686Swnj 		imp_stat.outactive = 1;      /* set myself active */
1834686Swnj 		imp_stat.outq_head = m->m_act;  /* -> next packet chain */
1844686Swnj 		/*
1854686Swnj 		 * Pack mbufs into ethernet packet.
1864686Swnj 		 */
1874686Swnj 		cp = (caddr_t)xpkt;
1884686Swnj 		top = (caddr_t)xpkt + sizeof(struct en_packet);
1894686Swnj 		while (m != NULL) {
190*4688Swnj 			char *dp;
1914686Swnj 			if (cp + m->m_len > top) {
1924686Swnj 				printf("imp_snd: my packet runneth over\n");
1934686Swnj 				m_freem(m);
1944686Swnj 				return;
1954686Swnj 			}
196*4688Swnj 			dp = mtod(m, char *);
197*4688Swnj 			if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) {
198*4688Swnj 				struct pte *pte = &Netmap[mtopf(dp)*2];
199*4688Swnj 				*(int *)enxmr = enwproto | pte++->pg_pfnum;
200*4688Swnj 				*(int *)(enxmr+1) = enwproto | pte->pg_pfnum;
201*4688Swnj 				enxswapd = enxswapnow = 1;
202*4688Swnj 			} else
203*4688Swnj 				bcopy((int)m + m->m_off, cp, m->m_len);
2044686Swnj 			cp += m->m_len;
205*4688Swnj 			/* too soon! */
2064686Swnj 			MFREE(m, mp);
2074686Swnj 			m = mp;
2084686Swnj 		}
2094686Swnj 	}
210*4688Swnj 	if (enxswapnow == 0 && enxswapd) {
211*4688Swnj 		enxmr[0] = enxmap[0];
212*4688Swnj 		enxmr[1] = enxmap[1];
213*4688Swnj 	}
2144686Swnj 	len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822;
2154686Swnj 	if (len > sizeof(struct en_packet)) {
2164686Swnj 		printf("imp_output: ridiculous IP length %d\n", len);
2174686Swnj 		return;
2184686Swnj 	}
2194686Swnj #if defined(VAX780) || defined(VAX750)
2204686Swnj 	switch (cpu) {
2214686Swnj #if defined(VAX780)
2224686Swnj 	case VAX_780:
223*4688Swnj 		UBA_PURGE780(enuba, enwbdp);
2244686Swnj 		break;
2254686Swnj #endif
2264686Swnj #if defined(VAX750)
2274686Swnj 	case VAX_750:
228*4688Swnj 		UBA_PURGE750(enuba, enwbdp);
2294686Swnj 		break;
2304686Swnj #endif
2314686Swnj 	}
2324686Swnj #endif
2334686Swnj 	addr->en_oba = imp_stat.oaddr;
2344686Swnj 	addr->en_odelay = imp_stat.endelay;
2354686Swnj 	addr->en_owc = -((len + 1) >> 1);
2364686Swnj #ifdef IMPDEBUG
2374686Swnj 	printf("en%d: sending packet (%d bytes)\n", unit, len);
2384686Swnj 	prt_byte(xpkt, len);
2394686Swnj #endif
2404686Swnj 	addr->en_ostat = IEN|GO;
2414686Swnj }
2424686Swnj 
2434686Swnj /*
244*4688Swnj  * Setup for a read
2454686Swnj  */
246*4688Swnj ensetup(dev)
2474686Swnj 	dev_t dev;
2484686Swnj {
2494686Swnj 	register struct endevice *addr;
2504686Swnj 	register struct uba_device *ui;
2514686Swnj         register unsigned ubaddr;
2524686Swnj 	register int sps;
253*4688Swnj COUNT(ENSETUP);
2544686Swnj 
2554686Swnj 	ui = eninfo[ENUNIT(dev)];
2564686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
2574686Swnj 		printf("en%d (imp_read): not alive\n", ENUNIT(dev));
2584686Swnj 		return;
2594686Swnj 	}
2604686Swnj 	addr = (struct endevice *)ui->ui_addr;
2614686Swnj 	addr->en_iba = imp_stat.iaddr;
2624686Swnj 	addr->en_iwc = -600;	/* a little extra to avoid hardware bugs */
2634686Swnj 	addr->en_istat = IEN|GO;
2644686Swnj }
2654686Swnj 
2664686Swnj /*
2674686Swnj  * Output interrupt handler.
2684686Swnj  */
2694686Swnj enxint(unit)
2704686Swnj 	int unit;
2714686Swnj {
2724686Swnj 	register struct endevice *addr;
2734686Swnj 	register struct uba_device *ui;
2744686Swnj COUNT(ENXINT);
2754686Swnj 
2764686Swnj 	ui = eninfo[unit];
2774686Swnj 	addr = (struct endevice *)ui->ui_addr;
2784686Swnj 
2794686Swnj #ifdef IMPDEBUG
2804686Swnj 	printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS);
2814686Swnj #endif
2824686Swnj 	if (!imp_stat.outactive) {
2834686Swnj 		printf("en%d: phantom output intr ostat=%b\n",
2844686Swnj 			unit, addr->en_ostat, EN_BITS);
2854686Swnj 		return;
2864686Swnj 	}
2874686Swnj 	imp_stat.endelay = 0;
2884686Swnj 	imp_stat.enmask = ~0;
2894686Swnj 	if (addr->en_ostat&ERROR)
2904686Swnj 		printf("en%d: output error ostat=%b\n", unit,
2914686Swnj 			addr->en_ostat, EN_BITS);
2924686Swnj 	imp_stat.outactive = 0;
293*4688Swnj 	if (imp_stat.outq_head)
294*4688Swnj 		enstart(unit);
2954686Swnj }
2964686Swnj 
2974686Swnj encollide(unit)
2984686Swnj 	int unit;
2994686Swnj {
3004686Swnj 	register struct endevice *addr;
3014686Swnj 	register struct uba_device *ui;
3024686Swnj COUNT(ENCOLLIDE);
3034686Swnj 
3044686Swnj 	ui = eninfo[unit];
3054686Swnj 	addr = (struct endevice *)ui->ui_addr;
3064686Swnj 
3074686Swnj #ifdef IMPDEBUG
3084686Swnj 	printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS);
3094686Swnj #endif
3104686Swnj 	if (!imp_stat.outactive) {
3114686Swnj 		printf("en%d: phantom collision intr ostat=%b\n",
3124686Swnj 			unit, addr->en_ostat, EN_BITS);
3134686Swnj 		return;
3144686Swnj 	}
3154686Swnj 	if (imp_stat.enmask == 0) {
3164686Swnj 		printf("en%d: output error ostat=%b\n", unit,
3174686Swnj 			addr->en_ostat, EN_BITS);
3184686Swnj 	} else {
3194686Swnj 		imp_stat.enmask <<= 1;
3204686Swnj 		imp_stat.endelay = time & ~imp_stat.enmask;
3214686Swnj 	}
322*4688Swnj 	enstart(unit);
3234686Swnj }
3244686Swnj 
3254686Swnj enrint(unit)
3264686Swnj 	int unit;
3274686Swnj {
3284686Swnj     	register struct mbuf *m;
3294686Swnj 	struct mbuf *mp;
3304686Swnj 	register struct endevice *addr;
3314686Swnj 	register struct uba_device *ui;
3324686Swnj 	register int len;
3334686Swnj 	register caddr_t cp;
3344686Swnj 	struct mbuf *p, *top = 0;
3354686Swnj 	struct ip *ip;
3364686Swnj 	int j, hlen;
3374686Swnj COUNT(ENRINT);
3384686Swnj 
3394686Swnj 	ui = eninfo[unit];
3404686Swnj 	addr = (struct endevice *)ui->ui_addr;
3414686Swnj #ifdef IMPDEBUG
3424686Swnj 	printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS);
3434686Swnj #endif
3444686Swnj 	if (imp_stat.flush)
3454686Swnj 		goto flush;
3464686Swnj 	if (addr->en_istat&ERROR) {
3474686Swnj #ifdef notdef
3484686Swnj 		printf("en%d: input error istat=%b\n", unit,
3494686Swnj 			addr->en_istat, EN_BITS);
3504686Swnj #endif
3514686Swnj 		goto flush;
3524686Swnj 	}
3534686Swnj #if defined(VAX780) || defined(VAX750)
3544686Swnj 	switch (cpu) {
3554686Swnj #if defined(VAX780)
3564686Swnj 	case VAX_780:
3574686Swnj 		UBA_PURGE780(enuba, enrbdp);
3584686Swnj 		break;
3594686Swnj #endif
3604686Swnj #if defined(VAX750)
3614686Swnj 	case VAX_750:
3624686Swnj 		UBA_PURGE750(enuba, enrbdp);
3634686Swnj 		break;
3644686Swnj #endif
3654686Swnj 	}
3664686Swnj #endif
3674686Swnj 	ip = (struct ip *)((int)rpkt + L1822);
3684686Swnj 	len = ntohs(ip->ip_len) + L1822;
3694686Swnj 	if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) {
3704686Swnj 		printf("enrint: bad ip length %d\n", len);
3714686Swnj 		goto flush;
3724686Swnj 	}
3734686Swnj 	hlen = L1822 + sizeof (struct ip);
3744686Swnj 	switch (ip->ip_p) {
3754686Swnj 
3764686Swnj 	case TCPROTO:
3774686Swnj 		hlen += ((struct th *)ip)->t_off * 4;
3784686Swnj 		break;
3794686Swnj 	}
3804686Swnj 	MGET(m, 0);
3814686Swnj 	if (m == 0)
3824686Swnj 		goto flush;
3834686Swnj 	top = m;
3844686Swnj 	m->m_off = MMINOFF;
3854686Swnj 	m->m_len = hlen;
3864686Swnj 	bcopy(rpkt, mtod(m, caddr_t), hlen);
3874686Swnj 	len -= hlen;
3884686Swnj 	cp = (caddr_t)rpkt + hlen;
3894686Swnj 	mp = m;
3904686Swnj 	while (len > 0) {
3914686Swnj 		MGET(m, 0);
3924686Swnj 		if (m == NULL)
3934686Swnj 			goto flush;
3944686Swnj 		if (len >= PGSIZE) {
3954686Swnj 			MPGET(p, 1);
3964686Swnj 			if (p == 0)
3974686Swnj 				goto nopage;
3984686Swnj 			m->m_len = PGSIZE;
3994686Swnj 			m->m_off = (int)p - (int)m;
4004686Swnj 			if (((int)cp & 0x3ff) == 0) {
4014686Swnj 				struct pte *cpte = &Netmap[mtopf(cp)*2];
4024686Swnj 				struct pte *ppte = &Netmap[mtopf(p)*2];
4034686Swnj 				struct pte t;
4044686Swnj 				enrswaps++;
4054686Swnj 				t = *ppte; *ppte++ = *cpte; *cpte++ = t;
4064686Swnj 				t = *ppte; *ppte = *cpte; *cpte = t;
4074686Swnj 				mtpr(TBIS, (caddr_t)cp);
4084686Swnj 				mtpr(TBIS, (caddr_t)cp+512);
4094686Swnj 				mtpr(TBIS, (caddr_t)p);
4104686Swnj 				mtpr(TBIS, (caddr_t)p+512);
4114686Swnj 				*(int *)(enrmr+1) =
4124686Swnj 				    cpte[0].pg_pfnum | enrproto;
4134686Swnj 				*(int *)(enrmr) =
4144686Swnj 				    cpte[-1].pg_pfnum | enrproto;
4154686Swnj 				goto nocopy;
4164686Swnj 			}
4174686Swnj 		} else {
4184686Swnj nopage:
4194686Swnj 			m->m_len = MIN(MLEN, len);
4204686Swnj 			m->m_off = MMINOFF;
4214686Swnj 		}
4224686Swnj 		bcopy(cp, (int)m + m->m_off, m->m_len);
4234686Swnj nocopy:
4244686Swnj 		cp += m->m_len;
4254686Swnj 		len -= m->m_len;
4264686Swnj 		mp->m_next = m;
4274686Swnj 		mp = m;
4284686Swnj 	}
4294686Swnj 	m = top;
4304686Swnj 	if (imp_stat.inq_head != NULL)
4314686Swnj 		imp_stat.inq_tail->m_act = m;
4324686Swnj 	else
4334686Swnj 		imp_stat.inq_head = m;
4344686Swnj 	imp_stat.inq_tail = m;
4354686Swnj #ifdef IMPDEBUG
4364686Swnj 	printf("en%d: received packet (%d bytes)\n", unit, len);
4374686Swnj 	prt_byte(rpkt, len);
4384686Swnj #endif
4394686Swnj 	setsoftnet();
440*4688Swnj 	goto setup;
4414686Swnj flush:
4424686Swnj 	m_freem(top);
4434686Swnj #ifdef IMPDEBUG
4444686Swnj 	printf("en%d: flushing packet %x\n", unit, top);
4454686Swnj #endif
446*4688Swnj setup:
447*4688Swnj 	addr->en_iba = imp_stat.iaddr;
448*4688Swnj 	addr->en_iwc = -600;
449*4688Swnj 	addr->en_istat = IEN|GO;
450*4688Swnj }
4514686Swnj 
4524686Swnj #ifdef IMPDEBUG
4534686Swnj prt_byte(s, ct)
4544686Swnj 	register char *s;
4554686Swnj 	int ct;
4564686Swnj {
4574686Swnj 	register i, j, c;
4584686Swnj 
4594686Swnj 	for (i=0; i<ct; i++) {
4604686Swnj 		c = *s++;
4614686Swnj 		for (j=0; j<2 ; j++)
4624686Swnj 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
4634686Swnj 		putchar(' ');
4644686Swnj 	}
4654686Swnj 	putchar('\n');
4664686Swnj }
4674686Swnj #endif IMPDEBUG
468