1 /* $NetBSD: smc90cx6.c,v 1.27 1998/10/20 22:18:13 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 #define 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_rxcookie = softintr_establish(IPL_SOFTNET, bah_srint, sc); 215 sc->sc_txcookie = softintr_establish(IPL_SOFTNET, 216 (void (*) __P((void *)))bah_start, ifp); 217 #endif 218 219 } 220 221 /* 222 * Initialize device 223 * 224 */ 225 void 226 bah_init(sc) 227 struct bah_softc *sc; 228 { 229 struct ifnet *ifp; 230 int s; 231 232 ifp = &sc->sc_arccom.ac_if; 233 234 if ((ifp->if_flags & IFF_RUNNING) == 0) { 235 s = splnet(); 236 ifp->if_flags |= IFF_RUNNING; 237 bah_reset(sc); 238 bah_start(ifp); 239 splx(s); 240 } 241 } 242 243 /* 244 * Reset the interface... 245 * 246 * this assumes that it is called inside a critical section... 247 * 248 */ 249 void 250 bah_reset(sc) 251 struct bah_softc *sc; 252 { 253 struct ifnet *ifp; 254 int linkaddress; 255 256 bus_space_tag_t bst_r = sc->sc_bst_r; 257 bus_space_tag_t bst_m = sc->sc_bst_m; 258 bus_space_handle_t regs = sc->sc_regs; 259 bus_space_handle_t mem = sc->sc_mem; 260 261 ifp = &sc->sc_arccom.ac_if; 262 263 #ifdef BAH_DEBUG 264 printf("%s: reset\n", sc->sc_dev.dv_xname); 265 #endif 266 /* stop and restart hardware */ 267 268 (*sc->sc_reset)(sc, 1); 269 do { 270 DELAY(200); 271 } while (!(GETREG(BAHSTAT) & BAH_POR)); 272 273 linkaddress = GETMEM(BAHMACOFF); 274 275 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2) 276 printf("%s: reset: card reset, link addr = 0x%02x (%ld)\n", 277 sc->sc_dev.dv_xname, linkaddress, linkaddress); 278 #endif 279 280 /* tell the routing level about the (possibly changed) link address */ 281 arc_ifattach(ifp, linkaddress); 282 283 /* POR is NMI, but we need it below: */ 284 sc->sc_intmask = BAH_RECON|BAH_POR; 285 PUTREG(BAHSTAT, sc->sc_intmask); 286 PUTREG(BAHCMD, BAH_CONF(CONF_LONG)); 287 288 #ifdef BAH_DEBUG 289 printf("%s: reset: chip configured, status=0x%02x\n", 290 sc->sc_dev.dv_xname, GETREG(BAHSTAT)); 291 #endif 292 PUTREG(BAHCMD, BAH_CLR(CLR_POR|CLR_RECONFIG)); 293 294 #ifdef BAH_DEBUG 295 printf("%s: reset: bits cleared, status=0x%02x\n", 296 sc->sc_dev.dv_xname, GETREG(BAHSTAT); 297 #endif 298 299 sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; 300 301 /* start receiver */ 302 303 sc->sc_intmask |= BAH_RI; 304 sc->sc_rx_fillcount = 0; 305 sc->sc_rx_act = 2; 306 307 PUTREG(BAHCMD, BAH_RXBC(2)); 308 PUTREG(BAHSTAT, sc->sc_intmask); 309 310 #ifdef BAH_DEBUG 311 printf("%s: reset: started receiver, status=0x%02x\n", 312 sc->sc_dev.dv_xname, GETREG(BAHSTAT); 313 #endif 314 315 /* and init transmitter status */ 316 sc->sc_tx_act = 0; 317 sc->sc_tx_fillcount = 0; 318 319 ifp->if_flags |= IFF_RUNNING; 320 ifp->if_flags &= ~IFF_OACTIVE; 321 322 bah_start(ifp); 323 } 324 325 /* 326 * Take interface offline 327 */ 328 void 329 bah_stop(sc) 330 struct bah_softc *sc; 331 { 332 bus_space_tag_t bst_r = sc->sc_bst_r; 333 bus_space_handle_t regs = sc->sc_regs; 334 335 /* Stop the interrupts */ 336 PUTREG(BAHSTAT, 0); 337 338 /* Stop the interface */ 339 (*sc->sc_reset)(sc, 0); 340 341 /* Stop watchdog timer */ 342 sc->sc_arccom.ac_if.if_timer = 0; 343 } 344 345 /* 346 * Start output on interface. Get another datagram to send 347 * off the interface queue, and copy it to the 348 * interface becore starting the output 349 * 350 * this assumes that it is called inside a critical section... 351 * XXX hm... does it still? 352 * 353 */ 354 void 355 bah_start(ifp) 356 struct ifnet *ifp; 357 { 358 struct bah_softc *sc = ifp->if_softc; 359 struct mbuf *m,*mp; 360 361 bus_space_tag_t bst_r = sc->sc_bst_r; 362 bus_space_handle_t regs = sc->sc_regs; 363 bus_space_tag_t bst_m = sc->sc_bst_m; 364 bus_space_handle_t mem = sc->sc_mem; 365 366 int bah_ram_ptr; 367 int len, tlen, offset, s, buffer; 368 #ifdef BAHTIMINGS 369 u_long copystart, lencopy, perbyte; 370 #endif 371 372 #if defined(BAH_DEBUG) && (BAH_DEBUG > 3) 373 printf("%s: start(0x%x)\n", sc->sc_dev.dv_xname, ifp); 374 #endif 375 376 if ((ifp->if_flags & IFF_RUNNING) == 0) 377 return; 378 379 s = splnet(); 380 381 if (sc->sc_tx_fillcount >= 2) { 382 splx(s); 383 return; 384 } 385 386 IF_DEQUEUE(&ifp->if_snd, m); 387 buffer = sc->sc_tx_act ^ 1; 388 389 splx(s); 390 391 if (m == 0) 392 return; 393 394 #if NBPFILTER > 0 395 /* 396 * If bpf is listening on this interface, let it 397 * see the packet before we commit it to the wire 398 * 399 * (can't give the copy in A2060 card RAM to bpf, because 400 * that RAM is just accessed as on every other byte) 401 */ 402 if (ifp->if_bpf) 403 bpf_mtap(ifp->if_bpf, m); 404 #endif 405 406 #ifdef BAH_DEBUG 407 m = m_pullup(m, 3); /* gcc does structure padding */ 408 printf("%s: start: filling %ld from %ld to %ld type %ld\n", 409 sc->sc_dev.dv_xname, buffer, mtod(m, u_char *)[0], 410 mtod(m, u_char *)[1], mtod(m, u_char *)[2]); 411 #else 412 m = m_pullup(m, 2); 413 #endif 414 bah_ram_ptr = buffer*512; 415 416 /* write the addresses to RAM and throw them away */ 417 418 /* 419 * Hardware does this: Yet Another Microsecond Saved. 420 * (btw, timing code says usually 2 microseconds) 421 * PUTMEM(bah_ram_ptr + 0, mtod(m, u_char *)[0]); 422 */ 423 424 PUTMEM(bah_ram_ptr + 1, mtod(m, u_char *)[1]); 425 m_adj(m, 2); 426 427 /* get total length left at this point */ 428 tlen = m->m_pkthdr.len; 429 if (tlen < ARC_MIN_FORBID_LEN) { 430 offset = 256 - tlen; 431 PUTMEM(bah_ram_ptr + 2, offset); 432 } else { 433 PUTMEM(bah_ram_ptr + 2, 0); 434 if (tlen <= ARC_MAX_FORBID_LEN) 435 offset = 255; /* !!! */ 436 else { 437 if (tlen > ARC_MAX_LEN) 438 tlen = ARC_MAX_LEN; 439 offset = 512 - tlen; 440 } 441 PUTMEM(bah_ram_ptr + 3, offset); 442 443 } 444 bah_ram_ptr += offset; 445 446 /* lets loop through the mbuf chain */ 447 448 for (mp = m; mp; mp = mp->m_next) { 449 if ((len = mp->m_len)) { /* YAMS */ 450 bus_space_write_region_1(bst_m, mem, bah_ram_ptr, 451 mtod(mp, caddr_t), len); 452 453 bah_ram_ptr += len; 454 } 455 } 456 457 sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0; 458 sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5; 459 460 /* actually transmit the packet */ 461 s = splnet(); 462 463 if (++sc->sc_tx_fillcount > 1) { 464 /* 465 * We are filled up to the rim. No more bufs for the moment, 466 * please. 467 */ 468 ifp->if_flags |= IFF_OACTIVE; 469 } else { 470 #ifdef BAH_DEBUG 471 printf("%s: start: starting transmitter on buffer %d\n", 472 sc->sc_dev.dv_xname, buffer); 473 #endif 474 /* Transmitter was off, start it */ 475 sc->sc_tx_act = buffer; 476 477 /* 478 * We still can accept another buf, so don't: 479 * ifp->if_flags |= IFF_OACTIVE; 480 */ 481 sc->sc_intmask |= BAH_TA; 482 PUTREG(BAHCMD, BAH_TX(buffer)); 483 PUTREG(BAHSTAT, sc->sc_intmask); 484 485 sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT; 486 } 487 splx(s); 488 m_freem(m); 489 490 /* 491 * After 10 times reading the docs, I realized 492 * that in the case the receiver NAKs the buffer request, 493 * the hardware retries till shutdown. 494 * This is integrated now in the code above. 495 */ 496 497 return; 498 } 499 500 /* 501 * Arcnet interface receiver soft interrupt: 502 * get the stuff out of any filled buffer we find. 503 */ 504 void 505 bah_srint(vsc) 506 void *vsc; 507 { 508 struct bah_softc *sc = (struct bah_softc *)vsc; 509 int buffer, len, len1, amount, offset, s, type; 510 int bah_ram_ptr; 511 struct mbuf *m, *dst, *head; 512 struct arc_header *ah; 513 struct ifnet *ifp; 514 515 bus_space_tag_t bst_r = sc->sc_bst_r; 516 bus_space_tag_t bst_m = sc->sc_bst_m; 517 bus_space_handle_t regs = sc->sc_regs; 518 bus_space_handle_t mem = sc->sc_mem; 519 520 ifp = &sc->sc_arccom.ac_if; 521 head = 0; 522 523 s = splnet(); 524 buffer = sc->sc_rx_act ^ 1; 525 splx(s); 526 527 /* Allocate header mbuf */ 528 MGETHDR(m, M_DONTWAIT, MT_DATA); 529 530 if (m == 0) { 531 /* 532 * in case s.th. goes wrong with mem, drop it 533 * to make sure the receiver can be started again 534 * count it as input error (we dont have any other 535 * detectable) 536 */ 537 ifp->if_ierrors++; 538 goto cleanup; 539 } 540 541 m->m_pkthdr.rcvif = ifp; 542 543 /* 544 * Align so that IP packet will be longword aligned. Here we 545 * assume that m_data of new packet is longword aligned. 546 * When implementing PHDS, we might have to change it to 2, 547 * (2*sizeof(ulong) - ARC_HDRNEWLEN)), packet type dependent. 548 */ 549 550 bah_ram_ptr = buffer*512; 551 offset = GETMEM(bah_ram_ptr + 2); 552 if (offset) 553 len = 256 - offset; 554 else { 555 offset = GETMEM(bah_ram_ptr + 3); 556 len = 512 - offset; 557 } 558 type = GETMEM(bah_ram_ptr + offset); 559 m->m_data += 1 + arc_isphds(type); 560 561 head = m; 562 ah = mtod(head, struct arc_header *); 563 564 ah->arc_shost = GETMEM(bah_ram_ptr + 0); 565 ah->arc_dhost = GETMEM(bah_ram_ptr + 1); 566 567 m->m_pkthdr.len = len+2; /* whole packet length */ 568 m->m_len = 2; /* mbuf filled with ARCnet addresses */ 569 bah_ram_ptr += offset; /* ram buffer continues there */ 570 571 while (len > 0) { 572 573 len1 = len; 574 amount = M_TRAILINGSPACE(m); 575 576 if (amount == 0) { 577 dst = m; 578 MGET(m, M_DONTWAIT, MT_DATA); 579 580 if (m == 0) { 581 ifp->if_ierrors++; 582 goto cleanup; 583 } 584 585 if (len1 >= MINCLSIZE) 586 MCLGET(m, M_DONTWAIT); 587 588 m->m_len = 0; 589 dst->m_next = m; 590 amount = M_TRAILINGSPACE(m); 591 } 592 593 if (amount < len1) 594 len1 = amount; 595 596 bus_space_read_region_1(bst_m, mem, bah_ram_ptr, 597 mtod(m, u_char *) + m->m_len, len1); 598 599 m->m_len += len1; 600 bah_ram_ptr += len1; 601 len -= len1; 602 } 603 604 #if NBPFILTER > 0 605 if (ifp->if_bpf) 606 bpf_mtap(ifp->if_bpf, head); 607 #endif 608 609 arc_input(&sc->sc_arccom.ac_if, head); 610 611 /* arc_input has freed it, we dont need to... */ 612 613 head = NULL; 614 ifp->if_ipackets++; 615 616 cleanup: 617 618 if (head != NULL) 619 m_freem(head); 620 621 /* mark buffer as invalid by source id 0 */ 622 bus_space_write_1(bst_m, mem, buffer*512, 0); 623 s = splnet(); 624 625 if (--sc->sc_rx_fillcount == 2 - 1) { 626 627 /* was off, restart it on buffer just emptied */ 628 sc->sc_rx_act = buffer; 629 sc->sc_intmask |= BAH_RI; 630 631 /* this also clears the RI flag interupt: */ 632 PUTREG(BAHCMD, BAH_RXBC(buffer)); 633 PUTREG(BAHSTAT, sc->sc_intmask); 634 635 #ifdef BAH_DEBUG 636 printf("%s: srint: restarted rx on buf %ld\n", 637 sc->sc_dev.dv_xname, buffer); 638 #endif 639 } 640 splx(s); 641 } 642 643 __inline static void 644 bah_tint(sc, isr) 645 struct bah_softc *sc; 646 int isr; 647 { 648 struct ifnet *ifp; 649 650 bus_space_tag_t bst_r = sc->sc_bst_r; 651 bus_space_handle_t regs = sc->sc_regs; 652 653 654 int buffer; 655 #ifdef BAHTIMINGS 656 int clknow; 657 #endif 658 659 ifp = &(sc->sc_arccom.ac_if); 660 buffer = sc->sc_tx_act; 661 662 /* 663 * retransmit code: 664 * Normal situtations first for fast path: 665 * If acknowledgement received ok or broadcast, we're ok. 666 * else if 667 */ 668 669 if (isr & BAH_TMA || sc->sc_broadcast[buffer]) 670 sc->sc_arccom.ac_if.if_opackets++; 671 #ifdef BAHRETRANSMIT 672 else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0 673 && --sc->sc_retransmits[buffer] > 0) { 674 /* retransmit same buffer */ 675 PUTREG(BAHCMD, BAH_TX(buffer)); 676 return; 677 } 678 #endif 679 else 680 ifp->if_oerrors++; 681 682 683 /* We know we can accept another buffer at this point. */ 684 ifp->if_flags &= ~IFF_OACTIVE; 685 686 if (--sc->sc_tx_fillcount > 0) { 687 688 /* 689 * start tx on other buffer. 690 * This also clears the int flag 691 */ 692 buffer ^= 1; 693 sc->sc_tx_act = buffer; 694 695 /* 696 * already given: 697 * sc->sc_intmask |= BAH_TA; 698 * PUTREG(BAHSTAT, sc->sc_intmask); 699 */ 700 PUTREG(BAHCMD, BAH_TX(buffer)); 701 /* init watchdog timer */ 702 ifp->if_timer = ARCTIMEOUT; 703 704 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1) 705 printf("%s: tint: starting tx on buffer %d, status 0x%02x\n", 706 sc->sc_dev.dv_xname, buffer, GETREG(BAHSTAT)); 707 #endif 708 } else { 709 /* have to disable TX interrupt */ 710 sc->sc_intmask &= ~BAH_TA; 711 PUTREG(BAHSTAT, sc->sc_intmask); 712 /* ... and watchdog timer */ 713 ifp->if_timer = 0; 714 715 #ifdef BAH_DEBUG 716 printf("%s: tint: no more buffers to send, status 0x%02x\n", 717 sc->sc_dev.dv_xname, GETREG(BAHSTAT)); 718 #endif 719 } 720 721 /* XXXX TODO */ 722 #ifdef BAHSOFTCOPY 723 /* schedule soft int to fill a new buffer for us */ 724 softintr_schedule(sc->sc_txcookie); 725 #else 726 /* call it directly */ 727 bah_start(ifp); 728 #endif 729 } 730 731 /* 732 * Our interrupt routine 733 */ 734 int 735 bahintr(arg) 736 void *arg; 737 { 738 struct bah_softc *sc = arg; 739 740 bus_space_tag_t bst_r = sc->sc_bst_r; 741 bus_space_tag_t bst_m = sc->sc_bst_m; 742 bus_space_handle_t regs = sc->sc_regs; 743 bus_space_handle_t mem = sc->sc_mem; 744 745 u_char isr, maskedisr; 746 int buffer; 747 u_long newsec; 748 749 isr = GETREG(BAHSTAT); 750 maskedisr = isr & sc->sc_intmask; 751 if (!maskedisr) 752 return (0); 753 do { 754 755 #if defined(BAH_DEBUG) && (BAH_DEBUG>1) 756 printf("%s: intr: status 0x%02x, intmask 0x%02x\n", 757 sc->sc_dev.dv_xname, isr, sc->sc_intmask); 758 #endif 759 760 if (maskedisr & BAH_POR) { 761 /* 762 * XXX We should never see this. Don't bother to store 763 * the address. 764 * sc->sc_arccom.ac_anaddr = GETMEM(BAHMACOFF); 765 */ 766 PUTREG(BAHCMD, BAH_CLR(CLR_POR)); 767 log(LOG_WARNING, 768 "%s: intr: got spurious power on reset int\n", 769 sc->sc_dev.dv_xname); 770 } 771 772 if (maskedisr & BAH_RECON) { 773 /* 774 * we dont need to: 775 * PUTREG(BAHCMD, BAH_CONF(CONF_LONG)); 776 */ 777 PUTREG(BAHCMD, BAH_CLR(CLR_RECONFIG)); 778 sc->sc_arccom.ac_if.if_collisions++; 779 780 /* 781 * If less than 2 seconds per reconfig: 782 * If ARC_EXCESSIVE_RECONFIGS 783 * since last burst, complain and set treshold for 784 * warnings to ARC_EXCESSIVE_RECONS_REWARN. 785 * 786 * This allows for, e.g., new stations on the cable, or 787 * cable switching as long as it is over after 788 * (normally) 16 seconds. 789 * 790 * XXX TODO: check timeout bits in status word and 791 * double time if necessary. 792 */ 793 794 untimeout(bah_reconwatch, (void *)sc); 795 newsec = time.tv_sec; 796 if ((newsec - sc->sc_recontime <= 2) && 797 (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) { 798 log(LOG_WARNING, 799 "%s: excessive token losses, " 800 "cable problem?\n", sc->sc_dev.dv_xname); 801 } 802 sc->sc_recontime = newsec; 803 timeout(bah_reconwatch, (void *)sc, 15*hz); 804 } 805 806 if (maskedisr & BAH_RI) { 807 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1) 808 printf("%s: intr: hard rint, act %ld\n", 809 sc->sc_dev.dv_xname, sc->sc_rx_act); 810 #endif 811 812 buffer = sc->sc_rx_act; 813 /* look if buffer is marked invalid: */ 814 if (GETMEM(buffer*512) == 0) { 815 /* 816 * invalid marked buffer (or illegally 817 * configured sender) 818 */ 819 log(LOG_WARNING, 820 "%s: spurious RX interupt or sender 0 " 821 " (ignored)\n", sc->sc_dev.dv_xname); 822 /* 823 * restart receiver on same buffer. 824 * XXX maybe better reset interface? 825 */ 826 PUTREG(BAHCMD, BAH_RXBC(buffer)); 827 } else { 828 if (++sc->sc_rx_fillcount > 1) { 829 sc->sc_intmask &= ~BAH_RI; 830 PUTREG(BAHSTAT, sc->sc_intmask); 831 } else { 832 buffer ^= 1; 833 sc->sc_rx_act = buffer; 834 835 /* 836 * Start receiver on other receive 837 * buffer. This also clears the RI 838 * interupt flag. 839 */ 840 PUTREG(BAHCMD, BAH_RXBC(buffer)); 841 /* in RX intr, so mask is ok for RX */ 842 843 #ifdef BAH_DEBUG 844 printf("%s: strt rx for buf %ld, " 845 "stat 0x%02x\n", 846 sc->sc_dev.dv_xname, sc->sc_rx_act, 847 GETREG(BAHSTAT); 848 #endif 849 } 850 851 #ifdef BAHSOFTCOPY 852 /* 853 * this one starts a soft int to copy out 854 * of the hw 855 */ 856 softintr_schedule(sc->sc_rxcookie); 857 #else 858 /* this one does the copy here */ 859 bah_srint(sc); 860 #endif 861 } 862 } 863 if (maskedisr & BAH_TA) { 864 bah_tint(sc, isr); 865 } 866 isr = GETREG(BAHSTAT); 867 maskedisr = isr & sc->sc_intmask; 868 } while (maskedisr); 869 870 return (1); 871 } 872 873 void 874 bah_reconwatch(arg) 875 void *arg; 876 { 877 struct bah_softc *sc = arg; 878 879 if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) { 880 sc->sc_reconcount = 0; 881 log(LOG_WARNING, "%s: token valid again.\n", 882 sc->sc_dev.dv_xname); 883 } 884 sc->sc_reconcount = 0; 885 } 886 887 888 /* 889 * Process an ioctl request. 890 * This code needs some work - it looks pretty ugly. 891 */ 892 int 893 bah_ioctl(ifp, command, data) 894 register struct ifnet *ifp; 895 u_long command; 896 caddr_t data; 897 { 898 struct bah_softc *sc; 899 register struct ifaddr *ifa; 900 struct ifreq *ifr; 901 int s, error; 902 903 error = 0; 904 sc = ifp->if_softc; 905 ifa = (struct ifaddr *)data; 906 ifr = (struct ifreq *)data; 907 s = splnet(); 908 909 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2) 910 printf("%s: ioctl() called, cmd = 0x%x\n", 911 sc->sc_dev.dv_xname, command); 912 #endif 913 914 switch (command) { 915 case SIOCSIFADDR: 916 ifp->if_flags |= IFF_UP; 917 switch (ifa->ifa_addr->sa_family) { 918 #ifdef INET 919 case AF_INET: 920 bah_init(sc); 921 arp_ifinit(ifp, ifa); 922 break; 923 #endif 924 default: 925 bah_init(sc); 926 break; 927 } 928 929 case SIOCSIFFLAGS: 930 if ((ifp->if_flags & IFF_UP) == 0 && 931 (ifp->if_flags & IFF_RUNNING) != 0) { 932 /* 933 * If interface is marked down and it is running, 934 * then stop it. 935 */ 936 bah_stop(sc); 937 ifp->if_flags &= ~IFF_RUNNING; 938 } else if ((ifp->if_flags & IFF_UP) != 0 && 939 (ifp->if_flags & IFF_RUNNING) == 0) { 940 /* 941 * If interface is marked up and it is stopped, then 942 * start it. 943 */ 944 bah_init(sc); 945 } 946 break; 947 948 case SIOCADDMULTI: 949 case SIOCDELMULTI: 950 if (ifr->ifr_addr.sa_family == AF_INET) 951 error = 0; 952 else 953 error = EAFNOSUPPORT; 954 break; 955 956 default: 957 error = EINVAL; 958 } 959 960 splx(s); 961 return (error); 962 } 963 964 /* 965 * watchdog routine for transmitter. 966 * 967 * We need this, because else a receiver whose hardware is alive, but whose 968 * software has not enabled the Receiver, would make our hardware wait forever 969 * Discovered this after 20 times reading the docs. 970 * 971 * Only thing we do is disable transmitter. We'll get an transmit timeout, 972 * and the int handler will have to decide not to retransmit (in case 973 * retransmission is implemented). 974 * 975 * This one assumes being called inside splnet() 976 */ 977 978 void 979 bah_watchdog(ifp) 980 struct ifnet *ifp; 981 { 982 struct bah_softc *sc = ifp->if_softc; 983 984 bus_space_tag_t bst_r = sc->sc_bst_r; 985 bus_space_handle_t regs = sc->sc_regs; 986 987 PUTREG(BAHCMD, BAH_TXDIS); 988 return; 989 } 990 991