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

Cache object: 445f13a987198beacfc925b0af45474f


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