smc90cx6.c revision 271849
1255570Strasz/* $NetBSD: smc90cx6.c,v 1.38 2001/07/07 15:57:53 thorpej Exp $ */ 2255570Strasz 3255570Strasz#include <sys/cdefs.h> 4255570Strasz__FBSDID("$FreeBSD: head/sys/dev/cm/smc90cx6.c 271849 2014-09-19 03:51:26Z glebius $"); 5255570Strasz 6255570Strasz/*- 7255570Strasz * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc. 8255570Strasz * All rights reserved. 9255570Strasz * 10255570Strasz * This code is derived from software contributed to The NetBSD Foundation 11255570Strasz * by Ignatios Souvatzis. 12255570Strasz * 13255570Strasz * Redistribution and use in source and binary forms, with or without 14255570Strasz * modification, are permitted provided that the following conditions 15255570Strasz * are met: 16255570Strasz * 1. Redistributions of source code must retain the above copyright 17255570Strasz * notice, this list of conditions and the following disclaimer. 18255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 19255570Strasz * notice, this list of conditions and the following disclaimer in the 20255570Strasz * documentation and/or other materials provided with the distribution. 21255570Strasz * 22255570Strasz * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23255570Strasz * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24255570Strasz * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25255570Strasz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26255570Strasz * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27255570Strasz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28255570Strasz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29255570Strasz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30255570Strasz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31270279Strasz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32270279Strasz * POSSIBILITY OF SUCH DAMAGE. 33270279Strasz */ 34255570Strasz 35255570Strasz/* 36255570Strasz * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56 37255570Strasz * compatibility mode) boards 38255570Strasz */ 39255570Strasz 40267606Smav/* #define CMSOFTCOPY */ 41267606Smav#define CMRETRANSMIT /**/ 42255570Strasz/* #define CM_DEBUG */ 43255570Strasz 44255570Strasz#include <sys/param.h> 45255570Strasz#include <sys/systm.h> 46255570Strasz#include <sys/sockio.h> 47255570Strasz#include <sys/mbuf.h> 48255570Strasz#include <sys/module.h> 49255570Strasz#include <sys/kernel.h> 50255570Strasz#include <sys/socket.h> 51255570Strasz#include <sys/syslog.h> 52255570Strasz#include <sys/bus.h> 53255570Strasz 54255570Strasz#include <machine/bus.h> 55255570Strasz#include <sys/rman.h> 56255570Strasz#include <machine/resource.h> 57255570Strasz 58255570Strasz#include <net/if.h> 59255570Strasz#include <net/if_var.h> 60255570Strasz#include <net/if_dl.h> 61255570Strasz#include <net/if_types.h> 62255570Strasz#include <net/if_arc.h> 63255570Strasz 64255570Strasz#include <dev/cm/smc90cx6reg.h> 65255570Strasz#include <dev/cm/smc90cx6var.h> 66255570Strasz 67255570StraszMODULE_DEPEND(if_cm, arcnet, 1, 1, 1); 68275864Smav 69255570Strasz/* these should be elsewhere */ 70275864Smav 71255570Strasz#define ARC_MIN_LEN 1 72255570Strasz#define ARC_MIN_FORBID_LEN 254 73255570Strasz#define ARC_MAX_FORBID_LEN 256 74275864Smav#define ARC_MAX_LEN 508 75255570Strasz#define ARC_ADDR_LEN 1 76255570Strasz 77255570Strasz/* for watchdog timer. This should be more than enough. */ 78255570Strasz#define ARCTIMEOUT (5*IFNET_SLOWHZ) 79255570Strasz 80255570Straszdevclass_t cm_devclass; 81255570Strasz 82255570Strasz/* 83255570Strasz * This currently uses 2 bufs for tx, 2 for rx 84255570Strasz * 85255570Strasz * New rx protocol: 86255570Strasz * 87255570Strasz * rx has a fillcount variable. If fillcount > (NRXBUF-1), 88255570Strasz * rx can be switched off from rx hard int. 89255570Strasz * Else rx is restarted on the other receiver. 90255570Strasz * rx soft int counts down. if it is == (NRXBUF-1), it restarts 91255570Strasz * the receiver. 92255570Strasz * To ensure packet ordering (we need that for 1201 later), we have a counter 93255570Strasz * which is incremented modulo 256 on each receive and a per buffer 94255570Strasz * variable, which is set to the counter on filling. The soft int can 95255570Strasz * compare both values to determine the older packet. 96255570Strasz * 97255570Strasz * Transmit direction: 98255570Strasz * 99255570Strasz * cm_start checks tx_fillcount 100255570Strasz * case 2: return 101255570Strasz * 102255570Strasz * else fill tx_act ^ 1 && inc tx_fillcount 103255570Strasz * 104255570Strasz * check tx_fillcount again. 105255570Strasz * case 2: set IFF_DRV_OACTIVE to stop arc_output from filling us. 106255570Strasz * case 1: start tx 107255570Strasz * 108255570Strasz * tint clears IFF_OACTIVE, decrements and checks tx_fillcount 109255570Strasz * case 1: start tx on tx_act ^ 1, softcall cm_start 110255570Strasz * case 0: softcall cm_start 111255570Strasz * 112255570Strasz * #define fill(i) get mbuf && copy mbuf to chip(i) 113255570Strasz */ 114255570Strasz 115255570Straszvoid cm_init(void *); 116255570Straszstatic void cm_init_locked(struct cm_softc *); 117255570Straszstatic void cm_reset_locked(struct cm_softc *); 118255570Straszvoid cm_start(struct ifnet *); 119255570Straszvoid cm_start_locked(struct ifnet *); 120255570Straszint cm_ioctl(struct ifnet *, unsigned long, caddr_t); 121255570Straszvoid cm_watchdog(void *); 122255570Straszvoid cm_srint_locked(void *vsc); 123275864Smavstatic void cm_tint_locked(struct cm_softc *, int); 124255570Straszvoid cm_reconwatch_locked(void *); 125275864Smav 126255570Strasz/* 127255570Strasz * Release all resources 128255570Strasz */ 129255570Straszvoid 130275864Smavcm_release_resources(dev) 131255570Strasz device_t dev; 132255570Strasz{ 133255570Strasz struct cm_softc *sc = device_get_softc(dev); 134255570Strasz 135255570Strasz if (sc->port_res != NULL) { 136255570Strasz bus_release_resource(dev, SYS_RES_IOPORT, 137255570Strasz 0, sc->port_res); 138255570Strasz sc->port_res = NULL; 139255570Strasz } 140255570Strasz if (sc->mem_res != NULL) { 141255570Strasz bus_release_resource(dev, SYS_RES_MEMORY, 142255570Strasz 0, sc->mem_res); 143255570Strasz sc->mem_res = NULL; 144255570Strasz } 145255570Strasz if (sc->irq_res != NULL) { 146255570Strasz bus_release_resource(dev, SYS_RES_IRQ, 147255570Strasz 0, sc->irq_res); 148255570Strasz sc->irq_res = NULL; 149255570Strasz } 150255570Strasz} 151255570Strasz 152255570Straszint 153255570Straszcm_attach(dev) 154255570Strasz device_t dev; 155255570Strasz{ 156255570Strasz struct cm_softc *sc = device_get_softc(dev); 157255570Strasz struct ifnet *ifp; 158255570Strasz u_int8_t linkaddress; 159255570Strasz 160255570Strasz ifp = sc->sc_ifp = if_alloc(IFT_ARCNET); 161255570Strasz if (ifp == NULL) 162267606Smav return (ENOSPC); 163273543Strasz 164267606Smav /* 165267606Smav * read the arcnet address from the board 166267606Smav */ 167267606Smav GETREG(CMRESET); 168267606Smav do { 169267606Smav DELAY(200); 170267606Smav } while (!(GETREG(CMSTAT) & CM_POR)); 171267606Smav linkaddress = GETMEM(CMMACOFF); 172267606Smav 173267606Smav /* clear the int mask... */ 174267606Smav sc->sc_intmask = 0; 175267606Smav PUTREG(CMSTAT, 0); 176267606Smav 177267606Smav PUTREG(CMCMD, CM_CONF(CONF_LONG)); 178267606Smav PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG)); 179267606Smav sc->sc_recontime = sc->sc_reconcount = 0; 180267606Smav 181267606Smav /* 182267606Smav * set interface to stopped condition (reset) 183267606Smav */ 184267606Smav cm_stop_locked(sc); 185267606Smav 186267606Smav ifp->if_softc = sc; 187267606Smav if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 188267606Smav ifp->if_output = arc_output; 189267606Smav ifp->if_start = cm_start; 190267606Smav ifp->if_ioctl = cm_ioctl; 191267606Smav ifp->if_init = cm_init; 192267606Smav /* XXX IFQ_SET_READY(&ifp->if_snd); */ 193267606Smav ifp->if_snd.ifq_maxlen = ifqmaxlen; 194267606Smav ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 195267606Smav 196267606Smav arc_ifattach(ifp, linkaddress); 197267606Smav 198267606Smav#ifdef CMSOFTCOPY 199267606Smav sc->sc_rxcookie = softintr_establish(IPL_SOFTNET, cm_srint, sc); 200267606Smav sc->sc_txcookie = softintr_establish(IPL_SOFTNET, 201267606Smav (void (*)(void *))cm_start, ifp); 202267606Smav#endif 203267606Smav 204273813Strasz callout_init_mtx(&sc->sc_recon_ch, &sc->sc_mtx, 0); 205273813Strasz callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0); 206273813Strasz 207273813Strasz if_printf(ifp, "link addr 0x%02x (%d)\n", linkaddress, linkaddress); 208273813Strasz return 0; 209273813Strasz} 210273813Strasz 211273813Strasz/* 212273813Strasz * Initialize device 213273813Strasz * 214273813Strasz */ 215273813Straszvoid 216273813Straszcm_init(xsc) 217273813Strasz void *xsc; 218273813Strasz{ 219273813Strasz struct cm_softc *sc = (struct cm_softc *)xsc; 220273813Strasz 221273813Strasz CM_LOCK(sc); 222273813Strasz cm_init_locked(sc); 223273813Strasz CM_UNLOCK(sc); 224273813Strasz} 225273813Strasz 226273813Straszstatic void 227273813Straszcm_init_locked(struct cm_softc *sc) 228273813Strasz{ 229273813Strasz struct ifnet *ifp = sc->sc_ifp; 230273813Strasz 231273813Strasz if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 232273813Strasz ifp->if_drv_flags |= IFF_DRV_RUNNING; 233273813Strasz cm_reset_locked(sc); 234273813Strasz } 235273813Strasz} 236273813Strasz 237273813Strasz/* 238273813Strasz * Reset the interface... 239273813Strasz * 240273813Strasz * Assumes that it is called with sc_mtx held 241273813Strasz */ 242273813Straszvoid 243273813Straszcm_reset_locked(sc) 244273813Strasz struct cm_softc *sc; 245273813Strasz{ 246273813Strasz struct ifnet *ifp; 247273813Strasz int linkaddress; 248273813Strasz 249273813Strasz ifp = sc->sc_ifp; 250273813Strasz 251273813Strasz#ifdef CM_DEBUG 252273813Strasz if_printf(ifp, "reset\n"); 253273813Strasz#endif 254273813Strasz /* stop and restart hardware */ 255273813Strasz 256273813Strasz GETREG(CMRESET); 257273813Strasz do { 258273813Strasz DELAY(200); 259273813Strasz } while (!(GETREG(CMSTAT) & CM_POR)); 260273813Strasz 261273813Strasz linkaddress = GETMEM(CMMACOFF); 262273813Strasz 263255570Strasz#if defined(CM_DEBUG) && (CM_DEBUG > 2) 264255570Strasz if_printf(ifp, "reset: card reset, link addr = 0x%02x (%d)\n", 265255570Strasz linkaddress, linkaddress); 266255570Strasz#endif 267255570Strasz 268273543Strasz /* tell the routing level about the (possibly changed) link address */ 269273543Strasz arc_storelladdr(ifp, linkaddress); 270255570Strasz arc_frag_init(ifp); 271255570Strasz 272273543Strasz /* POR is NMI, but we need it below: */ 273273543Strasz sc->sc_intmask = CM_RECON|CM_POR; 274255570Strasz PUTREG(CMSTAT, sc->sc_intmask); 275255570Strasz PUTREG(CMCMD, CM_CONF(CONF_LONG)); 276255570Strasz 277255570Strasz#ifdef CM_DEBUG 278255570Strasz if_printf(ifp, "reset: chip configured, status=0x%02x\n", 279255570Strasz GETREG(CMSTAT)); 280255570Strasz#endif 281255570Strasz PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG)); 282255570Strasz 283255570Strasz#ifdef CM_DEBUG 284255570Strasz if_printf(ifp, "reset: bits cleared, status=0x%02x\n", 285255570Strasz GETREG(CMSTAT)); 286255570Strasz#endif 287273543Strasz 288273543Strasz sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; 289255570Strasz 290255570Strasz /* start receiver */ 291261757Strasz 292255570Strasz sc->sc_intmask |= CM_RI; 293255570Strasz sc->sc_rx_fillcount = 0; 294273813Strasz sc->sc_rx_act = 2; 295273813Strasz 296273813Strasz PUTREG(CMCMD, CM_RXBC(2)); 297273813Strasz PUTREG(CMSTAT, sc->sc_intmask); 298267606Smav 299255570Strasz#ifdef CM_DEBUG 300255570Strasz if_printf(ifp, "reset: started receiver, status=0x%02x\n", 301273543Strasz GETREG(CMSTAT)); 302255570Strasz#endif 303255570Strasz 304255570Strasz /* and init transmitter status */ 305273813Strasz sc->sc_tx_act = 0; 306273813Strasz sc->sc_tx_fillcount = 0; 307273813Strasz 308273813Strasz ifp->if_drv_flags |= IFF_DRV_RUNNING; 309273813Strasz ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 310273813Strasz 311273813Strasz callout_reset(&sc->sc_watchdog_timer, hz, cm_watchdog, sc); 312255570Strasz cm_start_locked(ifp); 313255570Strasz} 314255570Strasz 315255570Strasz/* 316255570Strasz * Take interface offline 317255570Strasz */ 318255570Straszvoid 319255570Straszcm_stop_locked(sc) 320255570Strasz struct cm_softc *sc; 321255570Strasz{ 322255570Strasz /* Stop the interrupts */ 323255570Strasz PUTREG(CMSTAT, 0); 324255570Strasz 325255570Strasz /* Stop the interface */ 326255570Strasz GETREG(CMRESET); 327255570Strasz 328255570Strasz /* Stop watchdog timer */ 329255570Strasz callout_stop(&sc->sc_watchdog_timer); 330255570Strasz 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 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 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 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 548 goto cleanup; 549 } 550 } 551 552 if (m == 0) { 553 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 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 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 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 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 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 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 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 if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); 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