xref: /csrg-svn/sys/vax/if/if_en.c (revision 4922)
1*4922Swnj /* if_en.c 4.10 81/11/18 */
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"
124896Swnj #include "../net/inet_pcb.h"
134800Swnj #include "../net/inet_systm.h"
144800Swnj #include "../net/imp.h"
154800Swnj #include "../net/ip.h"
164896Swnj #include "../net/ip_var.h"
174883Swnj #include "../net/tcp.h"			/* XXX */
184896Swnj #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 
334906Swnj int	enrswaps;
344906Swnj /* int	enwswaps; */
354686Swnj int	enprobe(), enattach(), enrint(), enxint(), encollide();
364686Swnj struct	uba_device *eninfo[NEN];
374686Swnj u_short enstd[] = { 0 };
384686Swnj struct	uba_driver endriver =
394686Swnj 	{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
404686Swnj 
414686Swnj #define	ENUNIT(x)	minor(x)
424686Swnj 
434686Swnj struct	en_packet *xpkt, *rpkt;
444686Swnj struct	en_prefix {
454686Swnj 	struct en_header enp_h;
464883Swnj 	struct tcpiphdr enp_th;
474686Swnj };
484686Swnj struct	uba_regs *enuba;
494688Swnj struct	pte *enrmr, *enxmr;
504686Swnj int	enrbdp, enwbdp;
514686Swnj int	enrproto, enwproto;
524688Swnj struct	pte enxmap[2];
534688Swnj int	enxswapd;
544686Swnj 
554686Swnj enprobe(reg)
564686Swnj 	caddr_t reg;
574686Swnj {
584686Swnj 	register int br, cvec;
594686Swnj 	register struct endevice *addr = (struct endevice *)reg;
604686Swnj 
614686Swnj #ifdef lint
624686Swnj 	br = 0; cvec = br; br = cvec;
63*4922Swnj 	enrint(0); enxint(0); encollide(0);
644686Swnj #endif
654686Swnj 
664686Swnj 	addr->en_istat = 0;
674686Swnj 	addr->en_ostat = 0;
684686Swnj 	addr->en_owc = -1;
694686Swnj 	addr->en_oba = 0;
704771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
714686Swnj 	DELAY(100000);
724686Swnj 	addr->en_ostat = 0;
734686Swnj 	printf("ethernet address %d\n", ~addr->en_addr&0xff);
744686Swnj 	return (1);
754686Swnj }
764686Swnj 
774906Swnj /*ARGSUSED*/
784686Swnj enattach(ui)
794686Swnj 	struct uba_device *ui;
804686Swnj {
814688Swnj 
824686Swnj }
834686Swnj 
844688Swnj eninit(unit)
854686Swnj 	int unit;
864686Swnj {
874686Swnj 	register struct endevice *addr;
884686Swnj 	register struct uba_device *ui;
894686Swnj 	int uban, x;
904686Swnj 	static reenter;
914686Swnj 
924686Swnj 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
934686Swnj 		printf("en%d: not alive\n", unit);
944686Swnj 		return;
954686Swnj 	}
964686Swnj 	x = splimp();
974686Swnj 	if (reenter == 0) {
984686Swnj 		int n, j, i, k; char *cp;
994686Swnj 		reenter = 1;
1004686Swnj 		n = 10;
1014686Swnj 		k = n<<1;
1024800Swnj 		i = rmalloc(mbmap, n*2);
1034686Swnj 		if (i == 0)
1044688Swnj 			panic("eninit");
1054686Swnj 		j = i << 1;
1064686Swnj 		cp = (char *)pftom(i);
1074800Swnj 		if (memall(&Mbmap[j], k, proc, CSYS) == 0)
1084906Swnj 			panic("eninit");
1094800Swnj 		vmaccess(&Mbmap[j], (caddr_t)cp, k);
1104686Swnj 		rpkt = (struct en_packet *)
1114686Swnj 		    (cp + 1024 - sizeof (struct en_prefix));
1124686Swnj 		xpkt = (struct en_packet *)
1134686Swnj 		    (cp + 5 * 1024 + 1024 - sizeof (struct en_prefix));
1144686Swnj 		for (j = 0; j < n; j++)
1154686Swnj 			mprefcnt[i+j] = 1;
1164686Swnj 	}
1174686Swnj 	uban = ui->ui_ubanum;
1184686Swnj 	addr = (struct endevice *)ui->ui_addr;
1194686Swnj 	addr->en_istat = 0;
1204686Swnj 	addr->en_ostat = 0;
1214686Swnj 	imp_stat.iaddr =
1224686Swnj 	    uballoc(uban, (caddr_t)rpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
1234686Swnj 	imp_stat.oaddr =
1244686Swnj 	    uballoc(uban, (caddr_t)xpkt, 1024+512, UBA_NEED16|UBA_NEEDBDP);
1254686Swnj 	enuba = ui->ui_hd->uh_uba;
1264686Swnj 	enrbdp = (imp_stat.iaddr >> 28) & 0xf;
1274686Swnj 	enwbdp = (imp_stat.oaddr >> 28) & 0xf;
1284686Swnj 	enrproto = UBAMR_MRV | (enrbdp << 21);
1294686Swnj 	enwproto = UBAMR_MRV | (enwbdp << 21);
1304686Swnj 	enrmr = &enuba->uba_map[((imp_stat.iaddr>>9)&0x1ff) + 1];
1314688Swnj 	enxmr = &enuba->uba_map[((imp_stat.oaddr>>9)&0x1ff) + 1];
1324688Swnj 	enxmap[0] = enxmr[0];
1334688Swnj 	enxmap[1] = enxmr[1];
1344688Swnj 	enxswapd = 0;
1354686Swnj 	printf("enrbdp %x enrproto %x enrmr %x imp_stat.iaddr %x\n",
1364686Swnj 	    enrbdp, enrproto, enrmr, imp_stat.iaddr);
1374686Swnj 	imp_stat.impopen = 1;
1384686Swnj 	imp_stat.flush = 0;
1394686Swnj 	splx(x);
1404686Swnj #ifdef IMPDEBUG
1414686Swnj 	printf("eninit(%d): iaddr = %x, oaddr = %x\n",
1424686Swnj 		unit, imp_stat.iaddr, imp_stat.oaddr);
1434686Swnj #endif
1444686Swnj }
1454686Swnj 
1464686Swnj enreset(uban)
1474686Swnj 	int uban;
1484686Swnj {
1494686Swnj 	register int unit;
1504686Swnj 	struct uba_device *ui;
1514686Swnj 
1524686Swnj 	for (unit = 0; unit < NEN; unit++) {
1534686Swnj 		ui = eninfo[unit];
1544686Swnj 		if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
1554686Swnj 			continue;
1564686Swnj 		if (imp_stat.iaddr)
1574906Swnj 			ubarelse(uban, &imp_stat.iaddr);
1584686Swnj 		if (imp_stat.oaddr)
1594906Swnj 			ubarelse(uban, &imp_stat.oaddr);
1604688Swnj 		eninit(unit);
1614686Swnj 		printf("en%d ", unit);
1624686Swnj 	}
1634686Swnj }
1644686Swnj 
1654717Swnj int	enlastdel = 25;
1664717Swnj int	enlastx = 0;
1674688Swnj enstart(dev)
1684686Swnj 	dev_t dev;
1694686Swnj {
1704686Swnj 	register struct mbuf *m, *mp;
1714686Swnj 	register struct endevice *addr;
1724686Swnj 	register caddr_t cp, top;
1734686Swnj         int unit;
1744686Swnj         register int len;
1754686Swnj 	struct uba_device *ui;
1764688Swnj 	int enxswapnow = 0;
1774688Swnj COUNT(ENSTART);
1784686Swnj 
1794686Swnj 	unit = ENUNIT(dev);
1804686Swnj 	ui = eninfo[unit];
1814686Swnj 	if (ui == 0 || ui->ui_alive == 0) {
1824686Swnj 		printf("en%d (imp_output): not alive\n", unit);
1834686Swnj 		return;
1844686Swnj 	}
1854686Swnj 	addr = (struct endevice *)ui->ui_addr;
1864686Swnj 	if (!imp_stat.outactive) {
1874686Swnj 		if ((m = imp_stat.outq_head) == NULL)
1884686Swnj 			return;
1894686Swnj 		imp_stat.outactive = 1;      /* set myself active */
1904686Swnj 		imp_stat.outq_head = m->m_act;  /* -> next packet chain */
1914686Swnj 		/*
1924686Swnj 		 * Pack mbufs into ethernet packet.
1934686Swnj 		 */
1944686Swnj 		cp = (caddr_t)xpkt;
1954686Swnj 		top = (caddr_t)xpkt + sizeof(struct en_packet);
1964686Swnj 		while (m != NULL) {
1974688Swnj 			char *dp;
1984686Swnj 			if (cp + m->m_len > top) {
1994686Swnj 				printf("imp_snd: my packet runneth over\n");
2004686Swnj 				m_freem(m);
2014686Swnj 				return;
2024686Swnj 			}
2034688Swnj 			dp = mtod(m, char *);
2044688Swnj 			if (((int)cp&0x3ff)==0 && ((int)dp&0x3ff)==0) {
2054800Swnj 				struct pte *pte = &Mbmap[mtopf(dp)*2];
2064688Swnj 				*(int *)enxmr = enwproto | pte++->pg_pfnum;
2074688Swnj 				*(int *)(enxmr+1) = enwproto | pte->pg_pfnum;
2084688Swnj 				enxswapd = enxswapnow = 1;
2094688Swnj 			} else
2104906Swnj 				bcopy(mtod(m, caddr_t), cp,
2114906Swnj 				    (unsigned)m->m_len);
2124686Swnj 			cp += m->m_len;
2134688Swnj 			/* too soon! */
2144686Swnj 			MFREE(m, mp);
2154686Swnj 			m = mp;
2164686Swnj 		}
2174717Swnj 		if (enxswapnow == 0 && enxswapd) {
2184717Swnj 			enxmr[0] = enxmap[0];
2194717Swnj 			enxmr[1] = enxmap[1];
2204717Swnj 		}
2214717Swnj 		if (enlastx && enlastx == xpkt->Header.en_dhost)
2224717Swnj 			imp_stat.endelay = enlastdel;
2234717Swnj 		else
2244717Swnj 			enlastx = xpkt->Header.en_dhost;
2254686Swnj 	}
2264906Swnj 	len = ntohs((u_short)(((struct ip *)((int)xpkt + L1822))->ip_len)) +
2274906Swnj 	    L1822;
2284686Swnj 	if (len > sizeof(struct en_packet)) {
2294686Swnj 		printf("imp_output: ridiculous IP length %d\n", len);
2304686Swnj 		return;
2314686Swnj 	}
2324686Swnj #if defined(VAX780) || defined(VAX750)
2334686Swnj 	switch (cpu) {
2344686Swnj #if defined(VAX780)
2354686Swnj 	case VAX_780:
2364688Swnj 		UBA_PURGE780(enuba, enwbdp);
2374686Swnj 		break;
2384686Swnj #endif
2394686Swnj #if defined(VAX750)
2404686Swnj 	case VAX_750:
2414688Swnj 		UBA_PURGE750(enuba, enwbdp);
2424686Swnj 		break;
2434686Swnj #endif
2444686Swnj 	}
2454686Swnj #endif
2464686Swnj 	addr->en_oba = imp_stat.oaddr;
2474686Swnj 	addr->en_odelay = imp_stat.endelay;
2484686Swnj 	addr->en_owc = -((len + 1) >> 1);
2494686Swnj #ifdef IMPDEBUG
2504686Swnj 	printf("en%d: sending packet (%d bytes)\n", unit, len);
2514686Swnj 	prt_byte(xpkt, len);
2524686Swnj #endif
2534771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
2544686Swnj }
2554686Swnj 
2564686Swnj /*
2574686Swnj  * Output interrupt handler.
2584686Swnj  */
2594686Swnj enxint(unit)
2604686Swnj 	int unit;
2614686Swnj {
2624686Swnj 	register struct endevice *addr;
2634686Swnj 	register struct uba_device *ui;
2644686Swnj COUNT(ENXINT);
2654686Swnj 
2664686Swnj 	ui = eninfo[unit];
2674686Swnj 	addr = (struct endevice *)ui->ui_addr;
2684686Swnj 
2694686Swnj #ifdef IMPDEBUG
2704686Swnj 	printf("en%d: enxint ostat=%b\n", unit, addr->en_ostat, EN_BITS);
2714686Swnj #endif
2724686Swnj 	if (!imp_stat.outactive) {
2734686Swnj 		printf("en%d: phantom output intr ostat=%b\n",
2744686Swnj 			unit, addr->en_ostat, EN_BITS);
2754686Swnj 		return;
2764686Swnj 	}
2774686Swnj 	imp_stat.endelay = 0;
2784686Swnj 	imp_stat.enmask = ~0;
2794771Swnj 	if (addr->en_ostat&EN_OERROR)
2804686Swnj 		printf("en%d: output error ostat=%b\n", unit,
2814686Swnj 			addr->en_ostat, EN_BITS);
2824686Swnj 	imp_stat.outactive = 0;
2834688Swnj 	if (imp_stat.outq_head)
2844688Swnj 		enstart(unit);
2854717Swnj 	else
2864717Swnj 		enlastx = 0;
2874686Swnj }
2884686Swnj 
2894717Swnj int collisions;
2904686Swnj encollide(unit)
2914686Swnj 	int unit;
2924686Swnj {
2934686Swnj 	register struct endevice *addr;
2944686Swnj 	register struct uba_device *ui;
2954686Swnj COUNT(ENCOLLIDE);
2964686Swnj 
2974717Swnj 	collisions++;
2984686Swnj 	ui = eninfo[unit];
2994686Swnj 	addr = (struct endevice *)ui->ui_addr;
3004686Swnj 
3014686Swnj #ifdef IMPDEBUG
3024686Swnj 	printf("en%d: collision ostat=%b\n", unit, addr->en_ostat, EN_BITS);
3034686Swnj #endif
3044686Swnj 	if (!imp_stat.outactive) {
3054686Swnj 		printf("en%d: phantom collision intr ostat=%b\n",
3064686Swnj 			unit, addr->en_ostat, EN_BITS);
3074686Swnj 		return;
3084686Swnj 	}
3094686Swnj 	if (imp_stat.enmask == 0) {
3104686Swnj 		printf("en%d: output error ostat=%b\n", unit,
3114686Swnj 			addr->en_ostat, EN_BITS);
3124686Swnj 	} else {
3134686Swnj 		imp_stat.enmask <<= 1;
3144717Swnj 		imp_stat.endelay = mfpr(ICR) & ~imp_stat.enmask;
3154686Swnj 	}
3164688Swnj 	enstart(unit);
3174686Swnj }
3184686Swnj 
3194686Swnj enrint(unit)
3204686Swnj 	int unit;
3214686Swnj {
3224686Swnj     	register struct mbuf *m;
3234686Swnj 	struct mbuf *mp;
3244686Swnj 	register struct endevice *addr;
3254686Swnj 	register struct uba_device *ui;
3264686Swnj 	register int len;
3274686Swnj 	register caddr_t cp;
3284686Swnj 	struct mbuf *p, *top = 0;
3294686Swnj 	struct ip *ip;
3304906Swnj 	u_int hlen;
3314686Swnj COUNT(ENRINT);
3324686Swnj 
3334686Swnj 	ui = eninfo[unit];
3344686Swnj 	addr = (struct endevice *)ui->ui_addr;
3354686Swnj #ifdef IMPDEBUG
3364686Swnj 	printf("en%d: enrint istat=%b\n", unit, addr->en_istat, EN_BITS);
3374686Swnj #endif
3384686Swnj 	if (imp_stat.flush)
3394686Swnj 		goto flush;
3404771Swnj 	if (addr->en_istat&EN_IERROR) {
3414686Swnj #ifdef notdef
3424686Swnj 		printf("en%d: input error istat=%b\n", unit,
3434686Swnj 			addr->en_istat, EN_BITS);
3444686Swnj #endif
3454686Swnj 		goto flush;
3464686Swnj 	}
3474686Swnj #if defined(VAX780) || defined(VAX750)
3484686Swnj 	switch (cpu) {
3494686Swnj #if defined(VAX780)
3504686Swnj 	case VAX_780:
3514686Swnj 		UBA_PURGE780(enuba, enrbdp);
3524686Swnj 		break;
3534686Swnj #endif
3544686Swnj #if defined(VAX750)
3554686Swnj 	case VAX_750:
3564686Swnj 		UBA_PURGE750(enuba, enrbdp);
3574686Swnj 		break;
3584686Swnj #endif
3594686Swnj 	}
3604686Swnj #endif
3614686Swnj 	ip = (struct ip *)((int)rpkt + L1822);
3624686Swnj 	len = ntohs(ip->ip_len) + L1822;
3634686Swnj 	if (len > sizeof(struct en_packet) || len < sizeof (struct ip)) {
3644686Swnj 		printf("enrint: bad ip length %d\n", len);
3654686Swnj 		goto flush;
3664686Swnj 	}
3674686Swnj 	hlen = L1822 + sizeof (struct ip);
3684686Swnj 	switch (ip->ip_p) {
3694686Swnj 
3704732Swnj 	case IPPROTO_TCP:
3714896Swnj 		hlen += ((struct tcpiphdr *)ip)->ti_off << 2;
3724686Swnj 		break;
3734686Swnj 	}
3744686Swnj 	MGET(m, 0);
3754686Swnj 	if (m == 0)
3764686Swnj 		goto flush;
3774686Swnj 	top = m;
3784686Swnj 	m->m_off = MMINOFF;
3794686Swnj 	m->m_len = hlen;
3804906Swnj 	bcopy((caddr_t)rpkt, mtod(m, caddr_t), hlen);
3814686Swnj 	len -= hlen;
3824686Swnj 	cp = (caddr_t)rpkt + hlen;
3834686Swnj 	mp = m;
3844686Swnj 	while (len > 0) {
3854686Swnj 		MGET(m, 0);
3864686Swnj 		if (m == NULL)
3874686Swnj 			goto flush;
3884686Swnj 		if (len >= PGSIZE) {
3894686Swnj 			MPGET(p, 1);
3904686Swnj 			if (p == 0)
3914686Swnj 				goto nopage;
3924686Swnj 			m->m_len = PGSIZE;
3934686Swnj 			m->m_off = (int)p - (int)m;
3944686Swnj 			if (((int)cp & 0x3ff) == 0) {
3954800Swnj 				struct pte *cpte = &Mbmap[mtopf(cp)*2];
3964800Swnj 				struct pte *ppte = &Mbmap[mtopf(p)*2];
3974686Swnj 				struct pte t;
3984686Swnj 				enrswaps++;
3994686Swnj 				t = *ppte; *ppte++ = *cpte; *cpte++ = t;
4004686Swnj 				t = *ppte; *ppte = *cpte; *cpte = t;
4014686Swnj 				mtpr(TBIS, (caddr_t)cp);
4024686Swnj 				mtpr(TBIS, (caddr_t)cp+512);
4034686Swnj 				mtpr(TBIS, (caddr_t)p);
4044686Swnj 				mtpr(TBIS, (caddr_t)p+512);
4054686Swnj 				*(int *)(enrmr+1) =
4064686Swnj 				    cpte[0].pg_pfnum | enrproto;
4074686Swnj 				*(int *)(enrmr) =
4084686Swnj 				    cpte[-1].pg_pfnum | enrproto;
4094686Swnj 				goto nocopy;
4104686Swnj 			}
4114686Swnj 		} else {
4124686Swnj nopage:
4134686Swnj 			m->m_len = MIN(MLEN, len);
4144686Swnj 			m->m_off = MMINOFF;
4154686Swnj 		}
4164906Swnj 		bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
4174686Swnj nocopy:
4184686Swnj 		cp += m->m_len;
4194686Swnj 		len -= m->m_len;
4204686Swnj 		mp->m_next = m;
4214686Swnj 		mp = m;
4224686Swnj 	}
4234686Swnj 	m = top;
4244686Swnj 	if (imp_stat.inq_head != NULL)
4254686Swnj 		imp_stat.inq_tail->m_act = m;
4264686Swnj 	else
4274686Swnj 		imp_stat.inq_head = m;
4284686Swnj 	imp_stat.inq_tail = m;
4294686Swnj #ifdef IMPDEBUG
4304686Swnj 	printf("en%d: received packet (%d bytes)\n", unit, len);
4314686Swnj 	prt_byte(rpkt, len);
4324686Swnj #endif
4334686Swnj 	setsoftnet();
4344688Swnj 	goto setup;
4354686Swnj flush:
4364686Swnj 	m_freem(top);
4374686Swnj #ifdef IMPDEBUG
4384686Swnj 	printf("en%d: flushing packet %x\n", unit, top);
4394686Swnj #endif
4404688Swnj setup:
4414688Swnj 	addr->en_iba = imp_stat.iaddr;
4424688Swnj 	addr->en_iwc = -600;
4434771Swnj 	addr->en_istat = EN_IEN|EN_GO;
4444688Swnj }
4454686Swnj 
4464686Swnj #ifdef IMPDEBUG
4474686Swnj prt_byte(s, ct)
4484686Swnj 	register char *s;
4494686Swnj 	int ct;
4504686Swnj {
4514686Swnj 	register i, j, c;
4524686Swnj 
4534686Swnj 	for (i=0; i<ct; i++) {
4544686Swnj 		c = *s++;
4554686Swnj 		for (j=0; j<2 ; j++)
4564686Swnj 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
4574686Swnj 		putchar(' ');
4584686Swnj 	}
4594686Swnj 	putchar('\n');
4604686Swnj }
4614686Swnj #endif IMPDEBUG
462