smc90cx6.c revision 119418
189099Sfjoe/* $NetBSD: smc90cx6.c,v 1.38 2001/07/07 15:57:53 thorpej Exp $ */ 289099Sfjoe 3119418Sobrien#include <sys/cdefs.h> 4119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/cm/smc90cx6.c 119418 2003-08-24 17:55:58Z obrien $"); 5119418Sobrien 689099Sfjoe/*- 789099Sfjoe * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc. 889099Sfjoe * All rights reserved. 989099Sfjoe * 1089099Sfjoe * This code is derived from software contributed to The NetBSD Foundation 1189099Sfjoe * by Ignatios Souvatzis. 1289099Sfjoe * 1389099Sfjoe * Redistribution and use in source and binary forms, with or without 1489099Sfjoe * modification, are permitted provided that the following conditions 1589099Sfjoe * are met: 1689099Sfjoe * 1. Redistributions of source code must retain the above copyright 1789099Sfjoe * notice, this list of conditions and the following disclaimer. 1889099Sfjoe * 2. Redistributions in binary form must reproduce the above copyright 1989099Sfjoe * notice, this list of conditions and the following disclaimer in the 2089099Sfjoe * documentation and/or other materials provided with the distribution. 2189099Sfjoe * 3. All advertising materials mentioning features or use of this software 2289099Sfjoe * must display the following acknowledgement: 2389099Sfjoe * This product includes software developed by the NetBSD 2489099Sfjoe * Foundation, Inc. and its contributors. 2589099Sfjoe * 4. Neither the name of The NetBSD Foundation nor the names of its 2689099Sfjoe * contributors may be used to endorse or promote products derived 2789099Sfjoe * from this software without specific prior written permission. 2889099Sfjoe * 2989099Sfjoe * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 3089099Sfjoe * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 3189099Sfjoe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 3289099Sfjoe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3389099Sfjoe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3489099Sfjoe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3589099Sfjoe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3689099Sfjoe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3789099Sfjoe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3889099Sfjoe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3989099Sfjoe * POSSIBILITY OF SUCH DAMAGE. 4089099Sfjoe */ 4189099Sfjoe 4289099Sfjoe/* 4389099Sfjoe * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56 4489099Sfjoe * compatibility mode) boards 4589099Sfjoe */ 4689099Sfjoe 4789099Sfjoe/* #define CMSOFTCOPY */ 4889099Sfjoe#define CMRETRANSMIT /**/ 49109771Sfjoe/* #define CM_DEBUG */ 5089099Sfjoe 5189099Sfjoe#include <sys/param.h> 5289099Sfjoe#include <sys/systm.h> 5389099Sfjoe#include <sys/sockio.h> 5489099Sfjoe#include <sys/mbuf.h> 5589099Sfjoe#include <sys/module.h> 5689099Sfjoe#include <sys/kernel.h> 5789099Sfjoe#include <sys/socket.h> 5889099Sfjoe#include <sys/syslog.h> 5989099Sfjoe#include <sys/bus.h> 6089099Sfjoe 6189099Sfjoe#include <machine/bus.h> 6289099Sfjoe#include <sys/rman.h> 6389099Sfjoe#include <machine/resource.h> 6489099Sfjoe 6589099Sfjoe#if __FreeBSD_version < 500000 6689099Sfjoe#include <machine/clock.h> 6789099Sfjoe#endif 6889099Sfjoe 6989099Sfjoe#include <net/if.h> 7089099Sfjoe#include <net/if_dl.h> 7189099Sfjoe#include <net/if_types.h> 7289099Sfjoe#include <net/if_arc.h> 7389099Sfjoe 7489099Sfjoe#include <dev/cm/smc90cx6reg.h> 7589099Sfjoe#include <dev/cm/smc90cx6var.h> 7689099Sfjoe 7789099SfjoeMODULE_DEPEND(if_cm, arcnet, 1, 1, 1); 7889099Sfjoe 7989099Sfjoe/* these should be elsewhere */ 8089099Sfjoe 8189099Sfjoe#define ARC_MIN_LEN 1 8289099Sfjoe#define ARC_MIN_FORBID_LEN 254 8389099Sfjoe#define ARC_MAX_FORBID_LEN 256 8489099Sfjoe#define ARC_MAX_LEN 508 8589099Sfjoe#define ARC_ADDR_LEN 1 8689099Sfjoe 8789099Sfjoe/* for watchdog timer. This should be more than enough. */ 8889099Sfjoe#define ARCTIMEOUT (5*IFNET_SLOWHZ) 8989099Sfjoe 9089099Sfjoe/* short notation */ 9189099Sfjoe 9289099Sfjoe#define GETREG(off) \ 9389099Sfjoe bus_space_read_1(rman_get_bustag((sc)->port_res), \ 9489099Sfjoe rman_get_bushandle((sc)->port_res), \ 9589099Sfjoe (off)) 9689099Sfjoe#define PUTREG(off, value) \ 9789099Sfjoe bus_space_write_1(rman_get_bustag((sc)->port_res), \ 9889099Sfjoe rman_get_bushandle((sc)->port_res), \ 9989099Sfjoe (off), (value)) 10089099Sfjoe#define GETMEM(off) \ 10189099Sfjoe bus_space_read_1(rman_get_bustag((sc)->mem_res), \ 10289099Sfjoe rman_get_bushandle((sc)->mem_res), \ 10389099Sfjoe (off)) 10489099Sfjoe#define PUTMEM(off, value) \ 10589099Sfjoe bus_space_write_1(rman_get_bustag((sc)->mem_res), \ 10689099Sfjoe rman_get_bushandle((sc)->mem_res), \ 10789099Sfjoe (off), (value)) 10889099Sfjoe 10989099Sfjoedevclass_t cm_devclass; 11089099Sfjoe 11189099Sfjoe/* 11289099Sfjoe * This currently uses 2 bufs for tx, 2 for rx 11389099Sfjoe * 11489099Sfjoe * New rx protocol: 11589099Sfjoe * 11689099Sfjoe * rx has a fillcount variable. If fillcount > (NRXBUF-1), 11789099Sfjoe * rx can be switched off from rx hard int. 11889099Sfjoe * Else rx is restarted on the other receiver. 11989099Sfjoe * rx soft int counts down. if it is == (NRXBUF-1), it restarts 12089099Sfjoe * the receiver. 12189099Sfjoe * To ensure packet ordering (we need that for 1201 later), we have a counter 12289099Sfjoe * which is incremented modulo 256 on each receive and a per buffer 12389099Sfjoe * variable, which is set to the counter on filling. The soft int can 12489099Sfjoe * compare both values to determine the older packet. 12589099Sfjoe * 12689099Sfjoe * Transmit direction: 12789099Sfjoe * 12889099Sfjoe * cm_start checks tx_fillcount 12989099Sfjoe * case 2: return 13089099Sfjoe * 13189099Sfjoe * else fill tx_act ^ 1 && inc tx_fillcount 13289099Sfjoe * 13389099Sfjoe * check tx_fillcount again. 13489099Sfjoe * case 2: set IFF_OACTIVE to stop arc_output from filling us. 13589099Sfjoe * case 1: start tx 13689099Sfjoe * 13789099Sfjoe * tint clears IFF_OCATIVE, decrements and checks tx_fillcount 13889099Sfjoe * case 1: start tx on tx_act ^ 1, softcall cm_start 13989099Sfjoe * case 0: softcall cm_start 14089099Sfjoe * 14189099Sfjoe * #define fill(i) get mbuf && copy mbuf to chip(i) 14289099Sfjoe */ 14389099Sfjoe 14492739Salfredvoid cm_init(void *); 14592739Salfredvoid cm_reset(struct cm_softc *); 14692739Salfredvoid cm_start(struct ifnet *); 14792739Salfredint cm_ioctl(struct ifnet *, unsigned long, caddr_t); 14892739Salfredvoid cm_watchdog(struct ifnet *); 14992739Salfredvoid cm_srint(void *vsc); 15092739Salfredstatic void cm_tint(struct cm_softc *, int); 15189099Sfjoevoid cm_reconwatch(void *); 15289099Sfjoe 15389099Sfjoeint 15489099Sfjoecm_probe(dev) 15589099Sfjoe device_t dev; 15689099Sfjoe{ 15789099Sfjoe int error; 15889099Sfjoe struct cm_softc *sc = device_get_softc(dev); 15989099Sfjoe 16089099Sfjoe error = cm_alloc_port(dev, 0, CM_IO_PORTS); 16189099Sfjoe if (error) 16289099Sfjoe return error; 16389099Sfjoe 16489099Sfjoe if (GETREG(CMSTAT) == 0xff) 16589099Sfjoe return ENXIO; 16689099Sfjoe 16789099Sfjoe error = cm_alloc_memory(dev, 0, 0x800); 16889099Sfjoe if (error) 16989099Sfjoe return error; 17089099Sfjoe 17189099Sfjoe return 0; 17289099Sfjoe} 17389099Sfjoe 17489099Sfjoe/* 17589099Sfjoe * Allocate a port resource with the given resource id. 17689099Sfjoe */ 17789099Sfjoeint 17889099Sfjoecm_alloc_port(dev, rid, size) 17989099Sfjoe device_t dev; 18089099Sfjoe int rid; 18189099Sfjoe int size; 18289099Sfjoe{ 18389099Sfjoe struct cm_softc *sc = device_get_softc(dev); 18489099Sfjoe struct resource *res; 18589099Sfjoe 18689099Sfjoe res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 18789099Sfjoe 0ul, ~0ul, size, RF_ACTIVE); 18889099Sfjoe if (res) { 18989099Sfjoe sc->port_rid = rid; 19089099Sfjoe sc->port_res = res; 19189099Sfjoe sc->port_used = size; 19289099Sfjoe return (0); 19389099Sfjoe } else { 19489099Sfjoe return (ENOENT); 19589099Sfjoe } 19689099Sfjoe} 19789099Sfjoe 19889099Sfjoe/* 19989099Sfjoe * Allocate a memory resource with the given resource id. 20089099Sfjoe */ 20189099Sfjoeint 20289099Sfjoecm_alloc_memory(dev, rid, size) 20389099Sfjoe device_t dev; 20489099Sfjoe int rid; 20589099Sfjoe int size; 20689099Sfjoe{ 20789099Sfjoe struct cm_softc *sc = device_get_softc(dev); 20889099Sfjoe struct resource *res; 20989099Sfjoe 21089099Sfjoe res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 21189099Sfjoe 0ul, ~0ul, size, RF_ACTIVE); 21289099Sfjoe if (res) { 21389099Sfjoe sc->mem_rid = rid; 21489099Sfjoe sc->mem_res = res; 21589099Sfjoe sc->mem_used = size; 21689099Sfjoe return (0); 21789099Sfjoe } else { 21889099Sfjoe return (ENOENT); 21989099Sfjoe } 22089099Sfjoe} 22189099Sfjoe 22289099Sfjoe/* 22389099Sfjoe * Allocate an irq resource with the given resource id. 22489099Sfjoe */ 22589099Sfjoeint 22689099Sfjoecm_alloc_irq(dev, rid) 22789099Sfjoe device_t dev; 22889099Sfjoe int rid; 22989099Sfjoe{ 23089099Sfjoe struct cm_softc *sc = device_get_softc(dev); 23189099Sfjoe struct resource *res; 23289099Sfjoe 23389099Sfjoe res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 23489099Sfjoe 0ul, ~0ul, 1, RF_ACTIVE); 23589099Sfjoe if (res) { 23689099Sfjoe sc->irq_rid = rid; 23789099Sfjoe sc->irq_res = res; 23889099Sfjoe return (0); 23989099Sfjoe } else { 24089099Sfjoe return (ENOENT); 24189099Sfjoe } 24289099Sfjoe} 24389099Sfjoe 24489099Sfjoe/* 24589099Sfjoe * Release all resources 24689099Sfjoe */ 24789099Sfjoevoid 24889099Sfjoecm_release_resources(dev) 24989099Sfjoe device_t dev; 25089099Sfjoe{ 25189099Sfjoe struct cm_softc *sc = device_get_softc(dev); 25289099Sfjoe 25389099Sfjoe if (sc->port_res) { 25489099Sfjoe bus_deactivate_resource(dev, SYS_RES_IOPORT, 25589099Sfjoe sc->port_rid, sc->port_res); 25689099Sfjoe bus_release_resource(dev, SYS_RES_IOPORT, 25789099Sfjoe sc->port_rid, sc->port_res); 25889099Sfjoe sc->port_res = 0; 25989099Sfjoe } 26089099Sfjoe if (sc->mem_res) { 26189099Sfjoe bus_deactivate_resource(dev, SYS_RES_MEMORY, 26289099Sfjoe sc->mem_rid, sc->mem_res); 26389099Sfjoe bus_release_resource(dev, SYS_RES_MEMORY, 26489099Sfjoe sc->mem_rid, sc->mem_res); 26589099Sfjoe sc->mem_res = 0; 26689099Sfjoe } 26789099Sfjoe if (sc->irq_res) { 26889099Sfjoe bus_deactivate_resource(dev, SYS_RES_IRQ, 26989099Sfjoe sc->irq_rid, sc->irq_res); 27089099Sfjoe bus_release_resource(dev, SYS_RES_IRQ, 27189099Sfjoe sc->irq_rid, sc->irq_res); 27289099Sfjoe sc->irq_res = 0; 27389099Sfjoe } 27489099Sfjoe} 27589099Sfjoe 27689099Sfjoeint 27789099Sfjoecm_attach(sc, unit) 27889099Sfjoe struct cm_softc *sc; 27989099Sfjoe int unit; 28089099Sfjoe{ 28189099Sfjoe struct ifnet *ifp = &sc->sc_arccom.ac_if; 28289099Sfjoe int s; 28389099Sfjoe u_int8_t linkaddress; 28489099Sfjoe 28589099Sfjoe s = splhigh(); 28689099Sfjoe 28789099Sfjoe /* 28889099Sfjoe * read the arcnet address from the board 28989099Sfjoe */ 29089099Sfjoe 29189099Sfjoe GETREG(CMRESET); 29289099Sfjoe do { 29389099Sfjoe DELAY(200); 29489099Sfjoe } while (!(GETREG(CMSTAT) & CM_POR)); 29589099Sfjoe 29689099Sfjoe linkaddress = GETMEM(CMMACOFF); 29789099Sfjoe 29889099Sfjoe /* clear the int mask... */ 29989099Sfjoe 30089099Sfjoe sc->sc_intmask = 0; 30189099Sfjoe PUTREG(CMSTAT, 0); 30289099Sfjoe 30389099Sfjoe PUTREG(CMCMD, CM_CONF(CONF_LONG)); 30489099Sfjoe PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG)); 30589099Sfjoe sc->sc_recontime = sc->sc_reconcount = 0; 30689099Sfjoe 30789099Sfjoe /* and reenable kernel int level */ 30889099Sfjoe splx(s); 30989099Sfjoe 31089099Sfjoe /* 31189099Sfjoe * set interface to stopped condition (reset) 31289099Sfjoe */ 31389099Sfjoe cm_stop(sc); 31489099Sfjoe 31589099Sfjoe if (!ifp->if_name) { 31689099Sfjoe ifp->if_softc = sc; 31789099Sfjoe ifp->if_unit = unit; 31889099Sfjoe ifp->if_name = "cm"; 31989099Sfjoe ifp->if_output = arc_output; 32089099Sfjoe ifp->if_start = cm_start; 32189099Sfjoe ifp->if_ioctl = cm_ioctl; 32289099Sfjoe ifp->if_watchdog = cm_watchdog; 32389099Sfjoe ifp->if_init = cm_init; 32489099Sfjoe /* XXX IFQ_SET_READY(&ifp->if_snd); */ 32589099Sfjoe ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 32689099Sfjoe ifp->if_timer = 0; 32789099Sfjoe ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 32889099Sfjoe 32989099Sfjoe arc_ifattach(ifp, linkaddress); 33089099Sfjoe 33189099Sfjoe#ifdef CMSOFTCOPY 33289099Sfjoe sc->sc_rxcookie = softintr_establish(IPL_SOFTNET, cm_srint, sc); 33389099Sfjoe sc->sc_txcookie = softintr_establish(IPL_SOFTNET, 33492739Salfred (void (*)(void *))cm_start, ifp); 33589099Sfjoe#endif 33689099Sfjoe 33789099Sfjoe#if __FreeBSD_version < 500000 33889099Sfjoe callout_init(&sc->sc_recon_ch); 33989099Sfjoe#else 34089099Sfjoe callout_init(&sc->sc_recon_ch, 0); 34189099Sfjoe#endif 34289099Sfjoe } 34389099Sfjoe 344109771Sfjoe if_printf(ifp, "link addr 0x%02x (%d)\n", linkaddress, linkaddress); 34589099Sfjoe return 0; 34689099Sfjoe} 34789099Sfjoe 34889099Sfjoe/* 34989099Sfjoe * Initialize device 35089099Sfjoe * 35189099Sfjoe */ 35289099Sfjoevoid 35389099Sfjoecm_init(xsc) 35489099Sfjoe void *xsc; 35589099Sfjoe{ 35689099Sfjoe struct cm_softc *sc = (struct cm_softc *)xsc; 35789099Sfjoe struct ifnet *ifp; 35889099Sfjoe int s; 35989099Sfjoe 36089099Sfjoe ifp = &sc->sc_arccom.ac_if; 36189099Sfjoe 36289099Sfjoe if ((ifp->if_flags & IFF_RUNNING) == 0) { 36389099Sfjoe s = splimp(); 36489099Sfjoe ifp->if_flags |= IFF_RUNNING; 36589099Sfjoe cm_reset(sc); 36689099Sfjoe cm_start(ifp); 36789099Sfjoe splx(s); 36889099Sfjoe } 36989099Sfjoe} 37089099Sfjoe 37189099Sfjoe/* 37289099Sfjoe * Reset the interface... 37389099Sfjoe * 37489099Sfjoe * this assumes that it is called inside a critical section... 37589099Sfjoe * 37689099Sfjoe */ 37789099Sfjoevoid 37889099Sfjoecm_reset(sc) 37989099Sfjoe struct cm_softc *sc; 38089099Sfjoe{ 38189099Sfjoe struct ifnet *ifp; 38289099Sfjoe int linkaddress; 38389099Sfjoe 38489099Sfjoe ifp = &sc->sc_arccom.ac_if; 38589099Sfjoe 38689099Sfjoe#ifdef CM_DEBUG 387104251Sbrooks if_printf(ifp, "reset\n"); 38889099Sfjoe#endif 38989099Sfjoe /* stop and restart hardware */ 39089099Sfjoe 39189099Sfjoe GETREG(CMRESET); 39289099Sfjoe do { 39389099Sfjoe DELAY(200); 39489099Sfjoe } while (!(GETREG(CMSTAT) & CM_POR)); 39589099Sfjoe 39689099Sfjoe linkaddress = GETMEM(CMMACOFF); 39789099Sfjoe 39889099Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 2) 399104251Sbrooks if_printf(ifp, "reset: card reset, link addr = 0x%02x (%d)\n", 400104251Sbrooks linkaddress, linkaddress); 40189099Sfjoe#endif 40289099Sfjoe 40389099Sfjoe /* tell the routing level about the (possibly changed) link address */ 40489099Sfjoe arc_storelladdr(ifp, linkaddress); 40589099Sfjoe arc_frag_init(ifp); 40689099Sfjoe 40789099Sfjoe /* POR is NMI, but we need it below: */ 40889099Sfjoe sc->sc_intmask = CM_RECON|CM_POR; 40989099Sfjoe PUTREG(CMSTAT, sc->sc_intmask); 41089099Sfjoe PUTREG(CMCMD, CM_CONF(CONF_LONG)); 41189099Sfjoe 41289099Sfjoe#ifdef CM_DEBUG 413104251Sbrooks if_printf(ifp, "reset: chip configured, status=0x%02x\n", 414104251Sbrooks GETREG(CMSTAT)); 41589099Sfjoe#endif 41689099Sfjoe PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG)); 41789099Sfjoe 41889099Sfjoe#ifdef CM_DEBUG 419104251Sbrooks if_printf(ifp, "reset: bits cleared, status=0x%02x\n", 420104251Sbrooks GETREG(CMSTAT)); 42189099Sfjoe#endif 42289099Sfjoe 42389099Sfjoe sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; 42489099Sfjoe 42589099Sfjoe /* start receiver */ 42689099Sfjoe 42789099Sfjoe sc->sc_intmask |= CM_RI; 42889099Sfjoe sc->sc_rx_fillcount = 0; 42989099Sfjoe sc->sc_rx_act = 2; 43089099Sfjoe 43189099Sfjoe PUTREG(CMCMD, CM_RXBC(2)); 43289099Sfjoe PUTREG(CMSTAT, sc->sc_intmask); 43389099Sfjoe 43489099Sfjoe#ifdef CM_DEBUG 435104251Sbrooks if_printf(ifp, "reset: started receiver, status=0x%02x\n", 436104251Sbrooks GETREG(CMSTAT)); 43789099Sfjoe#endif 43889099Sfjoe 43989099Sfjoe /* and init transmitter status */ 44089099Sfjoe sc->sc_tx_act = 0; 44189099Sfjoe sc->sc_tx_fillcount = 0; 44289099Sfjoe 44389099Sfjoe ifp->if_flags |= IFF_RUNNING; 44489099Sfjoe ifp->if_flags &= ~IFF_OACTIVE; 44589099Sfjoe 44689099Sfjoe cm_start(ifp); 44789099Sfjoe} 44889099Sfjoe 44989099Sfjoe/* 45089099Sfjoe * Take interface offline 45189099Sfjoe */ 45289099Sfjoevoid 45389099Sfjoecm_stop(sc) 45489099Sfjoe struct cm_softc *sc; 45589099Sfjoe{ 45689099Sfjoe /* Stop the interrupts */ 45789099Sfjoe PUTREG(CMSTAT, 0); 45889099Sfjoe 45989099Sfjoe /* Stop the interface */ 46089099Sfjoe GETREG(CMRESET); 46189099Sfjoe 46289099Sfjoe /* Stop watchdog timer */ 46389099Sfjoe sc->sc_arccom.ac_if.if_timer = 0; 46489099Sfjoe} 46589099Sfjoe 46689099Sfjoe/* 46789099Sfjoe * Start output on interface. Get another datagram to send 46889099Sfjoe * off the interface queue, and copy it to the 46989099Sfjoe * interface becore starting the output 47089099Sfjoe * 47189099Sfjoe * this assumes that it is called inside a critical section... 47289099Sfjoe * XXX hm... does it still? 47389099Sfjoe * 47489099Sfjoe */ 47589099Sfjoevoid 47689099Sfjoecm_start(ifp) 47789099Sfjoe struct ifnet *ifp; 47889099Sfjoe{ 47989099Sfjoe struct cm_softc *sc = ifp->if_softc; 48089099Sfjoe struct mbuf *m,*mp; 48189099Sfjoe 48289099Sfjoe int cm_ram_ptr; 48389099Sfjoe int len, tlen, offset, s, buffer; 48489099Sfjoe#ifdef CMTIMINGS 48589099Sfjoe u_long copystart, lencopy, perbyte; 48689099Sfjoe#endif 48789099Sfjoe 48889099Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 3) 489104251Sbrooks if_printf(ifp, "start(%p)\n", ifp); 49089099Sfjoe#endif 49189099Sfjoe 49289099Sfjoe if ((ifp->if_flags & IFF_RUNNING) == 0) 49389099Sfjoe return; 49489099Sfjoe 49589099Sfjoe s = splimp(); 49689099Sfjoe 49789099Sfjoe if (sc->sc_tx_fillcount >= 2) { 49889099Sfjoe splx(s); 49989099Sfjoe return; 50089099Sfjoe } 50189099Sfjoe 50289099Sfjoe m = arc_frag_next(ifp); 50389099Sfjoe buffer = sc->sc_tx_act ^ 1; 50489099Sfjoe 50589099Sfjoe splx(s); 50689099Sfjoe 50789099Sfjoe if (m == 0) 50889099Sfjoe return; 50989099Sfjoe 51089099Sfjoe#ifdef CM_DEBUG 51189099Sfjoe if (m->m_len < ARC_HDRLEN) 51289099Sfjoe m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */ 513104251Sbrooks if_printf(ifp, "start: filling %d from %d to %d type %d\n", 514104251Sbrooks buffer, mtod(m, u_char *)[0], 51589099Sfjoe mtod(m, u_char *)[1], mtod(m, u_char *)[2]); 51689099Sfjoe#else 51789099Sfjoe if (m->m_len < 2) 51889099Sfjoe m = m_pullup(m, 2); 51989099Sfjoe#endif 520109771Sfjoe cm_ram_ptr = buffer * 512; 52189099Sfjoe 52289099Sfjoe if (m == 0) 52389099Sfjoe return; 52489099Sfjoe 52589099Sfjoe /* write the addresses to RAM and throw them away */ 52689099Sfjoe 52789099Sfjoe /* 52889099Sfjoe * Hardware does this: Yet Another Microsecond Saved. 52989099Sfjoe * (btw, timing code says usually 2 microseconds) 53089099Sfjoe * PUTMEM(cm_ram_ptr + 0, mtod(m, u_char *)[0]); 53189099Sfjoe */ 53289099Sfjoe 53389099Sfjoe PUTMEM(cm_ram_ptr + 1, mtod(m, u_char *)[1]); 53489099Sfjoe m_adj(m, 2); 53589099Sfjoe 53689099Sfjoe /* get total length left at this point */ 53789099Sfjoe tlen = m->m_pkthdr.len; 53889099Sfjoe if (tlen < ARC_MIN_FORBID_LEN) { 53989099Sfjoe offset = 256 - tlen; 54089099Sfjoe PUTMEM(cm_ram_ptr + 2, offset); 54189099Sfjoe } else { 54289099Sfjoe PUTMEM(cm_ram_ptr + 2, 0); 54389099Sfjoe if (tlen <= ARC_MAX_FORBID_LEN) 54489099Sfjoe offset = 255; /* !!! */ 54589099Sfjoe else { 54689099Sfjoe if (tlen > ARC_MAX_LEN) 54789099Sfjoe tlen = ARC_MAX_LEN; 54889099Sfjoe offset = 512 - tlen; 54989099Sfjoe } 55089099Sfjoe PUTMEM(cm_ram_ptr + 3, offset); 55189099Sfjoe 55289099Sfjoe } 55389099Sfjoe cm_ram_ptr += offset; 55489099Sfjoe 55589099Sfjoe /* lets loop through the mbuf chain */ 55689099Sfjoe 55789099Sfjoe for (mp = m; mp; mp = mp->m_next) { 55889099Sfjoe if ((len = mp->m_len)) { /* YAMS */ 55989099Sfjoe bus_space_write_region_1( 56089099Sfjoe rman_get_bustag(sc->mem_res), 56189099Sfjoe rman_get_bushandle(sc->mem_res), 56289099Sfjoe cm_ram_ptr, mtod(mp, caddr_t), len); 56389099Sfjoe 56489099Sfjoe cm_ram_ptr += len; 56589099Sfjoe } 56689099Sfjoe } 56789099Sfjoe 56889099Sfjoe sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0; 56989099Sfjoe sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5; 57089099Sfjoe 57189099Sfjoe /* actually transmit the packet */ 57289099Sfjoe s = splimp(); 57389099Sfjoe 57489099Sfjoe if (++sc->sc_tx_fillcount > 1) { 57589099Sfjoe /* 57689099Sfjoe * We are filled up to the rim. No more bufs for the moment, 57789099Sfjoe * please. 57889099Sfjoe */ 57989099Sfjoe ifp->if_flags |= IFF_OACTIVE; 58089099Sfjoe } else { 58189099Sfjoe#ifdef CM_DEBUG 582104251Sbrooks if_printf(ifp, "start: starting transmitter on buffer %d\n", 583104251Sbrooks buffer); 58489099Sfjoe#endif 58589099Sfjoe /* Transmitter was off, start it */ 58689099Sfjoe sc->sc_tx_act = buffer; 58789099Sfjoe 58889099Sfjoe /* 58989099Sfjoe * We still can accept another buf, so don't: 59089099Sfjoe * ifp->if_flags |= IFF_OACTIVE; 59189099Sfjoe */ 59289099Sfjoe sc->sc_intmask |= CM_TA; 59389099Sfjoe PUTREG(CMCMD, CM_TX(buffer)); 59489099Sfjoe PUTREG(CMSTAT, sc->sc_intmask); 59589099Sfjoe 59689099Sfjoe sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT; 59789099Sfjoe } 59889099Sfjoe splx(s); 59989099Sfjoe m_freem(m); 60089099Sfjoe 60189099Sfjoe /* 60289099Sfjoe * After 10 times reading the docs, I realized 60389099Sfjoe * that in the case the receiver NAKs the buffer request, 60489099Sfjoe * the hardware retries till shutdown. 60589099Sfjoe * This is integrated now in the code above. 60689099Sfjoe */ 60789099Sfjoe 60889099Sfjoe return; 60989099Sfjoe} 61089099Sfjoe 61189099Sfjoe/* 61289099Sfjoe * Arcnet interface receiver soft interrupt: 61389099Sfjoe * get the stuff out of any filled buffer we find. 61489099Sfjoe */ 61589099Sfjoevoid 61689099Sfjoecm_srint(vsc) 61789099Sfjoe void *vsc; 61889099Sfjoe{ 61989099Sfjoe struct cm_softc *sc = (struct cm_softc *)vsc; 62089099Sfjoe int buffer, len, offset, s, type; 62189099Sfjoe int cm_ram_ptr; 62289099Sfjoe struct mbuf *m; 62389099Sfjoe struct arc_header *ah; 62489099Sfjoe struct ifnet *ifp; 62589099Sfjoe 62689099Sfjoe ifp = &sc->sc_arccom.ac_if; 62789099Sfjoe 62889099Sfjoe s = splimp(); 62989099Sfjoe buffer = sc->sc_rx_act ^ 1; 63089099Sfjoe splx(s); 63189099Sfjoe 63289099Sfjoe /* Allocate header mbuf */ 633111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 63489099Sfjoe 63589099Sfjoe if (m == 0) { 63689099Sfjoe /* 63789099Sfjoe * in case s.th. goes wrong with mem, drop it 63889099Sfjoe * to make sure the receiver can be started again 63989099Sfjoe * count it as input error (we dont have any other 64089099Sfjoe * detectable) 64189099Sfjoe */ 64289099Sfjoe ifp->if_ierrors++; 64389099Sfjoe goto cleanup; 64489099Sfjoe } 64589099Sfjoe 64689099Sfjoe m->m_pkthdr.rcvif = ifp; 64789099Sfjoe 64889099Sfjoe /* 64989099Sfjoe * Align so that IP packet will be longword aligned. Here we 65089099Sfjoe * assume that m_data of new packet is longword aligned. 65189099Sfjoe * When implementing PHDS, we might have to change it to 2, 65289099Sfjoe * (2*sizeof(ulong) - CM_HDRNEWLEN)), packet type dependent. 65389099Sfjoe */ 65489099Sfjoe 655109771Sfjoe cm_ram_ptr = buffer * 512; 65689099Sfjoe offset = GETMEM(cm_ram_ptr + 2); 65789099Sfjoe if (offset) 65889099Sfjoe len = 256 - offset; 65989099Sfjoe else { 66089099Sfjoe offset = GETMEM(cm_ram_ptr + 3); 66189099Sfjoe len = 512 - offset; 66289099Sfjoe } 66389099Sfjoe 66489099Sfjoe /* 66589099Sfjoe * first +2 bytes for align fixup below 66689099Sfjoe * second +2 bytes are for src/dst addresses 66789099Sfjoe */ 66889099Sfjoe if ((len + 2 + 2) > MHLEN) { 66989099Sfjoe /* attach an mbuf cluster */ 670111119Simp MCLGET(m, M_DONTWAIT); 67189099Sfjoe 67289099Sfjoe /* Insist on getting a cluster */ 67389099Sfjoe if ((m->m_flags & M_EXT) == 0) { 67489099Sfjoe ifp->if_ierrors++; 67589099Sfjoe goto cleanup; 67689099Sfjoe } 67789099Sfjoe } 67889099Sfjoe 67989099Sfjoe if (m == 0) { 68089099Sfjoe ifp->if_ierrors++; 68189099Sfjoe goto cleanup; 68289099Sfjoe } 68389099Sfjoe 68489099Sfjoe type = GETMEM(cm_ram_ptr + offset); 68589099Sfjoe m->m_data += 1 + arc_isphds(type); 68689099Sfjoe /* mbuf filled with ARCnet addresses */ 68789099Sfjoe m->m_pkthdr.len = m->m_len = len + 2; 68889099Sfjoe 68989099Sfjoe ah = mtod(m, struct arc_header *); 69089099Sfjoe ah->arc_shost = GETMEM(cm_ram_ptr + 0); 69189099Sfjoe ah->arc_dhost = GETMEM(cm_ram_ptr + 1); 69289099Sfjoe 69389099Sfjoe bus_space_read_region_1( 69489099Sfjoe rman_get_bustag(sc->mem_res), rman_get_bushandle(sc->mem_res), 69589099Sfjoe cm_ram_ptr + offset, mtod(m, u_char *) + 2, len); 69689099Sfjoe 69789099Sfjoe arc_input(ifp, m); 69889099Sfjoe 69989099Sfjoe m = NULL; 70089099Sfjoe ifp->if_ipackets++; 70189099Sfjoe 70289099Sfjoecleanup: 70389099Sfjoe 70489099Sfjoe if (m != NULL) 70589099Sfjoe m_freem(m); 70689099Sfjoe 70789099Sfjoe /* mark buffer as invalid by source id 0 */ 70889099Sfjoe PUTMEM(buffer << 9, 0); 70989099Sfjoe s = splimp(); 71089099Sfjoe 71189099Sfjoe if (--sc->sc_rx_fillcount == 2 - 1) { 71289099Sfjoe 71389099Sfjoe /* was off, restart it on buffer just emptied */ 71489099Sfjoe sc->sc_rx_act = buffer; 71589099Sfjoe sc->sc_intmask |= CM_RI; 71689099Sfjoe 71789099Sfjoe /* this also clears the RI flag interupt: */ 71889099Sfjoe PUTREG(CMCMD, CM_RXBC(buffer)); 71989099Sfjoe PUTREG(CMSTAT, sc->sc_intmask); 72089099Sfjoe 72189099Sfjoe#ifdef CM_DEBUG 722104251Sbrooks if_printf(ifp, "srint: restarted rx on buf %d\n", buffer); 72389099Sfjoe#endif 72489099Sfjoe } 72589099Sfjoe splx(s); 72689099Sfjoe} 72789099Sfjoe 72889099Sfjoe__inline static void 72989099Sfjoecm_tint(sc, isr) 73089099Sfjoe struct cm_softc *sc; 73189099Sfjoe int isr; 73289099Sfjoe{ 73389099Sfjoe struct ifnet *ifp; 73489099Sfjoe 73589099Sfjoe int buffer; 73689099Sfjoe#ifdef CMTIMINGS 73789099Sfjoe int clknow; 73889099Sfjoe#endif 73989099Sfjoe 74089099Sfjoe ifp = &(sc->sc_arccom.ac_if); 74189099Sfjoe buffer = sc->sc_tx_act; 74289099Sfjoe 74389099Sfjoe /* 74489099Sfjoe * retransmit code: 74589099Sfjoe * Normal situtations first for fast path: 74689099Sfjoe * If acknowledgement received ok or broadcast, we're ok. 74789099Sfjoe * else if 74889099Sfjoe */ 74989099Sfjoe 75089099Sfjoe if (isr & CM_TMA || sc->sc_broadcast[buffer]) 75189099Sfjoe sc->sc_arccom.ac_if.if_opackets++; 75289099Sfjoe#ifdef CMRETRANSMIT 75389099Sfjoe else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0 75489099Sfjoe && --sc->sc_retransmits[buffer] > 0) { 75589099Sfjoe /* retransmit same buffer */ 75689099Sfjoe PUTREG(CMCMD, CM_TX(buffer)); 75789099Sfjoe return; 75889099Sfjoe } 75989099Sfjoe#endif 76089099Sfjoe else 76189099Sfjoe ifp->if_oerrors++; 76289099Sfjoe 76389099Sfjoe 76489099Sfjoe /* We know we can accept another buffer at this point. */ 76589099Sfjoe ifp->if_flags &= ~IFF_OACTIVE; 76689099Sfjoe 76789099Sfjoe if (--sc->sc_tx_fillcount > 0) { 76889099Sfjoe 76989099Sfjoe /* 77089099Sfjoe * start tx on other buffer. 77189099Sfjoe * This also clears the int flag 77289099Sfjoe */ 77389099Sfjoe buffer ^= 1; 77489099Sfjoe sc->sc_tx_act = buffer; 77589099Sfjoe 77689099Sfjoe /* 77789099Sfjoe * already given: 77889099Sfjoe * sc->sc_intmask |= CM_TA; 77989099Sfjoe * PUTREG(CMSTAT, sc->sc_intmask); 78089099Sfjoe */ 78189099Sfjoe PUTREG(CMCMD, CM_TX(buffer)); 78289099Sfjoe /* init watchdog timer */ 78389099Sfjoe ifp->if_timer = ARCTIMEOUT; 78489099Sfjoe 78589099Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 1) 786104251Sbrooks if_printf(ifp, 787104251Sbrooks "tint: starting tx on buffer %d, status 0x%02x\n", 788104251Sbrooks buffer, GETREG(CMSTAT)); 78989099Sfjoe#endif 79089099Sfjoe } else { 79189099Sfjoe /* have to disable TX interrupt */ 79289099Sfjoe sc->sc_intmask &= ~CM_TA; 79389099Sfjoe PUTREG(CMSTAT, sc->sc_intmask); 79489099Sfjoe /* ... and watchdog timer */ 79589099Sfjoe ifp->if_timer = 0; 79689099Sfjoe 79789099Sfjoe#ifdef CM_DEBUG 798104251Sbrooks if_printf(ifp, "tint: no more buffers to send, status 0x%02x\n", 799104251Sbrooks GETREG(CMSTAT)); 80089099Sfjoe#endif 80189099Sfjoe } 80289099Sfjoe 80389099Sfjoe /* XXXX TODO */ 80489099Sfjoe#ifdef CMSOFTCOPY 80589099Sfjoe /* schedule soft int to fill a new buffer for us */ 80689099Sfjoe softintr_schedule(sc->sc_txcookie); 80789099Sfjoe#else 80889099Sfjoe /* call it directly */ 80989099Sfjoe cm_start(ifp); 81089099Sfjoe#endif 81189099Sfjoe} 81289099Sfjoe 81389099Sfjoe/* 81489099Sfjoe * Our interrupt routine 81589099Sfjoe */ 81689099Sfjoevoid 81789099Sfjoecmintr(arg) 81889099Sfjoe void *arg; 81989099Sfjoe{ 82089099Sfjoe struct cm_softc *sc = arg; 82189099Sfjoe struct ifnet *ifp = &sc->sc_arccom.ac_if; 82289099Sfjoe 82389099Sfjoe u_char isr, maskedisr; 82489099Sfjoe int buffer; 82589099Sfjoe u_long newsec; 82689099Sfjoe 82789099Sfjoe isr = GETREG(CMSTAT); 82889099Sfjoe maskedisr = isr & sc->sc_intmask; 82989099Sfjoe if (!maskedisr) 83089099Sfjoe return; 83189099Sfjoe do { 83289099Sfjoe 833109771Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 1) 834104251Sbrooks if_printf(ifp, "intr: status 0x%02x, intmask 0x%02x\n", 835104251Sbrooks isr, sc->sc_intmask); 83689099Sfjoe#endif 83789099Sfjoe 83889099Sfjoe if (maskedisr & CM_POR) { 83989099Sfjoe /* 84089099Sfjoe * XXX We should never see this. Don't bother to store 84189099Sfjoe * the address. 84289099Sfjoe * sc->sc_arccom.ac_anaddr = GETMEM(CMMACOFF); 84389099Sfjoe */ 84489099Sfjoe PUTREG(CMCMD, CM_CLR(CLR_POR)); 84589099Sfjoe log(LOG_WARNING, 84689099Sfjoe "%s%d: intr: got spurious power on reset int\n", 84789099Sfjoe ifp->if_name, ifp->if_unit); 84889099Sfjoe } 84989099Sfjoe 85089099Sfjoe if (maskedisr & CM_RECON) { 85189099Sfjoe /* 85289099Sfjoe * we dont need to: 85389099Sfjoe * PUTREG(CMCMD, CM_CONF(CONF_LONG)); 85489099Sfjoe */ 85589099Sfjoe PUTREG(CMCMD, CM_CLR(CLR_RECONFIG)); 85689099Sfjoe sc->sc_arccom.ac_if.if_collisions++; 85789099Sfjoe 85889099Sfjoe /* 85989099Sfjoe * If less than 2 seconds per reconfig: 86089099Sfjoe * If ARC_EXCESSIVE_RECONFIGS 86189099Sfjoe * since last burst, complain and set treshold for 86289099Sfjoe * warnings to ARC_EXCESSIVE_RECONS_REWARN. 86389099Sfjoe * 86489099Sfjoe * This allows for, e.g., new stations on the cable, or 86589099Sfjoe * cable switching as long as it is over after 86689099Sfjoe * (normally) 16 seconds. 86789099Sfjoe * 86889099Sfjoe * XXX TODO: check timeout bits in status word and 86989099Sfjoe * double time if necessary. 87089099Sfjoe */ 87189099Sfjoe 87289099Sfjoe callout_stop(&sc->sc_recon_ch); 87389099Sfjoe newsec = time_second; 87489099Sfjoe if ((newsec - sc->sc_recontime <= 2) && 87589099Sfjoe (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) { 87689099Sfjoe log(LOG_WARNING, 87789099Sfjoe "%s%d: excessive token losses, " 87889099Sfjoe "cable problem?\n", 87989099Sfjoe ifp->if_name, ifp->if_unit); 88089099Sfjoe } 88189099Sfjoe sc->sc_recontime = newsec; 88289099Sfjoe callout_reset(&sc->sc_recon_ch, 15 * hz, 88389099Sfjoe cm_reconwatch, (void *)sc); 88489099Sfjoe } 88589099Sfjoe 88689099Sfjoe if (maskedisr & CM_RI) { 88789099Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 1) 888104251Sbrooks if_printf(ifp, "intr: hard rint, act %d\n", 889104251Sbrooks sc->sc_rx_act); 89089099Sfjoe#endif 89189099Sfjoe 89289099Sfjoe buffer = sc->sc_rx_act; 89389099Sfjoe /* look if buffer is marked invalid: */ 894109771Sfjoe if (GETMEM(buffer * 512) == 0) { 89589099Sfjoe /* 89689099Sfjoe * invalid marked buffer (or illegally 89789099Sfjoe * configured sender) 89889099Sfjoe */ 89989099Sfjoe log(LOG_WARNING, 90089099Sfjoe "%s%d: spurious RX interupt or sender 0 " 90189099Sfjoe " (ignored)\n", ifp->if_name, ifp->if_unit); 90289099Sfjoe /* 90389099Sfjoe * restart receiver on same buffer. 90489099Sfjoe * XXX maybe better reset interface? 90589099Sfjoe */ 90689099Sfjoe PUTREG(CMCMD, CM_RXBC(buffer)); 90789099Sfjoe } else { 90889099Sfjoe if (++sc->sc_rx_fillcount > 1) { 90989099Sfjoe sc->sc_intmask &= ~CM_RI; 91089099Sfjoe PUTREG(CMSTAT, sc->sc_intmask); 91189099Sfjoe } else { 91289099Sfjoe buffer ^= 1; 91389099Sfjoe sc->sc_rx_act = buffer; 91489099Sfjoe 91589099Sfjoe /* 91689099Sfjoe * Start receiver on other receive 91789099Sfjoe * buffer. This also clears the RI 91889099Sfjoe * interupt flag. 91989099Sfjoe */ 92089099Sfjoe PUTREG(CMCMD, CM_RXBC(buffer)); 92189099Sfjoe /* in RX intr, so mask is ok for RX */ 92289099Sfjoe 92389099Sfjoe#ifdef CM_DEBUG 924104251Sbrooks if_printf(ifp, "strt rx for buf %d, " 92589099Sfjoe "stat 0x%02x\n", 92689099Sfjoe sc->sc_rx_act, GETREG(CMSTAT)); 92789099Sfjoe#endif 92889099Sfjoe } 92989099Sfjoe 93089099Sfjoe#ifdef CMSOFTCOPY 93189099Sfjoe /* 93289099Sfjoe * this one starts a soft int to copy out 93389099Sfjoe * of the hw 93489099Sfjoe */ 93589099Sfjoe softintr_schedule(sc->sc_rxcookie); 93689099Sfjoe#else 93789099Sfjoe /* this one does the copy here */ 93889099Sfjoe cm_srint(sc); 93989099Sfjoe#endif 94089099Sfjoe } 94189099Sfjoe } 94289099Sfjoe if (maskedisr & CM_TA) { 94389099Sfjoe cm_tint(sc, isr); 94489099Sfjoe } 94589099Sfjoe isr = GETREG(CMSTAT); 94689099Sfjoe maskedisr = isr & sc->sc_intmask; 94789099Sfjoe } while (maskedisr); 948109771Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 1) 949104251Sbrooks if_printf(ifp, "intr (exit): status 0x%02x, intmask 0x%02x\n", 950104251Sbrooks isr, sc->sc_intmask); 95189099Sfjoe#endif 95289099Sfjoe} 95389099Sfjoe 95489099Sfjoevoid 95589099Sfjoecm_reconwatch(arg) 95689099Sfjoe void *arg; 95789099Sfjoe{ 95889099Sfjoe struct cm_softc *sc = arg; 95989099Sfjoe struct ifnet *ifp = &sc->sc_arccom.ac_if; 96089099Sfjoe 96189099Sfjoe if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) { 96289099Sfjoe sc->sc_reconcount = 0; 96389099Sfjoe log(LOG_WARNING, "%s%d: token valid again.\n", 96489099Sfjoe ifp->if_name, ifp->if_unit); 96589099Sfjoe } 96689099Sfjoe sc->sc_reconcount = 0; 96789099Sfjoe} 96889099Sfjoe 96989099Sfjoe 97089099Sfjoe/* 97189099Sfjoe * Process an ioctl request. 97289099Sfjoe * This code needs some work - it looks pretty ugly. 97389099Sfjoe */ 97489099Sfjoeint 97589099Sfjoecm_ioctl(ifp, command, data) 97689099Sfjoe struct ifnet *ifp; 97789099Sfjoe u_long command; 97889099Sfjoe caddr_t data; 97989099Sfjoe{ 98089099Sfjoe struct cm_softc *sc; 98189099Sfjoe struct ifaddr *ifa; 98289099Sfjoe struct ifreq *ifr; 98389099Sfjoe int s, error; 98489099Sfjoe 98589099Sfjoe error = 0; 98689099Sfjoe sc = ifp->if_softc; 98789099Sfjoe ifa = (struct ifaddr *)data; 98889099Sfjoe ifr = (struct ifreq *)data; 98989099Sfjoe s = splimp(); 99089099Sfjoe 99189099Sfjoe#if defined(CM_DEBUG) && (CM_DEBUG > 2) 992104251Sbrooks if_printf(ifp, "ioctl() called, cmd = 0x%lx\n", command); 99389099Sfjoe#endif 99489099Sfjoe 99589099Sfjoe switch (command) { 99689099Sfjoe case SIOCSIFADDR: 997109771Sfjoe case SIOCGIFADDR: 99889099Sfjoe case SIOCADDMULTI: 99989099Sfjoe case SIOCDELMULTI: 100089099Sfjoe case SIOCSIFMTU: 100189099Sfjoe error = arc_ioctl(ifp, command, data); 100289099Sfjoe break; 100389099Sfjoe 100489099Sfjoe case SIOCSIFFLAGS: 100589099Sfjoe if ((ifp->if_flags & IFF_UP) == 0 && 100689099Sfjoe (ifp->if_flags & IFF_RUNNING) != 0) { 100789099Sfjoe /* 100889099Sfjoe * If interface is marked down and it is running, 100989099Sfjoe * then stop it. 101089099Sfjoe */ 101189099Sfjoe cm_stop(sc); 101289099Sfjoe ifp->if_flags &= ~IFF_RUNNING; 101389099Sfjoe } else if ((ifp->if_flags & IFF_UP) != 0 && 101489099Sfjoe (ifp->if_flags & IFF_RUNNING) == 0) { 101589099Sfjoe /* 101689099Sfjoe * If interface is marked up and it is stopped, then 101789099Sfjoe * start it. 101889099Sfjoe */ 101989099Sfjoe cm_init(sc); 102089099Sfjoe } 102189099Sfjoe break; 102289099Sfjoe 102389099Sfjoe default: 102489099Sfjoe error = EINVAL; 102589099Sfjoe break; 102689099Sfjoe } 102789099Sfjoe 102889099Sfjoe splx(s); 102989099Sfjoe return (error); 103089099Sfjoe} 103189099Sfjoe 103289099Sfjoe/* 103389099Sfjoe * watchdog routine for transmitter. 103489099Sfjoe * 103589099Sfjoe * We need this, because else a receiver whose hardware is alive, but whose 103689099Sfjoe * software has not enabled the Receiver, would make our hardware wait forever 103789099Sfjoe * Discovered this after 20 times reading the docs. 103889099Sfjoe * 1039108470Sschweikh * Only thing we do is disable transmitter. We'll get a transmit timeout, 104089099Sfjoe * and the int handler will have to decide not to retransmit (in case 104189099Sfjoe * retransmission is implemented). 104289099Sfjoe * 104389099Sfjoe * This one assumes being called inside splimp() 104489099Sfjoe */ 104589099Sfjoe 104689099Sfjoevoid 104789099Sfjoecm_watchdog(ifp) 104889099Sfjoe struct ifnet *ifp; 104989099Sfjoe{ 105089099Sfjoe struct cm_softc *sc = ifp->if_softc; 105189099Sfjoe 105289099Sfjoe PUTREG(CMCMD, CM_TXDIS); 105389099Sfjoe return; 105489099Sfjoe} 1055