Commit 9dbfec80 authored by Petko Manolov's avatar Petko Manolov Committed by Greg Kroah-Hartman

[PATCH] pegasus & rtl8150

I chose a little bit more restrictive license for my drivers.
Rx skb pool introduced in pegasus driver and the pool locking in rtl8150
is refined.
parent 6c9a20c9
/* /*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller * Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
**
** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
**
**
** ChangeLog:
** .... Most of the time spend reading sources & docs.
** v0.2.x First official release for the Linux kernel.
** v0.3.0 Beutified and structured, some bugs fixed.
** v0.3.x URBifying bulk requests and bugfixing. First relatively
** stable release. Still can touch device's registers only
** from top-halves.
** v0.4.0 Control messages remained unurbified are now URBs.
** Now we can touch the HW at any time.
** v0.4.9 Control urbs again use process context to wait. Argh...
** Some long standing bugs (enable_net_traffic) fixed.
** Also nasty trick about resubmiting control urb from
** interrupt context used. Please let me know how it
** behaves. Pegasus II support added since this version.
** TODO: suppressing HCD warnings spewage on disconnect.
** v0.4.13 Ethernet address is now set at probe(), not at open()
** time as this seems to break dhcpd.
** v0.5.0 branch to 2.5.x kernels
** v0.5.1 ethtool support added
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is free software; you can redistribute it and/or modify
* but WITHOUT ANY WARRANTY; without even the implied warranty of * it under the terms of the GNU General Public License version 2 as
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * published by the Free Software Foundation.
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * ChangeLog:
* along with this program; if not, write to the Free Software * .... Most of the time spent on reading sources & docs.
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * v0.2.x First official release for the Linux kernel.
* v0.3.0 Beutified and structured, some bugs fixed.
* v0.3.x URBifying bulk requests and bugfixing. First relatively
* stable release. Still can touch device's registers only
* from top-halves.
* v0.4.0 Control messages remained unurbified are now URBs.
* Now we can touch the HW at any time.
* v0.4.9 Control urbs again use process context to wait. Argh...
* Some long standing bugs (enable_net_traffic) fixed.
* Also nasty trick about resubmiting control urb from
* interrupt context used. Please let me know how it
* behaves. Pegasus II support added since this version.
* TODO: suppressing HCD warnings spewage on disconnect.
* v0.4.13 Ethernet address is now set at probe(), not at open()
* time as this seems to break dhcpd.
* v0.5.0 branch to 2.5.x kernels
* 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.
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -58,14 +46,13 @@ ...@@ -58,14 +46,13 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.5.4 (2002/04/11)" #define DRIVER_VERSION "v0.5.6 (2002/06/23)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
static const char driver_name[] = "pegasus"; static const char driver_name[] = "pegasus";
#define PEGASUS_USE_INTR #undef PEGASUS_WRITE_EEPROM
#define PEGASUS_WRITE_EEPROM
#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ #define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
BMSR_100FULL | BMSR_ANEGCAPABLE) BMSR_100FULL | BMSR_ANEGCAPABLE)
...@@ -499,13 +486,57 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) ...@@ -499,13 +486,57 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
return 0; return 0;
} }
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;
pegasus->rx_pool[i]->dev = pegasus->net;
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) static void read_bulk_callback(struct urb *urb)
{ {
pegasus_t *pegasus = urb->context; pegasus_t *pegasus = urb->context;
struct net_device *net; struct net_device *net;
int count = urb->actual_length; int rx_status, count = urb->actual_length;
int rx_status;
struct sk_buff *skb;
__u16 pkt_len; __u16 pkt_len;
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING)) if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
...@@ -519,7 +550,7 @@ static void read_bulk_callback(struct urb *urb) ...@@ -519,7 +550,7 @@ static void read_bulk_callback(struct urb *urb)
case 0: case 0:
break; break;
case -ETIMEDOUT: case -ETIMEDOUT:
dbg("reset MAC"); dbg("%s: reset MAC", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY; pegasus->flags &= ~PEGASUS_RX_BUSY;
break; break;
case -ENOENT: case -ENOENT:
...@@ -546,23 +577,24 @@ static void read_bulk_callback(struct urb *urb) ...@@ -546,23 +577,24 @@ static void read_bulk_callback(struct urb *urb)
} }
pkt_len = (rx_status & 0xfff) - 8; pkt_len = (rx_status & 0xfff) - 8;
if (!pegasus->rx_skb) if (pegasus->rx_skb == NULL)
goto tl_sched; printk("%s: rx_skb == NULL\n", __FUNCTION__);
/*
** we are sure at this point pegasus->rx_skb != NULL
** so we go ahead and pass up the packet.
*/
skb_put(pegasus->rx_skb, pkt_len); skb_put(pegasus->rx_skb, pkt_len);
pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net); pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
netif_rx(pegasus->rx_skb); netif_rx(pegasus->rx_skb);
if (!(skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
pegasus->rx_skb = NULL;
goto tl_sched;
}
skb->dev = net;
skb_reserve(skb, 2);
pegasus->rx_skb = skb;
pegasus->stats.rx_packets++; pegasus->stats.rx_packets++;
pegasus->stats.rx_bytes += pkt_len; pegasus->stats.rx_bytes += pkt_len;
spin_lock(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus);
spin_unlock(&pegasus->rx_pool_lock);
if (pegasus->rx_skb == NULL)
goto tl_sched;
goon: goon:
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb, FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1), usb_rcvbulkpipe(pegasus->usb, 1),
...@@ -587,11 +619,19 @@ static void rx_fixup(unsigned long data) ...@@ -587,11 +619,19 @@ static void rx_fixup(unsigned long data)
pegasus = (pegasus_t *)data; pegasus = (pegasus_t *)data;
spin_lock_irq(&pegasus->rx_pool_lock);
fill_skb_pool(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
if (pegasus->flags & PEGASUS_RX_URB_FAIL) if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb) if (pegasus->rx_skb)
goto try_again; goto try_again;
if (pegasus->rx_skb == NULL) {
if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2))) { spin_lock_irq(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
}
if (pegasus->rx_skb == NULL) {
warn("wow, low on memory");
tasklet_schedule(&pegasus->rx_tl); tasklet_schedule(&pegasus->rx_tl);
return; return;
} }
...@@ -625,7 +665,6 @@ static void write_bulk_callback(struct urb *urb) ...@@ -625,7 +665,6 @@ static void write_bulk_callback(struct urb *urb)
netif_wake_queue(pegasus->net); netif_wake_queue(pegasus->net);
} }
#ifdef PEGASUS_USE_INTR
static void intr_callback(struct urb *urb) static void intr_callback(struct urb *urb)
{ {
pegasus_t *pegasus = urb->context; pegasus_t *pegasus = urb->context;
...@@ -662,7 +701,6 @@ static void intr_callback(struct urb *urb) ...@@ -662,7 +701,6 @@ static void intr_callback(struct urb *urb)
} }
} }
} }
#endif
static void pegasus_tx_timeout(struct net_device *net) static void pegasus_tx_timeout(struct net_device *net)
{ {
...@@ -748,15 +786,62 @@ static void set_carrier(struct net_device *net) ...@@ -748,15 +786,62 @@ static void set_carrier(struct net_device *net)
} }
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)
{
usb_unlink_urb(pegasus->intr_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_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;
}
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) static int pegasus_open(struct net_device *net)
{ {
pegasus_t *pegasus = (pegasus_t *) net->priv; pegasus_t *pegasus = (pegasus_t *) net->priv;
int res; int res;
if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2))) if (pegasus->rx_skb == NULL)
pegasus->rx_skb = pull_skb(pegasus);
/*
** Note: no point to free the pool. it is empty :-)
*/
if (!pegasus->rx_skb)
return -ENOMEM; return -ENOMEM;
pegasus->rx_skb->dev = net;
skb_reserve(pegasus->rx_skb, 2);
down(&pegasus->sem); down(&pegasus->sem);
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb, FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
...@@ -765,19 +850,20 @@ static int pegasus_open(struct net_device *net) ...@@ -765,19 +850,20 @@ static int pegasus_open(struct net_device *net)
read_bulk_callback, pegasus); read_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)))
warn("%s: failed rx_urb %d", __FUNCTION__, res); warn("%s: failed rx_urb %d", __FUNCTION__, res);
#ifdef PEGASUS_USE_INTR
FILL_INT_URB(pegasus->intr_urb, pegasus->usb, FILL_INT_URB(pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3), usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff), pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval); intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)))
warn("%s: failed intr_urb %d", __FUNCTION__, res); warn("%s: failed intr_urb %d", __FUNCTION__, res);
#endif
netif_start_queue(net); netif_start_queue(net);
pegasus->flags |= PEGASUS_RUNNING; pegasus->flags |= PEGASUS_RUNNING;
if ((res = enable_net_traffic(net, pegasus->usb))) { if ((res = enable_net_traffic(net, pegasus->usb))) {
err("can't enable_net_traffic() - %d", res); err("can't enable_net_traffic() - %d", res);
res = -EIO; res = -EIO;
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->intr_urb);
free_skb_pool(pegasus);
goto exit; goto exit;
} }
set_carrier(net); set_carrier(net);
...@@ -797,13 +883,7 @@ static int pegasus_close(struct net_device *net) ...@@ -797,13 +883,7 @@ static int pegasus_close(struct net_device *net)
netif_stop_queue(net); netif_stop_queue(net);
if (!(pegasus->flags & PEGASUS_UNPLUG)) if (!(pegasus->flags & PEGASUS_UNPLUG))
disable_net_traffic(pegasus); disable_net_traffic(pegasus);
unlink_all_urbs(pegasus);
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->ctrl_urb);
#ifdef PEGASUS_USE_INTR
usb_unlink_urb(pegasus->intr_urb);
#endif
up(&pegasus->sem); up(&pegasus->sem);
return 0; return 0;
...@@ -986,38 +1066,14 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -986,38 +1066,14 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
pegasus->dev_index = dev_index; pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait); init_waitqueue_head(&pegasus->ctrl_wait);
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); if (!alloc_urbs(pegasus)) {
if (!pegasus->ctrl_urb) {
kfree(pegasus);
return NULL;
}
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
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);
kfree(pegasus);
return NULL;
}
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);
kfree(pegasus); kfree(pegasus);
return NULL; return NULL;
} }
net = init_etherdev(NULL, 0); net = init_etherdev(NULL, 0);
if (!net) { if (!net) {
usb_free_urb(pegasus->tx_urb); free_all_urbs(pegasus);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus); kfree(pegasus);
return NULL; return NULL;
} }
...@@ -1039,32 +1095,26 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1039,32 +1095,26 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
net->set_multicast_list = pegasus_set_multicast; net->set_multicast_list = pegasus_set_multicast;
net->get_stats = pegasus_netdev_stats; net->get_stats = pegasus_netdev_stats;
net->mtu = PEGASUS_MTU; net->mtu = PEGASUS_MTU;
spin_lock_init(&pegasus->rx_pool_lock);
pegasus->features = usb_dev_id[dev_index].private; pegasus->features = usb_dev_id[dev_index].private;
#ifdef PEGASUS_USE_INTR
get_interrupt_interval(pegasus); get_interrupt_interval(pegasus);
#endif
if (reset_mac(pegasus)) { if (reset_mac(pegasus)) {
err("can't reset MAC"); err("can't reset MAC");
unregister_netdev(pegasus->net); unregister_netdev(pegasus->net);
usb_free_urb(pegasus->tx_urb); free_all_urbs(pegasus);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus->net); kfree(pegasus->net);
kfree(pegasus); kfree(pegasus);
pegasus = NULL; pegasus = NULL;
goto exit; goto exit;
} }
info("%s: %s", net->name, usb_dev_id[dev_index].name);
set_ethernet_addr(pegasus); set_ethernet_addr(pegasus);
fill_skb_pool(pegasus);
printk("%s: %s\n", net->name, usb_dev_id[dev_index].name);
if (pegasus->features & PEGASUS_II) { if (pegasus->features & PEGASUS_II) {
info("setup Pegasus II specific registers"); info("setup Pegasus II specific registers");
setup_pegasus_II(pegasus); setup_pegasus_II(pegasus);
} }
pegasus->phy = mii_phy_probe(pegasus); pegasus->phy = mii_phy_probe(pegasus);
if (pegasus->phy == 0xff) { if (pegasus->phy == 0xff) {
warn("can't locate MII phy, using default"); warn("can't locate MII phy, using default");
...@@ -1087,14 +1137,9 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr) ...@@ -1087,14 +1137,9 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
pegasus->flags |= PEGASUS_UNPLUG; pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev(pegasus->net); unregister_netdev(pegasus->net);
usb_put_dev(dev); usb_put_dev(dev);
usb_unlink_urb(pegasus->intr_urb); unlink_all_urbs(pegasus);
usb_unlink_urb(pegasus->tx_urb); free_all_urbs(pegasus);
usb_unlink_urb(pegasus->rx_urb); free_skb_pool(pegasus);
usb_unlink_urb(pegasus->ctrl_urb);
usb_free_urb(pegasus->intr_urb);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
if (pegasus->rx_skb) if (pegasus->rx_skb)
dev_kfree_skb(pegasus->rx_skb); dev_kfree_skb(pegasus->rx_skb);
kfree(pegasus->net); kfree(pegasus->net);
......
...@@ -2,18 +2,8 @@ ...@@ -2,18 +2,8 @@
* Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net) * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License version 2 as published
* the Free Software Foundation; either version 2 of the License, or * by the Free Software Foundation.
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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
*/ */
...@@ -23,6 +13,7 @@ ...@@ -23,6 +13,7 @@
#define HAS_HOME_PNA 0x40000000 #define HAS_HOME_PNA 0x40000000
#define PEGASUS_MTU 1536 #define PEGASUS_MTU 1536
#define RX_SKBS 4
#define EPROM_WRITE 0x01 #define EPROM_WRITE 0x01
#define EPROM_READ 0x02 #define EPROM_READ 0x02
...@@ -100,10 +91,12 @@ typedef struct pegasus { ...@@ -100,10 +91,12 @@ typedef struct pegasus {
int intr_interval; int intr_interval;
struct tasklet_struct rx_tl; struct tasklet_struct rx_tl;
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *rx_pool[RX_SKBS];
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
struct usb_ctrlrequest dr; struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait; wait_queue_head_t ctrl_wait;
struct semaphore sem; struct semaphore sem;
spinlock_t rx_pool_lock;
unsigned char intr_buff[8]; unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU]; __u8 tx_buff[PEGASUS_MTU];
__u8 eth_regs[4]; __u8 eth_regs[4];
......
/* /*
* Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* *
* 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 by the Free Software Foundation.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -19,7 +18,6 @@ ...@@ -19,7 +18,6 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/init.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* Version Information */ /* Version Information */
...@@ -106,7 +104,7 @@ unsigned long multicast_filter_limit = 32; ...@@ -106,7 +104,7 @@ unsigned long multicast_filter_limit = 32;
static void fill_skb_pool(rtl8150_t *); static void fill_skb_pool(rtl8150_t *);
static void free_skb_pool(rtl8150_t *); static void free_skb_pool(rtl8150_t *);
static struct sk_buff *pull_skb(rtl8150_t *); static inline struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_device *dev, void *ptr); static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum, static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id); const struct usb_device_id *id);
...@@ -312,7 +310,7 @@ static void read_bulk_callback(struct urb *urb) ...@@ -312,7 +310,7 @@ static void read_bulk_callback(struct urb *urb)
case -ENOENT: case -ENOENT:
return; /* the urb is in unlink state */ return; /* the urb is in unlink state */
case -ETIMEDOUT: case -ETIMEDOUT:
warn("reset needed may be?.."); warn("may be reset is needed?..");
goto goon; goto goon;
default: default:
warn("Rx status %d", urb->status); warn("Rx status %d", urb->status);
...@@ -331,13 +329,13 @@ static void read_bulk_callback(struct urb *urb) ...@@ -331,13 +329,13 @@ static void read_bulk_callback(struct urb *urb)
netif_rx(dev->rx_skb); netif_rx(dev->rx_skb);
dev->stats.rx_packets++; dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len; dev->stats.rx_bytes += pkt_len;
spin_lock(&dev->rx_pool_lock);
skb = pull_skb(dev); skb = pull_skb(dev);
spin_unlock(&dev->rx_pool_lock);
if (!skb) if (!skb)
goto resched; goto resched;
skb->dev = netdev;
skb_reserve(skb, 2);
dev->rx_skb = skb; dev->rx_skb = skb;
goon: goon:
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
...@@ -361,11 +359,16 @@ static void rx_fixup(unsigned long data) ...@@ -361,11 +359,16 @@ static void rx_fixup(unsigned long data)
dev = (rtl8150_t *)data; dev = (rtl8150_t *)data;
spin_lock_irq(&dev->rx_pool_lock);
fill_skb_pool(dev); fill_skb_pool(dev);
spin_unlock_irq(&dev->rx_pool_lock);
if (test_bit(RX_URB_FAIL, &dev->flags)) if (test_bit(RX_URB_FAIL, &dev->flags))
if (dev->rx_skb) if (dev->rx_skb)
goto try_again; goto try_again;
if (!(skb = pull_skb(dev))) spin_lock_irq(&dev->rx_pool_lock);
skb = pull_skb(dev);
spin_unlock_irq(&dev->rx_pool_lock);
if (skb == NULL)
goto tlsched; goto tlsched;
dev->rx_skb = skb; dev->rx_skb = skb;
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
...@@ -426,51 +429,41 @@ static void fill_skb_pool(rtl8150_t *dev) ...@@ -426,51 +429,41 @@ static void fill_skb_pool(rtl8150_t *dev)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int i; int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) { for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i]) if (dev->rx_skb_pool[i])
continue; continue;
skb = dev_alloc_skb(RTL8150_MTU + 2); skb = dev_alloc_skb(RTL8150_MTU + 2);
if (!skb) { if (!skb) {
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return; return;
} }
skb->dev = dev->netdev; skb->dev = dev->netdev;
skb_reserve(skb, 2); skb_reserve(skb, 2);
dev->rx_skb_pool[i] = skb; dev->rx_skb_pool[i] = skb;
} }
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
} }
static void free_skb_pool(rtl8150_t *dev) static void free_skb_pool(rtl8150_t *dev)
{ {
int i; int i;
spin_lock_irq(&dev->rx_pool_lock);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) for (i = 0; i < RX_SKB_POOL_SIZE; i++)
if (dev->rx_skb_pool[i]) if (dev->rx_skb_pool[i])
dev_kfree_skb(dev->rx_skb_pool[i]); dev_kfree_skb(dev->rx_skb_pool[i]);
spin_unlock_irq(&dev->rx_pool_lock);
} }
static struct sk_buff *pull_skb(rtl8150_t *dev) static inline struct sk_buff *pull_skb(rtl8150_t *dev)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int i; int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) { for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i]) { if (dev->rx_skb_pool[i]) {
skb = dev->rx_skb_pool[i]; skb = dev->rx_skb_pool[i];
dev->rx_skb_pool[i] = NULL; dev->rx_skb_pool[i] = NULL;
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return skb; return skb;
} }
} }
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return NULL; return NULL;
} }
...@@ -578,8 +571,8 @@ static int rtl8150_open(struct net_device *netdev) ...@@ -578,8 +571,8 @@ static int rtl8150_open(struct net_device *netdev)
if (dev == NULL) { if (dev == NULL) {
return -ENODEV; return -ENODEV;
} }
if (dev->rx_skb == NULL)
dev->rx_skb = pull_skb(dev); dev->rx_skb = pull_skb(dev);
if (!dev->rx_skb) if (!dev->rx_skb)
return -ENOMEM; return -ENOMEM;
...@@ -816,13 +809,13 @@ static void rtl8150_disconnect(struct usb_device *udev, void *ptr) ...@@ -816,13 +809,13 @@ static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
dev = NULL; dev = NULL;
} }
static int __init usb_rtl8150_init(void) int __init usb_rtl8150_init(void)
{ {
info(DRIVER_DESC " " DRIVER_VERSION); info(DRIVER_DESC " " DRIVER_VERSION);
return usb_register(&rtl8150_driver); return usb_register(&rtl8150_driver);
} }
static void __exit usb_rtl8150_exit(void) void __exit usb_rtl8150_exit(void)
{ {
usb_deregister(&rtl8150_driver); usb_deregister(&rtl8150_driver);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment