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