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