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