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 <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "efsys.h" 35 #include "efx.h" 36 #include "efx_types.h" 37 #include "efx_impl.h" 38 39 __checkReturn int 40 efx_port_init( 41 __in efx_nic_t *enp) 42 { 43 efx_port_t *epp = &(enp->en_port); 44 efx_phy_ops_t *epop = epp->ep_epop; 45 int 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_poll_needed = B_TRUE; 61 epp->ep_mac_drain = B_TRUE; 62 63 /* Configure the MAC */ 64 if ((rc = efx_mac_select(enp)) != 0) 65 goto fail1; 66 67 epp->ep_emop->emo_reconfigure(enp); 68 69 /* Pick up current phy capababilities */ 70 efx_port_poll(enp, NULL); 71 72 /* 73 * Turn on the PHY if available, otherwise reset it, and 74 * reconfigure it with the current configuration. 75 */ 76 if (epop->epo_power != NULL) { 77 if ((rc = epop->epo_power(enp, B_TRUE)) != 0) 78 goto fail2; 79 } else { 80 if ((rc = epop->epo_reset(enp)) != 0) 81 goto fail2; 82 } 83 84 EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY); 85 enp->en_reset_flags &= ~EFX_RESET_PHY; 86 87 if ((rc = epop->epo_reconfigure(enp)) != 0) 88 goto fail3; 89 90 return (0); 91 92 fail3: 93 EFSYS_PROBE(fail3); 94 fail2: 95 EFSYS_PROBE(fail2); 96 fail1: 97 EFSYS_PROBE1(fail1, int, rc); 98 99 enp->en_mod_flags &= ~EFX_MOD_PORT; 100 101 return (rc); 102 } 103 104 __checkReturn int 105 efx_port_poll( 106 __in efx_nic_t *enp, 107 __out_opt efx_link_mode_t *link_modep) 108 { 109 efx_port_t *epp = &(enp->en_port); 110 efx_mac_ops_t *emop = epp->ep_emop; 111 efx_link_mode_t ignore_link_mode; 112 int rc; 113 114 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 115 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 116 117 EFSYS_ASSERT(emop != NULL); 118 EFSYS_ASSERT(!epp->ep_mac_stats_pending); 119 120 if (link_modep == NULL) 121 link_modep = &ignore_link_mode; 122 123 if ((rc = emop->emo_poll(enp, link_modep)) != 0) 124 goto fail1; 125 126 return (0); 127 128 fail1: 129 EFSYS_PROBE1(fail1, int, rc); 130 131 return (rc); 132 } 133 134 #if EFSYS_OPT_LOOPBACK 135 136 __checkReturn int 137 efx_port_loopback_set( 138 __in efx_nic_t *enp, 139 __in efx_link_mode_t link_mode, 140 __in efx_loopback_type_t loopback_type) 141 { 142 efx_port_t *epp = &(enp->en_port); 143 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 144 efx_mac_ops_t *emop = epp->ep_emop; 145 int rc; 146 147 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 148 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 149 EFSYS_ASSERT(emop != NULL); 150 151 EFSYS_ASSERT(link_mode < EFX_LINK_NMODES); 152 153 if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode], 154 loopback_type) == 0) { 155 rc = ENOTSUP; 156 goto fail1; 157 } 158 159 if (epp->ep_loopback_type == loopback_type && 160 epp->ep_loopback_link_mode == link_mode) 161 return (0); 162 163 if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0) 164 goto fail2; 165 166 return (0); 167 168 fail2: 169 EFSYS_PROBE(fail2); 170 fail1: 171 EFSYS_PROBE1(fail1, int, rc); 172 173 return (rc); 174 } 175 176 #if EFSYS_OPT_NAMES 177 178 static const char *__efx_loopback_type_name[] = { 179 "OFF", 180 "DATA", 181 "GMAC", 182 "XGMII", 183 "XGXS", 184 "XAUI", 185 "GMII", 186 "SGMII", 187 "XGBR", 188 "XFI", 189 "XAUI_FAR", 190 "GMII_FAR", 191 "SGMII_FAR", 192 "XFI_FAR", 193 "GPHY", 194 "PHY_XS", 195 "PCS", 196 "PMA_PMD", 197 "XPORT", 198 "XGMII_WS", 199 "XAUI_WS", 200 "XAUI_WS_FAR", 201 "XAUI_WS_NEAR", 202 "GMII_WS", 203 "XFI_WS", 204 "XFI_WS_FAR", 205 "PHYXS_WS", 206 "PMA_INT", 207 "SD_NEAR", 208 "SD_FAR", 209 "PMA_INT_WS", 210 "SD_FEP2_WS", 211 "SD_FEP1_5_WS", 212 "SD_FEP_WS", 213 "SD_FES_WS", 214 }; 215 216 __checkReturn const char * 217 efx_loopback_type_name( 218 __in efx_nic_t *enp, 219 __in efx_loopback_type_t type) 220 { 221 EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) == 222 EFX_LOOPBACK_NTYPES); 223 224 _NOTE(ARGUNUSED(enp)) 225 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 226 EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES); 227 228 return (__efx_loopback_type_name[type]); 229 } 230 231 #endif /* EFSYS_OPT_NAMES */ 232 233 #endif /* EFSYS_OPT_LOOPBACK */ 234 235 void 236 efx_port_fini( 237 __in efx_nic_t *enp) 238 { 239 efx_port_t *epp = &(enp->en_port); 240 efx_phy_ops_t *epop = epp->ep_epop; 241 242 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 243 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 244 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 245 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 246 247 EFSYS_ASSERT(epp->ep_mac_drain); 248 249 epp->ep_emop = NULL; 250 epp->ep_mac_type = EFX_MAC_INVALID; 251 epp->ep_mac_drain = B_FALSE; 252 epp->ep_mac_poll_needed = B_FALSE; 253 254 /* Turn off the PHY */ 255 if (epop->epo_power != NULL) 256 (void) epop->epo_power(enp, B_FALSE); 257 258 enp->en_mod_flags &= ~EFX_MOD_PORT; 259 } 260