]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cm/smc90cx6.c
The r48589 promised to remove implicit inclusion of if_var.h soon. Prepare
[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 == 0)
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 == 0)
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 == 0) {
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                 ifp->if_ierrors++;
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                 MCLGET(m, M_NOWAIT);
544
545                 /* Insist on getting a cluster */
546                 if ((m->m_flags & M_EXT) == 0) {
547                         ifp->if_ierrors++;
548                         goto cleanup;
549                 }
550         }
551
552         if (m == 0) {
553                 ifp->if_ierrors++;
554                 goto cleanup;
555         }
556
557         type = GETMEM(cm_ram_ptr + offset);
558         m->m_data += 1 + arc_isphds(type);
559         /* mbuf filled with ARCnet addresses */
560         m->m_pkthdr.len = m->m_len = len + 2;
561
562         ah = mtod(m, struct arc_header *);
563         ah->arc_shost = GETMEM(cm_ram_ptr + 0);
564         ah->arc_dhost = GETMEM(cm_ram_ptr + 1);
565
566         bus_space_read_region_1(
567             rman_get_bustag(sc->mem_res), rman_get_bushandle(sc->mem_res),
568             cm_ram_ptr + offset, mtod(m, u_char *) + 2, len);
569
570         CM_UNLOCK(sc);
571         arc_input(ifp, m);
572         CM_LOCK(sc);
573
574         m = NULL;
575         ifp->if_ipackets++;
576
577 cleanup:
578
579         if (m != NULL)
580                 m_freem(m);
581
582         /* mark buffer as invalid by source id 0 */
583         PUTMEM(buffer << 9, 0);
584         if (--sc->sc_rx_fillcount == 2 - 1) {
585
586                 /* was off, restart it on buffer just emptied */
587                 sc->sc_rx_act = buffer;
588                 sc->sc_intmask |= CM_RI;
589
590                 /* this also clears the RI flag interrupt: */
591                 PUTREG(CMCMD, CM_RXBC(buffer));
592                 PUTREG(CMSTAT, sc->sc_intmask);
593
594 #ifdef CM_DEBUG
595                 if_printf(ifp, "srint: restarted rx on buf %d\n", buffer);
596 #endif
597         }
598 }
599
600 static inline void
601 cm_tint_locked(sc, isr)
602         struct cm_softc *sc;
603         int isr;
604 {
605         struct ifnet *ifp;
606
607         int buffer;
608 #ifdef CMTIMINGS
609         int clknow;
610 #endif
611
612         ifp = sc->sc_ifp;
613         buffer = sc->sc_tx_act;
614
615         /*
616          * retransmit code:
617          * Normal situtations first for fast path:
618          * If acknowledgement received ok or broadcast, we're ok.
619          * else if
620          */
621
622         if (isr & CM_TMA || sc->sc_broadcast[buffer])
623                 ifp->if_opackets++;
624 #ifdef CMRETRANSMIT
625         else if (ifp->if_flags & IFF_LINK2 && sc->sc_timer > 0
626             && --sc->sc_retransmits[buffer] > 0) {
627                 /* retransmit same buffer */
628                 PUTREG(CMCMD, CM_TX(buffer));
629                 return;
630         }
631 #endif
632         else
633                 ifp->if_oerrors++;
634
635
636         /* We know we can accept another buffer at this point. */
637         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
638
639         if (--sc->sc_tx_fillcount > 0) {
640
641                 /*
642                  * start tx on other buffer.
643                  * This also clears the int flag
644                  */
645                 buffer ^= 1;
646                 sc->sc_tx_act = buffer;
647
648                 /*
649                  * already given:
650                  * sc->sc_intmask |= CM_TA;
651                  * PUTREG(CMSTAT, sc->sc_intmask);
652                  */
653                 PUTREG(CMCMD, CM_TX(buffer));
654                 /* init watchdog timer */
655                 sc->sc_timer = ARCTIMEOUT;
656
657 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
658                 if_printf(ifp,
659                     "tint: starting tx on buffer %d, status 0x%02x\n",
660                     buffer, GETREG(CMSTAT));
661 #endif
662         } else {
663                 /* have to disable TX interrupt */
664                 sc->sc_intmask &= ~CM_TA;
665                 PUTREG(CMSTAT, sc->sc_intmask);
666                 /* ... and watchdog timer */
667                 sc->sc_timer = 0;
668
669 #ifdef CM_DEBUG
670                 if_printf(ifp, "tint: no more buffers to send, status 0x%02x\n",
671                     GETREG(CMSTAT));
672 #endif
673         }
674
675         /* XXXX TODO */
676 #ifdef CMSOFTCOPY
677         /* schedule soft int to fill a new buffer for us */
678         softintr_schedule(sc->sc_txcookie);
679 #else
680         /* call it directly */
681         cm_start_locked(ifp);
682 #endif
683 }
684
685 /*
686  * Our interrupt routine
687  */
688 void
689 cmintr(arg)
690         void *arg;
691 {
692         struct cm_softc *sc = arg;
693         struct ifnet *ifp = sc->sc_ifp;
694
695         u_char isr, maskedisr;
696         int buffer;
697         u_long newsec;
698
699         CM_LOCK(sc);
700
701         isr = GETREG(CMSTAT);
702         maskedisr = isr & sc->sc_intmask;
703         if (!maskedisr || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
704                 CM_UNLOCK(sc);
705                 return;
706         }
707
708         do {
709
710 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
711                 if_printf(ifp, "intr: status 0x%02x, intmask 0x%02x\n",
712                     isr, sc->sc_intmask);
713 #endif
714
715                 if (maskedisr & CM_POR) {
716                         /*
717                          * XXX We should never see this. Don't bother to store
718                          * the address.
719                          * sc->sc_ifp->if_l2com->ac_anaddr = GETMEM(CMMACOFF);
720                          */
721                         PUTREG(CMCMD, CM_CLR(CLR_POR));
722                         log(LOG_WARNING,
723                             "%s: intr: got spurious power on reset int\n",
724                             ifp->if_xname);
725                 }
726
727                 if (maskedisr & CM_RECON) {
728                         /*
729                          * we dont need to:
730                          * PUTREG(CMCMD, CM_CONF(CONF_LONG));
731                          */
732                         PUTREG(CMCMD, CM_CLR(CLR_RECONFIG));
733                         ifp->if_collisions++;
734
735                         /*
736                          * If less than 2 seconds per reconfig:
737                          *      If ARC_EXCESSIVE_RECONFIGS
738                          *      since last burst, complain and set treshold for
739                          *      warnings to ARC_EXCESSIVE_RECONS_REWARN.
740                          *
741                          * This allows for, e.g., new stations on the cable, or
742                          * cable switching as long as it is over after
743                          * (normally) 16 seconds.
744                          *
745                          * XXX TODO: check timeout bits in status word and
746                          * double time if necessary.
747                          */
748
749                         callout_stop(&sc->sc_recon_ch);
750                         newsec = time_second;
751                         if ((newsec - sc->sc_recontime <= 2) &&
752                             (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) {
753                                 log(LOG_WARNING,
754                                     "%s: excessive token losses, "
755                                     "cable problem?\n",
756                                     ifp->if_xname);
757                         }
758                         sc->sc_recontime = newsec;
759                         callout_reset(&sc->sc_recon_ch, 15 * hz,
760                             cm_reconwatch_locked, (void *)sc);
761                 }
762
763                 if (maskedisr & CM_RI) {
764 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
765                         if_printf(ifp, "intr: hard rint, act %d\n",
766                             sc->sc_rx_act);
767 #endif
768
769                         buffer = sc->sc_rx_act;
770                         /* look if buffer is marked invalid: */
771                         if (GETMEM(buffer * 512) == 0) {
772                                 /*
773                                  * invalid marked buffer (or illegally
774                                  * configured sender)
775                                  */
776                                 log(LOG_WARNING,
777                                     "%s: spurious RX interrupt or sender 0 "
778                                     " (ignored)\n", ifp->if_xname);
779                                 /*
780                                  * restart receiver on same buffer.
781                                  * XXX maybe better reset interface?
782                                  */
783                                 PUTREG(CMCMD, CM_RXBC(buffer));
784                         } else {
785                                 if (++sc->sc_rx_fillcount > 1) {
786                                         sc->sc_intmask &= ~CM_RI;
787                                         PUTREG(CMSTAT, sc->sc_intmask);
788                                 } else {
789                                         buffer ^= 1;
790                                         sc->sc_rx_act = buffer;
791
792                                         /*
793                                          * Start receiver on other receive
794                                          * buffer. This also clears the RI
795                                          * interrupt flag.
796                                          */
797                                         PUTREG(CMCMD, CM_RXBC(buffer));
798                                         /* in RX intr, so mask is ok for RX */
799
800 #ifdef CM_DEBUG
801                                         if_printf(ifp, "strt rx for buf %d, "
802                                             "stat 0x%02x\n",
803                                             sc->sc_rx_act, GETREG(CMSTAT));
804 #endif
805                                 }
806
807 #ifdef CMSOFTCOPY
808                                 /*
809                                  * this one starts a soft int to copy out
810                                  * of the hw
811                                  */
812                                 softintr_schedule(sc->sc_rxcookie);
813 #else
814                                 /* this one does the copy here */
815                                 cm_srint_locked(sc);
816 #endif
817                         }
818                 }
819                 if (maskedisr & CM_TA) {
820                         cm_tint_locked(sc, isr);
821                 }
822                 isr = GETREG(CMSTAT);
823                 maskedisr = isr & sc->sc_intmask;
824         } while (maskedisr);
825 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
826         if_printf(ifp, "intr (exit): status 0x%02x, intmask 0x%02x\n",
827             isr, sc->sc_intmask);
828 #endif
829         CM_UNLOCK(sc);
830 }
831
832 void
833 cm_reconwatch_locked(arg)
834         void *arg;
835 {
836         struct cm_softc *sc = arg;
837         struct ifnet *ifp = sc->sc_ifp;
838
839         if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) {
840                 sc->sc_reconcount = 0;
841                 log(LOG_WARNING, "%s: token valid again.\n",
842                     ifp->if_xname);
843         }
844         sc->sc_reconcount = 0;
845 }
846
847
848 /*
849  * Process an ioctl request.
850  * This code needs some work - it looks pretty ugly.
851  */
852 int
853 cm_ioctl(ifp, command, data)
854         struct ifnet *ifp;
855         u_long command;
856         caddr_t data;
857 {
858         struct cm_softc *sc;
859         int error;
860
861         error = 0;
862         sc = ifp->if_softc;
863
864 #if defined(CM_DEBUG) && (CM_DEBUG > 2)
865         if_printf(ifp, "ioctl() called, cmd = 0x%lx\n", command);
866 #endif
867
868         switch (command) {
869         case SIOCSIFADDR:
870         case SIOCGIFADDR:
871         case SIOCADDMULTI:
872         case SIOCDELMULTI:
873         case SIOCSIFMTU:
874                 error = arc_ioctl(ifp, command, data);
875                 break;
876
877         case SIOCSIFFLAGS:
878                 CM_LOCK(sc);
879                 if ((ifp->if_flags & IFF_UP) == 0 &&
880                     (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
881                         /*
882                          * If interface is marked down and it is running,
883                          * then stop it.
884                          */
885                         cm_stop_locked(sc);
886                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
887                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
888                            (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
889                         /*
890                          * If interface is marked up and it is stopped, then
891                          * start it.
892                          */
893                         cm_init_locked(sc);
894                 }
895                 CM_UNLOCK(sc);
896                 break;
897
898         default:
899                 error = EINVAL;
900                 break;
901         }
902
903         return (error);
904 }
905
906 /*
907  * watchdog routine for transmitter.
908  *
909  * We need this, because else a receiver whose hardware is alive, but whose
910  * software has not enabled the Receiver, would make our hardware wait forever
911  * Discovered this after 20 times reading the docs.
912  *
913  * Only thing we do is disable transmitter. We'll get a transmit timeout,
914  * and the int handler will have to decide not to retransmit (in case
915  * retransmission is implemented).
916  */
917 void
918 cm_watchdog(void *arg)
919 {
920         struct cm_softc *sc;
921
922         sc = arg;
923         callout_reset(&sc->sc_watchdog_timer, hz, cm_watchdog, sc);
924         if (sc->sc_timer == 0 || --sc->sc_timer > 0)
925                 return;
926         PUTREG(CMCMD, CM_TXDIS);
927 }