smc90cx6.c revision 199559
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 199559 2009-11-19 22:06:40Z jhb $"); 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(void *); 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_release_resource(dev, SYS_RES_IOPORT, 143 0, sc->port_res); 144 sc->port_res = NULL; 145 } 146 if (sc->mem_res != NULL) { 147 bus_release_resource(dev, SYS_RES_MEMORY, 148 0, sc->mem_res); 149 sc->mem_res = NULL; 150 } 151 if (sc->irq_res != NULL) { 152 bus_release_resource(dev, SYS_RES_IRQ, 153 0, sc->irq_res); 154 sc->irq_res = NULL; 155 } 156} 157 158int 159cm_attach(dev) 160 device_t dev; 161{ 162 struct cm_softc *sc = device_get_softc(dev); 163 struct ifnet *ifp; 164 u_int8_t linkaddress; 165 166 ifp = sc->sc_ifp = if_alloc(IFT_ARCNET); 167 if (ifp == NULL) 168 return (ENOSPC); 169 170 /* 171 * read the arcnet address from the board 172 */ 173 GETREG(CMRESET); 174 do { 175 DELAY(200); 176 } while (!(GETREG(CMSTAT) & CM_POR)); 177 linkaddress = GETMEM(CMMACOFF); 178 179 /* clear the int mask... */ 180 sc->sc_intmask = 0; 181 PUTREG(CMSTAT, 0); 182 183 PUTREG(CMCMD, CM_CONF(CONF_LONG)); 184 PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG)); 185 sc->sc_recontime = sc->sc_reconcount = 0; 186 187 /* 188 * set interface to stopped condition (reset) 189 */ 190 cm_stop_locked(sc); 191 192 ifp->if_softc = sc; 193 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 194 ifp->if_output = arc_output; 195 ifp->if_start = cm_start; 196 ifp->if_ioctl = cm_ioctl; 197 ifp->if_init = cm_init; 198 /* XXX IFQ_SET_READY(&ifp->if_snd); */ 199 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 200 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 201 202 arc_ifattach(ifp, linkaddress); 203 204#ifdef CMSOFTCOPY 205 sc->sc_rxcookie = softintr_establish(IPL_SOFTNET, cm_srint, sc); 206 sc->sc_txcookie = softintr_establish(IPL_SOFTNET, 207 (void (*)(void *))cm_start, ifp); 208#endif 209 210 callout_init_mtx(&sc->sc_recon_ch, &sc->sc_mtx, 0); 211 callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); 212 213 if_printf(ifp, "link addr 0x%02x (%d)\n", linkaddress, linkaddress); 214 return 0; 215} 216 217/* 218 * Initialize device 219 * 220 */ 221void 222cm_init(xsc) 223 void *xsc; 224{ 225 struct cm_softc *sc = (struct cm_softc *)xsc; 226 227 CM_LOCK(sc); 228 cm_init_locked(sc); 229 CM_UNLOCK(sc); 230} 231 232static void 233cm_init_locked(struct cm_softc *sc) 234{ 235 struct ifnet *ifp = sc->sc_ifp; 236 237 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 238 ifp->if_drv_flags |= IFF_DRV_RUNNING; 239 cm_reset_locked(sc); 240 } 241} 242 243/* 244 * Reset the interface... 245 * 246 * Assumes that it is called with sc_mtx held 247 */ 248void 249cm_reset_locked(sc) 250 struct cm_softc *sc; 251{ 252 struct ifnet *ifp; 253 int linkaddress; 254 255 ifp = sc->sc_ifp; 256 257#ifdef CM_DEBUG 258 if_printf(ifp, "reset\n"); 259#endif 260 /* stop and restart hardware */ 261 262 GETREG(CMRESET); 263 do { 264 DELAY(200); 265 } while (!(GETREG(CMSTAT) & CM_POR)); 266 267 linkaddress = GETMEM(CMMACOFF); 268 269#if defined(CM_DEBUG) && (CM_DEBUG > 2) 270 if_printf(ifp, "reset: card reset, link addr = 0x%02x (%d)\n", 271 linkaddress, linkaddress); 272#endif 273 274 /* tell the routing level about the (possibly changed) link address */ 275 arc_storelladdr(ifp, linkaddress); 276 arc_frag_init(ifp); 277 278 /* POR is NMI, but we need it below: */ 279 sc->sc_intmask = CM_RECON|CM_POR; 280 PUTREG(CMSTAT, sc->sc_intmask); 281 PUTREG(CMCMD, CM_CONF(CONF_LONG)); 282 283#ifdef CM_DEBUG 284 if_printf(ifp, "reset: chip configured, status=0x%02x\n", 285 GETREG(CMSTAT)); 286#endif 287 PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG)); 288 289#ifdef CM_DEBUG 290 if_printf(ifp, "reset: bits cleared, status=0x%02x\n", 291 GETREG(CMSTAT)); 292#endif 293 294 sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; 295 296 /* start receiver */ 297 298 sc->sc_intmask |= CM_RI; 299 sc->sc_rx_fillcount = 0; 300 sc->sc_rx_act = 2; 301 302 PUTREG(CMCMD, CM_RXBC(2)); 303 PUTREG(CMSTAT, sc->sc_intmask); 304 305#ifdef CM_DEBUG 306 if_printf(ifp, "reset: started receiver, status=0x%02x\n", 307 GETREG(CMSTAT)); 308#endif 309 310 /* and init transmitter status */ 311 sc->sc_tx_act = 0; 312 sc->sc_tx_fillcount = 0; 313 314 ifp->if_drv_flags |= IFF_DRV_RUNNING; 315 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 316 317 callout_reset(&sc->sc_watchdog_timer, hz, cm_watchdog, sc); 318 cm_start_locked(ifp); 319} 320 321/* 322 * Take interface offline 323 */ 324void 325cm_stop_locked(sc) 326 struct cm_softc *sc; 327{ 328 /* Stop the interrupts */ 329 PUTREG(CMSTAT, 0); 330 331 /* Stop the interface */ 332 GETREG(CMRESET); 333 334 /* Stop watchdog timer */ 335 callout_stop(&sc->sc_watchdog_timer); 336 sc->sc_timer = 0; 337} 338 339void 340cm_start(struct ifnet *ifp) 341{ 342 struct cm_softc *sc = ifp->if_softc; 343 344 CM_LOCK(sc); 345 cm_start_locked(ifp); 346 CM_UNLOCK(sc); 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 * Assumes that sc_mtx is held 355 */ 356void 357cm_start_locked(ifp) 358 struct ifnet *ifp; 359{ 360 struct cm_softc *sc = ifp->if_softc; 361 struct mbuf *m, *mp; 362 363 int cm_ram_ptr; 364 int len, tlen, offset, buffer; 365#ifdef CMTIMINGS 366 u_long copystart, lencopy, perbyte; 367#endif 368 369#if defined(CM_DEBUG) && (CM_DEBUG > 3) 370 if_printf(ifp, "start(%p)\n", ifp); 371#endif 372 373 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 374 return; 375 376 if (sc->sc_tx_fillcount >= 2) 377 return; 378 379 m = arc_frag_next(ifp); 380 buffer = sc->sc_tx_act ^ 1; 381 382 if (m == 0) 383 return; 384 385#ifdef CM_DEBUG 386 if (m->m_len < ARC_HDRLEN) 387 m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */ 388 if_printf(ifp, "start: filling %d from %d to %d type %d\n", 389 buffer, mtod(m, u_char *)[0], 390 mtod(m, u_char *)[1], mtod(m, u_char *)[2]); 391#else 392 if (m->m_len < 2) 393 m = m_pullup(m, 2); 394#endif 395 cm_ram_ptr = buffer * 512; 396 397 if (m == 0) 398 return; 399 400 /* write the addresses to RAM and throw them away */ 401 402 /* 403 * Hardware does this: Yet Another Microsecond Saved. 404 * (btw, timing code says usually 2 microseconds) 405 * PUTMEM(cm_ram_ptr + 0, mtod(m, u_char *)[0]); 406 */ 407 408 PUTMEM(cm_ram_ptr + 1, mtod(m, u_char *)[1]); 409 m_adj(m, 2); 410 411 /* get total length left at this point */ 412 tlen = m->m_pkthdr.len; 413 if (tlen < ARC_MIN_FORBID_LEN) { 414 offset = 256 - tlen; 415 PUTMEM(cm_ram_ptr + 2, offset); 416 } else { 417 PUTMEM(cm_ram_ptr + 2, 0); 418 if (tlen <= ARC_MAX_FORBID_LEN) 419 offset = 255; /* !!! */ 420 else { 421 if (tlen > ARC_MAX_LEN) 422 tlen = ARC_MAX_LEN; 423 offset = 512 - tlen; 424 } 425 PUTMEM(cm_ram_ptr + 3, offset); 426 427 } 428 cm_ram_ptr += offset; 429 430 /* lets loop through the mbuf chain */ 431 432 for (mp = m; mp; mp = mp->m_next) { 433 if ((len = mp->m_len)) { /* YAMS */ 434 bus_space_write_region_1( 435 rman_get_bustag(sc->mem_res), 436 rman_get_bushandle(sc->mem_res), 437 cm_ram_ptr, mtod(mp, caddr_t), len); 438 439 cm_ram_ptr += len; 440 } 441 } 442 443 sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0; 444 sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5; 445 446 if (++sc->sc_tx_fillcount > 1) { 447 /* 448 * We are filled up to the rim. No more bufs for the moment, 449 * please. 450 */ 451 ifp->if_drv_flags |= IFF_DRV_OACTIVE; 452 } else { 453#ifdef CM_DEBUG 454 if_printf(ifp, "start: starting transmitter on buffer %d\n", 455 buffer); 456#endif 457 /* Transmitter was off, start it */ 458 sc->sc_tx_act = buffer; 459 460 /* 461 * We still can accept another buf, so don't: 462 * ifp->if_drv_flags |= IFF_DRV_OACTIVE; 463 */ 464 sc->sc_intmask |= CM_TA; 465 PUTREG(CMCMD, CM_TX(buffer)); 466 PUTREG(CMSTAT, sc->sc_intmask); 467 468 sc->sc_timer = ARCTIMEOUT; 469 } 470 m_freem(m); 471 472 /* 473 * After 10 times reading the docs, I realized 474 * that in the case the receiver NAKs the buffer request, 475 * the hardware retries till shutdown. 476 * This is integrated now in the code above. 477 */ 478} 479 480#ifdef CMSOFTCOPY 481void 482cm_srint(void *vsc) 483{ 484 struct cm_softc *sc = (struct cm_softc *)vsc; 485 486 CM_LOCK(sc); 487 cm_srint_locked(vsc); 488 CM_UNLOCK(sc); 489} 490#endif 491 492/* 493 * Arcnet interface receiver soft interrupt: 494 * get the stuff out of any filled buffer we find. 495 */ 496void 497cm_srint_locked(vsc) 498 void *vsc; 499{ 500 struct cm_softc *sc = (struct cm_softc *)vsc; 501 int buffer, len, offset, type; 502 int cm_ram_ptr; 503 struct mbuf *m; 504 struct arc_header *ah; 505 struct ifnet *ifp; 506 507 ifp = sc->sc_ifp; 508 509 buffer = sc->sc_rx_act ^ 1; 510 511 /* Allocate header mbuf */ 512 MGETHDR(m, M_DONTWAIT, MT_DATA); 513 514 if (m == 0) { 515 /* 516 * in case s.th. goes wrong with mem, drop it 517 * to make sure the receiver can be started again 518 * count it as input error (we dont have any other 519 * detectable) 520 */ 521 ifp->if_ierrors++; 522 goto cleanup; 523 } 524 525 m->m_pkthdr.rcvif = ifp; 526 527 /* 528 * Align so that IP packet will be longword aligned. Here we 529 * assume that m_data of new packet is longword aligned. 530 * When implementing PHDS, we might have to change it to 2, 531 * (2*sizeof(ulong) - CM_HDRNEWLEN)), packet type dependent. 532 */ 533 534 cm_ram_ptr = buffer * 512; 535 offset = GETMEM(cm_ram_ptr + 2); 536 if (offset) 537 len = 256 - offset; 538 else { 539 offset = GETMEM(cm_ram_ptr + 3); 540 len = 512 - offset; 541 } 542 543 /* 544 * first +2 bytes for align fixup below 545 * second +2 bytes are for src/dst addresses 546 */ 547 if ((len + 2 + 2) > MHLEN) { 548 /* attach an mbuf cluster */ 549 MCLGET(m, M_DONTWAIT); 550 551 /* Insist on getting a cluster */ 552 if ((m->m_flags & M_EXT) == 0) { 553 ifp->if_ierrors++; 554 goto cleanup; 555 } 556 } 557 558 if (m == 0) { 559 ifp->if_ierrors++; 560 goto cleanup; 561 } 562 563 type = GETMEM(cm_ram_ptr + offset); 564 m->m_data += 1 + arc_isphds(type); 565 /* mbuf filled with ARCnet addresses */ 566 m->m_pkthdr.len = m->m_len = len + 2; 567 568 ah = mtod(m, struct arc_header *); 569 ah->arc_shost = GETMEM(cm_ram_ptr + 0); 570 ah->arc_dhost = GETMEM(cm_ram_ptr + 1); 571 572 bus_space_read_region_1( 573 rman_get_bustag(sc->mem_res), rman_get_bushandle(sc->mem_res), 574 cm_ram_ptr + offset, mtod(m, u_char *) + 2, len); 575 576 CM_UNLOCK(sc); 577 arc_input(ifp, m); 578 CM_LOCK(sc); 579 580 m = NULL; 581 ifp->if_ipackets++; 582 583cleanup: 584 585 if (m != NULL) 586 m_freem(m); 587 588 /* mark buffer as invalid by source id 0 */ 589 PUTMEM(buffer << 9, 0); 590 if (--sc->sc_rx_fillcount == 2 - 1) { 591 592 /* was off, restart it on buffer just emptied */ 593 sc->sc_rx_act = buffer; 594 sc->sc_intmask |= CM_RI; 595 596 /* this also clears the RI flag interrupt: */ 597 PUTREG(CMCMD, CM_RXBC(buffer)); 598 PUTREG(CMSTAT, sc->sc_intmask); 599 600#ifdef CM_DEBUG 601 if_printf(ifp, "srint: restarted rx on buf %d\n", buffer); 602#endif 603 } 604} 605 606__inline static void 607cm_tint_locked(sc, isr) 608 struct cm_softc *sc; 609 int isr; 610{ 611 struct ifnet *ifp; 612 613 int buffer; 614#ifdef CMTIMINGS 615 int clknow; 616#endif 617 618 ifp = sc->sc_ifp; 619 buffer = sc->sc_tx_act; 620 621 /* 622 * retransmit code: 623 * Normal situtations first for fast path: 624 * If acknowledgement received ok or broadcast, we're ok. 625 * else if 626 */ 627 628 if (isr & CM_TMA || sc->sc_broadcast[buffer]) 629 ifp->if_opackets++; 630#ifdef CMRETRANSMIT 631 else if (ifp->if_flags & IFF_LINK2 && sc->sc_timer > 0 632 && --sc->sc_retransmits[buffer] > 0) { 633 /* retransmit same buffer */ 634 PUTREG(CMCMD, CM_TX(buffer)); 635 return; 636 } 637#endif 638 else 639 ifp->if_oerrors++; 640 641 642 /* We know we can accept another buffer at this point. */ 643 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 644 645 if (--sc->sc_tx_fillcount > 0) { 646 647 /* 648 * start tx on other buffer. 649 * This also clears the int flag 650 */ 651 buffer ^= 1; 652 sc->sc_tx_act = buffer; 653 654 /* 655 * already given: 656 * sc->sc_intmask |= CM_TA; 657 * PUTREG(CMSTAT, sc->sc_intmask); 658 */ 659 PUTREG(CMCMD, CM_TX(buffer)); 660 /* init watchdog timer */ 661 sc->sc_timer = ARCTIMEOUT; 662 663#if defined(CM_DEBUG) && (CM_DEBUG > 1) 664 if_printf(ifp, 665 "tint: starting tx on buffer %d, status 0x%02x\n", 666 buffer, GETREG(CMSTAT)); 667#endif 668 } else { 669 /* have to disable TX interrupt */ 670 sc->sc_intmask &= ~CM_TA; 671 PUTREG(CMSTAT, sc->sc_intmask); 672 /* ... and watchdog timer */ 673 sc->sc_timer = 0; 674 675#ifdef CM_DEBUG 676 if_printf(ifp, "tint: no more buffers to send, status 0x%02x\n", 677 GETREG(CMSTAT)); 678#endif 679 } 680 681 /* XXXX TODO */ 682#ifdef CMSOFTCOPY 683 /* schedule soft int to fill a new buffer for us */ 684 softintr_schedule(sc->sc_txcookie); 685#else 686 /* call it directly */ 687 cm_start_locked(ifp); 688#endif 689} 690 691/* 692 * Our interrupt routine 693 */ 694void 695cmintr(arg) 696 void *arg; 697{ 698 struct cm_softc *sc = arg; 699 struct ifnet *ifp = sc->sc_ifp; 700 701 u_char isr, maskedisr; 702 int buffer; 703 u_long newsec; 704 705 CM_LOCK(sc); 706 707 isr = GETREG(CMSTAT); 708 maskedisr = isr & sc->sc_intmask; 709 if (!maskedisr || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 710 CM_UNLOCK(sc); 711 return; 712 } 713 714 do { 715 716#if defined(CM_DEBUG) && (CM_DEBUG > 1) 717 if_printf(ifp, "intr: status 0x%02x, intmask 0x%02x\n", 718 isr, sc->sc_intmask); 719#endif 720 721 if (maskedisr & CM_POR) { 722 /* 723 * XXX We should never see this. Don't bother to store 724 * the address. 725 * sc->sc_ifp->if_l2com->ac_anaddr = GETMEM(CMMACOFF); 726 */ 727 PUTREG(CMCMD, CM_CLR(CLR_POR)); 728 log(LOG_WARNING, 729 "%s: intr: got spurious power on reset int\n", 730 ifp->if_xname); 731 } 732 733 if (maskedisr & CM_RECON) { 734 /* 735 * we dont need to: 736 * PUTREG(CMCMD, CM_CONF(CONF_LONG)); 737 */ 738 PUTREG(CMCMD, CM_CLR(CLR_RECONFIG)); 739 ifp->if_collisions++; 740 741 /* 742 * If less than 2 seconds per reconfig: 743 * If ARC_EXCESSIVE_RECONFIGS 744 * since last burst, complain and set treshold for 745 * warnings to ARC_EXCESSIVE_RECONS_REWARN. 746 * 747 * This allows for, e.g., new stations on the cable, or 748 * cable switching as long as it is over after 749 * (normally) 16 seconds. 750 * 751 * XXX TODO: check timeout bits in status word and 752 * double time if necessary. 753 */ 754 755 callout_stop(&sc->sc_recon_ch); 756 newsec = time_second; 757 if ((newsec - sc->sc_recontime <= 2) && 758 (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) { 759 log(LOG_WARNING, 760 "%s: excessive token losses, " 761 "cable problem?\n", 762 ifp->if_xname); 763 } 764 sc->sc_recontime = newsec; 765 callout_reset(&sc->sc_recon_ch, 15 * hz, 766 cm_reconwatch_locked, (void *)sc); 767 } 768 769 if (maskedisr & CM_RI) { 770#if defined(CM_DEBUG) && (CM_DEBUG > 1) 771 if_printf(ifp, "intr: hard rint, act %d\n", 772 sc->sc_rx_act); 773#endif 774 775 buffer = sc->sc_rx_act; 776 /* look if buffer is marked invalid: */ 777 if (GETMEM(buffer * 512) == 0) { 778 /* 779 * invalid marked buffer (or illegally 780 * configured sender) 781 */ 782 log(LOG_WARNING, 783 "%s: spurious RX interrupt or sender 0 " 784 " (ignored)\n", ifp->if_xname); 785 /* 786 * restart receiver on same buffer. 787 * XXX maybe better reset interface? 788 */ 789 PUTREG(CMCMD, CM_RXBC(buffer)); 790 } else { 791 if (++sc->sc_rx_fillcount > 1) { 792 sc->sc_intmask &= ~CM_RI; 793 PUTREG(CMSTAT, sc->sc_intmask); 794 } else { 795 buffer ^= 1; 796 sc->sc_rx_act = buffer; 797 798 /* 799 * Start receiver on other receive 800 * buffer. This also clears the RI 801 * interrupt flag. 802 */ 803 PUTREG(CMCMD, CM_RXBC(buffer)); 804 /* in RX intr, so mask is ok for RX */ 805 806#ifdef CM_DEBUG 807 if_printf(ifp, "strt rx for buf %d, " 808 "stat 0x%02x\n", 809 sc->sc_rx_act, GETREG(CMSTAT)); 810#endif 811 } 812 813#ifdef CMSOFTCOPY 814 /* 815 * this one starts a soft int to copy out 816 * of the hw 817 */ 818 softintr_schedule(sc->sc_rxcookie); 819#else 820 /* this one does the copy here */ 821 cm_srint_locked(sc); 822#endif 823 } 824 } 825 if (maskedisr & CM_TA) { 826 cm_tint_locked(sc, isr); 827 } 828 isr = GETREG(CMSTAT); 829 maskedisr = isr & sc->sc_intmask; 830 } while (maskedisr); 831#if defined(CM_DEBUG) && (CM_DEBUG > 1) 832 if_printf(ifp, "intr (exit): status 0x%02x, intmask 0x%02x\n", 833 isr, sc->sc_intmask); 834#endif 835 CM_UNLOCK(sc); 836} 837 838void 839cm_reconwatch_locked(arg) 840 void *arg; 841{ 842 struct cm_softc *sc = arg; 843 struct ifnet *ifp = sc->sc_ifp; 844 845 if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) { 846 sc->sc_reconcount = 0; 847 log(LOG_WARNING, "%s: token valid again.\n", 848 ifp->if_xname); 849 } 850 sc->sc_reconcount = 0; 851} 852 853 854/* 855 * Process an ioctl request. 856 * This code needs some work - it looks pretty ugly. 857 */ 858int 859cm_ioctl(ifp, command, data) 860 struct ifnet *ifp; 861 u_long command; 862 caddr_t data; 863{ 864 struct cm_softc *sc; 865 int error; 866 867 error = 0; 868 sc = ifp->if_softc; 869 870#if defined(CM_DEBUG) && (CM_DEBUG > 2) 871 if_printf(ifp, "ioctl() called, cmd = 0x%lx\n", command); 872#endif 873 874 switch (command) { 875 case SIOCSIFADDR: 876 case SIOCGIFADDR: 877 case SIOCADDMULTI: 878 case SIOCDELMULTI: 879 case SIOCSIFMTU: 880 error = arc_ioctl(ifp, command, data); 881 break; 882 883 case SIOCSIFFLAGS: 884 CM_LOCK(sc); 885 if ((ifp->if_flags & IFF_UP) == 0 && 886 (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 887 /* 888 * If interface is marked down and it is running, 889 * then stop it. 890 */ 891 cm_stop_locked(sc); 892 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 893 } else if ((ifp->if_flags & IFF_UP) != 0 && 894 (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 895 /* 896 * If interface is marked up and it is stopped, then 897 * start it. 898 */ 899 cm_init_locked(sc); 900 } 901 CM_UNLOCK(sc); 902 break; 903 904 default: 905 error = EINVAL; 906 break; 907 } 908 909 return (error); 910} 911 912/* 913 * watchdog routine for transmitter. 914 * 915 * We need this, because else a receiver whose hardware is alive, but whose 916 * software has not enabled the Receiver, would make our hardware wait forever 917 * Discovered this after 20 times reading the docs. 918 * 919 * Only thing we do is disable transmitter. We'll get a transmit timeout, 920 * and the int handler will have to decide not to retransmit (in case 921 * retransmission is implemented). 922 */ 923void 924cm_watchdog(void *arg) 925{ 926 struct cm_softc *sc; 927 928 sc = arg; 929 callout_reset(&sc->sc_watchdog_timer, hz, cm_watchdog, sc); 930 if (sc->sc_timer == 0 || --sc->sc_timer > 0) 931 return; 932 PUTREG(CMCMD, CM_TXDIS); 933} 934