1 /*
   2  * Copyright (c) 2009-2015 Solarflare Communications Inc.
   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 are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include "efx.h"
  32 #include "efx_impl.h"
  33 
  34         __checkReturn   efx_rc_t
  35 efx_port_init(
  36         __in            efx_nic_t *enp)
  37 {
  38         efx_port_t *epp = &(enp->en_port);
  39         const efx_phy_ops_t *epop = epp->ep_epop;
  40         efx_rc_t rc;
  41 
  42         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  43         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
  44         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
  45 
  46         if (enp->en_mod_flags & EFX_MOD_PORT) {
  47                 rc = EINVAL;
  48                 goto fail1;
  49         }
  50 
  51         enp->en_mod_flags |= EFX_MOD_PORT;
  52 
  53         epp->ep_mac_type = EFX_MAC_INVALID;
  54         epp->ep_link_mode = EFX_LINK_UNKNOWN;
  55         epp->ep_mac_drain = B_TRUE;
  56 
  57         /* Configure the MAC */
  58         if ((rc = efx_mac_select(enp)) != 0)
  59                 goto fail1;
  60 
  61         epp->ep_emop->emo_reconfigure(enp);
  62 
  63         /* Pick up current phy capababilities */
  64         (void) efx_port_poll(enp, NULL);
  65 
  66         /*
  67          * Turn on the PHY if available, otherwise reset it, and
  68          * reconfigure it with the current configuration.
  69          */
  70         if (epop->epo_power != NULL) {
  71                 if ((rc = epop->epo_power(enp, B_TRUE)) != 0)
  72                         goto fail2;
  73         } else {
  74                 if ((rc = epop->epo_reset(enp)) != 0)
  75                         goto fail2;
  76         }
  77 
  78         EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
  79         enp->en_reset_flags &= ~EFX_RESET_PHY;
  80 
  81         if ((rc = epop->epo_reconfigure(enp)) != 0)
  82                 goto fail3;
  83 
  84         return (0);
  85 
  86 fail3:
  87         EFSYS_PROBE(fail3);
  88 fail2:
  89         EFSYS_PROBE(fail2);
  90 fail1:
  91         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  92 
  93         enp->en_mod_flags &= ~EFX_MOD_PORT;
  94 
  95         return (rc);
  96 }
  97 
  98         __checkReturn   efx_rc_t
  99 efx_port_poll(
 100         __in            efx_nic_t *enp,
 101         __out_opt       efx_link_mode_t *link_modep)
 102 {
 103         efx_port_t *epp = &(enp->en_port);
 104         const efx_mac_ops_t *emop = epp->ep_emop;
 105         efx_link_mode_t ignore_link_mode;
 106         efx_rc_t rc;
 107 
 108         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 109         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
 110 
 111         EFSYS_ASSERT(emop != NULL);
 112         EFSYS_ASSERT(!epp->ep_mac_stats_pending);
 113 
 114         if (link_modep == NULL)
 115                 link_modep = &ignore_link_mode;
 116 
 117         if ((rc = emop->emo_poll(enp, link_modep)) != 0)
 118                 goto fail1;
 119 
 120         return (0);
 121 
 122 fail1:
 123         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 124 
 125         return (rc);
 126 }
 127 
 128 #if EFSYS_OPT_LOOPBACK
 129 
 130         __checkReturn   efx_rc_t
 131 efx_port_loopback_set(
 132         __in            efx_nic_t *enp,
 133         __in            efx_link_mode_t link_mode,
 134         __in            efx_loopback_type_t loopback_type)
 135 {
 136         efx_port_t *epp = &(enp->en_port);
 137         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 138         const efx_mac_ops_t *emop = epp->ep_emop;
 139         efx_rc_t rc;
 140 
 141         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 142         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
 143         EFSYS_ASSERT(emop != NULL);
 144 
 145         EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
 146 
 147         if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode],
 148                 loopback_type) == 0) {
 149                 rc = ENOTSUP;
 150                 goto fail1;
 151         }
 152 
 153         if (epp->ep_loopback_type == loopback_type &&
 154             epp->ep_loopback_link_mode == link_mode)
 155                 return (0);
 156 
 157         if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0)
 158                 goto fail2;
 159 
 160         return (0);
 161 
 162 fail2:
 163         EFSYS_PROBE(fail2);
 164 fail1:
 165         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 166 
 167         return (rc);
 168 }
 169 
 170 #if EFSYS_OPT_NAMES
 171 
 172 static const char       *__efx_loopback_type_name[] = {
 173         "OFF",
 174         "DATA",
 175         "GMAC",
 176         "XGMII",
 177         "XGXS",
 178         "XAUI",
 179         "GMII",
 180         "SGMII",
 181         "XGBR",
 182         "XFI",
 183         "XAUI_FAR",
 184         "GMII_FAR",
 185         "SGMII_FAR",
 186         "XFI_FAR",
 187         "GPHY",
 188         "PHY_XS",
 189         "PCS",
 190         "PMA_PMD",
 191         "XPORT",
 192         "XGMII_WS",
 193         "XAUI_WS",
 194         "XAUI_WS_FAR",
 195         "XAUI_WS_NEAR",
 196         "GMII_WS",
 197         "XFI_WS",
 198         "XFI_WS_FAR",
 199         "PHYXS_WS",
 200         "PMA_INT",
 201         "SD_NEAR",
 202         "SD_FAR",
 203         "PMA_INT_WS",
 204         "SD_FEP2_WS",
 205         "SD_FEP1_5_WS",
 206         "SD_FEP_WS",
 207         "SD_FES_WS",
 208 };
 209 
 210         __checkReturn   const char *
 211 efx_loopback_type_name(
 212         __in            efx_nic_t *enp,
 213         __in            efx_loopback_type_t type)
 214 {
 215         EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) ==
 216             EFX_LOOPBACK_NTYPES);
 217 
 218         _NOTE(ARGUNUSED(enp))
 219         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 220         EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);
 221 
 222         return (__efx_loopback_type_name[type]);
 223 }
 224 
 225 #endif  /* EFSYS_OPT_NAMES */
 226 
 227 #endif  /* EFSYS_OPT_LOOPBACK */
 228 
 229                         void
 230 efx_port_fini(
 231         __in            efx_nic_t *enp)
 232 {
 233         efx_port_t *epp = &(enp->en_port);
 234         const efx_phy_ops_t *epop = epp->ep_epop;
 235 
 236         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 237         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 238         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
 239         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
 240 
 241         EFSYS_ASSERT(epp->ep_mac_drain);
 242 
 243         epp->ep_emop = NULL;
 244         epp->ep_mac_type = EFX_MAC_INVALID;
 245         epp->ep_mac_drain = B_FALSE;
 246 
 247         /* Turn off the PHY */
 248         if (epop->epo_power != NULL)
 249                 (void) epop->epo_power(enp, B_FALSE);
 250 
 251         enp->en_mod_flags &= ~EFX_MOD_PORT;
 252 }