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  * Copyright (c) 2010-2011 Solarflare Communications, Inc.
    3  * All rights reserved.
    4  *
    5  * This software was developed in part by Philip Paeps under contract for
    6  * Solarflare Communications, Inc.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/9.2/sys/dev/sfxge/sfxge_port.c 231156 2012-02-07 19:53:02Z jhb $");
   32 
   33 #include <sys/types.h>
   34 #include <sys/limits.h>
   35 #include <net/ethernet.h>
   36 #include <net/if_dl.h>
   37 
   38 #include "common/efx.h"
   39 
   40 #include "sfxge.h"
   41 
   42 static int
   43 sfxge_mac_stat_update(struct sfxge_softc *sc)
   44 {
   45         struct sfxge_port *port = &sc->port;
   46         efsys_mem_t *esmp = &(port->mac_stats.dma_buf);
   47         clock_t now;
   48         unsigned int count;
   49         int rc;
   50 
   51         mtx_lock(&port->lock);
   52 
   53         if (port->init_state != SFXGE_PORT_STARTED) {
   54                 rc = 0;
   55                 goto out;
   56         }
   57 
   58         now = ticks;
   59         if (now - port->mac_stats.update_time < hz) {
   60                 rc = 0;
   61                 goto out;
   62         }
   63 
   64         port->mac_stats.update_time = now;
   65 
   66         /* If we're unlucky enough to read statistics wduring the DMA, wait
   67          * up to 10ms for it to finish (typically takes <500us) */
   68         for (count = 0; count < 100; ++count) {
   69                 EFSYS_PROBE1(wait, unsigned int, count);
   70 
   71                 /* Synchronize the DMA memory for reading */
   72                 bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
   73                     BUS_DMASYNC_POSTREAD);
   74 
   75                 /* Try to update the cached counters */
   76                 if ((rc = efx_mac_stats_update(sc->enp, esmp,
   77                     port->mac_stats.decode_buf, NULL)) != EAGAIN)
   78                         goto out;
   79 
   80                 DELAY(100);
   81         }
   82 
   83         rc = ETIMEDOUT;
   84 out:
   85         mtx_unlock(&port->lock);
   86         return rc;
   87 }
   88 
   89 static int
   90 sfxge_mac_stat_handler(SYSCTL_HANDLER_ARGS)
   91 {
   92         struct sfxge_softc *sc = arg1;
   93         unsigned int id = arg2;
   94         int rc;
   95 
   96         if ((rc = sfxge_mac_stat_update(sc)) != 0)
   97                 return rc;
   98 
   99         return SYSCTL_OUT(req,
  100                           (uint64_t *)sc->port.mac_stats.decode_buf + id,
  101                           sizeof(uint64_t));
  102 }
  103 
  104 static void
  105 sfxge_mac_stat_init(struct sfxge_softc *sc)
  106 {
  107         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
  108         struct sysctl_oid_list *stat_list;
  109         unsigned int id;
  110         const char *name;
  111 
  112         stat_list = SYSCTL_CHILDREN(sc->stats_node);
  113 
  114         /* Initialise the named stats */
  115         for (id = 0; id < EFX_MAC_NSTATS; id++) {
  116                 name = efx_mac_stat_name(sc->enp, id);
  117                 SYSCTL_ADD_PROC(
  118                         ctx, stat_list,
  119                         OID_AUTO, name, CTLTYPE_U64|CTLFLAG_RD,
  120                         sc, id, sfxge_mac_stat_handler, "Q",
  121                         "");
  122         }
  123 }
  124 
  125 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
  126 
  127 static unsigned int
  128 sfxge_port_wanted_fc(struct sfxge_softc *sc)
  129 {
  130         struct ifmedia_entry *ifm = sc->media.ifm_cur;
  131 
  132         if (ifm->ifm_media == (IFM_ETHER | IFM_AUTO))
  133                 return EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
  134         return ((ifm->ifm_media & IFM_ETH_RXPAUSE) ? EFX_FCNTL_RESPOND : 0) |
  135                 ((ifm->ifm_media & IFM_ETH_TXPAUSE) ? EFX_FCNTL_GENERATE : 0);
  136 }
  137 
  138 static unsigned int
  139 sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
  140 {
  141         unsigned int wanted_fc, link_fc;
  142 
  143         efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
  144         return ((link_fc & EFX_FCNTL_RESPOND) ? IFM_ETH_RXPAUSE : 0) |
  145                 ((link_fc & EFX_FCNTL_GENERATE) ? IFM_ETH_TXPAUSE : 0);
  146 }
  147 
  148 #else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
  149 
  150 static unsigned int
  151 sfxge_port_wanted_fc(struct sfxge_softc *sc)
  152 {
  153         return sc->port.wanted_fc;
  154 }
  155 
  156 static unsigned int
  157 sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
  158 {
  159         return 0;
  160 }
  161 
  162 static int
  163 sfxge_port_wanted_fc_handler(SYSCTL_HANDLER_ARGS)
  164 {
  165         struct sfxge_softc *sc;
  166         struct sfxge_port *port;
  167         unsigned int fcntl;
  168         int error;
  169 
  170         sc = arg1;
  171         port = &sc->port;
  172 
  173         mtx_lock(&port->lock);
  174 
  175         if (req->newptr) {
  176                 if ((error = SYSCTL_IN(req, &fcntl, sizeof(fcntl))) != 0)
  177                         goto out;
  178 
  179                 if (port->wanted_fc == fcntl)
  180                         goto out;
  181 
  182                 port->wanted_fc = fcntl;
  183 
  184                 if (port->init_state != SFXGE_PORT_STARTED)
  185                         goto out;
  186 
  187                 error = efx_mac_fcntl_set(sc->enp, port->wanted_fc, B_TRUE);
  188         } else {
  189                 error = SYSCTL_OUT(req, &port->wanted_fc,
  190                                    sizeof(port->wanted_fc));
  191         }
  192 
  193 out:
  194         mtx_unlock(&port->lock);
  195 
  196         return (error);
  197 }
  198 
  199 static int
  200 sfxge_port_link_fc_handler(SYSCTL_HANDLER_ARGS)
  201 {
  202         struct sfxge_softc *sc;
  203         struct sfxge_port *port;
  204         unsigned int wanted_fc, link_fc;
  205         int error;
  206 
  207         sc = arg1;
  208         port = &sc->port;
  209 
  210         mtx_lock(&port->lock);
  211         if (port->init_state == SFXGE_PORT_STARTED && SFXGE_LINK_UP(sc))
  212                 efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
  213         else
  214                 link_fc = 0;
  215         error = SYSCTL_OUT(req, &link_fc, sizeof(link_fc));
  216         mtx_unlock(&port->lock);
  217 
  218         return (error);
  219 }
  220 
  221 #endif /* SFXGE_HAVE_PAUSE_MEDIAOPTS */
  222 
  223 static const u_long sfxge_link_baudrate[EFX_LINK_NMODES] = {
  224         [EFX_LINK_10HDX]        = IF_Mbps(10),
  225         [EFX_LINK_10FDX]        = IF_Mbps(10),
  226         [EFX_LINK_100HDX]       = IF_Mbps(100),
  227         [EFX_LINK_100FDX]       = IF_Mbps(100),
  228         [EFX_LINK_1000HDX]      = IF_Gbps(1),
  229         [EFX_LINK_1000FDX]      = IF_Gbps(1),
  230         [EFX_LINK_10000FDX]     = MIN(IF_Gbps(10ULL), ULONG_MAX),
  231 };
  232 
  233 void
  234 sfxge_mac_link_update(struct sfxge_softc *sc, efx_link_mode_t mode)
  235 {
  236         struct sfxge_port *port;
  237         int link_state;
  238         
  239         port = &sc->port;
  240 
  241         if (port->link_mode == mode)
  242                 return;
  243 
  244         port->link_mode = mode;
  245 
  246         /* Push link state update to the OS */
  247         link_state = (port->link_mode != EFX_LINK_DOWN ?
  248                       LINK_STATE_UP : LINK_STATE_DOWN);
  249         sc->ifnet->if_baudrate = sfxge_link_baudrate[port->link_mode];
  250         if_link_state_change(sc->ifnet, link_state);
  251 }
  252 
  253 static void
  254 sfxge_mac_poll_work(void *arg, int npending)
  255 {
  256         struct sfxge_softc *sc;
  257         efx_nic_t *enp;
  258         struct sfxge_port *port;
  259         efx_link_mode_t mode;
  260 
  261         sc = (struct sfxge_softc *)arg;
  262         enp = sc->enp;
  263         port = &sc->port;
  264 
  265         mtx_lock(&port->lock);
  266 
  267         if (port->init_state != SFXGE_PORT_STARTED)
  268                 goto done;
  269 
  270         /* This may sleep waiting for MCDI completion */
  271         (void)efx_port_poll(enp, &mode);
  272         sfxge_mac_link_update(sc, mode);
  273 
  274 done:
  275         mtx_unlock(&port->lock);
  276 }
  277 
  278 static int
  279 sfxge_mac_filter_set_locked(struct sfxge_softc *sc)
  280 {
  281         unsigned int bucket[EFX_MAC_HASH_BITS];
  282         struct ifnet *ifp = sc->ifnet;
  283         struct ifmultiaddr *ifma;
  284         struct sockaddr_dl *sa;
  285         efx_nic_t *enp = sc->enp;
  286         unsigned int index;
  287         int rc;
  288 
  289         /* Set promisc-unicast and broadcast filter bits */
  290         if ((rc = efx_mac_filter_set(enp, !!(ifp->if_flags & IFF_PROMISC),
  291                                      B_TRUE)) != 0)
  292                 return rc;
  293 
  294         /* Set multicast hash filter */
  295         if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
  296                 for (index = 0; index < EFX_MAC_HASH_BITS; index++)
  297                         bucket[index] = 1;
  298         } else {
  299                 /* Broadcast frames also go through the multicast
  300                  * filter, and the broadcast address hashes to
  301                  * 0xff. */
  302                 bucket[0xff] = 1;
  303 
  304                 if_maddr_rlock(ifp);
  305                 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  306                         if (ifma->ifma_addr->sa_family == AF_LINK) {
  307                                 sa = (struct sockaddr_dl *)ifma->ifma_addr;
  308                                 index = ether_crc32_le(LLADDR(sa), 6) & 0xff;
  309                                 bucket[index] = 1;
  310                         }
  311                 }
  312                 if_maddr_runlock(ifp);
  313         }
  314         return efx_mac_hash_set(enp, bucket);
  315 }
  316 
  317 int
  318 sfxge_mac_filter_set(struct sfxge_softc *sc)
  319 {
  320         struct sfxge_port *port = &sc->port;
  321         int rc;
  322 
  323         KASSERT(port->init_state == SFXGE_PORT_STARTED, ("port not started"));
  324 
  325         mtx_lock(&port->lock);
  326         rc = sfxge_mac_filter_set_locked(sc);
  327         mtx_unlock(&port->lock);
  328         return rc;
  329 }
  330 
  331 void
  332 sfxge_port_stop(struct sfxge_softc *sc)
  333 {
  334         struct sfxge_port *port;
  335         efx_nic_t *enp;
  336 
  337         port = &sc->port;
  338         enp = sc->enp;
  339 
  340         mtx_lock(&port->lock);
  341 
  342         KASSERT(port->init_state == SFXGE_PORT_STARTED,
  343             ("port not started"));
  344 
  345         port->init_state = SFXGE_PORT_INITIALIZED;
  346 
  347         port->mac_stats.update_time = 0;
  348 
  349         /* This may call MCDI */
  350         (void)efx_mac_drain(enp, B_TRUE);
  351 
  352         (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE);
  353 
  354         port->link_mode = EFX_LINK_UNKNOWN;
  355 
  356         /* Destroy the common code port object. */
  357         efx_port_fini(sc->enp);
  358 
  359         mtx_unlock(&port->lock);
  360 }
  361 
  362 int
  363 sfxge_port_start(struct sfxge_softc *sc)
  364 {
  365         uint8_t mac_addr[ETHER_ADDR_LEN];
  366         struct ifnet *ifp = sc->ifnet;
  367         struct sfxge_port *port;
  368         efx_nic_t *enp;
  369         size_t pdu;
  370         int rc;
  371 
  372         port = &sc->port;
  373         enp = sc->enp;
  374 
  375         mtx_lock(&port->lock);
  376 
  377         KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
  378             ("port not initialized"));
  379 
  380         /* Initialize the port object in the common code. */
  381         if ((rc = efx_port_init(sc->enp)) != 0)
  382                 goto fail;
  383 
  384         /* Set the SDU */
  385         pdu = EFX_MAC_PDU(ifp->if_mtu);
  386         if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
  387                 goto fail2;
  388 
  389         if ((rc = efx_mac_fcntl_set(enp, sfxge_port_wanted_fc(sc), B_TRUE))
  390             != 0)
  391                 goto fail2;
  392 
  393         /* Set the unicast address */
  394         if_addr_rlock(ifp);
  395         bcopy(LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr),
  396               mac_addr, sizeof(mac_addr));
  397         if_addr_runlock(ifp);
  398         if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0)
  399                 goto fail;
  400 
  401         sfxge_mac_filter_set_locked(sc);
  402 
  403         /* Update MAC stats by DMA every second */
  404         if ((rc = efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
  405             1000, B_FALSE)) != 0)
  406                 goto fail2;
  407 
  408         if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
  409                 goto fail3;
  410 
  411         if ((rc = efx_phy_adv_cap_set(sc->enp, sc->media.ifm_cur->ifm_data))
  412             != 0)
  413                 goto fail4;
  414 
  415         port->init_state = SFXGE_PORT_STARTED;
  416 
  417         /* Single poll in case there were missing initial events */
  418         mtx_unlock(&port->lock);
  419         sfxge_mac_poll_work(sc, 0);
  420 
  421         return (0);
  422 
  423 fail4:
  424         (void)efx_mac_drain(enp, B_TRUE);
  425 fail3:
  426         (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
  427             0, B_FALSE);
  428 fail2:
  429         efx_port_fini(sc->enp);
  430 fail:
  431         mtx_unlock(&port->lock);
  432 
  433         return (rc);
  434 }
  435 
  436 static int
  437 sfxge_phy_stat_update(struct sfxge_softc *sc)
  438 {
  439         struct sfxge_port *port = &sc->port;
  440         efsys_mem_t *esmp = &port->phy_stats.dma_buf;
  441         clock_t now;
  442         unsigned int count;
  443         int rc;
  444 
  445         mtx_lock(&port->lock);
  446 
  447         if (port->init_state != SFXGE_PORT_STARTED) {
  448                 rc = 0;
  449                 goto out;
  450         }
  451 
  452         now = ticks;
  453         if (now - port->phy_stats.update_time < hz) {
  454                 rc = 0;
  455                 goto out;
  456         }
  457 
  458         port->phy_stats.update_time = now;
  459 
  460         /* If we're unlucky enough to read statistics wduring the DMA, wait
  461          * up to 10ms for it to finish (typically takes <500us) */
  462         for (count = 0; count < 100; ++count) {
  463                 EFSYS_PROBE1(wait, unsigned int, count);
  464 
  465                 /* Synchronize the DMA memory for reading */
  466                 bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
  467                     BUS_DMASYNC_POSTREAD);
  468 
  469                 /* Try to update the cached counters */
  470                 if ((rc = efx_phy_stats_update(sc->enp, esmp,
  471                     port->phy_stats.decode_buf)) != EAGAIN)
  472                         goto out;
  473 
  474                 DELAY(100);
  475         }
  476 
  477         rc = ETIMEDOUT;
  478 out:
  479         mtx_unlock(&port->lock);
  480         return rc;
  481 }
  482 
  483 static int
  484 sfxge_phy_stat_handler(SYSCTL_HANDLER_ARGS)
  485 {
  486         struct sfxge_softc *sc = arg1;
  487         unsigned int id = arg2;
  488         int rc;
  489 
  490         if ((rc = sfxge_phy_stat_update(sc)) != 0)
  491                 return rc;
  492 
  493         return SYSCTL_OUT(req,
  494                           (uint32_t *)sc->port.phy_stats.decode_buf + id,
  495                           sizeof(uint32_t));
  496 }
  497 
  498 static void
  499 sfxge_phy_stat_init(struct sfxge_softc *sc)
  500 {
  501         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
  502         struct sysctl_oid_list *stat_list;
  503         unsigned int id;
  504         const char *name;
  505         uint64_t stat_mask = efx_nic_cfg_get(sc->enp)->enc_phy_stat_mask;
  506 
  507         stat_list = SYSCTL_CHILDREN(sc->stats_node);
  508 
  509         /* Initialise the named stats */
  510         for (id = 0; id < EFX_PHY_NSTATS; id++) {
  511                 if (!(stat_mask & ((uint64_t)1 << id)))
  512                         continue;
  513                 name = efx_phy_stat_name(sc->enp, id);
  514                 SYSCTL_ADD_PROC(
  515                         ctx, stat_list,
  516                         OID_AUTO, name, CTLTYPE_UINT|CTLFLAG_RD,
  517                         sc, id, sfxge_phy_stat_handler,
  518                         id == EFX_PHY_STAT_OUI ? "IX" : "IU",
  519                         "");
  520         }
  521 }
  522 
  523 void
  524 sfxge_port_fini(struct sfxge_softc *sc)
  525 {
  526         struct sfxge_port *port;
  527         efsys_mem_t *esmp;
  528 
  529         port = &sc->port;
  530         esmp = &port->mac_stats.dma_buf;
  531 
  532         KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
  533             ("Port not initialized"));
  534 
  535         port->init_state = SFXGE_PORT_UNINITIALIZED;
  536 
  537         port->link_mode = EFX_LINK_UNKNOWN;
  538 
  539         /* Finish with PHY DMA memory */
  540         sfxge_dma_free(&port->phy_stats.dma_buf);
  541         free(port->phy_stats.decode_buf, M_SFXGE);
  542 
  543         sfxge_dma_free(esmp);
  544         free(port->mac_stats.decode_buf, M_SFXGE);
  545 
  546         mtx_destroy(&port->lock);
  547 
  548         port->sc = NULL;
  549 }
  550 
  551 int
  552 sfxge_port_init(struct sfxge_softc *sc)
  553 {
  554         struct sfxge_port *port;
  555         struct sysctl_ctx_list *sysctl_ctx;
  556         struct sysctl_oid *sysctl_tree;
  557         efsys_mem_t *mac_stats_buf, *phy_stats_buf;
  558         int rc;
  559 
  560         port = &sc->port;
  561         mac_stats_buf = &port->mac_stats.dma_buf;
  562         phy_stats_buf = &port->phy_stats.dma_buf;
  563 
  564         KASSERT(port->init_state == SFXGE_PORT_UNINITIALIZED,
  565             ("Port already initialized"));
  566 
  567         port->sc = sc;
  568 
  569         mtx_init(&port->lock, "sfxge_port", NULL, MTX_DEF);
  570 
  571         port->phy_stats.decode_buf = malloc(EFX_PHY_NSTATS * sizeof(uint32_t),
  572                                             M_SFXGE, M_WAITOK | M_ZERO);
  573         if ((rc = sfxge_dma_alloc(sc, EFX_PHY_STATS_SIZE, phy_stats_buf)) != 0)
  574                 goto fail;
  575         bzero(phy_stats_buf->esm_base, phy_stats_buf->esm_size);
  576         sfxge_phy_stat_init(sc);
  577 
  578         sysctl_ctx = device_get_sysctl_ctx(sc->dev);
  579         sysctl_tree = device_get_sysctl_tree(sc->dev);
  580 
  581 #ifndef SFXGE_HAVE_PAUSE_MEDIAOPTS
  582         /* If flow control cannot be configured or reported through
  583          * ifmedia, provide sysctls for it. */
  584         port->wanted_fc = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
  585         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  586             "wanted_fc", CTLTYPE_UINT|CTLFLAG_RW, sc, 0,
  587             sfxge_port_wanted_fc_handler, "IU", "wanted flow control mode");
  588         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
  589             "link_fc", CTLTYPE_UINT|CTLFLAG_RD, sc, 0,
  590             sfxge_port_link_fc_handler, "IU", "link flow control mode");
  591 #endif
  592 
  593         port->mac_stats.decode_buf = malloc(EFX_MAC_NSTATS * sizeof(uint64_t),
  594                                             M_SFXGE, M_WAITOK | M_ZERO);
  595         if ((rc = sfxge_dma_alloc(sc, EFX_MAC_STATS_SIZE, mac_stats_buf)) != 0)
  596                 goto fail2;
  597         bzero(mac_stats_buf->esm_base, mac_stats_buf->esm_size);
  598         sfxge_mac_stat_init(sc);
  599 
  600         port->init_state = SFXGE_PORT_INITIALIZED;
  601 
  602         return (0);
  603 
  604 fail2:
  605         free(port->mac_stats.decode_buf, M_SFXGE);
  606         sfxge_dma_free(phy_stats_buf);
  607 fail:
  608         free(port->phy_stats.decode_buf, M_SFXGE);
  609         (void)mtx_destroy(&port->lock);
  610         port->sc = NULL;
  611         return rc;
  612 }
  613 
  614 static int sfxge_link_mode[EFX_PHY_MEDIA_NTYPES][EFX_LINK_NMODES] = {
  615         [EFX_PHY_MEDIA_CX4] = {
  616                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_CX4,
  617         },
  618         [EFX_PHY_MEDIA_KX4] = {
  619                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_KX4,
  620         },
  621         [EFX_PHY_MEDIA_XFP] = {
  622                 /* Don't know the module type, but assume SR for now. */
  623                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
  624         },
  625         [EFX_PHY_MEDIA_SFP_PLUS] = {
  626                 /* Don't know the module type, but assume SX/SR for now. */
  627                 [EFX_LINK_1000FDX]      = IFM_ETHER | IFM_FDX | IFM_1000_SX,
  628                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
  629         },
  630         [EFX_PHY_MEDIA_BASE_T] = {
  631                 [EFX_LINK_10HDX]        = IFM_ETHER | IFM_HDX | IFM_10_T,
  632                 [EFX_LINK_10FDX]        = IFM_ETHER | IFM_FDX | IFM_10_T,
  633                 [EFX_LINK_100HDX]       = IFM_ETHER | IFM_HDX | IFM_100_TX,
  634                 [EFX_LINK_100FDX]       = IFM_ETHER | IFM_FDX | IFM_100_TX,
  635                 [EFX_LINK_1000HDX]      = IFM_ETHER | IFM_HDX | IFM_1000_T,
  636                 [EFX_LINK_1000FDX]      = IFM_ETHER | IFM_FDX | IFM_1000_T,
  637                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_T,
  638         },
  639 };
  640 
  641 static void
  642 sfxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
  643 {
  644         struct sfxge_softc *sc;
  645         efx_phy_media_type_t medium_type;
  646         efx_link_mode_t mode;
  647 
  648         sc = ifp->if_softc;
  649         sx_xlock(&sc->softc_lock);
  650 
  651         ifmr->ifm_status = IFM_AVALID;
  652         ifmr->ifm_active = IFM_ETHER;
  653 
  654         if (SFXGE_RUNNING(sc) && SFXGE_LINK_UP(sc)) {
  655                 ifmr->ifm_status |= IFM_ACTIVE;
  656 
  657                 efx_phy_media_type_get(sc->enp, &medium_type);
  658                 mode = sc->port.link_mode;
  659                 ifmr->ifm_active |= sfxge_link_mode[medium_type][mode];
  660                 ifmr->ifm_active |= sfxge_port_link_fc_ifm(sc);
  661         }
  662 
  663         sx_xunlock(&sc->softc_lock);
  664 }
  665 
  666 static int
  667 sfxge_media_change(struct ifnet *ifp)
  668 {
  669         struct sfxge_softc *sc;
  670         struct ifmedia_entry *ifm;
  671         int rc;
  672 
  673         sc = ifp->if_softc;
  674         ifm = sc->media.ifm_cur;
  675 
  676         sx_xlock(&sc->softc_lock);
  677 
  678         if (!SFXGE_RUNNING(sc)) {
  679                 rc = 0;
  680                 goto out;
  681         }
  682 
  683         rc = efx_mac_fcntl_set(sc->enp, sfxge_port_wanted_fc(sc), B_TRUE);
  684         if (rc != 0)
  685                 goto out;
  686 
  687         rc = efx_phy_adv_cap_set(sc->enp, ifm->ifm_data);
  688 out:
  689         sx_xunlock(&sc->softc_lock);    
  690 
  691         return rc;
  692 }
  693 
  694 int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
  695 {
  696         efx_phy_media_type_t medium_type;
  697         uint32_t cap_mask, mode_cap_mask;
  698         efx_link_mode_t mode;
  699         int mode_ifm, best_mode_ifm = 0;
  700         int rc;
  701 
  702         /* We need port state to initialise the ifmedia list. */
  703         if ((rc = efx_nic_init(sc->enp)) != 0)
  704                 goto out;
  705         if ((rc = efx_port_init(sc->enp)) != 0)
  706                 goto out2;
  707 
  708         /*
  709          * Register ifconfig callbacks for querying and setting the
  710          * link mode and link status.
  711          */
  712         ifmedia_init(&sc->media, IFM_IMASK, sfxge_media_change,
  713             sfxge_media_status);
  714 
  715         /*
  716          * Map firmware medium type and capabilities to ifmedia types.
  717          * ifmedia does not distinguish between forcing the link mode
  718          * and disabling auto-negotiation.  1000BASE-T and 10GBASE-T
  719          * require AN even if only one link mode is enabled, and for
  720          * 100BASE-TX it is useful even if the link mode is forced.
  721          * Therefore we never disable auto-negotiation.
  722          *
  723          * Also enable and advertise flow control by default.
  724          */
  725 
  726         efx_phy_media_type_get(sc->enp, &medium_type);
  727         efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
  728 
  729         EFX_STATIC_ASSERT(EFX_LINK_10HDX == EFX_PHY_CAP_10HDX + 1);
  730         EFX_STATIC_ASSERT(EFX_LINK_10FDX == EFX_PHY_CAP_10FDX + 1);
  731         EFX_STATIC_ASSERT(EFX_LINK_100HDX == EFX_PHY_CAP_100HDX + 1);
  732         EFX_STATIC_ASSERT(EFX_LINK_100FDX == EFX_PHY_CAP_100FDX + 1);
  733         EFX_STATIC_ASSERT(EFX_LINK_1000HDX == EFX_PHY_CAP_1000HDX + 1);
  734         EFX_STATIC_ASSERT(EFX_LINK_1000FDX == EFX_PHY_CAP_1000FDX + 1);
  735         EFX_STATIC_ASSERT(EFX_LINK_10000FDX == EFX_PHY_CAP_10000FDX + 1);
  736 
  737         for (mode = EFX_LINK_10HDX; mode <= EFX_LINK_10000FDX; mode++) {
  738                 mode_cap_mask = 1 << (mode - 1);
  739                 mode_ifm = sfxge_link_mode[medium_type][mode];
  740 
  741                 if ((cap_mask & mode_cap_mask) && mode_ifm) {
  742                         mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN);
  743 
  744 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
  745                         /* No flow-control */
  746                         ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
  747 
  748                         /* Respond-only.  If using AN, we implicitly
  749                          * offer symmetric as well, but that doesn't
  750                          * mean we *have* to generate pause frames.
  751                          */
  752                         mode_cap_mask |= cap_mask & ((1 << EFX_PHY_CAP_PAUSE) |
  753                                                      (1 << EFX_PHY_CAP_ASYM));
  754                         mode_ifm |= IFM_ETH_RXPAUSE;
  755                         ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
  756 
  757                         /* Symmetric */
  758                         mode_cap_mask &= ~(1 << EFX_PHY_CAP_ASYM);
  759                         mode_ifm |= IFM_ETH_TXPAUSE;
  760 #else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
  761                         mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
  762 #endif
  763                         ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
  764 
  765                         /* Link modes are numbered in order of speed,
  766                          * so assume the last one available is the best.
  767                          */
  768                         best_mode_ifm = mode_ifm;
  769                 }
  770         }
  771 
  772         if (cap_mask & (1 << EFX_PHY_CAP_AN)) {
  773                 /* Add autoselect mode. */
  774                 mode_ifm = IFM_ETHER | IFM_AUTO;
  775                 ifmedia_add(&sc->media, mode_ifm,
  776                             cap_mask & ~(1 << EFX_PHY_CAP_ASYM), NULL);
  777                 best_mode_ifm = mode_ifm;
  778         }
  779 
  780         if (best_mode_ifm)
  781                 ifmedia_set(&sc->media, best_mode_ifm);
  782 
  783         /* Now discard port state until interface is started. */
  784         efx_port_fini(sc->enp);
  785 out2:
  786         efx_nic_fini(sc->enp);
  787 out:
  788         return rc;
  789 }

Cache object: 78a44307dad2a319c7188aef86959e45


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