1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009-2016 Solarflare Communications Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 *    this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 *    this list of conditions and the following disclaimer in the documentation
14 *    and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * The views and conclusions contained in the software and documentation are
29 * those of the authors and should not be interpreted as representing official
30 * policies, either expressed or implied, of the FreeBSD Project.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "efx.h"
37#include "efx_impl.h"
38
39	__checkReturn	efx_rc_t
40efx_port_init(
41	__in		efx_nic_t *enp)
42{
43	efx_port_t *epp = &(enp->en_port);
44	const efx_phy_ops_t *epop = epp->ep_epop;
45	efx_rc_t rc;
46
47	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
48	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
49	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
50
51	if (enp->en_mod_flags & EFX_MOD_PORT) {
52		rc = EINVAL;
53		goto fail1;
54	}
55
56	enp->en_mod_flags |= EFX_MOD_PORT;
57
58	epp->ep_mac_type = EFX_MAC_INVALID;
59	epp->ep_link_mode = EFX_LINK_UNKNOWN;
60	epp->ep_mac_drain = B_TRUE;
61
62	/* Configure the MAC */
63	if ((rc = efx_mac_select(enp)) != 0)
64		goto fail1;
65
66	epp->ep_emop->emo_reconfigure(enp);
67
68	/* Pick up current phy capababilities */
69	(void) efx_port_poll(enp, NULL);
70
71	/*
72	 * Turn on the PHY if available, otherwise reset it, and
73	 * reconfigure it with the current configuration.
74	 */
75	if (epop->epo_power != NULL) {
76		if ((rc = epop->epo_power(enp, B_TRUE)) != 0)
77			goto fail2;
78	} else {
79		if ((rc = epop->epo_reset(enp)) != 0)
80			goto fail2;
81	}
82
83	EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
84	enp->en_reset_flags &= ~EFX_RESET_PHY;
85
86	if ((rc = epop->epo_reconfigure(enp)) != 0)
87		goto fail3;
88
89	return (0);
90
91fail3:
92	EFSYS_PROBE(fail3);
93fail2:
94	EFSYS_PROBE(fail2);
95fail1:
96	EFSYS_PROBE1(fail1, efx_rc_t, rc);
97
98	enp->en_mod_flags &= ~EFX_MOD_PORT;
99
100	return (rc);
101}
102
103	__checkReturn	efx_rc_t
104efx_port_poll(
105	__in		efx_nic_t *enp,
106	__out_opt	efx_link_mode_t	*link_modep)
107{
108	efx_port_t *epp = &(enp->en_port);
109	const efx_mac_ops_t *emop = epp->ep_emop;
110	efx_link_mode_t ignore_link_mode;
111	efx_rc_t rc;
112
113	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
114	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
115
116	EFSYS_ASSERT(emop != NULL);
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
126fail1:
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
135efx_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	const 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		(int)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
166fail2:
167	EFSYS_PROBE(fail2);
168fail1:
169	EFSYS_PROBE1(fail1, efx_rc_t, rc);
170
171	return (rc);
172}
173
174#if EFSYS_OPT_NAMES
175
176static const char * const __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 *
215efx_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
234efx_port_fini(
235	__in		efx_nic_t *enp)
236{
237	efx_port_t *epp = &(enp->en_port);
238	const 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
251	/* Turn off the PHY */
252	if (epop->epo_power != NULL)
253		(void) epop->epo_power(enp, B_FALSE);
254
255	enp->en_mod_flags &= ~EFX_MOD_PORT;
256}
257