From owner-svn-src-head@FreeBSD.ORG Mon May 7 04:15:47 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 05F03106564A; Mon, 7 May 2012 04:15:47 +0000 (UTC) (envelope-from jmallett@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id E1A298FC19; Mon, 7 May 2012 04:15:46 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q474Fkms045878; Mon, 7 May 2012 04:15:46 GMT (envelope-from jmallett@svn.freebsd.org) Received: (from jmallett@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q474Fknx045874; Mon, 7 May 2012 04:15:46 GMT (envelope-from jmallett@svn.freebsd.org) Message-Id: <201205070415.q474Fknx045874@svn.freebsd.org> From: Juli Mallett Date: Mon, 7 May 2012 04:15:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r235117 - in head/sys: dev/gxemul/ether mips/conf mips/gxemul X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 May 2012 04:15:47 -0000 Author: jmallett Date: Mon May 7 04:15:46 2012 New Revision: 235117 URL: http://svn.freebsd.org/changeset/base/235117 Log: Add a trivial driver for the GXemul Ethernet device. Probably quite buggy and certainly non-optimal, but enough for basic networking use. Requested by: rwatson Added: head/sys/dev/gxemul/ether/ head/sys/dev/gxemul/ether/gxreg.h (contents, props changed) head/sys/dev/gxemul/ether/if_gx.c (contents, props changed) Modified: head/sys/mips/conf/GXEMUL head/sys/mips/gxemul/files.gxemul Added: head/sys/dev/gxemul/ether/gxreg.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/gxemul/ether/gxreg.h Mon May 7 04:15:46 2012 (r235117) @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2008-2012 Juli Mallett + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY 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$ + */ + +#ifndef _DEV_GXEMUL_ETHER_GXREG_H_ +#define _DEV_GXEMUL_ETHER_GXREG_H_ + +#define GXEMUL_ETHER_DEV_BASE (0x14000000) +#define GXEMUL_ETHER_DEV_IRQ (3) + +#define GXEMUL_ETHER_DEV_MTU (0x4000) + +#define GXEMUL_ETHER_DEV_BUFFER (0x0000) +#define GXEMUL_ETHER_DEV_STATUS (0x4000) +#define GXEMUL_ETHER_DEV_LENGTH (0x4010) +#define GXEMUL_ETHER_DEV_COMMAND (0x4020) +#define GXEMUL_ETHER_DEV_MAC (0x4040) + +#define GXEMUL_ETHER_DEV_FUNCTION(f) \ + (volatile uint64_t *)MIPS_PHYS_TO_DIRECT_UNCACHED(GXEMUL_ETHER_DEV_BASE + (f)) +#define GXEMUL_ETHER_DEV_READ(f) \ + (volatile uint64_t)*GXEMUL_ETHER_DEV_FUNCTION(f) +#define GXEMUL_ETHER_DEV_WRITE(f, v) \ + *GXEMUL_ETHER_DEV_FUNCTION(f) = (v) + +#define GXEMUL_ETHER_DEV_STATUS_RX_OK (0x01) +#define GXEMUL_ETHER_DEV_STATUS_RX_MORE (0x02) + +#define GXEMUL_ETHER_DEV_COMMAND_RX (0x00) +#define GXEMUL_ETHER_DEV_COMMAND_TX (0x01) + +#endif /* !_DEV_GXEMUL_ETHER_GXREG_H_ */ Added: head/sys/dev/gxemul/ether/if_gx.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/gxemul/ether/if_gx.c Mon May 7 04:15:46 2012 (r235117) @@ -0,0 +1,398 @@ +/*- + * Copyright (c) 2008-2012 Juli Mallett + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY 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$ + */ + +#include "opt_inet.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#endif + +#include + +#include + +struct gx_softc { + struct ifnet *sc_ifp; + device_t sc_dev; + unsigned sc_port; + int sc_flags; + struct ifmedia sc_ifmedia; + struct resource *sc_intr; + void *sc_intr_cookie; + struct mtx sc_mtx; +}; + +#define GXEMUL_ETHER_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define GXEMUL_ETHER_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) + +static void gx_identify(driver_t *, device_t); +static int gx_probe(device_t); +static int gx_attach(device_t); +static int gx_detach(device_t); +static int gx_shutdown(device_t); + +static void gx_init(void *); +static int gx_transmit(struct ifnet *, struct mbuf *); + +static int gx_medchange(struct ifnet *); +static void gx_medstat(struct ifnet *, struct ifmediareq *); + +static int gx_ioctl(struct ifnet *, u_long, caddr_t); + +static void gx_rx_intr(void *); + +static device_method_t gx_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, gx_identify), + DEVMETHOD(device_probe, gx_probe), + DEVMETHOD(device_attach, gx_attach), + DEVMETHOD(device_detach, gx_detach), + DEVMETHOD(device_shutdown, gx_shutdown), + + { 0, 0 } +}; + +static driver_t gx_driver = { + "gx", + gx_methods, + sizeof (struct gx_softc), +}; + +static devclass_t gx_devclass; + +DRIVER_MODULE(gx, nexus, gx_driver, gx_devclass, 0, 0); + +static void +gx_identify(driver_t *drv, device_t parent) +{ + BUS_ADD_CHILD(parent, 0, "gx", 0); +} + +static int +gx_probe(device_t dev) +{ + if (device_get_unit(dev) != 0) + return (ENXIO); + + device_set_desc(dev, "GXemul test Ethernet"); + + return (0); +} + +static int +gx_attach(device_t dev) +{ + struct ifnet *ifp; + struct gx_softc *sc; + uint8_t mac[6]; + int error; + int rid; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_port = device_get_unit(dev); + + /* Read MAC address. */ + GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_MAC, (uintptr_t)mac); + + /* Allocate and establish interrupt. */ + rid = 0; + sc->sc_intr = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ, &rid, + GXEMUL_ETHER_DEV_IRQ - 2, GXEMUL_ETHER_DEV_IRQ - 2, 1, RF_ACTIVE); + if (sc->sc_intr == NULL) { + device_printf(dev, "unable to allocate IRQ.\n"); + return (ENXIO); + } + + error = bus_setup_intr(sc->sc_dev, sc->sc_intr, INTR_TYPE_NET, NULL, + gx_rx_intr, sc, &sc->sc_intr_cookie); + if (error != 0) { + device_printf(dev, "unable to setup interrupt.\n"); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); + return (ENXIO); + } + + bus_describe_intr(sc->sc_dev, sc->sc_intr, sc->sc_intr_cookie, "rx"); + + ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "cannot allocate ifnet.\n"); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); + return (ENOMEM); + } + + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_mtu = ETHERMTU; + ifp->if_init = gx_init; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; + ifp->if_ioctl = gx_ioctl; + + sc->sc_ifp = ifp; + sc->sc_flags = ifp->if_flags; + + ifmedia_init(&sc->sc_ifmedia, 0, gx_medchange, gx_medstat); + + ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO); + + mtx_init(&sc->sc_mtx, "GXemul Ethernet", NULL, MTX_DEF); + + ether_ifattach(ifp, mac); + + ifp->if_transmit = gx_transmit; + + return (bus_generic_attach(dev)); +} + +static int +gx_detach(device_t dev) +{ + struct gx_softc *sc; + + sc = device_get_softc(dev); + + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); + /* XXX Incomplete. */ + + return (0); +} + +static int +gx_shutdown(device_t dev) +{ + return (gx_detach(dev)); +} + +static void +gx_init(void *arg) +{ + struct ifnet *ifp; + struct gx_softc *sc; + + sc = arg; + ifp = sc->sc_ifp; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + + ifp->if_drv_flags |= IFF_DRV_RUNNING; +} + +static int +gx_transmit(struct ifnet *ifp, struct mbuf *m) +{ + struct gx_softc *sc; + + sc = ifp->if_softc; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) { + m_freem(m); + return (0); + } + + GXEMUL_ETHER_LOCK(sc); + GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_LENGTH, m->m_pkthdr.len); + m_copydata(m, 0, m->m_pkthdr.len, (void *)(uintptr_t)GXEMUL_ETHER_DEV_FUNCTION(GXEMUL_ETHER_DEV_BUFFER)); + GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_COMMAND, GXEMUL_ETHER_DEV_COMMAND_TX); + GXEMUL_ETHER_UNLOCK(sc); + + ETHER_BPF_MTAP(ifp, m); + + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + + m_freem(m); + + return (0); +} + +static int +gx_medchange(struct ifnet *ifp) +{ + return (ENOTSUP); +} + +static void +gx_medstat(struct ifnet *ifp, struct ifmediareq *ifm) +{ + struct gx_softc *sc; + + sc = ifp->if_softc; + + /* Lie amazingly. */ + ifm->ifm_status = IFM_AVALID | IFM_ACTIVE; + ifm->ifm_active = IFT_ETHER | IFM_1000_T | IFM_FDX; +} + +static int +gx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct gx_softc *sc; + struct ifreq *ifr; +#ifdef INET + struct ifaddr *ifa; +#endif + int error; + + sc = ifp->if_softc; + ifr = (struct ifreq *)data; +#ifdef INET + ifa = (struct ifaddr *)data; +#endif + + switch (cmd) { + case SIOCSIFADDR: +#ifdef INET + /* + * Avoid reinitialization unless it's necessary. + */ + if (ifa->ifa_addr->sa_family == AF_INET) { + ifp->if_flags |= IFF_UP; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + gx_init(sc); + arp_ifinit(ifp, ifa); + + return (0); + } +#endif + error = ether_ioctl(ifp, cmd, data); + if (error != 0) + return (error); + return (0); + + case SIOCSIFFLAGS: + if (ifp->if_flags == sc->sc_flags) + return (0); + if ((ifp->if_flags & IFF_UP) != 0) { + gx_init(sc); + } else { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + } + } + sc->sc_flags = ifp->if_flags; + return (0); + + case SIOCSIFMTU: + if (ifr->ifr_mtu + ifp->if_data.ifi_hdrlen > GXEMUL_ETHER_DEV_MTU) + return (ENOTSUP); + return (0); + + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); + if (error != 0) + return (error); + return (0); + + default: + error = ether_ioctl(ifp, cmd, data); + if (error != 0) + return (error); + return (0); + } +} + +static void +gx_rx_intr(void *arg) +{ + struct gx_softc *sc = arg; + + GXEMUL_ETHER_LOCK(sc); + for (;;) { + uint64_t status, length; + struct mbuf *m; + + /* + * XXX + * Limit number of packets received at once? + */ + status = GXEMUL_ETHER_DEV_READ(GXEMUL_ETHER_DEV_STATUS); + if (status == GXEMUL_ETHER_DEV_STATUS_RX_MORE) { + GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_COMMAND, GXEMUL_ETHER_DEV_COMMAND_RX); + continue; + } + if (status != GXEMUL_ETHER_DEV_STATUS_RX_OK) + break; + length = GXEMUL_ETHER_DEV_READ(GXEMUL_ETHER_DEV_LENGTH); + if (length > MCLBYTES - ETHER_ALIGN) { + sc->sc_ifp->if_ierrors++; + continue; + } + + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + device_printf(sc->sc_dev, "no memory for receive mbuf.\n"); + sc->sc_ifp->if_iqdrops++; + GXEMUL_ETHER_UNLOCK(sc); + return; + } + + /* Align incoming frame so IP headers are aligned. */ + m->m_data += ETHER_ALIGN; + + memcpy(m->m_data, (const void *)(uintptr_t)GXEMUL_ETHER_DEV_FUNCTION(GXEMUL_ETHER_DEV_BUFFER), length); + + m->m_pkthdr.rcvif = sc->sc_ifp; + m->m_pkthdr.len = m->m_len = length; + + sc->sc_ifp->if_ipackets++; + + GXEMUL_ETHER_UNLOCK(sc); + + (*sc->sc_ifp->if_input)(sc->sc_ifp, m); + + GXEMUL_ETHER_LOCK(sc); + } + GXEMUL_ETHER_UNLOCK(sc); +} Modified: head/sys/mips/conf/GXEMUL ============================================================================== --- head/sys/mips/conf/GXEMUL Mon May 7 02:50:52 2012 (r235116) +++ head/sys/mips/conf/GXEMUL Mon May 7 04:15:46 2012 (r235117) @@ -27,6 +27,8 @@ options DDB options KDB options SCHED_ULE +options INET # InterNETworking +options INET6 # IPv6 communications protocols options FFS #Berkeley Fast Filesystem @@ -41,6 +43,18 @@ options ROOTDEVNAME=\"ufs:gxemul_disk0\ device gxemul_cons device gxemul_disk -device md -device loop -device random +device gxemul_ether + +# Pseudo devices. +device loop # Network loopback +device random # Entropy device +device ether # Ethernet support +device tun # Packet tunnel. +device md # Memory "disks" +device gif # IPv6 and IPv4 tunneling +device faith # IPv6-to-IPv4 relaying (translation) + +# The `bpf' device enables the Berkeley Packet Filter. +# Be aware of the administrative consequences of enabling this! +# Note that 'bpf' is required for DHCP. +device bpf # Berkeley packet filter Modified: head/sys/mips/gxemul/files.gxemul ============================================================================== --- head/sys/mips/gxemul/files.gxemul Mon May 7 02:50:52 2012 (r235116) +++ head/sys/mips/gxemul/files.gxemul Mon May 7 04:15:46 2012 (r235117) @@ -5,4 +5,4 @@ mips/mips/intr_machdep.c standard mips/mips/tick.c standard dev/gxemul/disk/gxemul_disk.c optional gxemul_disk -dev/gxemul/ether/gxemul_ether.c optional gxemul_ether +dev/gxemul/ether/if_gx.c optional gxemul_ether