aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/smsc/smsc911x.c
diff options
context:
space:
mode:
authorJavier Martinez Canillas <javier@dowhile0.org>2012-01-03 08:36:19 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-03 20:24:15 -0500
commit6386994e03ebbe60338ded3d586308a41e81c0dc (patch)
tree2fe7a1f71b5ae587b3203180a865bacb25089e51 /drivers/net/ethernet/smsc/smsc911x.c
parent43c6759e73907e4c8e6624f70f5c4a860518b203 (diff)
net/smsc911x: Check if PHY is in operational mode before software reset
SMSC LAN generation 4 chips integrate an IEEE 802.3 ethernet physical layer. The PHY driver for this integrated chip enable an energy detect power-down mode. When the PHY is in a power-down mode, it prevents the MAC portion chip to be software reseted. That means that if we compile the kernel with the configuration option SMSC_PHY enabled and try to bring the network interface up without an cable plug-ed the PHY will be in a low power mode and the software reset will fail returning -EIO to user-space: root@igep00x0:~# ifconfig eth0 up ifconfig: SIOCSIFFLAGS: Input/output error This patch disable the energy detect power-down mode before trying to software reset the LAN chip and re-enables after it was reseted successfully. Signed-off-by: Javier Martinez Canillas <javier@dowhile0.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/smsc/smsc911x.c')
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 06d0df61bee6..9d0b8ced0234 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -1319,10 +1319,92 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
1319 spin_unlock(&pdata->mac_lock); 1319 spin_unlock(&pdata->mac_lock);
1320} 1320}
1321 1321
1322static int smsc911x_phy_disable_energy_detect(struct smsc911x_data *pdata)
1323{
1324 int rc = 0;
1325
1326 if (!pdata->phy_dev)
1327 return rc;
1328
1329 rc = phy_read(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS);
1330
1331 if (rc < 0) {
1332 SMSC_WARN(pdata, drv, "Failed reading PHY control reg");
1333 return rc;
1334 }
1335
1336 /*
1337 * If energy is detected the PHY is already awake so is not necessary
1338 * to disable the energy detect power-down mode.
1339 */
1340 if ((rc & MII_LAN83C185_EDPWRDOWN) &&
1341 !(rc & MII_LAN83C185_ENERGYON)) {
1342 /* Disable energy detect mode for this SMSC Transceivers */
1343 rc = phy_write(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS,
1344 rc & (~MII_LAN83C185_EDPWRDOWN));
1345
1346 if (rc < 0) {
1347 SMSC_WARN(pdata, drv, "Failed writing PHY control reg");
1348 return rc;
1349 }
1350
1351 mdelay(1);
1352 }
1353
1354 return 0;
1355}
1356
1357static int smsc911x_phy_enable_energy_detect(struct smsc911x_data *pdata)
1358{
1359 int rc = 0;
1360
1361 if (!pdata->phy_dev)
1362 return rc;
1363
1364 rc = phy_read(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS);
1365
1366 if (rc < 0) {
1367 SMSC_WARN(pdata, drv, "Failed reading PHY control reg");
1368 return rc;
1369 }
1370
1371 /* Only enable if energy detect mode is already disabled */
1372 if (!(rc & MII_LAN83C185_EDPWRDOWN)) {
1373 mdelay(100);
1374 /* Enable energy detect mode for this SMSC Transceivers */
1375 rc = phy_write(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS,
1376 rc | MII_LAN83C185_EDPWRDOWN);
1377
1378 if (rc < 0) {
1379 SMSC_WARN(pdata, drv, "Failed writing PHY control reg");
1380 return rc;
1381 }
1382
1383 mdelay(1);
1384 }
1385 return 0;
1386}
1387
1322static int smsc911x_soft_reset(struct smsc911x_data *pdata) 1388static int smsc911x_soft_reset(struct smsc911x_data *pdata)
1323{ 1389{
1324 unsigned int timeout; 1390 unsigned int timeout;
1325 unsigned int temp; 1391 unsigned int temp;
1392 int ret;
1393
1394 /*
1395 * LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that
1396 * are initialized in a Energy Detect Power-Down mode that prevents
1397 * the MAC chip to be software reseted. So we have to wakeup the PHY
1398 * before.
1399 */
1400 if (pdata->generation == 4) {
1401 ret = smsc911x_phy_disable_energy_detect(pdata);
1402
1403 if (ret) {
1404 SMSC_WARN(pdata, drv, "Failed to wakeup the PHY chip");
1405 return ret;
1406 }
1407 }
1326 1408
1327 /* Reset the LAN911x */ 1409 /* Reset the LAN911x */
1328 smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_); 1410 smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_);
@@ -1336,6 +1418,16 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata)
1336 SMSC_WARN(pdata, drv, "Failed to complete reset"); 1418 SMSC_WARN(pdata, drv, "Failed to complete reset");
1337 return -EIO; 1419 return -EIO;
1338 } 1420 }
1421
1422 if (pdata->generation == 4) {
1423 ret = smsc911x_phy_enable_energy_detect(pdata);
1424
1425 if (ret) {
1426 SMSC_WARN(pdata, drv, "Failed to wakeup the PHY chip");
1427 return ret;
1428 }
1429 }
1430
1339 return 0; 1431 return 0;
1340} 1432}
1341 1433