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