diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73051d1..501db20 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.1 simplified [get|set]_register(s), async update registers + * logic revisited, receive skb_pool removed. */ #include @@ -45,8 +48,8 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.6.14 (2006/09/27)" -#define DRIVER_AUTHOR "Petko Manolov " +#define DRIVER_VERSION "v0.9.3 (2013/04/09)" +#define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" static const char driver_name[] = "pegasus"; @@ -108,299 +111,154 @@ 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, +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, +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) +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) +static int update_eth_regs_async(pegasus_t * pegasus) { - int ret; + int ret = -ENOMEM; + struct urb *async_urb; + struct usb_ctrlrequest *req; - 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; + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); + if (req == NULL) + return ret; - 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 ((async_urb = usb_alloc_urb(0, GFP_ATOMIC)) == 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); - if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { + if ((ret = usb_submit_urb(async_urb, GFP_ATOMIC))) { 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) { pegasus_t *pegasus = netdev_priv(dev); - u16 res; + __u16 res; read_mii_word(pegasus, phy_id, loc, &res); 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) +static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) { int i; __u8 tmp; @@ -420,18 +278,16 @@ static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) } if (i >= REG_TIMEOUT) goto fail; - ret = get_registers(pegasus, EpromData, 2, &retdatai); *retdata = le16_to_cpu(retdatai); return ret; - fail: netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); return -ETIMEDOUT; } #ifdef PEGASUS_WRITE_EEPROM -static inline void enable_eprom_write(pegasus_t *pegasus) +static inline void enable_eprom_write(pegasus_t * pegasus) { __u8 tmp; int ret; @@ -440,7 +296,7 @@ static inline void enable_eprom_write(pegasus_t *pegasus) set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); } -static inline void disable_eprom_write(pegasus_t *pegasus) +static inline void disable_eprom_write(pegasus_t * pegasus) { __u8 tmp; int ret; @@ -450,7 +306,7 @@ static inline void disable_eprom_write(pegasus_t *pegasus) set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE); } -static int write_eprom_word(pegasus_t *pegasus, __u8 index, __u16 data) +static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) { int i; __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE }; @@ -473,16 +329,14 @@ static int write_eprom_word(pegasus_t *pegasus, __u8 index, __u16 data) disable_eprom_write(pegasus); if (i >= REG_TIMEOUT) goto fail; - return ret; - fail: netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); return -ETIMEDOUT; } -#endif /* PEGASUS_WRITE_EEPROM */ +#endif /* PEGASUS_WRITE_EEPROM */ -static inline void get_node_id(pegasus_t *pegasus, __u8 *id) +static inline void get_node_id(pegasus_t * pegasus, __u8 * id) { int i; __u16 w16; @@ -493,7 +347,7 @@ static inline void get_node_id(pegasus_t *pegasus, __u8 *id) } } -static void set_ethernet_addr(pegasus_t *pegasus) +static void set_ethernet_addr(pegasus_t * pegasus) { __u8 node_id[6]; @@ -506,7 +360,7 @@ static void set_ethernet_addr(pegasus_t *pegasus) memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id)); } -static inline int reset_mac(pegasus_t *pegasus) +static inline int reset_mac(pegasus_t * pegasus) { __u8 data = 0x8; int i; @@ -528,7 +382,6 @@ static inline int reset_mac(pegasus_t *pegasus) } if (i == REG_TIMEOUT) return -ETIMEDOUT; - if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { set_register(pegasus, Gpio0, 0x24); @@ -537,18 +390,17 @@ 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; } -static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) +static void enable_net_traffic(struct net_device *dev, struct usb_device *usb) { __u16 linkpart; __u8 data[4]; pegasus_t *pegasus = netdev_priv(dev); - int ret; read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); data[0] = 0xc9; @@ -562,62 +414,16 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) data[2] = loopback ? 0x09 : 0x01; memcpy(pegasus->eth_regs, data, sizeof(data)); - ret = set_registers(pegasus, EthCtrl0, 3, data); + set_registers(pegasus, EthCtrl0, 3, data); if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { - u16 auxmode; + __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) @@ -643,7 +449,7 @@ static void read_bulk_callback(struct urb *urb) netif_dbg(pegasus, rx_err, net, "reset MAC\n"); pegasus->flags &= ~PEGASUS_RX_BUSY; break; - case -EPIPE: /* stall, or disconnect from TT */ + case -EPIPE: /* stall, or disconnect from TT */ /* FIXME schedule work to clear the halt */ netif_warn(pegasus, rx_err, net, "no rx stall recovery\n"); return; @@ -665,16 +471,16 @@ static void read_bulk_callback(struct urb *urb) netif_dbg(pegasus, rx_err, net, "RX packet error %x\n", rx_status); pegasus->stats.rx_errors++; - if (rx_status & 0x06) /* long or runt */ + if (rx_status & 0x06) /* long or runt */ pegasus->stats.rx_length_errors++; if (rx_status & 0x08) pegasus->stats.rx_crc_errors++; - if (rx_status & 0x10) /* extra bits */ + if (rx_status & 0x10) /* extra bits */ pegasus->stats.rx_frame_errors++; goto goon; } if (pegasus->chip == 0x8513) { - pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); + pkt_len = le32_to_cpu(*(__le32 *) urb->transfer_buffer); pkt_len &= 0x0fff; pegasus->rx_skb->data += 2; } else { @@ -683,14 +489,12 @@ static void read_bulk_callback(struct urb *urb) pkt_len &= 0xfff; pkt_len -= 8; } - /* * If the packet is unreasonably long, quietly drop it rather than * kernel panicing by calling skb_put. */ if (pkt_len > PEGASUS_MTU) goto goon; - /* * at this point we are sure pegasus->rx_skb != NULL * so we go ahead and pass up the packet. @@ -704,10 +508,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; goon: @@ -724,9 +526,7 @@ goon: } else { pegasus->flags &= ~PEGASUS_RX_URB_FAIL; } - return; - tl_sched: tasklet_schedule(&pegasus->rx_tl); } @@ -734,24 +534,22 @@ 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 +565,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) @@ -779,12 +575,9 @@ static void write_bulk_callback(struct urb *urb) if (!pegasus) return; - net = pegasus->net; - if (!netif_device_present(net) || !netif_running(net)) return; - switch (status) { case -EPIPE: /* FIXME schedule_work() to clear the tx halt */ @@ -802,8 +595,7 @@ static void write_bulk_callback(struct urb *urb) case 0: break; } - - net->trans_start = jiffies; /* prevent tx timeout */ + net->trans_start = jiffies; /* prevent tx timeout */ netif_wake_queue(net); } @@ -816,7 +608,6 @@ static void intr_callback(struct urb *urb) if (!pegasus) return; net = pegasus->net; - switch (status) { case 0: break; @@ -830,13 +621,12 @@ static void intr_callback(struct urb *urb) */ netif_dbg(pegasus, timer, net, "intr status %d\n", status); } - if (urb->actual_length >= 6) { u8 *d = urb->transfer_buffer; /* byte 0 == tx_status1, reg 2B */ - if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL - |LATE_COL|JABBER_TIMEOUT)) { + if (d[0] & (TX_UNDERRUN | EXCESSIVE_COL + | LATE_COL | JABBER_TIMEOUT)) { pegasus->stats.tx_errors++; if (d[0] & TX_UNDERRUN) pegasus->stats.tx_fifo_errors++; @@ -854,7 +644,6 @@ static void intr_callback(struct urb *urb) /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; } - res = usb_submit_urb(urb, GFP_ATOMIC); if (res == -ENODEV) netif_device_detach(pegasus->net); @@ -872,7 +661,7 @@ static void pegasus_tx_timeout(struct net_device *net) } static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb, - struct net_device *net) + struct net_device *net) { pegasus_t *pegasus = netdev_priv(net); int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; @@ -890,10 +679,10 @@ static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb, if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) { netif_warn(pegasus, tx_err, net, "fail tx, %d\n", res); switch (res) { - case -EPIPE: /* stall, or disconnect from TT */ + case -EPIPE: /* stall, or disconnect from TT */ /* cleanup should already have been scheduled */ break; - case -ENODEV: /* disconnect() upcoming */ + case -ENODEV: /* disconnect() upcoming */ case -EPERM: netif_device_detach(pegasus->net); break; @@ -915,14 +704,14 @@ static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) return &((pegasus_t *) netdev_priv(dev))->stats; } -static inline void disable_net_traffic(pegasus_t *pegasus) +static inline void disable_net_traffic(pegasus_t * pegasus) { __le16 tmp = cpu_to_le16(0); set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp); } -static inline void get_interrupt_interval(pegasus_t *pegasus) +static inline void get_interrupt_interval(pegasus_t * pegasus) { u16 data; u8 interval; @@ -935,7 +724,7 @@ static inline void get_interrupt_interval(pegasus_t *pegasus) "intr interval changed from %ums to %ums\n", interval, 0x80); interval = 0x80; - data = (data & 0x00FF) | ((u16)interval << 8); + data = (data & 0x00FF) | ((u16) interval << 8); #ifdef PEGASUS_WRITE_EEPROM write_eprom_word(pegasus, 4, data); #endif @@ -951,71 +740,58 @@ static void set_carrier(struct net_device *net) if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) return; - if (tmp & BMSR_LSTATUS) netif_carrier_on(net); else netif_carrier_off(net); } -static void free_all_urbs(pegasus_t *pegasus) +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) +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) +static int alloc_urbs(pegasus_t * pegasus) { - pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pegasus->ctrl_urb) - return 0; pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!pegasus->rx_urb) { - usb_free_urb(pegasus->ctrl_urb); return 0; } 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; } 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 1; } 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); - usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), pegasus->rx_skb->data, PEGASUS_MTU + 8, @@ -1026,7 +802,6 @@ static int pegasus_open(struct net_device *net) netif_dbg(pegasus, ifup, net, "failed rx_urb, %d\n", res); goto exit; } - usb_fill_int_urb(pegasus->intr_urb, pegasus->usb, usb_rcvintpipe(pegasus->usb, 3), pegasus->intr_buff, sizeof(pegasus->intr_buff), @@ -1038,18 +813,9 @@ static int pegasus_open(struct net_device *net) usb_kill_urb(pegasus->rx_urb); goto exit; } - if ((res = enable_net_traffic(net, pegasus->usb))) { - 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; - } + enable_net_traffic(net, pegasus->usb); set_carrier(net); netif_start_queue(net); - netif_dbg(pegasus, ifup, net, "open\n"); res = 0; exit: return res; @@ -1081,25 +847,22 @@ static void pegasus_get_drvinfo(struct net_device *dev, /* also handles three patterns of some kind in hardware */ #define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY) -static void -pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +static void pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - pegasus_t *pegasus = netdev_priv(dev); + pegasus_t *pegasus = netdev_priv(dev); wol->supported = WAKE_MAGIC | WAKE_PHY; wol->wolopts = pegasus->wolopts; } -static int -pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +static int pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - pegasus_t *pegasus = netdev_priv(dev); - u8 reg78 = 0x04; - int ret; + pegasus_t *pegasus = netdev_priv(dev); + u8 reg78 = 0x04; + int r; if (wol->wolopts & ~WOL_SUPPORTED) return -EINVAL; - if (wol->wolopts & WAKE_MAGIC) reg78 |= 0x80; if (wol->wolopts & WAKE_PHY) @@ -1111,11 +874,10 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) pegasus->eth_regs[0] &= ~0x10; pegasus->wolopts = wol->wolopts; - ret = set_register(pegasus, WakeupControl, reg78); - if (!ret) - ret = device_set_wakeup_enable(&pegasus->usb->dev, - wol->wolopts); - return ret; + r = set_register(pegasus, WakeupControl, reg78); + if (!r) + r = device_set_wakeup_enable(&pegasus->usb->dev, wol->wolopts); + return r; } static inline void pegasus_reset_wol(struct net_device *dev) @@ -1123,7 +885,7 @@ static inline void pegasus_reset_wol(struct net_device *dev) struct ethtool_wolinfo wol; memset(&wol, 0, sizeof wol); - (void) pegasus_set_wol(dev, &wol); + (void)pegasus_set_wol(dev, &wol); } static int @@ -1133,6 +895,7 @@ pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) pegasus = netdev_priv(dev); mii_ethtool_gset(&pegasus->mii, ecmd); + return 0; } @@ -1140,30 +903,35 @@ static int pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { pegasus_t *pegasus = netdev_priv(dev); + return mii_ethtool_sset(&pegasus->mii, ecmd); } static int pegasus_nway_reset(struct net_device *dev) { pegasus_t *pegasus = netdev_priv(dev); + return mii_nway_restart(&pegasus->mii); } static u32 pegasus_get_link(struct net_device *dev) { pegasus_t *pegasus = netdev_priv(dev); + return mii_link_ok(&pegasus->mii); } static u32 pegasus_get_msglevel(struct net_device *dev) { pegasus_t *pegasus = netdev_priv(dev); + return pegasus->msg_enable; } static void pegasus_set_msglevel(struct net_device *dev, u32 v) { pegasus_t *pegasus = netdev_priv(dev); + pegasus->msg_enable = v; } @@ -1181,7 +949,7 @@ static const struct ethtool_ops ops = { static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { - __u16 *data = (__u16 *) &rq->ifr_ifru; + __u16 *data = (__u16 *) & rq->ifr_ifru; pegasus_t *pegasus = netdev_priv(net); int res; @@ -1195,7 +963,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: @@ -1218,15 +986,12 @@ static void pegasus_set_multicast(struct net_device *net) } else { pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; + netif_dbg(pegasus, link, net, "general mode\n"); } - - 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) +static __u8 mii_phy_probe(pegasus_t * pegasus) { int i; __u16 tmp; @@ -1238,11 +1003,10 @@ static __u8 mii_phy_probe(pegasus_t *pegasus) else return i; } - return 0xff; } -static inline void setup_pegasus_II(pegasus_t *pegasus) +static inline void setup_pegasus_II(pegasus_t * pegasus) { __u8 data = 0xa5; @@ -1253,26 +1017,21 @@ static inline void setup_pegasus_II(pegasus_t *pegasus) set_register(pegasus, Reg7b, 0); else set_register(pegasus, Reg7b, 2); - set_register(pegasus, 0x83, data); get_registers(pegasus, 0x83, 1, &data); - if (data == 0xa5) pegasus->chip = 0x8513; else pegasus->chip = 0; - set_register(pegasus, 0x80, 0xc0); set_register(pegasus, 0x83, 0xff); set_register(pegasus, 0x84, 0x01); - if (pegasus->features & HAS_HOME_PNA && mii_mode) set_register(pegasus, Reg81, 6); else set_register(pegasus, Reg81, 2); } - static int pegasus_count; static struct workqueue_struct *pegasus_workqueue; #define CARRIER_CHECK_DELAY (2 * HZ) @@ -1281,10 +1040,9 @@ static void check_carrier(struct work_struct *work) { pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); set_carrier(pegasus->net); - if (!(pegasus->flags & PEGASUS_UNPLUG)) { + if (!(pegasus->flags & PEGASUS_UNPLUG)) queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); - } + CARRIER_CHECK_DELAY); } static int pegasus_blacklisted(struct usb_device *udev) @@ -1299,11 +1057,11 @@ static int pegasus_blacklisted(struct usb_device *udev) (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) && (udd->bDeviceProtocol == 1)) return 1; - return 0; } -/* we rely on probe() and remove() being serialized so we +/* + * we rely on probe() and remove() being serialized so we * don't need extra locking on pegasus_count. */ static void pegasus_dec_workqueue(void) @@ -1340,14 +1098,13 @@ 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)) { dev_err(&intf->dev, "can't allocate %s\n", "urbs"); goto out1; } - tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); + tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long)pegasus); INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); @@ -1355,7 +1112,6 @@ static int pegasus_probe(struct usb_interface *intf, pegasus->usb = dev; pegasus->net = net; - net->watchdog_timeo = PEGASUS_TX_TIMEOUT; net->netdev_ops = &pegasus_netdev_ops; SET_ETHTOOL_OPS(net, &ops); @@ -1364,9 +1120,9 @@ 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); + | NETIF_MSG_PROBE + | NETIF_MSG_LINK); pegasus->features = usb_dev_id[dev_index].private; get_interrupt_interval(pegasus); @@ -1376,7 +1132,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 +1149,12 @@ 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 +1179,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; @@ -1466,21 +1215,21 @@ static int pegasus_resume(struct usb_interface *intf) intr_callback(pegasus->intr_urb); } queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, - CARRIER_CHECK_DELAY); + CARRIER_CHECK_DELAY); return 0; } static const struct net_device_ops pegasus_netdev_ops = { - .ndo_open = pegasus_open, - .ndo_stop = pegasus_close, - .ndo_do_ioctl = pegasus_ioctl, - .ndo_start_xmit = pegasus_start_xmit, - .ndo_set_rx_mode = pegasus_set_multicast, - .ndo_get_stats = pegasus_netdev_stats, - .ndo_tx_timeout = pegasus_tx_timeout, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, + .ndo_open = pegasus_open, + .ndo_stop = pegasus_close, + .ndo_do_ioctl = pegasus_ioctl, + .ndo_start_xmit = pegasus_start_xmit, + .ndo_set_rx_mode = pegasus_set_multicast, + .ndo_get_stats = pegasus_netdev_stats, + .ndo_tx_timeout = pegasus_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static struct usb_driver pegasus_driver = { @@ -1500,7 +1249,7 @@ static void __init parse_id(char *id) if ((token = strsep(&id, ":")) != NULL) name = token; - /* name now points to a null terminated string*/ + /* name now points to a null terminated string */ if ((token = strsep(&id, ":")) != NULL) vendor_id = simple_strtoul(token, NULL, 16); if ((token = strsep(&id, ":")) != NULL) @@ -1514,7 +1263,7 @@ static void __init parse_id(char *id) if (device_id > 0x10000 || device_id == 0) return; - for (i = 0; usb_dev_id[i].name; i++); + for (i = 0; usb_dev_id[i].name; i++) ; usb_dev_id[i].name = name; usb_dev_id[i].vendor = vendor_id; usb_dev_id[i].device = device_id;