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