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