Skip to content

Commit

Permalink
smsc95xx: fix error handling in suspend failure case
Browse files Browse the repository at this point in the history
This patch ensures that if we fail to suspend the LAN9500 device
we call usbnet_resume before returning failure, instead of
leaving the usbnet driver in an unusable state.

Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Steve Glendinning authored and David S. Miller committed Nov 30, 2012
1 parent eed9a72 commit 3b9f7d8
Showing 1 changed file with 29 additions and 21 deletions.
50 changes: 29 additions & 21 deletions drivers/net/usb/smsc95xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1248,35 +1248,37 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)

/* disable energy detect (link up) & wake up events */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR\n");
check_warn_goto_done(ret, "Error reading WUCSR\n");

val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);

ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
check_warn_return(ret, "Error writing WUCSR\n");
check_warn_goto_done(ret, "Error writing WUCSR\n");

ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
check_warn_return(ret, "Error reading PM_CTRL\n");
check_warn_goto_done(ret, "Error reading PM_CTRL\n");

val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);

ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
check_warn_return(ret, "Error writing PM_CTRL\n");
check_warn_goto_done(ret, "Error writing PM_CTRL\n");

return smsc95xx_enter_suspend2(dev);
ret = smsc95xx_enter_suspend2(dev);
goto done;
}

if (pdata->wolopts & WAKE_PHY) {
ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
(PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_LINK_DOWN_));
check_warn_return(ret, "error enabling PHY wakeup ints\n");
check_warn_goto_done(ret, "error enabling PHY wakeup ints\n");

/* if link is down then configure EDPD and enter SUSPEND1,
* otherwise enter SUSPEND0 below
*/
if (!link_up) {
netdev_info(dev->net, "entering SUSPEND1 mode\n");
return smsc95xx_enter_suspend1(dev);
ret = smsc95xx_enter_suspend1(dev);
goto done;
}
}

Expand All @@ -1292,7 +1294,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)

if (!filter_mask) {
netdev_warn(dev->net, "Unable to allocate filter_mask\n");
return -ENOMEM;
ret = -ENOMEM;
goto done;
}

memset(command, 0, sizeof(command));
Expand Down Expand Up @@ -1354,49 +1357,49 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
if (ret < 0)
kfree(filter_mask);
check_warn_return(ret, "Error writing WUFF\n");
check_warn_goto_done(ret, "Error writing WUFF\n");
}
kfree(filter_mask);

for (i = 0; i < (wuff_filter_count / 4); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
check_warn_return(ret, "Error writing WUFF\n");
check_warn_goto_done(ret, "Error writing WUFF\n");
}

for (i = 0; i < (wuff_filter_count / 4); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
check_warn_return(ret, "Error writing WUFF\n");
check_warn_goto_done(ret, "Error writing WUFF\n");
}

for (i = 0; i < (wuff_filter_count / 2); i++) {
ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
check_warn_return(ret, "Error writing WUFF\n");
check_warn_goto_done(ret, "Error writing WUFF\n");
}

/* clear any pending pattern match packet status */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR\n");
check_warn_goto_done(ret, "Error reading WUCSR\n");

val |= WUCSR_WUFR_;

ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
check_warn_return(ret, "Error writing WUCSR\n");
check_warn_goto_done(ret, "Error writing WUCSR\n");
}

if (pdata->wolopts & WAKE_MAGIC) {
/* clear any pending magic packet status */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR\n");
check_warn_goto_done(ret, "Error reading WUCSR\n");

val |= WUCSR_MPR_;

ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
check_warn_return(ret, "Error writing WUCSR\n");
check_warn_goto_done(ret, "Error writing WUCSR\n");
}

/* enable/disable wakeup sources */
ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR\n");
check_warn_goto_done(ret, "Error reading WUCSR\n");

if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
netdev_info(dev->net, "enabling pattern match wakeup\n");
Expand All @@ -1415,11 +1418,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
}

ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
check_warn_return(ret, "Error writing WUCSR\n");
check_warn_goto_done(ret, "Error writing WUCSR\n");

/* enable wol wakeup source */
ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
check_warn_return(ret, "Error reading PM_CTRL\n");
check_warn_goto_done(ret, "Error reading PM_CTRL\n");

val |= PM_CTL_WOL_EN_;

Expand All @@ -1428,14 +1431,19 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
val |= PM_CTL_ED_EN_;

ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
check_warn_return(ret, "Error writing PM_CTRL\n");
check_warn_goto_done(ret, "Error writing PM_CTRL\n");

/* enable receiver to enable frame reception */
smsc95xx_start_rx_path(dev, 1);

/* some wol options are enabled, so enter SUSPEND0 */
netdev_info(dev->net, "entering SUSPEND0 mode\n");
return smsc95xx_enter_suspend0(dev);
ret = smsc95xx_enter_suspend0(dev);

done:
if (ret)
usbnet_resume(intf);
return ret;
}

static int smsc95xx_resume(struct usb_interface *intf)
Expand Down

0 comments on commit 3b9f7d8

Please sign in to comment.