]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/cm/smc90cx6.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / cm / smc90cx6.c
1 /*      $NetBSD: smc90cx6.c,v 1.38 2001/07/07 15:57:53 thorpej Exp $ */
2
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
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
66 MODULE_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
79 devclass_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
114 void    cm_init(void *);
115 static void cm_init_locked(struct cm_softc *);
116 static void cm_reset_locked(struct cm_softc *);
117 void    cm_start(struct ifnet *);
118 void    cm_start_locked(struct ifnet *);
119 int     cm_ioctl(struct ifnet *, unsigned long, caddr_t);
120 void    cm_watchdog(void *);
121 void    cm_srint_locked(void *vsc);
122 static  void cm_tint_locked(struct cm_softc *, int);
123 void    cm_reconwatch_locked(void *);
124
125 /*
126  * Release all resources
127  */
128 void
129 cm_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
151 int
152 cm_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  */
214 void
215 cm_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
225 static void
226 cm_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  */
241 void
242 cm_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  */
317 void
318 cm_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
332 void
333 cm_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  */
349 void
350 cm_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
474 void
475 cm_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  */
489 void
490 cm_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
576 cleanup:
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
599 static inline void
600 cm_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  */
687 void
688 cmintr(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
831 void
832 cm_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  */
851 int
852 cm_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  */
916 void
917 cm_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 }