1647112a4SAndrew Rybchenko /*-
2929c7febSAndrew Rybchenko * Copyright (c) 2012-2016 Solarflare Communications Inc.
3647112a4SAndrew Rybchenko * All rights reserved.
4647112a4SAndrew Rybchenko *
5647112a4SAndrew Rybchenko * Redistribution and use in source and binary forms, with or without
6647112a4SAndrew Rybchenko * modification, are permitted provided that the following conditions are met:
7647112a4SAndrew Rybchenko *
8647112a4SAndrew Rybchenko * 1. Redistributions of source code must retain the above copyright notice,
9647112a4SAndrew Rybchenko * this list of conditions and the following disclaimer.
10647112a4SAndrew Rybchenko * 2. Redistributions in binary form must reproduce the above copyright notice,
11647112a4SAndrew Rybchenko * this list of conditions and the following disclaimer in the documentation
12647112a4SAndrew Rybchenko * and/or other materials provided with the distribution.
13647112a4SAndrew Rybchenko *
14647112a4SAndrew Rybchenko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15647112a4SAndrew Rybchenko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16647112a4SAndrew Rybchenko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17647112a4SAndrew Rybchenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18647112a4SAndrew Rybchenko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19647112a4SAndrew Rybchenko * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20647112a4SAndrew Rybchenko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21647112a4SAndrew Rybchenko * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22647112a4SAndrew Rybchenko * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23647112a4SAndrew Rybchenko * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24647112a4SAndrew Rybchenko * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25647112a4SAndrew Rybchenko *
26647112a4SAndrew Rybchenko * The views and conclusions contained in the software and documentation are
27647112a4SAndrew Rybchenko * those of the authors and should not be interpreted as representing official
28647112a4SAndrew Rybchenko * policies, either expressed or implied, of the FreeBSD Project.
29647112a4SAndrew Rybchenko */
30647112a4SAndrew Rybchenko
31647112a4SAndrew Rybchenko #include <sys/cdefs.h>
32647112a4SAndrew Rybchenko #include "efx.h"
33647112a4SAndrew Rybchenko #include "efx_impl.h"
34647112a4SAndrew Rybchenko
3510d4c14dSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
36647112a4SAndrew Rybchenko
37647112a4SAndrew Rybchenko static void
mcdi_phy_decode_cap(__in uint32_t mcdi_cap,__out uint32_t * maskp)38647112a4SAndrew Rybchenko mcdi_phy_decode_cap(
39647112a4SAndrew Rybchenko __in uint32_t mcdi_cap,
40647112a4SAndrew Rybchenko __out uint32_t *maskp)
41647112a4SAndrew Rybchenko {
42647112a4SAndrew Rybchenko uint32_t mask;
43647112a4SAndrew Rybchenko
44d81df221SAndrew Rybchenko #define CHECK_CAP(_cap) \
45d81df221SAndrew Rybchenko EFX_STATIC_ASSERT(EFX_PHY_CAP_##_cap == MC_CMD_PHY_CAP_##_cap##_LBN)
46d81df221SAndrew Rybchenko
47d81df221SAndrew Rybchenko CHECK_CAP(10HDX);
48d81df221SAndrew Rybchenko CHECK_CAP(10FDX);
49d81df221SAndrew Rybchenko CHECK_CAP(100HDX);
50d81df221SAndrew Rybchenko CHECK_CAP(100FDX);
51d81df221SAndrew Rybchenko CHECK_CAP(1000HDX);
52d81df221SAndrew Rybchenko CHECK_CAP(1000FDX);
53d81df221SAndrew Rybchenko CHECK_CAP(10000FDX);
54d81df221SAndrew Rybchenko CHECK_CAP(25000FDX);
55d81df221SAndrew Rybchenko CHECK_CAP(40000FDX);
56d81df221SAndrew Rybchenko CHECK_CAP(50000FDX);
57d81df221SAndrew Rybchenko CHECK_CAP(100000FDX);
58d81df221SAndrew Rybchenko CHECK_CAP(PAUSE);
59d81df221SAndrew Rybchenko CHECK_CAP(ASYM);
60d81df221SAndrew Rybchenko CHECK_CAP(AN);
61d81df221SAndrew Rybchenko CHECK_CAP(DDM);
62ffde7424SAndrew Rybchenko CHECK_CAP(BASER_FEC);
63ffde7424SAndrew Rybchenko CHECK_CAP(BASER_FEC_REQUESTED);
64ffde7424SAndrew Rybchenko CHECK_CAP(RS_FEC);
65ffde7424SAndrew Rybchenko CHECK_CAP(RS_FEC_REQUESTED);
66ffde7424SAndrew Rybchenko CHECK_CAP(25G_BASER_FEC);
67ffde7424SAndrew Rybchenko CHECK_CAP(25G_BASER_FEC_REQUESTED);
68d81df221SAndrew Rybchenko #undef CHECK_CAP
69d81df221SAndrew Rybchenko
70647112a4SAndrew Rybchenko mask = 0;
71647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
72647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_10HDX);
73647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
74647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_10FDX);
75647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
76647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_100HDX);
77647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
78647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_100FDX);
79647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
80647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_1000HDX);
81647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
82647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_1000FDX);
83647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
84647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_10000FDX);
85d81df221SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN))
86d81df221SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_25000FDX);
87647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
88647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_40000FDX);
89d81df221SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))
90d81df221SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_50000FDX);
91d81df221SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN))
92d81df221SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_100000FDX);
93d81df221SAndrew Rybchenko
94647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
95647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_PAUSE);
96647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
97647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_ASYM);
98647112a4SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
99647112a4SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_AN);
100647112a4SAndrew Rybchenko
101ffde7424SAndrew Rybchenko /* FEC caps (supported on Medford2 and later) */
102ffde7424SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))
103ffde7424SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_BASER_FEC);
104ffde7424SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN))
105ffde7424SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_BASER_FEC_REQUESTED);
106ffde7424SAndrew Rybchenko
107ffde7424SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))
108ffde7424SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_RS_FEC);
109ffde7424SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN))
110ffde7424SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_RS_FEC_REQUESTED);
111ffde7424SAndrew Rybchenko
112ffde7424SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))
113ffde7424SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC);
114ffde7424SAndrew Rybchenko if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN))
115ffde7424SAndrew Rybchenko mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED);
116ffde7424SAndrew Rybchenko
117647112a4SAndrew Rybchenko *maskp = mask;
118647112a4SAndrew Rybchenko }
119647112a4SAndrew Rybchenko
120647112a4SAndrew Rybchenko static void
mcdi_phy_decode_link_mode(__in efx_nic_t * enp,__in uint32_t link_flags,__in unsigned int speed,__in unsigned int fcntl,__in uint32_t fec,__out efx_link_mode_t * link_modep,__out unsigned int * fcntlp,__out efx_phy_fec_type_t * fecp)121647112a4SAndrew Rybchenko mcdi_phy_decode_link_mode(
122647112a4SAndrew Rybchenko __in efx_nic_t *enp,
123647112a4SAndrew Rybchenko __in uint32_t link_flags,
124647112a4SAndrew Rybchenko __in unsigned int speed,
125647112a4SAndrew Rybchenko __in unsigned int fcntl,
126a8c1489fSAndrew Rybchenko __in uint32_t fec,
127647112a4SAndrew Rybchenko __out efx_link_mode_t *link_modep,
128a8c1489fSAndrew Rybchenko __out unsigned int *fcntlp,
129a8c1489fSAndrew Rybchenko __out efx_phy_fec_type_t *fecp)
130647112a4SAndrew Rybchenko {
131647112a4SAndrew Rybchenko boolean_t fd = !!(link_flags &
132647112a4SAndrew Rybchenko (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
133647112a4SAndrew Rybchenko boolean_t up = !!(link_flags &
134647112a4SAndrew Rybchenko (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
135647112a4SAndrew Rybchenko
136647112a4SAndrew Rybchenko _NOTE(ARGUNUSED(enp))
137647112a4SAndrew Rybchenko
138647112a4SAndrew Rybchenko if (!up)
139647112a4SAndrew Rybchenko *link_modep = EFX_LINK_DOWN;
140d81df221SAndrew Rybchenko else if (speed == 100000 && fd)
141d81df221SAndrew Rybchenko *link_modep = EFX_LINK_100000FDX;
142d81df221SAndrew Rybchenko else if (speed == 50000 && fd)
143d81df221SAndrew Rybchenko *link_modep = EFX_LINK_50000FDX;
144647112a4SAndrew Rybchenko else if (speed == 40000 && fd)
145647112a4SAndrew Rybchenko *link_modep = EFX_LINK_40000FDX;
146d81df221SAndrew Rybchenko else if (speed == 25000 && fd)
147d81df221SAndrew Rybchenko *link_modep = EFX_LINK_25000FDX;
148647112a4SAndrew Rybchenko else if (speed == 10000 && fd)
149647112a4SAndrew Rybchenko *link_modep = EFX_LINK_10000FDX;
150647112a4SAndrew Rybchenko else if (speed == 1000)
151647112a4SAndrew Rybchenko *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
152647112a4SAndrew Rybchenko else if (speed == 100)
153647112a4SAndrew Rybchenko *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
154647112a4SAndrew Rybchenko else if (speed == 10)
155647112a4SAndrew Rybchenko *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
156647112a4SAndrew Rybchenko else
157647112a4SAndrew Rybchenko *link_modep = EFX_LINK_UNKNOWN;
158647112a4SAndrew Rybchenko
159647112a4SAndrew Rybchenko if (fcntl == MC_CMD_FCNTL_OFF)
160647112a4SAndrew Rybchenko *fcntlp = 0;
161647112a4SAndrew Rybchenko else if (fcntl == MC_CMD_FCNTL_RESPOND)
162647112a4SAndrew Rybchenko *fcntlp = EFX_FCNTL_RESPOND;
163647112a4SAndrew Rybchenko else if (fcntl == MC_CMD_FCNTL_GENERATE)
164647112a4SAndrew Rybchenko *fcntlp = EFX_FCNTL_GENERATE;
165647112a4SAndrew Rybchenko else if (fcntl == MC_CMD_FCNTL_BIDIR)
166647112a4SAndrew Rybchenko *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
167647112a4SAndrew Rybchenko else {
168647112a4SAndrew Rybchenko EFSYS_PROBE1(mc_pcol_error, int, fcntl);
169647112a4SAndrew Rybchenko *fcntlp = 0;
170647112a4SAndrew Rybchenko }
171a8c1489fSAndrew Rybchenko
172a8c1489fSAndrew Rybchenko switch (fec) {
173a8c1489fSAndrew Rybchenko case MC_CMD_FEC_NONE:
174a8c1489fSAndrew Rybchenko *fecp = EFX_PHY_FEC_NONE;
175a8c1489fSAndrew Rybchenko break;
176a8c1489fSAndrew Rybchenko case MC_CMD_FEC_BASER:
177a8c1489fSAndrew Rybchenko *fecp = EFX_PHY_FEC_BASER;
178a8c1489fSAndrew Rybchenko break;
179a8c1489fSAndrew Rybchenko case MC_CMD_FEC_RS:
180a8c1489fSAndrew Rybchenko *fecp = EFX_PHY_FEC_RS;
181a8c1489fSAndrew Rybchenko break;
182a8c1489fSAndrew Rybchenko default:
183a8c1489fSAndrew Rybchenko EFSYS_PROBE1(mc_pcol_error, int, fec);
184a8c1489fSAndrew Rybchenko *fecp = EFX_PHY_FEC_NONE;
185a8c1489fSAndrew Rybchenko break;
186a8c1489fSAndrew Rybchenko }
187647112a4SAndrew Rybchenko }
188647112a4SAndrew Rybchenko
189647112a4SAndrew Rybchenko void
ef10_phy_link_ev(__in efx_nic_t * enp,__in efx_qword_t * eqp,__out efx_link_mode_t * link_modep)190647112a4SAndrew Rybchenko ef10_phy_link_ev(
191647112a4SAndrew Rybchenko __in efx_nic_t *enp,
192647112a4SAndrew Rybchenko __in efx_qword_t *eqp,
193647112a4SAndrew Rybchenko __out efx_link_mode_t *link_modep)
194647112a4SAndrew Rybchenko {
195647112a4SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
196647112a4SAndrew Rybchenko unsigned int link_flags;
197647112a4SAndrew Rybchenko unsigned int speed;
198647112a4SAndrew Rybchenko unsigned int fcntl;
199a8c1489fSAndrew Rybchenko efx_phy_fec_type_t fec = MC_CMD_FEC_NONE;
200647112a4SAndrew Rybchenko efx_link_mode_t link_mode;
201647112a4SAndrew Rybchenko uint32_t lp_cap_mask;
202647112a4SAndrew Rybchenko
203647112a4SAndrew Rybchenko /*
204647112a4SAndrew Rybchenko * Convert the LINKCHANGE speed enumeration into mbit/s, in the
205647112a4SAndrew Rybchenko * same way as GET_LINK encodes the speed
206647112a4SAndrew Rybchenko */
207647112a4SAndrew Rybchenko switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
208647112a4SAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_100M:
209647112a4SAndrew Rybchenko speed = 100;
210647112a4SAndrew Rybchenko break;
211647112a4SAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_1G:
212647112a4SAndrew Rybchenko speed = 1000;
213647112a4SAndrew Rybchenko break;
214647112a4SAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_10G:
215647112a4SAndrew Rybchenko speed = 10000;
216647112a4SAndrew Rybchenko break;
217f50efe9aSAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_25G:
218f50efe9aSAndrew Rybchenko speed = 25000;
219f50efe9aSAndrew Rybchenko break;
220647112a4SAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_40G:
221647112a4SAndrew Rybchenko speed = 40000;
222647112a4SAndrew Rybchenko break;
223f50efe9aSAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_50G:
224f50efe9aSAndrew Rybchenko speed = 50000;
225f50efe9aSAndrew Rybchenko break;
226f50efe9aSAndrew Rybchenko case MCDI_EVENT_LINKCHANGE_SPEED_100G:
227f50efe9aSAndrew Rybchenko speed = 100000;
228f50efe9aSAndrew Rybchenko break;
229647112a4SAndrew Rybchenko default:
230647112a4SAndrew Rybchenko speed = 0;
231647112a4SAndrew Rybchenko break;
232647112a4SAndrew Rybchenko }
233647112a4SAndrew Rybchenko
234647112a4SAndrew Rybchenko link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
235647112a4SAndrew Rybchenko mcdi_phy_decode_link_mode(enp, link_flags, speed,
236647112a4SAndrew Rybchenko MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
237a8c1489fSAndrew Rybchenko MC_CMD_FEC_NONE, &link_mode,
238a8c1489fSAndrew Rybchenko &fcntl, &fec);
239647112a4SAndrew Rybchenko mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
240647112a4SAndrew Rybchenko &lp_cap_mask);
241647112a4SAndrew Rybchenko
242647112a4SAndrew Rybchenko /*
243647112a4SAndrew Rybchenko * It's safe to update ep_lp_cap_mask without the driver's port lock
244647112a4SAndrew Rybchenko * because presumably any concurrently running efx_port_poll() is
245647112a4SAndrew Rybchenko * only going to arrive at the same value.
246647112a4SAndrew Rybchenko *
247647112a4SAndrew Rybchenko * ep_fcntl has two meanings. It's either the link common fcntl
248647112a4SAndrew Rybchenko * (if the PHY supports AN), or it's the forced link state. If
249647112a4SAndrew Rybchenko * the former, it's safe to update the value for the same reason as
250647112a4SAndrew Rybchenko * for ep_lp_cap_mask. If the latter, then just ignore the value,
251647112a4SAndrew Rybchenko * because we can race with efx_mac_fcntl_set().
252647112a4SAndrew Rybchenko */
253647112a4SAndrew Rybchenko epp->ep_lp_cap_mask = lp_cap_mask;
254647112a4SAndrew Rybchenko epp->ep_fcntl = fcntl;
255647112a4SAndrew Rybchenko
256647112a4SAndrew Rybchenko *link_modep = link_mode;
257647112a4SAndrew Rybchenko }
258647112a4SAndrew Rybchenko
259647112a4SAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_power(__in efx_nic_t * enp,__in boolean_t power)260647112a4SAndrew Rybchenko ef10_phy_power(
261647112a4SAndrew Rybchenko __in efx_nic_t *enp,
262647112a4SAndrew Rybchenko __in boolean_t power)
263647112a4SAndrew Rybchenko {
264647112a4SAndrew Rybchenko efx_rc_t rc;
265647112a4SAndrew Rybchenko
266647112a4SAndrew Rybchenko if (!power)
267647112a4SAndrew Rybchenko return (0);
268647112a4SAndrew Rybchenko
269647112a4SAndrew Rybchenko /* Check if the PHY is a zombie */
270647112a4SAndrew Rybchenko if ((rc = ef10_phy_verify(enp)) != 0)
271647112a4SAndrew Rybchenko goto fail1;
272647112a4SAndrew Rybchenko
273647112a4SAndrew Rybchenko enp->en_reset_flags |= EFX_RESET_PHY;
274647112a4SAndrew Rybchenko
275647112a4SAndrew Rybchenko return (0);
276647112a4SAndrew Rybchenko
277647112a4SAndrew Rybchenko fail1:
278647112a4SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
279647112a4SAndrew Rybchenko
280647112a4SAndrew Rybchenko return (rc);
281647112a4SAndrew Rybchenko }
282647112a4SAndrew Rybchenko
283647112a4SAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_get_link(__in efx_nic_t * enp,__out ef10_link_state_t * elsp)284647112a4SAndrew Rybchenko ef10_phy_get_link(
285647112a4SAndrew Rybchenko __in efx_nic_t *enp,
286647112a4SAndrew Rybchenko __out ef10_link_state_t *elsp)
287647112a4SAndrew Rybchenko {
288647112a4SAndrew Rybchenko efx_mcdi_req_t req;
289a8c1489fSAndrew Rybchenko uint32_t fec;
290315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
291a8c1489fSAndrew Rybchenko MC_CMD_GET_LINK_OUT_V2_LEN);
292647112a4SAndrew Rybchenko efx_rc_t rc;
293647112a4SAndrew Rybchenko
294647112a4SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_LINK;
295647112a4SAndrew Rybchenko req.emr_in_buf = payload;
296647112a4SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
297647112a4SAndrew Rybchenko req.emr_out_buf = payload;
298a8c1489fSAndrew Rybchenko req.emr_out_length = MC_CMD_GET_LINK_OUT_V2_LEN;
299647112a4SAndrew Rybchenko
300647112a4SAndrew Rybchenko efx_mcdi_execute(enp, &req);
301647112a4SAndrew Rybchenko
302647112a4SAndrew Rybchenko if (req.emr_rc != 0) {
303647112a4SAndrew Rybchenko rc = req.emr_rc;
304647112a4SAndrew Rybchenko goto fail1;
305647112a4SAndrew Rybchenko }
306647112a4SAndrew Rybchenko
307647112a4SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
308647112a4SAndrew Rybchenko rc = EMSGSIZE;
309647112a4SAndrew Rybchenko goto fail2;
310647112a4SAndrew Rybchenko }
311647112a4SAndrew Rybchenko
312647112a4SAndrew Rybchenko mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
313cf94ca37SAndrew Rybchenko &elsp->epls.epls_adv_cap_mask);
314647112a4SAndrew Rybchenko mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
315cf94ca37SAndrew Rybchenko &elsp->epls.epls_lp_cap_mask);
316647112a4SAndrew Rybchenko
317a8c1489fSAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN)
318a8c1489fSAndrew Rybchenko fec = MC_CMD_FEC_NONE;
319a8c1489fSAndrew Rybchenko else
320a8c1489fSAndrew Rybchenko fec = MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_FEC_TYPE);
321a8c1489fSAndrew Rybchenko
322647112a4SAndrew Rybchenko mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
323647112a4SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
324647112a4SAndrew Rybchenko MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
325cf94ca37SAndrew Rybchenko fec, &elsp->epls.epls_link_mode,
326cf94ca37SAndrew Rybchenko &elsp->epls.epls_fcntl, &elsp->epls.epls_fec);
327cf94ca37SAndrew Rybchenko
328cf94ca37SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN) {
329cf94ca37SAndrew Rybchenko elsp->epls.epls_ld_cap_mask = 0;
330cf94ca37SAndrew Rybchenko } else {
331cf94ca37SAndrew Rybchenko mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_LD_CAP),
332cf94ca37SAndrew Rybchenko &elsp->epls.epls_ld_cap_mask);
333cf94ca37SAndrew Rybchenko }
334cf94ca37SAndrew Rybchenko
335647112a4SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
3364add9918SAndrew Rybchenko /*
3374add9918SAndrew Rybchenko * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the
3384add9918SAndrew Rybchenko * MCDI value directly. Agreement is checked in efx_loopback_mask().
3394add9918SAndrew Rybchenko */
340647112a4SAndrew Rybchenko elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
341647112a4SAndrew Rybchenko #endif /* EFSYS_OPT_LOOPBACK */
342647112a4SAndrew Rybchenko
343647112a4SAndrew Rybchenko elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
344647112a4SAndrew Rybchenko
345647112a4SAndrew Rybchenko return (0);
346647112a4SAndrew Rybchenko
347647112a4SAndrew Rybchenko fail2:
348647112a4SAndrew Rybchenko EFSYS_PROBE(fail2);
349647112a4SAndrew Rybchenko fail1:
350647112a4SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
351647112a4SAndrew Rybchenko
352647112a4SAndrew Rybchenko return (rc);
353647112a4SAndrew Rybchenko }
354647112a4SAndrew Rybchenko
355647112a4SAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_reconfigure(__in efx_nic_t * enp)356647112a4SAndrew Rybchenko ef10_phy_reconfigure(
357647112a4SAndrew Rybchenko __in efx_nic_t *enp)
358647112a4SAndrew Rybchenko {
359647112a4SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
360647112a4SAndrew Rybchenko efx_mcdi_req_t req;
361315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_LINK_IN_LEN,
362315bbbaaSAndrew Rybchenko MC_CMD_SET_LINK_OUT_LEN);
363647112a4SAndrew Rybchenko uint32_t cap_mask;
364c68c424cSAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL
365647112a4SAndrew Rybchenko unsigned int led_mode;
366c68c424cSAndrew Rybchenko #endif
367647112a4SAndrew Rybchenko unsigned int speed;
3687fb55c62SAndrew Rybchenko boolean_t supported;
369647112a4SAndrew Rybchenko efx_rc_t rc;
370647112a4SAndrew Rybchenko
3717fb55c62SAndrew Rybchenko if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0)
3727fb55c62SAndrew Rybchenko goto fail1;
3737fb55c62SAndrew Rybchenko if (supported == B_FALSE)
374647112a4SAndrew Rybchenko goto out;
375647112a4SAndrew Rybchenko
376647112a4SAndrew Rybchenko req.emr_cmd = MC_CMD_SET_LINK;
377647112a4SAndrew Rybchenko req.emr_in_buf = payload;
378647112a4SAndrew Rybchenko req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
379647112a4SAndrew Rybchenko req.emr_out_buf = payload;
380647112a4SAndrew Rybchenko req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
381647112a4SAndrew Rybchenko
382647112a4SAndrew Rybchenko cap_mask = epp->ep_adv_cap_mask;
383647112a4SAndrew Rybchenko MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
384647112a4SAndrew Rybchenko PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
385647112a4SAndrew Rybchenko PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
386647112a4SAndrew Rybchenko PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
387647112a4SAndrew Rybchenko PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
388647112a4SAndrew Rybchenko PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
389647112a4SAndrew Rybchenko PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
390647112a4SAndrew Rybchenko PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
391647112a4SAndrew Rybchenko PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
392647112a4SAndrew Rybchenko PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
393647112a4SAndrew Rybchenko PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
394*db739f1cSGordon Bergling /* Too many fields for POPULATE macros, so insert this afterwards */
395647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
396d81df221SAndrew Rybchenko PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1);
397d81df221SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
398647112a4SAndrew Rybchenko PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1);
399d81df221SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
400d81df221SAndrew Rybchenko PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1);
401d81df221SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
402d81df221SAndrew Rybchenko PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1);
403647112a4SAndrew Rybchenko
404ffde7424SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
405ffde7424SAndrew Rybchenko PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1);
406ffde7424SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
407ffde7424SAndrew Rybchenko PHY_CAP_BASER_FEC_REQUESTED,
408ffde7424SAndrew Rybchenko (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1);
409ffde7424SAndrew Rybchenko
410ffde7424SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
411ffde7424SAndrew Rybchenko PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1);
412ffde7424SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
413ffde7424SAndrew Rybchenko PHY_CAP_RS_FEC_REQUESTED,
414ffde7424SAndrew Rybchenko (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1);
415ffde7424SAndrew Rybchenko
416ffde7424SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
417ffde7424SAndrew Rybchenko PHY_CAP_25G_BASER_FEC,
418ffde7424SAndrew Rybchenko (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1);
419ffde7424SAndrew Rybchenko MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP,
420ffde7424SAndrew Rybchenko PHY_CAP_25G_BASER_FEC_REQUESTED,
421ffde7424SAndrew Rybchenko (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1);
422ffde7424SAndrew Rybchenko
423647112a4SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
424647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
425647112a4SAndrew Rybchenko epp->ep_loopback_type);
426647112a4SAndrew Rybchenko switch (epp->ep_loopback_link_mode) {
427647112a4SAndrew Rybchenko case EFX_LINK_100FDX:
428647112a4SAndrew Rybchenko speed = 100;
429647112a4SAndrew Rybchenko break;
430647112a4SAndrew Rybchenko case EFX_LINK_1000FDX:
431647112a4SAndrew Rybchenko speed = 1000;
432647112a4SAndrew Rybchenko break;
433647112a4SAndrew Rybchenko case EFX_LINK_10000FDX:
434647112a4SAndrew Rybchenko speed = 10000;
435647112a4SAndrew Rybchenko break;
436d81df221SAndrew Rybchenko case EFX_LINK_25000FDX:
437d81df221SAndrew Rybchenko speed = 25000;
438d81df221SAndrew Rybchenko break;
439647112a4SAndrew Rybchenko case EFX_LINK_40000FDX:
440647112a4SAndrew Rybchenko speed = 40000;
441647112a4SAndrew Rybchenko break;
442d81df221SAndrew Rybchenko case EFX_LINK_50000FDX:
443d81df221SAndrew Rybchenko speed = 50000;
444d81df221SAndrew Rybchenko break;
445d81df221SAndrew Rybchenko case EFX_LINK_100000FDX:
446d81df221SAndrew Rybchenko speed = 100000;
447d81df221SAndrew Rybchenko break;
448647112a4SAndrew Rybchenko default:
449647112a4SAndrew Rybchenko speed = 0;
450647112a4SAndrew Rybchenko }
451647112a4SAndrew Rybchenko #else
452647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
453647112a4SAndrew Rybchenko speed = 0;
454647112a4SAndrew Rybchenko #endif /* EFSYS_OPT_LOOPBACK */
455647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
456647112a4SAndrew Rybchenko
457647112a4SAndrew Rybchenko #if EFSYS_OPT_PHY_FLAGS
458647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
459647112a4SAndrew Rybchenko #else
460647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
461647112a4SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_FLAGS */
462647112a4SAndrew Rybchenko
463647112a4SAndrew Rybchenko efx_mcdi_execute(enp, &req);
464647112a4SAndrew Rybchenko
465647112a4SAndrew Rybchenko if (req.emr_rc != 0) {
466647112a4SAndrew Rybchenko rc = req.emr_rc;
4677fb55c62SAndrew Rybchenko goto fail2;
468647112a4SAndrew Rybchenko }
469647112a4SAndrew Rybchenko
470647112a4SAndrew Rybchenko /* And set the blink mode */
471647112a4SAndrew Rybchenko (void) memset(payload, 0, sizeof (payload));
472647112a4SAndrew Rybchenko req.emr_cmd = MC_CMD_SET_ID_LED;
473647112a4SAndrew Rybchenko req.emr_in_buf = payload;
474647112a4SAndrew Rybchenko req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
475647112a4SAndrew Rybchenko req.emr_out_buf = payload;
476647112a4SAndrew Rybchenko req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
477647112a4SAndrew Rybchenko
478647112a4SAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL
479647112a4SAndrew Rybchenko switch (epp->ep_phy_led_mode) {
480647112a4SAndrew Rybchenko case EFX_PHY_LED_DEFAULT:
481647112a4SAndrew Rybchenko led_mode = MC_CMD_LED_DEFAULT;
482647112a4SAndrew Rybchenko break;
483647112a4SAndrew Rybchenko case EFX_PHY_LED_OFF:
484647112a4SAndrew Rybchenko led_mode = MC_CMD_LED_OFF;
485647112a4SAndrew Rybchenko break;
486647112a4SAndrew Rybchenko case EFX_PHY_LED_ON:
487647112a4SAndrew Rybchenko led_mode = MC_CMD_LED_ON;
488647112a4SAndrew Rybchenko break;
489647112a4SAndrew Rybchenko default:
490647112a4SAndrew Rybchenko EFSYS_ASSERT(0);
491647112a4SAndrew Rybchenko led_mode = MC_CMD_LED_DEFAULT;
492647112a4SAndrew Rybchenko }
493647112a4SAndrew Rybchenko
494647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
495647112a4SAndrew Rybchenko #else
496647112a4SAndrew Rybchenko MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
497647112a4SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_LED_CONTROL */
498647112a4SAndrew Rybchenko
499647112a4SAndrew Rybchenko efx_mcdi_execute(enp, &req);
500647112a4SAndrew Rybchenko
501647112a4SAndrew Rybchenko if (req.emr_rc != 0) {
502647112a4SAndrew Rybchenko rc = req.emr_rc;
5037fb55c62SAndrew Rybchenko goto fail3;
504647112a4SAndrew Rybchenko }
505647112a4SAndrew Rybchenko out:
506647112a4SAndrew Rybchenko return (0);
507647112a4SAndrew Rybchenko
5087fb55c62SAndrew Rybchenko fail3:
5097fb55c62SAndrew Rybchenko EFSYS_PROBE(fail3);
510647112a4SAndrew Rybchenko fail2:
511647112a4SAndrew Rybchenko EFSYS_PROBE(fail2);
512647112a4SAndrew Rybchenko fail1:
513647112a4SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
514647112a4SAndrew Rybchenko
515647112a4SAndrew Rybchenko return (rc);
516647112a4SAndrew Rybchenko }
517647112a4SAndrew Rybchenko
518647112a4SAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_verify(__in efx_nic_t * enp)519647112a4SAndrew Rybchenko ef10_phy_verify(
520647112a4SAndrew Rybchenko __in efx_nic_t *enp)
521647112a4SAndrew Rybchenko {
522647112a4SAndrew Rybchenko efx_mcdi_req_t req;
523315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
524315bbbaaSAndrew Rybchenko MC_CMD_GET_PHY_STATE_OUT_LEN);
525647112a4SAndrew Rybchenko uint32_t state;
526647112a4SAndrew Rybchenko efx_rc_t rc;
527647112a4SAndrew Rybchenko
528647112a4SAndrew Rybchenko req.emr_cmd = MC_CMD_GET_PHY_STATE;
529647112a4SAndrew Rybchenko req.emr_in_buf = payload;
530647112a4SAndrew Rybchenko req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
531647112a4SAndrew Rybchenko req.emr_out_buf = payload;
532647112a4SAndrew Rybchenko req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
533647112a4SAndrew Rybchenko
534647112a4SAndrew Rybchenko efx_mcdi_execute(enp, &req);
535647112a4SAndrew Rybchenko
536647112a4SAndrew Rybchenko if (req.emr_rc != 0) {
537647112a4SAndrew Rybchenko rc = req.emr_rc;
538647112a4SAndrew Rybchenko goto fail1;
539647112a4SAndrew Rybchenko }
540647112a4SAndrew Rybchenko
541647112a4SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
542647112a4SAndrew Rybchenko rc = EMSGSIZE;
543647112a4SAndrew Rybchenko goto fail2;
544647112a4SAndrew Rybchenko }
545647112a4SAndrew Rybchenko
546647112a4SAndrew Rybchenko state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
547647112a4SAndrew Rybchenko if (state != MC_CMD_PHY_STATE_OK) {
548647112a4SAndrew Rybchenko if (state != MC_CMD_PHY_STATE_ZOMBIE)
549647112a4SAndrew Rybchenko EFSYS_PROBE1(mc_pcol_error, int, state);
550647112a4SAndrew Rybchenko rc = ENOTACTIVE;
551647112a4SAndrew Rybchenko goto fail3;
552647112a4SAndrew Rybchenko }
553647112a4SAndrew Rybchenko
554647112a4SAndrew Rybchenko return (0);
555647112a4SAndrew Rybchenko
556647112a4SAndrew Rybchenko fail3:
557647112a4SAndrew Rybchenko EFSYS_PROBE(fail3);
558647112a4SAndrew Rybchenko fail2:
559647112a4SAndrew Rybchenko EFSYS_PROBE(fail2);
560647112a4SAndrew Rybchenko fail1:
561647112a4SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
562647112a4SAndrew Rybchenko
563647112a4SAndrew Rybchenko return (rc);
564647112a4SAndrew Rybchenko }
565647112a4SAndrew Rybchenko
566647112a4SAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_oui_get(__in efx_nic_t * enp,__out uint32_t * ouip)567647112a4SAndrew Rybchenko ef10_phy_oui_get(
568647112a4SAndrew Rybchenko __in efx_nic_t *enp,
569647112a4SAndrew Rybchenko __out uint32_t *ouip)
570647112a4SAndrew Rybchenko {
571647112a4SAndrew Rybchenko _NOTE(ARGUNUSED(enp, ouip))
572647112a4SAndrew Rybchenko
573647112a4SAndrew Rybchenko return (ENOTSUP);
574647112a4SAndrew Rybchenko }
575647112a4SAndrew Rybchenko
576a8c1489fSAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_link_state_get(__in efx_nic_t * enp,__out efx_phy_link_state_t * eplsp)577cf94ca37SAndrew Rybchenko ef10_phy_link_state_get(
578a8c1489fSAndrew Rybchenko __in efx_nic_t *enp,
579cf94ca37SAndrew Rybchenko __out efx_phy_link_state_t *eplsp)
580a8c1489fSAndrew Rybchenko {
581a8c1489fSAndrew Rybchenko efx_rc_t rc;
582a8c1489fSAndrew Rybchenko ef10_link_state_t els;
583a8c1489fSAndrew Rybchenko
584cf94ca37SAndrew Rybchenko /* Obtain the active link state */
585a8c1489fSAndrew Rybchenko if ((rc = ef10_phy_get_link(enp, &els)) != 0)
586a8c1489fSAndrew Rybchenko goto fail1;
587a8c1489fSAndrew Rybchenko
588cf94ca37SAndrew Rybchenko *eplsp = els.epls;
589a8c1489fSAndrew Rybchenko
590a8c1489fSAndrew Rybchenko return (0);
591a8c1489fSAndrew Rybchenko
592a8c1489fSAndrew Rybchenko fail1:
593a8c1489fSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
594a8c1489fSAndrew Rybchenko
595a8c1489fSAndrew Rybchenko return (rc);
596a8c1489fSAndrew Rybchenko }
597a8c1489fSAndrew Rybchenko
598647112a4SAndrew Rybchenko #if EFSYS_OPT_PHY_STATS
599647112a4SAndrew Rybchenko
600647112a4SAndrew Rybchenko __checkReturn efx_rc_t
ef10_phy_stats_update(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__inout_ecount (EFX_PHY_NSTATS)uint32_t * stat)601647112a4SAndrew Rybchenko ef10_phy_stats_update(
602647112a4SAndrew Rybchenko __in efx_nic_t *enp,
603647112a4SAndrew Rybchenko __in efsys_mem_t *esmp,
604647112a4SAndrew Rybchenko __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat)
605647112a4SAndrew Rybchenko {
606647112a4SAndrew Rybchenko /* TBD: no stats support in firmware yet */
607647112a4SAndrew Rybchenko _NOTE(ARGUNUSED(enp, esmp))
608647112a4SAndrew Rybchenko memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat));
609647112a4SAndrew Rybchenko
610647112a4SAndrew Rybchenko return (0);
611647112a4SAndrew Rybchenko }
612647112a4SAndrew Rybchenko
613647112a4SAndrew Rybchenko #endif /* EFSYS_OPT_PHY_STATS */
614647112a4SAndrew Rybchenko
615cc7a82f5SAndrew Rybchenko #if EFSYS_OPT_BIST
616cc7a82f5SAndrew Rybchenko
617cc7a82f5SAndrew Rybchenko __checkReturn efx_rc_t
ef10_bist_enable_offline(__in efx_nic_t * enp)618cc7a82f5SAndrew Rybchenko ef10_bist_enable_offline(
619cc7a82f5SAndrew Rybchenko __in efx_nic_t *enp)
620cc7a82f5SAndrew Rybchenko {
621cc7a82f5SAndrew Rybchenko efx_rc_t rc;
622cc7a82f5SAndrew Rybchenko
623cc7a82f5SAndrew Rybchenko if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0)
624cc7a82f5SAndrew Rybchenko goto fail1;
625cc7a82f5SAndrew Rybchenko
626cc7a82f5SAndrew Rybchenko return (0);
627cc7a82f5SAndrew Rybchenko
628cc7a82f5SAndrew Rybchenko fail1:
629cc7a82f5SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
630cc7a82f5SAndrew Rybchenko
631cc7a82f5SAndrew Rybchenko return (rc);
632cc7a82f5SAndrew Rybchenko }
633cc7a82f5SAndrew Rybchenko
634cc7a82f5SAndrew Rybchenko __checkReturn efx_rc_t
ef10_bist_start(__in efx_nic_t * enp,__in efx_bist_type_t type)635cc7a82f5SAndrew Rybchenko ef10_bist_start(
636cc7a82f5SAndrew Rybchenko __in efx_nic_t *enp,
637cc7a82f5SAndrew Rybchenko __in efx_bist_type_t type)
638cc7a82f5SAndrew Rybchenko {
639cc7a82f5SAndrew Rybchenko efx_rc_t rc;
640cc7a82f5SAndrew Rybchenko
641cc7a82f5SAndrew Rybchenko if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
642cc7a82f5SAndrew Rybchenko goto fail1;
643cc7a82f5SAndrew Rybchenko
644cc7a82f5SAndrew Rybchenko return (0);
645cc7a82f5SAndrew Rybchenko
646cc7a82f5SAndrew Rybchenko fail1:
647cc7a82f5SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
648cc7a82f5SAndrew Rybchenko
649cc7a82f5SAndrew Rybchenko return (rc);
650cc7a82f5SAndrew Rybchenko }
651cc7a82f5SAndrew Rybchenko
652cc7a82f5SAndrew Rybchenko __checkReturn efx_rc_t
653cc7a82f5SAndrew Rybchenko ef10_bist_poll(
654cc7a82f5SAndrew Rybchenko __in efx_nic_t *enp,
655cc7a82f5SAndrew Rybchenko __in efx_bist_type_t type,
656cc7a82f5SAndrew Rybchenko __out efx_bist_result_t *resultp,
657cc7a82f5SAndrew Rybchenko __out_opt __drv_when(count > 0, __notnull)
658cc7a82f5SAndrew Rybchenko uint32_t *value_maskp,
659cc7a82f5SAndrew Rybchenko __out_ecount_opt(count) __drv_when(count > 0, __notnull)
660cc7a82f5SAndrew Rybchenko unsigned long *valuesp,
661cc7a82f5SAndrew Rybchenko __in size_t count)
662cc7a82f5SAndrew Rybchenko {
6636b231fecSAndrew Rybchenko /*
6646b231fecSAndrew Rybchenko * MCDI_CTL_SDU_LEN_MAX_V1 is large enough cover all BIST results,
6656b231fecSAndrew Rybchenko * whilst not wasting stack.
6666b231fecSAndrew Rybchenko */
667315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
668315bbbaaSAndrew Rybchenko MCDI_CTL_SDU_LEN_MAX_V1);
669cc7a82f5SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
670cc7a82f5SAndrew Rybchenko efx_mcdi_req_t req;
671cc7a82f5SAndrew Rybchenko uint32_t value_mask = 0;
672cc7a82f5SAndrew Rybchenko uint32_t result;
673cc7a82f5SAndrew Rybchenko efx_rc_t rc;
674cc7a82f5SAndrew Rybchenko
6756b231fecSAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_LEN <=
6766b231fecSAndrew Rybchenko MCDI_CTL_SDU_LEN_MAX_V1);
6776b231fecSAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_SFT9001_LEN <=
6786b231fecSAndrew Rybchenko MCDI_CTL_SDU_LEN_MAX_V1);
6796b231fecSAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MRSFP_LEN <=
6806b231fecSAndrew Rybchenko MCDI_CTL_SDU_LEN_MAX_V1);
6816b231fecSAndrew Rybchenko EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MEM_LEN <=
6826b231fecSAndrew Rybchenko MCDI_CTL_SDU_LEN_MAX_V1);
6836b231fecSAndrew Rybchenko
684cc7a82f5SAndrew Rybchenko _NOTE(ARGUNUSED(type))
685cc7a82f5SAndrew Rybchenko
686cc7a82f5SAndrew Rybchenko req.emr_cmd = MC_CMD_POLL_BIST;
687cc7a82f5SAndrew Rybchenko req.emr_in_buf = payload;
688cc7a82f5SAndrew Rybchenko req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
689cc7a82f5SAndrew Rybchenko req.emr_out_buf = payload;
6906b231fecSAndrew Rybchenko req.emr_out_length = MCDI_CTL_SDU_LEN_MAX_V1;
691cc7a82f5SAndrew Rybchenko
692cc7a82f5SAndrew Rybchenko efx_mcdi_execute(enp, &req);
693cc7a82f5SAndrew Rybchenko
694cc7a82f5SAndrew Rybchenko if (req.emr_rc != 0) {
695cc7a82f5SAndrew Rybchenko rc = req.emr_rc;
696cc7a82f5SAndrew Rybchenko goto fail1;
697cc7a82f5SAndrew Rybchenko }
698cc7a82f5SAndrew Rybchenko
699cc7a82f5SAndrew Rybchenko if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
700cc7a82f5SAndrew Rybchenko rc = EMSGSIZE;
701cc7a82f5SAndrew Rybchenko goto fail2;
702cc7a82f5SAndrew Rybchenko }
703cc7a82f5SAndrew Rybchenko
704cc7a82f5SAndrew Rybchenko if (count > 0)
705cc7a82f5SAndrew Rybchenko (void) memset(valuesp, '\0', count * sizeof (unsigned long));
706cc7a82f5SAndrew Rybchenko
707cc7a82f5SAndrew Rybchenko result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
708cc7a82f5SAndrew Rybchenko
709cc7a82f5SAndrew Rybchenko if (result == MC_CMD_POLL_BIST_FAILED &&
710cc7a82f5SAndrew Rybchenko req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN &&
711cc7a82f5SAndrew Rybchenko count > EFX_BIST_MEM_ECC_FATAL) {
712cc7a82f5SAndrew Rybchenko if (valuesp != NULL) {
713cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_TEST] =
714cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST);
715cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_ADDR] =
716cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR);
717cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_BUS] =
718cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS);
719cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_EXPECT] =
720cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT);
721cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_ACTUAL] =
722cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL);
723cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_ECC] =
724cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC);
725cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_ECC_PARITY] =
726cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY);
727cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_MEM_ECC_FATAL] =
728cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL);
729cc7a82f5SAndrew Rybchenko }
730cc7a82f5SAndrew Rybchenko value_mask |= (1 << EFX_BIST_MEM_TEST) |
731cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_ADDR) |
732cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_BUS) |
733cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_EXPECT) |
734cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_ACTUAL) |
735cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_ECC) |
736cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_ECC_PARITY) |
737cc7a82f5SAndrew Rybchenko (1 << EFX_BIST_MEM_ECC_FATAL);
738cc7a82f5SAndrew Rybchenko } else if (result == MC_CMD_POLL_BIST_FAILED &&
739cc7a82f5SAndrew Rybchenko encp->enc_phy_type == EFX_PHY_XFI_FARMI &&
740cc7a82f5SAndrew Rybchenko req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
741cc7a82f5SAndrew Rybchenko count > EFX_BIST_FAULT_CODE) {
742cc7a82f5SAndrew Rybchenko if (valuesp != NULL)
743cc7a82f5SAndrew Rybchenko valuesp[EFX_BIST_FAULT_CODE] =
744cc7a82f5SAndrew Rybchenko MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
745cc7a82f5SAndrew Rybchenko value_mask |= 1 << EFX_BIST_FAULT_CODE;
746cc7a82f5SAndrew Rybchenko }
747cc7a82f5SAndrew Rybchenko
748cc7a82f5SAndrew Rybchenko if (value_maskp != NULL)
749cc7a82f5SAndrew Rybchenko *value_maskp = value_mask;
750cc7a82f5SAndrew Rybchenko
751cc7a82f5SAndrew Rybchenko EFSYS_ASSERT(resultp != NULL);
752cc7a82f5SAndrew Rybchenko if (result == MC_CMD_POLL_BIST_RUNNING)
753cc7a82f5SAndrew Rybchenko *resultp = EFX_BIST_RESULT_RUNNING;
754cc7a82f5SAndrew Rybchenko else if (result == MC_CMD_POLL_BIST_PASSED)
755cc7a82f5SAndrew Rybchenko *resultp = EFX_BIST_RESULT_PASSED;
756cc7a82f5SAndrew Rybchenko else
757cc7a82f5SAndrew Rybchenko *resultp = EFX_BIST_RESULT_FAILED;
758cc7a82f5SAndrew Rybchenko
759cc7a82f5SAndrew Rybchenko return (0);
760cc7a82f5SAndrew Rybchenko
761cc7a82f5SAndrew Rybchenko fail2:
762cc7a82f5SAndrew Rybchenko EFSYS_PROBE(fail2);
763cc7a82f5SAndrew Rybchenko fail1:
764cc7a82f5SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
765cc7a82f5SAndrew Rybchenko
766cc7a82f5SAndrew Rybchenko return (rc);
767cc7a82f5SAndrew Rybchenko }
768cc7a82f5SAndrew Rybchenko
769cc7a82f5SAndrew Rybchenko void
ef10_bist_stop(__in efx_nic_t * enp,__in efx_bist_type_t type)770cc7a82f5SAndrew Rybchenko ef10_bist_stop(
771cc7a82f5SAndrew Rybchenko __in efx_nic_t *enp,
772cc7a82f5SAndrew Rybchenko __in efx_bist_type_t type)
773cc7a82f5SAndrew Rybchenko {
774cc7a82f5SAndrew Rybchenko /* There is no way to stop BIST on EF10. */
775cc7a82f5SAndrew Rybchenko _NOTE(ARGUNUSED(enp, type))
776cc7a82f5SAndrew Rybchenko }
777cc7a82f5SAndrew Rybchenko
778cc7a82f5SAndrew Rybchenko #endif /* EFSYS_OPT_BIST */
779cc7a82f5SAndrew Rybchenko
78010d4c14dSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
781