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