efx_port.c revision 283514
1202878Srdivacky/*-
2202878Srdivacky * Copyright (c) 2009-2015 Solarflare Communications Inc.
3202878Srdivacky * All rights reserved.
4202878Srdivacky *
5202878Srdivacky * Redistribution and use in source and binary forms, with or without
6202878Srdivacky * modification, are permitted provided that the following conditions are met:
7202878Srdivacky *
8202878Srdivacky * 1. Redistributions of source code must retain the above copyright notice,
9202878Srdivacky *    this list of conditions and the following disclaimer.
10202878Srdivacky * 2. Redistributions in binary form must reproduce the above copyright notice,
11202878Srdivacky *    this list of conditions and the following disclaimer in the documentation
12202878Srdivacky *    and/or other materials provided with the distribution.
13202878Srdivacky *
14202878Srdivacky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15202878Srdivacky * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16202878Srdivacky * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17202878Srdivacky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18202878Srdivacky * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19202878Srdivacky * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20202878Srdivacky * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21202878Srdivacky * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22202878Srdivacky * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23202878Srdivacky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24202878Srdivacky * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25202878Srdivacky *
26202878Srdivacky * The views and conclusions contained in the software and documentation are
27202878Srdivacky * those of the authors and should not be interpreted as representing official
28202878Srdivacky * policies, either expressed or implied, of the FreeBSD Project.
29202878Srdivacky */
30202878Srdivacky
31202878Srdivacky#include <sys/cdefs.h>
32202878Srdivacky__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_port.c 283514 2015-05-25 08:34:55Z arybchik $");
33202878Srdivacky
34202878Srdivacky#include "efsys.h"
35202878Srdivacky#include "efx.h"
36202878Srdivacky#include "efx_types.h"
37202878Srdivacky#include "efx_impl.h"
38202878Srdivacky
39202878Srdivacky	__checkReturn	int
40202878Srdivackyefx_port_init(
41202878Srdivacky	__in		efx_nic_t *enp)
42202878Srdivacky{
43202878Srdivacky	efx_port_t *epp = &(enp->en_port);
44202878Srdivacky	efx_phy_ops_t *epop = epp->ep_epop;
45202878Srdivacky	int rc;
46202878Srdivacky
47202878Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
48202878Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
49202878Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
50202878Srdivacky
51202878Srdivacky	if (enp->en_mod_flags & EFX_MOD_PORT) {
52202878Srdivacky		rc = EINVAL;
53202878Srdivacky		goto fail1;
54202878Srdivacky	}
55202878Srdivacky
56202878Srdivacky	enp->en_mod_flags |= EFX_MOD_PORT;
57202878Srdivacky
58202878Srdivacky	epp->ep_mac_type = EFX_MAC_INVALID;
59202878Srdivacky	epp->ep_link_mode = EFX_LINK_UNKNOWN;
60202878Srdivacky	epp->ep_mac_poll_needed = B_TRUE;
61202878Srdivacky	epp->ep_mac_drain = B_TRUE;
62202878Srdivacky
63202878Srdivacky	/* Configure the MAC */
64202878Srdivacky	if ((rc = efx_mac_select(enp)) != 0)
65202878Srdivacky		goto fail1;
66202878Srdivacky
67202878Srdivacky	epp->ep_emop->emo_reconfigure(enp);
68202878Srdivacky
69202878Srdivacky	/* Pick up current phy capababilities */
70202878Srdivacky	efx_port_poll(enp, NULL);
71202878Srdivacky
72202878Srdivacky	/*
73202878Srdivacky	 * Turn on the PHY if available, otherwise reset it, and
74202878Srdivacky	 * reconfigure it with the current configuration.
75202878Srdivacky	 */
76202878Srdivacky	if (epop->epo_power != NULL) {
77207618Srdivacky		if ((rc = epop->epo_power(enp, B_TRUE)) != 0)
78207618Srdivacky			goto fail2;
79207618Srdivacky	} else {
80207618Srdivacky		if ((rc = epop->epo_reset(enp)) != 0)
81207618Srdivacky			goto fail2;
82202878Srdivacky	}
83202878Srdivacky
84202878Srdivacky	EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
85202878Srdivacky	enp->en_reset_flags &= ~EFX_RESET_PHY;
86202878Srdivacky
87202878Srdivacky	if ((rc = epop->epo_reconfigure(enp)) != 0)
88202878Srdivacky		goto fail3;
89202878Srdivacky
90202878Srdivacky	return (0);
91202878Srdivacky
92202878Srdivackyfail3:
93202878Srdivacky	EFSYS_PROBE(fail3);
94202878Srdivackyfail2:
95202878Srdivacky	EFSYS_PROBE(fail2);
96202878Srdivackyfail1:
97202878Srdivacky	EFSYS_PROBE1(fail1, int, rc);
98202878Srdivacky
99202878Srdivacky	enp->en_mod_flags &= ~EFX_MOD_PORT;
100202878Srdivacky
101202878Srdivacky	return (rc);
102202878Srdivacky}
103202878Srdivacky
104202878Srdivacky	__checkReturn	int
105202878Srdivackyefx_port_poll(
106202878Srdivacky	__in		efx_nic_t *enp,
107202878Srdivacky	__out_opt	efx_link_mode_t	*link_modep)
108202878Srdivacky{
109202878Srdivacky	efx_port_t *epp = &(enp->en_port);
110202878Srdivacky	efx_mac_ops_t *emop = epp->ep_emop;
111202878Srdivacky	efx_link_mode_t ignore_link_mode;
112202878Srdivacky	int rc;
113202878Srdivacky
114202878Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
115202878Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
116202878Srdivacky
117202878Srdivacky	EFSYS_ASSERT(emop != NULL);
118202878Srdivacky	EFSYS_ASSERT(!epp->ep_mac_stats_pending);
119202878Srdivacky
120202878Srdivacky	if (link_modep == NULL)
121202878Srdivacky		link_modep = &ignore_link_mode;
122202878Srdivacky
123202878Srdivacky	if ((rc = emop->emo_poll(enp, link_modep)) != 0)
124202878Srdivacky		goto fail1;
125202878Srdivacky
126202878Srdivacky	return (0);
127202878Srdivacky
128202878Srdivackyfail1:
129202878Srdivacky	EFSYS_PROBE1(fail1, int, rc);
130202878Srdivacky
131202878Srdivacky	return (rc);
132202878Srdivacky}
133202878Srdivacky
134202878Srdivacky#if EFSYS_OPT_LOOPBACK
135202878Srdivacky
136202878Srdivacky	__checkReturn	int
137202878Srdivackyefx_port_loopback_set(
138202878Srdivacky	__in		efx_nic_t *enp,
139202878Srdivacky	__in		efx_link_mode_t link_mode,
140202878Srdivacky	__in		efx_loopback_type_t loopback_type)
141202878Srdivacky{
142202878Srdivacky	efx_port_t *epp = &(enp->en_port);
143205218Srdivacky	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
144205218Srdivacky	efx_mac_ops_t *emop = epp->ep_emop;
145205218Srdivacky	int rc;
146205218Srdivacky
147205218Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
148205218Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
149205218Srdivacky	EFSYS_ASSERT(emop != NULL);
150205218Srdivacky
151202878Srdivacky	EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
152202878Srdivacky
153202878Srdivacky	if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode],
154202878Srdivacky		loopback_type) == 0) {
155202878Srdivacky		rc = ENOTSUP;
156208599Srdivacky		goto fail1;
157208599Srdivacky	}
158208599Srdivacky
159208599Srdivacky	if (epp->ep_loopback_type == loopback_type &&
160208599Srdivacky	    epp->ep_loopback_link_mode == link_mode)
161208599Srdivacky		return (0);
162202878Srdivacky
163202878Srdivacky	if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0)
164202878Srdivacky		goto fail2;
165202878Srdivacky
166202878Srdivacky	return (0);
167202878Srdivacky
168202878Srdivackyfail2:
169202878Srdivacky	EFSYS_PROBE(fail2);
170202878Srdivackyfail1:
171202878Srdivacky	EFSYS_PROBE1(fail1, int, rc);
172202878Srdivacky
173202878Srdivacky	return (rc);
174202878Srdivacky}
175202878Srdivacky
176202878Srdivacky#if EFSYS_OPT_NAMES
177202878Srdivacky
178202878Srdivackystatic const char 	*__efx_loopback_type_name[] = {
179202878Srdivacky	"OFF",
180202878Srdivacky	"DATA",
181202878Srdivacky	"GMAC",
182202878Srdivacky	"XGMII",
183202878Srdivacky	"XGXS",
184202878Srdivacky	"XAUI",
185202878Srdivacky	"GMII",
186202878Srdivacky	"SGMII",
187202878Srdivacky	"XGBR",
188202878Srdivacky	"XFI",
189202878Srdivacky	"XAUI_FAR",
190202878Srdivacky	"GMII_FAR",
191202878Srdivacky	"SGMII_FAR",
192202878Srdivacky	"XFI_FAR",
193202878Srdivacky	"GPHY",
194202878Srdivacky	"PHY_XS",
195202878Srdivacky	"PCS",
196202878Srdivacky	"PMA_PMD",
197202878Srdivacky	"XPORT",
198202878Srdivacky	"XGMII_WS",
199202878Srdivacky	"XAUI_WS",
200202878Srdivacky	"XAUI_WS_FAR",
201202878Srdivacky	"XAUI_WS_NEAR",
202202878Srdivacky	"GMII_WS",
203202878Srdivacky	"XFI_WS",
204202878Srdivacky	"XFI_WS_FAR",
205202878Srdivacky	"PHYXS_WS",
206202878Srdivacky	"PMA_INT",
207202878Srdivacky	"SD_NEAR",
208202878Srdivacky	"SD_FAR",
209202878Srdivacky	"PMA_INT_WS",
210202878Srdivacky	"SD_FEP2_WS",
211202878Srdivacky	"SD_FEP1_5_WS",
212202878Srdivacky	"SD_FEP_WS",
213202878Srdivacky	"SD_FES_WS",
214202878Srdivacky};
215202878Srdivacky
216202878Srdivacky	__checkReturn	const char *
217202878Srdivackyefx_loopback_type_name(
218202878Srdivacky	__in		efx_nic_t *enp,
219202878Srdivacky	__in		efx_loopback_type_t type)
220202878Srdivacky{
221202878Srdivacky	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) ==
222202878Srdivacky	    EFX_LOOPBACK_NTYPES);
223202878Srdivacky
224202878Srdivacky	_NOTE(ARGUNUSED(enp))
225202878Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
226202878Srdivacky	EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);
227202878Srdivacky
228202878Srdivacky	return (__efx_loopback_type_name[type]);
229202878Srdivacky}
230202878Srdivacky
231202878Srdivacky#endif	/* EFSYS_OPT_NAMES */
232202878Srdivacky
233202878Srdivacky#endif	/* EFSYS_OPT_LOOPBACK */
234202878Srdivacky
235202878Srdivacky			void
236202878Srdivackyefx_port_fini(
237202878Srdivacky	__in		efx_nic_t *enp)
238202878Srdivacky{
239202878Srdivacky	efx_port_t *epp = &(enp->en_port);
240202878Srdivacky	efx_phy_ops_t *epop = epp->ep_epop;
241202878Srdivacky
242202878Srdivacky	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
243202878Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
244202878Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
245202878Srdivacky	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
246202878Srdivacky
247202878Srdivacky	EFSYS_ASSERT(epp->ep_mac_drain);
248202878Srdivacky
249202878Srdivacky	epp->ep_emop = NULL;
250202878Srdivacky	epp->ep_mac_type = EFX_MAC_INVALID;
251202878Srdivacky	epp->ep_mac_drain = B_FALSE;
252202878Srdivacky	epp->ep_mac_poll_needed = B_FALSE;
253202878Srdivacky
254202878Srdivacky	/* Turn off the PHY */
255202878Srdivacky	if (epop->epo_power != NULL)
256202878Srdivacky		(void) epop->epo_power(enp, B_FALSE);
257202878Srdivacky
258202878Srdivacky	enp->en_mod_flags &= ~EFX_MOD_PORT;
259202878Srdivacky}
260202878Srdivacky