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