diff options
author | phk <phk@FreeBSD.org> | 2000-04-26 20:16:56 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2000-04-26 20:16:56 +0000 |
commit | c816580dfb530d84c2396d9f0d10a9f8e44d4ea4 (patch) | |
tree | 9754dfd8db6a41796c38824d131bd2d9369933e2 /sys/dev/lmc/if_lmc.c | |
parent | a0363301237e7450b90e5d8fe9242958c75bd43d (diff) | |
download | FreeBSD-src-c816580dfb530d84c2396d9f0d10a9f8e44d4ea4.zip FreeBSD-src-c816580dfb530d84c2396d9f0d10a9f8e44d4ea4.tar.gz |
Driver for DEC "Tulip" based WAN cards from LanMedia Corporation.
This driver should support both the SSI (V.35 etc) E1/T1 unchannelized,
DS3 and HSSI cards. Only tested on the SSI card.
More info at: http://www.lanmedia.com
Thanks to LanMedia for donating two LMC1000P cards.
if_de.c driver modified by: LanMedia
NetGraphification by: Stephen Kiernan <sk-ports@vegamuse.org>
Diffstat (limited to 'sys/dev/lmc/if_lmc.c')
-rw-r--r-- | sys/dev/lmc/if_lmc.c | 916 |
1 files changed, 521 insertions, 395 deletions
diff --git a/sys/dev/lmc/if_lmc.c b/sys/dev/lmc/if_lmc.c index 0753c72..f230620 100644 --- a/sys/dev/lmc/if_lmc.c +++ b/sys/dev/lmc/if_lmc.c @@ -1,10 +1,7 @@ -/* $FreeBSD$ */ -/* From NetBSD: if_de.c,v 1.56.2.1 1997/10/27 02:13:25 thorpej Exp */ -/* $Id: if_lmc.c,v 1.9 1999/02/19 15:08:42 explorer Exp $ */ - /*- * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) * Copyright (c) LAN Media Corporation 1998, 1999. + * Copyright (c) 2000 Stephen Kiernan (sk-ports@vegamuse.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,103 +22,40 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + * From NetBSD: if_de.c,v 1.56.2.1 1997/10/27 02:13:25 thorpej Exp + * $Id: if_lmc.c,v 1.9 1999/02/19 15:08:42 explorer Exp $ */ char lmc_version[] = "BSD 1.1"; +#include "opt_netgraph.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> #include <sys/socket.h> -#include <sys/ioctl.h> #include <sys/errno.h> #include <sys/malloc.h> #include <sys/kernel.h> -#include <sys/proc.h> /* only for declaration of wakeup() used by vm.h */ -#if defined(__FreeBSD__) #include <machine/clock.h> -#elif defined(__bsdi__) || defined(__NetBSD__) -#include <sys/device.h> -#endif - -#if defined(__NetBSD__) -#include <dev/pci/pcidevs.h> -#include "rnd.h" -#if NRND > 0 -#include <sys/rnd.h> -#endif -#endif #include <net/if.h> -#include <net/if_types.h> -#include <net/if_dl.h> -#include <net/netisr.h> - -#include "bpfilter.h" -#if NBPFILTER > 0 -#include <net/bpf.h> -#include <net/bpfdesc.h> -#endif +#include <sys/syslog.h> #include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> - -#if defined(__FreeBSD__) || defined(__NetBSD__) -#include <net/if_sppp.h> -#endif -#if defined(__bsdi__) -#if INET -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#endif - -#include <net/netisr.h> -#include <net/if.h> -#include <net/netisr.h> -#include <net/if_types.h> -#include <net/if_p2p.h> -#include <net/if_c_hdlc.h> -#endif +#include <netgraph/ng_message.h> +#include <netgraph/ng_parse.h> +#include <netgraph/netgraph.h> -#if defined(__FreeBSD__) #include <vm/pmap.h> #include <pci.h> -#if NPCI > 0 #include <pci/pcivar.h> #include <pci/dc21040reg.h> -#define INCLUDE_PATH_PREFIX "pci/" -#endif -#endif /* __FreeBSD__ */ - -#if defined(__bsdi__) -#include <i386/pci/ic/dc21040.h> -#include <i386/isa/isa.h> -#include <i386/isa/icu.h> -#include <i386/isa/dma.h> -#include <i386/isa/isavar.h> -#include <i386/pci/pci.h> - -#define INCLUDE_PATH_PREFIX "i386/pci/" -#endif /* __bsdi__ */ - -#if defined(__NetBSD__) -#include <machine/bus.h> -#if defined(__alpha__) -#include <machine/intr.h> -#endif -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> -#include <dev/ic/dc21040reg.h> -#define INCLUDE_PATH_PREFIX "dev/pci/" -#endif /* __NetBSD__ */ +#define INCLUDE_PATH_PREFIX "dev/lmc/" -/* - * Intel CPUs should use I/O mapped access. XXXMLG Is this true on NetBSD - * too? - */ +/* Intel CPUs should use I/O mapped access. */ #if defined(__i386__) #define LMC_IOMAPPED #endif @@ -130,8 +64,7 @@ char lmc_version[] = "BSD 1.1"; * This turns on all sort of debugging stuff and make the * driver much larger. */ -#if 0 -#define LMC_DEBUG +#ifdef LMC_DEBUG #define DP(x) printf x #else #define DP(x) @@ -153,41 +86,112 @@ typedef struct lmc___softc lmc_softc_t; typedef struct lmc___media lmc_media_t; typedef struct lmc___ctl lmc_ctl_t; -/* - * Sigh. Every OS puts these in different places. NetBSD and FreeBSD use - * a C preprocessor that allows this hack, but BSDI does not. - */ -#if defined(__NetBSD__) || defined(__FreeBSD__) -#include INCLUDE_PATH_PREFIX "if_lmcioctl.h" -#include INCLUDE_PATH_PREFIX "if_lmcvar.h" -#include INCLUDE_PATH_PREFIX "if_lmc_common.c" -#include INCLUDE_PATH_PREFIX "if_lmc_media.c" -#else /* BSDI */ -#include "i386/pci/if_lmcioctl.h" -#include "i386/pci/if_lmcvar.h" -#include "i386/pci/if_lmc_common.c" -#include "i386/pci/if_lmc_media.c" -#endif +#include "dev/lmc/if_lmcioctl.h" +#include "dev/lmc/if_lmcvar.h" +#include "dev/lmc/if_lmc_common.c" +#include "dev/lmc/if_lmc_media.c" /* * This module supports * the DEC 21140A pass 2.2 PCI Fast Ethernet Controller. */ static lmc_intrfunc_t lmc_intr_normal(void *); -static ifnet_ret_t lmc_ifstart_one(struct ifnet *ifp); -static ifnet_ret_t lmc_ifstart(struct ifnet *ifp); +static ifnet_ret_t lmc_ifstart(lmc_softc_t * const sc ); +static ifnet_ret_t lmc_ifstart_one(lmc_softc_t * const sc); static struct mbuf *lmc_txput(lmc_softc_t * const sc, struct mbuf *m); static void lmc_rx_intr(lmc_softc_t * const sc); -#if defined(__NetBSD__) || defined(__FreeBSD__) -static void lmc_watchdog(struct ifnet *ifp); -#endif -#if defined(__bsdi__) -static int lmc_watchdog(int); -#endif +static void lmc_watchdog(lmc_softc_t * const sc); static void lmc_ifup(lmc_softc_t * const sc); static void lmc_ifdown(lmc_softc_t * const sc); +#ifdef LMC_DEBUG +static void ng_lmc_dump_packet(struct mbuf *m); +#endif /* LMC_DEBUG */ +static void ng_lmc_watchdog_frame(void *arg); +static void ng_lmc_init(void *ignored); + +static ng_constructor_t ng_lmc_constructor; +static ng_rcvmsg_t ng_lmc_rcvmsg; +static ng_shutdown_t ng_lmc_rmnode; +static ng_newhook_t ng_lmc_newhook; +/*static ng_findhook_t ng_lmc_findhook; */ +static ng_connect_t ng_lmc_connect; +static ng_rcvdata_t ng_lmc_rcvdata; +static ng_disconnect_t ng_lmc_disconnect; + +/* Parse type for struct lmc_ctl */ +static const struct ng_parse_fixedarray_info ng_lmc_ctl_cardspec_info = { + &ng_parse_int32_type, + 7, + NULL +}; + +static const struct ng_parse_type ng_lmc_ctl_cardspec_type = { + &ng_parse_fixedarray_type, + &ng_lmc_ctl_cardspec_info +}; + +static const struct ng_parse_struct_info ng_lmc_ctl_type_info = { + { + { "cardtype", &ng_parse_int32_type }, + { "clock_source", &ng_parse_int32_type }, + { "clock_rate", &ng_parse_int32_type }, + { "crc_length", &ng_parse_int32_type }, + { "cable_length", &ng_parse_int32_type }, + { "scrambler_onoff", &ng_parse_int32_type }, + { "cable_type", &ng_parse_int32_type }, + { "keepalive_onoff", &ng_parse_int32_type }, + { "ticks", &ng_parse_int32_type }, + { "cardspec", &ng_lmc_ctl_cardspec_type }, + { "circuit_type", &ng_parse_int32_type }, + { NULL }, + } +}; + +static const struct ng_parse_type ng_lmc_ctl_type = { + &ng_parse_struct_type, + &ng_lmc_ctl_type_info +}; + + +/* List of commands and how to convert arguments to/from ASCII */ +static const struct ng_cmdlist ng_lmc_cmdlist[] = { + { + NG_LMC_COOKIE, + NGM_LMC_GET_CTL, + "getctl", + NULL, + &ng_lmc_ctl_type, + }, + { + NG_LMC_COOKIE, + NGM_LMC_SET_CTL, + "setctl", + &ng_lmc_ctl_type, + NULL + }, + { 0 } +}; + +static struct ng_type typestruct = { + NG_VERSION, + NG_LMC_NODE_TYPE, + NULL, + ng_lmc_constructor, + ng_lmc_rcvmsg, + ng_lmc_rmnode, + ng_lmc_newhook, + NULL, + ng_lmc_connect, + ng_lmc_rcvdata, + ng_lmc_rcvdata, + ng_lmc_disconnect, + ng_lmc_cmdlist +}; + +static int ng_lmc_done_init = 0; + /* * Code the read the SROM and MII bit streams (I2C) @@ -381,22 +385,9 @@ lmc_read_macaddr(lmc_softc_t * const sc) * Check to make certain there is a signal from the modem, and flicker * lights as needed. */ -#if defined(__NetBSD__) || defined(__FreeBSD__) static void -lmc_watchdog(struct ifnet *ifp) -#endif -#if defined(__bsdi__) -static int -lmc_watchdog(int unit) -#endif +lmc_watchdog(lmc_softc_t * const sc) { -#if defined(__NetBSD__) || defined(__FreeBSD__) - lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp); -#endif -#if defined(__bsdi__) - lmc_softc_t * const sc = LMC_UNIT_TO_SOFTC(unit); - struct ifnet *ifp = &sc->lmc_if; -#endif int state; u_int32_t ostatus; u_int32_t link_status; @@ -439,7 +430,7 @@ lmc_watchdog(int unit) LMC_CSR_WRITE(sc, csr_gp_timer, 0xffffffffUL); sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff); - ifp->if_timer = 1; + sc->lmc_out_dog = LMC_DOG_HOLDOFF; } /* @@ -449,7 +440,8 @@ lmc_watchdog(int unit) static void lmc_ifup(lmc_softc_t * const sc) { - sc->lmc_if.if_timer = 0; + untimeout(ng_lmc_watchdog_frame, sc, sc->lmc_handle); + sc->lmc_running = 0; lmc_dec_reset(sc); lmc_reset(sc); @@ -478,7 +470,9 @@ lmc_ifup(lmc_softc_t * const sc) sc->lmc_cmdmode |= TULIP_CMD_RXRUN; LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode); - sc->lmc_if.if_timer = 1; + untimeout(ng_lmc_watchdog_frame, sc, sc->lmc_handle); + sc->lmc_handle = timeout(ng_lmc_watchdog_frame, sc, hz); + sc->lmc_running = 1; } /* @@ -488,7 +482,8 @@ lmc_ifup(lmc_softc_t * const sc) static void lmc_ifdown(lmc_softc_t * const sc) { - sc->lmc_if.if_timer = 0; + untimeout(ng_lmc_watchdog_frame, sc, sc->lmc_handle); + sc->lmc_running = 0; sc->lmc_flags &= ~LMC_IFUP; sc->lmc_media->set_link_status(sc, 0); @@ -503,7 +498,6 @@ static void lmc_rx_intr(lmc_softc_t * const sc) { lmc_ringinfo_t * const ri = &sc->lmc_rxinfo; - struct ifnet * const ifp = &sc->lmc_if; int fillok = 1; sc->lmc_rxtick++; @@ -584,32 +578,23 @@ lmc_rx_intr(lmc_softc_t * const sc) else total_len -= 4; + sc->lmc_inbytes += total_len; + sc->lmc_inlast = 0; + if ((sc->lmc_flags & LMC_RXIGNORE) == 0 && ((eop->d_status & LMC_DSTS_ERRSUM) == 0 -#ifdef BIG_PACKET - || (total_len <= sc->lmc_if.if_mtu + PPP_HEADER_LEN - && (eop->d_status & TULIP_DSTS_RxOVERFLOW) == 0) -#endif )) { me->m_len = total_len - last_offset; -#if NBPFILTER > 0 - if (sc->lmc_bpf != NULL) { - if (me == ms) - LMC_BPF_TAP(sc, mtod(ms, caddr_t), total_len); - else - LMC_BPF_MTAP(sc, ms); - } -#endif sc->lmc_flags |= LMC_RXACT; accept = 1; } else { - ifp->if_ierrors++; + sc->lmc_ierrors++; if (eop->d_status & TULIP_DSTS_RxOVERFLOW) { sc->lmc_dot3stats.dot3StatsInternalMacReceiveErrors++; } } - ifp->if_ipackets++; + sc->lmc_ipackets++; if (++eop == ri->ri_last) eop = ri->ri_first; ri->ri_nextin = eop; @@ -640,13 +625,8 @@ lmc_rx_intr(lmc_softc_t * const sc) } if (accept) { ms->m_pkthdr.len = total_len; - ms->m_pkthdr.rcvif = ifp; -#if defined(__NetBSD__) || defined(__FreeBSD__) - sppp_input(ifp, ms); -#endif -#if defined(__bsdi__) - sc->lmc_p2pcom.p2p_input(&sc->lmc_p2pcom, ms); -#endif + ms->m_pkthdr.rcvif = NULL; + ng_send_data(sc->lmc_hook, ms, NULL); } ms = m0; } @@ -711,7 +691,7 @@ lmc_tx_intr(lmc_softc_t * const sc) } xmits++; if (d_status & LMC_DSTS_ERRSUM) { - sc->lmc_if.if_oerrors++; + sc->lmc_oerrors++; if (d_status & TULIP_DSTS_TxUNDERFLOW) sc->lmc_dot3stats.dot3StatsInternalTransmitUnderflows++; } else { @@ -725,13 +705,14 @@ lmc_tx_intr(lmc_softc_t * const sc) ri->ri_free++; descs++; - sc->lmc_if.if_flags &= ~IFF_OACTIVE; + /*sc->lmc_if.if_flags &= ~IFF_OACTIVE;*/ + sc->lmc_out_deficit++; } /* * If nothing left to transmit, disable the timer. * Else if progress, reset the timer back to 2 ticks. */ - sc->lmc_if.if_opackets += xmits; + sc->lmc_opackets += xmits; return descs; } @@ -749,12 +730,6 @@ lmc_intr_handler(lmc_softc_t * const sc, int *progress_p) while ((csr = LMC_CSR_READ(sc, csr_status)) & sc->lmc_intrmask) { -#if defined(__NetBSD__) -#if NRND > 0 - rnd_add_uint32(&sc->lmc_rndsource, csr); -#endif -#endif - *progress_p = 1; LMC_CSR_WRITE(sc, csr_status, csr); @@ -825,7 +800,7 @@ lmc_intr_handler(lmc_softc_t * const sc, int *progress_p) lmc_tx_intr(sc); if (sc->lmc_flags & LMC_WANTTXSTART) - lmc_ifstart(&sc->lmc_if); + lmc_ifstart(sc); } } @@ -1065,7 +1040,8 @@ lmc_txput(lmc_softc_t * const sc, struct mbuf *m) * switch back to the single queueing ifstart. */ sc->lmc_flags &= ~LMC_WANTTXSTART; - sc->lmc_if.if_start = lmc_ifstart_one; + sc->lmc_xmit_busy = 0; + sc->lmc_out_dog = 0; /* * If we want a txstart, there must be not enough space in the @@ -1077,297 +1053,455 @@ lmc_txput(lmc_softc_t * const sc, struct mbuf *m) * WANTTXSTART thereby causing TXINTR to be cleared. */ finish: - if (sc->lmc_flags & LMC_WANTTXSTART) { - sc->lmc_if.if_flags |= IFF_OACTIVE; - sc->lmc_if.if_start = lmc_ifstart; - } return m; } /* - * This routine is entered at splnet() (splsoftnet() on NetBSD) + * These routines gets called at device spl */ -static int -lmc_ifioctl(struct ifnet * ifp, ioctl_cmd_t cmd, caddr_t data) -{ - lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp); -#if defined(__NetBSD__) || defined(__FreeBSD__) - lmc_spl_t s; -#endif - int error = 0; - struct ifreq *ifr = (struct ifreq *)data; - u_int32_t new_state; - u_int32_t old_state; - lmc_ctl_t ctl; - -#if defined(__NetBSD__) || defined(__FreeBSD__) - s = LMC_RAISESPL(); -#endif - - switch (cmd) { - case LMCIOCGINFO: - error = copyout(&sc->ictl, ifr->ifr_data, sizeof(lmc_ctl_t)); - goto out; - break; - - case LMCIOCSINFO: -#if 0 /* XXX */ - error = suser(p->p_ucred, &p->p_acflag); - if (error) - goto out; -#endif - - error = copyin(ifr->ifr_data, &ctl, sizeof(lmc_ctl_t)); - if (error != 0) - goto out; +static ifnet_ret_t +lmc_ifstart(lmc_softc_t * const sc) +{ + struct mbuf *m; - sc->lmc_media->set_status(sc, &ctl); + if (sc->lmc_flags & LMC_IFUP) { + sc->lmc_xmit_busy = 1; + for(;;) { + struct ifqueue *q = &sc->lmc_xmitq_hipri; + IF_DEQUEUE(q, m); + if (m == NULL) { + q = &sc->lmc_xmitq; + IF_DEQUEUE(q, m); + } + if (m) { + sc->lmc_outbytes = m->m_pkthdr.len; + sc->lmc_opackets++; + if ((m = lmc_txput(sc, m)) != NULL) { + IF_PREPEND(q, m); + printf(LMC_PRINTF_FMT + ": lmc_txput failed\n", + LMC_PRINTF_ARGS); + break; + } + LMC_CSR_WRITE(sc, csr_txpoll, 1); + } + else + break; + } + } +} - goto out; - break; +static ifnet_ret_t +lmc_ifstart_one(lmc_softc_t * const sc) +{ + struct mbuf *m; -#if defined(__NetBSD__) || defined(__FreeBSD__) - case SIOCSIFMTU: - /* - * Don't allow the MTU to get larger than we can handle - */ - if (ifr->ifr_mtu > LMC_MTU) { - error = EINVAL; - goto out; + if ((sc->lmc_flags & LMC_IFUP)) { + struct ifqueue *q = &sc->lmc_xmitq_hipri; + IF_DEQUEUE(q, m); + if (m == NULL) { + q = &sc->lmc_xmitq; + IF_DEQUEUE(q, m); + } + if (m) { + sc->lmc_outbytes += m->m_pkthdr.len; + sc->lmc_opackets++; + if ((m = lmc_txput(sc, m)) != NULL) { + IF_PREPEND(q, m); + } + LMC_CSR_WRITE(sc, csr_txpoll, 1); } -#endif } +} -#if defined(__NetBSD__) || defined(__FreeBSD__) +/* + * Set up the OS interface magic and attach to the operating system + * network services. + */ +static int +lmc_attach(lmc_softc_t * const sc) +{ /* - * call the sppp ioctl layer + * we have found a node, make sure our 'type' is availabe. */ - error = sppp_ioctl(ifp, cmd, data); - if (error != 0) - goto out; -#endif - -#if defined(__bsdi__) - error = p2p_ioctl(ifp, cmd, data); -#endif + if (ng_lmc_done_init == 0) ng_lmc_init(NULL); + if (ng_make_node_common(&typestruct, &sc->lmc_node) != 0) + return (0); + sc->lmc_node->private = sc; + callout_handle_init(&sc->lmc_handle); + sc->lmc_xmitq.ifq_maxlen = IFQ_MAXLEN; + sc->lmc_xmitq_hipri.ifq_maxlen = IFQ_MAXLEN; + sprintf(sc->lmc_nodename, "%s%d", NG_LMC_NODE_TYPE, sc->lmc_unit); + if (ng_name_node(sc->lmc_node, sc->lmc_nodename)) { + ng_rmnode(sc->lmc_node); + ng_unref(sc->lmc_node); + return (0); + } + sc->lmc_running = 0; -#if defined(__NetBSD__) || defined(__FreeBSD__) /* - * If we are transitioning from up to down or down to up, call - * our init routine. + * turn off those LEDs... */ - new_state = ifp->if_flags & IFF_UP; - old_state = sc->lmc_flags & LMC_IFUP; - - if (new_state && !old_state) - lmc_ifup(sc); - else if (!new_state && old_state) - lmc_ifdown(sc); -#endif - - out: -#if defined(__NetBSD__) || defined(__FreeBSD__) - LMC_RESTORESPL(s); -#endif + sc->lmc_miireg16 |= LMC_MII16_LED_ALL; + lmc_led_on(sc, LMC_MII16_LED0); - return error; + return 1; } -/* - * These routines gets called at device spl (from sppp_output). - */ +static void +lmc_initring(lmc_softc_t * const sc, lmc_ringinfo_t * const ri, + tulip_desc_t *descs, int ndescs) +{ + ri->ri_max = ndescs; + ri->ri_first = descs; + ri->ri_last = ri->ri_first + ri->ri_max; + bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); + ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; +} -#if defined(__NetBSD__) || defined(__FreeBSD__) -static ifnet_ret_t -lmc_ifstart(struct ifnet * const ifp) + + +#ifdef LMC_DEBUG +static void +ng_lmc_dump_packet(struct mbuf *m) { - lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp); - struct mbuf *m; + int i; - if (sc->lmc_flags & LMC_IFUP) { - while (sppp_isempty(ifp) == 0) { - m = sppp_dequeue(ifp); - if ((m = lmc_txput(sc, m)) != NULL) { - IF_PREPEND(&((struct sppp *)ifp)->pp_fastq, m); - break; - } + printf("mbuf: %d bytes, %s packet\n", m->m_len, + (m->m_type == MT_DATA)?"data":"other"); + + for (i=0; i < m->m_len; i++) { + if( (i % 8) == 0 ) { + if( i ) printf("\n"); + printf("\t"); } - LMC_CSR_WRITE(sc, csr_txpoll, 1); + else + printf(" "); + printf( "0x%02x", m->m_dat[i] ); } + printf("\n"); } +#endif /* LMC_DEBUG */ -static ifnet_ret_t -lmc_ifstart_one(struct ifnet * const ifp) +/* Device timeout/watchdog routine */ +static void +ng_lmc_watchdog_frame(void *arg) { - lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp); - struct mbuf *m; - - if ((sc->lmc_flags & LMC_IFUP) && (sppp_isempty(ifp) == 0)) { - m = sppp_dequeue(ifp); - if ((m = lmc_txput(sc, m)) != NULL) { - IF_PREPEND(&((struct sppp *)ifp)->pp_fastq, m); - } - LMC_CSR_WRITE(sc, csr_txpoll, 1); + lmc_softc_t * sc = (lmc_softc_t *) arg; + int s; + int speed; + + if(sc->lmc_running == 0) + return; /* if we are not running let timeouts die */ + /* + * calculate the apparent throughputs + * XXX a real hack + */ + s = splimp(); + speed = sc->lmc_inbytes - sc->lmc_lastinbytes; + sc->lmc_lastinbytes = sc->lmc_inbytes; + if ( sc->lmc_inrate < speed ) + sc->lmc_inrate = speed; + speed = sc->lmc_outbytes - sc->lmc_lastoutbytes; + sc->lmc_lastoutbytes = sc->lmc_outbytes; + if ( sc->lmc_outrate < speed ) + sc->lmc_outrate = speed; + sc->lmc_inlast++; + splx(s); + + if ((sc->lmc_inlast > LMC_QUITE_A_WHILE) + && (sc->lmc_out_deficit > LMC_LOTS_OF_PACKETS)) { + log(LOG_ERR, "%s%d: No response from remote end\n", + sc->lmc_name, sc->lmc_unit); + s = splimp(); + lmc_ifdown(sc); + lmc_ifup(sc); + sc->lmc_inlast = sc->lmc_out_deficit = 0; + splx(s); + } else if (sc->lmc_xmit_busy) { + if (sc->lmc_out_dog == 0) { + log(LOG_ERR, "ar%d: Transmit failure.. no clock?\n", + sc->lmc_unit); + s = splimp(); + lmc_watchdog(sc); +#if 0 + lmc_ifdown(sc); + lmc_ifup(sc); +#endif + splx(s); + sc->lmc_inlast = sc->lmc_out_deficit = 0; + } else { + sc->lmc_out_dog--; + } } + lmc_watchdog(sc); + sc->lmc_handle = timeout(ng_lmc_watchdog_frame, sc, hz); } -#endif -#if defined(__bsdi__) -static ifnet_ret_t -lmc_ifstart(struct ifnet * const ifp) +/*********************************************************************** + * This section contains the methods for the Netgraph interface + ***********************************************************************/ +/* + * It is not possible or allowable to create a node of this type. + * If the hardware exists, it will already have created it. + */ +static int +ng_lmc_constructor(node_p *nodep) { - lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp); - struct mbuf *m; - struct ifqueue *ifq; + return (EINVAL); +} - if ((sc->lmc_flags & LMC_IFUP) == 0) - return; +/* + * give our ok for a hook to be added... + * If we are not running this should kick the device into life. + * We allow hooks called "control", "rawdata", and "debug". + * The hook's private info points to our stash of info about that + * device. + */ +static int +ng_lmc_newhook(node_p node, hook_p hook, const char *name) +{ + lmc_softc_t * sc = (lmc_softc_t *) node->private; + + /* + * check if it's our friend the debug hook + */ + if (strcmp(name, NG_LMC_HOOK_DEBUG) == 0) { + hook->private = NULL; /* paranoid */ + sc->lmc_debug_hook = hook; + return (0); + } + + /* + * Check for raw mode hook. + */ + if (strcmp(name, NG_LMC_HOOK_RAW) != 0) { + return (EINVAL); + } + hook->private = sc; + sc->lmc_hook = hook; + sc->lmc_datahooks++; + lmc_ifup(sc); + return (0); +} - for (;;) { - ifq = &sc->lmc_p2pcom.p2p_isnd; +/* + * incoming messages. + * Just respond to the generic TEXT_STATUS message + */ +static int +ng_lmc_rcvmsg(node_p node, + struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr) +{ + lmc_softc_t *sc = (lmc_softc_t *) node->private; + struct ng_mesg *resp = NULL; + int error = 0; - m = ifq->ifq_head; - if (m == NULL) { - ifq = &sc->lmc_if.if_snd; - m = ifq->ifq_head; - } - if (m == NULL) - break; - IF_DEQUEUE(ifq, m); + switch (msg->header.typecookie) { + case NG_LMC_COOKIE: + switch (msg->header.cmd) { + case NGM_LMC_GET_CTL: + { + lmc_ctl_t *ctl; - m = lmc_txput(sc, m); - if (m != NULL) { - IF_PREPEND(ifq, m); + NG_MKRESPONSE(resp, msg, sizeof(*ctl), M_NOWAIT); + if (!resp) { + error = ENOMEM; + break; + } + ctl = (lmc_ctl_t *) resp->data; + memcpy( ctl, &sc->ictl, sizeof(*ctl) ); break; - } - } - - LMC_CSR_WRITE(sc, csr_txpoll, 1); -} - -static ifnet_ret_t -lmc_ifstart_one(struct ifnet * const ifp) -{ - lmc_softc_t * const sc = LMC_IFP_TO_SOFTC(ifp); - struct mbuf *m; - struct ifqueue *ifq; + } + case NGM_LMC_SET_CTL: + { + lmc_ctl_t *ctl; - if ((sc->lmc_flags & LMC_IFUP) == 0) - return; + if (msg->header.arglen != sizeof(*ctl)) { + error = EINVAL; + break; + } - ifq = &sc->lmc_p2pcom.p2p_isnd; + ctl = (lmc_ctl_t *) msg->data; + sc->lmc_media->set_status(sc, ctl); + break; + } + default: + error = EINVAL; /* unknown command */ + break; + } + break; + case NGM_GENERIC_COOKIE: + switch(msg->header.cmd) { + case NGM_TEXT_STATUS: { + char *arg; + int pos = 0; + int resplen = sizeof(struct ng_mesg) + 512; + MALLOC(resp, struct ng_mesg *, resplen, M_NETGRAPH, + M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + bzero(resp, resplen); + arg = (resp)->data; - m = ifq->ifq_head; - if (m == NULL) { - ifq = &sc->lmc_if.if_snd; - m = ifq->ifq_head; + /* + * Put in the throughput information. + */ + pos = sprintf(arg, "%ld bytes in, %ld bytes out\n" + "highest rate seen: %ld B/S in, " + "%ld B/S out\n", + sc->lmc_inbytes, sc->lmc_outbytes, + sc->lmc_inrate, sc->lmc_outrate); + pos += sprintf(arg + pos, "%ld output errors\n", + sc->lmc_oerrors); + pos += sprintf(arg + pos, "%ld input errors\n", + sc->lmc_ierrors); + + resp->header.version = NG_VERSION; + resp->header.arglen = strlen(arg) + 1; + resp->header.token = msg->header.token; + resp->header.typecookie = NG_LMC_COOKIE; + resp->header.cmd = msg->header.cmd; + strncpy(resp->header.cmdstr, "status", + NG_CMDSTRLEN); + } + break; + default: + error = EINVAL; + break; + } + break; + default: + error = EINVAL; + break; } - if (m == NULL) - return 0; - IF_DEQUEUE(ifq, m); - m = lmc_txput(sc, m); - if (m != NULL) - IF_PREPEND(ifq, m); + /* Take care of synchronous response, if any */ + if (rptr) + *rptr = resp; + else if (resp) + FREE(resp, M_NETGRAPH); - LMC_CSR_WRITE(sc, csr_txpoll, 1); + free(msg, M_NETGRAPH); + return (error); } -#endif - -#if defined(__bsdi__) -int -lmc_getmdm(struct p2pcom *pp, caddr_t b) -{ - lmc_softc_t *sc = LMC_UNIT_TO_SOFTC(pp->p2p_if.if_unit); - - if (sc->lmc_media->get_link_status(sc)) { - *(int *)b = TIOCM_CAR; - } else { - *(int *)b = 0; - } - return (0); +/* + * get data from another node and transmit it to the line + */ +static int +ng_lmc_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) +{ + int s; + int error = 0; + lmc_softc_t * sc = (lmc_softc_t *) hook->node->private; + struct ifqueue *xmitq_p; + + /* + * data doesn't come in from just anywhere (e.g control hook) + */ + if ( hook->private == NULL) { + error = ENETDOWN; + goto bad; + } + + /* + * Now queue the data for when it can be sent + */ + if (meta && meta->priority > 0) { + xmitq_p = (&sc->lmc_xmitq_hipri); + } else { + xmitq_p = (&sc->lmc_xmitq); + } + s = splimp(); + if (IF_QFULL(xmitq_p)) { + IF_DROP(xmitq_p); + splx(s); + error = ENOBUFS; + goto bad; + } + IF_ENQUEUE(xmitq_p, m); + lmc_ifstart_one(sc); + splx(s); + return (0); + +bad: + /* + * It was an error case. + * check if we need to free the mbuf, and then return the error + */ + NG_FREE_DATA(m, meta); + return (error); } -int -lmc_mdmctl(struct p2pcom *pp, int flag) +/* + * do local shutdown processing.. + * this node will refuse to go away, unless the hardware says to.. + * don't unref the node, or remove our name. just clear our links up. + */ +static int +ng_lmc_rmnode(node_p node) { - lmc_softc_t *sc = LMC_UNIT_TO_SOFTC(pp->p2p_if.if_unit); + lmc_softc_t * sc = (lmc_softc_t *) node->private; - sc->lmc_media->set_link_status(sc, flag); - - if (flag) - if ((sc->lmc_flags & LMC_IFUP) == 0) - lmc_ifup(sc); - else - if ((sc->lmc_flags & LMC_IFUP) == LMC_IFUP) - lmc_ifdown(sc); - - return (0); + lmc_ifdown(sc); + ng_cutlinks(node); + node->flags &= ~NG_INVALID; /* bounce back to life */ + return (0); +} +/* already linked */ +static int +ng_lmc_connect(hook_p hook) +{ + /* be really amiable and just say "YUP that's OK by me! " */ + return (0); } -#endif /* - * Set up the OS interface magic and attach to the operating system - * network services. + * notify on hook disconnection (destruction) + * + * For this type, removal of the last link resets tries to destroy the node. + * As the device still exists, the shutdown method will not actually + * destroy the node, but reset the device and leave it 'fresh' :) + * + * The node removal code will remove all references except that owned by the + * driver. */ -static void -lmc_attach(lmc_softc_t * const sc) +static int +ng_lmc_disconnect(hook_p hook) { - struct ifnet * const ifp = &sc->lmc_if; - - ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; - ifp->if_ioctl = lmc_ifioctl; - ifp->if_start = lmc_ifstart; - ifp->if_watchdog = lmc_watchdog; - ifp->if_timer = 1; - ifp->if_mtu = LMC_MTU; - -#if defined(__bsdi__) - ifp->if_type = IFT_NONE; - ifp->if_unit = (sc->lmc_dev.dv_unit); -#endif - - if_attach(ifp); - -#if defined(__NetBSD__) || defined(__FreeBSD__) - sppp_attach((struct ifnet *)&sc->lmc_sppp); - sc->lmc_sppp.pp_flags = PP_CISCO | PP_KEEPALIVE; -#endif -#if defined(__bsdi__) - sc->lmc_p2pcom.p2p_mdmctl = lmc_mdmctl; - sc->lmc_p2pcom.p2p_getmdm = lmc_getmdm; - p2p_attach(&sc->lmc_p2pcom); -#endif - -#if NBPFILTER > 0 - LMC_BPF_ATTACH(sc); -#endif - -#if defined(__NetBSD__) && NRND > 0 - rnd_attach_source(&sc->lmc_rndsource, sc->lmc_dev.dv_xname, - RND_TYPE_NET); -#endif - - /* - * turn off those LEDs... - */ - sc->lmc_miireg16 |= LMC_MII16_LED_ALL; - lmc_led_on(sc, LMC_MII16_LED0); + lmc_softc_t * sc = (lmc_softc_t *) hook->node->private; + int s; + /* + * If it's the data hook, then free resources etc. + */ + if (hook->private) { + s = splimp(); + sc->lmc_datahooks--; + if (sc->lmc_datahooks == 0) + lmc_ifdown(sc); + splx(s); + } else { + sc->lmc_debug_hook = NULL; + } + return (0); } - + +/* + * called during bootup + * or LKM loading to put this type into the list of known modules + */ static void -lmc_initring(lmc_softc_t * const sc, lmc_ringinfo_t * const ri, - tulip_desc_t *descs, int ndescs) +ng_lmc_init(void *ignored) { - ri->ri_max = ndescs; - ri->ri_first = descs; - ri->ri_last = ri->ri_first + ri->ri_max; - bzero((caddr_t) ri->ri_first, sizeof(ri->ri_first[0]) * ri->ri_max); - ri->ri_last[-1].d_flag = TULIP_DFLAG_ENDRING; + if (ng_newtype(&typestruct)) + printf("ng_lmc install failed\n"); + ng_lmc_done_init = 1; } /* @@ -1385,12 +1519,4 @@ lmc_initring(lmc_softc_t * const sc, lmc_ringinfo_t * const ri, -#if defined(__NetBSD__) -#include "dev/pci/if_lmc_nbsd.c" -#elif defined(__FreeBSD__) -#include "pci/if_lmc_fbsd.c" -#elif defined(__bsdi__) -#include "i386/pci/if_lmc_bsdi.c" -#else -#error "This driver only works on NetBSD, FreeBSD, or BSDi" -#endif +#include "dev/lmc/if_lmc_fbsd3.c" |