blob: 0421190db7de671411d8766bdfc4045953b586ca [file] [log] [blame]
Ben Hutchings8ceee662008-04-27 12:55:59 +01001/****************************************************************************
Ben Hutchings177dfcd2008-12-12 21:50:08 -08002 * Driver for Solarflare Solarstorm network controllers and boards
3 * Copyright 2007-2008 Solarflare Communications Inc.
Ben Hutchings8ceee662008-04-27 12:55:59 +01004 *
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#include <linux/delay.h>
Herbert Xuda3bc072009-01-18 21:50:16 -080011#include <linux/rtnetlink.h>
Ben Hutchings8ceee662008-04-27 12:55:59 +010012#include <linux/seq_file.h>
13#include "efx.h"
Ben Hutchings8ceee662008-04-27 12:55:59 +010014#include "mdio_10g.h"
15#include "falcon.h"
16#include "phy.h"
17#include "falcon_hwdefs.h"
18#include "boards.h"
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080019#include "workarounds.h"
20#include "selftest.h"
Ben Hutchings8ceee662008-04-27 12:55:59 +010021
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080022/* We expect these MMDs to be in the package. SFT9001 also has a
23 * clause 22 extension MMD, but since it doesn't have all the generic
24 * MMD registers it is pointless to include it here.
25 */
Ben Hutchings68e7f452009-04-29 08:05:08 +000026#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD | \
27 MDIO_DEVS_PCS | \
28 MDIO_DEVS_PHYXS | \
29 MDIO_DEVS_AN)
Ben Hutchings8ceee662008-04-27 12:55:59 +010030
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080031#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \
32 (1 << LOOPBACK_PCS) | \
33 (1 << LOOPBACK_PMAPMD) | \
34 (1 << LOOPBACK_NETWORK))
35
36#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \
37 (1 << LOOPBACK_PHYXS) | \
38 (1 << LOOPBACK_PCS) | \
39 (1 << LOOPBACK_PMAPMD) | \
40 (1 << LOOPBACK_NETWORK))
Ben Hutchings3273c2e2008-05-07 13:36:19 +010041
Ben Hutchings8ceee662008-04-27 12:55:59 +010042/* We complain if we fail to see the link partner as 10G capable this many
43 * times in a row (must be > 1 as sampling the autoneg. registers is racy)
44 */
45#define MAX_BAD_LP_TRIES (5)
46
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080047/* LASI Control */
48#define PMA_PMD_LASI_CTRL 36866
49#define PMA_PMD_LASI_STATUS 36869
50#define PMA_PMD_LS_ALARM_LBN 0
51#define PMA_PMD_LS_ALARM_WIDTH 1
52#define PMA_PMD_TX_ALARM_LBN 1
53#define PMA_PMD_TX_ALARM_WIDTH 1
54#define PMA_PMD_RX_ALARM_LBN 2
55#define PMA_PMD_RX_ALARM_WIDTH 1
56#define PMA_PMD_AN_ALARM_LBN 3
57#define PMA_PMD_AN_ALARM_WIDTH 1
58
Ben Hutchings8ceee662008-04-27 12:55:59 +010059/* Extended control register */
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080060#define PMA_PMD_XCONTROL_REG 49152
61#define PMA_PMD_EXT_GMII_EN_LBN 1
62#define PMA_PMD_EXT_GMII_EN_WIDTH 1
63#define PMA_PMD_EXT_CLK_OUT_LBN 2
64#define PMA_PMD_EXT_CLK_OUT_WIDTH 1
65#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 /* SFX7101 only */
66#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
67#define PMA_PMD_EXT_CLK312_LBN 8 /* SFT9001 only */
68#define PMA_PMD_EXT_CLK312_WIDTH 1
69#define PMA_PMD_EXT_LPOWER_LBN 12
70#define PMA_PMD_EXT_LPOWER_WIDTH 1
Steve Hodgson869b5b32009-01-29 17:48:10 +000071#define PMA_PMD_EXT_ROBUST_LBN 14
72#define PMA_PMD_EXT_ROBUST_WIDTH 1
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080073#define PMA_PMD_EXT_SSR_LBN 15
74#define PMA_PMD_EXT_SSR_WIDTH 1
Ben Hutchings8ceee662008-04-27 12:55:59 +010075
76/* extended status register */
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080077#define PMA_PMD_XSTATUS_REG 49153
Ben Hutchings8ceee662008-04-27 12:55:59 +010078#define PMA_PMD_XSTAT_FLP_LBN (12)
79
80/* LED control register */
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080081#define PMA_PMD_LED_CTRL_REG 49159
Ben Hutchings8ceee662008-04-27 12:55:59 +010082#define PMA_PMA_LED_ACTIVITY_LBN (3)
83
84/* LED function override register */
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -080085#define PMA_PMD_LED_OVERR_REG 49161
Ben Hutchings8ceee662008-04-27 12:55:59 +010086/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
87#define PMA_PMD_LED_LINK_LBN (0)
88#define PMA_PMD_LED_SPEED_LBN (2)
89#define PMA_PMD_LED_TX_LBN (4)
90#define PMA_PMD_LED_RX_LBN (6)
91/* Override settings */
92#define PMA_PMD_LED_AUTO (0) /* H/W control */
93#define PMA_PMD_LED_ON (1)
94#define PMA_PMD_LED_OFF (2)
95#define PMA_PMD_LED_FLASH (3)
Ben Hutchings04cc8ca2008-12-12 21:50:46 -080096#define PMA_PMD_LED_MASK 3
Ben Hutchings8ceee662008-04-27 12:55:59 +010097/* All LEDs under hardware control */
98#define PMA_PMD_LED_FULL_AUTO (0)
99/* Green and Amber under hardware control, Red off */
100#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
101
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800102#define PMA_PMD_SPEED_ENABLE_REG 49192
103#define PMA_PMD_100TX_ADV_LBN 1
104#define PMA_PMD_100TX_ADV_WIDTH 1
105#define PMA_PMD_1000T_ADV_LBN 2
106#define PMA_PMD_1000T_ADV_WIDTH 1
107#define PMA_PMD_10000T_ADV_LBN 3
108#define PMA_PMD_10000T_ADV_WIDTH 1
109#define PMA_PMD_SPEED_LBN 4
110#define PMA_PMD_SPEED_WIDTH 4
Ben Hutchings8ceee662008-04-27 12:55:59 +0100111
Ben Hutchings307505e2008-12-26 13:48:00 -0800112/* Cable diagnostics - SFT9001 only */
113#define PMA_PMD_CDIAG_CTRL_REG 49213
114#define CDIAG_CTRL_IMMED_LBN 15
115#define CDIAG_CTRL_BRK_LINK_LBN 12
116#define CDIAG_CTRL_IN_PROG_LBN 11
117#define CDIAG_CTRL_LEN_UNIT_LBN 10
118#define CDIAG_CTRL_LEN_METRES 1
119#define PMA_PMD_CDIAG_RES_REG 49174
120#define CDIAG_RES_A_LBN 12
121#define CDIAG_RES_B_LBN 8
122#define CDIAG_RES_C_LBN 4
123#define CDIAG_RES_D_LBN 0
124#define CDIAG_RES_WIDTH 4
125#define CDIAG_RES_OPEN 2
126#define CDIAG_RES_OK 1
127#define CDIAG_RES_INVALID 0
128/* Set of 4 registers for pairs A-D */
129#define PMA_PMD_CDIAG_LEN_REG 49175
130
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800131/* Serdes control registers - SFT9001 only */
132#define PMA_PMD_CSERDES_CTRL_REG 64258
133/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */
134#define PMA_PMD_CSERDES_DEFAULT 0x000f
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100135
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800136/* Misc register defines - SFX7101 only */
137#define PCS_CLOCK_CTRL_REG 55297
Ben Hutchings8ceee662008-04-27 12:55:59 +0100138#define PLL312_RST_N_LBN 2
139
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800140#define PCS_SOFT_RST2_REG 55302
Ben Hutchings8ceee662008-04-27 12:55:59 +0100141#define SERDES_RST_N_LBN 13
142#define XGXS_RST_N_LBN 12
143
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800144#define PCS_TEST_SELECT_REG 55303 /* PRM 10.5.8 */
Ben Hutchings8ceee662008-04-27 12:55:59 +0100145#define CLK312_EN_LBN 3
146
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100147/* PHYXS registers */
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800148#define PHYXS_XCONTROL_REG 49152
149#define PHYXS_RESET_LBN 15
150#define PHYXS_RESET_WIDTH 1
151
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100152#define PHYXS_TEST1 (49162)
153#define LOOPBACK_NEAR_LBN (8)
154#define LOOPBACK_NEAR_WIDTH (1)
155
Ben Hutchings8ceee662008-04-27 12:55:59 +0100156/* Boot status register */
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000157#define PCS_BOOT_STATUS_REG 53248
158#define PCS_BOOT_FATAL_ERROR_LBN 0
159#define PCS_BOOT_PROGRESS_LBN 1
160#define PCS_BOOT_PROGRESS_WIDTH 2
161#define PCS_BOOT_PROGRESS_INIT 0
162#define PCS_BOOT_PROGRESS_WAIT_MDIO 1
163#define PCS_BOOT_PROGRESS_CHECKSUM 2
164#define PCS_BOOT_PROGRESS_JUMP 3
165#define PCS_BOOT_DOWNLOAD_WAIT_LBN 3
166#define PCS_BOOT_CODE_STARTED_LBN 4
Ben Hutchings8ceee662008-04-27 12:55:59 +0100167
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800168/* 100M/1G PHY registers */
169#define GPHY_XCONTROL_REG 49152
170#define GPHY_ISOLATE_LBN 10
171#define GPHY_ISOLATE_WIDTH 1
172#define GPHY_DUPLEX_LBN 8
173#define GPHY_DUPLEX_WIDTH 1
174#define GPHY_LOOPBACK_NEAR_LBN 14
175#define GPHY_LOOPBACK_NEAR_WIDTH 1
176
177#define C22EXT_STATUS_REG 49153
178#define C22EXT_STATUS_LINK_LBN 2
179#define C22EXT_STATUS_LINK_WIDTH 1
180
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000181#define C22EXT_MSTSLV_CTRL 49161
182#define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN 8
183#define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN 9
184
185#define C22EXT_MSTSLV_STATUS 49162
186#define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN 10
187#define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN 11
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800188
Ben Hutchings8ceee662008-04-27 12:55:59 +0100189/* Time to wait between powering down the LNPGA and turning off the power
190 * rails */
191#define LNPGA_PDOWN_WAIT (HZ / 5)
192
Ben Hutchings8ceee662008-04-27 12:55:59 +0100193struct tenxpress_phy_data {
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100194 enum efx_loopback_mode loopback_mode;
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100195 enum efx_phy_mode phy_mode;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100196 int bad_lp_tries;
197};
198
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800199static ssize_t show_phy_short_reach(struct device *dev,
200 struct device_attribute *attr, char *buf)
201{
202 struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
203 int reg;
204
Ben Hutchings68e7f452009-04-29 08:05:08 +0000205 reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR);
206 return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT));
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800207}
208
209static ssize_t set_phy_short_reach(struct device *dev,
210 struct device_attribute *attr,
211 const char *buf, size_t count)
212{
213 struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
214
215 rtnl_lock();
Ben Hutchings68e7f452009-04-29 08:05:08 +0000216 efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
217 MDIO_PMA_10GBT_TXPWR_SHORT,
218 count != 0 && *buf != '0');
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800219 efx_reconfigure_port(efx);
220 rtnl_unlock();
221
222 return count;
223}
224
225static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
226 set_phy_short_reach);
227
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000228int sft9001_wait_boot(struct efx_nic *efx)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100229{
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000230 unsigned long timeout = jiffies + HZ + 1;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100231 int boot_stat;
232
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000233 for (;;) {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000234 boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
235 PCS_BOOT_STATUS_REG);
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000236 if (boot_stat >= 0) {
237 EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
238 switch (boot_stat &
239 ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
240 (3 << PCS_BOOT_PROGRESS_LBN) |
241 (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
242 (1 << PCS_BOOT_CODE_STARTED_LBN))) {
243 case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
244 (PCS_BOOT_PROGRESS_CHECKSUM <<
245 PCS_BOOT_PROGRESS_LBN)):
246 case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
247 (PCS_BOOT_PROGRESS_INIT <<
248 PCS_BOOT_PROGRESS_LBN) |
249 (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
250 return -EINVAL;
251 case ((PCS_BOOT_PROGRESS_WAIT_MDIO <<
252 PCS_BOOT_PROGRESS_LBN) |
253 (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
254 return (efx->phy_mode & PHY_MODE_SPECIAL) ?
255 0 : -EIO;
256 case ((PCS_BOOT_PROGRESS_JUMP <<
257 PCS_BOOT_PROGRESS_LBN) |
258 (1 << PCS_BOOT_CODE_STARTED_LBN)):
259 case ((PCS_BOOT_PROGRESS_JUMP <<
260 PCS_BOOT_PROGRESS_LBN) |
261 (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
262 (1 << PCS_BOOT_CODE_STARTED_LBN)):
263 return (efx->phy_mode & PHY_MODE_SPECIAL) ?
264 -EIO : 0;
265 default:
266 if (boot_stat & (1 << PCS_BOOT_FATAL_ERROR_LBN))
267 return -EIO;
268 break;
269 }
270 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100271
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000272 if (time_after_eq(jiffies, timeout))
273 return -ETIMEDOUT;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100274
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000275 msleep(50);
276 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100277}
278
Ben Hutchings8ceee662008-04-27 12:55:59 +0100279static int tenxpress_init(struct efx_nic *efx)
280{
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800281 int reg;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100282
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800283 if (efx->phy_type == PHY_TYPE_SFX7101) {
284 /* Enable 312.5 MHz clock */
Ben Hutchings68e7f452009-04-29 08:05:08 +0000285 efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
286 1 << CLK312_EN_LBN);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800287 } else {
288 /* Enable 312.5 MHz clock and GMII */
Ben Hutchings68e7f452009-04-29 08:05:08 +0000289 reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800290 reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) |
291 (1 << PMA_PMD_EXT_CLK_OUT_LBN) |
Steve Hodgson869b5b32009-01-29 17:48:10 +0000292 (1 << PMA_PMD_EXT_CLK312_LBN) |
293 (1 << PMA_PMD_EXT_ROBUST_LBN));
294
Ben Hutchings68e7f452009-04-29 08:05:08 +0000295 efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
296 efx_mdio_set_flag(efx, MDIO_MMD_C22EXT,
297 GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN,
298 false);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800299 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100300
Ben Hutchings8ceee662008-04-27 12:55:59 +0100301 /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800302 if (efx->phy_type == PHY_TYPE_SFX7101) {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000303 efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
304 1 << PMA_PMA_LED_ACTIVITY_LBN, true);
305 efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
306 PMA_PMD_LED_DEFAULT);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800307 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100308
Ben Hutchings190dbcf2009-02-27 13:06:45 +0000309 return 0;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100310}
311
312static int tenxpress_phy_init(struct efx_nic *efx)
313{
314 struct tenxpress_phy_data *phy_data;
315 int rc = 0;
316
317 phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
Ben Hutchings9b7bfc42008-05-16 21:20:20 +0100318 if (!phy_data)
319 return -ENOMEM;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100320 efx->phy_data = phy_data;
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100321 phy_data->phy_mode = efx->phy_mode;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100322
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800323 if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
324 if (efx->phy_type == PHY_TYPE_SFT9001A) {
325 int reg;
Ben Hutchings68e7f452009-04-29 08:05:08 +0000326 reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
327 PMA_PMD_XCONTROL_REG);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800328 reg |= (1 << PMA_PMD_EXT_SSR_LBN);
Ben Hutchings68e7f452009-04-29 08:05:08 +0000329 efx_mdio_write(efx, MDIO_MMD_PMAPMD,
330 PMA_PMD_XCONTROL_REG, reg);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800331 mdelay(200);
332 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100333
Ben Hutchings68e7f452009-04-29 08:05:08 +0000334 rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800335 if (rc < 0)
336 goto fail;
337
Ben Hutchings68e7f452009-04-29 08:05:08 +0000338 rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800339 if (rc < 0)
340 goto fail;
341 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100342
343 rc = tenxpress_init(efx);
344 if (rc < 0)
345 goto fail;
346
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800347 if (efx->phy_type == PHY_TYPE_SFT9001B) {
348 rc = device_create_file(&efx->pci_dev->dev,
349 &dev_attr_phy_short_reach);
350 if (rc)
351 goto fail;
352 }
353
Ben Hutchings8ceee662008-04-27 12:55:59 +0100354 schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
355
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800356 /* Let XGXS and SerDes out of reset */
Ben Hutchings8ceee662008-04-27 12:55:59 +0100357 falcon_reset_xaui(efx);
358
359 return 0;
360
361 fail:
362 kfree(efx->phy_data);
363 efx->phy_data = NULL;
364 return rc;
365}
366
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800367/* Perform a "special software reset" on the PHY. The caller is
368 * responsible for saving and restoring the PHY hardware registers
369 * properly, and masking/unmasking LASI */
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100370static int tenxpress_special_reset(struct efx_nic *efx)
371{
372 int rc, reg;
373
Ben Hutchingsc8fcc492008-09-01 12:49:25 +0100374 /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
375 * a special software reset can glitch the XGMAC sufficiently for stats
Ben Hutchings1974cc22009-01-29 18:00:07 +0000376 * requests to fail. */
377 efx_stats_disable(efx);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100378
379 /* Initiate reset */
Ben Hutchings68e7f452009-04-29 08:05:08 +0000380 reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100381 reg |= (1 << PMA_PMD_EXT_SSR_LBN);
Ben Hutchings68e7f452009-04-29 08:05:08 +0000382 efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100383
Ben Hutchingsc8fcc492008-09-01 12:49:25 +0100384 mdelay(200);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100385
386 /* Wait for the blocks to come out of reset */
Ben Hutchings68e7f452009-04-29 08:05:08 +0000387 rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100388 if (rc < 0)
Ben Hutchings1974cc22009-01-29 18:00:07 +0000389 goto out;
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100390
391 /* Try and reconfigure the device */
392 rc = tenxpress_init(efx);
393 if (rc < 0)
Ben Hutchings1974cc22009-01-29 18:00:07 +0000394 goto out;
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100395
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800396 /* Wait for the XGXS state machine to churn */
397 mdelay(10);
Ben Hutchings1974cc22009-01-29 18:00:07 +0000398out:
399 efx_stats_enable(efx);
Ben Hutchingsc8fcc492008-09-01 12:49:25 +0100400 return rc;
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100401}
402
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800403static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100404{
405 struct tenxpress_phy_data *pd = efx->phy_data;
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800406 bool bad_lp;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100407 int reg;
408
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800409 if (link_ok) {
410 bad_lp = false;
411 } else {
412 /* Check that AN has started but not completed. */
Ben Hutchings68e7f452009-04-29 08:05:08 +0000413 reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);
414 if (!(reg & MDIO_AN_STAT1_LPABLE))
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800415 return; /* LP status is unknown */
Ben Hutchings68e7f452009-04-29 08:05:08 +0000416 bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE);
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800417 if (bad_lp)
418 pd->bad_lp_tries++;
419 }
420
Ben Hutchings8ceee662008-04-27 12:55:59 +0100421 /* Nothing to do if all is well and was previously so. */
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800422 if (!pd->bad_lp_tries)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100423 return;
424
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800425 /* Use the RX (red) LED as an error indicator once we've seen AN
426 * failure several times in a row, and also log a message. */
427 if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000428 reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
429 PMA_PMD_LED_OVERR_REG);
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800430 reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
431 if (!bad_lp) {
432 reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
433 } else {
434 reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;
435 EFX_ERR(efx, "appears to be plugged into a port"
436 " that is not 10GBASE-T capable. The PHY"
437 " supports 10GBASE-T ONLY, so no link can"
438 " be established\n");
439 }
Ben Hutchings68e7f452009-04-29 08:05:08 +0000440 efx_mdio_write(efx, MDIO_MMD_PMAPMD,
441 PMA_PMD_LED_OVERR_REG, reg);
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800442 pd->bad_lp_tries = bad_lp;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100443 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100444}
445
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800446static bool sfx7101_link_ok(struct efx_nic *efx)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100447{
Ben Hutchings68e7f452009-04-29 08:05:08 +0000448 return efx_mdio_links_ok(efx,
449 MDIO_DEVS_PMAPMD |
450 MDIO_DEVS_PCS |
451 MDIO_DEVS_PHYXS);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800452}
453
454static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
455{
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800456 u32 reg;
457
Ben Hutchingscaa8d8b2008-12-26 13:46:12 -0800458 if (efx_phy_mode_disabled(efx->phy_mode))
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800459 return false;
Ben Hutchingscaa8d8b2008-12-26 13:46:12 -0800460 else if (efx->loopback_mode == LOOPBACK_GPHY)
461 return true;
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800462 else if (efx->loopback_mode)
Ben Hutchings68e7f452009-04-29 08:05:08 +0000463 return efx_mdio_links_ok(efx,
464 MDIO_DEVS_PMAPMD |
465 MDIO_DEVS_PHYXS);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800466
467 /* We must use the same definition of link state as LASI,
468 * otherwise we can miss a link state transition
469 */
470 if (ecmd->speed == 10000) {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000471 reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
472 return reg & MDIO_PCS_10GBRT_STAT1_BLKLK;
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800473 } else {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000474 reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800475 return reg & (1 << C22EXT_STATUS_LINK_LBN);
476 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100477}
478
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800479static void tenxpress_ext_loopback(struct efx_nic *efx)
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100480{
Ben Hutchings68e7f452009-04-29 08:05:08 +0000481 efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
482 1 << LOOPBACK_NEAR_LBN,
483 efx->loopback_mode == LOOPBACK_PHYXS);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800484 if (efx->phy_type != PHY_TYPE_SFX7101)
Ben Hutchings68e7f452009-04-29 08:05:08 +0000485 efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG,
486 1 << GPHY_LOOPBACK_NEAR_LBN,
487 efx->loopback_mode == LOOPBACK_GPHY);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800488}
489
490static void tenxpress_low_power(struct efx_nic *efx)
491{
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800492 if (efx->phy_type == PHY_TYPE_SFX7101)
Ben Hutchings68e7f452009-04-29 08:05:08 +0000493 efx_mdio_set_mmds_lpower(
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800494 efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
495 TENXPRESS_REQUIRED_DEVS);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100496 else
Ben Hutchings68e7f452009-04-29 08:05:08 +0000497 efx_mdio_set_flag(
498 efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG,
499 1 << PMA_PMD_EXT_LPOWER_LBN,
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800500 !!(efx->phy_mode & PHY_MODE_LOW_POWER));
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100501}
502
Ben Hutchings8ceee662008-04-27 12:55:59 +0100503static void tenxpress_phy_reconfigure(struct efx_nic *efx)
504{
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100505 struct tenxpress_phy_data *phy_data = efx->phy_data;
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800506 struct ethtool_cmd ecmd;
Steve Hodgson8b9dc8d2009-01-29 17:49:09 +0000507 bool phy_mode_change, loop_reset;
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100508
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800509 if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100510 phy_data->phy_mode = efx->phy_mode;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100511 return;
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100512 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100513
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800514 tenxpress_low_power(efx);
515
516 phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
517 phy_data->phy_mode != PHY_MODE_NORMAL);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800518 loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
519 LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
520
Steve Hodgson8b9dc8d2009-01-29 17:49:09 +0000521 if (loop_reset || phy_mode_change) {
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800522 int rc;
523
524 efx->phy_op->get_settings(efx, &ecmd);
525
526 if (loop_reset || phy_mode_change) {
527 tenxpress_special_reset(efx);
528
529 /* Reset XAUI if we were in 10G, and are staying
530 * in 10G. If we're moving into and out of 10G
531 * then xaui will be reset anyway */
532 if (EFX_IS10G(efx))
533 falcon_reset_xaui(efx);
534 }
535
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800536 rc = efx->phy_op->set_settings(efx, &ecmd);
537 WARN_ON(rc);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100538 }
539
Ben Hutchings68e7f452009-04-29 08:05:08 +0000540 efx_mdio_transmit_disable(efx);
541 efx_mdio_phy_reconfigure(efx);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800542 tenxpress_ext_loopback(efx);
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100543
Ben Hutchings3273c2e2008-05-07 13:36:19 +0100544 phy_data->loopback_mode = efx->loopback_mode;
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100545 phy_data->phy_mode = efx->phy_mode;
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800546
547 if (efx->phy_type == PHY_TYPE_SFX7101) {
548 efx->link_speed = 10000;
549 efx->link_fd = true;
550 efx->link_up = sfx7101_link_ok(efx);
551 } else {
552 efx->phy_op->get_settings(efx, &ecmd);
553 efx->link_speed = ecmd.speed;
554 efx->link_fd = ecmd.duplex == DUPLEX_FULL;
555 efx->link_up = sft9001_link_ok(efx, &ecmd);
556 }
Ben Hutchings68e7f452009-04-29 08:05:08 +0000557 efx->link_fc = efx_mdio_get_pause(efx);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100558}
559
Ben Hutchings8ceee662008-04-27 12:55:59 +0100560/* Poll PHY for interrupt */
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800561static void tenxpress_phy_poll(struct efx_nic *efx)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100562{
563 struct tenxpress_phy_data *phy_data = efx->phy_data;
Hannes Eder37d37692009-02-14 11:41:03 +0000564 bool change = false;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100565
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800566 if (efx->phy_type == PHY_TYPE_SFX7101) {
Hannes Eder37d37692009-02-14 11:41:03 +0000567 bool link_ok = sfx7101_link_ok(efx);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800568 if (link_ok != efx->link_up) {
569 change = true;
570 } else {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000571 unsigned int link_fc = efx_mdio_get_pause(efx);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800572 if (link_fc != efx->link_fc)
573 change = true;
574 }
575 sfx7101_check_bad_lp(efx, link_ok);
Ben Hutchingscaa8d8b2008-12-26 13:46:12 -0800576 } else if (efx->loopback_mode) {
577 bool link_ok = sft9001_link_ok(efx, NULL);
578 if (link_ok != efx->link_up)
579 change = true;
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800580 } else {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000581 int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
582 PMA_PMD_LASI_STATUS);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800583 if (status & (1 << PMA_PMD_LS_ALARM_LBN))
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800584 change = true;
585 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100586
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800587 if (change)
Ben Hutchings177dfcd2008-12-12 21:50:08 -0800588 falcon_sim_phy_event(efx);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100589
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100590 if (phy_data->phy_mode != PHY_MODE_NORMAL)
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800591 return;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100592}
593
594static void tenxpress_phy_fini(struct efx_nic *efx)
595{
596 int reg;
597
Ben Hutchings2a7e6372009-01-11 00:18:13 -0800598 if (efx->phy_type == PHY_TYPE_SFT9001B)
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800599 device_remove_file(&efx->pci_dev->dev,
600 &dev_attr_phy_short_reach);
Ben Hutchings2a7e6372009-01-11 00:18:13 -0800601
602 if (efx->phy_type == PHY_TYPE_SFX7101) {
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800603 /* Power down the LNPGA */
604 reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
Ben Hutchings68e7f452009-04-29 08:05:08 +0000605 efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100606
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800607 /* Waiting here ensures that the board fini, which can turn
608 * off the power to the PHY, won't get run until the LNPGA
609 * powerdown has been given long enough to complete. */
610 schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
611 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100612
613 kfree(efx->phy_data);
614 efx->phy_data = NULL;
615}
616
617
618/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
619 * (which probably aren't wired anyway) are left in AUTO mode */
Ben Hutchingsdc8cfa52008-09-01 12:46:50 +0100620void tenxpress_phy_blink(struct efx_nic *efx, bool blink)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100621{
622 int reg;
623
624 if (blink)
625 reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
626 (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
627 (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
628 else
629 reg = PMA_PMD_LED_DEFAULT;
630
Ben Hutchings68e7f452009-04-29 08:05:08 +0000631 efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100632}
633
Ben Hutchings307505e2008-12-26 13:48:00 -0800634static const char *const sfx7101_test_names[] = {
Ben Hutchings17967212008-12-26 13:47:25 -0800635 "bist"
636};
637
638static int
Ben Hutchings307505e2008-12-26 13:48:00 -0800639sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
Ben Hutchings8c8661e2008-09-01 12:49:02 +0100640{
Ben Hutchings17967212008-12-26 13:47:25 -0800641 int rc;
642
643 if (!(flags & ETH_TEST_FL_OFFLINE))
644 return 0;
645
Ben Hutchings8c8661e2008-09-01 12:49:02 +0100646 /* BIST is automatically run after a special software reset */
Ben Hutchings17967212008-12-26 13:47:25 -0800647 rc = tenxpress_special_reset(efx);
648 results[0] = rc ? -1 : 1;
649 return rc;
Ben Hutchings8c8661e2008-09-01 12:49:02 +0100650}
651
Ben Hutchings307505e2008-12-26 13:48:00 -0800652static const char *const sft9001_test_names[] = {
653 "bist",
654 "cable.pairA.status",
655 "cable.pairB.status",
656 "cable.pairC.status",
657 "cable.pairD.status",
658 "cable.pairA.length",
659 "cable.pairB.length",
660 "cable.pairC.length",
661 "cable.pairD.length",
662};
663
664static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
665{
666 struct ethtool_cmd ecmd;
Ben Hutchings22ef02c2009-02-27 13:04:07 +0000667 int rc = 0, rc2, i, ctrl_reg, res_reg;
Ben Hutchings307505e2008-12-26 13:48:00 -0800668
Ben Hutchings22ef02c2009-02-27 13:04:07 +0000669 if (flags & ETH_TEST_FL_OFFLINE)
670 efx->phy_op->get_settings(efx, &ecmd);
Ben Hutchings307505e2008-12-26 13:48:00 -0800671
672 /* Initialise cable diagnostic results to unknown failure */
673 for (i = 1; i < 9; ++i)
674 results[i] = -1;
675
676 /* Run cable diagnostics; wait up to 5 seconds for them to complete.
677 * A cable fault is not a self-test failure, but a timeout is. */
Ben Hutchings22ef02c2009-02-27 13:04:07 +0000678 ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) |
679 (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
680 if (flags & ETH_TEST_FL_OFFLINE) {
681 /* Break the link in order to run full diagnostics. We
682 * must reset the PHY to resume normal service. */
683 ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN);
684 }
Ben Hutchings68e7f452009-04-29 08:05:08 +0000685 efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG,
686 ctrl_reg);
Ben Hutchings307505e2008-12-26 13:48:00 -0800687 i = 0;
Ben Hutchings68e7f452009-04-29 08:05:08 +0000688 while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) &
Ben Hutchings307505e2008-12-26 13:48:00 -0800689 (1 << CDIAG_CTRL_IN_PROG_LBN)) {
690 if (++i == 50) {
691 rc = -ETIMEDOUT;
Ben Hutchings22ef02c2009-02-27 13:04:07 +0000692 goto out;
Ben Hutchings307505e2008-12-26 13:48:00 -0800693 }
694 msleep(100);
695 }
Ben Hutchings68e7f452009-04-29 08:05:08 +0000696 res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG);
Ben Hutchings307505e2008-12-26 13:48:00 -0800697 for (i = 0; i < 4; i++) {
698 int pair_res =
699 (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH))
700 & ((1 << CDIAG_RES_WIDTH) - 1);
Ben Hutchings68e7f452009-04-29 08:05:08 +0000701 int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
702 PMA_PMD_CDIAG_LEN_REG + i);
Ben Hutchings307505e2008-12-26 13:48:00 -0800703 if (pair_res == CDIAG_RES_OK)
704 results[1 + i] = 1;
705 else if (pair_res == CDIAG_RES_INVALID)
706 results[1 + i] = -1;
707 else
708 results[1 + i] = -pair_res;
709 if (pair_res != CDIAG_RES_INVALID &&
710 pair_res != CDIAG_RES_OPEN &&
711 len_reg != 0xffff)
712 results[5 + i] = len_reg;
713 }
714
Ben Hutchings22ef02c2009-02-27 13:04:07 +0000715out:
716 if (flags & ETH_TEST_FL_OFFLINE) {
717 /* Reset, running the BIST and then resuming normal service. */
718 rc2 = tenxpress_special_reset(efx);
719 results[0] = rc2 ? -1 : 1;
720 if (!rc)
721 rc = rc2;
Ben Hutchings307505e2008-12-26 13:48:00 -0800722
Ben Hutchings22ef02c2009-02-27 13:04:07 +0000723 rc2 = efx->phy_op->set_settings(efx, &ecmd);
724 if (!rc)
725 rc = rc2;
726 }
Ben Hutchings307505e2008-12-26 13:48:00 -0800727
728 return rc;
729}
730
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000731static void
732tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800733{
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000734 u32 adv = 0, lpa = 0;
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800735 int reg;
736
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800737 if (efx->phy_type != PHY_TYPE_SFX7101) {
Ben Hutchings68e7f452009-04-29 08:05:08 +0000738 reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL);
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000739 if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN))
740 adv |= ADVERTISED_1000baseT_Full;
Ben Hutchings68e7f452009-04-29 08:05:08 +0000741 reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS);
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000742 if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN))
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800743 lpa |= ADVERTISED_1000baseT_Half;
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000744 if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN))
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800745 lpa |= ADVERTISED_1000baseT_Full;
746 }
Ben Hutchings68e7f452009-04-29 08:05:08 +0000747 reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
748 if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000749 adv |= ADVERTISED_10000baseT_Full;
Ben Hutchings68e7f452009-04-29 08:05:08 +0000750 reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
751 if (reg & MDIO_AN_10GBT_STAT_LP10G)
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800752 lpa |= ADVERTISED_10000baseT_Full;
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800753
Ben Hutchings68e7f452009-04-29 08:05:08 +0000754 mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
Ben Hutchings04cc8ca2008-12-12 21:50:46 -0800755
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000756 if (efx->phy_type != PHY_TYPE_SFX7101)
757 ecmd->supported |= (SUPPORTED_100baseT_Full |
758 SUPPORTED_1000baseT_Full);
Steve Hodgson8b9dc8d2009-01-29 17:49:09 +0000759
760 /* In loopback, the PHY automatically brings up the correct interface,
761 * but doesn't advertise the correct speed. So override it */
762 if (efx->loopback_mode == LOOPBACK_GPHY)
763 ecmd->speed = SPEED_1000;
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000764 else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)
Steve Hodgson8b9dc8d2009-01-29 17:49:09 +0000765 ecmd->speed = SPEED_10000;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100766}
767
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000768static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100769{
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000770 if (!ecmd->autoneg)
771 return -EINVAL;
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800772
Ben Hutchings68e7f452009-04-29 08:05:08 +0000773 return efx_mdio_set_settings(efx, ecmd);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100774}
775
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000776static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising)
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800777{
Ben Hutchings68e7f452009-04-29 08:05:08 +0000778 efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
779 MDIO_AN_10GBT_CTRL_ADV10G,
780 advertising & ADVERTISED_10000baseT_Full);
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000781}
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800782
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000783static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800784{
Ben Hutchings68e7f452009-04-29 08:05:08 +0000785 efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL,
786 1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN,
787 advertising & ADVERTISED_1000baseT_Full);
788 efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
789 MDIO_AN_10GBT_CTRL_ADV10G,
790 advertising & ADVERTISED_10000baseT_Full);
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800791}
792
793struct efx_phy_operations falcon_sfx7101_phy_ops = {
Ben Hutchings177dfcd2008-12-12 21:50:08 -0800794 .macs = EFX_XMAC,
Ben Hutchings8ceee662008-04-27 12:55:59 +0100795 .init = tenxpress_phy_init,
796 .reconfigure = tenxpress_phy_reconfigure,
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800797 .poll = tenxpress_phy_poll,
Ben Hutchings8ceee662008-04-27 12:55:59 +0100798 .fini = tenxpress_phy_fini,
Ben Hutchings766ca0f2008-12-12 21:59:24 -0800799 .clear_interrupt = efx_port_dummy_op_void,
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000800 .get_settings = tenxpress_get_settings,
801 .set_settings = tenxpress_set_settings,
802 .set_npage_adv = sfx7101_set_npage_adv,
Ben Hutchings307505e2008-12-26 13:48:00 -0800803 .num_tests = ARRAY_SIZE(sfx7101_test_names),
804 .test_names = sfx7101_test_names,
805 .run_tests = sfx7101_run_tests,
Ben Hutchings8ceee662008-04-27 12:55:59 +0100806 .mmds = TENXPRESS_REQUIRED_DEVS,
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800807 .loopbacks = SFX7101_LOOPBACKS,
808};
809
810struct efx_phy_operations falcon_sft9001_phy_ops = {
811 .macs = EFX_GMAC | EFX_XMAC,
812 .init = tenxpress_phy_init,
813 .reconfigure = tenxpress_phy_reconfigure,
814 .poll = tenxpress_phy_poll,
815 .fini = tenxpress_phy_fini,
816 .clear_interrupt = efx_port_dummy_op_void,
Ben Hutchingsaf4ad9b2009-01-29 17:59:37 +0000817 .get_settings = tenxpress_get_settings,
818 .set_settings = tenxpress_set_settings,
819 .set_npage_adv = sft9001_set_npage_adv,
Ben Hutchings307505e2008-12-26 13:48:00 -0800820 .num_tests = ARRAY_SIZE(sft9001_test_names),
821 .test_names = sft9001_test_names,
822 .run_tests = sft9001_run_tests,
Ben Hutchingse6fa2eb2008-12-12 22:00:17 -0800823 .mmds = TENXPRESS_REQUIRED_DEVS,
824 .loopbacks = SFT9001_LOOPBACKS,
Ben Hutchings8ceee662008-04-27 12:55:59 +0100825};