aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/sfe4001.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-09-01 07:48:17 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-09-03 09:53:47 -0400
commitf8b87c17017f2ce1890fb9a7f85fb0fbf5643e37 (patch)
tree261a31a95d2fa296ef7abaf6019ff5b7c86bbc63 /drivers/net/sfc/sfe4001.c
parent3594e131b23665b728b4c98daaf0b61b1d4aaa7a (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/net/sfc/sfe4001.c')
-rw-r--r--drivers/net/sfc/sfe4001.c186
1 files changed, 118 insertions, 68 deletions
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
123static void sfe4001_fini(struct efx_nic *efx) 124static 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 */
136unsigned int sfe4001_phy_flash_cfg;
137module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444);
138MODULE_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 */
145int 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, &reg, XX_PWR_RST_REG_MAC); 141 falcon_xmac_writel(efx, &reg, 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; 218fail_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
228static 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
235static 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
263static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);
264
265static 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 */
279int 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
274done:
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
278fail_on: 328fail_on:
279 sfe4001_poweroff(efx); 329 sfe4001_poweroff(efx);
280fail_ioexp: 330fail_ioexp:
281 i2c_unregister_device(ioexp_client); 331 i2c_unregister_device(efx->board_info.ioexp_client);
282fail_hwmon: 332fail_hwmon:
283 i2c_unregister_device(hwmon_client); 333 i2c_unregister_device(hwmon_client);
284 return rc; 334 return rc;
285} 335}