efx_port.c revision 299517
1227569Sphilip/*- 2283514Sarybchik * Copyright (c) 2009-2015 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_port.c 299517 2016-05-12 06:19:06Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efx.h" 35227569Sphilip#include "efx_impl.h" 36227569Sphilip 37291436Sarybchik __checkReturn efx_rc_t 38227569Sphilipefx_port_init( 39227569Sphilip __in efx_nic_t *enp) 40227569Sphilip{ 41227569Sphilip efx_port_t *epp = &(enp->en_port); 42299517Sarybchik const efx_phy_ops_t *epop = epp->ep_epop; 43291436Sarybchik efx_rc_t rc; 44227569Sphilip 45227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 46227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 47227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 48227569Sphilip 49227569Sphilip if (enp->en_mod_flags & EFX_MOD_PORT) { 50227569Sphilip rc = EINVAL; 51227569Sphilip goto fail1; 52227569Sphilip } 53227569Sphilip 54227569Sphilip enp->en_mod_flags |= EFX_MOD_PORT; 55227569Sphilip 56227569Sphilip epp->ep_mac_type = EFX_MAC_INVALID; 57227569Sphilip epp->ep_link_mode = EFX_LINK_UNKNOWN; 58227569Sphilip epp->ep_mac_drain = B_TRUE; 59227569Sphilip 60227569Sphilip /* Configure the MAC */ 61227569Sphilip if ((rc = efx_mac_select(enp)) != 0) 62227569Sphilip goto fail1; 63227569Sphilip 64227569Sphilip epp->ep_emop->emo_reconfigure(enp); 65227569Sphilip 66283514Sarybchik /* Pick up current phy capababilities */ 67283514Sarybchik efx_port_poll(enp, NULL); 68283514Sarybchik 69227569Sphilip /* 70227569Sphilip * Turn on the PHY if available, otherwise reset it, and 71227569Sphilip * reconfigure it with the current configuration. 72227569Sphilip */ 73227569Sphilip if (epop->epo_power != NULL) { 74227569Sphilip if ((rc = epop->epo_power(enp, B_TRUE)) != 0) 75227569Sphilip goto fail2; 76227569Sphilip } else { 77227569Sphilip if ((rc = epop->epo_reset(enp)) != 0) 78227569Sphilip goto fail2; 79227569Sphilip } 80227569Sphilip 81227569Sphilip EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY); 82227569Sphilip enp->en_reset_flags &= ~EFX_RESET_PHY; 83227569Sphilip 84227569Sphilip if ((rc = epop->epo_reconfigure(enp)) != 0) 85227569Sphilip goto fail3; 86227569Sphilip 87227569Sphilip return (0); 88227569Sphilip 89227569Sphilipfail3: 90227569Sphilip EFSYS_PROBE(fail3); 91227569Sphilipfail2: 92227569Sphilip EFSYS_PROBE(fail2); 93227569Sphilipfail1: 94291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 95227569Sphilip 96227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PORT; 97227569Sphilip 98227569Sphilip return (rc); 99227569Sphilip} 100227569Sphilip 101291436Sarybchik __checkReturn efx_rc_t 102227569Sphilipefx_port_poll( 103227569Sphilip __in efx_nic_t *enp, 104283514Sarybchik __out_opt efx_link_mode_t *link_modep) 105227569Sphilip{ 106227569Sphilip efx_port_t *epp = &(enp->en_port); 107299517Sarybchik const efx_mac_ops_t *emop = epp->ep_emop; 108227569Sphilip efx_link_mode_t ignore_link_mode; 109291436Sarybchik efx_rc_t rc; 110227569Sphilip 111227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 112227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 113227569Sphilip 114227569Sphilip EFSYS_ASSERT(emop != NULL); 115227569Sphilip EFSYS_ASSERT(!epp->ep_mac_stats_pending); 116227569Sphilip 117227569Sphilip if (link_modep == NULL) 118227569Sphilip link_modep = &ignore_link_mode; 119227569Sphilip 120227569Sphilip if ((rc = emop->emo_poll(enp, link_modep)) != 0) 121227569Sphilip goto fail1; 122227569Sphilip 123227569Sphilip return (0); 124227569Sphilip 125227569Sphilipfail1: 126291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 127227569Sphilip 128227569Sphilip return (rc); 129227569Sphilip} 130227569Sphilip 131227569Sphilip#if EFSYS_OPT_LOOPBACK 132227569Sphilip 133291436Sarybchik __checkReturn efx_rc_t 134227569Sphilipefx_port_loopback_set( 135227569Sphilip __in efx_nic_t *enp, 136227569Sphilip __in efx_link_mode_t link_mode, 137227569Sphilip __in efx_loopback_type_t loopback_type) 138227569Sphilip{ 139227569Sphilip efx_port_t *epp = &(enp->en_port); 140227569Sphilip efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 141299517Sarybchik const efx_mac_ops_t *emop = epp->ep_emop; 142291436Sarybchik efx_rc_t rc; 143227569Sphilip 144227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 145227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 146227569Sphilip EFSYS_ASSERT(emop != NULL); 147227569Sphilip 148227569Sphilip EFSYS_ASSERT(link_mode < EFX_LINK_NMODES); 149283514Sarybchik 150283514Sarybchik if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode], 151283514Sarybchik loopback_type) == 0) { 152227569Sphilip rc = ENOTSUP; 153227569Sphilip goto fail1; 154227569Sphilip } 155227569Sphilip 156227569Sphilip if (epp->ep_loopback_type == loopback_type && 157227569Sphilip epp->ep_loopback_link_mode == link_mode) 158227569Sphilip return (0); 159227569Sphilip 160227569Sphilip if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0) 161227569Sphilip goto fail2; 162227569Sphilip 163227569Sphilip return (0); 164227569Sphilip 165227569Sphilipfail2: 166227569Sphilip EFSYS_PROBE(fail2); 167227569Sphilipfail1: 168291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 169227569Sphilip 170227569Sphilip return (rc); 171227569Sphilip} 172227569Sphilip 173227569Sphilip#if EFSYS_OPT_NAMES 174227569Sphilip 175283514Sarybchikstatic const char *__efx_loopback_type_name[] = { 176227569Sphilip "OFF", 177227569Sphilip "DATA", 178227569Sphilip "GMAC", 179227569Sphilip "XGMII", 180227569Sphilip "XGXS", 181227569Sphilip "XAUI", 182227569Sphilip "GMII", 183227569Sphilip "SGMII", 184227569Sphilip "XGBR", 185227569Sphilip "XFI", 186227569Sphilip "XAUI_FAR", 187227569Sphilip "GMII_FAR", 188227569Sphilip "SGMII_FAR", 189227569Sphilip "XFI_FAR", 190227569Sphilip "GPHY", 191227569Sphilip "PHY_XS", 192227569Sphilip "PCS", 193227569Sphilip "PMA_PMD", 194283514Sarybchik "XPORT", 195283514Sarybchik "XGMII_WS", 196283514Sarybchik "XAUI_WS", 197283514Sarybchik "XAUI_WS_FAR", 198283514Sarybchik "XAUI_WS_NEAR", 199283514Sarybchik "GMII_WS", 200283514Sarybchik "XFI_WS", 201283514Sarybchik "XFI_WS_FAR", 202283514Sarybchik "PHYXS_WS", 203283514Sarybchik "PMA_INT", 204283514Sarybchik "SD_NEAR", 205283514Sarybchik "SD_FAR", 206283514Sarybchik "PMA_INT_WS", 207283514Sarybchik "SD_FEP2_WS", 208283514Sarybchik "SD_FEP1_5_WS", 209283514Sarybchik "SD_FEP_WS", 210283514Sarybchik "SD_FES_WS", 211227569Sphilip}; 212227569Sphilip 213283514Sarybchik __checkReturn const char * 214227569Sphilipefx_loopback_type_name( 215227569Sphilip __in efx_nic_t *enp, 216227569Sphilip __in efx_loopback_type_t type) 217227569Sphilip{ 218283514Sarybchik EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) == 219283514Sarybchik EFX_LOOPBACK_NTYPES); 220283514Sarybchik 221227569Sphilip _NOTE(ARGUNUSED(enp)) 222227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 223227569Sphilip EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES); 224227569Sphilip 225227569Sphilip return (__efx_loopback_type_name[type]); 226227569Sphilip} 227227569Sphilip 228227569Sphilip#endif /* EFSYS_OPT_NAMES */ 229227569Sphilip 230227569Sphilip#endif /* EFSYS_OPT_LOOPBACK */ 231227569Sphilip 232227569Sphilip void 233227569Sphilipefx_port_fini( 234227569Sphilip __in efx_nic_t *enp) 235227569Sphilip{ 236227569Sphilip efx_port_t *epp = &(enp->en_port); 237299517Sarybchik const efx_phy_ops_t *epop = epp->ep_epop; 238227569Sphilip 239227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 240227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 241227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 242227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 243227569Sphilip 244227569Sphilip EFSYS_ASSERT(epp->ep_mac_drain); 245227569Sphilip 246227569Sphilip epp->ep_emop = NULL; 247227569Sphilip epp->ep_mac_type = EFX_MAC_INVALID; 248227569Sphilip epp->ep_mac_drain = B_FALSE; 249227569Sphilip 250227569Sphilip /* Turn off the PHY */ 251227569Sphilip if (epop->epo_power != NULL) 252227569Sphilip (void) epop->epo_power(enp, B_FALSE); 253227569Sphilip 254227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PORT; 255227569Sphilip} 256