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