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