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