134405Skarels /* 234405Skarels * Copyright (c) 1988 Regents of the University of California. 334405Skarels * All rights reserved. 434405Skarels * 535411Skarels * This code is derived from software contributed to Berkeley by 635411Skarels * Computer Consoles Inc. 735411Skarels * 8*44532Sbostic * %sccs.include.redist.c% 934405Skarels * 10*44532Sbostic * @(#)if_ace.c 7.7 (Berkeley) 06/28/90 1134405Skarels */ 1224007Ssam 1324007Ssam /* 1424007Ssam * ACC VERSAbus Ethernet controller 1524007Ssam */ 1624007Ssam #include "ace.h" 1724007Ssam #if NACE > 0 1824007Ssam 1925694Ssam #include "param.h" 2025694Ssam #include "systm.h" 2135411Skarels #include "malloc.h" 2225694Ssam #include "mbuf.h" 2325694Ssam #include "buf.h" 2425694Ssam #include "protosw.h" 2525694Ssam #include "socket.h" 2625694Ssam #include "vmmac.h" 2725694Ssam #include "ioctl.h" 2825694Ssam #include "errno.h" 2925694Ssam #include "vmparam.h" 3025855Ssam #include "syslog.h" 3124007Ssam 3224007Ssam #include "../net/if.h" 3324007Ssam #include "../net/netisr.h" 3424007Ssam #include "../net/route.h" 3525855Ssam #ifdef INET 3624007Ssam #include "../netinet/in.h" 3724007Ssam #include "../netinet/in_systm.h" 3825694Ssam #include "../netinet/in_var.h" 3924007Ssam #include "../netinet/ip.h" 4024007Ssam #include "../netinet/ip_var.h" 4124007Ssam #include "../netinet/if_ether.h" 4225855Ssam #endif 4325855Ssam #ifdef NS 4425855Ssam #include "../netns/ns.h" 4525855Ssam #include "../netns/ns_if.h" 4625855Ssam #endif 4724007Ssam 4837503Smckusick #include "machine/cpu.h" 4937503Smckusick #include "machine/pte.h" 5030229Ssam 5124007Ssam #include "../tahoe/mtpr.h" 5224007Ssam #include "../tahoeif/if_acereg.h" 5325694Ssam #include "../tahoevba/vbavar.h" 5424007Ssam 5535411Skarels int aceprobe(), aceattach(), acerint(), acecint(), acestart(); 5624007Ssam struct vba_device *aceinfo[NACE]; 5725983Ssam long acestd[] = { 0 }; 5824007Ssam struct vba_driver acedriver = 5925927Ssam { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 }; 6024007Ssam 6124007Ssam int aceinit(), aceoutput(), aceioctl(), acereset(); 6224007Ssam struct mbuf *aceget(); 6324007Ssam 6424007Ssam /* 6524007Ssam * Ethernet software status per interface. 6624007Ssam * 6724007Ssam * Each interface is referenced by a network interface structure, 6824007Ssam * is_if, which the routing code uses to locate the interface. 6924007Ssam * This structure contains the output queue for the interface, its address, ... 7024007Ssam */ 7124007Ssam struct ace_softc { 7224007Ssam struct arpcom is_ac; /* Ethernet common part */ 7324007Ssam #define is_if is_ac.ac_if /* network-visible interface */ 7424007Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 7524007Ssam short is_flags; 7624007Ssam #define ACEF_OACTIVE 0x1 /* output is active */ 7724007Ssam #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ 7824007Ssam short is_promiscuous; /* true is enabled */ 7924007Ssam short is_segboundry; /* first TX Seg in dpm */ 8024007Ssam short is_eictr; /* Rx segment tracking ctr */ 8124007Ssam short is_eoctr; /* Tx segment tracking ctr */ 8224007Ssam short is_txnext; /* Next available Tx segment */ 8324007Ssam short is_currnd; /* current random backoff */ 8424007Ssam struct ace_stats is_stats; /* holds board statistics */ 8524007Ssam short is_xcnt; /* count xmitted segments to be acked 8624007Ssam by the controller */ 8725855Ssam long is_ivec; /* autoconfig interrupt vector base */ 8825927Ssam struct pte *is_map; /* pte map for dual ported memory */ 8925927Ssam caddr_t is_dpm; /* address of mapped memory */ 9024007Ssam } ace_softc[NACE]; 9124007Ssam extern struct ifnet loif; 9224007Ssam 9325855Ssam aceprobe(reg, vi) 9424007Ssam caddr_t reg; 9525855Ssam struct vba_device *vi; 9624007Ssam { 9725855Ssam register br, cvec; /* must be r12, r11 */ 9825855Ssam struct acedevice *ap = (struct acedevice *)reg; 9925855Ssam struct ace_softc *is = &ace_softc[vi->ui_unit]; 10024007Ssam 10124007Ssam #ifdef lint 10230295Ssam br = 0; cvec = br; br = cvec; 10324007Ssam acerint(0); acecint(0); 10424007Ssam #endif 10524007Ssam if (badaddr(reg, 2)) 10625855Ssam return (0); 10725855Ssam movow(&ap->csr, CSR_RESET); 10824007Ssam DELAY(10000); 10925855Ssam #ifdef notdef 11025855Ssam /* 11125855Ssam * Select two spaces for the interrupts aligned to an 11225855Ssam * eight vector boundary and fitting in 8 bits (as 11325855Ssam * required by the controller) -- YECH. The controller 11425855Ssam * will be notified later at initialization time. 11525855Ssam */ 11625855Ssam if ((vi->ui_hd->vh_lastiv -= 2) > 0xff) 11725855Ssam vi->ui_hd->vh_lastiv = 0x200; 11825855Ssam is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7; 11925855Ssam #else 12025855Ssam is->is_ivec = 0x90+vi->ui_unit*8; 12125855Ssam #endif 12225855Ssam br = 0x14, cvec = is->is_ivec; /* XXX */ 12325855Ssam return (sizeof (*ap)); 12424007Ssam } 12524007Ssam 12624007Ssam /* 12724007Ssam * Interface exists: make available by filling in network interface 12824007Ssam * record. System will initialize the interface when it is ready 12924007Ssam * to accept packets. 13024007Ssam */ 13124007Ssam aceattach(ui) 13224007Ssam struct vba_device *ui; 13324007Ssam { 13424007Ssam register short unit = ui->ui_unit; 13524007Ssam register struct ace_softc *is = &ace_softc[unit]; 13624007Ssam register struct ifnet *ifp = &is->is_if; 13724007Ssam register struct acedevice *addr = (struct acedevice *)ui->ui_addr; 13824007Ssam register short *wp, i; 13924007Ssam 14024007Ssam ifp->if_unit = unit; 14124007Ssam ifp->if_name = "ace"; 14224007Ssam ifp->if_mtu = ETHERMTU; 14324007Ssam /* 14429408Ssam * Get station's addresses and set multicast hash table. 14524007Ssam */ 14629408Ssam for (wp = (short *)addr->station, i = 0; i < 6; i++) 14729408Ssam is->is_addr[i] = ~*wp++; 14829408Ssam printf("ace%d: hardware address %s\n", unit, 14929408Ssam ether_sprintf(is->is_addr)); 15024007Ssam is->is_promiscuous = 0; 15129408Ssam for (wp = (short *)addr->hash, i = 0; i < 8; i++) 15229408Ssam movow(wp++, ~0xf); 15325694Ssam movow(&addr->bcastena[0], ~0xffff); 15425694Ssam movow(&addr->bcastena[1], ~0xffff); 15525927Ssam /* 15625927Ssam * Allocate and map dual ported VERSAbus memory. 15725927Ssam */ 15831735Skarels if (vbmemalloc(32, (caddr_t)ui->ui_flags, 15931735Skarels &is->is_map, &is->is_dpm) == 0) { 16031735Skarels printf("ace%d: can't allocate VERSAbus memory map\n", unit); 16131735Skarels return; 16231735Skarels } 16325927Ssam 16424007Ssam ifp->if_init = aceinit; 16537474Ssklower ifp->if_output = ether_output; 16635411Skarels ifp->if_start = acestart; 16724007Ssam ifp->if_ioctl = aceioctl; 16824007Ssam ifp->if_reset = acereset; 16935411Skarels ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 17024007Ssam if_attach(ifp); 17124007Ssam } 17224007Ssam 17324007Ssam /* 17424007Ssam * Reset of interface after "system" reset. 17524007Ssam */ 17624007Ssam acereset(unit, vban) 17724007Ssam int unit, vban; 17824007Ssam { 17924007Ssam register struct vba_device *ui; 18024007Ssam 18124007Ssam if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || 18224007Ssam ui->ui_vbanum != vban) 18324007Ssam return; 18424007Ssam printf(" ace%d", unit); 18524007Ssam aceinit(unit); 18624007Ssam } 18724007Ssam 18824007Ssam /* 18924007Ssam * Initialization of interface; clear recorded pending operations 19024007Ssam */ 19124007Ssam aceinit(unit) 19224007Ssam int unit; 19324007Ssam { 19424007Ssam register struct ace_softc *is = &ace_softc[unit]; 19524007Ssam register struct vba_device *ui = aceinfo[unit]; 19624007Ssam register struct acedevice *addr; 19724007Ssam register short Csr; 19825694Ssam register int s; 19924007Ssam 20035411Skarels if (is->is_if.if_addrlist == (struct ifaddr *)0) 20124007Ssam return; 20235411Skarels if ((is->is_if.if_flags & IFF_RUNNING) == 0) { 20324007Ssam /* 20424007Ssam * Reset the controller, initialize the recieve buffers, 20524007Ssam * and turn the controller on again and set board online. 20624007Ssam */ 20724007Ssam addr = (struct acedevice *)ui->ui_addr; 20824007Ssam s = splimp(); 20925694Ssam movow(&addr->csr, CSR_RESET); 21024007Ssam DELAY(10000); 21124007Ssam 21224007Ssam /* 21325927Ssam * Clean up dpm since the controller might 21425927Ssam * jumble dpm after reset. 21524007Ssam */ 21625927Ssam acesetup(unit); 21725694Ssam movow(&addr->csr, CSR_GO); 21824007Ssam Csr = addr->csr; 21924007Ssam if (Csr & CSR_ACTIVE) { 22025855Ssam movow(&addr->ivct, is->is_ivec); 22124007Ssam Csr |= CSR_IENA | is->is_promiscuous; 22225694Ssam movow(&addr->csr, Csr); 22324007Ssam is->is_flags = 0; 22424007Ssam is->is_xcnt = 0; 22525694Ssam is->is_if.if_flags |= IFF_RUNNING; 22624007Ssam } 22724007Ssam splx(s); 22824007Ssam } 22925694Ssam if (is->is_if.if_snd.ifq_head) 23035411Skarels acestart(&is->is_if); 23124007Ssam } 23224007Ssam 23324007Ssam /* 23424007Ssam * Start output on interface. 23524007Ssam * Get another datagram to send off of the interface queue, 23624007Ssam * and map it to the interface before starting the output. 23724007Ssam */ 23835411Skarels acestart(ifp) 23935411Skarels register struct ifnet *ifp; 24024007Ssam { 24124007Ssam register struct tx_segment *txs; 24225694Ssam register long len; 24325694Ssam register int s; 24424007Ssam struct mbuf *m; 24525694Ssam short retries; 24635411Skarels #define is ((struct ace_softc *)ifp) 24724007Ssam 24824007Ssam again: 24924007Ssam txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); 25024007Ssam if (txs->tx_csr & TCS_TBFULL) { 25124007Ssam is->is_stats.tx_busy++; 25235411Skarels ifp->if_flags |= IFF_OACTIVE; 25335411Skarels return (0); 25424007Ssam } 25525694Ssam s = splimp(); 25635411Skarels IF_DEQUEUE(&ifp->if_snd, m); 25725694Ssam splx(s); 25825927Ssam if (m == 0) { 25935411Skarels ifp->if_flags &= ~IFF_OACTIVE; 26035411Skarels return (0); 26125927Ssam } 26235411Skarels len = aceput(txs->tx_data, m); 26324007Ssam retries = txs->tx_csr & TCS_RTC; 26424007Ssam if (retries > 0) 26524007Ssam acebakoff(is, txs, retries); 26624007Ssam 26724007Ssam /* 26824007Ssam * Ensure minimum packet length. 26924007Ssam * This makes the safe assumtion that there are no virtual holes 27024007Ssam * after the data. 27124007Ssam * For security, it might be wise to zero out the added bytes, 27224007Ssam * but we're mainly interested in speed at the moment. 27324007Ssam */ 27424007Ssam if (len - sizeof (struct ether_header) < ETHERMIN) 27524007Ssam len = ETHERMIN + sizeof (struct ether_header); 27624007Ssam if (++is->is_txnext > SEG_MAX) 27724007Ssam is->is_txnext = is->is_segboundry; 27835411Skarels ifp->if_opackets++; 27924007Ssam is->is_xcnt++; 28024007Ssam len = (len & 0x7fff) | TCS_TBFULL; 28125694Ssam movow(txs, len); 28224007Ssam goto again; 28335411Skarels #undef is 28424007Ssam } 28524007Ssam 28624007Ssam /* 28724007Ssam * Transmit done interrupt. 28824007Ssam */ 28924007Ssam acecint(unit) 29024007Ssam int unit; 29124007Ssam { 29224007Ssam register struct ace_softc *is = &ace_softc[unit]; 29324007Ssam register struct tx_segment *txseg; 29425694Ssam short eostat; 29524007Ssam 29624007Ssam if (is->is_xcnt <= 0) { 29725855Ssam log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n", 29824007Ssam unit, is->is_xcnt); 29924007Ssam is->is_xcnt = 0; 30025694Ssam if (is->is_if.if_snd.ifq_head) 30135411Skarels acestart(&is->is_if); 30224007Ssam return; 30324007Ssam } 30424007Ssam is->is_xcnt--; 30524007Ssam txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); 30624007Ssam eostat = txseg->tx_csr; 30724007Ssam if ((eostat & TCS_TBFULL) == 0) { 30824007Ssam is->is_stats.tx_retries += eostat & TCS_RTC; 30924007Ssam if (eostat & TCS_RTFAIL) { 31024007Ssam is->is_stats.tx_discarded++; 31124007Ssam is->is_if.if_oerrors++; 31224007Ssam } else 31324007Ssam is->is_stats.tx_datagrams++; 31424007Ssam if (++is->is_eoctr >= 16) 31524007Ssam is->is_eoctr = is->is_segboundry; 31624007Ssam } 31725694Ssam if (is->is_if.if_snd.ifq_head) 31835411Skarels acestart(&is->is_if); 31924007Ssam } 32024007Ssam 32124007Ssam /* 32224007Ssam * Ethernet interface receiver interrupt. 32324007Ssam * If input error just drop packet. 32424007Ssam * Otherwise purge input buffered data path and examine 32524007Ssam * packet to determine type. If can't determine length 32624007Ssam * from type, then have to drop packet. Othewise decapsulate 32724007Ssam * packet based on type and pass to type specific higher-level 32824007Ssam * input routine. 32924007Ssam */ 33024007Ssam acerint(unit) 33124007Ssam int unit; 33224007Ssam { 33324007Ssam register struct ace_softc *is = &ace_softc[unit]; 33424007Ssam register struct ifqueue *inq; 33524007Ssam register struct ether_header *ace; 33624007Ssam register struct rx_segment *rxseg; 33724007Ssam int len, s, off, resid; 33824007Ssam struct mbuf *m; 33924007Ssam short eistat; 34024007Ssam 34125694Ssam if ((is->is_if.if_flags&IFF_RUNNING) == 0) 34225694Ssam return; 34324007Ssam again: 34424007Ssam rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); 34524007Ssam eistat = rxseg->rx_csr; 34624007Ssam if ((eistat & RCS_RBFULL) == 0) 34724007Ssam return; 34824007Ssam is->is_if.if_ipackets++; 34924007Ssam if (++is->is_eictr >= is->is_segboundry) 35024007Ssam is->is_eictr = 0; 35124007Ssam len = eistat & RCS_RBC; 35224007Ssam if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || 35324007Ssam len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { 35424007Ssam if (eistat & RCS_ROVRN) 35524007Ssam is->is_stats.rx_overruns++; 35624007Ssam if (eistat & RCS_RCRC) 35724007Ssam is->is_stats.rx_crc_errors++; 35824007Ssam if (eistat & RCS_RODD) 35924007Ssam is->is_stats.rx_align_errors++; 36024007Ssam if (len < ET_MINLEN) 36124007Ssam is->is_stats.rx_underruns++; 36224007Ssam if (len > ET_MAXLEN+CRC_SIZE) 36324007Ssam is->is_stats.rx_overruns++; 36424007Ssam is->is_if.if_ierrors++; 36524007Ssam rxseg->rx_csr = 0; 36624007Ssam return; 36724007Ssam } else 36824007Ssam is->is_stats.rx_datagrams++; 36924007Ssam ace = (struct ether_header *)rxseg->rx_data; 37024007Ssam len -= sizeof (struct ether_header); 37124007Ssam /* 37225694Ssam * Deal with trailer protocol: if type is trailer 37324007Ssam * get true type from first 16-bit word past data. 37424007Ssam * Remember that type was trailer by setting off. 37524007Ssam */ 37624007Ssam ace->ether_type = ntohs((u_short)ace->ether_type); 37724007Ssam #define acedataaddr(ace, off, type) \ 37824007Ssam ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) 37925694Ssam if (ace->ether_type >= ETHERTYPE_TRAIL && 38025694Ssam ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 38125694Ssam off = (ace->ether_type - ETHERTYPE_TRAIL) * 512; 38224007Ssam if (off >= ETHERMTU) 38324007Ssam goto setup; /* sanity */ 38424007Ssam ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); 38524007Ssam resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); 38624007Ssam if (off + resid > len) 38724007Ssam goto setup; /* sanity */ 38824007Ssam len = off + resid; 38924007Ssam } else 39024007Ssam off = 0; 39124007Ssam if (len == 0) 39224007Ssam goto setup; 39324007Ssam 39424007Ssam /* 39524007Ssam * Pull packet off interface. Off is nonzero if packet 39624007Ssam * has trailing header; aceget will then force this header 39735411Skarels * information to be at the front. 39824007Ssam */ 39925855Ssam m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if); 40040739Skarels if (m) 40140739Skarels ether_input(&is->is_if, ace, m); 40224007Ssam setup: 40324007Ssam rxseg->rx_csr = 0; 40424007Ssam goto again; 40524007Ssam } 40624007Ssam 40724007Ssam /* 40824007Ssam * Routine to copy from mbuf chain to transmit buffer on the VERSAbus 40924007Ssam * If packet size is less than the minimum legal size, 41024007Ssam * the buffer is expanded. We probably should zero out the extra 41124007Ssam * bytes for security, but that would slow things down. 41224007Ssam */ 41335411Skarels aceput(txbuf, m) 41425694Ssam char *txbuf; 41524007Ssam struct mbuf *m; 41637474Ssklower #ifdef notdef 41724007Ssam { 41825855Ssam register u_char *bp, *mcp; 41925855Ssam register short *s1, *s2; 42025694Ssam register u_int len; 42124007Ssam register struct mbuf *mp; 42225694Ssam int total; 42324007Ssam 42435411Skarels total = mp->m_pkthdr.len; 42525694Ssam bp = (u_char *)txbuf; 42637474Ssklower for (mp = m; mp; mp = mp->m_next) { 42724007Ssam len = mp->m_len; 42824007Ssam if (len == 0) 42924007Ssam continue; 43024007Ssam mcp = mtod(mp, u_char *); 43124007Ssam if (((int)mcp & 01) && ((int)bp & 01)) { 43224007Ssam /* source & destination at odd addresses */ 43325694Ssam movob(bp++, *mcp++); 43424007Ssam --len; 43524007Ssam } 43624007Ssam if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 43737474Ssklower int l = len & 1; 43824007Ssam 43924007Ssam s1 = (short *)bp; 44024007Ssam s2 = (short *)mcp; 44135411Skarels len >>= 1; /* count # of shorts */ 44235411Skarels while (len-- != 0) 44325694Ssam movow(s1++, *s2++); 44437474Ssklower len = l; /* # remaining bytes */ 44524007Ssam bp = (u_char *)s1; 44624007Ssam mcp = (u_char *)s2; 44724007Ssam } 44825694Ssam while (len-- != 0) 44925694Ssam movob(bp++, *mcp++); 45024007Ssam } 45124007Ssam m_freem(m); 45224007Ssam return (total); 45324007Ssam } 45437474Ssklower #else 45537474Ssklower { 45637474Ssklower register u_char *bp, *mcp; 45737474Ssklower register short *s1, *s2; 45837474Ssklower register u_int len; 45937474Ssklower register struct mbuf *mp; 46037474Ssklower int total; 46124007Ssam 46237474Ssklower total = 0; 46337474Ssklower bp = (u_char *)txbuf; 46437474Ssklower for (mp = m; (mp); mp = mp->m_next) { 46537474Ssklower len = mp->m_len; 46637474Ssklower if (len == 0) 46737474Ssklower continue; 46837474Ssklower total += len; 46937474Ssklower mcp = mtod(mp, u_char *); 47037474Ssklower if (((int)mcp & 01) && ((int)bp & 01)) { 47137474Ssklower /* source & destination at odd addresses */ 47237474Ssklower movob(bp++, *mcp++); 47337474Ssklower --len; 47437474Ssklower } 47537474Ssklower if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { 47637474Ssklower register u_int l; 47737474Ssklower 47837474Ssklower s1 = (short *)bp; 47937474Ssklower s2 = (short *)mcp; 48037474Ssklower l = len >> 1; /* count # of shorts */ 48137474Ssklower while (l-- != 0) 48237474Ssklower movow(s1++, *s2++); 48337474Ssklower len &= 1; /* # remaining bytes */ 48437474Ssklower bp = (u_char *)s1; 48537474Ssklower mcp = (u_char *)s2; 48637474Ssklower } 48737474Ssklower while (len-- != 0) 48837474Ssklower movob(bp++, *mcp++); 48937474Ssklower } 49037474Ssklower m_freem(m); 49137474Ssklower return (total); 49237474Ssklower } 49337474Ssklower #endif 49437474Ssklower 49524007Ssam /* 49624007Ssam * Routine to copy from VERSAbus memory into mbufs. 49724007Ssam * 49824007Ssam * Warning: This makes the fairly safe assumption that 49924007Ssam * mbufs have even lengths. 50024007Ssam */ 50124007Ssam struct mbuf * 50235411Skarels aceget(rxbuf, totlen, off, ifp) 50324007Ssam u_char *rxbuf; 50435411Skarels int totlen, off; 50525855Ssam struct ifnet *ifp; 50624007Ssam { 50725855Ssam register u_char *cp, *mcp; 50835411Skarels register struct mbuf *m; 50924007Ssam register int tlen; 51024007Ssam struct mbuf *top = 0, **mp = ⊤ 51135411Skarels int len; 51235411Skarels u_char *packet_end; 51324007Ssam 51435411Skarels rxbuf += sizeof (struct ether_header); 51535411Skarels cp = rxbuf; 51635411Skarels packet_end = cp + totlen; 51735411Skarels if (off) { 51835411Skarels off += 2 * sizeof(u_short); 51940739Skarels totlen -= 2 * sizeof(u_short); 52035411Skarels cp = rxbuf + off; 52135411Skarels } 52235411Skarels 52335411Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 52435411Skarels if (m == 0) 52535411Skarels return (0); 52635411Skarels m->m_pkthdr.rcvif = ifp; 52735411Skarels m->m_pkthdr.len = totlen; 52835411Skarels m->m_len = MHLEN; 52935411Skarels 53024007Ssam while (totlen > 0) { 53135411Skarels if (top) { 53235411Skarels MGET(m, M_DONTWAIT, MT_DATA); 53335411Skarels if (m == 0) { 53435411Skarels m_freem(top); 53535411Skarels return (0); 53635411Skarels } 53735411Skarels m->m_len = MLEN; 53835411Skarels } 53935411Skarels len = min(totlen, (packet_end - cp)); 54035411Skarels if (len >= MINCLSIZE) { 54135411Skarels MCLGET(m, M_DONTWAIT); 54235411Skarels if (m->m_flags & M_EXT) 54335411Skarels m->m_len = len = min(len, MCLBYTES); 54429563Ssam else 54535411Skarels len = m->m_len; 54624007Ssam } else { 54725855Ssam /* 54835411Skarels * Place initial small packet/header at end of mbuf. 54925855Ssam */ 55035411Skarels if (len < m->m_len) { 55135411Skarels if (top == 0 && len + max_linkhdr <= m->m_len) 55235411Skarels m->m_data += max_linkhdr; 55335411Skarels m->m_len = len; 55435411Skarels } else 55535411Skarels len = m->m_len; 55625855Ssam } 55735411Skarels mcp = mtod(m, u_char *); 55824007Ssam /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ 55924007Ssam /*cp += len; mcp += len;*/ 56024007Ssam tlen = len; 56124007Ssam if (((int)mcp & 01) && ((int)cp & 01)) { 56224007Ssam /* source & destination at odd addresses */ 56324007Ssam *mcp++ = *cp++; 56424007Ssam --tlen; 56524007Ssam } 56624007Ssam if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { 56724007Ssam register short *s1, *s2; 56824007Ssam register int l; 56924007Ssam 57024007Ssam s1 = (short *)mcp; 57124007Ssam s2 = (short *)cp; 57224007Ssam l = tlen >> 1; /* count # of shorts */ 57324007Ssam while (l-- > 0) /* copy shorts */ 57424007Ssam *s1++ = *s2++; 57524007Ssam tlen &= 1; /* # remaining bytes */ 57624007Ssam mcp = (u_char *)s1; 57724007Ssam cp = (u_char *)s2; 57824007Ssam } 57924007Ssam while (tlen-- > 0) 58024007Ssam *mcp++ = *cp++; 58124007Ssam *mp = m; 58224007Ssam mp = &m->m_next; 58335411Skarels totlen -= len; 58435411Skarels if (cp == packet_end) 58535411Skarels cp = rxbuf; 58624007Ssam } 58724007Ssam return (top); 58824007Ssam } 58924007Ssam 59029408Ssam /* backoff table masks */ 59129408Ssam short random_mask_tbl[16] = { 59229563Ssam 0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0, 59329563Ssam 0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0 59429408Ssam }; 59529408Ssam 59624007Ssam acebakoff(is, txseg, retries) 59724007Ssam struct ace_softc *is; 59824007Ssam struct tx_segment *txseg; 59924007Ssam register int retries; 60024007Ssam { 60124007Ssam register short *pBakNum, random_num; 60224007Ssam short *pMask; 60324007Ssam 60424007Ssam pMask = &random_mask_tbl[0]; 60524007Ssam pBakNum = &txseg->tx_backoff[0]; 60624007Ssam while (--retries >= 0) { 60724007Ssam random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); 60824007Ssam random_num &= *pMask++; 60929563Ssam *pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc); 61024007Ssam } 61124007Ssam } 61224007Ssam 61324007Ssam /* 61424007Ssam * Process an ioctl request. 61524007Ssam */ 61624007Ssam aceioctl(ifp, cmd, data) 61724007Ssam register struct ifnet *ifp; 61824007Ssam int cmd; 61924007Ssam caddr_t data; 62024007Ssam { 62125694Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 62225855Ssam struct acedevice *addr; 62325694Ssam int s = splimp(), error = 0; 62424007Ssam 62524007Ssam switch (cmd) { 62624007Ssam 62724007Ssam case SIOCSIFADDR: 62825694Ssam ifp->if_flags |= IFF_UP; 62937474Ssklower switch (ifa->ifa_addr->sa_family) { 63025855Ssam #ifdef INET 63125855Ssam case AF_INET: 63225855Ssam aceinit(ifp->if_unit); /* before arpwhohas */ 63325855Ssam ((struct arpcom *)ifp)->ac_ipaddr = 63425855Ssam IA_SIN(ifa)->sin_addr; 63525855Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 63625855Ssam break; 63725855Ssam #endif 63825855Ssam #ifdef NS 63925855Ssam case AF_NS: { 64025937Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 64125937Ssam struct ace_softc *is = &ace_softc[ifp->if_unit]; 64225855Ssam 64325855Ssam if (!ns_nullhost(*ina)) { 64425855Ssam ifp->if_flags &= ~IFF_RUNNING; 64525855Ssam addr = (struct acedevice *) 64625937Ssam aceinfo[ifp->if_unit]->ui_addr; 64725855Ssam movow(&addr->csr, CSR_RESET); 64825855Ssam DELAY(10000); 64925855Ssam /* set station address & copy addr to arp */ 65029408Ssam acesetaddr(ifp->if_unit, addr, 65125855Ssam ina->x_host.c_host); 65225855Ssam } else 65325937Ssam ina->x_host = *(union ns_host *)is->is_addr; 65425855Ssam aceinit(ifp->if_unit); 65525855Ssam break; 65625855Ssam } 65725855Ssam #endif 65825855Ssam default: 65925855Ssam aceinit(ifp->if_unit); 66025855Ssam break; 66125855Ssam } 66224007Ssam break; 66324007Ssam 66425855Ssam case SIOCSIFFLAGS: 66525855Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 66625855Ssam addr = (struct acedevice *) 66725855Ssam (aceinfo[ifp->if_unit]->ui_addr); 66825855Ssam movow(&addr->csr, CSR_RESET); 66925855Ssam ifp->if_flags &= ~IFF_RUNNING; 67025855Ssam } else if (ifp->if_flags&IFF_UP && 67125855Ssam (ifp->if_flags&IFF_RUNNING) == 0) 67225855Ssam aceinit(ifp->if_unit); 67324007Ssam break; 67424007Ssam 67524007Ssam default: 67624007Ssam error = EINVAL; 67724007Ssam } 67824007Ssam splx(s); 67924007Ssam return (error); 68024007Ssam } 68124007Ssam 68229408Ssam /* 68329408Ssam * Set the on-board station address, then read it back 68429408Ssam * to initialize the address used by ARP (among others). 68529408Ssam */ 68629408Ssam acesetaddr(unit, addr, station) 68729408Ssam short unit; 68829408Ssam struct acedevice *addr; 68930295Ssam u_char *station; 69029408Ssam { 69129408Ssam struct ace_softc *is = &ace_softc[unit]; 69229408Ssam register short *wp, i; 69329408Ssam 69429408Ssam for (wp = (short *)addr->station, i = 0; i < 6; i++) 69529408Ssam movow(wp++, ~*station++); 69629408Ssam for (wp = (short *)addr->station, i = 0; i < 6; i++) 69729408Ssam is->is_addr[i] = ~*wp++; 69829408Ssam printf("ace%d: hardware address %s\n", unit, 69929408Ssam ether_sprintf(is->is_addr)); 70029408Ssam } 70129408Ssam 70229408Ssam /* 70329408Ssam * Setup the device for use. Initialize dual-ported memory, 70429408Ssam * backoff parameters, and various other software state. 70529408Ssam */ 70625927Ssam acesetup(unit) 70724007Ssam int unit; 70824007Ssam { 70924007Ssam register struct ace_softc *is = &ace_softc[unit]; 71025927Ssam register char *pData1; 71125694Ssam register short i; 71225927Ssam struct acedevice *addr; 71324007Ssam 71425927Ssam bzero(is->is_dpm, 16384*2); 71524007Ssam is->is_currnd = 49123; 71625927Ssam addr = (struct acedevice *)aceinfo[unit]->ui_addr; 71724007Ssam is->is_segboundry = (addr->segb >> 11) & 0xf; 71825927Ssam pData1 = is->is_dpm + (is->is_segboundry << 11); 71924007Ssam for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { 72024007Ssam acebakoff(is, (struct tx_segment *)pData1, 15); 72124007Ssam pData1 += sizeof (struct tx_segment); 72224007Ssam } 72324007Ssam is->is_eictr = 0; 72424007Ssam is->is_eoctr = is->is_txnext = is->is_segboundry; 72524007Ssam bzero((char *)&is->is_stats, sizeof (is->is_stats)); 72624007Ssam } 72724007Ssam #endif 728