1e948693eSPhilip Paeps /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4929c7febSAndrew Rybchenko * Copyright (c) 2009-2016 Solarflare Communications Inc.
53c838a9fSAndrew Rybchenko * All rights reserved.
6e948693eSPhilip Paeps *
7e948693eSPhilip Paeps * Redistribution and use in source and binary forms, with or without
83c838a9fSAndrew Rybchenko * modification, are permitted provided that the following conditions are met:
9e948693eSPhilip Paeps *
103c838a9fSAndrew Rybchenko * 1. Redistributions of source code must retain the above copyright notice,
113c838a9fSAndrew Rybchenko * this list of conditions and the following disclaimer.
123c838a9fSAndrew Rybchenko * 2. Redistributions in binary form must reproduce the above copyright notice,
133c838a9fSAndrew Rybchenko * this list of conditions and the following disclaimer in the documentation
143c838a9fSAndrew Rybchenko * and/or other materials provided with the distribution.
153c838a9fSAndrew Rybchenko *
163c838a9fSAndrew Rybchenko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173c838a9fSAndrew Rybchenko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
183c838a9fSAndrew Rybchenko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193c838a9fSAndrew Rybchenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
203c838a9fSAndrew Rybchenko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213c838a9fSAndrew Rybchenko * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223c838a9fSAndrew Rybchenko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
233c838a9fSAndrew Rybchenko * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
243c838a9fSAndrew Rybchenko * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
253c838a9fSAndrew Rybchenko * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
263c838a9fSAndrew Rybchenko * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273c838a9fSAndrew Rybchenko *
283c838a9fSAndrew Rybchenko * The views and conclusions contained in the software and documentation are
293c838a9fSAndrew Rybchenko * those of the authors and should not be interpreted as representing official
303c838a9fSAndrew Rybchenko * policies, either expressed or implied, of the FreeBSD Project.
31e948693eSPhilip Paeps */
325dee87d7SPhilip Paeps
335dee87d7SPhilip Paeps #include <sys/cdefs.h>
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps
37e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
38e948693eSPhilip Paeps
39e948693eSPhilip Paeps static void
siena_phy_decode_cap(__in uint32_t mcdi_cap,__out uint32_t * maskp)40e948693eSPhilip Paeps siena_phy_decode_cap(
41e948693eSPhilip Paeps __in uint32_t mcdi_cap,
42e948693eSPhilip Paeps __out uint32_t *maskp)
43e948693eSPhilip Paeps {
44e948693eSPhilip Paeps uint32_t mask;
45e948693eSPhilip Paeps
46e948693eSPhilip Paeps mask = 0;
47e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
48e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_10HDX);
49e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
50e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_10FDX);
51e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
52e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_100HDX);
53e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
54e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_100FDX);
55e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
56e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_1000HDX);
57e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
58e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_1000FDX);
59e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
60e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_10000FDX);
61e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
62e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_PAUSE);
63e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
64e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_ASYM);
65e948693eSPhilip Paeps if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
66e948693eSPhilip Paeps mask |= (1 << EFX_PHY_CAP_AN);
67e948693eSPhilip Paeps
68e948693eSPhilip Paeps *maskp = mask;
69e948693eSPhilip Paeps }
70e948693eSPhilip Paeps
71e948693eSPhilip Paeps static void
siena_phy_decode_link_mode(__in efx_nic_t * enp,__in uint32_t link_flags,__in unsigned int speed,__in unsigned int fcntl,__out efx_link_mode_t * link_modep,__out unsigned int * fcntlp)72e948693eSPhilip Paeps siena_phy_decode_link_mode(
73e948693eSPhilip Paeps __in efx_nic_t *enp,
74e948693eSPhilip Paeps __in uint32_t link_flags,
75e948693eSPhilip Paeps __in unsigned int speed,
76e948693eSPhilip Paeps __in unsigned int fcntl,
77e948693eSPhilip Paeps __out efx_link_mode_t *link_modep,
78e948693eSPhilip Paeps __out unsigned int *fcntlp)
79e948693eSPhilip Paeps {
80e948693eSPhilip Paeps boolean_t fd = !!(link_flags &
81e948693eSPhilip Paeps (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
82e948693eSPhilip Paeps boolean_t up = !!(link_flags &
83e948693eSPhilip Paeps (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
84e948693eSPhilip Paeps
85e948693eSPhilip Paeps _NOTE(ARGUNUSED(enp))
86e948693eSPhilip Paeps
87e948693eSPhilip Paeps if (!up)
88e948693eSPhilip Paeps *link_modep = EFX_LINK_DOWN;
89e948693eSPhilip Paeps else if (speed == 10000 && fd)
90e948693eSPhilip Paeps *link_modep = EFX_LINK_10000FDX;
91e948693eSPhilip Paeps else if (speed == 1000)
92e948693eSPhilip Paeps *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
93e948693eSPhilip Paeps else if (speed == 100)
94e948693eSPhilip Paeps *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
95e948693eSPhilip Paeps else if (speed == 10)
96e948693eSPhilip Paeps *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
97e948693eSPhilip Paeps else
98e948693eSPhilip Paeps *link_modep = EFX_LINK_UNKNOWN;
99e948693eSPhilip Paeps
100e948693eSPhilip Paeps if (fcntl == MC_CMD_FCNTL_OFF)
101e948693eSPhilip Paeps *fcntlp = 0;
102e948693eSPhilip Paeps else if (fcntl == MC_CMD_FCNTL_RESPOND)
103e948693eSPhilip Paeps *fcntlp = EFX_FCNTL_RESPOND;
104e948693eSPhilip Paeps else if (fcntl == MC_CMD_FCNTL_BIDIR)
105e948693eSPhilip Paeps *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
106e948693eSPhilip Paeps else {
107e948693eSPhilip Paeps EFSYS_PROBE1(mc_pcol_error, int, fcntl);
108e948693eSPhilip Paeps *fcntlp = 0;
109e948693eSPhilip Paeps }
110e948693eSPhilip Paeps }
111e948693eSPhilip Paeps
112e948693eSPhilip Paeps void
siena_phy_link_ev(__in efx_nic_t * enp,__in efx_qword_t * eqp,__out efx_link_mode_t * link_modep)113e948693eSPhilip Paeps siena_phy_link_ev(
114e948693eSPhilip Paeps __in efx_nic_t *enp,
115e948693eSPhilip Paeps __in efx_qword_t *eqp,
116e948693eSPhilip Paeps __out efx_link_mode_t *link_modep)
117e948693eSPhilip Paeps {
118e948693eSPhilip Paeps efx_port_t *epp = &(enp->en_port);
119e948693eSPhilip Paeps unsigned int link_flags;
120e948693eSPhilip Paeps unsigned int speed;
121e948693eSPhilip Paeps unsigned int fcntl;
122e948693eSPhilip Paeps efx_link_mode_t link_mode;
123e948693eSPhilip Paeps uint32_t lp_cap_mask;
124e948693eSPhilip Paeps
125e948693eSPhilip Paeps /*
126e948693eSPhilip Paeps * Convert the LINKCHANGE speed enumeration into mbit/s, in the
127e948693eSPhilip Paeps * same way as GET_LINK encodes the speed
128e948693eSPhilip Paeps */
129d8574f4fSAndrew Rybchenko switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
130e948693eSPhilip Paeps case MCDI_EVENT_LINKCHANGE_SPEED_100M:
131e948693eSPhilip Paeps speed = 100;
132e948693eSPhilip Paeps break;
133e948693eSPhilip Paeps case MCDI_EVENT_LINKCHANGE_SPEED_1G:
134e948693eSPhilip Paeps speed = 1000;
135e948693eSPhilip Paeps break;
136e948693eSPhilip Paeps case MCDI_EVENT_LINKCHANGE_SPEED_10G:
137e948693eSPhilip Paeps speed = 10000;
138e948693eSPhilip Paeps break;
139e948693eSPhilip Paeps default:
140e948693eSPhilip Paeps speed = 0;
141e948693eSPhilip Paeps break;
142e948693eSPhilip Paeps }
143e948693eSPhilip Paeps
144d8574f4fSAndrew Rybchenko link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
145e948693eSPhilip Paeps siena_phy_decode_link_mode(enp, link_flags, speed,
146d8574f4fSAndrew Rybchenko MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
147e948693eSPhilip Paeps &link_mode, &fcntl);
148d8574f4fSAndrew Rybchenko siena_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
149e948693eSPhilip Paeps &lp_cap_mask);
150e948693eSPhilip Paeps
151e948693eSPhilip Paeps /*
152e948693eSPhilip Paeps * It's safe to update ep_lp_cap_mask without the driver's port lock
153e948693eSPhilip Paeps * because presumably any concurrently running efx_port_poll() is
154e948693eSPhilip Paeps * only going to arrive at the same value.
155e948693eSPhilip Paeps *
156e948693eSPhilip Paeps * ep_fcntl has two meanings. It's either the link common fcntl
157e948693eSPhilip Paeps * (if the PHY supports AN), or it's the forced link state. If
158e948693eSPhilip Paeps * the former, it's safe to update the value for the same reason as
159e948693eSPhilip Paeps * for ep_lp_cap_mask. If the latter, then just ignore the value,
160e948693eSPhilip Paeps * because we can race with efx_mac_fcntl_set().
161e948693eSPhilip Paeps */
162e948693eSPhilip Paeps epp->ep_lp_cap_mask = lp_cap_mask;
163e948693eSPhilip Paeps if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
164e948693eSPhilip Paeps epp->ep_fcntl = fcntl;
165e948693eSPhilip Paeps
166e948693eSPhilip Paeps *link_modep = link_mode;
167e948693eSPhilip Paeps }
168e948693eSPhilip Paeps
169460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_power(__in efx_nic_t * enp,__in boolean_t power)170e948693eSPhilip Paeps siena_phy_power(
171e948693eSPhilip Paeps __in efx_nic_t *enp,
172e948693eSPhilip Paeps __in boolean_t power)
173e948693eSPhilip Paeps {
174460cb568SAndrew Rybchenko efx_rc_t rc;
175e948693eSPhilip Paeps
176e948693eSPhilip Paeps if (!power)
177e948693eSPhilip Paeps return (0);
178e948693eSPhilip Paeps
179e948693eSPhilip Paeps /* Check if the PHY is a zombie */
180e948693eSPhilip Paeps if ((rc = siena_phy_verify(enp)) != 0)
181e948693eSPhilip Paeps goto fail1;
182e948693eSPhilip Paeps
183e948693eSPhilip Paeps enp->en_reset_flags |= EFX_RESET_PHY;
184e948693eSPhilip Paeps
185e948693eSPhilip Paeps return (0);
186e948693eSPhilip Paeps
187e948693eSPhilip Paeps fail1:
188460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
189e948693eSPhilip Paeps
190e948693eSPhilip Paeps return (rc);
191e948693eSPhilip Paeps }
192e948693eSPhilip Paeps
193460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_get_link(__in efx_nic_t * enp,__out siena_link_state_t * slsp)194e948693eSPhilip Paeps siena_phy_get_link(
195e948693eSPhilip Paeps __in efx_nic_t *enp,
196e948693eSPhilip Paeps __out siena_link_state_t *slsp)
197e948693eSPhilip Paeps {
198e948693eSPhilip Paeps efx_mcdi_req_t req;
199315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN,
200315bbbaaSAndrew Rybchenko MC_CMD_GET_LINK_OUT_LEN);
201460cb568SAndrew Rybchenko efx_rc_t rc;
202e948693eSPhilip Paeps
203e948693eSPhilip Paeps req.emr_cmd = MC_CMD_GET_LINK;
2043c838a9fSAndrew Rybchenko req.emr_in_buf = payload;
2053c838a9fSAndrew Rybchenko req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
2063c838a9fSAndrew Rybchenko req.emr_out_buf = payload;
2073c838a9fSAndrew Rybchenko req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
208e948693eSPhilip Paeps
209e948693eSPhilip Paeps efx_mcdi_execute(enp, &req);
210e948693eSPhilip Paeps
211e948693eSPhilip Paeps if (req.emr_rc != 0) {
212e948693eSPhilip Paeps rc = req.emr_rc;
213e948693eSPhilip Paeps goto fail1;
214e948693eSPhilip Paeps }
215e948693eSPhilip Paeps
216e948693eSPhilip Paeps if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
217e948693eSPhilip Paeps rc = EMSGSIZE;
218e948693eSPhilip Paeps goto fail2;
219e948693eSPhilip Paeps }
220e948693eSPhilip Paeps
221e948693eSPhilip Paeps siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
222e948693eSPhilip Paeps &slsp->sls_adv_cap_mask);
223e948693eSPhilip Paeps siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
224e948693eSPhilip Paeps &slsp->sls_lp_cap_mask);
225e948693eSPhilip Paeps
226e948693eSPhilip Paeps siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
227e948693eSPhilip Paeps MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
228e948693eSPhilip Paeps MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
229e948693eSPhilip Paeps &slsp->sls_link_mode, &slsp->sls_fcntl);
230e948693eSPhilip Paeps
231e948693eSPhilip Paeps #if EFSYS_OPT_LOOPBACK
232e948693eSPhilip Paeps /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
233e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
234e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
235e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
236e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
237e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
238e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
239e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
240e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
241e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
242e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
243e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
244e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
245e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
246e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
247e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
248e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
249e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
250e948693eSPhilip Paeps EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
251e948693eSPhilip Paeps
252e948693eSPhilip Paeps slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
253e948693eSPhilip Paeps #endif /* EFSYS_OPT_LOOPBACK */
254e948693eSPhilip Paeps
255e948693eSPhilip Paeps slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
256e948693eSPhilip Paeps
257e948693eSPhilip Paeps return (0);
258e948693eSPhilip Paeps
259e948693eSPhilip Paeps fail2:
260e948693eSPhilip Paeps EFSYS_PROBE(fail2);
261e948693eSPhilip Paeps fail1:
262460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
263e948693eSPhilip Paeps
264e948693eSPhilip Paeps return (rc);
265e948693eSPhilip Paeps }
266e948693eSPhilip Paeps
267460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_reconfigure(__in efx_nic_t * enp)268e948693eSPhilip Paeps siena_phy_reconfigure(
269e948693eSPhilip Paeps __in efx_nic_t *enp)
270e948693eSPhilip Paeps {
271e948693eSPhilip Paeps efx_port_t *epp = &(enp->en_port);
272e948693eSPhilip Paeps efx_mcdi_req_t req;
273315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload,
274315bbbaaSAndrew Rybchenko MAX(MC_CMD_SET_ID_LED_IN_LEN, MC_CMD_SET_LINK_IN_LEN),
275315bbbaaSAndrew Rybchenko MAX(MC_CMD_SET_ID_LED_OUT_LEN, MC_CMD_SET_LINK_OUT_LEN));
276e948693eSPhilip Paeps uint32_t cap_mask;
277c68c424cSAndrew Rybchenko #if EFSYS_OPT_PHY_LED_CONTROL
278e948693eSPhilip Paeps unsigned int led_mode;
279c68c424cSAndrew Rybchenko #endif
280e948693eSPhilip Paeps unsigned int speed;
281460cb568SAndrew Rybchenko efx_rc_t rc;
282e948693eSPhilip Paeps
283e948693eSPhilip Paeps req.emr_cmd = MC_CMD_SET_LINK;
284e948693eSPhilip Paeps req.emr_in_buf = payload;
285e948693eSPhilip Paeps req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
2863c838a9fSAndrew Rybchenko req.emr_out_buf = payload;
2873c838a9fSAndrew Rybchenko req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
288e948693eSPhilip Paeps
289e948693eSPhilip Paeps cap_mask = epp->ep_adv_cap_mask;
290e948693eSPhilip Paeps MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
291e948693eSPhilip Paeps PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
292e948693eSPhilip Paeps PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
293e948693eSPhilip Paeps PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
294e948693eSPhilip Paeps PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
295e948693eSPhilip Paeps PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
296e948693eSPhilip Paeps PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
297e948693eSPhilip Paeps PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
298e948693eSPhilip Paeps PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
299e948693eSPhilip Paeps PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
300e948693eSPhilip Paeps PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
301e948693eSPhilip Paeps
302e948693eSPhilip Paeps #if EFSYS_OPT_LOOPBACK
303e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
304e948693eSPhilip Paeps epp->ep_loopback_type);
305e948693eSPhilip Paeps switch (epp->ep_loopback_link_mode) {
306e948693eSPhilip Paeps case EFX_LINK_100FDX:
307e948693eSPhilip Paeps speed = 100;
308e948693eSPhilip Paeps break;
309e948693eSPhilip Paeps case EFX_LINK_1000FDX:
310e948693eSPhilip Paeps speed = 1000;
311e948693eSPhilip Paeps break;
312e948693eSPhilip Paeps case EFX_LINK_10000FDX:
313e948693eSPhilip Paeps speed = 10000;
314e948693eSPhilip Paeps break;
315e948693eSPhilip Paeps default:
316e948693eSPhilip Paeps speed = 0;
317e948693eSPhilip Paeps }
318e948693eSPhilip Paeps #else
319e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
320e948693eSPhilip Paeps speed = 0;
321e948693eSPhilip Paeps #endif /* EFSYS_OPT_LOOPBACK */
322e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
323e948693eSPhilip Paeps
324e948693eSPhilip Paeps #if EFSYS_OPT_PHY_FLAGS
325e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
326e948693eSPhilip Paeps #else
327e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
328e948693eSPhilip Paeps #endif /* EFSYS_OPT_PHY_FLAGS */
329e948693eSPhilip Paeps
330e948693eSPhilip Paeps efx_mcdi_execute(enp, &req);
331e948693eSPhilip Paeps
332e948693eSPhilip Paeps if (req.emr_rc != 0) {
333e948693eSPhilip Paeps rc = req.emr_rc;
334e948693eSPhilip Paeps goto fail1;
335e948693eSPhilip Paeps }
336e948693eSPhilip Paeps
337e948693eSPhilip Paeps /* And set the blink mode */
3383c838a9fSAndrew Rybchenko (void) memset(payload, 0, sizeof (payload));
339e948693eSPhilip Paeps req.emr_cmd = MC_CMD_SET_ID_LED;
340e948693eSPhilip Paeps req.emr_in_buf = payload;
341e948693eSPhilip Paeps req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
3423c838a9fSAndrew Rybchenko req.emr_out_buf = payload;
3433c838a9fSAndrew Rybchenko req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
344e948693eSPhilip Paeps
345e948693eSPhilip Paeps #if EFSYS_OPT_PHY_LED_CONTROL
346e948693eSPhilip Paeps switch (epp->ep_phy_led_mode) {
347e948693eSPhilip Paeps case EFX_PHY_LED_DEFAULT:
348e948693eSPhilip Paeps led_mode = MC_CMD_LED_DEFAULT;
349e948693eSPhilip Paeps break;
350e948693eSPhilip Paeps case EFX_PHY_LED_OFF:
351e948693eSPhilip Paeps led_mode = MC_CMD_LED_OFF;
352e948693eSPhilip Paeps break;
353e948693eSPhilip Paeps case EFX_PHY_LED_ON:
354e948693eSPhilip Paeps led_mode = MC_CMD_LED_ON;
355e948693eSPhilip Paeps break;
356e948693eSPhilip Paeps default:
357e948693eSPhilip Paeps EFSYS_ASSERT(0);
358e948693eSPhilip Paeps led_mode = MC_CMD_LED_DEFAULT;
359e948693eSPhilip Paeps }
360e948693eSPhilip Paeps
361e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
362e948693eSPhilip Paeps #else
363e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
364e948693eSPhilip Paeps #endif /* EFSYS_OPT_PHY_LED_CONTROL */
365e948693eSPhilip Paeps
366e948693eSPhilip Paeps efx_mcdi_execute(enp, &req);
367e948693eSPhilip Paeps
368e948693eSPhilip Paeps if (req.emr_rc != 0) {
369e948693eSPhilip Paeps rc = req.emr_rc;
370e948693eSPhilip Paeps goto fail2;
371e948693eSPhilip Paeps }
372e948693eSPhilip Paeps
373e948693eSPhilip Paeps return (0);
374e948693eSPhilip Paeps
375e948693eSPhilip Paeps fail2:
376e948693eSPhilip Paeps EFSYS_PROBE(fail2);
377e948693eSPhilip Paeps fail1:
378460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
379e948693eSPhilip Paeps
380e948693eSPhilip Paeps return (rc);
381e948693eSPhilip Paeps }
382e948693eSPhilip Paeps
383460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_verify(__in efx_nic_t * enp)384e948693eSPhilip Paeps siena_phy_verify(
385e948693eSPhilip Paeps __in efx_nic_t *enp)
386e948693eSPhilip Paeps {
387e948693eSPhilip Paeps efx_mcdi_req_t req;
388315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN,
389315bbbaaSAndrew Rybchenko MC_CMD_GET_PHY_STATE_OUT_LEN);
390e948693eSPhilip Paeps uint32_t state;
391460cb568SAndrew Rybchenko efx_rc_t rc;
392e948693eSPhilip Paeps
393e948693eSPhilip Paeps req.emr_cmd = MC_CMD_GET_PHY_STATE;
3943c838a9fSAndrew Rybchenko req.emr_in_buf = payload;
3953c838a9fSAndrew Rybchenko req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
3963c838a9fSAndrew Rybchenko req.emr_out_buf = payload;
3973c838a9fSAndrew Rybchenko req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
398e948693eSPhilip Paeps
399e948693eSPhilip Paeps efx_mcdi_execute(enp, &req);
400e948693eSPhilip Paeps
401e948693eSPhilip Paeps if (req.emr_rc != 0) {
402e948693eSPhilip Paeps rc = req.emr_rc;
403e948693eSPhilip Paeps goto fail1;
404e948693eSPhilip Paeps }
405e948693eSPhilip Paeps
406e948693eSPhilip Paeps if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
407e948693eSPhilip Paeps rc = EMSGSIZE;
408e948693eSPhilip Paeps goto fail2;
409e948693eSPhilip Paeps }
410e948693eSPhilip Paeps
411e948693eSPhilip Paeps state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
412e948693eSPhilip Paeps if (state != MC_CMD_PHY_STATE_OK) {
413e948693eSPhilip Paeps if (state != MC_CMD_PHY_STATE_ZOMBIE)
414e948693eSPhilip Paeps EFSYS_PROBE1(mc_pcol_error, int, state);
415e948693eSPhilip Paeps rc = ENOTACTIVE;
416e948693eSPhilip Paeps goto fail3;
417e948693eSPhilip Paeps }
418e948693eSPhilip Paeps
419e948693eSPhilip Paeps return (0);
420e948693eSPhilip Paeps
421e948693eSPhilip Paeps fail3:
422e948693eSPhilip Paeps EFSYS_PROBE(fail3);
423e948693eSPhilip Paeps fail2:
424e948693eSPhilip Paeps EFSYS_PROBE(fail2);
425e948693eSPhilip Paeps fail1:
426460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
427e948693eSPhilip Paeps
428e948693eSPhilip Paeps return (rc);
429e948693eSPhilip Paeps }
430e948693eSPhilip Paeps
431460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_oui_get(__in efx_nic_t * enp,__out uint32_t * ouip)432e948693eSPhilip Paeps siena_phy_oui_get(
433e948693eSPhilip Paeps __in efx_nic_t *enp,
434e948693eSPhilip Paeps __out uint32_t *ouip)
435e948693eSPhilip Paeps {
436e948693eSPhilip Paeps _NOTE(ARGUNUSED(enp, ouip))
437e948693eSPhilip Paeps
438e948693eSPhilip Paeps return (ENOTSUP);
439e948693eSPhilip Paeps }
440e948693eSPhilip Paeps
441e948693eSPhilip Paeps #if EFSYS_OPT_PHY_STATS
442e948693eSPhilip Paeps
443e948693eSPhilip Paeps #define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \
444e948693eSPhilip Paeps _mc_record, _efx_record) \
445e948693eSPhilip Paeps if ((_vmask) & (1ULL << (_mc_record))) { \
446e948693eSPhilip Paeps (_smask) |= (1ULL << (_efx_record)); \
447e948693eSPhilip Paeps if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) { \
448e948693eSPhilip Paeps efx_dword_t dword; \
449e948693eSPhilip Paeps EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
450e948693eSPhilip Paeps (_stat)[_efx_record] = \
451e948693eSPhilip Paeps EFX_DWORD_FIELD(dword, EFX_DWORD_0); \
452e948693eSPhilip Paeps } \
453e948693eSPhilip Paeps }
454e948693eSPhilip Paeps
455e948693eSPhilip Paeps #define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record) \
456e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \
457e948693eSPhilip Paeps MC_CMD_ ## _record, \
458e948693eSPhilip Paeps EFX_PHY_STAT_ ## _record)
459e948693eSPhilip Paeps
460e948693eSPhilip Paeps void
siena_phy_decode_stats(__in efx_nic_t * enp,__in uint32_t vmask,__in_opt efsys_mem_t * esmp,__out_opt uint64_t * smaskp,__inout_ecount_opt (EFX_PHY_NSTATS)uint32_t * stat)461e948693eSPhilip Paeps siena_phy_decode_stats(
462e948693eSPhilip Paeps __in efx_nic_t *enp,
463e948693eSPhilip Paeps __in uint32_t vmask,
464e948693eSPhilip Paeps __in_opt efsys_mem_t *esmp,
465e948693eSPhilip Paeps __out_opt uint64_t *smaskp,
466536c03c2SAndrew Rybchenko __inout_ecount_opt(EFX_PHY_NSTATS) uint32_t *stat)
467e948693eSPhilip Paeps {
468e948693eSPhilip Paeps uint64_t smask = 0;
469e948693eSPhilip Paeps
470e948693eSPhilip Paeps _NOTE(ARGUNUSED(enp))
471e948693eSPhilip Paeps
472e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
473e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
474e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
475e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
476e948693eSPhilip Paeps
477e948693eSPhilip Paeps if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
478e948693eSPhilip Paeps smask |= ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
479e948693eSPhilip Paeps (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
480e948693eSPhilip Paeps (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
481e948693eSPhilip Paeps (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
482e948693eSPhilip Paeps if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
483e948693eSPhilip Paeps efx_dword_t dword;
484e948693eSPhilip Paeps uint32_t sig;
485e948693eSPhilip Paeps EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
486e948693eSPhilip Paeps &dword);
487e948693eSPhilip Paeps sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
488e948693eSPhilip Paeps stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
489e948693eSPhilip Paeps stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
490e948693eSPhilip Paeps stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
491e948693eSPhilip Paeps stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
492e948693eSPhilip Paeps }
493e948693eSPhilip Paeps }
494e948693eSPhilip Paeps
495e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
496e948693eSPhilip Paeps EFX_PHY_STAT_SNR_A);
497e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
498e948693eSPhilip Paeps EFX_PHY_STAT_SNR_B);
499e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
500e948693eSPhilip Paeps EFX_PHY_STAT_SNR_C);
501e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
502e948693eSPhilip Paeps EFX_PHY_STAT_SNR_D);
503e948693eSPhilip Paeps
504e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
505e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
506e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
507e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
508e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
509e948693eSPhilip Paeps
510e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
511e948693eSPhilip Paeps EFX_PHY_STAT_PHY_XS_LINK_UP);
512e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
513e948693eSPhilip Paeps EFX_PHY_STAT_PHY_XS_RX_FAULT);
514e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
515e948693eSPhilip Paeps EFX_PHY_STAT_PHY_XS_TX_FAULT);
516e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
517e948693eSPhilip Paeps EFX_PHY_STAT_PHY_XS_ALIGN);
518e948693eSPhilip Paeps
519e948693eSPhilip Paeps if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
520e948693eSPhilip Paeps smask |= ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
521e948693eSPhilip Paeps (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
522e948693eSPhilip Paeps (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
523e948693eSPhilip Paeps (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
524e948693eSPhilip Paeps if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
525e948693eSPhilip Paeps efx_dword_t dword;
526e948693eSPhilip Paeps uint32_t sync;
527e948693eSPhilip Paeps EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
528e948693eSPhilip Paeps sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
529e948693eSPhilip Paeps stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
530e948693eSPhilip Paeps stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
531e948693eSPhilip Paeps stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
532e948693eSPhilip Paeps stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
533e948693eSPhilip Paeps }
534e948693eSPhilip Paeps }
535e948693eSPhilip Paeps
536e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
537e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
538e948693eSPhilip Paeps
539e948693eSPhilip Paeps SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
540e948693eSPhilip Paeps EFX_PHY_STAT_CL22EXT_LINK_UP);
541e948693eSPhilip Paeps
542e948693eSPhilip Paeps if (smaskp != NULL)
543e948693eSPhilip Paeps *smaskp = smask;
544e948693eSPhilip Paeps }
545e948693eSPhilip Paeps
546460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_stats_update(__in efx_nic_t * enp,__in efsys_mem_t * esmp,__inout_ecount (EFX_PHY_NSTATS)uint32_t * stat)547e948693eSPhilip Paeps siena_phy_stats_update(
548e948693eSPhilip Paeps __in efx_nic_t *enp,
549e948693eSPhilip Paeps __in efsys_mem_t *esmp,
550536c03c2SAndrew Rybchenko __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat)
551e948693eSPhilip Paeps {
552e948693eSPhilip Paeps efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
5533c838a9fSAndrew Rybchenko uint32_t vmask = encp->enc_mcdi_phy_stat_mask;
554e948693eSPhilip Paeps uint64_t smask;
555e948693eSPhilip Paeps efx_mcdi_req_t req;
556315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PHY_STATS_IN_LEN,
557315bbbaaSAndrew Rybchenko MC_CMD_PHY_STATS_OUT_DMA_LEN);
558460cb568SAndrew Rybchenko efx_rc_t rc;
559e948693eSPhilip Paeps
5604aaefb95SAndrew Rybchenko if ((esmp == NULL) || (EFSYS_MEM_SIZE(esmp) < EFX_PHY_STATS_SIZE)) {
5614aaefb95SAndrew Rybchenko rc = EINVAL;
5624aaefb95SAndrew Rybchenko goto fail1;
5634aaefb95SAndrew Rybchenko }
5644aaefb95SAndrew Rybchenko
565e948693eSPhilip Paeps req.emr_cmd = MC_CMD_PHY_STATS;
566e948693eSPhilip Paeps req.emr_in_buf = payload;
5673c838a9fSAndrew Rybchenko req.emr_in_length = MC_CMD_PHY_STATS_IN_LEN;
5683c838a9fSAndrew Rybchenko req.emr_out_buf = payload;
5693c838a9fSAndrew Rybchenko req.emr_out_length = MC_CMD_PHY_STATS_OUT_DMA_LEN;
570e948693eSPhilip Paeps
571e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
572e948693eSPhilip Paeps EFSYS_MEM_ADDR(esmp) & 0xffffffff);
573e948693eSPhilip Paeps MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
574e948693eSPhilip Paeps EFSYS_MEM_ADDR(esmp) >> 32);
575e948693eSPhilip Paeps
576e948693eSPhilip Paeps efx_mcdi_execute(enp, &req);
577e948693eSPhilip Paeps
578e948693eSPhilip Paeps if (req.emr_rc != 0) {
579e948693eSPhilip Paeps rc = req.emr_rc;
5804aaefb95SAndrew Rybchenko goto fail2;
581e948693eSPhilip Paeps }
582e948693eSPhilip Paeps EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
583e948693eSPhilip Paeps
584e948693eSPhilip Paeps siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
585e948693eSPhilip Paeps EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
586e948693eSPhilip Paeps
58719447fc4SMateusz Guzik (void)rc; /* XXX? */
588e948693eSPhilip Paeps return (0);
589e948693eSPhilip Paeps
5904aaefb95SAndrew Rybchenko fail2:
5914aaefb95SAndrew Rybchenko EFSYS_PROBE(fail2);
592e948693eSPhilip Paeps fail1:
593460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
594e948693eSPhilip Paeps
595e948693eSPhilip Paeps return (0);
596e948693eSPhilip Paeps }
597e948693eSPhilip Paeps
598e948693eSPhilip Paeps #endif /* EFSYS_OPT_PHY_STATS */
599e948693eSPhilip Paeps
6003c838a9fSAndrew Rybchenko #if EFSYS_OPT_BIST
601e948693eSPhilip Paeps
602460cb568SAndrew Rybchenko __checkReturn efx_rc_t
siena_phy_bist_start(__in efx_nic_t * enp,__in efx_bist_type_t type)603e948693eSPhilip Paeps siena_phy_bist_start(
604e948693eSPhilip Paeps __in efx_nic_t *enp,
6053c838a9fSAndrew Rybchenko __in efx_bist_type_t type)
606e948693eSPhilip Paeps {
607460cb568SAndrew Rybchenko efx_rc_t rc;
608e948693eSPhilip Paeps
6093c838a9fSAndrew Rybchenko if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
610e948693eSPhilip Paeps goto fail1;
611e948693eSPhilip Paeps
612e948693eSPhilip Paeps return (0);
613e948693eSPhilip Paeps
614e948693eSPhilip Paeps fail1:
615460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
616e948693eSPhilip Paeps
617e948693eSPhilip Paeps return (rc);
618e948693eSPhilip Paeps }
619e948693eSPhilip Paeps
620e948693eSPhilip Paeps static __checkReturn unsigned long
siena_phy_sft9001_bist_status(__in uint16_t code)621e948693eSPhilip Paeps siena_phy_sft9001_bist_status(
622e948693eSPhilip Paeps __in uint16_t code)
623e948693eSPhilip Paeps {
624e948693eSPhilip Paeps switch (code) {
625e948693eSPhilip Paeps case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
626e948693eSPhilip Paeps return (EFX_PHY_CABLE_STATUS_BUSY);
627e948693eSPhilip Paeps case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
628e948693eSPhilip Paeps return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
629e948693eSPhilip Paeps case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
630e948693eSPhilip Paeps return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
631e948693eSPhilip Paeps case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
632e948693eSPhilip Paeps return (EFX_PHY_CABLE_STATUS_OPEN);
633e948693eSPhilip Paeps case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
634e948693eSPhilip Paeps return (EFX_PHY_CABLE_STATUS_OK);
635e948693eSPhilip Paeps default:
636e948693eSPhilip Paeps return (EFX_PHY_CABLE_STATUS_INVALID);
637e948693eSPhilip Paeps }
638e948693eSPhilip Paeps }
639e948693eSPhilip Paeps
640460cb568SAndrew Rybchenko __checkReturn efx_rc_t
641e948693eSPhilip Paeps siena_phy_bist_poll(
642e948693eSPhilip Paeps __in efx_nic_t *enp,
6433c838a9fSAndrew Rybchenko __in efx_bist_type_t type,
6443c838a9fSAndrew Rybchenko __out efx_bist_result_t *resultp,
645e948693eSPhilip Paeps __out_opt __drv_when(count > 0, __notnull)
646e948693eSPhilip Paeps uint32_t *value_maskp,
647e948693eSPhilip Paeps __out_ecount_opt(count) __drv_when(count > 0, __notnull)
648e948693eSPhilip Paeps unsigned long *valuesp,
649e948693eSPhilip Paeps __in size_t count)
650e948693eSPhilip Paeps {
651e948693eSPhilip Paeps efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
652315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN,
653315bbbaaSAndrew Rybchenko MCDI_CTL_SDU_LEN_MAX);
654e948693eSPhilip Paeps uint32_t value_mask = 0;
655e948693eSPhilip Paeps efx_mcdi_req_t req;
656e948693eSPhilip Paeps uint32_t result;
657460cb568SAndrew Rybchenko efx_rc_t rc;
658e948693eSPhilip Paeps
659e948693eSPhilip Paeps req.emr_cmd = MC_CMD_POLL_BIST;
6603c838a9fSAndrew Rybchenko req.emr_in_buf = payload;
6613c838a9fSAndrew Rybchenko req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
662e948693eSPhilip Paeps req.emr_out_buf = payload;
6633c838a9fSAndrew Rybchenko req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
664e948693eSPhilip Paeps
665e948693eSPhilip Paeps efx_mcdi_execute(enp, &req);
666e948693eSPhilip Paeps
667e948693eSPhilip Paeps if (req.emr_rc != 0) {
668e948693eSPhilip Paeps rc = req.emr_rc;
669e948693eSPhilip Paeps goto fail1;
670e948693eSPhilip Paeps }
671e948693eSPhilip Paeps
672e948693eSPhilip Paeps if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
673e948693eSPhilip Paeps rc = EMSGSIZE;
674e948693eSPhilip Paeps goto fail2;
675e948693eSPhilip Paeps }
676e948693eSPhilip Paeps
677e948693eSPhilip Paeps if (count > 0)
678e948693eSPhilip Paeps (void) memset(valuesp, '\0', count * sizeof (unsigned long));
679e948693eSPhilip Paeps
680e948693eSPhilip Paeps result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
681e948693eSPhilip Paeps
682e948693eSPhilip Paeps /* Extract PHY specific results */
683e948693eSPhilip Paeps if (result == MC_CMD_POLL_BIST_PASSED &&
684e948693eSPhilip Paeps encp->enc_phy_type == EFX_PHY_SFT9001B &&
685e948693eSPhilip Paeps req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
6863c838a9fSAndrew Rybchenko (type == EFX_BIST_TYPE_PHY_CABLE_SHORT ||
6873c838a9fSAndrew Rybchenko type == EFX_BIST_TYPE_PHY_CABLE_LONG)) {
688e948693eSPhilip Paeps uint16_t word;
689e948693eSPhilip Paeps
6903c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_LENGTH_A) {
691e948693eSPhilip Paeps if (valuesp != NULL)
6923c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] =
693e948693eSPhilip Paeps MCDI_OUT_DWORD(req,
694e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
6953c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A);
696e948693eSPhilip Paeps }
697e948693eSPhilip Paeps
6983c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_LENGTH_B) {
699e948693eSPhilip Paeps if (valuesp != NULL)
7003c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] =
701e948693eSPhilip Paeps MCDI_OUT_DWORD(req,
702e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
7033c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B);
704e948693eSPhilip Paeps }
705e948693eSPhilip Paeps
7063c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_LENGTH_C) {
707e948693eSPhilip Paeps if (valuesp != NULL)
7083c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] =
709e948693eSPhilip Paeps MCDI_OUT_DWORD(req,
710e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
7113c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C);
712e948693eSPhilip Paeps }
713e948693eSPhilip Paeps
7143c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_LENGTH_D) {
715e948693eSPhilip Paeps if (valuesp != NULL)
7163c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] =
717e948693eSPhilip Paeps MCDI_OUT_DWORD(req,
718e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
7193c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D);
720e948693eSPhilip Paeps }
721e948693eSPhilip Paeps
7223c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_STATUS_A) {
723e948693eSPhilip Paeps if (valuesp != NULL) {
724e948693eSPhilip Paeps word = MCDI_OUT_WORD(req,
725e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
7263c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_STATUS_A] =
727e948693eSPhilip Paeps siena_phy_sft9001_bist_status(word);
728e948693eSPhilip Paeps }
7293c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A);
730e948693eSPhilip Paeps }
731e948693eSPhilip Paeps
7323c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_STATUS_B) {
733e948693eSPhilip Paeps if (valuesp != NULL) {
734e948693eSPhilip Paeps word = MCDI_OUT_WORD(req,
735e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
7363c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_STATUS_B] =
737e948693eSPhilip Paeps siena_phy_sft9001_bist_status(word);
738e948693eSPhilip Paeps }
7393c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B);
740e948693eSPhilip Paeps }
741e948693eSPhilip Paeps
7423c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_STATUS_C) {
743e948693eSPhilip Paeps if (valuesp != NULL) {
744e948693eSPhilip Paeps word = MCDI_OUT_WORD(req,
745e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
7463c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_STATUS_C] =
747e948693eSPhilip Paeps siena_phy_sft9001_bist_status(word);
748e948693eSPhilip Paeps }
7493c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C);
750e948693eSPhilip Paeps }
751e948693eSPhilip Paeps
7523c838a9fSAndrew Rybchenko if (count > EFX_BIST_PHY_CABLE_STATUS_D) {
753e948693eSPhilip Paeps if (valuesp != NULL) {
754e948693eSPhilip Paeps word = MCDI_OUT_WORD(req,
755e948693eSPhilip Paeps POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
7563c838a9fSAndrew Rybchenko valuesp[EFX_BIST_PHY_CABLE_STATUS_D] =
757e948693eSPhilip Paeps siena_phy_sft9001_bist_status(word);
758e948693eSPhilip Paeps }
7593c838a9fSAndrew Rybchenko value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D);
760e948693eSPhilip Paeps }
761e948693eSPhilip Paeps
762e948693eSPhilip Paeps } else if (result == MC_CMD_POLL_BIST_FAILED &&
763e948693eSPhilip Paeps encp->enc_phy_type == EFX_PHY_QLX111V &&
764e948693eSPhilip Paeps req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
7653c838a9fSAndrew Rybchenko count > EFX_BIST_FAULT_CODE) {
766e948693eSPhilip Paeps if (valuesp != NULL)
7673c838a9fSAndrew Rybchenko valuesp[EFX_BIST_FAULT_CODE] =
768e948693eSPhilip Paeps MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
7693c838a9fSAndrew Rybchenko value_mask |= 1 << EFX_BIST_FAULT_CODE;
770e948693eSPhilip Paeps }
771e948693eSPhilip Paeps
772e948693eSPhilip Paeps if (value_maskp != NULL)
773e948693eSPhilip Paeps *value_maskp = value_mask;
774e948693eSPhilip Paeps
775e948693eSPhilip Paeps EFSYS_ASSERT(resultp != NULL);
776e948693eSPhilip Paeps if (result == MC_CMD_POLL_BIST_RUNNING)
7773c838a9fSAndrew Rybchenko *resultp = EFX_BIST_RESULT_RUNNING;
778e948693eSPhilip Paeps else if (result == MC_CMD_POLL_BIST_PASSED)
7793c838a9fSAndrew Rybchenko *resultp = EFX_BIST_RESULT_PASSED;
780e948693eSPhilip Paeps else
7813c838a9fSAndrew Rybchenko *resultp = EFX_BIST_RESULT_FAILED;
782e948693eSPhilip Paeps
783e948693eSPhilip Paeps return (0);
784e948693eSPhilip Paeps
785e948693eSPhilip Paeps fail2:
786e948693eSPhilip Paeps EFSYS_PROBE(fail2);
787e948693eSPhilip Paeps fail1:
788460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
789e948693eSPhilip Paeps
790e948693eSPhilip Paeps return (rc);
791e948693eSPhilip Paeps }
792e948693eSPhilip Paeps
793e948693eSPhilip Paeps void
siena_phy_bist_stop(__in efx_nic_t * enp,__in efx_bist_type_t type)794e948693eSPhilip Paeps siena_phy_bist_stop(
795e948693eSPhilip Paeps __in efx_nic_t *enp,
7963c838a9fSAndrew Rybchenko __in efx_bist_type_t type)
797e948693eSPhilip Paeps {
798e948693eSPhilip Paeps /* There is no way to stop BIST on Siena */
799e948693eSPhilip Paeps _NOTE(ARGUNUSED(enp, type))
800e948693eSPhilip Paeps }
801e948693eSPhilip Paeps
8023c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_BIST */
803e948693eSPhilip Paeps
804e948693eSPhilip Paeps #endif /* EFSYS_OPT_SIENA */
805