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

Cache object: 9f534eb1e41d4e7945451cf33a8b3bc3


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