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