]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cm/smc90cx6.c
MFV r323678: file 5.32
[FreeBSD/FreeBSD.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_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
67 MODULE_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
80 devclass_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
115 void    cm_init(void *);
116 static void cm_init_locked(struct cm_softc *);
117 static void cm_reset_locked(struct cm_softc *);
118 void    cm_start(struct ifnet *);
119 void    cm_start_locked(struct ifnet *);
120 int     cm_ioctl(struct ifnet *, unsigned long, caddr_t);
121 void    cm_watchdog(void *);
122 void    cm_srint_locked(void *vsc);
123 static  void cm_tint_locked(struct cm_softc *, int);
124 void    cm_reconwatch_locked(void *);
125
126 /*
127  * Release all resources
128  */
129 void
130 cm_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
152 int
153 cm_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  */
215 void
216 cm_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
226 static void
227 cm_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  */
242 void
243 cm_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  */
318 void
319 cm_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
333 void
334 cm_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  */
350 void
351 cm_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
475 void
476 cm_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  */
490 void
491 cm_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
574 cleanup:
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
597 static inline void
598 cm_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  */
685 void
686 cmintr(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
829 void
830 cm_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  */
849 int
850 cm_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  */
914 void
915 cm_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 }