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