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