diff options
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/asix_devices.c | 6 | ||||
-rw-r--r-- | drivers/net/usb/ax88179_178a.c | 12 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ether.c | 5 | ||||
-rw-r--r-- | drivers/net/usb/cdc_mbim.c | 4 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ncm.c | 18 | ||||
-rw-r--r-- | drivers/net/usb/dm9601.c | 7 | ||||
-rw-r--r-- | drivers/net/usb/mcs7830.c | 6 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.c | 447 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.h | 11 | ||||
-rw-r--r-- | drivers/net/usb/sierra_net.c | 3 | ||||
-rw-r--r-- | drivers/net/usb/usbnet.c | 45 |
11 files changed, 185 insertions, 379 deletions
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 709753469099..ad5d1e4384db 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -55,11 +55,7 @@ static void asix_status(struct usbnet *dev, struct urb *urb) event = urb->transfer_buffer; link = event->link & 0x01; if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent (dev, EVENT_LINK_RESET ); - } else - netif_carrier_off(dev->net); + usbnet_link_change(dev, link, 1); netdev_dbg(dev->net, "Link Status is: %d\n", link); } } diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 71c27d8d214f..bd8758fa38c1 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -352,11 +352,7 @@ static void ax88179_status(struct usbnet *dev, struct urb *urb) link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16; if (netif_carrier_ok(dev->net) != link) { - if (link) - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - else - netif_carrier_off(dev->net); - + usbnet_link_change(dev, link, 1); netdev_info(dev->net, "ax88179 - Link status is: %d\n", link); } } @@ -455,7 +451,7 @@ static int ax88179_resume(struct usb_interface *intf) u16 tmp16; u8 tmp8; - netif_carrier_off(dev->net); + usbnet_link_change(dev, 0, 0); /* Power up ethernet PHY */ tmp16 = 0; @@ -1068,7 +1064,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) /* Restart autoneg */ mii_nway_restart(&dev->mii); - netif_carrier_off(dev->net); + usbnet_link_change(dev, 0, 0); return 0; } @@ -1356,7 +1352,7 @@ static int ax88179_reset(struct usbnet *dev) /* Restart autoneg */ mii_nway_restart(&dev->mii); - netif_carrier_off(dev->net); + usbnet_link_change(dev, 0, 0); return 0; } diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 57136dc1b887..4ff71d619cd8 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -406,10 +406,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb) case USB_CDC_NOTIFY_NETWORK_CONNECTION: netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n", event->wValue ? "on" : "off"); - if (event->wValue) - netif_carrier_on(dev->net); - else - netif_carrier_off(dev->net); + usbnet_link_change(dev, !!event->wValue, 0); break; case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n", diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 32a76059e7da..872819851aef 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -101,7 +101,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->flags |= IFF_NOARP; /* no need to put the VLAN tci in the packet headers */ - dev->net->features |= NETIF_F_HW_VLAN_TX; + dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX; err: return ret; } @@ -221,7 +221,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_ /* map MBIM session to VLAN */ if (tci) - vlan_put_tag(skb, tci); + vlan_put_tag(skb, htons(ETH_P_8021Q), tci); err: return skb; } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4709fa3497cf..43afde8f48d2 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -362,8 +362,8 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ u8 iface_no; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (ctx == NULL) - return -ENODEV; + if (!ctx) + return -ENOMEM; hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ctx->tx_timer.function = &cdc_ncm_tx_timer_cb; @@ -610,7 +610,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) * (carrier is OFF) during attach, so the IP network stack does not * start IPv6 negotiation and more. */ - netif_carrier_off(dev->net); + usbnet_link_change(dev, 0, 0); return ret; } @@ -1106,12 +1106,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb) " %sconnected\n", ctx->netdev->name, ctx->connected ? "" : "dis"); - if (ctx->connected) - netif_carrier_on(dev->net); - else { - netif_carrier_off(dev->net); + usbnet_link_change(dev, ctx->connected, 0); + if (!ctx->connected) ctx->tx_speed = ctx->rx_speed = 0; - } break; case USB_CDC_NOTIFY_SPEED_CHANGE: @@ -1124,8 +1121,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb) break; default: - dev_err(&dev->udev->dev, "NCM: unexpected " - "notification 0x%02x!\n", event->bNotificationType); + dev_dbg(&dev->udev->dev, + "NCM: unexpected notification 0x%02x!\n", + event->bNotificationType); break; } } diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 174e5ecea4cc..2dbb9460349d 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -524,12 +524,7 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb) link = !!(buf[0] & 0x40); if (netif_carrier_ok(dev->net) != link) { - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent (dev, EVENT_LINK_RESET); - } - else - netif_carrier_off(dev->net); + usbnet_link_change(dev, link, 1); netdev_dbg(dev->net, "Link Status is: %d\n", link); } } diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 3f3f566afa0b..03832d3780aa 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -576,11 +576,7 @@ static void mcs7830_status(struct usbnet *dev, struct urb *urb) */ if (data->link_counter > 20) { data->link_counter = 0; - if (link) { - netif_carrier_on(dev->net); - usbnet_defer_kevent(dev, EVENT_LINK_RESET); - } else - netif_carrier_off(dev->net); + usbnet_link_change(dev, link, 0); netdev_dbg(dev->net, "Link Status is: %d\n", link); } } else diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73051d10ead2..09699054b54f 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net) + * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,6 +26,9 @@ * v0.5.1 ethtool support added * v0.5.5 rx socket buffers are in a pool and the their allocation * is out of the interrupt routine. + * ... + * v0.9.3 simplified [get|set]_register(s), async update registers + * logic revisited, receive skb_pool removed. */ #include <linux/sched.h> @@ -45,8 +48,8 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.6.14 (2006/09/27)" -#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" +#define DRIVER_VERSION "v0.9.3 (2013/04/25)" +#define DRIVER_AUTHOR "Petko Manolov <petkan@nucleusys.com>" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" static const char driver_name[] = "pegasus"; @@ -108,251 +111,137 @@ MODULE_PARM_DESC(msg_level, "Override default message level"); MODULE_DEVICE_TABLE(usb, pegasus_ids); static const struct net_device_ops pegasus_netdev_ops; -static int update_eth_regs_async(pegasus_t *); -/* Aargh!!! I _really_ hate such tweaks */ -static void ctrl_callback(struct urb *urb) +/*****/ + +static void async_ctrl_callback(struct urb *urb) { - pegasus_t *pegasus = urb->context; + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; int status = urb->status; - if (!pegasus) - return; - - switch (status) { - case 0: - if (pegasus->flags & ETH_REGS_CHANGE) { - pegasus->flags &= ~ETH_REGS_CHANGE; - pegasus->flags |= ETH_REGS_CHANGED; - update_eth_regs_async(pegasus); - return; - } - break; - case -EINPROGRESS: - return; - case -ENOENT: - break; - default: - if (net_ratelimit()) - netif_dbg(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, status); - break; - } - pegasus->flags &= ~ETH_REGS_CHANGED; - wake_up(&pegasus->ctrl_wait); + if (status < 0) + dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status); + kfree(req); + usb_free_urb(urb); } -static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, - void *data) +static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { int ret; - char *buffer; - DECLARE_WAITQUEUE(wait, current); - - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - while (pegasus->flags & ETH_REGS_CHANGED) - schedule(); - remove_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_RUNNING); - - pegasus->dr.bRequestType = PEGASUS_REQT_READ; - pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; - pegasus->dr.wValue = cpu_to_le16(0); - pegasus->dr.wIndex = cpu_to_le16(indx); - pegasus->dr.wLength = cpu_to_le16(size); - pegasus->ctrl_urb->transfer_buffer_length = size; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_rcvctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - buffer, size, ctrl_callback, pegasus); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - - /* using ATOMIC, we'd never wake up if we slept */ - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - set_current_state(TASK_RUNNING); - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - if (net_ratelimit()) - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, ret); - goto out; - } - - schedule(); -out: - remove_wait_queue(&pegasus->ctrl_wait, &wait); - memcpy(data, buffer, size); - kfree(buffer); + ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), + PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, + indx, data, size, 1000); + if (ret < 0) + netif_dbg(pegasus, drv, pegasus->net, + "%s returned %d\n", __func__, ret); return ret; } -static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, - void *data) +static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { int ret; - char *buffer; - DECLARE_WAITQUEUE(wait, current); - - buffer = kmemdup(data, size, GFP_KERNEL); - if (!buffer) { - netif_warn(pegasus, drv, pegasus->net, - "out of memory in %s\n", __func__); - return -ENOMEM; - } - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - while (pegasus->flags & ETH_REGS_CHANGED) - schedule(); - remove_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_RUNNING); - - pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; - pegasus->dr.wValue = cpu_to_le16(0); - pegasus->dr.wIndex = cpu_to_le16(indx); - pegasus->dr.wLength = cpu_to_le16(size); - pegasus->ctrl_urb->transfer_buffer_length = size; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - buffer, size, ctrl_callback, pegasus); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, ret); - goto out; - } - - schedule(); -out: - remove_wait_queue(&pegasus->ctrl_wait, &wait); - kfree(buffer); + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), + PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, + indx, data, size, 100); + if (ret < 0) + netif_dbg(pegasus, drv, pegasus->net, + "%s returned %d\n", __func__, ret); return ret; } static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data) { int ret; - char *tmp; - DECLARE_WAITQUEUE(wait, current); - - tmp = kmemdup(&data, 1, GFP_KERNEL); - if (!tmp) { - netif_warn(pegasus, drv, pegasus->net, - "out of memory in %s\n", __func__); - return -ENOMEM; - } - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - while (pegasus->flags & ETH_REGS_CHANGED) - schedule(); - remove_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_RUNNING); - - pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; - pegasus->dr.wValue = cpu_to_le16(data); - pegasus->dr.wIndex = cpu_to_le16(indx); - pegasus->dr.wLength = cpu_to_le16(1); - pegasus->ctrl_urb->transfer_buffer_length = 1; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - tmp, 1, ctrl_callback, pegasus); - - add_wait_queue(&pegasus->ctrl_wait, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) - netif_device_detach(pegasus->net); - if (net_ratelimit()) - netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, ret); - goto out; - } - - schedule(); -out: - remove_wait_queue(&pegasus->ctrl_wait, &wait); - kfree(tmp); + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), + PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, + indx, &data, 1, 1000); + if (ret < 0) + netif_dbg(pegasus, drv, pegasus->net, + "%s returned %d\n", __func__, ret); return ret; } static int update_eth_regs_async(pegasus_t *pegasus) { - int ret; - - pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; - pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; - pegasus->dr.wValue = cpu_to_le16(0); - pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); - pegasus->dr.wLength = cpu_to_le16(3); - pegasus->ctrl_urb->transfer_buffer_length = 3; - - usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, - usb_sndctrlpipe(pegasus->usb, 0), - (char *) &pegasus->dr, - pegasus->eth_regs, 3, ctrl_callback, pegasus); - - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { + int ret = -ENOMEM; + struct urb *async_urb; + struct usb_ctrlrequest *req; + + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); + if (req == NULL) + return ret; + + async_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (async_urb == NULL) { + kfree(req); + return ret; + } + req->bRequestType = PEGASUS_REQT_WRITE; + req->bRequest = PEGASUS_REQ_SET_REGS; + req->wValue = cpu_to_le16(0); + req->wIndex = cpu_to_le16(EthCtrl0); + req->wLength = cpu_to_le16(3); + + usb_fill_control_urb(async_urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb, 0), (void *)req, + pegasus->eth_regs, 3, async_ctrl_callback, req); + + ret = usb_submit_urb(async_urb, GFP_ATOMIC); + if (ret) { if (ret == -ENODEV) netif_device_detach(pegasus->net); netif_err(pegasus, drv, pegasus->net, - "%s, status %d\n", __func__, ret); + "%s returned %d\n", __func__, ret); } - return ret; } -/* Returns 0 on success, error on failure */ -static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd) { int i; __u8 data[4] = { phy, 0, 0, indx }; __le16 regdi; - int ret; + int ret = -ETIMEDOUT; - set_register(pegasus, PhyCtrl, 0); - set_registers(pegasus, PhyAddr, sizeof(data), data); - set_register(pegasus, PhyCtrl, (indx | PHY_READ)); + if (cmd & PHY_WRITE) { + __le16 *t = (__le16 *) & data[1]; + *t = cpu_to_le16(*regd); + } + set_register(p, PhyCtrl, 0); + set_registers(p, PhyAddr, sizeof(data), data); + set_register(p, PhyCtrl, (indx | cmd)); for (i = 0; i < REG_TIMEOUT; i++) { - ret = get_registers(pegasus, PhyCtrl, 1, data); - if (ret == -ESHUTDOWN) + ret = get_registers(p, PhyCtrl, 1, data); + if (ret < 0) goto fail; if (data[0] & PHY_DONE) break; } - if (i >= REG_TIMEOUT) goto fail; - - ret = get_registers(pegasus, PhyData, 2, ®di); - *regd = le16_to_cpu(regdi); + if (cmd & PHY_READ) { + ret = get_registers(p, PhyData, 2, ®di); + *regd = le16_to_cpu(regdi); + return ret; + } + return 0; +fail: + netif_dbg(p, drv, p->net, "%s failed\n", __func__); return ret; +} -fail: - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); +/* Returns non-negative int on success, error on failure */ +static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +{ + return __mii_op(pegasus, phy, indx, regd, PHY_READ); +} - return ret; +/* Returns zero on success, error on failure */ +static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +{ + return __mii_op(pegasus, phy, indx, regd, PHY_WRITE); } static int mdio_read(struct net_device *dev, int phy_id, int loc) @@ -364,40 +253,11 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc) return (int)res; } -static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd) -{ - int i; - __u8 data[4] = { phy, 0, 0, indx }; - int ret; - - data[1] = (u8) regd; - data[2] = (u8) (regd >> 8); - set_register(pegasus, PhyCtrl, 0); - set_registers(pegasus, PhyAddr, sizeof(data), data); - set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); - for (i = 0; i < REG_TIMEOUT; i++) { - ret = get_registers(pegasus, PhyCtrl, 1, data); - if (ret == -ESHUTDOWN) - goto fail; - if (data[0] & PHY_DONE) - break; - } - - if (i >= REG_TIMEOUT) - goto fail; - - return ret; - -fail: - netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); - return -ETIMEDOUT; -} - static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) { pegasus_t *pegasus = netdev_priv(dev); - write_mii_word(pegasus, phy_id, loc, val); + write_mii_word(pegasus, phy_id, loc, (__u16 *)&val); } static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) @@ -434,7 +294,6 @@ fail: static inline void enable_eprom_write(pegasus_t *pegasus) { __u8 tmp; - int ret; get_registers(pegasus, EthCtrl2, 1, &tmp); set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); @@ -443,7 +302,6 @@ static inline void enable_eprom_write(pegasus_t *pegasus) static inline void disable_eprom_write(pegasus_t *pegasus) { __u8 tmp; - int ret; get_registers(pegasus, EthCtrl2, 1, &tmp); set_register(pegasus, EpromCtrl, 0); @@ -537,7 +395,8 @@ static inline int reset_mac(pegasus_t *pegasus) if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { __u16 auxmode; read_mii_word(pegasus, 3, 0x1b, &auxmode); - write_mii_word(pegasus, 3, 0x1b, auxmode | 4); + auxmode |= 4; + write_mii_word(pegasus, 3, 0x1b, &auxmode); } return 0; @@ -569,57 +428,13 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { u16 auxmode; read_mii_word(pegasus, 0, 0x1b, &auxmode); - write_mii_word(pegasus, 0, 0x1b, auxmode | 4); + auxmode |= 4; + write_mii_word(pegasus, 0, 0x1b, &auxmode); } return ret; } -static void fill_skb_pool(pegasus_t *pegasus) -{ - int i; - - for (i = 0; i < RX_SKBS; i++) { - if (pegasus->rx_pool[i]) - continue; - pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); - /* - ** we give up if the allocation fail. the tasklet will be - ** rescheduled again anyway... - */ - if (pegasus->rx_pool[i] == NULL) - return; - skb_reserve(pegasus->rx_pool[i], 2); - } -} - -static void free_skb_pool(pegasus_t *pegasus) -{ - int i; - - for (i = 0; i < RX_SKBS; i++) { - if (pegasus->rx_pool[i]) { - dev_kfree_skb(pegasus->rx_pool[i]); - pegasus->rx_pool[i] = NULL; - } - } -} - -static inline struct sk_buff *pull_skb(pegasus_t * pegasus) -{ - int i; - struct sk_buff *skb; - - for (i = 0; i < RX_SKBS; i++) { - if (likely(pegasus->rx_pool[i] != NULL)) { - skb = pegasus->rx_pool[i]; - pegasus->rx_pool[i] = NULL; - return skb; - } - } - return NULL; -} - static void read_bulk_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; @@ -704,9 +519,8 @@ static void read_bulk_callback(struct urb *urb) if (pegasus->flags & PEGASUS_UNPLUG) return; - spin_lock(&pegasus->rx_pool_lock); - pegasus->rx_skb = pull_skb(pegasus); - spin_unlock(&pegasus->rx_pool_lock); + pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, PEGASUS_MTU, + GFP_ATOMIC); if (pegasus->rx_skb == NULL) goto tl_sched; @@ -734,24 +548,23 @@ tl_sched: static void rx_fixup(unsigned long data) { pegasus_t *pegasus; - unsigned long flags; int status; pegasus = (pegasus_t *) data; if (pegasus->flags & PEGASUS_UNPLUG) return; - spin_lock_irqsave(&pegasus->rx_pool_lock, flags); - fill_skb_pool(pegasus); if (pegasus->flags & PEGASUS_RX_URB_FAIL) if (pegasus->rx_skb) goto try_again; if (pegasus->rx_skb == NULL) - pegasus->rx_skb = pull_skb(pegasus); + pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, + PEGASUS_MTU, + GFP_ATOMIC); if (pegasus->rx_skb == NULL) { netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n"); tasklet_schedule(&pegasus->rx_tl); - goto done; + return; } usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), @@ -767,8 +580,6 @@ try_again: } else { pegasus->flags &= ~PEGASUS_RX_URB_FAIL; } -done: - spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags); } static void write_bulk_callback(struct urb *urb) @@ -963,7 +774,6 @@ static void free_all_urbs(pegasus_t *pegasus) usb_free_urb(pegasus->intr_urb); usb_free_urb(pegasus->tx_urb); usb_free_urb(pegasus->rx_urb); - usb_free_urb(pegasus->ctrl_urb); } static void unlink_all_urbs(pegasus_t *pegasus) @@ -971,48 +781,42 @@ static void unlink_all_urbs(pegasus_t *pegasus) usb_kill_urb(pegasus->intr_urb); usb_kill_urb(pegasus->tx_urb); usb_kill_urb(pegasus->rx_urb); - usb_kill_urb(pegasus->ctrl_urb); } static int alloc_urbs(pegasus_t *pegasus) { - pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pegasus->ctrl_urb) - return 0; + int res = -ENOMEM; + pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!pegasus->rx_urb) { - usb_free_urb(pegasus->ctrl_urb); - return 0; + return res; } pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!pegasus->tx_urb) { usb_free_urb(pegasus->rx_urb); - usb_free_urb(pegasus->ctrl_urb); - return 0; + return res; } pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL); if (!pegasus->intr_urb) { usb_free_urb(pegasus->tx_urb); usb_free_urb(pegasus->rx_urb); - usb_free_urb(pegasus->ctrl_urb); - return 0; + return res; } - return 1; + return 0; } static int pegasus_open(struct net_device *net) { pegasus_t *pegasus = netdev_priv(net); - int res; + int res=-ENOMEM; if (pegasus->rx_skb == NULL) - pegasus->rx_skb = pull_skb(pegasus); - /* - ** Note: no point to free the pool. it is empty :-) - */ + pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, + PEGASUS_MTU, + GFP_KERNEL); if (!pegasus->rx_skb) - return -ENOMEM; + goto exit; res = set_registers(pegasus, EthID, 6, net->dev_addr); @@ -1038,13 +842,13 @@ static int pegasus_open(struct net_device *net) usb_kill_urb(pegasus->rx_urb); goto exit; } - if ((res = enable_net_traffic(net, pegasus->usb))) { + res = enable_net_traffic(net, pegasus->usb); + if (res < 0) { netif_dbg(pegasus, ifup, net, "can't enable_net_traffic() - %d\n", res); res = -EIO; usb_kill_urb(pegasus->rx_urb); usb_kill_urb(pegasus->intr_urb); - free_skb_pool(pegasus); goto exit; } set_carrier(net); @@ -1195,7 +999,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) case SIOCDEVPRIVATE + 2: if (!capable(CAP_NET_ADMIN)) return -EPERM; - write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); + write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]); res = 0; break; default: @@ -1219,11 +1023,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; } - - pegasus->ctrl_urb->status = 0; - - pegasus->flags |= ETH_REGS_CHANGE; - ctrl_callback(pegasus->ctrl_urb); + update_eth_regs_async(pegasus); } static __u8 mii_phy_probe(pegasus_t *pegasus) @@ -1340,9 +1140,9 @@ static int pegasus_probe(struct usb_interface *intf, pegasus = netdev_priv(net); pegasus->dev_index = dev_index; - init_waitqueue_head(&pegasus->ctrl_wait); - if (!alloc_urbs(pegasus)) { + res = alloc_urbs(pegasus); + if (res < 0) { dev_err(&intf->dev, "can't allocate %s\n", "urbs"); goto out1; } @@ -1364,7 +1164,6 @@ static int pegasus_probe(struct usb_interface *intf, pegasus->mii.mdio_write = mdio_write; pegasus->mii.phy_id_mask = 0x1f; pegasus->mii.reg_num_mask = 0x1f; - spin_lock_init(&pegasus->rx_pool_lock); pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK); @@ -1376,7 +1175,6 @@ static int pegasus_probe(struct usb_interface *intf, goto out2; } set_ethernet_addr(pegasus); - fill_skb_pool(pegasus); if (pegasus->features & PEGASUS_II) { dev_info(&intf->dev, "setup Pegasus II specific registers\n"); setup_pegasus_II(pegasus); @@ -1394,17 +1192,13 @@ static int pegasus_probe(struct usb_interface *intf, if (res) goto out3; queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); - - dev_info(&intf->dev, "%s, %s, %pM\n", - net->name, - usb_dev_id[dev_index].name, - net->dev_addr); + CARRIER_CHECK_DELAY); + dev_info(&intf->dev, "%s, %s, %pM\n", net->name, + usb_dev_id[dev_index].name, net->dev_addr); return 0; out3: usb_set_intfdata(intf, NULL); - free_skb_pool(pegasus); out2: free_all_urbs(pegasus); out1: @@ -1429,7 +1223,6 @@ static void pegasus_disconnect(struct usb_interface *intf) unregister_netdev(pegasus->net); unlink_all_urbs(pegasus); free_all_urbs(pegasus); - free_skb_pool(pegasus); if (pegasus->rx_skb != NULL) { dev_kfree_skb(pegasus->rx_skb); pegasus->rx_skb = NULL; diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h index 65b78b35b73c..d15646244fdf 100644 --- a/drivers/net/usb/pegasus.h +++ b/drivers/net/usb/pegasus.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net) + * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published @@ -13,7 +13,6 @@ #define HAS_HOME_PNA 0x40000000 #define PEGASUS_MTU 1536 -#define RX_SKBS 4 #define EPROM_WRITE 0x01 #define EPROM_READ 0x02 @@ -34,8 +33,6 @@ #define CTRL_URB_SLEEP 0x00000020 #define PEGASUS_UNPLUG 0x00000040 #define PEGASUS_RX_URB_FAIL 0x00000080 -#define ETH_REGS_CHANGE 0x40000000 -#define ETH_REGS_CHANGED 0x80000000 #define RX_MULTICAST 2 #define RX_PROMISCUOUS 4 @@ -96,12 +93,8 @@ typedef struct pegasus { int intr_interval; struct tasklet_struct rx_tl; struct delayed_work carrier_check; - struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; - struct sk_buff *rx_pool[RX_SKBS]; + struct urb *rx_urb, *tx_urb, *intr_urb; struct sk_buff *rx_skb; - struct usb_ctrlrequest dr; - wait_queue_head_t ctrl_wait; - spinlock_t rx_pool_lock; int chip; unsigned char intr_buff[8]; __u8 tx_buff[PEGASUS_MTU]; diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index 79ab2435d9d3..a923d61c6fc5 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -413,11 +413,10 @@ static void sierra_net_handle_lsi(struct usbnet *dev, char *data, if (link_up) { sierra_net_set_ctx_index(priv, hh->msgspecific.byte); priv->link_up = 1; - netif_carrier_on(dev->net); } else { priv->link_up = 0; - netif_carrier_off(dev->net); } + usbnet_link_change(dev, link_up, 0); } static void sierra_net_dosync(struct usbnet *dev) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 51f3192f3931..1e5a9b72650e 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -938,6 +938,27 @@ static const struct ethtool_ops usbnet_ethtool_ops = { /*-------------------------------------------------------------------------*/ +static void __handle_link_change(struct usbnet *dev) +{ + if (!test_bit(EVENT_DEV_OPEN, &dev->flags)) + return; + + if (!netif_carrier_ok(dev->net)) { + /* kill URBs for reading packets to save bus bandwidth */ + unlink_urbs(dev, &dev->rxq); + + /* + * tx_timeout will unlink URBs for sending packets and + * tx queue is stopped by netcore after link becomes off + */ + } else { + /* submitting URBs for reading packets */ + tasklet_schedule(&dev->bh); + } + + clear_bit(EVENT_LINK_CHANGE, &dev->flags); +} + /* work that cannot be done in interrupt context uses keventd. * * NOTE: with 2.5 we could do more of this using completion callbacks, @@ -1035,8 +1056,14 @@ skip_reset: } else { usb_autopm_put_interface(dev->intf); } + + /* handle link change from link resetting */ + __handle_link_change(dev); } + if (test_bit (EVENT_LINK_CHANGE, &dev->flags)) + __handle_link_change(dev); + if (dev->flags) netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); } @@ -1286,6 +1313,7 @@ static void usbnet_bh (unsigned long param) // or are we maybe short a few urbs? } else if (netif_running (dev->net) && netif_device_present (dev->net) && + netif_carrier_ok(dev->net) && !timer_pending (&dev->delay) && !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; @@ -1521,7 +1549,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) netif_device_attach (net); if (dev->driver_info->flags & FLAG_LINK_INTR) - netif_carrier_off(net); + usbnet_link_change(dev, 0, 0); return 0; @@ -1653,6 +1681,21 @@ int usbnet_manage_power(struct usbnet *dev, int on) } EXPORT_SYMBOL(usbnet_manage_power); +void usbnet_link_change(struct usbnet *dev, bool link, bool need_reset) +{ + /* update link after link is reseted */ + if (link && !need_reset) + netif_carrier_on(dev->net); + else + netif_carrier_off(dev->net); + + if (need_reset && link) + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + else + usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); +} +EXPORT_SYMBOL(usbnet_link_change); + /*-------------------------------------------------------------------------*/ static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, u16 value, u16 index, void *data, u16 size) |