1 /*
2 * Copyright 2009 Solarflare Communications Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include "efsys.h"
27 #include "efx.h"
28 #include "efx_types.h"
29 #include "efx_impl.h"
30
31 __checkReturn int
32 efx_port_init(
33 __in efx_nic_t *enp)
34 {
35 efx_port_t *epp = &(enp->en_port);
36 efx_phy_ops_t *epop = epp->ep_epop;
37 int rc;
38
39 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
40 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
41 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
42
43 if (enp->en_mod_flags & EFX_MOD_PORT) {
44 rc = EINVAL;
45 goto fail1;
46 }
47
48 enp->en_mod_flags |= EFX_MOD_PORT;
49
50 epp->ep_mac_type = EFX_MAC_INVALID;
51 epp->ep_link_mode = EFX_LINK_UNKNOWN;
52 epp->ep_mac_poll_needed = B_TRUE;
53 epp->ep_mac_drain = B_TRUE;
54
55 /* Configure the MAC */
56 if ((rc = efx_mac_select(enp)) != 0)
57 goto fail1;
58
59 epp->ep_emop->emo_reconfigure(enp);
60
61 /*
62 * Turn on the PHY if available, otherwise reset it, and
63 * reconfigure it with the current configuration.
64 */
65 if (epop->epo_power != NULL) {
66 if ((rc = epop->epo_power(enp, B_TRUE)) != 0)
67 goto fail2;
68 } else {
69 if ((rc = epop->epo_reset(enp)) != 0)
70 goto fail2;
71 }
72
73 EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
74 enp->en_reset_flags &= ~EFX_RESET_PHY;
75
76 if ((rc = epop->epo_reconfigure(enp)) != 0)
77 goto fail3;
78
79 return (0);
80
81 fail3:
82 EFSYS_PROBE(fail3);
83 fail2:
84 EFSYS_PROBE(fail2);
85 fail1:
86 EFSYS_PROBE1(fail1, int, rc);
87
88 enp->en_mod_flags &= ~EFX_MOD_PORT;
89
90 return (rc);
91 }
92
93 __checkReturn int
94 efx_port_poll(
95 __in efx_nic_t *enp,
96 __out efx_link_mode_t *link_modep)
97 {
98 efx_port_t *epp = &(enp->en_port);
99 efx_mac_ops_t *emop = epp->ep_emop;
100 efx_link_mode_t ignore_link_mode;
101 int rc;
102
103 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
104 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
105
106 EFSYS_ASSERT(emop != NULL);
107 EFSYS_ASSERT(!epp->ep_mac_stats_pending);
108
109 if (link_modep == NULL)
110 link_modep = &ignore_link_mode;
111
112 if ((rc = emop->emo_poll(enp, link_modep)) != 0)
113 goto fail1;
114
115 return (0);
116
117 fail1:
118 EFSYS_PROBE1(fail1, int, rc);
119
120 return (rc);
121 }
122
123 #if EFSYS_OPT_LOOPBACK
124
125 __checkReturn int
126 efx_port_loopback_set(
127 __in efx_nic_t *enp,
128 __in efx_link_mode_t link_mode,
129 __in efx_loopback_type_t loopback_type)
130 {
131 efx_port_t *epp = &(enp->en_port);
132 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
133 efx_mac_ops_t *emop = epp->ep_emop;
134 int rc;
135
136 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
137 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
138 EFSYS_ASSERT(emop != NULL);
139
140 EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
141 if ((1 << loopback_type) & ~encp->enc_loopback_types[link_mode]) {
142 rc = ENOTSUP;
143 goto fail1;
144 }
145
146 if (epp->ep_loopback_type == loopback_type &&
147 epp->ep_loopback_link_mode == link_mode)
148 return (0);
149
150 if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0)
151 goto fail2;
152
153 return (0);
154
155 fail2:
156 EFSYS_PROBE(fail2);
157 fail1:
158 EFSYS_PROBE1(fail1, int, rc);
159
160 return (rc);
161 }
162
163 #if EFSYS_OPT_NAMES
164
165 static const char __cs * __cs __efx_loopback_type_name[] = {
166 "OFF",
167 "DATA",
168 "GMAC",
169 "XGMII",
170 "XGXS",
171 "XAUI",
172 "GMII",
173 "SGMII",
174 "XGBR",
175 "XFI",
176 "XAUI_FAR",
177 "GMII_FAR",
178 "SGMII_FAR",
179 "XFI_FAR",
180 "GPHY",
181 "PHY_XS",
182 "PCS",
183 "PMA_PMD",
184 };
185
186 __checkReturn const char __cs *
187 efx_loopback_type_name(
188 __in efx_nic_t *enp,
189 __in efx_loopback_type_t type)
190 {
191 _NOTE(ARGUNUSED(enp))
192 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193 EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);
194
195 return (__efx_loopback_type_name[type]);
196 }
197
198 #endif /* EFSYS_OPT_NAMES */
199
200 #endif /* EFSYS_OPT_LOOPBACK */
201
202 void
203 efx_port_fini(
204 __in efx_nic_t *enp)
205 {
206 efx_port_t *epp = &(enp->en_port);
207 efx_phy_ops_t *epop = epp->ep_epop;
208
209 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
210 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
211 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
212 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
213
214 EFSYS_ASSERT(epp->ep_mac_drain);
215
216 epp->ep_emop = NULL;
217 epp->ep_mac_type = EFX_MAC_INVALID;
218 epp->ep_mac_drain = B_FALSE;
219 epp->ep_mac_poll_needed = B_FALSE;
220
221 /* Turn off the PHY */
222 if (epop->epo_power != NULL)
223 (void) epop->epo_power(enp, B_FALSE);
224
225 enp->en_mod_flags &= ~EFX_MOD_PORT;
226 }