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