]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cm/smc90cx6.c
This commit was generated by cvs2svn to compensate for changes in r107207,
[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         BPF_MTAP(ifp, m);
523
524 #ifdef CM_DEBUG
525         if (m->m_len < ARC_HDRLEN)
526                 m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */
527         if_printf(ifp, "start: filling %d from %d to %d type %d\n",
528             buffer, mtod(m, u_char *)[0],
529             mtod(m, u_char *)[1], mtod(m, u_char *)[2]);
530 #else
531         if (m->m_len < 2)
532                 m = m_pullup(m, 2);
533 #endif
534         cm_ram_ptr = buffer*512;
535
536         if (m == 0)
537                 return;
538
539         /* write the addresses to RAM and throw them away */
540
541         /*
542          * Hardware does this: Yet Another Microsecond Saved.
543          * (btw, timing code says usually 2 microseconds)
544          * PUTMEM(cm_ram_ptr + 0, mtod(m, u_char *)[0]);
545          */
546
547         PUTMEM(cm_ram_ptr + 1, mtod(m, u_char *)[1]);
548         m_adj(m, 2);
549
550         /* get total length left at this point */
551         tlen = m->m_pkthdr.len;
552         if (tlen < ARC_MIN_FORBID_LEN) {
553                 offset = 256 - tlen;
554                 PUTMEM(cm_ram_ptr + 2, offset);
555         } else {
556                 PUTMEM(cm_ram_ptr + 2, 0);
557                 if (tlen <= ARC_MAX_FORBID_LEN)
558                         offset = 255;           /* !!! */
559                 else {
560                         if (tlen > ARC_MAX_LEN)
561                                 tlen = ARC_MAX_LEN;
562                         offset = 512 - tlen;
563                 }
564                 PUTMEM(cm_ram_ptr + 3, offset);
565
566         }
567         cm_ram_ptr += offset;
568
569         /* lets loop through the mbuf chain */
570
571         for (mp = m; mp; mp = mp->m_next) {
572                 if ((len = mp->m_len)) {                /* YAMS */
573                         bus_space_write_region_1(
574                             rman_get_bustag(sc->mem_res),
575                             rman_get_bushandle(sc->mem_res),
576                             cm_ram_ptr, mtod(mp, caddr_t), len);
577
578                         cm_ram_ptr += len;
579                 }
580         }
581
582         sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
583         sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5;
584
585         /* actually transmit the packet */
586         s = splimp();
587
588         if (++sc->sc_tx_fillcount > 1) {
589                 /*
590                  * We are filled up to the rim. No more bufs for the moment,
591                  * please.
592                  */
593                 ifp->if_flags |= IFF_OACTIVE;
594         } else {
595 #ifdef CM_DEBUG
596                 if_printf(ifp, "start: starting transmitter on buffer %d\n",
597                     buffer);
598 #endif
599                 /* Transmitter was off, start it */
600                 sc->sc_tx_act = buffer;
601
602                 /*
603                  * We still can accept another buf, so don't:
604                  * ifp->if_flags |= IFF_OACTIVE;
605                  */
606                 sc->sc_intmask |= CM_TA;
607                 PUTREG(CMCMD, CM_TX(buffer));
608                 PUTREG(CMSTAT, sc->sc_intmask);
609
610                 sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT;
611         }
612         splx(s);
613         m_freem(m);
614
615         /*
616          * After 10 times reading the docs, I realized
617          * that in the case the receiver NAKs the buffer request,
618          * the hardware retries till shutdown.
619          * This is integrated now in the code above.
620          */
621
622         return;
623 }
624
625 /*
626  * Arcnet interface receiver soft interrupt:
627  * get the stuff out of any filled buffer we find.
628  */
629 void
630 cm_srint(vsc)
631         void *vsc;
632 {
633         struct cm_softc *sc = (struct cm_softc *)vsc;
634         int buffer, len, offset, s, type;
635         int cm_ram_ptr;
636         struct mbuf *m;
637         struct arc_header *ah;
638         struct ifnet *ifp;
639
640         ifp = &sc->sc_arccom.ac_if;
641
642         s = splimp();
643         buffer = sc->sc_rx_act ^ 1;
644         splx(s);
645
646         /* Allocate header mbuf */
647         MGETHDR(m, M_DONTWAIT, MT_DATA);
648
649         if (m == 0) {
650                 /*
651                  * in case s.th. goes wrong with mem, drop it
652                  * to make sure the receiver can be started again
653                  * count it as input error (we dont have any other
654                  * detectable)
655                  */
656                 ifp->if_ierrors++;
657                 goto cleanup;
658         }
659
660         m->m_pkthdr.rcvif = ifp;
661
662         /*
663          * Align so that IP packet will be longword aligned. Here we
664          * assume that m_data of new packet is longword aligned.
665          * When implementing PHDS, we might have to change it to 2,
666          * (2*sizeof(ulong) - CM_HDRNEWLEN)), packet type dependent.
667          */
668
669         cm_ram_ptr = buffer*512;
670         offset = GETMEM(cm_ram_ptr + 2);
671         if (offset)
672                 len = 256 - offset;
673         else {
674                 offset = GETMEM(cm_ram_ptr + 3);
675                 len = 512 - offset;
676         }
677
678         /*
679          * first +2 bytes for align fixup below
680          * second +2 bytes are for src/dst addresses
681          */
682         if ((len + 2 + 2) > MHLEN) {
683                 /* attach an mbuf cluster */
684                 MCLGET(m, M_DONTWAIT);
685
686                 /* Insist on getting a cluster */
687                 if ((m->m_flags & M_EXT) == 0) {
688                         ifp->if_ierrors++;
689                         goto cleanup;
690                 }
691         }
692
693         if (m == 0) {
694                 ifp->if_ierrors++;
695                 goto cleanup;
696         }
697
698         type = GETMEM(cm_ram_ptr + offset);
699         m->m_data += 1 + arc_isphds(type);
700         /* mbuf filled with ARCnet addresses */
701         m->m_pkthdr.len = m->m_len = len + 2;
702
703         ah = mtod(m, struct arc_header *);
704         ah->arc_shost = GETMEM(cm_ram_ptr + 0);
705         ah->arc_dhost = GETMEM(cm_ram_ptr + 1);
706
707         bus_space_read_region_1(
708             rman_get_bustag(sc->mem_res), rman_get_bushandle(sc->mem_res),
709             cm_ram_ptr + offset, mtod(m, u_char *) + 2, len);
710
711         arc_input(ifp, m);
712
713         m = NULL;
714         ifp->if_ipackets++;
715
716 cleanup:
717
718         if (m != NULL)
719                 m_freem(m);
720
721         /* mark buffer as invalid by source id 0 */
722         PUTMEM(buffer << 9, 0);
723         s = splimp();
724
725         if (--sc->sc_rx_fillcount == 2 - 1) {
726
727                 /* was off, restart it on buffer just emptied */
728                 sc->sc_rx_act = buffer;
729                 sc->sc_intmask |= CM_RI;
730
731                 /* this also clears the RI flag interupt: */
732                 PUTREG(CMCMD, CM_RXBC(buffer));
733                 PUTREG(CMSTAT, sc->sc_intmask);
734
735 #ifdef CM_DEBUG
736                 if_printf(ifp, "srint: restarted rx on buf %d\n", buffer);
737 #endif
738         }
739         splx(s);
740 }
741
742 __inline static void
743 cm_tint(sc, isr)
744         struct cm_softc *sc;
745         int isr;
746 {
747         struct ifnet *ifp;
748
749         int buffer;
750 #ifdef CMTIMINGS
751         int clknow;
752 #endif
753
754         ifp = &(sc->sc_arccom.ac_if);
755         buffer = sc->sc_tx_act;
756
757         /*
758          * retransmit code:
759          * Normal situtations first for fast path:
760          * If acknowledgement received ok or broadcast, we're ok.
761          * else if
762          */
763
764         if (isr & CM_TMA || sc->sc_broadcast[buffer])
765                 sc->sc_arccom.ac_if.if_opackets++;
766 #ifdef CMRETRANSMIT
767         else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0
768             && --sc->sc_retransmits[buffer] > 0) {
769                 /* retransmit same buffer */
770                 PUTREG(CMCMD, CM_TX(buffer));
771                 return;
772         }
773 #endif
774         else
775                 ifp->if_oerrors++;
776
777
778         /* We know we can accept another buffer at this point. */
779         ifp->if_flags &= ~IFF_OACTIVE;
780
781         if (--sc->sc_tx_fillcount > 0) {
782
783                 /*
784                  * start tx on other buffer.
785                  * This also clears the int flag
786                  */
787                 buffer ^= 1;
788                 sc->sc_tx_act = buffer;
789
790                 /*
791                  * already given:
792                  * sc->sc_intmask |= CM_TA;
793                  * PUTREG(CMSTAT, sc->sc_intmask);
794                  */
795                 PUTREG(CMCMD, CM_TX(buffer));
796                 /* init watchdog timer */
797                 ifp->if_timer = ARCTIMEOUT;
798
799 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
800                 if_printf(ifp,
801                     "tint: starting tx on buffer %d, status 0x%02x\n",
802                     buffer, GETREG(CMSTAT));
803 #endif
804         } else {
805                 /* have to disable TX interrupt */
806                 sc->sc_intmask &= ~CM_TA;
807                 PUTREG(CMSTAT, sc->sc_intmask);
808                 /* ... and watchdog timer */
809                 ifp->if_timer = 0;
810
811 #ifdef CM_DEBUG
812                 if_printf(ifp, "tint: no more buffers to send, status 0x%02x\n",
813                     GETREG(CMSTAT));
814 #endif
815         }
816
817         /* XXXX TODO */
818 #ifdef CMSOFTCOPY
819         /* schedule soft int to fill a new buffer for us */
820         softintr_schedule(sc->sc_txcookie);
821 #else
822         /* call it directly */
823         cm_start(ifp);
824 #endif
825 }
826
827 /*
828  * Our interrupt routine
829  */
830 void
831 cmintr(arg)
832         void *arg;
833 {
834         struct cm_softc *sc = arg;
835         struct ifnet *ifp = &sc->sc_arccom.ac_if;
836
837         u_char isr, maskedisr;
838         int buffer;
839         u_long newsec;
840
841         isr = GETREG(CMSTAT);
842         maskedisr = isr & sc->sc_intmask;
843         if (!maskedisr)
844                 return;
845         do {
846
847 #if defined(CM_DEBUG) && (CM_DEBUG>1)
848                 if_printf(ifp, "intr: status 0x%02x, intmask 0x%02x\n",
849                     isr, sc->sc_intmask);
850 #endif
851
852                 if (maskedisr & CM_POR) {
853                         /*
854                          * XXX We should never see this. Don't bother to store
855                          * the address.
856                          * sc->sc_arccom.ac_anaddr = GETMEM(CMMACOFF);
857                          */
858                         PUTREG(CMCMD, CM_CLR(CLR_POR));
859                         log(LOG_WARNING,
860                             "%s%d: intr: got spurious power on reset int\n",
861                             ifp->if_name, ifp->if_unit);
862                 }
863
864                 if (maskedisr & CM_RECON) {
865                         /*
866                          * we dont need to:
867                          * PUTREG(CMCMD, CM_CONF(CONF_LONG));
868                          */
869                         PUTREG(CMCMD, CM_CLR(CLR_RECONFIG));
870                         sc->sc_arccom.ac_if.if_collisions++;
871
872                         /*
873                          * If less than 2 seconds per reconfig:
874                          *      If ARC_EXCESSIVE_RECONFIGS
875                          *      since last burst, complain and set treshold for
876                          *      warnings to ARC_EXCESSIVE_RECONS_REWARN.
877                          *
878                          * This allows for, e.g., new stations on the cable, or
879                          * cable switching as long as it is over after
880                          * (normally) 16 seconds.
881                          *
882                          * XXX TODO: check timeout bits in status word and
883                          * double time if necessary.
884                          */
885
886                         callout_stop(&sc->sc_recon_ch);
887                         newsec = time_second;
888                         if ((newsec - sc->sc_recontime <= 2) &&
889                             (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) {
890                                 log(LOG_WARNING,
891                                     "%s%d: excessive token losses, "
892                                     "cable problem?\n",
893                                     ifp->if_name, ifp->if_unit);
894                         }
895                         sc->sc_recontime = newsec;
896                         callout_reset(&sc->sc_recon_ch, 15 * hz,
897                             cm_reconwatch, (void *)sc);
898                 }
899
900                 if (maskedisr & CM_RI) {
901 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
902                         if_printf(ifp, "intr: hard rint, act %d\n",
903                             sc->sc_rx_act);
904 #endif
905
906                         buffer = sc->sc_rx_act;
907                         /* look if buffer is marked invalid: */
908                         if (GETMEM(buffer*512) == 0) {
909                                 /*
910                                  * invalid marked buffer (or illegally
911                                  * configured sender)
912                                  */
913                                 log(LOG_WARNING,
914                                     "%s%d: spurious RX interupt or sender 0 "
915                                     " (ignored)\n", ifp->if_name, ifp->if_unit);
916                                 /*
917                                  * restart receiver on same buffer.
918                                  * XXX maybe better reset interface?
919                                  */
920                                 PUTREG(CMCMD, CM_RXBC(buffer));
921                         } else {
922                                 if (++sc->sc_rx_fillcount > 1) {
923                                         sc->sc_intmask &= ~CM_RI;
924                                         PUTREG(CMSTAT, sc->sc_intmask);
925                                 } else {
926                                         buffer ^= 1;
927                                         sc->sc_rx_act = buffer;
928
929                                         /*
930                                          * Start receiver on other receive
931                                          * buffer. This also clears the RI
932                                          * interupt flag.
933                                          */
934                                         PUTREG(CMCMD, CM_RXBC(buffer));
935                                         /* in RX intr, so mask is ok for RX */
936
937 #ifdef CM_DEBUG
938                                         if_printf(ifp, "strt rx for buf %d, "
939                                             "stat 0x%02x\n",
940                                             sc->sc_rx_act, GETREG(CMSTAT));
941 #endif
942                                 }
943
944 #ifdef CMSOFTCOPY
945                                 /*
946                                  * this one starts a soft int to copy out
947                                  * of the hw
948                                  */
949                                 softintr_schedule(sc->sc_rxcookie);
950 #else
951                                 /* this one does the copy here */
952                                 cm_srint(sc);
953 #endif
954                         }
955                 }
956                 if (maskedisr & CM_TA) {
957                         cm_tint(sc, isr);
958                 }
959                 isr = GETREG(CMSTAT);
960                 maskedisr = isr & sc->sc_intmask;
961         } while (maskedisr);
962 #if defined(CM_DEBUG) && (CM_DEBUG>1)
963         if_printf(ifp, "intr (exit): status 0x%02x, intmask 0x%02x\n",
964             isr, sc->sc_intmask);
965 #endif
966 }
967
968 void
969 cm_reconwatch(arg)
970         void *arg;
971 {
972         struct cm_softc *sc = arg;
973         struct ifnet *ifp = &sc->sc_arccom.ac_if;
974
975         if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) {
976                 sc->sc_reconcount = 0;
977                 log(LOG_WARNING, "%s%d: token valid again.\n",
978                     ifp->if_name, ifp->if_unit);
979         }
980         sc->sc_reconcount = 0;
981 }
982
983
984 /*
985  * Process an ioctl request.
986  * This code needs some work - it looks pretty ugly.
987  */
988 int
989 cm_ioctl(ifp, command, data)
990         struct ifnet *ifp;
991         u_long command;
992         caddr_t data;
993 {
994         struct cm_softc *sc;
995         struct ifaddr *ifa;
996         struct ifreq *ifr;
997         int s, error;
998
999         error = 0;
1000         sc = ifp->if_softc;
1001         ifa = (struct ifaddr *)data;
1002         ifr = (struct ifreq *)data;
1003         s = splimp();
1004
1005 #if defined(CM_DEBUG) && (CM_DEBUG > 2)
1006         if_printf(ifp, "ioctl() called, cmd = 0x%lx\n", command);
1007 #endif
1008
1009         switch (command) {
1010         case SIOCSIFADDR:
1011         case SIOCADDMULTI:
1012         case SIOCDELMULTI:
1013         case SIOCSIFMTU:
1014                 error = arc_ioctl(ifp, command, data);
1015                 break;
1016
1017         case SIOCSIFFLAGS:
1018                 if ((ifp->if_flags & IFF_UP) == 0 &&
1019                     (ifp->if_flags & IFF_RUNNING) != 0) {
1020                         /*
1021                          * If interface is marked down and it is running,
1022                          * then stop it.
1023                          */
1024                         cm_stop(sc);
1025                         ifp->if_flags &= ~IFF_RUNNING;
1026                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
1027                            (ifp->if_flags & IFF_RUNNING) == 0) {
1028                         /*
1029                          * If interface is marked up and it is stopped, then
1030                          * start it.
1031                          */
1032                         cm_init(sc);
1033                 }
1034                 break;
1035
1036         default:
1037                 error = EINVAL;
1038                 break;
1039         }
1040
1041         splx(s);
1042         return (error);
1043 }
1044
1045 /*
1046  * watchdog routine for transmitter.
1047  *
1048  * We need this, because else a receiver whose hardware is alive, but whose
1049  * software has not enabled the Receiver, would make our hardware wait forever
1050  * Discovered this after 20 times reading the docs.
1051  *
1052  * Only thing we do is disable transmitter. We'll get an transmit timeout,
1053  * and the int handler will have to decide not to retransmit (in case
1054  * retransmission is implemented).
1055  *
1056  * This one assumes being called inside splimp()
1057  */
1058
1059 void
1060 cm_watchdog(ifp)
1061         struct ifnet *ifp;
1062 {
1063         struct cm_softc *sc = ifp->if_softc;
1064
1065         PUTREG(CMCMD, CM_TXDIS);
1066         return;
1067 }