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/sfxge/sfxge_port.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-2016 Solarflare Communications Inc.
    5  * All rights reserved.
    6  *
    7  * This software was developed in part by Philip Paeps under contract for
    8  * Solarflare Communications, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions are met:
   12  *
   13  * 1. Redistributions of source code must retain the above copyright notice,
   14  *    this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright notice,
   16  *    this list of conditions and the following disclaimer in the documentation
   17  *    and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * The views and conclusions contained in the software and documentation are
   32  * those of the authors and should not be interpreted as representing official
   33  * policies, either expressed or implied, of the FreeBSD Project.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/types.h>
   40 #include <sys/limits.h>
   41 #include <net/ethernet.h>
   42 #include <net/if_dl.h>
   43 
   44 #include "common/efx.h"
   45 
   46 #include "sfxge.h"
   47 
   48 #define SFXGE_PARAM_STATS_UPDATE_PERIOD_MS \
   49         SFXGE_PARAM(stats_update_period_ms)
   50 static int sfxge_stats_update_period_ms = SFXGE_STATS_UPDATE_PERIOD_MS;
   51 TUNABLE_INT(SFXGE_PARAM_STATS_UPDATE_PERIOD_MS,
   52             &sfxge_stats_update_period_ms);
   53 SYSCTL_INT(_hw_sfxge, OID_AUTO, stats_update_period_ms, CTLFLAG_RDTUN,
   54            &sfxge_stats_update_period_ms, 0,
   55            "netstat interface statistics update period in milliseconds");
   56 
   57 static int sfxge_phy_cap_mask(struct sfxge_softc *, int, uint32_t *);
   58 
   59 static int
   60 sfxge_mac_stat_update(struct sfxge_softc *sc)
   61 {
   62         struct sfxge_port *port = &sc->port;
   63         efsys_mem_t *esmp = &(port->mac_stats.dma_buf);
   64         clock_t now;
   65         unsigned int min_ticks;
   66         unsigned int count;
   67         int rc;
   68 
   69         SFXGE_PORT_LOCK_ASSERT_OWNED(port);
   70 
   71         if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) {
   72                 rc = 0;
   73                 goto out;
   74         }
   75 
   76         min_ticks = (unsigned int)hz * port->stats_update_period_ms / 1000;
   77 
   78         now = ticks;
   79         if ((unsigned int)(now - port->mac_stats.update_time) < min_ticks) {
   80                 rc = 0;
   81                 goto out;
   82         }
   83 
   84         port->mac_stats.update_time = now;
   85 
   86         /* If we're unlucky enough to read statistics wduring the DMA, wait
   87          * up to 10ms for it to finish (typically takes <500us) */
   88         for (count = 0; count < 100; ++count) {
   89                 EFSYS_PROBE1(wait, unsigned int, count);
   90 
   91                 /* Try to update the cached counters */
   92                 if ((rc = efx_mac_stats_update(sc->enp, esmp,
   93                     port->mac_stats.decode_buf, NULL)) != EAGAIN)
   94                         goto out;
   95 
   96                 DELAY(100);
   97         }
   98 
   99         rc = ETIMEDOUT;
  100 out:
  101         return (rc);
  102 }
  103 
  104 uint64_t
  105 sfxge_get_counter(struct ifnet *ifp, ift_counter c)
  106 {
  107         struct sfxge_softc *sc = ifp->if_softc;
  108         uint64_t *mac_stats;
  109         uint64_t val;
  110 
  111         SFXGE_PORT_LOCK(&sc->port);
  112 
  113         /* Ignore error and use old values */
  114         (void)sfxge_mac_stat_update(sc);
  115 
  116         mac_stats = (uint64_t *)sc->port.mac_stats.decode_buf;
  117 
  118         switch (c) {
  119         case IFCOUNTER_IPACKETS:
  120                 val = mac_stats[EFX_MAC_RX_PKTS];
  121                 break;
  122         case IFCOUNTER_IERRORS:
  123                 val = mac_stats[EFX_MAC_RX_ERRORS];
  124                 break;
  125         case IFCOUNTER_OPACKETS:
  126                 val = mac_stats[EFX_MAC_TX_PKTS];
  127                 break;
  128         case IFCOUNTER_OERRORS:
  129                 val = mac_stats[EFX_MAC_TX_ERRORS];
  130                 break;
  131         case IFCOUNTER_COLLISIONS:
  132                 val = mac_stats[EFX_MAC_TX_SGL_COL_PKTS] +
  133                       mac_stats[EFX_MAC_TX_MULT_COL_PKTS] +
  134                       mac_stats[EFX_MAC_TX_EX_COL_PKTS] +
  135                       mac_stats[EFX_MAC_TX_LATE_COL_PKTS];
  136                 break;
  137         case IFCOUNTER_IBYTES:
  138                 val = mac_stats[EFX_MAC_RX_OCTETS];
  139                 break;
  140         case IFCOUNTER_OBYTES:
  141                 val = mac_stats[EFX_MAC_TX_OCTETS];
  142                 break;
  143         case IFCOUNTER_OMCASTS:
  144                 val = mac_stats[EFX_MAC_TX_MULTICST_PKTS] +
  145                       mac_stats[EFX_MAC_TX_BRDCST_PKTS];
  146                 break;
  147         case IFCOUNTER_OQDROPS:
  148                 SFXGE_PORT_UNLOCK(&sc->port);
  149                 return (sfxge_tx_get_drops(sc));
  150         case IFCOUNTER_IMCASTS:
  151                 /* if_imcasts is maintained in net/if_ethersubr.c */
  152         case IFCOUNTER_IQDROPS:
  153                 /* if_iqdrops is maintained in net/if_ethersubr.c */
  154         case IFCOUNTER_NOPROTO:
  155                 /* if_noproto is maintained in net/if_ethersubr.c */
  156         default:
  157                 SFXGE_PORT_UNLOCK(&sc->port);
  158                 return (if_get_counter_default(ifp, c));
  159         }
  160 
  161         SFXGE_PORT_UNLOCK(&sc->port);
  162 
  163         return (val);
  164 }
  165 
  166 static int
  167 sfxge_mac_stat_handler(SYSCTL_HANDLER_ARGS)
  168 {
  169         struct sfxge_softc *sc = arg1;
  170         unsigned int id = arg2;
  171         int rc;
  172         uint64_t val;
  173 
  174         SFXGE_PORT_LOCK(&sc->port);
  175         if ((rc = sfxge_mac_stat_update(sc)) == 0)
  176                 val = ((uint64_t *)sc->port.mac_stats.decode_buf)[id];
  177         SFXGE_PORT_UNLOCK(&sc->port);
  178 
  179         if (rc == 0)
  180                 rc = SYSCTL_OUT(req, &val, sizeof(val));
  181         return (rc);
  182 }
  183 
  184 static void
  185 sfxge_mac_stat_init(struct sfxge_softc *sc)
  186 {
  187         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
  188         struct sysctl_oid_list *stat_list;
  189         unsigned int id;
  190         const char *name;
  191 
  192         stat_list = SYSCTL_CHILDREN(sc->stats_node);
  193 
  194         /* Initialise the named stats */
  195         for (id = 0; id < EFX_MAC_NSTATS; id++) {
  196                 name = efx_mac_stat_name(sc->enp, id);
  197                 SYSCTL_ADD_PROC(ctx, stat_list, OID_AUTO, name,
  198                     CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
  199                     sc, id, sfxge_mac_stat_handler, "Q", "");
  200         }
  201 }
  202 
  203 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
  204 
  205 static unsigned int
  206 sfxge_port_wanted_fc(struct sfxge_softc *sc)
  207 {
  208         struct ifmedia_entry *ifm = sc->media.ifm_cur;
  209 
  210         if (ifm->ifm_media == (IFM_ETHER | IFM_AUTO))
  211                 return (EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE);
  212         return (((ifm->ifm_media & IFM_ETH_RXPAUSE) ? EFX_FCNTL_RESPOND : 0) |
  213                 ((ifm->ifm_media & IFM_ETH_TXPAUSE) ? EFX_FCNTL_GENERATE : 0));
  214 }
  215 
  216 static unsigned int
  217 sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
  218 {
  219         unsigned int wanted_fc, link_fc;
  220 
  221         efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
  222         return ((link_fc & EFX_FCNTL_RESPOND) ? IFM_ETH_RXPAUSE : 0) |
  223                 ((link_fc & EFX_FCNTL_GENERATE) ? IFM_ETH_TXPAUSE : 0);
  224 }
  225 
  226 #else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
  227 
  228 static unsigned int
  229 sfxge_port_wanted_fc(struct sfxge_softc *sc)
  230 {
  231         return (sc->port.wanted_fc);
  232 }
  233 
  234 static unsigned int
  235 sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
  236 {
  237         return (0);
  238 }
  239 
  240 static int
  241 sfxge_port_wanted_fc_handler(SYSCTL_HANDLER_ARGS)
  242 {
  243         struct sfxge_softc *sc;
  244         struct sfxge_port *port;
  245         unsigned int fcntl;
  246         int error;
  247 
  248         sc = arg1;
  249         port = &sc->port;
  250 
  251         if (req->newptr != NULL) {
  252                 if ((error = SYSCTL_IN(req, &fcntl, sizeof(fcntl))) != 0)
  253                         return (error);
  254 
  255                 SFXGE_PORT_LOCK(port);
  256 
  257                 if (port->wanted_fc != fcntl) {
  258                         if (port->init_state == SFXGE_PORT_STARTED)
  259                                 error = efx_mac_fcntl_set(sc->enp,
  260                                                           port->wanted_fc,
  261                                                           B_TRUE);
  262                         if (error == 0)
  263                                 port->wanted_fc = fcntl;
  264                 }
  265 
  266                 SFXGE_PORT_UNLOCK(port);
  267         } else {
  268                 SFXGE_PORT_LOCK(port);
  269                 fcntl = port->wanted_fc;
  270                 SFXGE_PORT_UNLOCK(port);
  271 
  272                 error = SYSCTL_OUT(req, &fcntl, sizeof(fcntl));
  273         }
  274 
  275         return (error);
  276 }
  277 
  278 static int
  279 sfxge_port_link_fc_handler(SYSCTL_HANDLER_ARGS)
  280 {
  281         struct sfxge_softc *sc;
  282         struct sfxge_port *port;
  283         unsigned int wanted_fc, link_fc;
  284 
  285         sc = arg1;
  286         port = &sc->port;
  287 
  288         SFXGE_PORT_LOCK(port);
  289         if (__predict_true(port->init_state == SFXGE_PORT_STARTED) &&
  290             SFXGE_LINK_UP(sc))
  291                 efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
  292         else
  293                 link_fc = 0;
  294         SFXGE_PORT_UNLOCK(port);
  295 
  296         return (SYSCTL_OUT(req, &link_fc, sizeof(link_fc)));
  297 }
  298 
  299 #endif /* SFXGE_HAVE_PAUSE_MEDIAOPTS */
  300 
  301 static const uint64_t sfxge_link_baudrate[EFX_LINK_NMODES] = {
  302         [EFX_LINK_10HDX]        = IF_Mbps(10),
  303         [EFX_LINK_10FDX]        = IF_Mbps(10),
  304         [EFX_LINK_100HDX]       = IF_Mbps(100),
  305         [EFX_LINK_100FDX]       = IF_Mbps(100),
  306         [EFX_LINK_1000HDX]      = IF_Gbps(1),
  307         [EFX_LINK_1000FDX]      = IF_Gbps(1),
  308         [EFX_LINK_10000FDX]     = IF_Gbps(10),
  309         [EFX_LINK_25000FDX]     = IF_Gbps(25),
  310         [EFX_LINK_40000FDX]     = IF_Gbps(40),
  311         [EFX_LINK_50000FDX]     = IF_Gbps(50),
  312         [EFX_LINK_100000FDX]    = IF_Gbps(100),
  313 };
  314 
  315 void
  316 sfxge_mac_link_update(struct sfxge_softc *sc, efx_link_mode_t mode)
  317 {
  318         struct sfxge_port *port;
  319         int link_state;
  320 
  321         port = &sc->port;
  322 
  323         if (port->link_mode == mode)
  324                 return;
  325 
  326         port->link_mode = mode;
  327 
  328         /* Push link state update to the OS */
  329         link_state = (SFXGE_LINK_UP(sc) ? LINK_STATE_UP : LINK_STATE_DOWN);
  330         sc->ifnet->if_baudrate = sfxge_link_baudrate[port->link_mode];
  331         if_link_state_change(sc->ifnet, link_state);
  332 }
  333 
  334 static void
  335 sfxge_mac_poll_work(void *arg, int npending)
  336 {
  337         struct sfxge_softc *sc;
  338         efx_nic_t *enp;
  339         struct sfxge_port *port;
  340         efx_link_mode_t mode;
  341 
  342         sc = (struct sfxge_softc *)arg;
  343         enp = sc->enp;
  344         port = &sc->port;
  345 
  346         SFXGE_PORT_LOCK(port);
  347 
  348         if (__predict_false(port->init_state != SFXGE_PORT_STARTED))
  349                 goto done;
  350 
  351         /* This may sleep waiting for MCDI completion */
  352         (void)efx_port_poll(enp, &mode);
  353         sfxge_mac_link_update(sc, mode);
  354 
  355 done:
  356         SFXGE_PORT_UNLOCK(port);
  357 }
  358 
  359 static u_int
  360 sfxge_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
  361 {
  362         uint8_t *mcast_addr = arg;
  363 
  364         if (cnt == EFX_MAC_MULTICAST_LIST_MAX)
  365                 return (0);
  366 
  367         memcpy(mcast_addr + (cnt * EFX_MAC_ADDR_LEN), LLADDR(sdl),
  368             EFX_MAC_ADDR_LEN);
  369 
  370         return (1);
  371 }
  372 
  373 static int
  374 sfxge_mac_multicast_list_set(struct sfxge_softc *sc)
  375 {
  376         struct ifnet *ifp = sc->ifnet;
  377         struct sfxge_port *port = &sc->port;
  378         int rc = 0;
  379 
  380         mtx_assert(&port->lock, MA_OWNED);
  381 
  382         port->mcast_count = if_foreach_llmaddr(ifp, sfxge_copy_maddr,
  383             port->mcast_addrs);
  384         if (port->mcast_count == EFX_MAC_MULTICAST_LIST_MAX) {
  385                 device_printf(sc->dev, "Too many multicast addresses\n");
  386                 rc = EINVAL;
  387         }
  388 
  389         if (rc == 0) {
  390                 rc = efx_mac_multicast_list_set(sc->enp, port->mcast_addrs,
  391                                                 port->mcast_count);
  392                 if (rc != 0)
  393                         device_printf(sc->dev,
  394                             "Cannot set multicast address list\n");
  395         }
  396 
  397         return (rc);
  398 }
  399 
  400 static int
  401 sfxge_mac_filter_set_locked(struct sfxge_softc *sc)
  402 {
  403         struct ifnet *ifp = sc->ifnet;
  404         struct sfxge_port *port = &sc->port;
  405         boolean_t all_mulcst;
  406         int rc;
  407 
  408         mtx_assert(&port->lock, MA_OWNED);
  409 
  410         all_mulcst = !!(ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI));
  411 
  412         rc = sfxge_mac_multicast_list_set(sc);
  413         /* Fallback to all multicast if cannot set multicast list */
  414         if (rc != 0)
  415                 all_mulcst = B_TRUE;
  416 
  417         rc = efx_mac_filter_set(sc->enp, !!(ifp->if_flags & IFF_PROMISC),
  418                                 (port->mcast_count > 0), all_mulcst, B_TRUE);
  419 
  420         return (rc);
  421 }
  422 
  423 int
  424 sfxge_mac_filter_set(struct sfxge_softc *sc)
  425 {
  426         struct sfxge_port *port = &sc->port;
  427         int rc;
  428 
  429         SFXGE_PORT_LOCK(port);
  430         /*
  431          * The function may be called without softc_lock held in the
  432          * case of SIOCADDMULTI and SIOCDELMULTI ioctls. ioctl handler
  433          * checks IFF_DRV_RUNNING flag which implies port started, but
  434          * it is not guaranteed to remain. softc_lock shared lock can't
  435          * be held in the case of these ioctls processing, since it
  436          * results in failure where kernel complains that non-sleepable
  437          * lock is held in sleeping thread. Both problems are repeatable
  438          * on LAG with LACP proto bring up.
  439          */
  440         if (__predict_true(port->init_state == SFXGE_PORT_STARTED))
  441                 rc = sfxge_mac_filter_set_locked(sc);
  442         else
  443                 rc = 0;
  444         SFXGE_PORT_UNLOCK(port);
  445         return (rc);
  446 }
  447 
  448 void
  449 sfxge_port_stop(struct sfxge_softc *sc)
  450 {
  451         struct sfxge_port *port;
  452         efx_nic_t *enp;
  453 
  454         port = &sc->port;
  455         enp = sc->enp;
  456 
  457         SFXGE_PORT_LOCK(port);
  458 
  459         KASSERT(port->init_state == SFXGE_PORT_STARTED,
  460             ("port not started"));
  461 
  462         port->init_state = SFXGE_PORT_INITIALIZED;
  463 
  464         port->mac_stats.update_time = 0;
  465 
  466         /* This may call MCDI */
  467         (void)efx_mac_drain(enp, B_TRUE);
  468 
  469         (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE);
  470 
  471         port->link_mode = EFX_LINK_UNKNOWN;
  472 
  473         /* Destroy the common code port object. */
  474         efx_port_fini(enp);
  475 
  476         efx_filter_fini(enp);
  477 
  478         SFXGE_PORT_UNLOCK(port);
  479 }
  480 
  481 int
  482 sfxge_port_start(struct sfxge_softc *sc)
  483 {
  484         uint8_t mac_addr[ETHER_ADDR_LEN];
  485         struct epoch_tracker et;
  486         struct ifnet *ifp = sc->ifnet;
  487         struct sfxge_port *port;
  488         efx_nic_t *enp;
  489         size_t pdu;
  490         int rc;
  491         uint32_t phy_cap_mask;
  492 
  493         port = &sc->port;
  494         enp = sc->enp;
  495 
  496         SFXGE_PORT_LOCK(port);
  497 
  498         KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
  499             ("port not initialized"));
  500 
  501         /* Initialise the required filtering */
  502         if ((rc = efx_filter_init(enp)) != 0)
  503                 goto fail_filter_init;
  504 
  505         /* Initialize the port object in the common code. */
  506         if ((rc = efx_port_init(sc->enp)) != 0)
  507                 goto fail;
  508 
  509         /* Set the SDU */
  510         pdu = EFX_MAC_PDU(ifp->if_mtu);
  511         if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
  512                 goto fail2;
  513 
  514         if ((rc = efx_mac_fcntl_set(enp, sfxge_port_wanted_fc(sc), B_TRUE))
  515             != 0)
  516                 goto fail3;
  517 
  518         /* Set the unicast address */
  519         NET_EPOCH_ENTER(et);
  520         bcopy(LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr),
  521               mac_addr, sizeof(mac_addr));
  522         NET_EPOCH_EXIT(et);
  523         if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0)
  524                 goto fail4;
  525 
  526         sfxge_mac_filter_set_locked(sc);
  527 
  528         /* Update MAC stats by DMA every period */
  529         if ((rc = efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
  530                                          port->stats_update_period_ms,
  531                                          B_FALSE)) != 0)
  532                 goto fail6;
  533 
  534         if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
  535                 goto fail8;
  536 
  537         if ((rc = sfxge_phy_cap_mask(sc, sc->media.ifm_cur->ifm_media,
  538                                      &phy_cap_mask)) != 0)
  539                 goto fail9;
  540 
  541         if ((rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask)) != 0)
  542                 goto fail10;
  543 
  544         port->init_state = SFXGE_PORT_STARTED;
  545 
  546         /* Single poll in case there were missing initial events */
  547         SFXGE_PORT_UNLOCK(port);
  548         sfxge_mac_poll_work(sc, 0);
  549 
  550         return (0);
  551 
  552 fail10:
  553 fail9:
  554         (void)efx_mac_drain(enp, B_TRUE);
  555 fail8:
  556         (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE);
  557 fail6:
  558 fail4:
  559 fail3:
  560 
  561 fail2:
  562         efx_port_fini(enp);
  563 fail:
  564         efx_filter_fini(enp);
  565 fail_filter_init:
  566         SFXGE_PORT_UNLOCK(port);
  567 
  568         return (rc);
  569 }
  570 
  571 static int
  572 sfxge_phy_stat_update(struct sfxge_softc *sc)
  573 {
  574         struct sfxge_port *port = &sc->port;
  575         efsys_mem_t *esmp = &port->phy_stats.dma_buf;
  576         clock_t now;
  577         unsigned int count;
  578         int rc;
  579 
  580         SFXGE_PORT_LOCK_ASSERT_OWNED(port);
  581 
  582         if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) {
  583                 rc = 0;
  584                 goto out;
  585         }
  586 
  587         now = ticks;
  588         if ((unsigned int)(now - port->phy_stats.update_time) < (unsigned int)hz) {
  589                 rc = 0;
  590                 goto out;
  591         }
  592 
  593         port->phy_stats.update_time = now;
  594 
  595         /* If we're unlucky enough to read statistics wduring the DMA, wait
  596          * up to 10ms for it to finish (typically takes <500us) */
  597         for (count = 0; count < 100; ++count) {
  598                 EFSYS_PROBE1(wait, unsigned int, count);
  599 
  600                 /* Synchronize the DMA memory for reading */
  601                 bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
  602                     BUS_DMASYNC_POSTREAD);
  603 
  604                 /* Try to update the cached counters */
  605                 if ((rc = efx_phy_stats_update(sc->enp, esmp,
  606                     port->phy_stats.decode_buf)) != EAGAIN)
  607                         goto out;
  608 
  609                 DELAY(100);
  610         }
  611 
  612         rc = ETIMEDOUT;
  613 out:
  614         return (rc);
  615 }
  616 
  617 static int
  618 sfxge_phy_stat_handler(SYSCTL_HANDLER_ARGS)
  619 {
  620         struct sfxge_softc *sc = arg1;
  621         unsigned int id = arg2;
  622         int rc;
  623         uint32_t val;
  624 
  625         SFXGE_PORT_LOCK(&sc->port);
  626         if ((rc = sfxge_phy_stat_update(sc)) == 0)
  627                 val = ((uint32_t *)sc->port.phy_stats.decode_buf)[id];
  628         SFXGE_PORT_UNLOCK(&sc->port);
  629 
  630         if (rc == 0)
  631                 rc = SYSCTL_OUT(req, &val, sizeof(val));
  632         return (rc);
  633 }
  634 
  635 static void
  636 sfxge_phy_stat_init(struct sfxge_softc *sc)
  637 {
  638         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
  639         struct sysctl_oid_list *stat_list;
  640         unsigned int id;
  641         const char *name;
  642         uint64_t stat_mask = efx_nic_cfg_get(sc->enp)->enc_phy_stat_mask;
  643 
  644         stat_list = SYSCTL_CHILDREN(sc->stats_node);
  645 
  646         /* Initialise the named stats */
  647         for (id = 0; id < EFX_PHY_NSTATS; id++) {
  648                 if (!(stat_mask & ((uint64_t)1 << id)))
  649                         continue;
  650                 name = efx_phy_stat_name(sc->enp, id);
  651                 SYSCTL_ADD_PROC(ctx, stat_list, OID_AUTO, name,
  652                     CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
  653                     sc, id, sfxge_phy_stat_handler,
  654                     id == EFX_PHY_STAT_OUI ? "IX" : "IU", "");
  655         }
  656 }
  657 
  658 void
  659 sfxge_port_fini(struct sfxge_softc *sc)
  660 {
  661         struct sfxge_port *port;
  662         efsys_mem_t *esmp;
  663 
  664         port = &sc->port;
  665         esmp = &port->mac_stats.dma_buf;
  666 
  667         KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
  668             ("Port not initialized"));
  669 
  670         port->init_state = SFXGE_PORT_UNINITIALIZED;
  671 
  672         port->link_mode = EFX_LINK_UNKNOWN;
  673 
  674         /* Finish with PHY DMA memory */
  675         sfxge_dma_free(&port->phy_stats.dma_buf);
  676         free(port->phy_stats.decode_buf, M_SFXGE);
  677 
  678         sfxge_dma_free(esmp);
  679         free(port->mac_stats.decode_buf, M_SFXGE);
  680 
  681         SFXGE_PORT_LOCK_DESTROY(port);
  682 
  683         port->sc = NULL;
  684 }
  685 
  686 static uint16_t
  687 sfxge_port_stats_update_period_ms(struct sfxge_softc *sc)
  688 {
  689         int period_ms = sfxge_stats_update_period_ms;
  690 
  691         if (period_ms < 0) {
  692                 device_printf(sc->dev,
  693                         "treat negative stats update period %d as 0 (disable)\n",
  694                          period_ms);
  695                 period_ms = 0;
  696         } else if (period_ms > UINT16_MAX) {
  697                 device_printf(sc->dev,
  698                         "treat too big stats update period %d as %u\n",
  699                         period_ms, UINT16_MAX);
  700                 period_ms = UINT16_MAX;
  701         }
  702 
  703         return period_ms;
  704 }
  705 
  706 static int
  707 sfxge_port_stats_update_period_ms_handler(SYSCTL_HANDLER_ARGS)
  708 {
  709         struct sfxge_softc *sc;
  710         struct sfxge_port *port;
  711         unsigned int period_ms;
  712         int error;
  713 
  714         sc = arg1;
  715         port = &sc->port;
  716 
  717         if (req->newptr != NULL) {
  718                 error = SYSCTL_IN(req, &period_ms, sizeof(period_ms));
  719                 if (error != 0)
  720                         return (error);
  721 
  722                 if (period_ms > UINT16_MAX)
  723                         return (EINVAL);
  724 
  725                 SFXGE_PORT_LOCK(port);
  726 
  727                 if (port->stats_update_period_ms != period_ms) {
  728                         if (port->init_state == SFXGE_PORT_STARTED)
  729                                 error = efx_mac_stats_periodic(sc->enp,
  730                                                 &port->mac_stats.dma_buf,
  731                                                 period_ms, B_FALSE);
  732                         if (error == 0)
  733                                 port->stats_update_period_ms = period_ms;
  734                 }
  735 
  736                 SFXGE_PORT_UNLOCK(port);
  737         } else {
  738                 SFXGE_PORT_LOCK(port);
  739                 period_ms = port->stats_update_period_ms;
  740                 SFXGE_PORT_UNLOCK(port);
  741 
  742                 error = SYSCTL_OUT(req, &period_ms, sizeof(period_ms));
  743         }
  744 
  745         return (error);
  746 }
  747 
  748 int
  749 sfxge_port_init(struct sfxge_softc *sc)
  750 {
  751         struct sfxge_port *port;
  752         struct sysctl_ctx_list *sysctl_ctx;
  753         struct sysctl_oid *sysctl_tree;
  754         efsys_mem_t *mac_stats_buf, *phy_stats_buf;
  755         uint32_t mac_nstats;
  756         size_t mac_stats_size;
  757         int rc;
  758 
  759         port = &sc->port;
  760         mac_stats_buf = &port->mac_stats.dma_buf;
  761         phy_stats_buf = &port->phy_stats.dma_buf;
  762 
  763         KASSERT(port->init_state == SFXGE_PORT_UNINITIALIZED,
  764             ("Port already initialized"));
  765 
  766         port->sc = sc;
  767 
  768         SFXGE_PORT_LOCK_INIT(port, device_get_nameunit(sc->dev));
  769 
  770         DBGPRINT(sc->dev, "alloc PHY stats");
  771         port->phy_stats.decode_buf = malloc(EFX_PHY_NSTATS * sizeof(uint32_t),
  772                                             M_SFXGE, M_WAITOK | M_ZERO);
  773         if ((rc = sfxge_dma_alloc(sc, EFX_PHY_STATS_SIZE, phy_stats_buf)) != 0)
  774                 goto fail;
  775         sfxge_phy_stat_init(sc);
  776 
  777         DBGPRINT(sc->dev, "init sysctl");
  778         sysctl_ctx = device_get_sysctl_ctx(sc->dev);
  779         sysctl_tree = device_get_sysctl_tree(sc->dev);
  780 
  781 #ifndef SFXGE_HAVE_PAUSE_MEDIAOPTS
  782         /* If flow control cannot be configured or reported through
  783          * ifmedia, provide sysctls for it. */
  784         port->wanted_fc = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
  785         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  786             "wanted_fc", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
  787             sfxge_port_wanted_fc_handler, "IU", "wanted flow control mode");
  788         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  789             "link_fc", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
  790             sfxge_port_link_fc_handler, "IU", "link flow control mode");
  791 #endif
  792 
  793         DBGPRINT(sc->dev, "alloc MAC stats");
  794         port->mac_stats.decode_buf = malloc(EFX_MAC_NSTATS * sizeof(uint64_t),
  795                                             M_SFXGE, M_WAITOK | M_ZERO);
  796         mac_nstats = efx_nic_cfg_get(sc->enp)->enc_mac_stats_nstats;
  797         mac_stats_size = EFX_P2ROUNDUP(size_t, mac_nstats * sizeof(uint64_t),
  798                                        EFX_BUF_SIZE);
  799         if ((rc = sfxge_dma_alloc(sc, mac_stats_size, mac_stats_buf)) != 0)
  800                 goto fail2;
  801         port->stats_update_period_ms = sfxge_port_stats_update_period_ms(sc);
  802         sfxge_mac_stat_init(sc);
  803 
  804         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  805             "stats_update_period_ms",
  806             CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
  807             sfxge_port_stats_update_period_ms_handler, "IU",
  808             "interface statistics refresh period");
  809 
  810         port->init_state = SFXGE_PORT_INITIALIZED;
  811 
  812         DBGPRINT(sc->dev, "success");
  813         return (0);
  814 
  815 fail2:
  816         free(port->mac_stats.decode_buf, M_SFXGE);
  817         sfxge_dma_free(phy_stats_buf);
  818 fail:
  819         free(port->phy_stats.decode_buf, M_SFXGE);
  820         SFXGE_PORT_LOCK_DESTROY(port);
  821         port->sc = NULL;
  822         DBGPRINT(sc->dev, "failed %d", rc);
  823         return (rc);
  824 }
  825 
  826 static const int sfxge_link_mode[EFX_PHY_MEDIA_NTYPES][EFX_LINK_NMODES] = {
  827         [EFX_PHY_MEDIA_CX4] = {
  828                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_CX4,
  829         },
  830         [EFX_PHY_MEDIA_KX4] = {
  831                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_KX4,
  832         },
  833         [EFX_PHY_MEDIA_XFP] = {
  834                 /* Don't know the module type, but assume SR for now. */
  835                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
  836         },
  837         [EFX_PHY_MEDIA_QSFP_PLUS] = {
  838                 /* Don't know the module type, but assume SR for now. */
  839                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
  840                 [EFX_LINK_25000FDX]     = IFM_ETHER | IFM_FDX | IFM_25G_SR,
  841                 [EFX_LINK_40000FDX]     = IFM_ETHER | IFM_FDX | IFM_40G_CR4,
  842                 [EFX_LINK_50000FDX]     = IFM_ETHER | IFM_FDX | IFM_50G_SR,
  843                 [EFX_LINK_100000FDX]    = IFM_ETHER | IFM_FDX | IFM_100G_SR2,
  844         },
  845         [EFX_PHY_MEDIA_SFP_PLUS] = {
  846                 /* Don't know the module type, but assume SX/SR for now. */
  847                 [EFX_LINK_1000FDX]      = IFM_ETHER | IFM_FDX | IFM_1000_SX,
  848                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
  849                 [EFX_LINK_25000FDX]     = IFM_ETHER | IFM_FDX | IFM_25G_SR,
  850         },
  851         [EFX_PHY_MEDIA_BASE_T] = {
  852                 [EFX_LINK_10HDX]        = IFM_ETHER | IFM_HDX | IFM_10_T,
  853                 [EFX_LINK_10FDX]        = IFM_ETHER | IFM_FDX | IFM_10_T,
  854                 [EFX_LINK_100HDX]       = IFM_ETHER | IFM_HDX | IFM_100_TX,
  855                 [EFX_LINK_100FDX]       = IFM_ETHER | IFM_FDX | IFM_100_TX,
  856                 [EFX_LINK_1000HDX]      = IFM_ETHER | IFM_HDX | IFM_1000_T,
  857                 [EFX_LINK_1000FDX]      = IFM_ETHER | IFM_FDX | IFM_1000_T,
  858                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_T,
  859         },
  860 };
  861 
  862 static void
  863 sfxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
  864 {
  865         struct sfxge_softc *sc;
  866         efx_phy_media_type_t medium_type;
  867         efx_link_mode_t mode;
  868 
  869         sc = ifp->if_softc;
  870         SFXGE_ADAPTER_LOCK(sc);
  871 
  872         ifmr->ifm_status = IFM_AVALID;
  873         ifmr->ifm_active = IFM_ETHER;
  874 
  875         if (SFXGE_RUNNING(sc) && SFXGE_LINK_UP(sc)) {
  876                 ifmr->ifm_status |= IFM_ACTIVE;
  877 
  878                 efx_phy_media_type_get(sc->enp, &medium_type);
  879                 mode = sc->port.link_mode;
  880                 ifmr->ifm_active |= sfxge_link_mode[medium_type][mode];
  881                 ifmr->ifm_active |= sfxge_port_link_fc_ifm(sc);
  882         }
  883 
  884         SFXGE_ADAPTER_UNLOCK(sc);
  885 }
  886 
  887 static efx_phy_cap_type_t
  888 sfxge_link_mode_to_phy_cap(efx_link_mode_t mode)
  889 {
  890         switch (mode) {
  891         case EFX_LINK_10HDX:
  892                 return (EFX_PHY_CAP_10HDX);
  893         case EFX_LINK_10FDX:
  894                 return (EFX_PHY_CAP_10FDX);
  895         case EFX_LINK_100HDX:
  896                 return (EFX_PHY_CAP_100HDX);
  897         case EFX_LINK_100FDX:
  898                 return (EFX_PHY_CAP_100FDX);
  899         case EFX_LINK_1000HDX:
  900                 return (EFX_PHY_CAP_1000HDX);
  901         case EFX_LINK_1000FDX:
  902                 return (EFX_PHY_CAP_1000FDX);
  903         case EFX_LINK_10000FDX:
  904                 return (EFX_PHY_CAP_10000FDX);
  905         case EFX_LINK_25000FDX:
  906                 return (EFX_PHY_CAP_25000FDX);
  907         case EFX_LINK_40000FDX:
  908                 return (EFX_PHY_CAP_40000FDX);
  909         case EFX_LINK_50000FDX:
  910                 return (EFX_PHY_CAP_50000FDX);
  911         case EFX_LINK_100000FDX:
  912                 return (EFX_PHY_CAP_100000FDX);
  913         default:
  914                 return (EFX_PHY_CAP_INVALID);
  915         }
  916 }
  917 
  918 static int
  919 sfxge_phy_cap_mask(struct sfxge_softc *sc, int ifmedia, uint32_t *phy_cap_mask)
  920 {
  921         /* Get global options (duplex), type and subtype bits */
  922         int ifmedia_masked = ifmedia & (IFM_GMASK | IFM_NMASK | IFM_TMASK);
  923         efx_phy_media_type_t medium_type;
  924         boolean_t mode_found = B_FALSE;
  925         uint32_t cap_mask, mode_cap_mask;
  926         efx_link_mode_t mode;
  927         efx_phy_cap_type_t phy_cap;
  928 
  929         efx_phy_media_type_get(sc->enp, &medium_type);
  930         if (medium_type >= nitems(sfxge_link_mode)) {
  931                 if_printf(sc->ifnet, "unexpected media type %d\n", medium_type);
  932                 return (EINVAL);
  933         }
  934 
  935         efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
  936 
  937         for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) {
  938                 if (ifmedia_masked == sfxge_link_mode[medium_type][mode]) {
  939                         mode_found = B_TRUE;
  940                         break;
  941                 }
  942         }
  943 
  944         if (!mode_found) {
  945                 /*
  946                  * If media is not in the table, it must be IFM_AUTO.
  947                  */
  948                 KASSERT((cap_mask & (1 << EFX_PHY_CAP_AN)) &&
  949                     ifmedia_masked == (IFM_ETHER | IFM_AUTO),
  950                     ("%s: no mode for media %#x", __func__, ifmedia));
  951                 *phy_cap_mask = (cap_mask & ~(1 << EFX_PHY_CAP_ASYM));
  952                 return (0);
  953         }
  954 
  955         phy_cap = sfxge_link_mode_to_phy_cap(mode);
  956         if (phy_cap == EFX_PHY_CAP_INVALID) {
  957                 if_printf(sc->ifnet,
  958                           "cannot map link mode %d to phy capability\n",
  959                           mode);
  960                 return (EINVAL);
  961         }
  962 
  963         mode_cap_mask = (1 << phy_cap);
  964         mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN);
  965 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
  966         if (ifmedia & IFM_ETH_RXPAUSE)
  967                 mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
  968         if (!(ifmedia & IFM_ETH_TXPAUSE))
  969                 mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_ASYM);
  970 #else
  971         mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
  972 #endif
  973 
  974         *phy_cap_mask = mode_cap_mask;
  975         return (0);
  976 }
  977 
  978 static int
  979 sfxge_media_change(struct ifnet *ifp)
  980 {
  981         struct sfxge_softc *sc;
  982         struct ifmedia_entry *ifm;
  983         int rc;
  984         uint32_t phy_cap_mask;
  985 
  986         sc = ifp->if_softc;
  987         ifm = sc->media.ifm_cur;
  988 
  989         SFXGE_ADAPTER_LOCK(sc);
  990 
  991         if (!SFXGE_RUNNING(sc)) {
  992                 rc = 0;
  993                 goto out;
  994         }
  995 
  996         rc = efx_mac_fcntl_set(sc->enp, sfxge_port_wanted_fc(sc), B_TRUE);
  997         if (rc != 0)
  998                 goto out;
  999 
 1000         if ((rc = sfxge_phy_cap_mask(sc, ifm->ifm_media, &phy_cap_mask)) != 0)
 1001                 goto out;
 1002 
 1003         rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask);
 1004 out:
 1005         SFXGE_ADAPTER_UNLOCK(sc);
 1006 
 1007         return (rc);
 1008 }
 1009 
 1010 int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
 1011 {
 1012         efx_phy_media_type_t medium_type;
 1013         uint32_t cap_mask, mode_cap_mask;
 1014         efx_link_mode_t mode;
 1015         efx_phy_cap_type_t phy_cap;
 1016         int mode_ifm, best_mode_ifm = 0;
 1017         int rc;
 1018 
 1019         /*
 1020          * We need port state to initialise the ifmedia list.
 1021          * It requires initialized NIC what is already done in
 1022          * sfxge_create() when resources are estimated.
 1023          */
 1024         if ((rc = efx_filter_init(sc->enp)) != 0)
 1025                 goto out1;
 1026         if ((rc = efx_port_init(sc->enp)) != 0)
 1027                 goto out2;
 1028 
 1029         /*
 1030          * Register ifconfig callbacks for querying and setting the
 1031          * link mode and link status.
 1032          */
 1033         ifmedia_init(&sc->media, IFM_IMASK, sfxge_media_change,
 1034             sfxge_media_status);
 1035 
 1036         /*
 1037          * Map firmware medium type and capabilities to ifmedia types.
 1038          * ifmedia does not distinguish between forcing the link mode
 1039          * and disabling auto-negotiation.  1000BASE-T and 10GBASE-T
 1040          * require AN even if only one link mode is enabled, and for
 1041          * 100BASE-TX it is useful even if the link mode is forced.
 1042          * Therefore we never disable auto-negotiation.
 1043          *
 1044          * Also enable and advertise flow control by default.
 1045          */
 1046 
 1047         efx_phy_media_type_get(sc->enp, &medium_type);
 1048         efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
 1049 
 1050         for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) {
 1051                 phy_cap = sfxge_link_mode_to_phy_cap(mode);
 1052                 if (phy_cap == EFX_PHY_CAP_INVALID)
 1053                         continue;
 1054 
 1055                 mode_cap_mask = (1 << phy_cap);
 1056                 mode_ifm = sfxge_link_mode[medium_type][mode];
 1057 
 1058                 if ((cap_mask & mode_cap_mask) && mode_ifm) {
 1059                         /* No flow-control */
 1060                         ifmedia_add(&sc->media, mode_ifm, 0, NULL);
 1061 
 1062 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
 1063                         /* Respond-only.  If using AN, we implicitly
 1064                          * offer symmetric as well, but that doesn't
 1065                          * mean we *have* to generate pause frames.
 1066                          */
 1067                         mode_ifm |= IFM_ETH_RXPAUSE;
 1068                         ifmedia_add(&sc->media, mode_ifm, 0, NULL);
 1069 
 1070                         /* Symmetric */
 1071                         mode_ifm |= IFM_ETH_TXPAUSE;
 1072                         ifmedia_add(&sc->media, mode_ifm, 0, NULL);
 1073 #endif
 1074 
 1075                         /* Link modes are numbered in order of speed,
 1076                          * so assume the last one available is the best.
 1077                          */
 1078                         best_mode_ifm = mode_ifm;
 1079                 }
 1080         }
 1081 
 1082         if (cap_mask & (1 << EFX_PHY_CAP_AN)) {
 1083                 /* Add autoselect mode. */
 1084                 mode_ifm = IFM_ETHER | IFM_AUTO;
 1085                 ifmedia_add(&sc->media, mode_ifm, 0, NULL);
 1086                 best_mode_ifm = mode_ifm;
 1087         }
 1088 
 1089         if (best_mode_ifm != 0)
 1090                 ifmedia_set(&sc->media, best_mode_ifm);
 1091 
 1092         /* Now discard port state until interface is started. */
 1093         efx_port_fini(sc->enp);
 1094 out2:
 1095         efx_filter_fini(sc->enp);
 1096 out1:
 1097         return (rc);
 1098 }

Cache object: 182cf03c7666c52aa02369394994bd5f


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