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/mips/cavium/octe/octe.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) 2010 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 /*
   32  * Cavium Octeon Ethernet devices.
   33  *
   34  * XXX This file should be moved to if_octe.c
   35  * XXX The driver may have sufficient locking but we need locking to protect
   36  *     the interfaces presented here, right?
   37  */
   38 
   39 #include "opt_inet.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/bus.h>
   44 #include <sys/endian.h>
   45 #include <sys/kernel.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/lock.h>
   48 #include <sys/module.h>
   49 #include <sys/mutex.h>
   50 #include <sys/rman.h>
   51 #include <sys/socket.h>
   52 #include <sys/sockio.h>
   53 #include <sys/sysctl.h>
   54 
   55 #include <net/bpf.h>
   56 #include <net/ethernet.h>
   57 #include <net/if.h>
   58 #include <net/if_dl.h>
   59 #include <net/if_media.h>
   60 #include <net/if_types.h>
   61 #include <net/if_var.h>
   62 #include <net/if_vlan_var.h>
   63 
   64 #ifdef INET
   65 #include <netinet/in.h>
   66 #include <netinet/if_ether.h>
   67 #endif
   68 
   69 #include <dev/mii/mii.h>
   70 #include <dev/mii/miivar.h>
   71 
   72 #include "wrapper-cvmx-includes.h"
   73 #include "cavium-ethernet.h"
   74 
   75 #include "ethernet-common.h"
   76 #include "ethernet-defines.h"
   77 #include "ethernet-mdio.h"
   78 #include "ethernet-tx.h"
   79 
   80 #include "miibus_if.h"
   81 
   82 #define OCTE_TX_LOCK(priv)      mtx_lock(&(priv)->tx_mtx)
   83 #define OCTE_TX_UNLOCK(priv)    mtx_unlock(&(priv)->tx_mtx)
   84 
   85 static int              octe_probe(device_t);
   86 static int              octe_attach(device_t);
   87 static int              octe_detach(device_t);
   88 static int              octe_shutdown(device_t);
   89 
   90 static int              octe_miibus_readreg(device_t, int, int);
   91 static int              octe_miibus_writereg(device_t, int, int, int);
   92 
   93 static void             octe_init(void *);
   94 static void             octe_stop(void *);
   95 static int              octe_transmit(struct ifnet *, struct mbuf *);
   96 
   97 static int              octe_mii_medchange(struct ifnet *);
   98 static void             octe_mii_medstat(struct ifnet *, struct ifmediareq *);
   99 
  100 static int              octe_medchange(struct ifnet *);
  101 static void             octe_medstat(struct ifnet *, struct ifmediareq *);
  102 
  103 static int              octe_ioctl(struct ifnet *, u_long, caddr_t);
  104 
  105 static device_method_t octe_methods[] = {
  106         /* Device interface */
  107         DEVMETHOD(device_probe,         octe_probe),
  108         DEVMETHOD(device_attach,        octe_attach),
  109         DEVMETHOD(device_detach,        octe_detach),
  110         DEVMETHOD(device_shutdown,      octe_shutdown),
  111 
  112         /* MII interface */
  113         DEVMETHOD(miibus_readreg,       octe_miibus_readreg),
  114         DEVMETHOD(miibus_writereg,      octe_miibus_writereg),
  115 
  116         { 0, 0 }
  117 };
  118 
  119 static driver_t octe_driver = {
  120         "octe",
  121         octe_methods,
  122         sizeof (cvm_oct_private_t),
  123 };
  124 
  125 static devclass_t octe_devclass;
  126 
  127 DRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0);
  128 DRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0);
  129 
  130 static int
  131 octe_probe(device_t dev)
  132 {
  133         return (0);
  134 }
  135 
  136 static int
  137 octe_attach(device_t dev)
  138 {
  139         struct ifnet *ifp;
  140         cvm_oct_private_t *priv;
  141         device_t child;
  142         unsigned qos;
  143         int error;
  144 
  145         priv = device_get_softc(dev);
  146         ifp = priv->ifp;
  147 
  148         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  149 
  150         if (priv->phy_id != -1) {
  151                 if (priv->phy_device == NULL) {
  152                         error = mii_attach(dev, &priv->miibus, ifp,
  153                             octe_mii_medchange, octe_mii_medstat,
  154                             BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0);
  155                         if (error != 0)
  156                                 device_printf(dev, "attaching PHYs failed\n");
  157                 } else {
  158                         child = device_add_child(dev, priv->phy_device, -1);
  159                         if (child == NULL)
  160                                 device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device);
  161                 }
  162         }
  163 
  164         if (priv->miibus == NULL) {
  165                 ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat);
  166 
  167                 ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
  168                 ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
  169         }
  170 
  171         /*
  172          * XXX
  173          * We don't support programming the multicast filter right now, although it
  174          * ought to be easy enough.  (Presumably it's just a matter of putting
  175          * multicast addresses in the CAM?)
  176          */
  177         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
  178         ifp->if_init = octe_init;
  179         ifp->if_ioctl = octe_ioctl;
  180 
  181         priv->if_flags = ifp->if_flags;
  182 
  183         mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF);
  184 
  185         for (qos = 0; qos < 16; qos++) {
  186                 mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF);
  187                 IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH);
  188         }
  189 
  190         ether_ifattach(ifp, priv->mac);
  191 
  192         ifp->if_transmit = octe_transmit;
  193 
  194         ifp->if_hdrlen = sizeof(struct ether_vlan_header);
  195         ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM;
  196         ifp->if_capenable = ifp->if_capabilities;
  197         ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
  198 
  199         OCTE_TX_LOCK(priv);
  200         IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH);
  201         ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH;
  202         IFQ_SET_READY(&ifp->if_snd);
  203         OCTE_TX_UNLOCK(priv);
  204 
  205         return (bus_generic_attach(dev));
  206 }
  207 
  208 static int
  209 octe_detach(device_t dev)
  210 {
  211         return (0);
  212 }
  213 
  214 static int
  215 octe_shutdown(device_t dev)
  216 {
  217         return (octe_detach(dev));
  218 }
  219 
  220 static int
  221 octe_miibus_readreg(device_t dev, int phy, int reg)
  222 {
  223         cvm_oct_private_t *priv;
  224 
  225         priv = device_get_softc(dev);
  226 
  227         /*
  228          * Try interface-specific MII routine.
  229          */
  230         if (priv->mdio_read != NULL)
  231                 return (priv->mdio_read(priv->ifp, phy, reg));
  232 
  233         /*
  234          * Try generic MII routine.
  235          */
  236         KASSERT(phy == priv->phy_id,
  237             ("read from phy %u but our phy is %u", phy, priv->phy_id));
  238         return (cvm_oct_mdio_read(priv->ifp, phy, reg));
  239 }
  240 
  241 static int
  242 octe_miibus_writereg(device_t dev, int phy, int reg, int val)
  243 {
  244         cvm_oct_private_t *priv;
  245 
  246         priv = device_get_softc(dev);
  247 
  248         /*
  249          * Try interface-specific MII routine.
  250          */
  251         if (priv->mdio_write != NULL) {
  252                 priv->mdio_write(priv->ifp, phy, reg, val);
  253                 return (0);
  254         }
  255 
  256         /*
  257          * Try generic MII routine.
  258          */
  259         KASSERT(phy == priv->phy_id,
  260             ("write to phy %u but our phy is %u", phy, priv->phy_id));
  261         cvm_oct_mdio_write(priv->ifp, phy, reg, val);
  262 
  263         return (0);
  264 }
  265 
  266 static void
  267 octe_init(void *arg)
  268 {
  269         struct ifnet *ifp;
  270         cvm_oct_private_t *priv;
  271 
  272         priv = arg;
  273         ifp = priv->ifp;
  274 
  275         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
  276                 octe_stop(priv);
  277 
  278         if (priv->open != NULL)
  279                 priv->open(ifp);
  280 
  281         if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0)
  282                 cvm_oct_common_set_multicast_list(ifp);
  283 
  284         cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp));
  285 
  286         cvm_oct_common_poll(ifp);
  287 
  288         if (priv->miibus != NULL)
  289                 mii_mediachg(device_get_softc(priv->miibus));
  290 
  291         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  292         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  293 }
  294 
  295 static void
  296 octe_stop(void *arg)
  297 {
  298         struct ifnet *ifp;
  299         cvm_oct_private_t *priv;
  300 
  301         priv = arg;
  302         ifp = priv->ifp;
  303 
  304         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  305                 return;
  306 
  307         if (priv->stop != NULL)
  308                 priv->stop(ifp);
  309 
  310         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  311 }
  312 
  313 static int
  314 octe_transmit(struct ifnet *ifp, struct mbuf *m)
  315 {
  316         cvm_oct_private_t *priv;
  317 
  318         priv = ifp->if_softc;
  319 
  320         if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
  321             IFF_DRV_RUNNING) {
  322                 m_freem(m);
  323                 return (0);
  324         }
  325 
  326         return (cvm_oct_xmit(m, ifp));
  327 }
  328 
  329 static int
  330 octe_mii_medchange(struct ifnet *ifp)
  331 {
  332         cvm_oct_private_t *priv;
  333         struct mii_data *mii;
  334         struct mii_softc *miisc;
  335 
  336         priv = ifp->if_softc;
  337         mii = device_get_softc(priv->miibus);
  338         LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
  339                 PHY_RESET(miisc);
  340         mii_mediachg(mii);
  341 
  342         return (0);
  343 }
  344 
  345 static void
  346 octe_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
  347 {
  348         cvm_oct_private_t *priv;
  349         struct mii_data *mii;
  350 
  351         priv = ifp->if_softc;
  352         mii = device_get_softc(priv->miibus);
  353 
  354         mii_pollstat(mii);
  355         ifm->ifm_active = mii->mii_media_active;
  356         ifm->ifm_status = mii->mii_media_status;
  357 }
  358 
  359 static int
  360 octe_medchange(struct ifnet *ifp)
  361 {
  362         return (ENOTSUP);
  363 }
  364 
  365 static void
  366 octe_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
  367 {
  368         cvm_oct_private_t *priv;
  369         cvmx_helper_link_info_t link_info;
  370 
  371         priv = ifp->if_softc;
  372 
  373         ifm->ifm_status = IFM_AVALID;
  374         ifm->ifm_active = IFT_ETHER;
  375 
  376         if (priv->poll == NULL)
  377                 return;
  378         priv->poll(ifp);
  379 
  380         link_info.u64 = priv->link_info;
  381 
  382         if (!link_info.s.link_up)
  383                 return;
  384 
  385         ifm->ifm_status |= IFM_ACTIVE;
  386 
  387         switch (link_info.s.speed) {
  388         case 10:
  389                 ifm->ifm_active |= IFM_10_T;
  390                 break;
  391         case 100:
  392                 ifm->ifm_active |= IFM_100_TX;
  393                 break;
  394         case 1000:
  395                 ifm->ifm_active |= IFM_1000_T;
  396                 break;
  397         case 10000:
  398                 ifm->ifm_active |= IFM_10G_T;
  399                 break;
  400         }
  401 
  402         if (link_info.s.full_duplex)
  403                 ifm->ifm_active |= IFM_FDX;
  404         else
  405                 ifm->ifm_active |= IFM_HDX;
  406 }
  407 
  408 static int
  409 octe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  410 {
  411         cvm_oct_private_t *priv;
  412         struct mii_data *mii;
  413         struct ifreq *ifr;
  414 #ifdef INET
  415         struct ifaddr *ifa;
  416 #endif
  417         int error;
  418 
  419         priv = ifp->if_softc;
  420         ifr = (struct ifreq *)data;
  421 #ifdef INET
  422         ifa = (struct ifaddr *)data;
  423 #endif
  424 
  425         switch (cmd) {
  426         case SIOCSIFADDR:
  427 #ifdef INET
  428                 /*
  429                  * Avoid reinitialization unless it's necessary.
  430                  */
  431                 if (ifa->ifa_addr->sa_family == AF_INET) {
  432                         ifp->if_flags |= IFF_UP;
  433                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  434                                 octe_init(priv);
  435                         arp_ifinit(ifp, ifa);
  436 
  437                         return (0);
  438                 }
  439 #endif
  440                 error = ether_ioctl(ifp, cmd, data);
  441                 if (error != 0)
  442                         return (error);
  443                 return (0);
  444 
  445         case SIOCSIFFLAGS:
  446                 if (ifp->if_flags == priv->if_flags)
  447                         return (0);
  448                 if ((ifp->if_flags & IFF_UP) != 0) {
  449                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  450                                 octe_init(priv);
  451                 } else {
  452                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
  453                                 octe_stop(priv);
  454                 }
  455                 priv->if_flags = ifp->if_flags;
  456                 return (0);
  457         
  458         case SIOCSIFCAP:
  459                 /*
  460                  * Just change the capabilities in software, currently none
  461                  * require reprogramming hardware, they just toggle whether we
  462                  * make use of already-present facilities in software.
  463                  */
  464                 ifp->if_capenable = ifr->ifr_reqcap;
  465                 return (0);
  466 
  467         case SIOCSIFMTU:
  468                 error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu);
  469                 if (error != 0)
  470                         return (EINVAL);
  471                 return (0);
  472 
  473         case SIOCSIFMEDIA:
  474         case SIOCGIFMEDIA:
  475                 if (priv->miibus != NULL) {
  476                         mii = device_get_softc(priv->miibus);
  477                         error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
  478                         if (error != 0)
  479                                 return (error);
  480                         return (0);
  481                 }
  482                 error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd);
  483                 if (error != 0)
  484                         return (error);
  485                 return (0);
  486         
  487         default:
  488                 error = ether_ioctl(ifp, cmd, data);
  489                 if (error != 0)
  490                         return (error);
  491                 return (0);
  492         }
  493 }

Cache object: c51fe1a5b0aa97624f0a14089977beb4


[ 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.