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