diff options
Diffstat (limited to 'drivers/net/usb/smsc95xx.c')
| -rw-r--r-- | drivers/net/usb/smsc95xx.c | 64 |
1 files changed, 40 insertions, 24 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index ff4fa37dfd1..d07bf4cb893 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -13,14 +13,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * *****************************************************************************/ #include <linux/module.h> #include <linux/kmod.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -53,7 +51,7 @@ #define FEATURE_8_WAKEUP_FILTERS (0x01) #define FEATURE_PHY_NLP_CROSSOVER (0x02) -#define FEATURE_AUTOSUSPEND (0x04) +#define FEATURE_REMOTE_WAKEUP (0x04) #define SUSPEND_SUSPEND0 (0x01) #define SUSPEND_SUSPEND1 (0x02) @@ -1146,7 +1144,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) (val == ID_REV_CHIP_ID_89530_) || (val == ID_REV_CHIP_ID_9730_)) pdata->features = (FEATURE_8_WAKEUP_FILTERS | FEATURE_PHY_NLP_CROSSOVER | - FEATURE_AUTOSUSPEND); + FEATURE_REMOTE_WAKEUP); else if (val == ID_REV_CHIP_ID_9512_) pdata->features = FEATURE_8_WAKEUP_FILTERS; @@ -1247,10 +1245,12 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev) /* read back PM_CTRL */ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); + if (ret < 0) + return ret; pdata->suspend_flags |= SUSPEND_SUSPEND0; - return ret; + return 0; } static int smsc95xx_enter_suspend1(struct usbnet *dev) @@ -1293,10 +1293,12 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev) val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_); ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); + if (ret < 0) + return ret; pdata->suspend_flags |= SUSPEND_SUSPEND1; - return ret; + return 0; } static int smsc95xx_enter_suspend2(struct usbnet *dev) @@ -1313,10 +1315,12 @@ static int smsc95xx_enter_suspend2(struct usbnet *dev) val |= PM_CTL_SUS_MODE_2; ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); + if (ret < 0) + return ret; pdata->suspend_flags |= SUSPEND_SUSPEND2; - return ret; + return 0; } static int smsc95xx_enter_suspend3(struct usbnet *dev) @@ -1372,7 +1376,7 @@ static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up) if (!link_up) { /* link is down so enter EDPD mode, but only if device can * reliably resume from it. This check should be redundant - * as current FEATURE_AUTOSUSPEND parts also support + * as current FEATURE_REMOTE_WAKEUP parts also support * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */ if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) { netdev_warn(dev->net, "EDPD not supported\n"); @@ -1412,15 +1416,6 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) u32 val, link_up; int ret; - /* TODO: don't indicate this feature to usb framework if - * our current hardware doesn't have the capability - */ - if ((message.event == PM_EVENT_AUTO_SUSPEND) && - (!(pdata->features & FEATURE_AUTOSUSPEND))) { - netdev_warn(dev->net, "autosuspend not supported\n"); - return -EBUSY; - } - ret = usbnet_suspend(intf, message); if (ret < 0) { netdev_warn(dev->net, "usbnet_suspend error\n"); @@ -1435,7 +1430,8 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) /* determine if link is up using only _nopm functions */ link_up = smsc95xx_link_ok_nopm(dev); - if (message.event == PM_EVENT_AUTO_SUSPEND) { + if (message.event == PM_EVENT_AUTO_SUSPEND && + (pdata->features & FEATURE_REMOTE_WAKEUP)) { ret = smsc95xx_autosuspend(dev, link_up); goto done; } @@ -1662,7 +1658,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) ret = smsc95xx_enter_suspend0(dev); done: - if (ret) + /* + * TODO: resume() might need to handle the suspend failure + * in system sleep + */ + if (ret && PMSG_IS_AUTO(message)) usbnet_resume(intf); return ret; } @@ -1714,6 +1714,18 @@ static int smsc95xx_resume(struct usb_interface *intf) return ret; } +static int smsc95xx_reset_resume(struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + int ret; + + ret = smsc95xx_reset(dev); + if (ret < 0) + return ret; + + return smsc95xx_resume(intf); +} + static void smsc95xx_rx_csum_offload(struct sk_buff *skb) { skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); @@ -1723,6 +1735,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; @@ -1872,11 +1888,11 @@ static int smsc95xx_manage_power(struct usbnet *dev, int on) dev->intf->needs_remote_wakeup = on; - if (pdata->features & FEATURE_AUTOSUSPEND) + if (pdata->features & FEATURE_REMOTE_WAKEUP) return 0; - /* this chip revision doesn't support autosuspend */ - netdev_info(dev->net, "hardware doesn't support USB autosuspend\n"); + /* this chip revision isn't capable of remote wakeup */ + netdev_info(dev->net, "hardware isn't capable of remote wakeup\n"); if (on) usb_autopm_get_interface_no_resume(dev->intf); @@ -2000,7 +2016,7 @@ static struct usb_driver smsc95xx_driver = { .probe = usbnet_probe, .suspend = smsc95xx_suspend, .resume = smsc95xx_resume, - .reset_resume = smsc95xx_resume, + .reset_resume = smsc95xx_reset_resume, .disconnect = usbnet_disconnect, .disable_hub_initiated_lpm = 1, .supports_autosuspend = 1, |
