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