xref: /csrg-svn/sys/vax/if/if_en.c (revision 4896)
1*4896Swnj /* if_en.c 4.8 81/11/15 */
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"
114800Swnj #include "../net/inet.h"
12*4896Swnj #include "../net/inet_pcb.h"
134800Swnj #include "../net/inet_systm.h"
144800Swnj #include "../net/imp.h"
154800Swnj #include "../net/ip.h"
16*4896Swnj #include "../net/ip_var.h"
174883Swnj #include "../net/tcp.h"			/* XXX */
18*4896Swnj #include "../net/tcp_var.h"
194686Swnj #include "../h/map.h"
204686Swnj #include "../h/pte.h"
214686Swnj #include "../h/buf.h"
224686Swnj #include "../h/ubareg.h"
234686Swnj #include "../h/ubavar.h"
244686Swnj #include "../h/conf.h"
254686Swnj #include "../h/dir.h"
264686Swnj #include "../h/user.h"
274686Swnj #include "../h/proc.h"
284686Swnj #include "../h/enreg.h"
294686Swnj #include "../h/mtpr.h"
304686Swnj #include "../h/cpu.h"
314686Swnj #include "../h/cmap.h"
324686Swnj 
334686Swnj int	enrswaps, enwswaps;
344686Swnj int	enprobe(), enattach(), enrint(), enxint(), encollide();
354686Swnj struct	uba_device *eninfo[NEN];
364686Swnj u_short enstd[] = { 0 };
374686Swnj struct	uba_driver endriver =
384686Swnj 	{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
394686Swnj 
404686Swnj #define	ENUNIT(x)	minor(x)
414686Swnj 
424686Swnj struct	en_packet *xpkt, *rpkt;
434686Swnj struct	en_prefix {
444686Swnj 	struct en_header enp_h;
454883Swnj 	struct tcpiphdr enp_th;
464686Swnj };
474686Swnj struct	uba_regs *enuba;
484688Swnj struct	pte *enrmr, *enxmr;
494686Swnj int	enrbdp, enwbdp;
504686Swnj int	enrproto, enwproto;
514688Swnj struct	pte enxmap[2];
524688Swnj int	enxswapd;
534686Swnj 
544686Swnj enprobe(reg)
554686Swnj 	caddr_t reg;
564686Swnj {
574686Swnj 	register int br, cvec;
584686Swnj 	register struct endevice *addr = (struct endevice *)reg;
594686Swnj 
604686Swnj #ifdef lint
614686Swnj 	br = 0; cvec = br; br = cvec;
624686Swnj #endif
634686Swnj 
644686Swnj 	addr->en_istat = 0;
654686Swnj 	addr->en_ostat = 0;
664686Swnj 	addr->en_owc = -1;
674686Swnj 	addr->en_oba = 0;
684771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
694686Swnj 	DELAY(100000);
704686Swnj 	addr->en_ostat = 0;
714686Swnj 	printf("ethernet address %d\n", ~addr->en_addr&0xff);
724686Swnj 	return (1);
734686Swnj }
744686Swnj 
754686Swnj enattach(ui)
764686Swnj 	struct uba_device *ui;
774686Swnj {
784688Swnj 
794686Swnj }
804686Swnj 
814688Swnj eninit(unit)
824686Swnj 	int unit;
834686Swnj {
844686Swnj 	register struct endevice *addr;
854686Swnj 	register struct uba_device *ui;
864686Swnj 	int uban, x;
874686Swnj 	static reenter;
884686Swnj 
894686Swnj 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
904686Swnj 		printf("en%d: not alive\n", unit);
914686Swnj 		return;
924686Swnj 	}
934686Swnj 	x = splimp();
944686Swnj 	if (reenter == 0) {
954686Swnj 		int n, j, i, k; char *cp;
964686Swnj 		reenter = 1;
974686Swnj 		n = 10;
984686Swnj 		k = n<<1;
994800Swnj 		i = rmalloc(mbmap, n*2);
1004686Swnj 		if (i == 0)
1014688Swnj 			panic("eninit");
1024686Swnj 		j = i << 1;
1034686Swnj 		cp = (char *)pftom(i);
1044800Swnj 		if (memall(&Mbmap[j], k, proc, CSYS) == 0)
1054686Swnj 			return (0);
1064800Swnj 		vmaccess(&Mbmap[j], (caddr_t)cp, k);
1074686Swnj 		rpkt = (struct en_packet *)
1084686Swnj 		    (cp + 1024 - sizeof (struct en_prefix));
1094686Swnj 		xpkt = (struct en_packet *)
1104686Swnj 		    (cp + 5 * 1024 + 1024 - sizeof (struct en_prefix));
1114686Swnj 		for (j = 0; j < n; j++)
1124686Swnj 			mprefcnt[i+j] = 1;
1134686Swnj 	}
1144686Swnj 	uban = ui->ui_ubanum;
1154686Swnj 	addr = (struct endevice *)ui->ui_addr;
1164686Swnj 	addr->en_istat = 0;
1174686Swnj 	addr->en_ostat = 0;
1184686Swnj 	imp_stat.iaddr =
1194686Swnj 	    uballoc(uban, (caddr_t)rpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
1204686Swnj 	imp_stat.oaddr =
1214686Swnj 	    uballoc(uban, (caddr_t)xpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
1224686Swnj 	enuba = ui->ui_hd->uh_uba;
1234686Swnj 	enrbdp = (imp_stat.iaddr >> 28) & 0xf;
1244686Swnj 	enwbdp = (imp_stat.oaddr >> 28) & 0xf;
1254686Swnj 	enrproto = UBAMR_MRV | (enrbdp << 21);
1264686Swnj 	enwproto = UBAMR_MRV | (enwbdp << 21);
1274686Swnj 	enrmr = &enuba->uba_map[((imp_stat.iaddr>>9)&0x1ff) + 1];
1284688Swnj 	enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1];
1294688Swnj 	enxmap[0] = enxmr[0];
1304688Swnj 	enxmap[1] = enxmr[1];
1314688Swnj 	enxswapd = 0;
1324686Swnj 	printf("enrbdp %x enrproto %x enrmr %x imp_stat.iaddr %x\n",
1334686Swnj 	    enrbdp, enrproto, enrmr, imp_stat.iaddr);
1344686Swnj 	imp_stat.impopen = 1;
1354686Swnj 	imp_stat.flush = 0;
1364686Swnj 	splx(x);
1374686Swnj #ifdef IMPDEBUG
1384686Swnj 	printf("eninit(%d): iaddr = %x, oaddr = %x\n",
1394686Swnj 		unit, imp_stat.iaddr, imp_stat.oaddr);
1404686Swnj #endif
1414686Swnj }
1424686Swnj 
1434686Swnj enreset(uban)
1444686Swnj 	int uban;
1454686Swnj {
1464686Swnj 	register int unit;
1474686Swnj 	struct uba_device *ui;
1484686Swnj 
1494686Swnj 	for (unit = 0; unit < NEN; unit++) {
1504686Swnj 		ui = eninfo[unit];
1514686Swnj 		if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
1524686Swnj 			continue;
1534686Swnj 		if (imp_stat.iaddr)
1544686Swnj 			ubarelse(uban, imp_stat.iaddr);
1554686Swnj 		if (imp_stat.oaddr)
1564686Swnj 			ubarelse(uban, imp_stat.oaddr);
1574688Swnj 		eninit(unit);
1584686Swnj 		printf("en%d ", unit);
1594686Swnj 	}
1604686Swnj }
1614686Swnj 
1624717Swnj int	enlastdel = 25;
1634717Swnj int	enlastx = 0;
1644688Swnj enstart(dev)
1654686Swnj 	dev_t dev;
1664686Swnj {
1674686Swnj 	register struct mbuf *m, *mp;
1684686Swnj 	register struct endevice *addr;
1694686Swnj 	register caddr_t cp, top;
1704686Swnj         int unit;
1714686Swnj         register int len;
1724686Swnj 	u_short uaddr;
1734686Swnj 	struct uba_device *ui;
1744688Swnj 	int enxswapnow = 0;
1754688Swnj COUNT(ENSTART);
1764686Swnj 
1774686Swnj 	unit = ENUNIT(dev);
1784686Swnj 	ui = eninfo[unit];
1794686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
1804686Swnj 		printf("en%d (imp_output): not alive\n", unit);
1814686Swnj 		return;
1824686Swnj 	}
1834686Swnj 	addr = (struct endevice *)ui->ui_addr;
1844686Swnj 	if (!imp_stat.outactive) {
1854686Swnj 		if ((m = imp_stat.outq_head) == NULL)
1864686Swnj 			return;
1874686Swnj 		imp_stat.outactive = 1;      /* set myself active */
1884686Swnj 		imp_stat.outq_head = m->m_act;  /* -> next packet chain */
1894686Swnj 		/*
1904686Swnj 		 * Pack mbufs into ethernet packet.
1914686Swnj 		 */
1924686Swnj 		cp = (caddr_t)xpkt;
1934686Swnj 		top = (caddr_t)xpkt + sizeof(struct en_packet);
1944686Swnj 		while (m != NULL) {
1954688Swnj 			char *dp;
1964686Swnj 			if (cp + m->m_len > top) {
1974686Swnj 				printf("imp_snd: my packet runneth over\n");
1984686Swnj 				m_freem(m);
1994686Swnj 				return;
2004686Swnj 			}
2014688Swnj 			dp = mtod(m, char *);
2024688Swnj 			if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) {
2034800Swnj 				struct pte *pte = &Mbmap[mtopf(dp)*2];
2044688Swnj 				*(int *)enxmr = enwproto | pte++->pg_pfnum;
2054688Swnj 				*(int *)(enxmr+1) = enwproto | pte->pg_pfnum;
2064688Swnj 				enxswapd = enxswapnow = 1;
2074688Swnj 			} else
2084688Swnj 				bcopy((int)m + m->m_off, cp, m->m_len);
2094686Swnj 			cp += m->m_len;
2104688Swnj 			/* too soon! */
2114686Swnj 			MFREE(m, mp);
2124686Swnj 			m = mp;
2134686Swnj 		}
2144717Swnj 		if (enxswapnow == 0 && enxswapd) {
2154717Swnj 			enxmr[0] = enxmap[0];
2164717Swnj 			enxmr[1] = enxmap[1];
2174717Swnj 		}
2184717Swnj 		if (enlastx && enlastx == xpkt->Header.en_dhost)
2194717Swnj 			imp_stat.endelay = enlastdel;
2204717Swnj 		else
2214717Swnj 			enlastx = xpkt->Header.en_dhost;
2224686Swnj 	}
2234686Swnj 	len = ntohs(((struct ip *)((int)xpkt + L1822))->ip_len) + L1822;
2244686Swnj 	if (len > sizeof(struct en_packet)) {
2254686Swnj 		printf("imp_output: ridiculous IP length %d\n", len);
2264686Swnj 		return;
2274686Swnj 	}
2284686Swnj #if defined(VAX780) || defined(VAX750)
2294686Swnj 	switch (cpu) {
2304686Swnj #if defined(VAX780)
2314686Swnj 	case VAX_780:
2324688Swnj 		UBA_PURGE780(enuba, enwbdp);
2334686Swnj 		break;
2344686Swnj #endif
2354686Swnj #if defined(VAX750)
2364686Swnj 	case VAX_750:
2374688Swnj 		UBA_PURGE750(enuba, enwbdp);
2384686Swnj 		break;
2394686Swnj #endif
2404686Swnj 	}
2414686Swnj #endif
2424686Swnj 	addr->en_oba = imp_stat.oaddr;
2434686Swnj 	addr->en_odelay = imp_stat.endelay;
2444686Swnj 	addr->en_owc = -((len + 1) >> 1);
2454686Swnj #ifdef IMPDEBUG
2464686Swnj 	printf("en%d: sending packet (%d bytes)\n", unit, len);
2474686Swnj 	prt_byte(xpkt, len);
2484686Swnj #endif
2494771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
2504686Swnj }
2514686Swnj 
2524686Swnj /*
2534688Swnj  * Setup for a read
2544686Swnj  */
2554688Swnj ensetup(dev)
2564686Swnj 	dev_t dev;
2574686Swnj {
2584686Swnj 	register struct endevice *addr;
2594686Swnj 	register struct uba_device *ui;
2604686Swnj         register unsigned ubaddr;
2614686Swnj 	register int sps;
2624688Swnj COUNT(ENSETUP);
2634686Swnj 
2644686Swnj 	ui = eninfo[ENUNIT(dev)];
2654686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
2664686Swnj 		printf("en%d (imp_read): not alive\n", ENUNIT(dev));
2674686Swnj 		return;
2684686Swnj 	}
2694686Swnj 	addr = (struct endevice *)ui->ui_addr;
2704686Swnj 	addr->en_iba = imp_stat.iaddr;
2714686Swnj 	addr->en_iwc = -600;	/* a little extra to avoid hardware bugs */
2724771Swnj 	addr->en_istat = EN_IEN|EN_GO;
2734686Swnj }
2744686Swnj 
2754686Swnj /*
2764686Swnj  * Output interrupt handler.
2774686Swnj  */
2784686Swnj enxint(unit)
2794686Swnj 	int unit;
2804686Swnj {
2814686Swnj 	register struct endevice *addr;
2824686Swnj 	register struct uba_device *ui;
2834686Swnj COUNT(ENXINT);
2844686Swnj 
2854686Swnj 	ui = eninfo[unit];
2864686Swnj 	addr = (struct endevice *)ui->ui_addr;
2874686Swnj 
2884686Swnj #ifdef IMPDEBUG
2894686Swnj 	printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS);
2904686Swnj #endif
2914686Swnj 	if (!imp_stat.outactive) {
2924686Swnj 		printf("en%d: phantom output intr ostat=%b\n",
2934686Swnj 			unit, addr->en_ostat, EN_BITS);
2944686Swnj 		return;
2954686Swnj 	}
2964686Swnj 	imp_stat.endelay = 0;
2974686Swnj 	imp_stat.enmask = ~0;
2984771Swnj 	if (addr->en_ostat&EN_OERROR)
2994686Swnj 		printf("en%d: output error ostat=%b\n", unit,
3004686Swnj 			addr->en_ostat, EN_BITS);
3014686Swnj 	imp_stat.outactive = 0;
3024688Swnj 	if (imp_stat.outq_head)
3034688Swnj 		enstart(unit);
3044717Swnj 	else
3054717Swnj 		enlastx = 0;
3064686Swnj }
3074686Swnj 
3084717Swnj int collisions;
3094686Swnj encollide(unit)
3104686Swnj 	int unit;
3114686Swnj {
3124686Swnj 	register struct endevice *addr;
3134686Swnj 	register struct uba_device *ui;
3144686Swnj COUNT(ENCOLLIDE);
3154686Swnj 
3164717Swnj 	collisions++;
3174686Swnj 	ui = eninfo[unit];
3184686Swnj 	addr = (struct endevice *)ui->ui_addr;
3194686Swnj 
3204686Swnj #ifdef IMPDEBUG
3214686Swnj 	printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS);
3224686Swnj #endif
3234686Swnj 	if (!imp_stat.outactive) {
3244686Swnj 		printf("en%d: phantom collision intr ostat=%b\n",
3254686Swnj 			unit, addr->en_ostat, EN_BITS);
3264686Swnj 		return;
3274686Swnj 	}
3284686Swnj 	if (imp_stat.enmask == 0) {
3294686Swnj 		printf("en%d: output error ostat=%b\n", unit,
3304686Swnj 			addr->en_ostat, EN_BITS);
3314686Swnj 	} else {
3324686Swnj 		imp_stat.enmask <<= 1;
3334717Swnj 		imp_stat.endelay = mfpr(ICR) & ~imp_stat.enmask;
3344686Swnj 	}
3354688Swnj 	enstart(unit);
3364686Swnj }
3374686Swnj 
3384686Swnj enrint(unit)
3394686Swnj 	int unit;
3404686Swnj {
3414686Swnj     	register struct mbuf *m;
3424686Swnj 	struct mbuf *mp;
3434686Swnj 	register struct endevice *addr;
3444686Swnj 	register struct uba_device *ui;
3454686Swnj 	register int len;
3464686Swnj 	register caddr_t cp;
3474686Swnj 	struct mbuf *p, *top = 0;
3484686Swnj 	struct ip *ip;
3494686Swnj 	int j, hlen;
3504686Swnj COUNT(ENRINT);
3514686Swnj 
3524686Swnj 	ui = eninfo[unit];
3534686Swnj 	addr = (struct endevice *)ui->ui_addr;
3544686Swnj #ifdef IMPDEBUG
3554686Swnj 	printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS);
3564686Swnj #endif
3574686Swnj 	if (imp_stat.flush)
3584686Swnj 		goto flush;
3594771Swnj 	if (addr->en_istat&EN_IERROR) {
3604686Swnj #ifdef notdef
3614686Swnj 		printf("en%d: input error istat=%b\n", unit,
3624686Swnj 			addr->en_istat, EN_BITS);
3634686Swnj #endif
3644686Swnj 		goto flush;
3654686Swnj 	}
3664686Swnj #if defined(VAX780) || defined(VAX750)
3674686Swnj 	switch (cpu) {
3684686Swnj #if defined(VAX780)
3694686Swnj 	case VAX_780:
3704686Swnj 		UBA_PURGE780(enuba, enrbdp);
3714686Swnj 		break;
3724686Swnj #endif
3734686Swnj #if defined(VAX750)
3744686Swnj 	case VAX_750:
3754686Swnj 		UBA_PURGE750(enuba, enrbdp);
3764686Swnj 		break;
3774686Swnj #endif
3784686Swnj 	}
3794686Swnj #endif
3804686Swnj 	ip = (struct ip *)((int)rpkt + L1822);
3814686Swnj 	len = ntohs(ip->ip_len) + L1822;
3824686Swnj 	if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) {
3834686Swnj 		printf("enrint: bad ip length %d\n", len);
3844686Swnj 		goto flush;
3854686Swnj 	}
3864686Swnj 	hlen = L1822 + sizeof (struct ip);
3874686Swnj 	switch (ip->ip_p) {
3884686Swnj 
3894732Swnj 	case IPPROTO_TCP:
390*4896Swnj 		hlen += ((struct tcpiphdr *)ip)->ti_off << 2;
3914686Swnj 		break;
3924686Swnj 	}
3934686Swnj 	MGET(m, 0);
3944686Swnj 	if (m == 0)
3954686Swnj 		goto flush;
3964686Swnj 	top = m;
3974686Swnj 	m->m_off = MMINOFF;
3984686Swnj 	m->m_len = hlen;
3994686Swnj 	bcopy(rpkt, mtod(m, caddr_t), hlen);
4004686Swnj 	len -= hlen;
4014686Swnj 	cp = (caddr_t)rpkt + hlen;
4024686Swnj 	mp = m;
4034686Swnj 	while (len > 0) {
4044686Swnj 		MGET(m, 0);
4054686Swnj 		if (m == NULL)
4064686Swnj 			goto flush;
4074686Swnj 		if (len >= PGSIZE) {
4084686Swnj 			MPGET(p, 1);
4094686Swnj 			if (p == 0)
4104686Swnj 				goto nopage;
4114686Swnj 			m->m_len = PGSIZE;
4124686Swnj 			m->m_off = (int)p - (int)m;
4134686Swnj 			if (((int)cp & 0x3ff) == 0) {
4144800Swnj 				struct pte *cpte = &Mbmap[mtopf(cp)*2];
4154800Swnj 				struct pte *ppte = &Mbmap[mtopf(p)*2];
4164686Swnj 				struct pte t;
4174686Swnj 				enrswaps++;
4184686Swnj 				t = *ppte; *ppte++ = *cpte; *cpte++ = t;
4194686Swnj 				t = *ppte; *ppte = *cpte; *cpte = t;
4204686Swnj 				mtpr(TBIS, (caddr_t)cp);
4214686Swnj 				mtpr(TBIS, (caddr_t)cp+512);
4224686Swnj 				mtpr(TBIS, (caddr_t)p);
4234686Swnj 				mtpr(TBIS, (caddr_t)p+512);
4244686Swnj 				*(int *)(enrmr+1) =
4254686Swnj 				    cpte[0].pg_pfnum | enrproto;
4264686Swnj 				*(int *)(enrmr) =
4274686Swnj 				    cpte[-1].pg_pfnum | enrproto;
4284686Swnj 				goto nocopy;
4294686Swnj 			}
4304686Swnj 		} else {
4314686Swnj nopage:
4324686Swnj 			m->m_len = MIN(MLEN, len);
4334686Swnj 			m->m_off = MMINOFF;
4344686Swnj 		}
4354686Swnj 		bcopy(cp, (int)m + m->m_off, m->m_len);
4364686Swnj nocopy:
4374686Swnj 		cp += m->m_len;
4384686Swnj 		len -= m->m_len;
4394686Swnj 		mp->m_next = m;
4404686Swnj 		mp = m;
4414686Swnj 	}
4424686Swnj 	m = top;
4434686Swnj 	if (imp_stat.inq_head != NULL)
4444686Swnj 		imp_stat.inq_tail->m_act = m;
4454686Swnj 	else
4464686Swnj 		imp_stat.inq_head = m;
4474686Swnj 	imp_stat.inq_tail = m;
4484686Swnj #ifdef IMPDEBUG
4494686Swnj 	printf("en%d: received packet (%d bytes)\n", unit, len);
4504686Swnj 	prt_byte(rpkt, len);
4514686Swnj #endif
4524686Swnj 	setsoftnet();
4534688Swnj 	goto setup;
4544686Swnj flush:
4554686Swnj 	m_freem(top);
4564686Swnj #ifdef IMPDEBUG
4574686Swnj 	printf("en%d: flushing packet %x\n", unit, top);
4584686Swnj #endif
4594688Swnj setup:
4604688Swnj 	addr->en_iba = imp_stat.iaddr;
4614688Swnj 	addr->en_iwc = -600;
4624771Swnj 	addr->en_istat = EN_IEN|EN_GO;
4634688Swnj }
4644686Swnj 
4654686Swnj #ifdef IMPDEBUG
4664686Swnj prt_byte(s, ct)
4674686Swnj 	register char *s;
4684686Swnj 	int ct;
4694686Swnj {
4704686Swnj 	register i, j, c;
4714686Swnj 
4724686Swnj 	for (i=0; i<ct; i++) {
4734686Swnj 		c = *s++;
4744686Swnj 		for (j=0; j<2 ; j++)
4754686Swnj 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
4764686Swnj 		putchar(' ');
4774686Swnj 	}
4784686Swnj 	putchar('\n');
4794686Swnj }
4804686Swnj #endif IMPDEBUG
481