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