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