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