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

Cache object: 8f1104d1a5a5649f635040f9f3f9c28b


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