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