1/*	$NetBSD: smc90cx6.c,v 1.62 2010/01/19 22:06:25 pooka Exp $ */
2
3/*-
4 * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ignatios Souvatzis.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56
34 * compatibility mode) boards
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: smc90cx6.c,v 1.62 2010/01/19 22:06:25 pooka Exp $");
39
40/* #define BAHSOFTCOPY */
41#define BAHRETRANSMIT /**/
42
43#include "opt_inet.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/mbuf.h>
48#include <sys/buf.h>
49#include <sys/device.h>
50#include <sys/protosw.h>
51#include <sys/socket.h>
52#include <sys/syslog.h>
53#include <sys/ioctl.h>
54#include <sys/errno.h>
55#include <sys/kernel.h>
56#include <sys/intr.h>
57
58#include <net/if.h>
59#include <net/if_dl.h>
60#include <net/if_ether.h>
61#include <net/if_types.h>
62#include <net/if_arc.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_inarp.h>
70#endif
71
72#include <net/bpf.h>
73#include <net/bpfdesc.h>
74
75#include <sys/bus.h>
76#include <sys/cpu.h>
77
78#include <dev/ic/smc90cx6reg.h>
79#include <dev/ic/smc90cx6var.h>
80
81/* these should be elsewhere */
82
83#define ARC_MIN_LEN 1
84#define ARC_MIN_FORBID_LEN 254
85#define ARC_MAX_FORBID_LEN 256
86#define ARC_MAX_LEN 508
87#define ARC_ADDR_LEN 1
88
89/* for watchdog timer. This should be more than enough. */
90#define ARCTIMEOUT (5*IFNET_SLOWHZ)
91
92/*
93 * This currently uses 2 bufs for tx, 2 for rx
94 *
95 * New rx protocol:
96 *
97 * rx has a fillcount variable. If fillcount > (NRXBUF-1),
98 * rx can be switched off from rx hard int.
99 * Else rx is restarted on the other receiver.
100 * rx soft int counts down. if it is == (NRXBUF-1), it restarts
101 * the receiver.
102 * To ensure packet ordering (we need that for 1201 later), we have a counter
103 * which is incremented modulo 256 on each receive and a per buffer
104 * variable, which is set to the counter on filling. The soft int can
105 * compare both values to determine the older packet.
106 *
107 * Transmit direction:
108 *
109 * bah_start checks tx_fillcount
110 * case 2: return
111 *
112 * else fill tx_act ^ 1 && inc tx_fillcount
113 *
114 * check tx_fillcount again.
115 * case 2: set IFF_OACTIVE to stop arc_output from filling us.
116 * case 1: start tx
117 *
118 * tint clears IFF_OCATIVE, decrements and checks tx_fillcount
119 * case 1: start tx on tx_act ^ 1, softcall bah_start
120 * case 0: softcall bah_start
121 *
122 * #define fill(i) get mbuf && copy mbuf to chip(i)
123 */
124
125void	bah_init(struct bah_softc *);
126void	bah_reset(struct bah_softc *);
127void	bah_stop(struct bah_softc *);
128void	bah_start(struct ifnet *);
129int	bahintr(void *);
130int	bah_ioctl(struct ifnet *, unsigned long, void *);
131void	bah_watchdog(struct ifnet *);
132void	bah_srint(void *vsc);
133static	void bah_tint(struct bah_softc *, int);
134void	bah_reconwatch(void *);
135
136/* short notation */
137
138#define GETREG(off)	bus_space_read_1(bst_r, regs, (off))
139#define PUTREG(off, v)	bus_space_write_1(bst_r, regs, (off), (v))
140#define GETMEM(off)	bus_space_read_1(bst_m, mem, (off))
141#define PUTMEM(off, v)	bus_space_write_1(bst_m, mem, (off), (v))
142
143void
144bah_attach_subr(struct bah_softc *sc)
145{
146	struct ifnet *ifp = &sc->sc_arccom.ac_if;
147	int s;
148	u_int8_t linkaddress;
149
150	bus_space_tag_t bst_r = sc->sc_bst_r;
151	bus_space_tag_t bst_m = sc->sc_bst_m;
152	bus_space_handle_t regs = sc->sc_regs;
153	bus_space_handle_t mem = sc->sc_mem;
154
155#if (defined(BAH_DEBUG) && (BAH_DEBUG > 2))
156	printf("\n%s: attach(0x%x, 0x%x, 0x%x)\n",
157	    device_xname(&sc->sc_dev), parent, self, aux);
158#endif
159	s = splhigh();
160
161	/*
162	 * read the arcnet address from the board
163	 */
164
165	(*sc->sc_reset)(sc, 1);
166
167	do {
168		delay(200);
169	} while (!(GETREG(BAHSTAT) & BAH_POR));
170
171	linkaddress = GETMEM(BAHMACOFF);
172
173	printf(": link addr 0x%02x(%d)\n", linkaddress, linkaddress);
174
175	/* clear the int mask... */
176
177	sc->sc_intmask = 0;
178	PUTREG(BAHSTAT, 0);
179
180	PUTREG(BAHCMD, BAH_CONF(CONF_LONG));
181	PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG));
182	sc->sc_recontime = sc->sc_reconcount = 0;
183
184	/* and reenable kernel int level */
185	splx(s);
186
187	/*
188	 * set interface to stopped condition (reset)
189	 */
190	bah_stop(sc);
191
192	strlcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ);
193	ifp->if_softc = sc;
194	ifp->if_start = bah_start;
195	ifp->if_ioctl = bah_ioctl;
196	ifp->if_timer = 0;
197	ifp->if_watchdog  = bah_watchdog;
198	IFQ_SET_READY(&ifp->if_snd);
199
200	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
201
202	ifp->if_mtu = ARCMTU;
203
204	arc_ifattach(ifp, linkaddress);
205
206#ifdef BAHSOFTCOPY
207	sc->sc_rxcookie = softint_establish(SOFTINT_NET, bah_srint, sc);
208	sc->sc_txcookie = softint_establish(SOFTINT_NET,
209		(void (*)(void *))bah_start, ifp);
210#endif
211
212	callout_init(&sc->sc_recon_ch, 0);
213}
214
215/*
216 * Initialize device
217 *
218 */
219void
220bah_init(struct bah_softc *sc)
221{
222	struct ifnet *ifp;
223	int s;
224
225	ifp = &sc->sc_arccom.ac_if;
226
227	if ((ifp->if_flags & IFF_RUNNING) == 0) {
228		s = splnet();
229		ifp->if_flags |= IFF_RUNNING;
230		bah_reset(sc);
231		bah_start(ifp);
232		splx(s);
233	}
234}
235
236/*
237 * Reset the interface...
238 *
239 * this assumes that it is called inside a critical section...
240 *
241 */
242void
243bah_reset(struct bah_softc *sc)
244{
245	struct ifnet *ifp;
246	uint8_t linkaddress;
247
248	bus_space_tag_t bst_r = sc->sc_bst_r;
249        bus_space_tag_t bst_m = sc->sc_bst_m;
250	bus_space_handle_t regs = sc->sc_regs;
251	bus_space_handle_t mem = sc->sc_mem;
252
253	ifp = &sc->sc_arccom.ac_if;
254
255#ifdef BAH_DEBUG
256	printf("%s: reset\n", device_xname(&sc->sc_dev));
257#endif
258	/* stop and restart hardware */
259
260	(*sc->sc_reset)(sc, 1);
261	do {
262		DELAY(200);
263	} while (!(GETREG(BAHSTAT) & BAH_POR));
264
265	linkaddress = GETMEM(BAHMACOFF);
266
267#if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
268	printf("%s: reset: card reset, link addr = 0x%02x (%ld)\n",
269	    device_xname(&sc->sc_dev), linkaddress, linkaddress);
270#endif
271
272	/* tell the routing level about the (possibly changed) link address */
273	if_set_sadl(ifp, &linkaddress, sizeof(linkaddress), false);
274
275	/* POR is NMI, but we need it below: */
276	sc->sc_intmask = BAH_RECON|BAH_POR;
277	PUTREG(BAHSTAT, sc->sc_intmask);
278	PUTREG(BAHCMD, BAH_CONF(CONF_LONG));
279
280#ifdef BAH_DEBUG
281	printf("%s: reset: chip configured, status=0x%02x\n",
282	    device_xname(&sc->sc_dev), GETREG(BAHSTAT));
283#endif
284	PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG));
285
286#ifdef BAH_DEBUG
287	printf("%s: reset: bits cleared, status=0x%02x\n",
288	    device_xname(&sc->sc_dev), GETREG(BAHSTAT));
289#endif
290
291	sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
292
293	/* start receiver */
294
295	sc->sc_intmask  |= BAH_RI;
296	sc->sc_rx_fillcount = 0;
297	sc->sc_rx_act = 2;
298
299	PUTREG(BAHCMD, BAH_RXBC(2));
300	PUTREG(BAHSTAT, sc->sc_intmask);
301
302#ifdef BAH_DEBUG
303	printf("%s: reset: started receiver, status=0x%02x\n",
304	    device_xname(&sc->sc_dev), GETREG(BAHSTAT));
305#endif
306
307	/* and init transmitter status */
308	sc->sc_tx_act = 0;
309	sc->sc_tx_fillcount = 0;
310
311	ifp->if_flags |= IFF_RUNNING;
312	ifp->if_flags &= ~IFF_OACTIVE;
313
314	bah_start(ifp);
315}
316
317/*
318 * Take interface offline
319 */
320void
321bah_stop(struct bah_softc *sc)
322{
323	bus_space_tag_t bst_r = sc->sc_bst_r;
324	bus_space_handle_t regs = sc->sc_regs;
325
326	/* Stop the interrupts */
327	PUTREG(BAHSTAT, 0);
328
329	/* Stop the interface */
330	(*sc->sc_reset)(sc, 0);
331
332	/* Stop watchdog timer */
333	sc->sc_arccom.ac_if.if_timer = 0;
334}
335
336/*
337 * Start output on interface. Get another datagram to send
338 * off the interface queue, and copy it to the
339 * interface before starting the output
340 *
341 * this assumes that it is called inside a critical section...
342 * XXX hm... does it still?
343 *
344 */
345void
346bah_start(struct ifnet *ifp)
347{
348	struct bah_softc *sc = ifp->if_softc;
349	struct mbuf *m,*mp;
350
351	bus_space_tag_t bst_r = sc->sc_bst_r;
352	bus_space_handle_t regs = sc->sc_regs;
353	bus_space_tag_t bst_m = sc->sc_bst_m;
354	bus_space_handle_t mem = sc->sc_mem;
355
356	int bah_ram_ptr;
357	int len, tlen, offset, s, buffer;
358#ifdef BAHTIMINGS
359	u_long copystart, lencopy, perbyte;
360#endif
361
362#if defined(BAH_DEBUG) && (BAH_DEBUG > 3)
363	printf("%s: start(0x%x)\n", device_xname(&sc->sc_dev), ifp);
364#endif
365
366	if ((ifp->if_flags & IFF_RUNNING) == 0)
367		return;
368
369	s = splnet();
370
371	if (sc->sc_tx_fillcount >= 2) {
372		splx(s);
373		return;
374	}
375
376	IFQ_DEQUEUE(&ifp->if_snd, m);
377	buffer = sc->sc_tx_act ^ 1;
378
379	splx(s);
380
381	if (m == 0)
382		return;
383
384	/*
385	 * If bpf is listening on this interface, let it
386	 * see the packet before we commit it to the wire
387	 *
388	 * (can't give the copy in A2060 card RAM to bpf, because
389	 * that RAM is just accessed as on every other byte)
390	 */
391	bpf_mtap(ifp, m);
392
393#ifdef BAH_DEBUG
394	if (m->m_len < ARC_HDRLEN)
395		m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */
396	printf("%s: start: filling %ld from %ld to %ld type %ld\n",
397	    device_xname(&sc->sc_dev), buffer, mtod(m, u_char *)[0],
398	    mtod(m, u_char *)[1], mtod(m, u_char *)[2]);
399#else
400	if (m->m_len < 2)
401		m = m_pullup(m, 2);
402#endif
403	bah_ram_ptr = buffer*512;
404
405	if (m == 0)
406		return;
407
408	/* write the addresses to RAM and throw them away */
409
410	/*
411	 * Hardware does this: Yet Another Microsecond Saved.
412	 * (btw, timing code says usually 2 microseconds)
413	 * PUTMEM(bah_ram_ptr + 0, mtod(m, u_char *)[0]);
414	 */
415
416	PUTMEM(bah_ram_ptr + 1, mtod(m, u_char *)[1]);
417	m_adj(m, 2);
418
419	/* get total length left at this point */
420	tlen = m->m_pkthdr.len;
421	if (tlen < ARC_MIN_FORBID_LEN) {
422		offset = 256 - tlen;
423		PUTMEM(bah_ram_ptr + 2, offset);
424	} else {
425		PUTMEM(bah_ram_ptr + 2, 0);
426		if (tlen <= ARC_MAX_FORBID_LEN)
427			offset = 255;		/* !!! */
428		else {
429			if (tlen > ARC_MAX_LEN)
430				tlen = ARC_MAX_LEN;
431			offset = 512 - tlen;
432		}
433		PUTMEM(bah_ram_ptr + 3, offset);
434
435	}
436	bah_ram_ptr += offset;
437
438	/* lets loop through the mbuf chain */
439
440	for (mp = m; mp; mp = mp->m_next) {
441		if ((len = mp->m_len)) {		/* YAMS */
442			bus_space_write_region_1(bst_m, mem, bah_ram_ptr,
443			    mtod(mp, void *), len);
444
445			bah_ram_ptr += len;
446		}
447	}
448
449	sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
450	sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5;
451
452	/* actually transmit the packet */
453	s = splnet();
454
455	if (++sc->sc_tx_fillcount > 1) {
456		/*
457		 * We are filled up to the rim. No more bufs for the moment,
458		 * please.
459		 */
460		ifp->if_flags |= IFF_OACTIVE;
461	} else {
462#ifdef BAH_DEBUG
463		printf("%s: start: starting transmitter on buffer %d\n",
464		    device_xname(&sc->sc_dev), buffer);
465#endif
466		/* Transmitter was off, start it */
467		sc->sc_tx_act = buffer;
468
469		/*
470		 * We still can accept another buf, so don't:
471		 * ifp->if_flags |= IFF_OACTIVE;
472		 */
473		sc->sc_intmask |= BAH_TA;
474		PUTREG(BAHCMD, BAH_TX(buffer));
475		PUTREG(BAHSTAT, sc->sc_intmask);
476
477		sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT;
478	}
479	splx(s);
480	m_freem(m);
481
482	/*
483	 * After 10 times reading the docs, I realized
484	 * that in the case the receiver NAKs the buffer request,
485	 * the hardware retries till shutdown.
486	 * This is integrated now in the code above.
487	 */
488
489	return;
490}
491
492/*
493 * Arcnet interface receiver soft interrupt:
494 * get the stuff out of any filled buffer we find.
495 */
496void
497bah_srint(void *vsc)
498{
499	struct bah_softc *sc = (struct bah_softc *)vsc;
500	int buffer, len, len1, amount, offset, s, type;
501	int bah_ram_ptr;
502	struct mbuf *m, *dst, *head;
503	struct arc_header *ah;
504	struct ifnet *ifp;
505
506	bus_space_tag_t bst_r = sc->sc_bst_r;
507        bus_space_tag_t bst_m = sc->sc_bst_m;
508	bus_space_handle_t regs = sc->sc_regs;
509	bus_space_handle_t mem = sc->sc_mem;
510
511	ifp = &sc->sc_arccom.ac_if;
512	head = 0;
513
514	s = splnet();
515	buffer = sc->sc_rx_act ^ 1;
516	splx(s);
517
518	/* Allocate header mbuf */
519	MGETHDR(m, M_DONTWAIT, MT_DATA);
520
521	if (m == 0) {
522		/*
523	 	 * in case s.th. goes wrong with mem, drop it
524	 	 * to make sure the receiver can be started again
525		 * count it as input error (we dont have any other
526		 * detectable)
527	 	 */
528		ifp->if_ierrors++;
529		goto cleanup;
530	}
531
532	m->m_pkthdr.rcvif = ifp;
533
534	/*
535	 * Align so that IP packet will be longword aligned. Here we
536	 * assume that m_data of new packet is longword aligned.
537	 * When implementing PHDS, we might have to change it to 2,
538	 * (2*sizeof(ulong) - ARC_HDRNEWLEN)), packet type dependent.
539	 */
540
541	bah_ram_ptr = buffer*512;
542	offset = GETMEM(bah_ram_ptr + 2);
543	if (offset)
544		len = 256 - offset;
545	else {
546		offset = GETMEM(bah_ram_ptr + 3);
547		len = 512 - offset;
548	}
549	if (len+2 >= MINCLSIZE)
550		MCLGET(m, M_DONTWAIT);
551
552	if (m == 0) {
553		ifp->if_ierrors++;
554		goto cleanup;
555	}
556
557	type = GETMEM(bah_ram_ptr + offset);
558	m->m_data += 1 + arc_isphds(type);
559
560	head = m;
561	ah = mtod(head, struct arc_header *);
562
563	ah->arc_shost = GETMEM(bah_ram_ptr + 0);
564	ah->arc_dhost = GETMEM(bah_ram_ptr + 1);
565
566	m->m_pkthdr.len = len+2; /* whole packet length */
567	m->m_len = 2;		 /* mbuf filled with ARCnet addresses */
568	bah_ram_ptr += offset;	/* ram buffer continues there */
569
570	while (len > 0) {
571
572		len1 = len;
573		amount = M_TRAILINGSPACE(m);
574
575		if (amount == 0) {
576			dst = m;
577			MGET(m, M_DONTWAIT, MT_DATA);
578
579			if (m == 0) {
580				ifp->if_ierrors++;
581				goto cleanup;
582			}
583
584			if (len1 >= MINCLSIZE)
585				MCLGET(m, M_DONTWAIT);
586
587			m->m_len = 0;
588			dst->m_next = m;
589			amount = M_TRAILINGSPACE(m);
590		}
591
592		if (amount < len1)
593			len1 = amount;
594
595		bus_space_read_region_1(bst_m, mem, bah_ram_ptr,
596		    mtod(m, u_char *) + m->m_len, len1);
597
598		m->m_len += len1;
599		bah_ram_ptr += len1;
600		len -= len1;
601	}
602
603	bpf_mtap(ifp, head);
604
605	(*sc->sc_arccom.ac_if.if_input)(&sc->sc_arccom.ac_if, head);
606
607	head = NULL;
608	ifp->if_ipackets++;
609
610cleanup:
611
612	if (head != NULL)
613		m_freem(head);
614
615	/* mark buffer as invalid by source id 0 */
616	bus_space_write_1(bst_m, mem, buffer*512, 0);
617	s = splnet();
618
619	if (--sc->sc_rx_fillcount == 2 - 1) {
620
621		/* was off, restart it on buffer just emptied */
622		sc->sc_rx_act = buffer;
623		sc->sc_intmask |= BAH_RI;
624
625		/* this also clears the RI flag interrupt: */
626		PUTREG(BAHCMD, BAH_RXBC(buffer));
627		PUTREG(BAHSTAT, sc->sc_intmask);
628
629#ifdef BAH_DEBUG
630		printf("%s: srint: restarted rx on buf %ld\n",
631		    device_xname(&sc->sc_dev), buffer);
632#endif
633	}
634	splx(s);
635}
636
637inline static void
638bah_tint(struct bah_softc *sc, int isr)
639{
640	struct ifnet *ifp;
641
642	bus_space_tag_t bst_r = sc->sc_bst_r;
643	bus_space_handle_t regs = sc->sc_regs;
644
645
646	int buffer;
647#ifdef BAHTIMINGS
648	int clknow;
649#endif
650
651	ifp = &(sc->sc_arccom.ac_if);
652	buffer = sc->sc_tx_act;
653
654	/*
655	 * retransmit code:
656	 * Normal situations first for fast path:
657	 * If acknowledgement received ok or broadcast, we're ok.
658	 * else if
659	 */
660
661	if (isr & BAH_TMA || sc->sc_broadcast[buffer])
662		sc->sc_arccom.ac_if.if_opackets++;
663#ifdef BAHRETRANSMIT
664	else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0
665	    && --sc->sc_retransmits[buffer] > 0) {
666		/* retransmit same buffer */
667		PUTREG(BAHCMD, BAH_TX(buffer));
668		return;
669	}
670#endif
671	else
672		ifp->if_oerrors++;
673
674
675	/* We know we can accept another buffer at this point. */
676	ifp->if_flags &= ~IFF_OACTIVE;
677
678	if (--sc->sc_tx_fillcount > 0) {
679
680		/*
681		 * start tx on other buffer.
682		 * This also clears the int flag
683		 */
684		buffer ^= 1;
685		sc->sc_tx_act = buffer;
686
687		/*
688		 * already given:
689		 * sc->sc_intmask |= BAH_TA;
690		 * PUTREG(BAHSTAT, sc->sc_intmask);
691		 */
692		PUTREG(BAHCMD, BAH_TX(buffer));
693		/* init watchdog timer */
694		ifp->if_timer = ARCTIMEOUT;
695
696#if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
697		printf("%s: tint: starting tx on buffer %d, status 0x%02x\n",
698		    device_xname(&sc->sc_dev), buffer, GETREG(BAHSTAT));
699#endif
700	} else {
701		/* have to disable TX interrupt */
702		sc->sc_intmask &= ~BAH_TA;
703		PUTREG(BAHSTAT, sc->sc_intmask);
704		/* ... and watchdog timer */
705		ifp->if_timer = 0;
706
707#ifdef BAH_DEBUG
708		printf("%s: tint: no more buffers to send, status 0x%02x\n",
709		    device_xname(&sc->sc_dev), GETREG(BAHSTAT));
710#endif
711	}
712
713	/* XXXX TODO */
714#ifdef BAHSOFTCOPY
715	/* schedule soft int to fill a new buffer for us */
716	softint_schedule(sc->sc_txcookie);
717#else
718	/* call it directly */
719	bah_start(ifp);
720#endif
721}
722
723/*
724 * Our interrupt routine
725 */
726int
727bahintr(void *arg)
728{
729	struct bah_softc *sc = arg;
730
731	bus_space_tag_t bst_r = sc->sc_bst_r;
732        bus_space_tag_t bst_m = sc->sc_bst_m;
733	bus_space_handle_t regs = sc->sc_regs;
734	bus_space_handle_t mem = sc->sc_mem;
735
736	u_char isr, maskedisr;
737	int buffer;
738	u_long newsec;
739
740	isr = GETREG(BAHSTAT);
741	maskedisr = isr & sc->sc_intmask;
742	if (!maskedisr)
743		return (0);
744	do {
745
746#if defined(BAH_DEBUG) && (BAH_DEBUG>1)
747		printf("%s: intr: status 0x%02x, intmask 0x%02x\n",
748		    device_xname(&sc->sc_dev), isr, sc->sc_intmask);
749#endif
750
751		if (maskedisr & BAH_POR) {
752		  	/*
753			 * XXX We should never see this. Don't bother to store
754			 * the address.
755			 * sc->sc_arccom.ac_anaddr = GETMEM(BAHMACOFF);
756			 */
757			PUTREG(BAHCMD, BAH_CLR(CLR_POR));
758			log(LOG_WARNING,
759			    "%s: intr: got spurious power on reset int\n",
760			    device_xname(&sc->sc_dev));
761		}
762
763		if (maskedisr & BAH_RECON) {
764			/*
765			 * we dont need to:
766			 * PUTREG(BAHCMD, BAH_CONF(CONF_LONG));
767			 */
768			PUTREG(BAHCMD, BAH_CLR(CLR_RECONFIG));
769			sc->sc_arccom.ac_if.if_collisions++;
770
771			/*
772			 * If less than 2 seconds per reconfig:
773			 *	If ARC_EXCESSIVE_RECONFIGS
774			 *	since last burst, complain and set threshold for
775			 *	warnings to ARC_EXCESSIVE_RECONS_REWARN.
776			 *
777			 * This allows for, e.g., new stations on the cable, or
778			 * cable switching as long as it is over after
779			 * (normally) 16 seconds.
780			 *
781			 * XXX TODO: check timeout bits in status word and
782			 * double time if necessary.
783			 */
784
785			callout_stop(&sc->sc_recon_ch);
786			newsec = time_second;
787			if ((newsec - sc->sc_recontime <= 2) &&
788			    (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) {
789				log(LOG_WARNING,
790				    "%s: excessive token losses, "
791				    "cable problem?\n", device_xname(&sc->sc_dev));
792			}
793			sc->sc_recontime = newsec;
794			callout_reset(&sc->sc_recon_ch, 15 * hz,
795			    bah_reconwatch, (void *)sc);
796		}
797
798		if (maskedisr & BAH_RI) {
799#if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
800			printf("%s: intr: hard rint, act %ld\n",
801			    device_xname(&sc->sc_dev), sc->sc_rx_act);
802#endif
803
804			buffer = sc->sc_rx_act;
805			/* look if buffer is marked invalid: */
806			if (GETMEM(buffer*512) == 0) {
807				/*
808				 * invalid marked buffer (or illegally
809				 * configured sender)
810				 */
811				log(LOG_WARNING,
812				    "%s: spurious RX interrupt or sender 0 "
813				    " (ignored)\n", device_xname(&sc->sc_dev));
814				/*
815				 * restart receiver on same buffer.
816				 * XXX maybe better reset interface?
817				 */
818				PUTREG(BAHCMD, BAH_RXBC(buffer));
819			} else {
820				if (++sc->sc_rx_fillcount > 1) {
821					sc->sc_intmask &= ~BAH_RI;
822					PUTREG(BAHSTAT, sc->sc_intmask);
823				} else {
824					buffer ^= 1;
825					sc->sc_rx_act = buffer;
826
827					/*
828					 * Start receiver on other receive
829					 * buffer. This also clears the RI
830					 * interrupt flag.
831					 */
832					PUTREG(BAHCMD, BAH_RXBC(buffer));
833					/* in RX intr, so mask is ok for RX */
834
835#ifdef BAH_DEBUG
836					printf("%s: strt rx for buf %ld, "
837					    "stat 0x%02x\n",
838					    device_xname(&sc->sc_dev), sc->sc_rx_act,
839					    GETREG(BAHSTAT));
840#endif
841				}
842
843#ifdef BAHSOFTCOPY
844				/*
845				 * this one starts a soft int to copy out
846				 * of the hw
847				 */
848				softint_schedule(sc->sc_rxcookie);
849#else
850				/* this one does the copy here */
851				bah_srint(sc);
852#endif
853			}
854		}
855		if (maskedisr & BAH_TA) {
856			bah_tint(sc, isr);
857		}
858		isr = GETREG(BAHSTAT);
859		maskedisr = isr & sc->sc_intmask;
860	} while (maskedisr);
861
862	return (1);
863}
864
865void
866bah_reconwatch(void *arg)
867{
868	struct bah_softc *sc = arg;
869
870	if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) {
871		sc->sc_reconcount = 0;
872		log(LOG_WARNING, "%s: token valid again.\n",
873		    device_xname(&sc->sc_dev));
874	}
875	sc->sc_reconcount = 0;
876}
877
878
879/*
880 * Process an ioctl request.
881 * This code needs some work - it looks pretty ugly.
882 */
883int
884bah_ioctl(struct ifnet *ifp, u_long cmd, void *data)
885{
886	struct bah_softc *sc;
887	struct ifaddr *ifa;
888	struct ifreq *ifr;
889	int s, error;
890
891	error = 0;
892	sc = ifp->if_softc;
893	ifa = (struct ifaddr *)data;
894	ifr = (struct ifreq *)data;
895	s = splnet();
896
897#if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
898	printf("%s: ioctl() called, cmd = 0x%x\n",
899	    device_xname(&sc->sc_dev), cmd);
900#endif
901
902	switch (cmd) {
903	case SIOCINITIFADDR:
904		ifp->if_flags |= IFF_UP;
905		bah_init(sc);
906		switch (ifa->ifa_addr->sa_family) {
907#ifdef INET
908		case AF_INET:
909			arp_ifinit(ifp, ifa);
910			break;
911#endif
912		default:
913			break;
914		}
915
916	case SIOCSIFFLAGS:
917		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
918			break;
919		/* XXX re-use ether_ioctl() */
920		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
921		case IFF_RUNNING:
922			/*
923			 * If interface is marked down and it is running,
924			 * then stop it.
925			 */
926			bah_stop(sc);
927			ifp->if_flags &= ~IFF_RUNNING;
928			break;
929		case IFF_UP:
930			/*
931			 * If interface is marked up and it is stopped, then
932			 * start it.
933			 */
934			bah_init(sc);
935			break;
936		}
937		break;
938
939	case SIOCADDMULTI:
940	case SIOCDELMULTI:
941		switch (ifreq_getaddr(cmd, ifr)->sa_family) {
942		case AF_INET:
943		case AF_INET6:
944			error = 0;
945			break;
946		default:
947			error = EAFNOSUPPORT;
948			break;
949		}
950		break;
951
952	default:
953		error = ether_ioctl(ifp, cmd, data);
954	}
955
956	splx(s);
957	return (error);
958}
959
960/*
961 * watchdog routine for transmitter.
962 *
963 * We need this, because else a receiver whose hardware is alive, but whose
964 * software has not enabled the Receiver, would make our hardware wait forever
965 * Discovered this after 20 times reading the docs.
966 *
967 * Only thing we do is disable transmitter. We'll get an transmit timeout,
968 * and the int handler will have to decide not to retransmit (in case
969 * retransmission is implemented).
970 *
971 * This one assumes being called inside splnet()
972 */
973
974void
975bah_watchdog(struct ifnet *ifp)
976{
977	struct bah_softc *sc = ifp->if_softc;
978
979	bus_space_tag_t bst_r = sc->sc_bst_r;
980	bus_space_handle_t regs = sc->sc_regs;
981
982	PUTREG(BAHCMD, BAH_TXDIS);
983	return;
984}
985
986