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