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