xref: /csrg-svn/sys/vax/if/if_en.c (revision 4771)
1*4771Swnj /* if_en.c 4.5 81/11/07 */
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;
454688Swnj struct	pte *enrmr, *enxmr;
464686Swnj int	enrbdp, enwbdp;
474686Swnj int	enrproto, enwproto;
484688Swnj struct	pte enxmap[2];
494688Swnj 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;
65*4771Swnj 	addr->en_ostat = EN_IEN|EN_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 {
754688Swnj 
764686Swnj }
774686Swnj 
784688Swnj 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)
984688Swnj 			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];
1254688Swnj 	enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1];
1264688Swnj 	enxmap[0] = enxmr[0];
1274688Swnj 	enxmap[1] = enxmr[1];
1284688Swnj 	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);
1544688Swnj 		eninit(unit);
1554686Swnj 		printf("en%d ", unit);
1564686Swnj 	}
1574686Swnj }
1584686Swnj 
1594717Swnj int	enlastdel = 25;
1604717Swnj int	enlastx = 0;
1614688Swnj enstart(dev)
1624686Swnj 	dev_t dev;
1634686Swnj {
1644686Swnj 	register struct mbuf *m, *mp;
1654686Swnj 	register struct endevice *addr;
1664686Swnj 	register caddr_t cp, top;
1674686Swnj         int unit;
1684686Swnj         register int len;
1694686Swnj 	u_short uaddr;
1704686Swnj 	struct uba_device *ui;
1714688Swnj 	int enxswapnow = 0;
1724688Swnj COUNT(ENSTART);
1734686Swnj 
1744686Swnj 	unit = ENUNIT(dev);
1754686Swnj 	ui = eninfo[unit];
1764686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
1774686Swnj 		printf("en%d (imp_output): not alive\n", unit);
1784686Swnj 		return;
1794686Swnj 	}
1804686Swnj 	addr = (struct endevice *)ui->ui_addr;
1814686Swnj 	if (!imp_stat.outactive) {
1824686Swnj 		if ((m = imp_stat.outq_head) == NULL)
1834686Swnj 			return;
1844686Swnj 		imp_stat.outactive = 1;      /* set myself active */
1854686Swnj 		imp_stat.outq_head = m->m_act;  /* -> next packet chain */
1864686Swnj 		/*
1874686Swnj 		 * Pack mbufs into ethernet packet.
1884686Swnj 		 */
1894686Swnj 		cp = (caddr_t)xpkt;
1904686Swnj 		top = (caddr_t)xpkt + sizeof(struct en_packet);
1914686Swnj 		while (m != NULL) {
1924688Swnj 			char *dp;
1934686Swnj 			if (cp + m->m_len > top) {
1944686Swnj 				printf("imp_snd: my packet runneth over\n");
1954686Swnj 				m_freem(m);
1964686Swnj 				return;
1974686Swnj 			}
1984688Swnj 			dp = mtod(m, char *);
1994688Swnj 			if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) {
2004688Swnj 				struct pte *pte = &Netmap[mtopf(dp)*2];
2014688Swnj 				*(int *)enxmr = enwproto | pte++->pg_pfnum;
2024688Swnj 				*(int *)(enxmr+1) = enwproto | pte->pg_pfnum;
2034688Swnj 				enxswapd = enxswapnow = 1;
2044688Swnj 			} else
2054688Swnj 				bcopy((int)m + m->m_off, cp, m->m_len);
2064686Swnj 			cp += m->m_len;
2074688Swnj 			/* too soon! */
2084686Swnj 			MFREE(m, mp);
2094686Swnj 			m = mp;
2104686Swnj 		}
2114717Swnj 		if (enxswapnow == 0 && enxswapd) {
2124717Swnj 			enxmr[0] = enxmap[0];
2134717Swnj 			enxmr[1] = enxmap[1];
2144717Swnj 		}
2154717Swnj 		if (enlastx && enlastx == xpkt->Header.en_dhost)
2164717Swnj 			imp_stat.endelay = enlastdel;
2174717Swnj 		else
2184717Swnj 			enlastx = xpkt->Header.en_dhost;
2194686Swnj 	}
2204686Swnj 	len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822;
2214686Swnj 	if (len > sizeof(struct en_packet)) {
2224686Swnj 		printf("imp_output: ridiculous IP length %d\n", len);
2234686Swnj 		return;
2244686Swnj 	}
2254686Swnj #if defined(VAX780) || defined(VAX750)
2264686Swnj 	switch (cpu) {
2274686Swnj #if defined(VAX780)
2284686Swnj 	case VAX_780:
2294688Swnj 		UBA_PURGE780(enuba, enwbdp);
2304686Swnj 		break;
2314686Swnj #endif
2324686Swnj #if defined(VAX750)
2334686Swnj 	case VAX_750:
2344688Swnj 		UBA_PURGE750(enuba, enwbdp);
2354686Swnj 		break;
2364686Swnj #endif
2374686Swnj 	}
2384686Swnj #endif
2394686Swnj 	addr->en_oba = imp_stat.oaddr;
2404686Swnj 	addr->en_odelay = imp_stat.endelay;
2414686Swnj 	addr->en_owc = -((len + 1) >> 1);
2424686Swnj #ifdef IMPDEBUG
2434686Swnj 	printf("en%d: sending packet (%d bytes)\n", unit, len);
2444686Swnj 	prt_byte(xpkt, len);
2454686Swnj #endif
246*4771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
2474686Swnj }
2484686Swnj 
2494686Swnj /*
2504688Swnj  * Setup for a read
2514686Swnj  */
2524688Swnj ensetup(dev)
2534686Swnj 	dev_t dev;
2544686Swnj {
2554686Swnj 	register struct endevice *addr;
2564686Swnj 	register struct uba_device *ui;
2574686Swnj         register unsigned ubaddr;
2584686Swnj 	register int sps;
2594688Swnj COUNT(ENSETUP);
2604686Swnj 
2614686Swnj 	ui = eninfo[ENUNIT(dev)];
2624686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
2634686Swnj 		printf("en%d (imp_read): not alive\n", ENUNIT(dev));
2644686Swnj 		return;
2654686Swnj 	}
2664686Swnj 	addr = (struct endevice *)ui->ui_addr;
2674686Swnj 	addr->en_iba = imp_stat.iaddr;
2684686Swnj 	addr->en_iwc = -600;	/* a little extra to avoid hardware bugs */
269*4771Swnj 	addr->en_istat = EN_IEN|EN_GO;
2704686Swnj }
2714686Swnj 
2724686Swnj /*
2734686Swnj  * Output interrupt handler.
2744686Swnj  */
2754686Swnj enxint(unit)
2764686Swnj 	int unit;
2774686Swnj {
2784686Swnj 	register struct endevice *addr;
2794686Swnj 	register struct uba_device *ui;
2804686Swnj COUNT(ENXINT);
2814686Swnj 
2824686Swnj 	ui = eninfo[unit];
2834686Swnj 	addr = (struct endevice *)ui->ui_addr;
2844686Swnj 
2854686Swnj #ifdef IMPDEBUG
2864686Swnj 	printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS);
2874686Swnj #endif
2884686Swnj 	if (!imp_stat.outactive) {
2894686Swnj 		printf("en%d: phantom output intr ostat=%b\n",
2904686Swnj 			unit, addr->en_ostat, EN_BITS);
2914686Swnj 		return;
2924686Swnj 	}
2934686Swnj 	imp_stat.endelay = 0;
2944686Swnj 	imp_stat.enmask = ~0;
295*4771Swnj 	if (addr->en_ostat&EN_OERROR)
2964686Swnj 		printf("en%d: output error ostat=%b\n", unit,
2974686Swnj 			addr->en_ostat, EN_BITS);
2984686Swnj 	imp_stat.outactive = 0;
2994688Swnj 	if (imp_stat.outq_head)
3004688Swnj 		enstart(unit);
3014717Swnj 	else
3024717Swnj 		enlastx = 0;
3034686Swnj }
3044686Swnj 
3054717Swnj int collisions;
3064686Swnj encollide(unit)
3074686Swnj 	int unit;
3084686Swnj {
3094686Swnj 	register struct endevice *addr;
3104686Swnj 	register struct uba_device *ui;
3114686Swnj COUNT(ENCOLLIDE);
3124686Swnj 
3134717Swnj 	collisions++;
3144686Swnj 	ui = eninfo[unit];
3154686Swnj 	addr = (struct endevice *)ui->ui_addr;
3164686Swnj 
3174686Swnj #ifdef IMPDEBUG
3184686Swnj 	printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS);
3194686Swnj #endif
3204686Swnj 	if (!imp_stat.outactive) {
3214686Swnj 		printf("en%d: phantom collision intr ostat=%b\n",
3224686Swnj 			unit, addr->en_ostat, EN_BITS);
3234686Swnj 		return;
3244686Swnj 	}
3254686Swnj 	if (imp_stat.enmask == 0) {
3264686Swnj 		printf("en%d: output error ostat=%b\n", unit,
3274686Swnj 			addr->en_ostat, EN_BITS);
3284686Swnj 	} else {
3294686Swnj 		imp_stat.enmask <<= 1;
3304717Swnj 		imp_stat.endelay = mfpr(ICR) & ~imp_stat.enmask;
3314686Swnj 	}
3324688Swnj 	enstart(unit);
3334686Swnj }
3344686Swnj 
3354686Swnj enrint(unit)
3364686Swnj 	int unit;
3374686Swnj {
3384686Swnj     	register struct mbuf *m;
3394686Swnj 	struct mbuf *mp;
3404686Swnj 	register struct endevice *addr;
3414686Swnj 	register struct uba_device *ui;
3424686Swnj 	register int len;
3434686Swnj 	register caddr_t cp;
3444686Swnj 	struct mbuf *p, *top = 0;
3454686Swnj 	struct ip *ip;
3464686Swnj 	int j, hlen;
3474686Swnj COUNT(ENRINT);
3484686Swnj 
3494686Swnj 	ui = eninfo[unit];
3504686Swnj 	addr = (struct endevice *)ui->ui_addr;
3514686Swnj #ifdef IMPDEBUG
3524686Swnj 	printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS);
3534686Swnj #endif
3544686Swnj 	if (imp_stat.flush)
3554686Swnj 		goto flush;
356*4771Swnj 	if (addr->en_istat&EN_IERROR) {
3574686Swnj #ifdef notdef
3584686Swnj 		printf("en%d: input error istat=%b\n", unit,
3594686Swnj 			addr->en_istat, EN_BITS);
3604686Swnj #endif
3614686Swnj 		goto flush;
3624686Swnj 	}
3634686Swnj #if defined(VAX780) || defined(VAX750)
3644686Swnj 	switch (cpu) {
3654686Swnj #if defined(VAX780)
3664686Swnj 	case VAX_780:
3674686Swnj 		UBA_PURGE780(enuba, enrbdp);
3684686Swnj 		break;
3694686Swnj #endif
3704686Swnj #if defined(VAX750)
3714686Swnj 	case VAX_750:
3724686Swnj 		UBA_PURGE750(enuba, enrbdp);
3734686Swnj 		break;
3744686Swnj #endif
3754686Swnj 	}
3764686Swnj #endif
3774686Swnj 	ip = (struct ip *)((int)rpkt + L1822);
3784686Swnj 	len = ntohs(ip->ip_len) + L1822;
3794686Swnj 	if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) {
3804686Swnj 		printf("enrint: bad ip length %d\n", len);
3814686Swnj 		goto flush;
3824686Swnj 	}
3834686Swnj 	hlen = L1822 + sizeof (struct ip);
3844686Swnj 	switch (ip->ip_p) {
3854686Swnj 
3864732Swnj 	case IPPROTO_TCP:
3874686Swnj 		hlen += ((struct th *)ip)->t_off * 4;
3884686Swnj 		break;
3894686Swnj 	}
3904686Swnj 	MGET(m, 0);
3914686Swnj 	if (m == 0)
3924686Swnj 		goto flush;
3934686Swnj 	top = m;
3944686Swnj 	m->m_off = MMINOFF;
3954686Swnj 	m->m_len = hlen;
3964686Swnj 	bcopy(rpkt, mtod(m, caddr_t), hlen);
3974686Swnj 	len -= hlen;
3984686Swnj 	cp = (caddr_t)rpkt + hlen;
3994686Swnj 	mp = m;
4004686Swnj 	while (len > 0) {
4014686Swnj 		MGET(m, 0);
4024686Swnj 		if (m == NULL)
4034686Swnj 			goto flush;
4044686Swnj 		if (len >= PGSIZE) {
4054686Swnj 			MPGET(p, 1);
4064686Swnj 			if (p == 0)
4074686Swnj 				goto nopage;
4084686Swnj 			m->m_len = PGSIZE;
4094686Swnj 			m->m_off = (int)p - (int)m;
4104686Swnj 			if (((int)cp & 0x3ff) == 0) {
4114686Swnj 				struct pte *cpte = &Netmap[mtopf(cp)*2];
4124686Swnj 				struct pte *ppte = &Netmap[mtopf(p)*2];
4134686Swnj 				struct pte t;
4144686Swnj 				enrswaps++;
4154686Swnj 				t = *ppte; *ppte++ = *cpte; *cpte++ = t;
4164686Swnj 				t = *ppte; *ppte = *cpte; *cpte = t;
4174686Swnj 				mtpr(TBIS, (caddr_t)cp);
4184686Swnj 				mtpr(TBIS, (caddr_t)cp+512);
4194686Swnj 				mtpr(TBIS, (caddr_t)p);
4204686Swnj 				mtpr(TBIS, (caddr_t)p+512);
4214686Swnj 				*(int *)(enrmr+1) =
4224686Swnj 				    cpte[0].pg_pfnum | enrproto;
4234686Swnj 				*(int *)(enrmr) =
4244686Swnj 				    cpte[-1].pg_pfnum | enrproto;
4254686Swnj 				goto nocopy;
4264686Swnj 			}
4274686Swnj 		} else {
4284686Swnj nopage:
4294686Swnj 			m->m_len = MIN(MLEN, len);
4304686Swnj 			m->m_off = MMINOFF;
4314686Swnj 		}
4324686Swnj 		bcopy(cp, (int)m + m->m_off, m->m_len);
4334686Swnj nocopy:
4344686Swnj 		cp += m->m_len;
4354686Swnj 		len -= m->m_len;
4364686Swnj 		mp->m_next = m;
4374686Swnj 		mp = m;
4384686Swnj 	}
4394686Swnj 	m = top;
4404686Swnj 	if (imp_stat.inq_head != NULL)
4414686Swnj 		imp_stat.inq_tail->m_act = m;
4424686Swnj 	else
4434686Swnj 		imp_stat.inq_head = m;
4444686Swnj 	imp_stat.inq_tail = m;
4454686Swnj #ifdef IMPDEBUG
4464686Swnj 	printf("en%d: received packet (%d bytes)\n", unit, len);
4474686Swnj 	prt_byte(rpkt, len);
4484686Swnj #endif
4494686Swnj 	setsoftnet();
4504688Swnj 	goto setup;
4514686Swnj flush:
4524686Swnj 	m_freem(top);
4534686Swnj #ifdef IMPDEBUG
4544686Swnj 	printf("en%d: flushing packet %x\n", unit, top);
4554686Swnj #endif
4564688Swnj setup:
4574688Swnj 	addr->en_iba = imp_stat.iaddr;
4584688Swnj 	addr->en_iwc = -600;
459*4771Swnj 	addr->en_istat = EN_IEN|EN_GO;
4604688Swnj }
4614686Swnj 
4624686Swnj #ifdef IMPDEBUG
4634686Swnj prt_byte(s, ct)
4644686Swnj 	register char *s;
4654686Swnj 	int ct;
4664686Swnj {
4674686Swnj 	register i, j, c;
4684686Swnj 
4694686Swnj 	for (i=0; i<ct; i++) {
4704686Swnj 		c = *s++;
4714686Swnj 		for (j=0; j<2 ; j++)
4724686Swnj 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
4734686Swnj 		putchar(' ');
4744686Swnj 	}
4754686Swnj 	putchar('\n');
4764686Swnj }
4774686Swnj #endif IMPDEBUG
478