diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-09-01 07:48:17 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-09-03 09:53:47 -0400 |
commit | f8b87c17017f2ce1890fb9a7f85fb0fbf5643e37 (patch) | |
tree | 261a31a95d2fa296ef7abaf6019ff5b7c86bbc63 /drivers | |
parent | 3594e131b23665b728b4c98daaf0b61b1d4aaa7a (diff) |
sfc: Make PHY flash mode a device attribute, not a module parameter
This allows updating PHY firmware for one interface without removing
all other interfaces handled by the driver.
Replace tx_disabled flags and 10Xpress status enumeration with flags in
enum efx_phy_mode.
Prevent an interface from being brought up while in PHY flash mode.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sfc/boards.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/efx.c | 3 | ||||
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 15 | ||||
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 4 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 21 | ||||
-rw-r--r-- | drivers/net/sfc/phy.h | 8 | ||||
-rw-r--r-- | drivers/net/sfc/sfe4001.c | 186 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 46 | ||||
-rw-r--r-- | drivers/net/sfc/xfp_phy.c | 9 |
9 files changed, 171 insertions, 123 deletions
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h index e5e844359ce7..c6e01b64bfb4 100644 --- a/drivers/net/sfc/boards.h +++ b/drivers/net/sfc/boards.h | |||
@@ -21,7 +21,5 @@ enum efx_board_type { | |||
21 | 21 | ||
22 | extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); | 22 | extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); |
23 | extern int sfe4001_init(struct efx_nic *efx); | 23 | extern int sfe4001_init(struct efx_nic *efx); |
24 | /* Are we putting the PHY into flash config mode */ | ||
25 | extern unsigned int sfe4001_phy_flash_cfg; | ||
26 | 24 | ||
27 | #endif | 25 | #endif |
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 864095ea5b37..d41a6e34da7d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -1296,6 +1296,9 @@ static int efx_net_open(struct net_device *net_dev) | |||
1296 | EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name, | 1296 | EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name, |
1297 | raw_smp_processor_id()); | 1297 | raw_smp_processor_id()); |
1298 | 1298 | ||
1299 | if (efx->phy_mode & PHY_MODE_SPECIAL) | ||
1300 | return -EBUSY; | ||
1301 | |||
1299 | efx_start_all(efx); | 1302 | efx_start_all(efx); |
1300 | return 0; | 1303 | return 0; |
1301 | } | 1304 | } |
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index be5a86f0e5cf..5620d9d13925 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c | |||
@@ -69,10 +69,6 @@ static int falcon_reset_xmac(struct efx_nic *efx) | |||
69 | udelay(10); | 69 | udelay(10); |
70 | } | 70 | } |
71 | 71 | ||
72 | /* This often fails when DSP is disabled, ignore it */ | ||
73 | if (sfe4001_phy_flash_cfg) | ||
74 | return 0; | ||
75 | |||
76 | EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); | 72 | EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); |
77 | return -ETIMEDOUT; | 73 | return -ETIMEDOUT; |
78 | } | 74 | } |
@@ -444,7 +440,8 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx) | |||
444 | max_tries = tries; | 440 | max_tries = tries; |
445 | 441 | ||
446 | if ((efx->loopback_mode == LOOPBACK_NETWORK) || | 442 | if ((efx->loopback_mode == LOOPBACK_NETWORK) || |
447 | (efx->phy_type == PHY_TYPE_NONE)) | 443 | (efx->phy_type == PHY_TYPE_NONE) || |
444 | efx_phy_mode_disabled(efx->phy_mode)) | ||
448 | return false; | 445 | return false; |
449 | 446 | ||
450 | while (tries) { | 447 | while (tries) { |
@@ -471,7 +468,11 @@ void falcon_reconfigure_xmac(struct efx_nic *efx) | |||
471 | 468 | ||
472 | falcon_deconfigure_mac_wrapper(efx); | 469 | falcon_deconfigure_mac_wrapper(efx); |
473 | 470 | ||
474 | efx->tx_disabled = LOOPBACK_INTERNAL(efx); | 471 | /* Reconfigure the PHY, disabling transmit in mac level loopback. */ |
472 | if (LOOPBACK_INTERNAL(efx)) | ||
473 | efx->phy_mode |= PHY_MODE_TX_DISABLED; | ||
474 | else | ||
475 | efx->phy_mode &= ~PHY_MODE_TX_DISABLED; | ||
475 | efx->phy_op->reconfigure(efx); | 476 | efx->phy_op->reconfigure(efx); |
476 | 477 | ||
477 | falcon_reconfigure_xgxs_core(efx); | 478 | falcon_reconfigure_xgxs_core(efx); |
@@ -566,7 +567,7 @@ int falcon_check_xmac(struct efx_nic *efx) | |||
566 | int rc; | 567 | int rc; |
567 | 568 | ||
568 | if ((efx->loopback_mode == LOOPBACK_NETWORK) || | 569 | if ((efx->loopback_mode == LOOPBACK_NETWORK) || |
569 | (efx->phy_type == PHY_TYPE_NONE)) | 570 | efx_phy_mode_disabled(efx->phy_mode)) |
570 | return 0; | 571 | return 0; |
571 | 572 | ||
572 | falcon_mask_status_intr(efx, false); | 573 | falcon_mask_status_intr(efx, false); |
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 406494684bb8..003e48dcb2f3 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c | |||
@@ -172,6 +172,8 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) | |||
172 | return true; | 172 | return true; |
173 | else if (efx->loopback_mode == LOOPBACK_NETWORK) | 173 | else if (efx->loopback_mode == LOOPBACK_NETWORK) |
174 | return false; | 174 | return false; |
175 | else if (efx_phy_mode_disabled(efx->phy_mode)) | ||
176 | return false; | ||
175 | else if (efx->loopback_mode == LOOPBACK_PHYXS) | 177 | else if (efx->loopback_mode == LOOPBACK_PHYXS) |
176 | mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS | | 178 | mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS | |
177 | MDIO_MMDREG_DEVS0_PCS | | 179 | MDIO_MMDREG_DEVS0_PCS | |
@@ -206,7 +208,7 @@ void mdio_clause45_transmit_disable(struct efx_nic *efx) | |||
206 | 208 | ||
207 | ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | 209 | ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
208 | MDIO_MMDREG_TXDIS); | 210 | MDIO_MMDREG_TXDIS); |
209 | if (efx->tx_disabled) | 211 | if (efx->phy_mode & PHY_MODE_TX_DISABLED) |
210 | ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); | 212 | ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); |
211 | else | 213 | else |
212 | ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); | 214 | ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index e65d6617beea..df863bcc06f8 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -519,6 +519,23 @@ struct efx_phy_operations { | |||
519 | unsigned loopbacks; | 519 | unsigned loopbacks; |
520 | }; | 520 | }; |
521 | 521 | ||
522 | /** | ||
523 | * @enum efx_phy_mode - PHY operating mode flags | ||
524 | * @PHY_MODE_NORMAL: on and should pass traffic | ||
525 | * @PHY_MODE_TX_DISABLED: on with TX disabled | ||
526 | * @PHY_MODE_SPECIAL: on but will not pass traffic | ||
527 | */ | ||
528 | enum efx_phy_mode { | ||
529 | PHY_MODE_NORMAL = 0, | ||
530 | PHY_MODE_TX_DISABLED = 1, | ||
531 | PHY_MODE_SPECIAL = 8, | ||
532 | }; | ||
533 | |||
534 | static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode) | ||
535 | { | ||
536 | return (mode & ~PHY_MODE_TX_DISABLED) != 0; | ||
537 | } | ||
538 | |||
522 | /* | 539 | /* |
523 | * Efx extended statistics | 540 | * Efx extended statistics |
524 | * | 541 | * |
@@ -661,7 +678,7 @@ union efx_multicast_hash { | |||
661 | * @phy_op: PHY interface | 678 | * @phy_op: PHY interface |
662 | * @phy_data: PHY private data (including PHY-specific stats) | 679 | * @phy_data: PHY private data (including PHY-specific stats) |
663 | * @mii: PHY interface | 680 | * @mii: PHY interface |
664 | * @tx_disabled: PHY transmitter turned off | 681 | * @phy_mode: PHY operating mode |
665 | * @link_up: Link status | 682 | * @link_up: Link status |
666 | * @link_options: Link options (MII/GMII format) | 683 | * @link_options: Link options (MII/GMII format) |
667 | * @n_link_state_changes: Number of times the link has changed state | 684 | * @n_link_state_changes: Number of times the link has changed state |
@@ -735,7 +752,7 @@ struct efx_nic { | |||
735 | struct efx_phy_operations *phy_op; | 752 | struct efx_phy_operations *phy_op; |
736 | void *phy_data; | 753 | void *phy_data; |
737 | struct mii_if_info mii; | 754 | struct mii_if_info mii; |
738 | bool tx_disabled; | 755 | enum efx_phy_mode phy_mode; |
739 | 756 | ||
740 | bool link_up; | 757 | bool link_up; |
741 | unsigned int link_options; | 758 | unsigned int link_options; |
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 25bd18ec7046..f746536f4ffa 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h | |||
@@ -15,14 +15,6 @@ | |||
15 | */ | 15 | */ |
16 | extern struct efx_phy_operations falcon_tenxpress_phy_ops; | 16 | extern struct efx_phy_operations falcon_tenxpress_phy_ops; |
17 | 17 | ||
18 | enum tenxpress_state { | ||
19 | TENXPRESS_STATUS_OFF = 0, | ||
20 | TENXPRESS_STATUS_OTEMP = 1, | ||
21 | TENXPRESS_STATUS_NORMAL = 2, | ||
22 | }; | ||
23 | |||
24 | extern void tenxpress_set_state(struct efx_nic *efx, | ||
25 | enum tenxpress_state state); | ||
26 | extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); | 18 | extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); |
27 | extern void tenxpress_crc_err(struct efx_nic *efx); | 19 | extern void tenxpress_crc_err(struct efx_nic *efx); |
28 | 20 | ||
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index f9272816437d..d90fab59f83e 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * the PHY | 13 | * the PHY |
14 | */ | 14 | */ |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include "net_driver.h" | ||
16 | #include "efx.h" | 17 | #include "efx.h" |
17 | #include "phy.h" | 18 | #include "phy.h" |
18 | #include "boards.h" | 19 | #include "boards.h" |
@@ -120,52 +121,15 @@ static void sfe4001_poweroff(struct efx_nic *efx) | |||
120 | i2c_smbus_read_byte_data(hwmon_client, RSL); | 121 | i2c_smbus_read_byte_data(hwmon_client, RSL); |
121 | } | 122 | } |
122 | 123 | ||
123 | static void sfe4001_fini(struct efx_nic *efx) | 124 | static int sfe4001_poweron(struct efx_nic *efx) |
124 | { | 125 | { |
125 | EFX_INFO(efx, "%s\n", __func__); | 126 | struct i2c_client *hwmon_client = efx->board_info.hwmon_client; |
126 | 127 | struct i2c_client *ioexp_client = efx->board_info.ioexp_client; | |
127 | sfe4001_poweroff(efx); | ||
128 | i2c_unregister_device(efx->board_info.ioexp_client); | ||
129 | i2c_unregister_device(efx->board_info.hwmon_client); | ||
130 | } | ||
131 | |||
132 | /* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected | ||
133 | * to the FLASH_CFG_1 input on the DSP. We must keep it high at power- | ||
134 | * up to allow writing the flash (done through MDIO from userland). | ||
135 | */ | ||
136 | unsigned int sfe4001_phy_flash_cfg; | ||
137 | module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444); | ||
138 | MODULE_PARM_DESC(phy_flash_cfg, | ||
139 | "Force PHY to enter flash configuration mode"); | ||
140 | |||
141 | /* This board uses an I2C expander to provider power to the PHY, which needs to | ||
142 | * be turned on before the PHY can be used. | ||
143 | * Context: Process context, rtnl lock held | ||
144 | */ | ||
145 | int sfe4001_init(struct efx_nic *efx) | ||
146 | { | ||
147 | struct i2c_client *hwmon_client, *ioexp_client; | ||
148 | unsigned int i, j; | 128 | unsigned int i, j; |
149 | int rc; | 129 | int rc; |
150 | u8 out; | 130 | u8 out; |
151 | efx_dword_t reg; | 131 | efx_dword_t reg; |
152 | 132 | ||
153 | hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); | ||
154 | if (!hwmon_client) | ||
155 | return -EIO; | ||
156 | efx->board_info.hwmon_client = hwmon_client; | ||
157 | |||
158 | ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); | ||
159 | if (!ioexp_client) { | ||
160 | rc = -EIO; | ||
161 | goto fail_hwmon; | ||
162 | } | ||
163 | efx->board_info.ioexp_client = ioexp_client; | ||
164 | |||
165 | /* 10Xpress has fixed-function LED pins, so there is no board-specific | ||
166 | * blink code. */ | ||
167 | efx->board_info.blink = tenxpress_phy_blink; | ||
168 | |||
169 | /* Ensure that XGXS and XAUI SerDes are held in reset */ | 133 | /* Ensure that XGXS and XAUI SerDes are held in reset */ |
170 | EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1, | 134 | EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1, |
171 | XX_PWRDNB_EN, 1, | 135 | XX_PWRDNB_EN, 1, |
@@ -177,33 +141,15 @@ int sfe4001_init(struct efx_nic *efx) | |||
177 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | 141 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); |
178 | udelay(10); | 142 | udelay(10); |
179 | 143 | ||
180 | efx->board_info.fini = sfe4001_fini; | ||
181 | |||
182 | /* Set DSP over-temperature alert threshold */ | ||
183 | EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); | ||
184 | rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, | ||
185 | xgphy_max_temperature); | ||
186 | if (rc) | ||
187 | goto fail_ioexp; | ||
188 | |||
189 | /* Read it back and verify */ | ||
190 | rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); | ||
191 | if (rc < 0) | ||
192 | goto fail_ioexp; | ||
193 | if (rc != xgphy_max_temperature) { | ||
194 | rc = -EFAULT; | ||
195 | goto fail_ioexp; | ||
196 | } | ||
197 | |||
198 | /* Clear any previous over-temperature alert */ | 144 | /* Clear any previous over-temperature alert */ |
199 | rc = i2c_smbus_read_byte_data(hwmon_client, RSL); | 145 | rc = i2c_smbus_read_byte_data(hwmon_client, RSL); |
200 | if (rc < 0) | 146 | if (rc < 0) |
201 | goto fail_ioexp; | 147 | return rc; |
202 | 148 | ||
203 | /* Enable port 0 and port 1 outputs on IO expander */ | 149 | /* Enable port 0 and port 1 outputs on IO expander */ |
204 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); | 150 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); |
205 | if (rc) | 151 | if (rc) |
206 | goto fail_ioexp; | 152 | return rc; |
207 | rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, | 153 | rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, |
208 | 0xff & ~(1 << P1_SPARE_LBN)); | 154 | 0xff & ~(1 << P1_SPARE_LBN)); |
209 | if (rc) | 155 | if (rc) |
@@ -231,7 +177,7 @@ int sfe4001_init(struct efx_nic *efx) | |||
231 | out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | | 177 | out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | |
232 | (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | | 178 | (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | |
233 | (1 << P0_X_TRST_LBN)); | 179 | (1 << P0_X_TRST_LBN)); |
234 | if (sfe4001_phy_flash_cfg) | 180 | if (efx->phy_mode & PHY_MODE_SPECIAL) |
235 | out |= 1 << P0_EN_3V3X_LBN; | 181 | out |= 1 << P0_EN_3V3X_LBN; |
236 | 182 | ||
237 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); | 183 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); |
@@ -250,9 +196,9 @@ int sfe4001_init(struct efx_nic *efx) | |||
250 | /* In flash config mode, DSP does not turn on AFE, so | 196 | /* In flash config mode, DSP does not turn on AFE, so |
251 | * just wait 1 second. | 197 | * just wait 1 second. |
252 | */ | 198 | */ |
253 | if (sfe4001_phy_flash_cfg) { | 199 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
254 | schedule_timeout_uninterruptible(HZ); | 200 | schedule_timeout_uninterruptible(HZ); |
255 | goto done; | 201 | return 0; |
256 | } | 202 | } |
257 | 203 | ||
258 | for (j = 0; j < 10; ++j) { | 204 | for (j = 0; j < 10; ++j) { |
@@ -263,23 +209,127 @@ int sfe4001_init(struct efx_nic *efx) | |||
263 | if (rc < 0) | 209 | if (rc < 0) |
264 | goto fail_on; | 210 | goto fail_on; |
265 | if (rc & (1 << P1_AFE_PWD_LBN)) | 211 | if (rc & (1 << P1_AFE_PWD_LBN)) |
266 | goto done; | 212 | return 0; |
267 | } | 213 | } |
268 | } | 214 | } |
269 | 215 | ||
270 | EFX_INFO(efx, "timed out waiting for DSP boot\n"); | 216 | EFX_INFO(efx, "timed out waiting for DSP boot\n"); |
271 | rc = -ETIMEDOUT; | 217 | rc = -ETIMEDOUT; |
272 | goto fail_on; | 218 | fail_on: |
219 | sfe4001_poweroff(efx); | ||
220 | return rc; | ||
221 | } | ||
222 | |||
223 | /* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin | ||
224 | * using the 3V3X output of the IO-expander. Allow the user to set | ||
225 | * this when the device is stopped, and keep it stopped then. | ||
226 | */ | ||
227 | |||
228 | static ssize_t show_phy_flash_cfg(struct device *dev, | ||
229 | struct device_attribute *attr, char *buf) | ||
230 | { | ||
231 | struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); | ||
232 | return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); | ||
233 | } | ||
234 | |||
235 | static ssize_t set_phy_flash_cfg(struct device *dev, | ||
236 | struct device_attribute *attr, | ||
237 | const char *buf, size_t count) | ||
238 | { | ||
239 | struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); | ||
240 | enum efx_phy_mode old_mode, new_mode; | ||
241 | int err; | ||
242 | |||
243 | rtnl_lock(); | ||
244 | old_mode = efx->phy_mode; | ||
245 | if (count == 0 || *buf == '0') | ||
246 | new_mode = old_mode & ~PHY_MODE_SPECIAL; | ||
247 | else | ||
248 | new_mode = PHY_MODE_SPECIAL; | ||
249 | if (old_mode == new_mode) { | ||
250 | err = 0; | ||
251 | } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { | ||
252 | err = -EBUSY; | ||
253 | } else { | ||
254 | efx->phy_mode = new_mode; | ||
255 | err = sfe4001_poweron(efx); | ||
256 | efx_reconfigure_port(efx); | ||
257 | } | ||
258 | rtnl_unlock(); | ||
259 | |||
260 | return err ? err : count; | ||
261 | } | ||
262 | |||
263 | static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); | ||
264 | |||
265 | static void sfe4001_fini(struct efx_nic *efx) | ||
266 | { | ||
267 | EFX_INFO(efx, "%s\n", __func__); | ||
268 | |||
269 | device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); | ||
270 | sfe4001_poweroff(efx); | ||
271 | i2c_unregister_device(efx->board_info.ioexp_client); | ||
272 | i2c_unregister_device(efx->board_info.hwmon_client); | ||
273 | } | ||
274 | |||
275 | /* This board uses an I2C expander to provider power to the PHY, which needs to | ||
276 | * be turned on before the PHY can be used. | ||
277 | * Context: Process context, rtnl lock held | ||
278 | */ | ||
279 | int sfe4001_init(struct efx_nic *efx) | ||
280 | { | ||
281 | struct i2c_client *hwmon_client; | ||
282 | int rc; | ||
283 | |||
284 | hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); | ||
285 | if (!hwmon_client) | ||
286 | return -EIO; | ||
287 | efx->board_info.hwmon_client = hwmon_client; | ||
288 | |||
289 | /* Set DSP over-temperature alert threshold */ | ||
290 | EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); | ||
291 | rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, | ||
292 | xgphy_max_temperature); | ||
293 | if (rc) | ||
294 | goto fail_ioexp; | ||
295 | |||
296 | /* Read it back and verify */ | ||
297 | rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); | ||
298 | if (rc < 0) | ||
299 | goto fail_ioexp; | ||
300 | if (rc != xgphy_max_temperature) { | ||
301 | rc = -EFAULT; | ||
302 | goto fail_ioexp; | ||
303 | } | ||
304 | |||
305 | efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); | ||
306 | if (!efx->board_info.ioexp_client) { | ||
307 | rc = -EIO; | ||
308 | goto fail_hwmon; | ||
309 | } | ||
310 | |||
311 | /* 10Xpress has fixed-function LED pins, so there is no board-specific | ||
312 | * blink code. */ | ||
313 | efx->board_info.blink = tenxpress_phy_blink; | ||
314 | |||
315 | efx->board_info.fini = sfe4001_fini; | ||
316 | |||
317 | rc = sfe4001_poweron(efx); | ||
318 | if (rc) | ||
319 | goto fail_ioexp; | ||
320 | |||
321 | rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); | ||
322 | if (rc) | ||
323 | goto fail_on; | ||
273 | 324 | ||
274 | done: | ||
275 | EFX_INFO(efx, "PHY is powered on\n"); | 325 | EFX_INFO(efx, "PHY is powered on\n"); |
276 | return 0; | 326 | return 0; |
277 | 327 | ||
278 | fail_on: | 328 | fail_on: |
279 | sfe4001_poweroff(efx); | 329 | sfe4001_poweroff(efx); |
280 | fail_ioexp: | 330 | fail_ioexp: |
281 | i2c_unregister_device(ioexp_client); | 331 | i2c_unregister_device(efx->board_info.ioexp_client); |
282 | fail_hwmon: | 332 | fail_hwmon: |
283 | i2c_unregister_device(hwmon_client); | 333 | i2c_unregister_device(hwmon_client); |
284 | return rc; | 334 | return rc; |
285 | } | 335 | } |
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index b92b24bba9e8..499e127f6dd5 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -119,27 +119,12 @@ MODULE_PARM_DESC(crc_error_reset_threshold, | |||
119 | "Max number of CRC errors before XAUI reset"); | 119 | "Max number of CRC errors before XAUI reset"); |
120 | 120 | ||
121 | struct tenxpress_phy_data { | 121 | struct tenxpress_phy_data { |
122 | enum tenxpress_state state; | ||
123 | enum efx_loopback_mode loopback_mode; | 122 | enum efx_loopback_mode loopback_mode; |
124 | atomic_t bad_crc_count; | 123 | atomic_t bad_crc_count; |
125 | bool tx_disabled; | 124 | enum efx_phy_mode phy_mode; |
126 | int bad_lp_tries; | 125 | int bad_lp_tries; |
127 | }; | 126 | }; |
128 | 127 | ||
129 | static int tenxpress_state_is(struct efx_nic *efx, int state) | ||
130 | { | ||
131 | struct tenxpress_phy_data *phy_data = efx->phy_data; | ||
132 | return (phy_data != NULL) && (state == phy_data->state); | ||
133 | } | ||
134 | |||
135 | void tenxpress_set_state(struct efx_nic *efx, | ||
136 | enum tenxpress_state state) | ||
137 | { | ||
138 | struct tenxpress_phy_data *phy_data = efx->phy_data; | ||
139 | if (phy_data != NULL) | ||
140 | phy_data->state = state; | ||
141 | } | ||
142 | |||
143 | void tenxpress_crc_err(struct efx_nic *efx) | 128 | void tenxpress_crc_err(struct efx_nic *efx) |
144 | { | 129 | { |
145 | struct tenxpress_phy_data *phy_data = efx->phy_data; | 130 | struct tenxpress_phy_data *phy_data = efx->phy_data; |
@@ -214,15 +199,12 @@ static int tenxpress_phy_init(struct efx_nic *efx) | |||
214 | if (!phy_data) | 199 | if (!phy_data) |
215 | return -ENOMEM; | 200 | return -ENOMEM; |
216 | efx->phy_data = phy_data; | 201 | efx->phy_data = phy_data; |
202 | phy_data->phy_mode = efx->phy_mode; | ||
217 | 203 | ||
218 | tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL); | 204 | rc = mdio_clause45_wait_reset_mmds(efx, |
219 | 205 | TENXPRESS_REQUIRED_DEVS); | |
220 | if (!sfe4001_phy_flash_cfg) { | 206 | if (rc < 0) |
221 | rc = mdio_clause45_wait_reset_mmds(efx, | 207 | goto fail; |
222 | TENXPRESS_REQUIRED_DEVS); | ||
223 | if (rc < 0) | ||
224 | goto fail; | ||
225 | } | ||
226 | 208 | ||
227 | rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); | 209 | rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); |
228 | if (rc < 0) | 210 | if (rc < 0) |
@@ -370,13 +352,16 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) | |||
370 | bool loop_change = LOOPBACK_OUT_OF(phy_data, efx, | 352 | bool loop_change = LOOPBACK_OUT_OF(phy_data, efx, |
371 | TENXPRESS_LOOPBACKS); | 353 | TENXPRESS_LOOPBACKS); |
372 | 354 | ||
373 | if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL)) | 355 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
356 | phy_data->phy_mode = efx->phy_mode; | ||
374 | return; | 357 | return; |
358 | } | ||
375 | 359 | ||
376 | /* When coming out of transmit disable, coming out of low power | 360 | /* When coming out of transmit disable, coming out of low power |
377 | * mode, or moving out of any PHY internal loopback mode, | 361 | * mode, or moving out of any PHY internal loopback mode, |
378 | * perform a special software reset */ | 362 | * perform a special software reset */ |
379 | if ((phy_data->tx_disabled && !efx->tx_disabled) || | 363 | if ((efx->phy_mode == PHY_MODE_NORMAL && |
364 | phy_data->phy_mode != PHY_MODE_NORMAL) || | ||
380 | loop_change) { | 365 | loop_change) { |
381 | tenxpress_special_reset(efx); | 366 | tenxpress_special_reset(efx); |
382 | falcon_reset_xaui(efx); | 367 | falcon_reset_xaui(efx); |
@@ -386,8 +371,8 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) | |||
386 | mdio_clause45_phy_reconfigure(efx); | 371 | mdio_clause45_phy_reconfigure(efx); |
387 | tenxpress_phyxs_loopback(efx); | 372 | tenxpress_phyxs_loopback(efx); |
388 | 373 | ||
389 | phy_data->tx_disabled = efx->tx_disabled; | ||
390 | phy_data->loopback_mode = efx->loopback_mode; | 374 | phy_data->loopback_mode = efx->loopback_mode; |
375 | phy_data->phy_mode = efx->phy_mode; | ||
391 | efx->link_up = tenxpress_link_ok(efx, false); | 376 | efx->link_up = tenxpress_link_ok(efx, false); |
392 | efx->link_options = GM_LPA_10000FULL; | 377 | efx->link_options = GM_LPA_10000FULL; |
393 | } | 378 | } |
@@ -402,16 +387,15 @@ static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) | |||
402 | static int tenxpress_phy_check_hw(struct efx_nic *efx) | 387 | static int tenxpress_phy_check_hw(struct efx_nic *efx) |
403 | { | 388 | { |
404 | struct tenxpress_phy_data *phy_data = efx->phy_data; | 389 | struct tenxpress_phy_data *phy_data = efx->phy_data; |
405 | bool phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL); | ||
406 | bool link_ok; | 390 | bool link_ok; |
407 | 391 | ||
408 | link_ok = phy_up && tenxpress_link_ok(efx, true); | 392 | link_ok = (phy_data->phy_mode == PHY_MODE_NORMAL && |
393 | tenxpress_link_ok(efx, true)); | ||
409 | 394 | ||
410 | if (link_ok != efx->link_up) | 395 | if (link_ok != efx->link_up) |
411 | falcon_xmac_sim_phy_event(efx); | 396 | falcon_xmac_sim_phy_event(efx); |
412 | 397 | ||
413 | /* Nothing to check if we've already shut down the PHY */ | 398 | if (phy_data->phy_mode != PHY_MODE_NORMAL) |
414 | if (!phy_up) | ||
415 | return 0; | 399 | return 0; |
416 | 400 | ||
417 | if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { | 401 | if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { |
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index fd4045b4d9d0..f6edecc2e588 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c | |||
@@ -40,7 +40,7 @@ void xfp_set_led(struct efx_nic *p, int led, int mode) | |||
40 | } | 40 | } |
41 | 41 | ||
42 | struct xfp_phy_data { | 42 | struct xfp_phy_data { |
43 | bool tx_disabled; | 43 | enum efx_phy_mode phy_mode; |
44 | }; | 44 | }; |
45 | 45 | ||
46 | #define XFP_MAX_RESET_TIME 500 | 46 | #define XFP_MAX_RESET_TIME 500 |
@@ -93,7 +93,7 @@ static int xfp_phy_init(struct efx_nic *efx) | |||
93 | " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid), | 93 | " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid), |
94 | MDIO_ID_REV(devid)); | 94 | MDIO_ID_REV(devid)); |
95 | 95 | ||
96 | phy_data->tx_disabled = efx->tx_disabled; | 96 | phy_data->phy_mode = efx->phy_mode; |
97 | 97 | ||
98 | rc = xfp_reset_phy(efx); | 98 | rc = xfp_reset_phy(efx); |
99 | 99 | ||
@@ -136,13 +136,14 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) | |||
136 | struct xfp_phy_data *phy_data = efx->phy_data; | 136 | struct xfp_phy_data *phy_data = efx->phy_data; |
137 | 137 | ||
138 | /* Reset the PHY when moving from tx off to tx on */ | 138 | /* Reset the PHY when moving from tx off to tx on */ |
139 | if (phy_data->tx_disabled && !efx->tx_disabled) | 139 | if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && |
140 | (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) | ||
140 | xfp_reset_phy(efx); | 141 | xfp_reset_phy(efx); |
141 | 142 | ||
142 | mdio_clause45_transmit_disable(efx); | 143 | mdio_clause45_transmit_disable(efx); |
143 | mdio_clause45_phy_reconfigure(efx); | 144 | mdio_clause45_phy_reconfigure(efx); |
144 | 145 | ||
145 | phy_data->tx_disabled = efx->tx_disabled; | 146 | phy_data->phy_mode = efx->phy_mode; |
146 | efx->link_up = xfp_link_ok(efx); | 147 | efx->link_up = xfp_link_ok(efx); |
147 | efx->link_options = GM_LPA_10000FULL; | 148 | efx->link_options = GM_LPA_10000FULL; |
148 | } | 149 | } |