Home | History | Annotate | Line # | Download | only in ic
smc90cx6.c revision 1.1
      1 /*
      2  * Copyright (c) 1994, 1995 Ignatios Souvatzis
      3  * Copyright (c) 1994 Timo Rossi
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *      This product includes software developed by  Timo Rossi
     17  *      This product includes software developed by  Ignatios Souvatzis
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  *
     32  *	$Id: smc90cx6.c,v 1.1 1995/02/28 22:03:59 chopps Exp $
     33  */
     34 
     35 /*
     36  * Driver for the Commodore Busines Machines arcnet card
     37  * written by Ignatios Souvatzis <is (at) beverly.rhein.de>,
     38  * somewhat based on Amiga if_ed.c
     39  */
     40 
     41 #define BAHASMCOPY /**/
     42 #define BAHSOFTCOPY /**/
     43 /* #define BAHTIMINGS /**/
     44 /* #define BAH_DEBUG 3 /**/
     45 
     46 #include "bpfilter.h"
     47 
     48 #include <sys/param.h>
     49 #include <sys/systm.h>
     50 #include <sys/mbuf.h>
     51 #include <sys/buf.h>
     52 #include <sys/device.h>
     53 #include <sys/protosw.h>
     54 #include <sys/socket.h>
     55 #include <sys/syslog.h>
     56 #include <sys/ioctl.h>
     57 #include <sys/errno.h>
     58 
     59 #include <net/if.h>
     60 #include <net/if_dl.h>
     61 #include <net/if_types.h>
     62 #include <net/netisr.h>
     63 
     64 #ifdef INET
     65 #include <netinet/in.h>
     66 #include <netinet/in_systm.h>
     67 #include <netinet/in_var.h>
     68 #include <netinet/ip.h>
     69 #include <netinet/if_ether.h>
     70 #include <netinet/if_arc.h>
     71 #endif
     72 
     73 #if NBPFILTER > 0
     74 #include <net/bpf.h>
     75 #include <net/bpfdesc.h>
     76 #endif
     77 
     78 #include <sys/kernel.h>
     79 #include <machine/cpu.h>
     80 #include <machine/mtpr.h>
     81 
     82 #include <amiga/amiga/device.h>
     83 #include <amiga/amiga/isr.h>
     84 #include <amiga/dev/zbusvar.h>
     85 #include <amiga/dev/if_bahreg.h>
     86 
     87 /* these should be elsewhere */
     88 
     89 #define ARC_MIN_LEN 1
     90 #define ARC_MIN_FORBID_LEN 254
     91 #define ARC_MAX_FORBID_LEN 256
     92 #define ARC_MAX_LEN 508
     93 #define ARC_ADDR_LEN 1
     94 
     95 #define MIN(a,b) ((b)<0?(a):min((a),(b)))
     96 
     97 /*
     98  * This currently uses 2 bufs for tx, 2 for rx
     99  *
    100  * New rx protocol:
    101  *
    102  * rx has a fillcount variable. If fillcount > (NRXBUF-1),
    103  * rx can be switched off from rx hard int.
    104  * Else rx is restarted on the other receiver.
    105  * rx soft int counts down. if it is == (NRXBUF-1), it restarts
    106  * the receiver.
    107  * To ensure packet ordering (we need that for 1201 later), we have a counter
    108  * which is incremented modulo 256 on each receive and a per buffer
    109  * variable, which is set to the counter on filling. The soft int can
    110  * compare both values to determine the older packet.
    111  *
    112  * Transmit direction:
    113  *
    114  * bah_start checks tx_fillcount
    115  * case 2: return
    116  *
    117  * else fill tx_act ^ 1 && inc tx_fillcount
    118  *
    119  * check tx_fillcount again.
    120  * case 2: set IFF_OACTIVE to stop arc_output from filling us.
    121  * case 1: start tx
    122  *
    123  * tint clears IFF_OCATIVE, decrements and checks tx_fillcount
    124  * case 1: start tx on tx_act ^ 1, softcall bah_start
    125  * case 0: softcall bah_start
    126  *
    127  * #define fill(i) get mbuf && copy mbuf to chip(i)
    128  */
    129 
    130 /*
    131  * Arcnet software status per interface
    132  *
    133  */
    134 struct bah_softc {
    135 	struct	device sc_dev;
    136 	struct	arccom sc_arccom;	/* Common arcnet structures */
    137 	struct isr sc_isr;
    138 
    139 	A2060 *sc_base;
    140 
    141 	u_long	sc_recontime;		/* seconds only, I'm lazy */
    142 	u_long	sc_reconcount;		/* for the above */
    143 	u_long	sc_reconcount_excessive; /* for the above */
    144 
    145 #define ARC_EXCESSIVE_RECONS 20
    146 #define ARC_EXCESSIVE_RECONS_REWARN 400
    147 
    148 
    149 	u_char sc_bufstat[4];		/* use for packet no for rx */
    150 
    151 	u_char	sc_intmask;
    152 	u_char	sc_rx_packetno;
    153 
    154 	u_char	sc_rx_act,		/* 2..3 */
    155 		sc_tx_act;		/* 0..1 */
    156 
    157 	u_char	sc_rx_fillcount,
    158 		sc_tx_fillcount;
    159 
    160 	u_char	sc_broadcast[2];	/* is it a broadcast packet? */
    161 	u_char	sc_retransmits[2];	/* unused at the moment */
    162 
    163 
    164 #ifdef BAHTIMINGS
    165 	struct	{
    166 		int mincopyin, maxcopyin;	/* divided by byte count */
    167 		int mincopyout, maxcopyout;
    168 
    169 		int minsend, maxsend;
    170 
    171 		int lasttxstart_mics;
    172 		struct timeval lasttxstart_tv;
    173 
    174 	} sc_stats;
    175 #endif
    176 
    177 #if NBPFILTER > 0
    178 	caddr_t sc_bpf;
    179 #endif
    180 /* Add other fields as needed... -- IS */
    181 };
    182 
    183 /* prototypes */
    184 
    185 int bahmatch	__P((struct device *, struct cfdata *, void *));
    186 void bahattach	__P((struct device *, struct device *, void *));
    187 void bah_ini	__P((struct bah_softc *));
    188 void bah_reset	__P((struct bah_softc *));
    189 void bah_stop	__P((struct bah_softc *));
    190 int bah_start	__P((struct ifnet *));
    191 int bahintr	__P((struct bah_softc *sc));
    192 int bah_ioctl	__P((struct ifnet *, unsigned long, caddr_t));
    193 
    194 void movepout	__P((u_char *from, u_char volatile *to, int len));
    195 void movepin	__P((u_char volatile *from, u_char *to, int len));
    196 
    197 void bah_srint	__P((struct bah_softc *sc, void *dummy));
    198 
    199 void callstart	__P((struct bah_softc *sc, void *dummy));
    200 
    201 int arc_output();
    202 int arc_input	__P((struct ifnet *, struct arc_header *, struct mbuf *));
    203 
    204 #ifdef BAHTIMINGS
    205 int clkread();
    206 #endif
    207 
    208 struct cfdriver bahcd = {
    209 	NULL, "bah", (cfmatch_t)bahmatch, bahattach, DV_IFNET,
    210 	    sizeof(struct bah_softc),
    211 };
    212 
    213 
    214 int
    215 bahmatch(pdp, cfp, auxp)
    216 	struct device *pdp;
    217 	struct cfdata *cfp;
    218 	void *auxp;
    219 {
    220 	struct zbus_args *zap;
    221 
    222 	zap = auxp;
    223 
    224 	if ((zap->manid == 514 || zap->manid == 1053) && zap->prodid == 9)
    225 		return (1);
    226 	return (0);
    227 }
    228 
    229 void
    230 bahattach(pdp, dp, auxp)
    231 	struct device *pdp, *dp;
    232 	void *auxp;
    233 {
    234 
    235 	struct zbus_args *zap;
    236 	struct bah_softc *sc;
    237 	struct ifnet *ifp;
    238 	int i, s, linkaddress;
    239 
    240 	zap = auxp;
    241 	sc = (struct bah_softc *)dp;
    242 	ifp = &sc->sc_arccom.ac_if;
    243 
    244 #if (defined(BAH_DEBUG) && (BAH_DEBUG > 2))
    245 	printf("\nbah%ld: attach(0x%x, 0x%x, 0x%x)\n",
    246 	    sc->sc_dev.dv_unit, pdp, dp, auxp);
    247 #endif
    248 	s = splhigh();
    249 	sc->sc_base = zap->va;
    250 
    251 	/*
    252 	 * read the arcnet address from the board
    253 	 */
    254 
    255 	sc->sc_base->kick1 = 0x0;
    256 	sc->sc_base->kick2 = 0x0;
    257 	DELAY(120);
    258 
    259 	sc->sc_base->kick1 = 0xFF;
    260 	sc->sc_base->kick2 = 0xFF;
    261 	do {
    262 		DELAY(120);
    263 	} while (!(sc->sc_base->status & ARC_POR));
    264 
    265 	linkaddress = sc->sc_base->dipswitches;
    266 
    267 #ifdef BAHTIMINGS
    268 	printf(": link addr 0x%02x(%ld), with timer\n",
    269 	    linkaddress, linkaddress);
    270 #else
    271 	printf(": link addr 0x%02x(%ld)\n", linkaddress, linkaddress);
    272 #endif
    273 
    274 	sc->sc_arccom.ac_anaddr = sc->sc_base->dipswitches;
    275 
    276 	/* clear the int mask... */
    277 
    278 	sc->sc_base->status =
    279 	    sc->sc_intmask = 0;
    280 
    281 	sc->sc_base->command = ARC_CONF(CONF_LONG);
    282 	sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG);
    283 	sc->sc_recontime =
    284 	    sc->sc_reconcount = 0;
    285 
    286 	/* and reenable kernel int level */
    287 	splx(s);
    288 
    289 	/*
    290 	 * set interface to stopped condition (reset)
    291 	 *
    292 	 */
    293 	bah_stop(sc);
    294 
    295 	ifp->if_unit = sc->sc_dev.dv_unit;
    296 	ifp->if_name = bahcd.cd_name;
    297 	ifp->if_output = arc_output;
    298 	ifp->if_start = bah_start;
    299 	ifp->if_ioctl = bah_ioctl;
    300 	/* might need later: ifp->if_watchdog  = bah_watchdog */
    301 
    302 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX |
    303 	    IFF_NOTRAILERS | IFF_NOARP;
    304 
    305 	ifp->if_mtu = ARCMTU;
    306 
    307 #if NBPFILTER > 0
    308 	bpfattach(&sc->sc_bpf, ifp, DLT_ARCNET, ARC_HDRLEN);
    309 #endif
    310 
    311 	if_attach(ifp);
    312 	arc_ifattach(ifp);
    313 
    314 	sc->sc_isr.isr_intr = bahintr;
    315 	sc->sc_isr.isr_arg = sc;
    316 	sc->sc_isr.isr_ipl = 2;
    317 	add_isr(&sc->sc_isr);
    318 }
    319 
    320 /*
    321  * Initialize device
    322  *
    323  */
    324 void
    325 bah_init(sc)
    326 	struct bah_softc *sc;
    327 {
    328 	int s;
    329 	struct ifnet *ifp = &sc->sc_arccom.ac_if;
    330 
    331 	/* Address not known. */
    332 	if (ifp->if_addrlist == 0)
    333 		return;
    334 
    335 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
    336 		s = splimp();
    337 		ifp->if_flags |= IFF_RUNNING;
    338 		bah_reset(sc);
    339 		(void)bah_start(ifp);
    340 		splx(s);
    341 	}
    342 }
    343 
    344 /*
    345  * Reset the interface...
    346  *
    347  * this assumes that it is called inside a critical section...
    348  *
    349  */
    350 void
    351 bah_reset(sc)
    352 	struct bah_softc *sc;
    353 {
    354 	int i, s;
    355 	struct ifnet *ifp;
    356 
    357 	ifp = &sc->sc_arccom.ac_if;
    358 
    359 #ifdef BAH_DEBUG
    360 	printf("bah%ld: reset\n", ifp->if_unit);
    361 #endif
    362 	/* stop hardware in case it still runs */
    363 
    364 	sc->sc_base->kick1 = 0;
    365 	sc->sc_base->kick2 = 0;
    366 	DELAY(120);
    367 
    368 	/* and restart it */
    369 	sc->sc_base->kick1 = 0xFF;
    370 	sc->sc_base->kick2 = 0xFF;
    371 
    372 	do {
    373 		DELAY(120);
    374 	} while (!(sc->sc_base->status & ARC_POR));
    375 
    376 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
    377 	printf("bah%ld: reset: card reset, status=0x%02x\n",
    378 	    ifp->if_unit,
    379 	    sc->sc_base->status);
    380 #endif
    381 	/* POR is NMI, but we need it below: */
    382 	sc->sc_intmask = ARC_RECON|ARC_POR;
    383 	sc->sc_base->status	= sc->sc_intmask;
    384 	sc->sc_base->command = ARC_CONF(CONF_LONG);
    385 
    386 #ifdef BAH_DEBUG
    387 	printf("bah%ld: reset: chip configured, status=0x%02x\n",
    388 	    ifp->if_unit,
    389 	    sc->sc_base->status);
    390 #endif
    391 
    392 	sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG);
    393 
    394 #ifdef BAH_DEBUG
    395 	printf("bah%ld: reset: bits cleared, status=0x%02x\n",
    396 	    ifp->if_unit,
    397 	    sc->sc_base->status);
    398 #endif
    399 
    400 	sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
    401 
    402 	/* start receiver */
    403 
    404 	sc->sc_intmask  |= ARC_RI;
    405 
    406 	sc->sc_bufstat[2] =
    407 	    sc->sc_bufstat[3] =
    408 	    sc->sc_rx_packetno =
    409 	    sc->sc_rx_fillcount = 0;
    410 
    411 	sc->sc_rx_act = 2;
    412 
    413 	sc->sc_base->command = ARC_RXBC(2);
    414 	sc->sc_base->status	= sc->sc_intmask;
    415 
    416 #ifdef BAH_DEBUG
    417 	printf("bah%ld: reset: started receiver, status=0x%02x\n",
    418 	    ifp->if_unit,
    419 	    sc->sc_base->status);
    420 #endif
    421 
    422 	/* and init transmitter status */
    423 	sc->sc_tx_act = 0;
    424 	sc->sc_tx_fillcount = 0;
    425 
    426 	ifp->if_flags |= IFF_RUNNING;
    427 	ifp->if_flags &= ~IFF_OACTIVE;
    428 
    429 #ifdef BAHTIMINGS
    430 	bzero((caddr_t)&(sc->sc_stats),sizeof(sc->sc_stats));
    431 	sc->sc_stats.mincopyin =
    432 	    sc->sc_stats.mincopyout =
    433 	    sc->sc_stats.minsend = 999999L;
    434 
    435 #endif
    436 
    437 	bah_start(ifp);
    438 }
    439 
    440 /*
    441  * Take interface offline
    442  */
    443 void
    444 bah_stop(sc)
    445 	struct bah_softc *sc;
    446 {
    447 	int s;
    448 
    449 	/* Stop the interrupts */
    450 	sc->sc_base->status = 0;
    451 
    452 	/* Stop the interface */
    453 	sc->sc_base->kick1 = 0;
    454 	sc->sc_base->kick2 = 0;
    455 
    456 #ifdef BAHTIMINGS
    457 	log(LOG_DEBUG,"%s%ld\
    458   To board: %6ld .. %6ld ns/byte\nFrom board: %6ld .. %6ld ns/byte\n\
    459 Send time:  %6ld .. %6ld mics\n",
    460 	    sc->sc_arccom.ac_if.if_name,
    461 	    sc->sc_arccom.ac_if.if_unit,
    462 	    sc->sc_stats.mincopyout,sc->sc_stats.maxcopyout,
    463 	    sc->sc_stats.mincopyin, sc->sc_stats.maxcopyin,
    464 	    sc->sc_stats.minsend,   sc->sc_stats.maxsend);
    465 
    466 	sc->sc_stats.minsend =
    467 	    sc->sc_stats.mincopyout =
    468 	    sc->sc_stats.mincopyin = 999999L;
    469 	sc->sc_stats.maxsend =
    470 	    sc->sc_stats.maxcopyout =
    471 	    sc->sc_stats.maxcopyin = 0L;
    472 #endif
    473 
    474 }
    475 
    476 inline void
    477 movepout(from,to,len)
    478 	u_char *from;
    479 	volatile u_char *to;
    480 	int len;
    481 {
    482 #ifdef BAHASMCOPY
    483 	u_short shortd;
    484 	u_long longd,longd1,longd2,longd3,longd4;
    485 
    486 	if ((len>3) && ((int)from)&3) {
    487 		switch (((int)from) & 3) {
    488 		case 3:
    489 			*to = *from++;
    490 			to+=2;--len;
    491 			break;
    492 		case 1:
    493 			*to = *from++;
    494 			to += 2; --len;
    495 		case 2:
    496 			shortd = *((u_short *)from)++;
    497 			asm("movepw %0,%1@(0)" : : "d"(shortd), "a"(to));
    498 			to += 4; len -= 2;
    499 			break;
    500 		default:
    501 		}
    502 
    503 		while (len>=32) {
    504 			longd1 = *((u_long *)from)++;
    505 			longd2 = *((u_long *)from)++;
    506 			longd3 = *((u_long *)from)++;
    507 			longd4 = *((u_long *)from)++;
    508 			asm("movepl %0,%1@(0)"  : : "d"(longd1), "a"(to));
    509 			asm("movepl %0,%1@(8)"  : : "d"(longd2), "a"(to));
    510 			asm("movepl %0,%1@(16)" : : "d"(longd3), "a"(to));
    511 			asm("movepl %0,%1@(24)" : : "d"(longd4), "a"(to));
    512 
    513 			longd1 = *((u_long *)from)++;
    514 			longd2 = *((u_long *)from)++;
    515 			longd3 = *((u_long *)from)++;
    516 			longd4 = *((u_long *)from)++;
    517 			asm("movepl %0,%1@(32)" : : "d"(longd1), "a"(to));
    518 			asm("movepl %0,%1@(40)" : : "d"(longd2), "a"(to));
    519 			asm("movepl %0,%1@(48)" : : "d"(longd3), "a"(to));
    520 			asm("movepl %0,%1@(56)" : : "d"(longd4), "a"(to));
    521 
    522 			to += 64; len -= 32;
    523 		}
    524 		while (len>0) {
    525 			longd = *((u_long *)from)++;
    526 			asm("movepl %0,%1@(0)" : : "d"(longd), "a"(to));
    527 			to += 8; len -= 4;
    528 		}
    529 	}
    530 #endif
    531 	while (len>0) {
    532 		*to = *from++;
    533 		to+=2;
    534 		--len;
    535 	}
    536 }
    537 
    538 /*
    539  * Start output on interface. Get another datagram to send
    540  * off the interface queue, and copy it to the
    541  * interface becore starting the output
    542  *
    543  * this assumes that it is called inside a critical section...
    544  * XXX hm... does it still?
    545  *
    546  */
    547 int
    548 bah_start(ifp)
    549 	struct ifnet *ifp;
    550 {
    551 	struct bah_softc *sc;
    552 	struct mbuf *m,*mp;
    553 	volatile u_char *bah_ram_ptr;
    554 	int i,len,tlen, offset, s, buffer;
    555 
    556 #ifdef BAHTIMINGS
    557 	int copystart,lencopy,perbyte;
    558 #endif
    559 
    560 
    561 	sc = bahcd.cd_devs[ifp->if_unit];
    562 
    563 #if defined(BAH_DEBUG) && (BAH_DEBUG > 3)
    564 	printf("bah%ld: start(0x%x)\n",
    565 	    ifp->if_unit, ifp);
    566 #endif
    567 
    568 	if((ifp->if_flags & IFF_RUNNING) == 0)
    569 		return 0;
    570 
    571 	s = splimp();
    572 
    573 	if (sc->sc_tx_fillcount >= 2) {
    574 		splx(s);
    575 		return 0;
    576 	}
    577 
    578 	IF_DEQUEUE(&ifp->if_snd, m);
    579 	buffer = sc->sc_tx_act ^ 1;
    580 
    581 	splx(s);
    582 
    583 	if (m == 0)
    584 		return 0;
    585 
    586 #if NBPFILTER > 0
    587 	/*
    588 	 * If bpf is listening on this interface, let it
    589 	 * see the packet before we commit it to the wire
    590 	 *
    591 	 * (can't give the copy in A2060 card RAM to bpf, because
    592 	 * that RAM is just accessed as on every other byte)
    593 	 */
    594 
    595 	if (sc->sc_bpf)
    596 		bpf_mtap(sc->sc_bpf, m);
    597 #endif
    598 	/* we need the data length beforehand */
    599 
    600 	for (mp = m,tlen=0;mp;mp=mp->m_next) {
    601 		tlen += mp->m_len;
    602 	}
    603 
    604 #ifdef BAH_DEBUG
    605 	m = m_pullup(m,3);	/* gcc does structure padding */
    606 	printf("bah%ld: start: filling %ld from %ld to %ld type %ld\n",
    607 	    ifp->if_unit,
    608 	    buffer,
    609 	    mtod(m, u_char *)[0],
    610 	    mtod(m, u_char *)[1],
    611 	    mtod(m, u_char *)[2]);
    612 #else
    613 	m = m_pullup(m,2);
    614 #endif
    615 	bah_ram_ptr = sc->sc_base->buffers + buffer*512*2;
    616 
    617 	/* write the addresses to RAM and throw them away */
    618 
    619 	/*
    620 	 * Hardware does this: Yet Another Microsecond Saved.
    621 	 * (btw, timing code says usually 2 microseconds)
    622 	 * bah_ram_ptr[0*2] = mtod(m, u_char *)[0];
    623 	 */
    624 
    625 	bah_ram_ptr[1*2] = mtod(m, u_char *)[1];
    626 	m_adj(m,2);
    627 
    628 	/* correct total length for that */
    629 	tlen -= 2;
    630 	if (tlen >= ARC_MIN_FORBID_LEN)
    631 	{
    632 		if (tlen <= ARC_MAX_FORBID_LEN)
    633 			offset = 512-3-tlen;
    634 		else {
    635 			if (tlen > ARC_MAX_LEN)
    636 				tlen = ARC_MAX_LEN;
    637 			offset = 512-tlen;
    638 		}
    639 
    640 		bah_ram_ptr[2*2] = 0;
    641 		bah_ram_ptr[3*2] = offset;
    642 	} else {
    643 		offset = 256-tlen;
    644 		bah_ram_ptr[2*2] = offset;
    645 	}
    646 	bah_ram_ptr += offset*2;
    647 
    648 	/* lets loop again through the mbuf chain */
    649 
    650 	for (mp=m;mp;mp=mp->m_next) {
    651 		if (len = mp->m_len) {		/* YAMS */
    652 #ifdef BAHTIMINGS
    653 			lencopy = len;
    654 			copystart = clkread();
    655 #endif
    656 			movepout(mtod(mp, caddr_t),bah_ram_ptr,len);
    657 
    658 #ifdef BAHTIMINGS
    659 			perbyte = 1000*(clkread() - copystart) / lencopy;
    660 			sc->sc_stats.mincopyout =
    661 			    MIN(sc->sc_stats.mincopyout,perbyte);
    662 			sc->sc_stats.maxcopyout =
    663 			    max(sc->sc_stats.maxcopyout,perbyte);
    664 #endif
    665 			bah_ram_ptr += len*2;
    666 		}
    667 	}
    668 
    669 	sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
    670 	sc->sc_retransmits[buffer] =
    671 		m->m_flags & M_BCAST ? 1 : 5;
    672 
    673 	/* actually transmit the packet */
    674 	s = splimp();
    675 
    676 	if (++sc->sc_tx_fillcount <= 1) {
    677 #ifdef BAH_DEBUG
    678 		printf("bah%ld: start: starting transmitter on buffer %d\n",
    679 		    ifp->if_unit, buffer);
    680 #endif
    681 		/* Transmitter was off, start it */
    682 		sc->sc_tx_act = buffer;
    683 
    684 		/*
    685 		 * We still can accept another buf, so don't:
    686 		 * ifp->if_flags |= IFF_OACTIVE;
    687 		 *
    688 		 */
    689 
    690 		sc->sc_intmask |= ARC_TA;
    691 		sc->sc_base->command = ARC_TX(buffer);
    692 		sc->sc_base->status  = sc->sc_intmask;
    693 
    694 #ifdef BAHTIMINGS
    695 		bcopy((caddr_t)&time,
    696 		    (caddr_t)&(sc->sc_stats.lasttxstart_tv),
    697 		    sizeof(struct timeval));
    698 
    699 		sc->sc_stats.lasttxstart_mics = clkread();
    700 #endif
    701 	} else {
    702 		/*
    703 		 * We are filled up to the rim. No more bufs for the moment,
    704 		 * please.
    705 		 */
    706 		ifp->if_flags |= IFF_OACTIVE;
    707 	}
    708 	splx(s);
    709 	m_freem(m);
    710 
    711 	/*
    712 	 * We dont really need a transmit timeout timer, do we?
    713 	 * XXX (sighing deeply) yes, after 10 times reading the docs,
    714 	 * I realized that in the case the receiver NAKs the buffer request,
    715 	 * the hardware retries till shutdown.
    716 	 * TODO: Insert some reasonable transmit timeout timer.
    717 	 */
    718 
    719 	return 1;
    720 }
    721 
    722 void
    723 callstart(sc, dummy)
    724 	struct bah_softc *sc;
    725 	void *dummy;
    726 {
    727 	(void) bah_start(&sc->sc_arccom.ac_if);
    728 }
    729 
    730 inline void
    731 movepin(from,to,len)
    732 	volatile u_char *from;
    733 	u_char *to;
    734 	int len;
    735 {
    736 #ifdef BAHASMCOPY
    737 	unsigned long	longd, longd1, longd2, longd3, longd4;
    738 	ushort		shortd;
    739 
    740 	if ((len>3) && (((int)to) & 3)) {
    741 		switch(((int)to) & 3) {
    742 		case 3: *to++ = *from;
    743 			from+=2; --len;
    744 			break;
    745 		case 1: *to++ = *from;
    746 			from+=2; --len;
    747 		case 2:	asm ("movepw %1@(0),%0": "=d" (shortd) : "a" (from));
    748 			*((ushort *)to)++ = shortd;
    749 			from += 4; len -= 2;
    750 			break;
    751 		default:
    752 		}
    753 
    754 		while (len>=32) {
    755 			asm("movepl %1@(0),%0"  : "=d"(longd1) : "a" (from));
    756 			asm("movepl %1@(8),%0"  : "=d"(longd2) : "a" (from));
    757 			asm("movepl %1@(16),%0" : "=d"(longd3) : "a" (from));
    758 			asm("movepl %1@(24),%0" : "=d"(longd4) : "a" (from));
    759 			*((unsigned long *)to)++ = longd1;
    760 			*((unsigned long *)to)++ = longd2;
    761 			*((unsigned long *)to)++ = longd3;
    762 			*((unsigned long *)to)++ = longd4;
    763 
    764 			asm("movepl %1@(32),%0" : "=d"(longd1) : "a" (from));
    765 			asm("movepl %1@(40),%0" : "=d"(longd2) : "a" (from));
    766 			asm("movepl %1@(48),%0" : "=d"(longd3) : "a" (from));
    767 			asm("movepl %1@(56),%0" : "=d"(longd4) : "a" (from));
    768 			*((unsigned long *)to)++ = longd1;
    769 			*((unsigned long *)to)++ = longd2;
    770 			*((unsigned long *)to)++ = longd3;
    771 			*((unsigned long *)to)++ = longd4;
    772 
    773 			from += 64; len -= 32;
    774 		}
    775 		while (len>0) {
    776 			asm("movepl %1@(0),%0" : "=d"(longd) : "a" (from));
    777 			*((unsigned long *)to)++ = longd;
    778 			from += 8; len -= 4;
    779 		}
    780 
    781 	}
    782 #endif /* BAHASMCOPY */
    783 	while (len>0) {
    784 		*to++ = *from;
    785 		from+=2;
    786 		--len;
    787 	}
    788 
    789 }
    790 
    791 /*
    792  * Arcnet interface receiver soft interrupt:
    793  * get the stuff out of any filled buffer we find.
    794  */
    795 void
    796 bah_srint(sc,dummy)
    797 	struct bah_softc *sc;
    798 	void *dummy;
    799 {
    800 	u_char volatile *bah_ram_ptr;
    801 	int len, len1, amount, offset, s;
    802 	int buffer, buffer1, i;
    803 
    804 	struct mbuf *m,*dst,*head = 0;
    805 	struct arc_header *ah;
    806 
    807 #ifdef BAHTIMINGS
    808 	int copystart,lencopy,perbyte;
    809 #endif
    810 
    811 	s = splimp();
    812 
    813 	if (sc->sc_rx_fillcount > 1) {
    814 
    815 		i = ((unsigned)(sc->sc_bufstat[2] - sc->sc_bufstat[3])) % 256;
    816 		if (i < 64)
    817 			buffer = 3;
    818 		else if (i > 192)
    819 			buffer = 2;
    820 		else {
    821 			log(LOG_WARNING,
    822 			    "bah%ld: rx srint: which is older, %ld or %ld?\
    823 (filled %ld)\n",
    824 			    sc->sc_bufstat[2],sc->sc_bufstat[3],
    825 			    sc->sc_rx_fillcount);
    826 			splx(s);
    827 			return;
    828 		}
    829 	} else
    830 		buffer = sc->sc_rx_act ^ 1;
    831 
    832 	splx(s);
    833 
    834 	/* Allocate header mbuf */
    835 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    836 
    837 	if (m == 0) {
    838 		/*
    839 	 	 * in case s.th. goes wrong with mem, drop it
    840 	 	 * to make sure the receiver can be started again
    841 		 * count it as input error (we dont have any other
    842 		 * detectable)
    843 	 	 */
    844 		sc->sc_arccom.ac_if.if_ierrors++;
    845 		goto cleanup;
    846 	}
    847 
    848 	m->m_pkthdr.rcvif = &sc->sc_arccom.ac_if;
    849 	m->m_len = 0;
    850 
    851 	/*
    852 	 * Align so that IP packet will be longword aligned. Here we
    853 	 * assume that m_data of new packet is longword aligned.
    854 	 * When implementing RFC1201, we might have to change it to 2,
    855 	 * (2*sizeof(ulong) - ARC_HDRLEN - sizeof(splitflag) - sizeof(pckid))
    856 	 * possibly packet type dependent.
    857 	 */
    858 
    859 	m->m_data += 1;		/* sizeof(ulong) - ARC_HDRLEN */
    860 
    861 	head = m;
    862 
    863 	ah = mtod(head, struct arc_header *);
    864 	bah_ram_ptr = sc->sc_base->buffers + buffer*512*2;
    865 
    866 	ah->arc_shost = bah_ram_ptr[0*2];
    867 	ah->arc_dhost = bah_ram_ptr[1*2];
    868 	offset = bah_ram_ptr[2*2];
    869 	if (offset) {
    870 		len = 256 - offset;
    871 	} else {
    872 		offset = bah_ram_ptr[3*2];
    873 		len = 512 - offset;
    874 	}
    875 	m->m_pkthdr.len = len+2;        /* whole packet length */
    876 	m->m_len += 2; 		    	/* mbuf filled with ARCnet addresses */
    877 	bah_ram_ptr += offset*2;	/* ram buffer continues there */
    878 
    879 	while (len > 0) {
    880 
    881 		len1 = len;
    882 		amount = M_TRAILINGSPACE(m);
    883 
    884 		if (amount == 0) {
    885 			dst = m;
    886 			MGET(m, M_DONTWAIT, MT_DATA);
    887 
    888 			if (m == 0) {
    889 				sc->sc_arccom.ac_if.if_ierrors++;
    890 				goto cleanup;
    891 			}
    892 
    893 			if (len1 >= MINCLSIZE)
    894 				MCLGET(m, M_DONTWAIT);
    895 
    896 			m->m_len = 0;
    897 			dst->m_next = m;
    898 			amount = M_TRAILINGSPACE(m);
    899 		}
    900 
    901 		if (amount < len1)
    902 			len1 = amount;
    903 
    904 #ifdef BAHTIMINGS
    905 		lencopy = len;
    906 		copystart = clkread();
    907 #endif
    908 
    909 		movepin(bah_ram_ptr,mtod(m, u_char *) + m->m_len, len1);
    910 
    911 #ifdef BAHTIMINGS
    912 		perbyte = 1000*(clkread() - copystart) / lencopy;
    913 		sc->sc_stats.mincopyin = MIN(sc->sc_stats.mincopyin,perbyte);
    914 		sc->sc_stats.maxcopyin = max(sc->sc_stats.maxcopyin,perbyte);
    915 #endif
    916 
    917 		m->m_len += len1;
    918 		bah_ram_ptr += len1*2;
    919 		len -= len1;
    920 	}
    921 
    922 #if NBPFILTER > 0
    923 	if (sc->sc_bpf) {
    924 		bpf_mtap(sc->sc_bpf, head);
    925 	}
    926 #endif
    927 
    928 	m_adj(head, 3); /* gcc does structure padding */
    929 	arc_input(&sc->sc_arccom.ac_if, ah, head);
    930 
    931 	/* arc_input has freed it, we dont need to... */
    932 
    933 	head = NULL;
    934 	sc->sc_arccom.ac_if.if_ipackets++;
    935 
    936 cleanup:
    937 
    938 	if(head == NULL)
    939 		m_freem(head);
    940 
    941 	s = splimp();
    942 
    943 	if (--sc->sc_rx_fillcount == 1) {
    944 
    945 		/* was off, restart it on buffer just emptied */
    946 		sc->sc_rx_act = buffer;
    947 		sc->sc_intmask |= ARC_RI;
    948 
    949 		/* this also clears the RI flag interupt: */
    950 		sc->sc_base->command = ARC_RXBC(buffer);
    951 		sc->sc_base->status = sc->sc_intmask;
    952 
    953 #ifdef BAH_DEBUG
    954 		printf("bah%ld: srint: restarted rx on buf %ld\n",
    955 		    sc->sc_arccom.ac_if.if_unit, buffer);
    956 #endif
    957 	}
    958 	splx(s);
    959 	return;
    960 }
    961 
    962 inline static void
    963 bah_tint(sc)
    964 	struct bah_softc *sc;
    965 {
    966 	int buffer;
    967 	u_char volatile *bah_ram_ptr;
    968 	int isr;
    969 	int clknow;
    970 
    971 	buffer = sc->sc_tx_act;
    972 	isr = sc->sc_base->status;
    973 
    974 	/* XXX insert retransmit code etc. here. For now just: */
    975 
    976 	if (!(isr & ARC_TMA) && !(sc->sc_broadcast[buffer])) {
    977 		sc->sc_arccom.ac_if.if_oerrors++;
    978 	} else {
    979 		sc->sc_arccom.ac_if.if_opackets++;
    980 	}
    981 
    982 #ifdef BAHTIMINGS
    983 	clknow = clkread();
    984 
    985 	sc->sc_stats.minsend = MIN(sc->sc_stats.minsend,
    986 	    clknow - sc->sc_stats.lasttxstart_mics);
    987 
    988 	sc->sc_stats.maxsend = max(sc->sc_stats.maxsend,
    989 	    clknow - sc->sc_stats.lasttxstart_mics);
    990 #endif
    991 
    992 	/* We know we can accept another buffer at this point. */
    993 	sc->sc_arccom.ac_if.if_flags &= ~IFF_OACTIVE;
    994 
    995 	if (--sc->sc_tx_fillcount > 0) {
    996 
    997 		/*
    998 		 * start tx on other buffer.
    999 		 * This also clears the int flag
   1000 		 */
   1001 
   1002 		buffer ^= 1;
   1003 		sc->sc_tx_act = buffer;
   1004 
   1005 		/*
   1006 		 * already given:
   1007 		 * sc->sc_intmask |= ARC_TA;
   1008 		 * sc->sc_base->status = sc->sc_intmask;
   1009 		 */
   1010 
   1011 		sc->sc_base->command = ARC_TX(buffer);
   1012 
   1013 #ifdef BAHTIMINGS
   1014 		bcopy((caddr_t)&time,
   1015 		    (caddr_t)&(sc->sc_stats.lasttxstart_tv),
   1016 		    sizeof(struct timeval));
   1017 
   1018 		sc->sc_stats.lasttxstart_mics = clkread();
   1019 #endif
   1020 
   1021 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
   1022 		printf("bah%ld: tint: starting tx on buffer %d,\
   1023 status 0x%02x\n",
   1024 		    sc->sc_arccom.ac_if.if_unit,
   1025 		    buffer,sc->sc_base->status);
   1026 #endif
   1027 	} else {
   1028 		/* have to disable TX interrupt */
   1029 		sc->sc_intmask &= ~ARC_TA;
   1030 		sc->sc_base->status = sc->sc_intmask;
   1031 
   1032 #ifdef BAH_DEBUG
   1033 		printf("bah%ld: tint: no more buffers to send,\
   1034 status 0x%02x\n",
   1035 		    sc->sc_arccom.ac_if.if_unit,
   1036 		    sc->sc_base->status);
   1037 #endif
   1038 	}
   1039 
   1040 #ifdef BAHSOFTCOPY
   1041 	/* schedule soft int to fill a new buffer for us */
   1042 	add_sicallback(callstart, sc, NULL);
   1043 #else
   1044 	/* call it directly */
   1045 	callstart(sc, NULL);
   1046 #endif
   1047 }
   1048 
   1049 /*
   1050  * Our interrupt routine
   1051  */
   1052 int
   1053 bahintr(sc)
   1054 	struct bah_softc *sc;
   1055 {
   1056 	u_char isr;
   1057 	int buffer;
   1058 	int unit;
   1059 	u_long newsec;
   1060 
   1061 
   1062 	isr = sc->sc_base->status;
   1063 	if (!(isr & sc->sc_intmask))
   1064 		return 0;
   1065 
   1066 #if defined(BAH_DEBUG) && (BAH_DEBUG>1)
   1067 	printf("bah%ld: intr: status 0x%02x, intmask 0x%02x\n",
   1068 	    sc->sc_arccom.ac_if.if_unit,
   1069 	    isr, sc->sc_intmask);
   1070 #endif
   1071 
   1072 	if (isr & ARC_POR) {
   1073 		sc->sc_arccom.ac_anaddr = sc->sc_base->dipswitches;
   1074 		sc->sc_base->command = ARC_CLR(CLR_POR);
   1075 		log(LOG_WARNING,
   1076 		    "%s%ld: intr: got spurious power on reset int\n",
   1077 		    sc->sc_arccom.ac_if.if_name,
   1078 		    sc->sc_arccom.ac_if.if_unit);
   1079 	}
   1080 
   1081 	if (isr & ARC_RECON) {
   1082 		/*
   1083 		 * we dont need to:
   1084 		 * sc->sc_base->command = ARC_CONF(CONF_LONG);
   1085 		 */
   1086 		sc->sc_base->command = ARC_CLR(CLR_RECONFIG);
   1087 		sc->sc_arccom.ac_if.if_collisions++;
   1088 /*
   1089  * if more than 2 seconds per reconfig, reset time and counter.
   1090  * else
   1091  * if more than ARC_EXCESSIVE_RECONFIGS reconfigs since last burst, complain
   1092  * and set treshold for warnings to ARC_EXCESSIVE_RECONS_REWARN.
   1093  * This allows for, e.g., new stations on the cable, or cable switching as long
   1094  * as it is over after (normally) 16 seconds.
   1095  * XXX Todo: check timeout bits in status word and double time if necessary.
   1096  */
   1097 
   1098 		newsec = time.tv_sec;
   1099 		if (newsec - sc->sc_recontime > 2*sc->sc_reconcount) {
   1100 			sc->sc_recontime = newsec;
   1101 			sc->sc_reconcount = 0;
   1102 			sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
   1103 		} else {
   1104 			if (++sc->sc_reconcount >
   1105 			    sc->sc_reconcount_excessive) {
   1106 				sc->sc_reconcount_excessive =
   1107 				    ARC_EXCESSIVE_RECONS_REWARN;
   1108 				log(LOG_WARNING,
   1109 				    "%s%d: excessive token losses,\
   1110 cable problem?\n",
   1111 				    sc->sc_arccom.ac_if.if_name,
   1112 				    sc->sc_arccom.ac_if.if_unit);
   1113 				    sc->sc_recontime = newsec;
   1114 				    sc->sc_reconcount = 0;
   1115 			}
   1116 		}
   1117 	}
   1118 
   1119 	if (isr & ARC_RI) {
   1120 
   1121 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
   1122 		printf("bah%ld: intr: hard rint, act %ld 2:%ld 3:%ld\n",
   1123 			sc->sc_arccom.ac_if.if_unit,
   1124 			sc->sc_rx_act,sc->sc_bufstat[2],sc->sc_bufstat[3]);
   1125 #endif
   1126 
   1127 		buffer = sc->sc_rx_act;
   1128 		sc->sc_rx_packetno = (sc->sc_rx_packetno+1)%256;
   1129 		sc->sc_bufstat[buffer] = sc->sc_rx_packetno;
   1130 
   1131 		if (++sc->sc_rx_fillcount > 1) {
   1132 
   1133 			sc->sc_intmask &= ~ARC_RI;
   1134 			sc->sc_base->status = sc->sc_intmask;
   1135 
   1136 		} else {
   1137 
   1138 			buffer ^= 1;
   1139 			sc->sc_rx_act = buffer;
   1140 
   1141 			/*
   1142 			 * Start receiver on other receive buffer.
   1143 			 * This also clears the RI interupt flag.
   1144 			 */
   1145 
   1146 			sc->sc_base->command = ARC_RXBC(buffer);
   1147 			/* we are in the RX intr, so mask is ok for RX */
   1148 
   1149 #ifdef BAH_DEBUG
   1150 			printf("bah%ld:  started rx for buffer %ld,\
   1151 status 0x%02x\n",
   1152 			    sc->sc_arccom.ac_if.if_unit,sc->sc_rx_act,
   1153 			    sc->sc_base->status);
   1154 #endif
   1155 		}
   1156 
   1157 #ifdef BAHSOFTCOPY
   1158 		/* this one starts a soft int to copy out of the hw */
   1159 		add_sicallback(bah_srint,sc,NULL);
   1160 #else
   1161 		/* this one does the copy here */
   1162 		bah_srint(sc,NULL);
   1163 #endif
   1164 
   1165 	}
   1166 
   1167 	if (isr & sc->sc_intmask & ARC_TA)
   1168 		bah_tint(sc);
   1169 
   1170 	return 1;
   1171 }
   1172 
   1173 /*
   1174  * Process an ioctl request.
   1175  * This code needs some work - it looks pretty ugly.
   1176  */
   1177 int
   1178 bah_ioctl(ifp, command, data)
   1179 	register struct ifnet *ifp;
   1180 	unsigned long command;
   1181 	caddr_t data;
   1182 {
   1183 	struct bah_softc *sc;
   1184 	register struct ifaddr *ifa;
   1185 	int s, error = 0;
   1186 
   1187 	sc  = bahcd.cd_devs[ifp->if_unit];
   1188 	ifa = (struct ifaddr *)data;
   1189 	s = splimp();
   1190 
   1191 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
   1192 	printf("bah%ld: ioctl() called, cmd = 0x%x\n",
   1193 	    sc->sc_arccom.ac_if.if_unit, command);
   1194 #endif
   1195 
   1196 	switch(command) {
   1197 	case SIOCSIFADDR:
   1198 		ifp->if_flags |= IFF_UP;
   1199 		switch(ifa->ifa_addr->sa_family) {
   1200 
   1201 #ifdef INET
   1202 		case AF_INET:
   1203 			bah_init(sc);	 /* before arpwhohas */
   1204 			((struct arccom *)ifp)->ac_ipaddr =
   1205 			    IA_SIN(ifa)->sin_addr;
   1206 			/* arpwhohas((struct arccom *)ifp,
   1207 			    &IA_SIN(ifa)->sin_addr);*/
   1208 			break;
   1209 #endif
   1210 		default:
   1211 			bah_init(sc);
   1212 			break;
   1213 		}
   1214 
   1215 	case SIOCSIFFLAGS:
   1216 		if ((ifp->if_flags & IFF_UP) == 0 &&
   1217 		    (ifp->if_flags & IFF_RUNNING) != 0) {
   1218 
   1219 			/*
   1220 			 * If interface is marked down and it is running,
   1221 			 * then stop it.
   1222 			 */
   1223 
   1224 			bah_stop(sc);
   1225 			ifp->if_flags &= ~IFF_RUNNING;
   1226 
   1227 		} else if((ifp->if_flags & IFF_UP) != 0 &&
   1228 		    (ifp->if_flags & IFF_RUNNING) == 0) {
   1229 
   1230 			/*
   1231 			 * If interface is marked up and it is stopped, then
   1232 			 * start it.
   1233 			 */
   1234 
   1235 			bah_init(sc);
   1236 		}
   1237 		break;
   1238 
   1239 		/* Multicast not supported */
   1240 	default:
   1241 		error = EINVAL;
   1242 	}
   1243 
   1244 	(void)splx(s);
   1245 	return error;
   1246 }
   1247