cassini/niu/sun*: Move the Sun drivers
[pandora-kernel.git] / drivers / net / ethernet / sfc / mcdi_phy.c
1 /****************************************************************************
2  * Driver for Solarflare Solarstorm network controllers and boards
3  * Copyright 2009-2010 Solarflare Communications Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published
7  * by the Free Software Foundation, incorporated herein by reference.
8  */
9
10 /*
11  * Driver for PHY related operations via MCDI.
12  */
13
14 #include <linux/slab.h>
15 #include "efx.h"
16 #include "phy.h"
17 #include "mcdi.h"
18 #include "mcdi_pcol.h"
19 #include "nic.h"
20 #include "selftest.h"
21
22 struct efx_mcdi_phy_data {
23         u32 flags;
24         u32 type;
25         u32 supported_cap;
26         u32 channel;
27         u32 port;
28         u32 stats_mask;
29         u8 name[20];
30         u32 media;
31         u32 mmd_mask;
32         u8 revision[20];
33         u32 forced_cap;
34 };
35
36 static int
37 efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg)
38 {
39         u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
40         size_t outlen;
41         int rc;
42
43         BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0);
44         BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name));
45
46         rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0,
47                           outbuf, sizeof(outbuf), &outlen);
48         if (rc)
49                 goto fail;
50
51         if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) {
52                 rc = -EIO;
53                 goto fail;
54         }
55
56         cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS);
57         cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE);
58         cfg->supported_cap =
59                 MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP);
60         cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL);
61         cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT);
62         cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK);
63         memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME),
64                sizeof(cfg->name));
65         cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE);
66         cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK);
67         memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION),
68                sizeof(cfg->revision));
69
70         return 0;
71
72 fail:
73         netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
74         return rc;
75 }
76
77 static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,
78                              u32 flags, u32 loopback_mode,
79                              u32 loopback_speed)
80 {
81         u8 inbuf[MC_CMD_SET_LINK_IN_LEN];
82         int rc;
83
84         BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0);
85
86         MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities);
87         MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags);
88         MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode);
89         MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed);
90
91         rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf),
92                           NULL, 0, NULL);
93         if (rc)
94                 goto fail;
95
96         return 0;
97
98 fail:
99         netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
100         return rc;
101 }
102
103 static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes)
104 {
105         u8 outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN];
106         size_t outlen;
107         int rc;
108
109         rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0,
110                           outbuf, sizeof(outbuf), &outlen);
111         if (rc)
112                 goto fail;
113
114         if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) {
115                 rc = -EIO;
116                 goto fail;
117         }
118
119         *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_SUGGESTED);
120
121         return 0;
122
123 fail:
124         netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
125         return rc;
126 }
127
128 int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus,
129                          unsigned int prtad, unsigned int devad, u16 addr,
130                          u16 *value_out, u32 *status_out)
131 {
132         u8 inbuf[MC_CMD_MDIO_READ_IN_LEN];
133         u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN];
134         size_t outlen;
135         int rc;
136
137         MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus);
138         MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad);
139         MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad);
140         MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr);
141
142         rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf),
143                           outbuf, sizeof(outbuf), &outlen);
144         if (rc)
145                 goto fail;
146
147         *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE);
148         *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS);
149         return 0;
150
151 fail:
152         netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
153         return rc;
154 }
155
156 int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus,
157                           unsigned int prtad, unsigned int devad, u16 addr,
158                           u16 value, u32 *status_out)
159 {
160         u8 inbuf[MC_CMD_MDIO_WRITE_IN_LEN];
161         u8 outbuf[MC_CMD_MDIO_WRITE_OUT_LEN];
162         size_t outlen;
163         int rc;
164
165         MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, bus);
166         MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad);
167         MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad);
168         MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr);
169         MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value);
170
171         rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf),
172                           outbuf, sizeof(outbuf), &outlen);
173         if (rc)
174                 goto fail;
175
176         *status_out = MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS);
177         return 0;
178
179 fail:
180         netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
181         return rc;
182 }
183
184 static u32 mcdi_to_ethtool_cap(u32 media, u32 cap)
185 {
186         u32 result = 0;
187
188         switch (media) {
189         case MC_CMD_MEDIA_KX4:
190                 result |= SUPPORTED_Backplane;
191                 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
192                         result |= SUPPORTED_1000baseKX_Full;
193                 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
194                         result |= SUPPORTED_10000baseKX4_Full;
195                 break;
196
197         case MC_CMD_MEDIA_XFP:
198         case MC_CMD_MEDIA_SFP_PLUS:
199                 result |= SUPPORTED_FIBRE;
200                 break;
201
202         case MC_CMD_MEDIA_BASE_T:
203                 result |= SUPPORTED_TP;
204                 if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
205                         result |= SUPPORTED_10baseT_Half;
206                 if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
207                         result |= SUPPORTED_10baseT_Full;
208                 if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
209                         result |= SUPPORTED_100baseT_Half;
210                 if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
211                         result |= SUPPORTED_100baseT_Full;
212                 if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
213                         result |= SUPPORTED_1000baseT_Half;
214                 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
215                         result |= SUPPORTED_1000baseT_Full;
216                 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
217                         result |= SUPPORTED_10000baseT_Full;
218                 break;
219         }
220
221         if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
222                 result |= SUPPORTED_Pause;
223         if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
224                 result |= SUPPORTED_Asym_Pause;
225         if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
226                 result |= SUPPORTED_Autoneg;
227
228         return result;
229 }
230
231 static u32 ethtool_to_mcdi_cap(u32 cap)
232 {
233         u32 result = 0;
234
235         if (cap & SUPPORTED_10baseT_Half)
236                 result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN);
237         if (cap & SUPPORTED_10baseT_Full)
238                 result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN);
239         if (cap & SUPPORTED_100baseT_Half)
240                 result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN);
241         if (cap & SUPPORTED_100baseT_Full)
242                 result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN);
243         if (cap & SUPPORTED_1000baseT_Half)
244                 result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN);
245         if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full))
246                 result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN);
247         if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full))
248                 result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN);
249         if (cap & SUPPORTED_Pause)
250                 result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN);
251         if (cap & SUPPORTED_Asym_Pause)
252                 result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN);
253         if (cap & SUPPORTED_Autoneg)
254                 result |= (1 << MC_CMD_PHY_CAP_AN_LBN);
255
256         return result;
257 }
258
259 static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
260 {
261         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
262         enum efx_phy_mode mode, supported;
263         u32 flags;
264
265         /* TODO: Advertise the capabilities supported by this PHY */
266         supported = 0;
267         if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_TXDIS_LBN))
268                 supported |= PHY_MODE_TX_DISABLED;
269         if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_LOWPOWER_LBN))
270                 supported |= PHY_MODE_LOW_POWER;
271         if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_POWEROFF_LBN))
272                 supported |= PHY_MODE_OFF;
273
274         mode = efx->phy_mode & supported;
275
276         flags = 0;
277         if (mode & PHY_MODE_TX_DISABLED)
278                 flags |= (1 << MC_CMD_SET_LINK_TXDIS_LBN);
279         if (mode & PHY_MODE_LOW_POWER)
280                 flags |= (1 << MC_CMD_SET_LINK_LOWPOWER_LBN);
281         if (mode & PHY_MODE_OFF)
282                 flags |= (1 << MC_CMD_SET_LINK_POWEROFF_LBN);
283
284         return flags;
285 }
286
287 static u32 mcdi_to_ethtool_media(u32 media)
288 {
289         switch (media) {
290         case MC_CMD_MEDIA_XAUI:
291         case MC_CMD_MEDIA_CX4:
292         case MC_CMD_MEDIA_KX4:
293                 return PORT_OTHER;
294
295         case MC_CMD_MEDIA_XFP:
296         case MC_CMD_MEDIA_SFP_PLUS:
297                 return PORT_FIBRE;
298
299         case MC_CMD_MEDIA_BASE_T:
300                 return PORT_TP;
301
302         default:
303                 return PORT_OTHER;
304         }
305 }
306
307 static int efx_mcdi_phy_probe(struct efx_nic *efx)
308 {
309         struct efx_mcdi_phy_data *phy_data;
310         u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
311         u32 caps;
312         int rc;
313
314         /* Initialise and populate phy_data */
315         phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
316         if (phy_data == NULL)
317                 return -ENOMEM;
318
319         rc = efx_mcdi_get_phy_cfg(efx, phy_data);
320         if (rc != 0)
321                 goto fail;
322
323         /* Read initial link advertisement */
324         BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
325         rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
326                           outbuf, sizeof(outbuf), NULL);
327         if (rc)
328                 goto fail;
329
330         /* Fill out nic state */
331         efx->phy_data = phy_data;
332         efx->phy_type = phy_data->type;
333
334         efx->mdio_bus = phy_data->channel;
335         efx->mdio.prtad = phy_data->port;
336         efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22);
337         efx->mdio.mode_support = 0;
338         if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22))
339                 efx->mdio.mode_support |= MDIO_SUPPORTS_C22;
340         if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22))
341                 efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
342
343         caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);
344         if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))
345                 efx->link_advertising =
346                         mcdi_to_ethtool_cap(phy_data->media, caps);
347         else
348                 phy_data->forced_cap = caps;
349
350         /* Assert that we can map efx -> mcdi loopback modes */
351         BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE);
352         BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA);
353         BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC);
354         BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII);
355         BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS);
356         BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI);
357         BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII);
358         BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII);
359         BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR);
360         BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI);
361         BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR);
362         BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR);
363         BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR);
364         BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR);
365         BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY);
366         BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS);
367         BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS);
368         BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD);
369         BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT);
370         BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS);
371         BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS);
372         BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR);
373         BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR);
374         BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS);
375         BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS);
376         BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR);
377         BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS);
378
379         rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes);
380         if (rc != 0)
381                 goto fail;
382         /* The MC indicates that LOOPBACK_NONE is a valid loopback mode,
383          * but by convention we don't */
384         efx->loopback_modes &= ~(1 << LOOPBACK_NONE);
385
386         /* Set the initial link mode */
387         efx_mcdi_phy_decode_link(
388                 efx, &efx->link_state,
389                 MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
390                 MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
391                 MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
392
393         /* Default to Autonegotiated flow control if the PHY supports it */
394         efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
395         if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
396                 efx->wanted_fc |= EFX_FC_AUTO;
397         efx_link_set_wanted_fc(efx, efx->wanted_fc);
398
399         return 0;
400
401 fail:
402         kfree(phy_data);
403         return rc;
404 }
405
406 int efx_mcdi_phy_reconfigure(struct efx_nic *efx)
407 {
408         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
409         u32 caps = (efx->link_advertising ?
410                     ethtool_to_mcdi_cap(efx->link_advertising) :
411                     phy_cfg->forced_cap);
412
413         return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
414                                  efx->loopback_mode, 0);
415 }
416
417 void efx_mcdi_phy_decode_link(struct efx_nic *efx,
418                               struct efx_link_state *link_state,
419                               u32 speed, u32 flags, u32 fcntl)
420 {
421         switch (fcntl) {
422         case MC_CMD_FCNTL_AUTO:
423                 WARN_ON(1);     /* This is not a link mode */
424                 link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX;
425                 break;
426         case MC_CMD_FCNTL_BIDIR:
427                 link_state->fc = EFX_FC_TX | EFX_FC_RX;
428                 break;
429         case MC_CMD_FCNTL_RESPOND:
430                 link_state->fc = EFX_FC_RX;
431                 break;
432         default:
433                 WARN_ON(1);
434         case MC_CMD_FCNTL_OFF:
435                 link_state->fc = 0;
436                 break;
437         }
438
439         link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_LINK_UP_LBN));
440         link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_FULL_DUPLEX_LBN));
441         link_state->speed = speed;
442 }
443
444 /* Verify that the forced flow control settings (!EFX_FC_AUTO) are
445  * supported by the link partner. Warn the user if this isn't the case
446  */
447 void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
448 {
449         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
450         u32 rmtadv;
451
452         /* The link partner capabilities are only relevant if the
453          * link supports flow control autonegotiation */
454         if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
455                 return;
456
457         /* If flow control autoneg is supported and enabled, then fine */
458         if (efx->wanted_fc & EFX_FC_AUTO)
459                 return;
460
461         rmtadv = 0;
462         if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
463                 rmtadv |= ADVERTISED_Pause;
464         if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
465                 rmtadv |=  ADVERTISED_Asym_Pause;
466
467         if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause)
468                 netif_err(efx, link, efx->net_dev,
469                           "warning: link partner doesn't support pause frames");
470 }
471
472 static bool efx_mcdi_phy_poll(struct efx_nic *efx)
473 {
474         struct efx_link_state old_state = efx->link_state;
475         u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
476         int rc;
477
478         WARN_ON(!mutex_is_locked(&efx->mac_lock));
479
480         BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
481
482         rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
483                           outbuf, sizeof(outbuf), NULL);
484         if (rc) {
485                 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
486                           __func__, rc);
487                 efx->link_state.up = false;
488         } else {
489                 efx_mcdi_phy_decode_link(
490                         efx, &efx->link_state,
491                         MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
492                         MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
493                         MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
494         }
495
496         return !efx_link_state_equal(&efx->link_state, &old_state);
497 }
498
499 static void efx_mcdi_phy_remove(struct efx_nic *efx)
500 {
501         struct efx_mcdi_phy_data *phy_data = efx->phy_data;
502
503         efx->phy_data = NULL;
504         kfree(phy_data);
505 }
506
507 static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
508 {
509         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
510         u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
511         int rc;
512
513         ecmd->supported =
514                 mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
515         ecmd->advertising = efx->link_advertising;
516         ethtool_cmd_speed_set(ecmd, efx->link_state.speed);
517         ecmd->duplex = efx->link_state.fd;
518         ecmd->port = mcdi_to_ethtool_media(phy_cfg->media);
519         ecmd->phy_address = phy_cfg->port;
520         ecmd->transceiver = XCVR_INTERNAL;
521         ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
522         ecmd->mdio_support = (efx->mdio.mode_support &
523                               (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));
524
525         BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
526         rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
527                           outbuf, sizeof(outbuf), NULL);
528         if (rc) {
529                 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
530                           __func__, rc);
531                 return;
532         }
533         ecmd->lp_advertising =
534                 mcdi_to_ethtool_cap(phy_cfg->media,
535                                     MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
536 }
537
538 static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
539 {
540         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
541         u32 caps;
542         int rc;
543
544         if (ecmd->autoneg) {
545                 caps = (ethtool_to_mcdi_cap(ecmd->advertising) |
546                          1 << MC_CMD_PHY_CAP_AN_LBN);
547         } else if (ecmd->duplex) {
548                 switch (ethtool_cmd_speed(ecmd)) {
549                 case 10:    caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN;    break;
550                 case 100:   caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN;   break;
551                 case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN;  break;
552                 case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break;
553                 default:    return -EINVAL;
554                 }
555         } else {
556                 switch (ethtool_cmd_speed(ecmd)) {
557                 case 10:    caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN;    break;
558                 case 100:   caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN;   break;
559                 case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN;  break;
560                 default:    return -EINVAL;
561                 }
562         }
563
564         rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
565                                efx->loopback_mode, 0);
566         if (rc)
567                 return rc;
568
569         if (ecmd->autoneg) {
570                 efx_link_set_advertising(
571                         efx, ecmd->advertising | ADVERTISED_Autoneg);
572                 phy_cfg->forced_cap = 0;
573         } else {
574                 efx_link_set_advertising(efx, 0);
575                 phy_cfg->forced_cap = caps;
576         }
577         return 0;
578 }
579
580 static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
581 {
582         u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
583         size_t outlen;
584         int rc;
585
586         BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);
587
588         rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,
589                           outbuf, sizeof(outbuf), &outlen);
590         if (rc)
591                 return rc;
592
593         if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
594                 return -EIO;
595         if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK)
596                 return -EINVAL;
597
598         return 0;
599 }
600
601 static const char *const mcdi_sft9001_cable_diag_names[] = {
602         "cable.pairA.length",
603         "cable.pairB.length",
604         "cable.pairC.length",
605         "cable.pairD.length",
606         "cable.pairA.status",
607         "cable.pairB.status",
608         "cable.pairC.status",
609         "cable.pairD.status",
610 };
611
612 static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode,
613                          int *results)
614 {
615         unsigned int retry, i, count = 0;
616         size_t outlen;
617         u32 status;
618         u8 *buf, *ptr;
619         int rc;
620
621         buf = kzalloc(0x100, GFP_KERNEL);
622         if (buf == NULL)
623                 return -ENOMEM;
624
625         BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0);
626         MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode);
627         rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN,
628                           NULL, 0, NULL);
629         if (rc)
630                 goto out;
631
632         /* Wait up to 10s for BIST to finish */
633         for (retry = 0; retry < 100; ++retry) {
634                 BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0);
635                 rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
636                                   buf, 0x100, &outlen);
637                 if (rc)
638                         goto out;
639
640                 status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT);
641                 if (status != MC_CMD_POLL_BIST_RUNNING)
642                         goto finished;
643
644                 msleep(100);
645         }
646
647         rc = -ETIMEDOUT;
648         goto out;
649
650 finished:
651         results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1;
652
653         /* SFT9001 specific cable diagnostics output */
654         if (efx->phy_type == PHY_TYPE_SFT9001B &&
655             (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT ||
656              bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) {
657                 ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
658                 if (status == MC_CMD_POLL_BIST_PASSED &&
659                     outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) {
660                         for (i = 0; i < 8; i++) {
661                                 results[count + i] =
662                                         EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i],
663                                                         EFX_DWORD_0);
664                         }
665                 }
666                 count += 8;
667         }
668         rc = count;
669
670 out:
671         kfree(buf);
672
673         return rc;
674 }
675
676 static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
677                                   unsigned flags)
678 {
679         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
680         u32 mode;
681         int rc;
682
683         if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
684                 rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results);
685                 if (rc < 0)
686                         return rc;
687
688                 results += rc;
689         }
690
691         /* If we support both LONG and SHORT, then run each in response to
692          * break or not. Otherwise, run the one we support */
693         mode = 0;
694         if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN)) {
695                 if ((flags & ETH_TEST_FL_OFFLINE) &&
696                     (phy_cfg->flags &
697                      (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN)))
698                         mode = MC_CMD_PHY_BIST_CABLE_LONG;
699                 else
700                         mode = MC_CMD_PHY_BIST_CABLE_SHORT;
701         } else if (phy_cfg->flags &
702                    (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))
703                 mode = MC_CMD_PHY_BIST_CABLE_LONG;
704
705         if (mode != 0) {
706                 rc = efx_mcdi_bist(efx, mode, results);
707                 if (rc < 0)
708                         return rc;
709                 results += rc;
710         }
711
712         return 0;
713 }
714
715 static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
716                                           unsigned int index)
717 {
718         struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
719
720         if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
721                 if (index == 0)
722                         return "bist";
723                 --index;
724         }
725
726         if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN) |
727                               (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) {
728                 if (index == 0)
729                         return "cable";
730                 --index;
731
732                 if (efx->phy_type == PHY_TYPE_SFT9001B) {
733                         if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names))
734                                 return mcdi_sft9001_cable_diag_names[index];
735                         index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names);
736                 }
737         }
738
739         return NULL;
740 }
741
742 const struct efx_phy_operations efx_mcdi_phy_ops = {
743         .probe          = efx_mcdi_phy_probe,
744         .init           = efx_port_dummy_op_int,
745         .reconfigure    = efx_mcdi_phy_reconfigure,
746         .poll           = efx_mcdi_phy_poll,
747         .fini           = efx_port_dummy_op_void,
748         .remove         = efx_mcdi_phy_remove,
749         .get_settings   = efx_mcdi_phy_get_settings,
750         .set_settings   = efx_mcdi_phy_set_settings,
751         .test_alive     = efx_mcdi_phy_test_alive,
752         .run_tests      = efx_mcdi_phy_run_tests,
753         .test_name      = efx_mcdi_phy_test_name,
754 };