The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/gxemul/ether/if_gx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2008-2012 Juli Mallett <jmallett@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 #include "opt_inet.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/endian.h>
   37 #include <sys/kernel.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/lock.h>
   40 #include <sys/module.h>
   41 #include <sys/mutex.h>
   42 #include <sys/rman.h>
   43 #include <sys/socket.h>
   44 #include <sys/sockio.h>
   45 #include <sys/sysctl.h>
   46 
   47 #include <net/bpf.h>
   48 #include <net/ethernet.h>
   49 #include <net/if.h>
   50 #include <net/if_dl.h>
   51 #include <net/if_media.h>
   52 #include <net/if_types.h>
   53 #include <net/if_var.h>
   54 #include <net/if_vlan_var.h>
   55 
   56 #ifdef INET
   57 #include <netinet/in.h>
   58 #include <netinet/if_ether.h>
   59 #endif
   60 
   61 #include <machine/cpuregs.h>
   62 
   63 #include <dev/gxemul/ether/gxreg.h>
   64 
   65 struct gx_softc {
   66         struct ifnet *sc_ifp;
   67         device_t sc_dev;
   68         unsigned sc_port;
   69         int sc_flags;
   70         struct ifmedia sc_ifmedia;
   71         struct resource *sc_intr;
   72         void *sc_intr_cookie;
   73         struct mtx sc_mtx;
   74 };
   75 
   76 #define GXEMUL_ETHER_LOCK(sc)   mtx_lock(&(sc)->sc_mtx)
   77 #define GXEMUL_ETHER_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
   78 
   79 static void     gx_identify(driver_t *, device_t);
   80 static int      gx_probe(device_t);
   81 static int      gx_attach(device_t);
   82 static int      gx_detach(device_t);
   83 static int      gx_shutdown(device_t);
   84 
   85 static void     gx_init(void *);
   86 static int      gx_transmit(struct ifnet *, struct mbuf *);
   87 
   88 static int      gx_medchange(struct ifnet *);
   89 static void     gx_medstat(struct ifnet *, struct ifmediareq *);
   90 
   91 static int      gx_ioctl(struct ifnet *, u_long, caddr_t);
   92 
   93 static void     gx_rx_intr(void *);
   94 
   95 static device_method_t gx_methods[] = {
   96         /* Device interface */
   97         DEVMETHOD(device_identify,      gx_identify),
   98         DEVMETHOD(device_probe,         gx_probe),
   99         DEVMETHOD(device_attach,        gx_attach),
  100         DEVMETHOD(device_detach,        gx_detach),
  101         DEVMETHOD(device_shutdown,      gx_shutdown),
  102 
  103         { 0, 0 }
  104 };
  105 
  106 static driver_t gx_driver = {
  107         "gx",
  108         gx_methods,
  109         sizeof (struct gx_softc),
  110 };
  111 
  112 DRIVER_MODULE(gx, nexus, gx_driver, 0, 0);
  113 
  114 static void
  115 gx_identify(driver_t *drv, device_t parent)
  116 {
  117         BUS_ADD_CHILD(parent, 0, "gx", 0);
  118 }
  119 
  120 static int
  121 gx_probe(device_t dev)
  122 {
  123         if (device_get_unit(dev) != 0)
  124                 return (ENXIO);
  125 
  126         device_set_desc(dev, "GXemul test Ethernet");
  127 
  128         return (BUS_PROBE_NOWILDCARD);
  129 }
  130 
  131 static int
  132 gx_attach(device_t dev)
  133 {
  134         struct ifnet *ifp;
  135         struct gx_softc *sc;
  136         uint8_t mac[6];
  137         int error;
  138         int rid;
  139 
  140         sc = device_get_softc(dev);
  141         sc->sc_dev = dev;
  142         sc->sc_port = device_get_unit(dev);
  143 
  144         /* Read MAC address.  */
  145         GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_MAC, (uintptr_t)mac);
  146 
  147         /* Allocate and establish interrupt.  */
  148         rid = 0;
  149         sc->sc_intr = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ, &rid,
  150             GXEMUL_ETHER_DEV_IRQ - 2, GXEMUL_ETHER_DEV_IRQ - 2, 1, RF_ACTIVE);
  151         if (sc->sc_intr == NULL) {
  152                 device_printf(dev, "unable to allocate IRQ.\n");
  153                 return (ENXIO);
  154         }
  155 
  156         error = bus_setup_intr(sc->sc_dev, sc->sc_intr, INTR_TYPE_NET, NULL,
  157             gx_rx_intr, sc, &sc->sc_intr_cookie);
  158         if (error != 0) {
  159                 device_printf(dev, "unable to setup interrupt.\n");
  160                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr);
  161                 return (ENXIO);
  162         }
  163 
  164         bus_describe_intr(sc->sc_dev, sc->sc_intr, sc->sc_intr_cookie, "rx");
  165 
  166         ifp = if_alloc(IFT_ETHER);
  167         if (ifp == NULL) {
  168                 device_printf(dev, "cannot allocate ifnet.\n");
  169                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr);
  170                 return (ENOMEM);
  171         }
  172 
  173         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  174         ifp->if_mtu = ETHERMTU;
  175         ifp->if_init = gx_init;
  176         ifp->if_softc = sc;
  177         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
  178         ifp->if_ioctl = gx_ioctl;
  179 
  180         sc->sc_ifp = ifp;
  181         sc->sc_flags = ifp->if_flags;
  182 
  183         ifmedia_init(&sc->sc_ifmedia, 0, gx_medchange, gx_medstat);
  184 
  185         ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
  186         ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
  187 
  188         mtx_init(&sc->sc_mtx, "GXemul Ethernet", NULL, MTX_DEF);
  189 
  190         ether_ifattach(ifp, mac);
  191 
  192         ifp->if_transmit = gx_transmit;
  193 
  194         return (bus_generic_attach(dev));
  195 }
  196 
  197 static int
  198 gx_detach(device_t dev)
  199 {
  200         struct gx_softc *sc;
  201 
  202         sc = device_get_softc(dev);
  203 
  204         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr);
  205         /* XXX Incomplete.  */
  206 
  207         return (0);
  208 }
  209 
  210 static int
  211 gx_shutdown(device_t dev)
  212 {
  213         return (gx_detach(dev));
  214 }
  215 
  216 static void
  217 gx_init(void *arg)
  218 {
  219         struct ifnet *ifp;
  220         struct gx_softc *sc;
  221 
  222         sc = arg;
  223         ifp = sc->sc_ifp;
  224 
  225         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
  226                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  227 
  228         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  229 }
  230 
  231 static int
  232 gx_transmit(struct ifnet *ifp, struct mbuf *m)
  233 {
  234         struct gx_softc *sc;
  235 
  236         sc = ifp->if_softc;
  237 
  238         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) {
  239                 m_freem(m);
  240                 return (0);
  241         }
  242 
  243         GXEMUL_ETHER_LOCK(sc);
  244         GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_LENGTH, m->m_pkthdr.len);
  245         m_copydata(m, 0, m->m_pkthdr.len, (void *)(uintptr_t)GXEMUL_ETHER_DEV_FUNCTION(GXEMUL_ETHER_DEV_BUFFER));
  246         GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_COMMAND, GXEMUL_ETHER_DEV_COMMAND_TX);
  247         GXEMUL_ETHER_UNLOCK(sc);
  248 
  249         ETHER_BPF_MTAP(ifp, m);
  250 
  251         if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
  252         if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
  253 
  254         m_freem(m);
  255 
  256         return (0);
  257 }
  258 
  259 static int
  260 gx_medchange(struct ifnet *ifp)
  261 {
  262         return (ENOTSUP);
  263 }
  264 
  265 static void
  266 gx_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
  267 {
  268         struct gx_softc *sc;
  269 
  270         sc = ifp->if_softc;
  271 
  272         /* Lie amazingly.  */
  273         ifm->ifm_status = IFM_AVALID | IFM_ACTIVE;
  274         ifm->ifm_active = IFT_ETHER | IFM_1000_T | IFM_FDX;
  275 }
  276 
  277 static int
  278 gx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  279 {
  280         struct gx_softc *sc;
  281         struct ifreq *ifr;
  282 #ifdef INET
  283         struct ifaddr *ifa;
  284 #endif
  285         int error;
  286 
  287         sc = ifp->if_softc;
  288         ifr = (struct ifreq *)data;
  289 #ifdef INET
  290         ifa = (struct ifaddr *)data;
  291 #endif
  292 
  293         switch (cmd) {
  294         case SIOCSIFADDR:
  295 #ifdef INET
  296                 /*
  297                  * Avoid reinitialization unless it's necessary.
  298                  */
  299                 if (ifa->ifa_addr->sa_family == AF_INET) {
  300                         ifp->if_flags |= IFF_UP;
  301                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  302                                 gx_init(sc);
  303                         arp_ifinit(ifp, ifa);
  304 
  305                         return (0);
  306                 }
  307 #endif
  308                 error = ether_ioctl(ifp, cmd, data);
  309                 if (error != 0)
  310                         return (error);
  311                 return (0);
  312 
  313         case SIOCSIFFLAGS:
  314                 if (ifp->if_flags == sc->sc_flags)
  315                         return (0);
  316                 if ((ifp->if_flags & IFF_UP) != 0) {
  317                         gx_init(sc);
  318                 } else {
  319                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
  320                                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  321                         }
  322                 }
  323                 sc->sc_flags = ifp->if_flags;
  324                 return (0);
  325 
  326         case SIOCSIFMTU:
  327                 if (ifr->ifr_mtu + ifp->if_hdrlen > GXEMUL_ETHER_DEV_MTU)
  328                         return (ENOTSUP);
  329                 return (0);
  330 
  331         case SIOCSIFMEDIA:
  332         case SIOCGIFMEDIA:
  333                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
  334                 if (error != 0)
  335                         return (error);
  336                 return (0);
  337         
  338         default:
  339                 error = ether_ioctl(ifp, cmd, data);
  340                 if (error != 0)
  341                         return (error);
  342                 return (0);
  343         }
  344 }
  345 
  346 static void
  347 gx_rx_intr(void *arg)
  348 {
  349         struct gx_softc *sc = arg;
  350 
  351         GXEMUL_ETHER_LOCK(sc);
  352         for (;;) {
  353                 uint64_t status, length;
  354                 struct mbuf *m;
  355 
  356                 /*
  357                  * XXX
  358                  * Limit number of packets received at once?
  359                  */
  360                 status = GXEMUL_ETHER_DEV_READ(GXEMUL_ETHER_DEV_STATUS);
  361                 if (status == GXEMUL_ETHER_DEV_STATUS_RX_MORE) {
  362                         GXEMUL_ETHER_DEV_WRITE(GXEMUL_ETHER_DEV_COMMAND, GXEMUL_ETHER_DEV_COMMAND_RX);
  363                         continue;
  364                 }
  365                 if (status != GXEMUL_ETHER_DEV_STATUS_RX_OK)
  366                         break;
  367                 length = GXEMUL_ETHER_DEV_READ(GXEMUL_ETHER_DEV_LENGTH);
  368                 if (length > MCLBYTES - ETHER_ALIGN) {
  369                         if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
  370                         continue;
  371                 }
  372 
  373                 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
  374                 if (m == NULL) {
  375                         device_printf(sc->sc_dev, "no memory for receive mbuf.\n");
  376                         if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1);
  377                         GXEMUL_ETHER_UNLOCK(sc);
  378                         return;
  379                 }
  380 
  381                 /* Align incoming frame so IP headers are aligned.  */
  382                 m->m_data += ETHER_ALIGN;
  383 
  384                 memcpy(m->m_data, (const void *)(uintptr_t)GXEMUL_ETHER_DEV_FUNCTION(GXEMUL_ETHER_DEV_BUFFER), length);
  385 
  386                 m->m_pkthdr.rcvif = sc->sc_ifp;
  387                 m->m_pkthdr.len = m->m_len = length;
  388 
  389                 if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
  390 
  391                 GXEMUL_ETHER_UNLOCK(sc);
  392 
  393                 (*sc->sc_ifp->if_input)(sc->sc_ifp, m);
  394 
  395                 GXEMUL_ETHER_LOCK(sc);
  396         }
  397         GXEMUL_ETHER_UNLOCK(sc);
  398 }

Cache object: f89a6939172e548e74b96a470cab4a62


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.