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