efx_port.c revision 227569
1227569Sphilip/*- 2227569Sphilip * Copyright 2009 Solarflare Communications Inc. All rights reserved. 3227569Sphilip * 4227569Sphilip * Redistribution and use in source and binary forms, with or without 5227569Sphilip * modification, are permitted provided that the following conditions 6227569Sphilip * are met: 7227569Sphilip * 1. Redistributions of source code must retain the above copyright 8227569Sphilip * notice, this list of conditions and the following disclaimer. 9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright 10227569Sphilip * notice, this list of conditions and the following disclaimer in the 11227569Sphilip * documentation and/or other materials provided with the distribution. 12227569Sphilip * 13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16227569Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23227569Sphilip * SUCH DAMAGE. 24227569Sphilip */ 25227569Sphilip 26227569Sphilip#include "efsys.h" 27227569Sphilip#include "efx.h" 28227569Sphilip#include "efx_types.h" 29227569Sphilip#include "efx_impl.h" 30227569Sphilip 31227569Sphilip __checkReturn int 32227569Sphilipefx_port_init( 33227569Sphilip __in efx_nic_t *enp) 34227569Sphilip{ 35227569Sphilip efx_port_t *epp = &(enp->en_port); 36227569Sphilip efx_phy_ops_t *epop = epp->ep_epop; 37227569Sphilip int rc; 38227569Sphilip 39227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 40227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 41227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 42227569Sphilip 43227569Sphilip if (enp->en_mod_flags & EFX_MOD_PORT) { 44227569Sphilip rc = EINVAL; 45227569Sphilip goto fail1; 46227569Sphilip } 47227569Sphilip 48227569Sphilip enp->en_mod_flags |= EFX_MOD_PORT; 49227569Sphilip 50227569Sphilip epp->ep_mac_type = EFX_MAC_INVALID; 51227569Sphilip epp->ep_link_mode = EFX_LINK_UNKNOWN; 52227569Sphilip epp->ep_mac_poll_needed = B_TRUE; 53227569Sphilip epp->ep_mac_drain = B_TRUE; 54227569Sphilip 55227569Sphilip /* Configure the MAC */ 56227569Sphilip if ((rc = efx_mac_select(enp)) != 0) 57227569Sphilip goto fail1; 58227569Sphilip 59227569Sphilip epp->ep_emop->emo_reconfigure(enp); 60227569Sphilip 61227569Sphilip /* 62227569Sphilip * Turn on the PHY if available, otherwise reset it, and 63227569Sphilip * reconfigure it with the current configuration. 64227569Sphilip */ 65227569Sphilip if (epop->epo_power != NULL) { 66227569Sphilip if ((rc = epop->epo_power(enp, B_TRUE)) != 0) 67227569Sphilip goto fail2; 68227569Sphilip } else { 69227569Sphilip if ((rc = epop->epo_reset(enp)) != 0) 70227569Sphilip goto fail2; 71227569Sphilip } 72227569Sphilip 73227569Sphilip EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY); 74227569Sphilip enp->en_reset_flags &= ~EFX_RESET_PHY; 75227569Sphilip 76227569Sphilip if ((rc = epop->epo_reconfigure(enp)) != 0) 77227569Sphilip goto fail3; 78227569Sphilip 79227569Sphilip return (0); 80227569Sphilip 81227569Sphilipfail3: 82227569Sphilip EFSYS_PROBE(fail3); 83227569Sphilipfail2: 84227569Sphilip EFSYS_PROBE(fail2); 85227569Sphilipfail1: 86227569Sphilip EFSYS_PROBE1(fail1, int, rc); 87227569Sphilip 88227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PORT; 89227569Sphilip 90227569Sphilip return (rc); 91227569Sphilip} 92227569Sphilip 93227569Sphilip __checkReturn int 94227569Sphilipefx_port_poll( 95227569Sphilip __in efx_nic_t *enp, 96227569Sphilip __out efx_link_mode_t *link_modep) 97227569Sphilip{ 98227569Sphilip efx_port_t *epp = &(enp->en_port); 99227569Sphilip efx_mac_ops_t *emop = epp->ep_emop; 100227569Sphilip efx_link_mode_t ignore_link_mode; 101227569Sphilip int rc; 102227569Sphilip 103227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 104227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 105227569Sphilip 106227569Sphilip EFSYS_ASSERT(emop != NULL); 107227569Sphilip EFSYS_ASSERT(!epp->ep_mac_stats_pending); 108227569Sphilip 109227569Sphilip if (link_modep == NULL) 110227569Sphilip link_modep = &ignore_link_mode; 111227569Sphilip 112227569Sphilip if ((rc = emop->emo_poll(enp, link_modep)) != 0) 113227569Sphilip goto fail1; 114227569Sphilip 115227569Sphilip return (0); 116227569Sphilip 117227569Sphilipfail1: 118227569Sphilip EFSYS_PROBE1(fail1, int, rc); 119227569Sphilip 120227569Sphilip return (rc); 121227569Sphilip} 122227569Sphilip 123227569Sphilip#if EFSYS_OPT_LOOPBACK 124227569Sphilip 125227569Sphilip __checkReturn int 126227569Sphilipefx_port_loopback_set( 127227569Sphilip __in efx_nic_t *enp, 128227569Sphilip __in efx_link_mode_t link_mode, 129227569Sphilip __in efx_loopback_type_t loopback_type) 130227569Sphilip{ 131227569Sphilip efx_port_t *epp = &(enp->en_port); 132227569Sphilip efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 133227569Sphilip efx_mac_ops_t *emop = epp->ep_emop; 134227569Sphilip int rc; 135227569Sphilip 136227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 137227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 138227569Sphilip EFSYS_ASSERT(emop != NULL); 139227569Sphilip 140227569Sphilip EFSYS_ASSERT(link_mode < EFX_LINK_NMODES); 141227569Sphilip if ((1 << loopback_type) & ~encp->enc_loopback_types[link_mode]) { 142227569Sphilip rc = ENOTSUP; 143227569Sphilip goto fail1; 144227569Sphilip } 145227569Sphilip 146227569Sphilip if (epp->ep_loopback_type == loopback_type && 147227569Sphilip epp->ep_loopback_link_mode == link_mode) 148227569Sphilip return (0); 149227569Sphilip 150227569Sphilip if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0) 151227569Sphilip goto fail2; 152227569Sphilip 153227569Sphilip return (0); 154227569Sphilip 155227569Sphilipfail2: 156227569Sphilip EFSYS_PROBE(fail2); 157227569Sphilipfail1: 158227569Sphilip EFSYS_PROBE1(fail1, int, rc); 159227569Sphilip 160227569Sphilip return (rc); 161227569Sphilip} 162227569Sphilip 163227569Sphilip#if EFSYS_OPT_NAMES 164227569Sphilip 165227569Sphilipstatic const char __cs * __cs __efx_loopback_type_name[] = { 166227569Sphilip "OFF", 167227569Sphilip "DATA", 168227569Sphilip "GMAC", 169227569Sphilip "XGMII", 170227569Sphilip "XGXS", 171227569Sphilip "XAUI", 172227569Sphilip "GMII", 173227569Sphilip "SGMII", 174227569Sphilip "XGBR", 175227569Sphilip "XFI", 176227569Sphilip "XAUI_FAR", 177227569Sphilip "GMII_FAR", 178227569Sphilip "SGMII_FAR", 179227569Sphilip "XFI_FAR", 180227569Sphilip "GPHY", 181227569Sphilip "PHY_XS", 182227569Sphilip "PCS", 183227569Sphilip "PMA_PMD", 184227569Sphilip}; 185227569Sphilip 186227569Sphilip __checkReturn const char __cs * 187227569Sphilipefx_loopback_type_name( 188227569Sphilip __in efx_nic_t *enp, 189227569Sphilip __in efx_loopback_type_t type) 190227569Sphilip{ 191227569Sphilip _NOTE(ARGUNUSED(enp)) 192227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 193227569Sphilip EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES); 194227569Sphilip 195227569Sphilip return (__efx_loopback_type_name[type]); 196227569Sphilip} 197227569Sphilip 198227569Sphilip#endif /* EFSYS_OPT_NAMES */ 199227569Sphilip 200227569Sphilip#endif /* EFSYS_OPT_LOOPBACK */ 201227569Sphilip 202227569Sphilip void 203227569Sphilipefx_port_fini( 204227569Sphilip __in efx_nic_t *enp) 205227569Sphilip{ 206227569Sphilip efx_port_t *epp = &(enp->en_port); 207227569Sphilip efx_phy_ops_t *epop = epp->ep_epop; 208227569Sphilip 209227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 210227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 211227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 212227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 213227569Sphilip 214227569Sphilip EFSYS_ASSERT(epp->ep_mac_drain); 215227569Sphilip 216227569Sphilip epp->ep_emop = NULL; 217227569Sphilip epp->ep_mac_type = EFX_MAC_INVALID; 218227569Sphilip epp->ep_mac_drain = B_FALSE; 219227569Sphilip epp->ep_mac_poll_needed = B_FALSE; 220227569Sphilip 221227569Sphilip /* Turn off the PHY */ 222227569Sphilip if (epop->epo_power != NULL) 223227569Sphilip (void) epop->epo_power(enp, B_FALSE); 224227569Sphilip 225227569Sphilip enp->en_mod_flags &= ~EFX_MOD_PORT; 226227569Sphilip} 227