xref: /freebsd/sys/dev/sfxge/common/efx_port.c (revision 929c7feb83b66d65bde31f02eca36b9bdd65eb9c)
1e948693eSPhilip Paeps /*-
2*929c7febSAndrew Rybchenko  * Copyright (c) 2009-2016 Solarflare Communications Inc.
33c838a9fSAndrew Rybchenko  * All rights reserved.
4e948693eSPhilip Paeps  *
5e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
63c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
7e948693eSPhilip Paeps  *
83c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
93c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
103c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
123c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
133c838a9fSAndrew Rybchenko  *
143c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
153c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
163c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
173c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
183c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
193c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
203c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
213c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
223c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
233c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
243c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253c838a9fSAndrew Rybchenko  *
263c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
273c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
283c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
29e948693eSPhilip Paeps  */
30e948693eSPhilip Paeps 
315dee87d7SPhilip Paeps #include <sys/cdefs.h>
325dee87d7SPhilip Paeps __FBSDID("$FreeBSD$");
335dee87d7SPhilip Paeps 
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps 
37460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
38e948693eSPhilip Paeps efx_port_init(
39e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
40e948693eSPhilip Paeps {
41e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
42ec831f7fSAndrew Rybchenko 	const efx_phy_ops_t *epop = epp->ep_epop;
43460cb568SAndrew Rybchenko 	efx_rc_t rc;
44e948693eSPhilip Paeps 
45e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
46e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
47e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
48e948693eSPhilip Paeps 
49e948693eSPhilip Paeps 	if (enp->en_mod_flags & EFX_MOD_PORT) {
50e948693eSPhilip Paeps 		rc = EINVAL;
51e948693eSPhilip Paeps 		goto fail1;
52e948693eSPhilip Paeps 	}
53e948693eSPhilip Paeps 
54e948693eSPhilip Paeps 	enp->en_mod_flags |= EFX_MOD_PORT;
55e948693eSPhilip Paeps 
56e948693eSPhilip Paeps 	epp->ep_mac_type = EFX_MAC_INVALID;
57e948693eSPhilip Paeps 	epp->ep_link_mode = EFX_LINK_UNKNOWN;
58e948693eSPhilip Paeps 	epp->ep_mac_drain = B_TRUE;
59e948693eSPhilip Paeps 
60e948693eSPhilip Paeps 	/* Configure the MAC */
61e948693eSPhilip Paeps 	if ((rc = efx_mac_select(enp)) != 0)
62e948693eSPhilip Paeps 		goto fail1;
63e948693eSPhilip Paeps 
64e948693eSPhilip Paeps 	epp->ep_emop->emo_reconfigure(enp);
65e948693eSPhilip Paeps 
663c838a9fSAndrew Rybchenko 	/* Pick up current phy capababilities */
673c838a9fSAndrew Rybchenko 	efx_port_poll(enp, NULL);
683c838a9fSAndrew Rybchenko 
69e948693eSPhilip Paeps 	/*
70e948693eSPhilip Paeps 	 * Turn on the PHY if available, otherwise reset it, and
71e948693eSPhilip Paeps 	 * reconfigure it with the current configuration.
72e948693eSPhilip Paeps 	 */
73e948693eSPhilip Paeps 	if (epop->epo_power != NULL) {
74e948693eSPhilip Paeps 		if ((rc = epop->epo_power(enp, B_TRUE)) != 0)
75e948693eSPhilip Paeps 			goto fail2;
76e948693eSPhilip Paeps 	} else {
77e948693eSPhilip Paeps 		if ((rc = epop->epo_reset(enp)) != 0)
78e948693eSPhilip Paeps 			goto fail2;
79e948693eSPhilip Paeps 	}
80e948693eSPhilip Paeps 
81e948693eSPhilip Paeps 	EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
82e948693eSPhilip Paeps 	enp->en_reset_flags &= ~EFX_RESET_PHY;
83e948693eSPhilip Paeps 
84e948693eSPhilip Paeps 	if ((rc = epop->epo_reconfigure(enp)) != 0)
85e948693eSPhilip Paeps 		goto fail3;
86e948693eSPhilip Paeps 
87e948693eSPhilip Paeps 	return (0);
88e948693eSPhilip Paeps 
89e948693eSPhilip Paeps fail3:
90e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
91e948693eSPhilip Paeps fail2:
92e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
93e948693eSPhilip Paeps fail1:
94460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
95e948693eSPhilip Paeps 
96e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_PORT;
97e948693eSPhilip Paeps 
98e948693eSPhilip Paeps 	return (rc);
99e948693eSPhilip Paeps }
100e948693eSPhilip Paeps 
101460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
102e948693eSPhilip Paeps efx_port_poll(
103e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
1043c838a9fSAndrew Rybchenko 	__out_opt	efx_link_mode_t	*link_modep)
105e948693eSPhilip Paeps {
106e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
107ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
108e948693eSPhilip Paeps 	efx_link_mode_t ignore_link_mode;
109460cb568SAndrew Rybchenko 	efx_rc_t rc;
110e948693eSPhilip Paeps 
111e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
112e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
113e948693eSPhilip Paeps 
114e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
115e948693eSPhilip Paeps 	EFSYS_ASSERT(!epp->ep_mac_stats_pending);
116e948693eSPhilip Paeps 
117e948693eSPhilip Paeps 	if (link_modep == NULL)
118e948693eSPhilip Paeps 		link_modep = &ignore_link_mode;
119e948693eSPhilip Paeps 
120e948693eSPhilip Paeps 	if ((rc = emop->emo_poll(enp, link_modep)) != 0)
121e948693eSPhilip Paeps 		goto fail1;
122e948693eSPhilip Paeps 
123e948693eSPhilip Paeps 	return (0);
124e948693eSPhilip Paeps 
125e948693eSPhilip Paeps fail1:
126460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
127e948693eSPhilip Paeps 
128e948693eSPhilip Paeps 	return (rc);
129e948693eSPhilip Paeps }
130e948693eSPhilip Paeps 
131e948693eSPhilip Paeps #if EFSYS_OPT_LOOPBACK
132e948693eSPhilip Paeps 
133460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
134e948693eSPhilip Paeps efx_port_loopback_set(
135e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
136e948693eSPhilip Paeps 	__in		efx_link_mode_t link_mode,
137e948693eSPhilip Paeps 	__in		efx_loopback_type_t loopback_type)
138e948693eSPhilip Paeps {
139e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
140e948693eSPhilip Paeps 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
141ec831f7fSAndrew Rybchenko 	const efx_mac_ops_t *emop = epp->ep_emop;
142460cb568SAndrew Rybchenko 	efx_rc_t rc;
143e948693eSPhilip Paeps 
144e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
145e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
146e948693eSPhilip Paeps 	EFSYS_ASSERT(emop != NULL);
147e948693eSPhilip Paeps 
148e948693eSPhilip Paeps 	EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
1493c838a9fSAndrew Rybchenko 
1503c838a9fSAndrew Rybchenko 	if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode],
1513c838a9fSAndrew Rybchenko 		loopback_type) == 0) {
152e948693eSPhilip Paeps 		rc = ENOTSUP;
153e948693eSPhilip Paeps 		goto fail1;
154e948693eSPhilip Paeps 	}
155e948693eSPhilip Paeps 
156e948693eSPhilip Paeps 	if (epp->ep_loopback_type == loopback_type &&
157e948693eSPhilip Paeps 	    epp->ep_loopback_link_mode == link_mode)
158e948693eSPhilip Paeps 		return (0);
159e948693eSPhilip Paeps 
160e948693eSPhilip Paeps 	if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0)
161e948693eSPhilip Paeps 		goto fail2;
162e948693eSPhilip Paeps 
163e948693eSPhilip Paeps 	return (0);
164e948693eSPhilip Paeps 
165e948693eSPhilip Paeps fail2:
166e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
167e948693eSPhilip Paeps fail1:
168460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
169e948693eSPhilip Paeps 
170e948693eSPhilip Paeps 	return (rc);
171e948693eSPhilip Paeps }
172e948693eSPhilip Paeps 
173e948693eSPhilip Paeps #if EFSYS_OPT_NAMES
174e948693eSPhilip Paeps 
1753c838a9fSAndrew Rybchenko static const char 	*__efx_loopback_type_name[] = {
176e948693eSPhilip Paeps 	"OFF",
177e948693eSPhilip Paeps 	"DATA",
178e948693eSPhilip Paeps 	"GMAC",
179e948693eSPhilip Paeps 	"XGMII",
180e948693eSPhilip Paeps 	"XGXS",
181e948693eSPhilip Paeps 	"XAUI",
182e948693eSPhilip Paeps 	"GMII",
183e948693eSPhilip Paeps 	"SGMII",
184e948693eSPhilip Paeps 	"XGBR",
185e948693eSPhilip Paeps 	"XFI",
186e948693eSPhilip Paeps 	"XAUI_FAR",
187e948693eSPhilip Paeps 	"GMII_FAR",
188e948693eSPhilip Paeps 	"SGMII_FAR",
189e948693eSPhilip Paeps 	"XFI_FAR",
190e948693eSPhilip Paeps 	"GPHY",
191e948693eSPhilip Paeps 	"PHY_XS",
192e948693eSPhilip Paeps 	"PCS",
193e948693eSPhilip Paeps 	"PMA_PMD",
1943c838a9fSAndrew Rybchenko 	"XPORT",
1953c838a9fSAndrew Rybchenko 	"XGMII_WS",
1963c838a9fSAndrew Rybchenko 	"XAUI_WS",
1973c838a9fSAndrew Rybchenko 	"XAUI_WS_FAR",
1983c838a9fSAndrew Rybchenko 	"XAUI_WS_NEAR",
1993c838a9fSAndrew Rybchenko 	"GMII_WS",
2003c838a9fSAndrew Rybchenko 	"XFI_WS",
2013c838a9fSAndrew Rybchenko 	"XFI_WS_FAR",
2023c838a9fSAndrew Rybchenko 	"PHYXS_WS",
2033c838a9fSAndrew Rybchenko 	"PMA_INT",
2043c838a9fSAndrew Rybchenko 	"SD_NEAR",
2053c838a9fSAndrew Rybchenko 	"SD_FAR",
2063c838a9fSAndrew Rybchenko 	"PMA_INT_WS",
2073c838a9fSAndrew Rybchenko 	"SD_FEP2_WS",
2083c838a9fSAndrew Rybchenko 	"SD_FEP1_5_WS",
2093c838a9fSAndrew Rybchenko 	"SD_FEP_WS",
2103c838a9fSAndrew Rybchenko 	"SD_FES_WS",
211e948693eSPhilip Paeps };
212e948693eSPhilip Paeps 
2133c838a9fSAndrew Rybchenko 	__checkReturn	const char *
214e948693eSPhilip Paeps efx_loopback_type_name(
215e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
216e948693eSPhilip Paeps 	__in		efx_loopback_type_t type)
217e948693eSPhilip Paeps {
2183c838a9fSAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) ==
2193c838a9fSAndrew Rybchenko 	    EFX_LOOPBACK_NTYPES);
2203c838a9fSAndrew Rybchenko 
221e948693eSPhilip Paeps 	_NOTE(ARGUNUSED(enp))
222e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
223e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);
224e948693eSPhilip Paeps 
225e948693eSPhilip Paeps 	return (__efx_loopback_type_name[type]);
226e948693eSPhilip Paeps }
227e948693eSPhilip Paeps 
228e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NAMES */
229e948693eSPhilip Paeps 
230e948693eSPhilip Paeps #endif	/* EFSYS_OPT_LOOPBACK */
231e948693eSPhilip Paeps 
232e948693eSPhilip Paeps 			void
233e948693eSPhilip Paeps efx_port_fini(
234e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
235e948693eSPhilip Paeps {
236e948693eSPhilip Paeps 	efx_port_t *epp = &(enp->en_port);
237ec831f7fSAndrew Rybchenko 	const efx_phy_ops_t *epop = epp->ep_epop;
238e948693eSPhilip Paeps 
239e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
240e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
241e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
242e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
243e948693eSPhilip Paeps 
244e948693eSPhilip Paeps 	EFSYS_ASSERT(epp->ep_mac_drain);
245e948693eSPhilip Paeps 
246e948693eSPhilip Paeps 	epp->ep_emop = NULL;
247e948693eSPhilip Paeps 	epp->ep_mac_type = EFX_MAC_INVALID;
248e948693eSPhilip Paeps 	epp->ep_mac_drain = B_FALSE;
249e948693eSPhilip Paeps 
250e948693eSPhilip Paeps 	/* Turn off the PHY */
251e948693eSPhilip Paeps 	if (epop->epo_power != NULL)
252e948693eSPhilip Paeps 		(void) epop->epo_power(enp, B_FALSE);
253e948693eSPhilip Paeps 
254e948693eSPhilip Paeps 	enp->en_mod_flags &= ~EFX_MOD_PORT;
255e948693eSPhilip Paeps }
256