Skip to content

Commit f329ccd

Browse files
steveglendavem330
authored andcommitted
smsc75xx: support PHY wakeup source
This patch enables LAN7500 family devices to wake from suspend on either link up or link down events. It also adds _nopm versions of mdio access functions, so we can safely call them from suspend and resume functions Updated patch to add newlines to printk messages Signed-off-by: Steve Glendinning <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9deb275 commit f329ccd

File tree

1 file changed

+152
-17
lines changed

1 file changed

+152
-17
lines changed

drivers/net/usb/smsc75xx.c

Lines changed: 152 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
#define USB_PRODUCT_ID_LAN7500 (0x7500)
5555
#define USB_PRODUCT_ID_LAN7505 (0x7505)
5656
#define RXW_PADDING 2
57-
#define SUPPORTED_WAKE (WAKE_UCAST | WAKE_BCAST | \
57+
#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \
5858
WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
5959

6060
#define check_warn(ret, fmt, args...) \
@@ -185,14 +185,15 @@ static int smsc75xx_clear_feature(struct usbnet *dev, u32 feature)
185185

186186
/* Loop until the read is completed with timeout
187187
* called with phy_mutex held */
188-
static int smsc75xx_phy_wait_not_busy(struct usbnet *dev)
188+
static __must_check int __smsc75xx_phy_wait_not_busy(struct usbnet *dev,
189+
int in_pm)
189190
{
190191
unsigned long start_time = jiffies;
191192
u32 val;
192193
int ret;
193194

194195
do {
195-
ret = smsc75xx_read_reg(dev, MII_ACCESS, &val);
196+
ret = __smsc75xx_read_reg(dev, MII_ACCESS, &val, in_pm);
196197
check_warn_return(ret, "Error reading MII_ACCESS\n");
197198

198199
if (!(val & MII_ACCESS_BUSY))
@@ -202,7 +203,8 @@ static int smsc75xx_phy_wait_not_busy(struct usbnet *dev)
202203
return -EIO;
203204
}
204205

205-
static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
206+
static int __smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
207+
int in_pm)
206208
{
207209
struct usbnet *dev = netdev_priv(netdev);
208210
u32 val, addr;
@@ -211,7 +213,7 @@ static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
211213
mutex_lock(&dev->phy_mutex);
212214

213215
/* confirm MII not busy */
214-
ret = smsc75xx_phy_wait_not_busy(dev);
216+
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
215217
check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_read\n");
216218

217219
/* set the address, index & direction (read from PHY) */
@@ -220,13 +222,13 @@ static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
220222
addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
221223
| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
222224
| MII_ACCESS_READ | MII_ACCESS_BUSY;
223-
ret = smsc75xx_write_reg(dev, MII_ACCESS, addr);
225+
ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
224226
check_warn_goto_done(ret, "Error writing MII_ACCESS\n");
225227

226-
ret = smsc75xx_phy_wait_not_busy(dev);
228+
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
227229
check_warn_goto_done(ret, "Timed out reading MII reg %02X\n", idx);
228230

229-
ret = smsc75xx_read_reg(dev, MII_DATA, &val);
231+
ret = __smsc75xx_read_reg(dev, MII_DATA, &val, in_pm);
230232
check_warn_goto_done(ret, "Error reading MII_DATA\n");
231233

232234
ret = (u16)(val & 0xFFFF);
@@ -236,8 +238,8 @@ static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
236238
return ret;
237239
}
238240

239-
static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
240-
int regval)
241+
static void __smsc75xx_mdio_write(struct net_device *netdev, int phy_id,
242+
int idx, int regval, int in_pm)
241243
{
242244
struct usbnet *dev = netdev_priv(netdev);
243245
u32 val, addr;
@@ -246,11 +248,11 @@ static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
246248
mutex_lock(&dev->phy_mutex);
247249

248250
/* confirm MII not busy */
249-
ret = smsc75xx_phy_wait_not_busy(dev);
251+
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
250252
check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_write\n");
251253

252254
val = regval;
253-
ret = smsc75xx_write_reg(dev, MII_DATA, val);
255+
ret = __smsc75xx_write_reg(dev, MII_DATA, val, in_pm);
254256
check_warn_goto_done(ret, "Error writing MII_DATA\n");
255257

256258
/* set the address, index & direction (write to PHY) */
@@ -259,16 +261,39 @@ static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
259261
addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
260262
| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
261263
| MII_ACCESS_WRITE | MII_ACCESS_BUSY;
262-
ret = smsc75xx_write_reg(dev, MII_ACCESS, addr);
264+
ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
263265
check_warn_goto_done(ret, "Error writing MII_ACCESS\n");
264266

265-
ret = smsc75xx_phy_wait_not_busy(dev);
267+
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
266268
check_warn_goto_done(ret, "Timed out writing MII reg %02X\n", idx);
267269

268270
done:
269271
mutex_unlock(&dev->phy_mutex);
270272
}
271273

274+
static int smsc75xx_mdio_read_nopm(struct net_device *netdev, int phy_id,
275+
int idx)
276+
{
277+
return __smsc75xx_mdio_read(netdev, phy_id, idx, 1);
278+
}
279+
280+
static void smsc75xx_mdio_write_nopm(struct net_device *netdev, int phy_id,
281+
int idx, int regval)
282+
{
283+
__smsc75xx_mdio_write(netdev, phy_id, idx, regval, 1);
284+
}
285+
286+
static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
287+
{
288+
return __smsc75xx_mdio_read(netdev, phy_id, idx, 0);
289+
}
290+
291+
static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
292+
int regval)
293+
{
294+
__smsc75xx_mdio_write(netdev, phy_id, idx, regval, 0);
295+
}
296+
272297
static int smsc75xx_wait_eeprom(struct usbnet *dev)
273298
{
274299
unsigned long start_time = jiffies;
@@ -1233,6 +1258,32 @@ static int smsc75xx_enter_suspend0(struct usbnet *dev)
12331258
return 0;
12341259
}
12351260

1261+
static int smsc75xx_enter_suspend1(struct usbnet *dev)
1262+
{
1263+
u32 val;
1264+
int ret;
1265+
1266+
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1267+
check_warn_return(ret, "Error reading PMT_CTL\n");
1268+
1269+
val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
1270+
val |= PMT_CTL_SUS_MODE_1;
1271+
1272+
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1273+
check_warn_return(ret, "Error writing PMT_CTL\n");
1274+
1275+
/* clear wol status, enable energy detection */
1276+
val &= ~PMT_CTL_WUPS;
1277+
val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
1278+
1279+
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1280+
check_warn_return(ret, "Error writing PMT_CTL\n");
1281+
1282+
smsc75xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
1283+
1284+
return 0;
1285+
}
1286+
12361287
static int smsc75xx_enter_suspend2(struct usbnet *dev)
12371288
{
12381289
u32 val;
@@ -1250,18 +1301,61 @@ static int smsc75xx_enter_suspend2(struct usbnet *dev)
12501301
return 0;
12511302
}
12521303

1304+
static int smsc75xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
1305+
{
1306+
struct mii_if_info *mii = &dev->mii;
1307+
int ret;
1308+
1309+
netdev_dbg(dev->net, "enabling PHY wakeup interrupts\n");
1310+
1311+
/* read to clear */
1312+
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
1313+
check_warn_return(ret, "Error reading PHY_INT_SRC\n");
1314+
1315+
/* enable interrupt source */
1316+
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
1317+
check_warn_return(ret, "Error reading PHY_INT_MASK\n");
1318+
1319+
ret |= mask;
1320+
1321+
smsc75xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret);
1322+
1323+
return 0;
1324+
}
1325+
1326+
static int smsc75xx_link_ok_nopm(struct usbnet *dev)
1327+
{
1328+
struct mii_if_info *mii = &dev->mii;
1329+
int ret;
1330+
1331+
/* first, a dummy read, needed to latch some MII phys */
1332+
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
1333+
check_warn_return(ret, "Error reading MII_BMSR\n");
1334+
1335+
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
1336+
check_warn_return(ret, "Error reading MII_BMSR\n");
1337+
1338+
return !!(ret & BMSR_LSTATUS);
1339+
}
1340+
12531341
static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
12541342
{
12551343
struct usbnet *dev = usb_get_intfdata(intf);
12561344
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
1345+
u32 val, link_up;
12571346
int ret;
1258-
u32 val;
12591347

12601348
ret = usbnet_suspend(intf, message);
12611349
check_warn_return(ret, "usbnet_suspend error\n");
12621350

1263-
/* if no wol options set, enter lowest power SUSPEND2 mode */
1264-
if (!(pdata->wolopts & SUPPORTED_WAKE)) {
1351+
/* determine if link is up using only _nopm functions */
1352+
link_up = smsc75xx_link_ok_nopm(dev);
1353+
1354+
/* if no wol options set, or if link is down and we're not waking on
1355+
* PHY activity, enter lowest power SUSPEND2 mode
1356+
*/
1357+
if (!(pdata->wolopts & SUPPORTED_WAKE) ||
1358+
!(link_up || (pdata->wolopts & WAKE_PHY))) {
12651359
netdev_info(dev->net, "entering SUSPEND2 mode\n");
12661360

12671361
/* disable energy detect (link up) & wake up events */
@@ -1284,6 +1378,33 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
12841378
return smsc75xx_enter_suspend2(dev);
12851379
}
12861380

1381+
if (pdata->wolopts & WAKE_PHY) {
1382+
ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
1383+
(PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN));
1384+
check_warn_return(ret, "error enabling PHY wakeup ints\n");
1385+
1386+
/* if link is down then configure EDPD and enter SUSPEND1,
1387+
* otherwise enter SUSPEND0 below
1388+
*/
1389+
if (!link_up) {
1390+
struct mii_if_info *mii = &dev->mii;
1391+
netdev_info(dev->net, "entering SUSPEND1 mode\n");
1392+
1393+
/* enable energy detect power-down mode */
1394+
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id,
1395+
PHY_MODE_CTRL_STS);
1396+
check_warn_return(ret, "Error reading PHY_MODE_CTRL_STS\n");
1397+
1398+
ret |= MODE_CTRL_STS_EDPWRDOWN;
1399+
1400+
smsc75xx_mdio_write_nopm(dev->net, mii->phy_id,
1401+
PHY_MODE_CTRL_STS, ret);
1402+
1403+
/* enter SUSPEND1 mode */
1404+
return smsc75xx_enter_suspend1(dev);
1405+
}
1406+
}
1407+
12871408
if (pdata->wolopts & (WAKE_MCAST | WAKE_ARP)) {
12881409
int i, filter = 0;
12891410

@@ -1350,6 +1471,20 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
13501471
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
13511472
check_warn_return(ret, "Error writing WUCSR\n");
13521473

1474+
if (pdata->wolopts & WAKE_PHY) {
1475+
netdev_info(dev->net, "enabling PHY wakeup\n");
1476+
1477+
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
1478+
check_warn_return(ret, "Error reading PMT_CTL\n");
1479+
1480+
/* clear wol status, enable energy detection */
1481+
val &= ~PMT_CTL_WUPS;
1482+
val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
1483+
1484+
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
1485+
check_warn_return(ret, "Error writing PMT_CTL\n");
1486+
}
1487+
13531488
if (pdata->wolopts & WAKE_MAGIC) {
13541489
netdev_info(dev->net, "enabling magic packet wakeup\n");
13551490
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);

0 commit comments

Comments
 (0)