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