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