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 *
844532Sbostic * %sccs.include.redist.c%
934405Skarels *
10*45795Sbostic * @(#)if_ace.c 7.8 (Berkeley) 12/16/90
1134405Skarels */
1224007Ssam
1324007Ssam /*
1424007Ssam * ACC VERSAbus Ethernet controller
1524007Ssam */
1624007Ssam #include "ace.h"
1724007Ssam #if NACE > 0
1824007Ssam
19*45795Sbostic #include "sys/param.h"
20*45795Sbostic #include "sys/systm.h"
21*45795Sbostic #include "sys/malloc.h"
22*45795Sbostic #include "sys/mbuf.h"
23*45795Sbostic #include "sys/buf.h"
24*45795Sbostic #include "sys/protosw.h"
25*45795Sbostic #include "sys/socket.h"
26*45795Sbostic #include "sys/vmmac.h"
27*45795Sbostic #include "sys/ioctl.h"
28*45795Sbostic #include "sys/errno.h"
29*45795Sbostic #include "sys/vmparam.h"
30*45795Sbostic #include "sys/syslog.h"
3124007Ssam
32*45795Sbostic #include "net/if.h"
33*45795Sbostic #include "net/netisr.h"
34*45795Sbostic #include "net/route.h"
3525855Ssam #ifdef INET
36*45795Sbostic #include "netinet/in.h"
37*45795Sbostic #include "netinet/in_systm.h"
38*45795Sbostic #include "netinet/in_var.h"
39*45795Sbostic #include "netinet/ip.h"
40*45795Sbostic #include "netinet/ip_var.h"
41*45795Sbostic #include "netinet/if_ether.h"
4225855Ssam #endif
4325855Ssam #ifdef NS
44*45795Sbostic #include "netns/ns.h"
45*45795Sbostic #include "netns/ns_if.h"
4625855Ssam #endif
4724007Ssam
48*45795Sbostic #include "../include/cpu.h"
49*45795Sbostic #include "../include/pte.h"
5030229Ssam
51*45795Sbostic #include "../include/mtpr.h"
52*45795Sbostic #include "../if/if_acereg.h"
53*45795Sbostic #include "../vba/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
aceprobe(reg,vi)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 */
acereset(unit,vban)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 */
aceinit(unit)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 */
acestart(ifp)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 */
acecint(unit)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 */
acerint(unit)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 */
aceput(txbuf,m)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 *
aceget(rxbuf,totlen,off,ifp)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 */
aceioctl(ifp,cmd,data)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 */
acesetaddr(unit,addr,station)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 */
acesetup(unit)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