2005-04-17 06:20:36 +08:00
|
|
|
|
/*
|
2005-09-01 00:54:50 +08:00
|
|
|
|
* USB Network driver infrastructure
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
* Copyright (C) 2000-2005 by David Brownell
|
2005-04-17 06:20:36 +08:00
|
|
|
|
* Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
|
|
|
|
|
*
|
|
|
|
|
* 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,
|
|
|
|
|
* 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
|
2013-12-06 22:28:46 +08:00
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2005-04-17 06:20:36 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is a generic "USB networking" framework that works with several
|
2005-09-01 00:54:50 +08:00
|
|
|
|
* kinds of full and high speed networking devices: host-to-host cables,
|
|
|
|
|
* smart usb peripherals, and actual Ethernet adapters.
|
2005-04-17 06:20:36 +08:00
|
|
|
|
*
|
2005-09-01 00:54:50 +08:00
|
|
|
|
* These devices usually differ in terms of control protocols (if they
|
|
|
|
|
* even have one!) and sometimes they define new framing to wrap or batch
|
|
|
|
|
* Ethernet packets. Otherwise, they talk to USB pretty much the same,
|
|
|
|
|
* so interface (un)binding, endpoint I/O queues, fault handling, and other
|
|
|
|
|
* issues can usefully be addressed by this framework.
|
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
// #define DEBUG // error path messages, extra info
|
|
|
|
|
// #define VERBOSE // more; success messages
|
|
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
|
#include <linux/etherdevice.h>
|
2009-04-18 15:24:17 +08:00
|
|
|
|
#include <linux/ctype.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
#include <linux/ethtool.h>
|
|
|
|
|
#include <linux/workqueue.h>
|
|
|
|
|
#include <linux/mii.h>
|
|
|
|
|
#include <linux/usb.h>
|
2008-01-26 06:51:45 +08:00
|
|
|
|
#include <linux/usb/usbnet.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
|
#include <linux/slab.h>
|
2010-07-23 11:18:08 +08:00
|
|
|
|
#include <linux/kernel.h>
|
2010-11-01 22:11:54 +08:00
|
|
|
|
#include <linux/pm_runtime.h>
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
|
|
|
|
|
#define DRIVER_VERSION "22-Aug-2005"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
|
|
|
|
|
* Several dozen bytes of IPv4 data can fit in two such transactions.
|
|
|
|
|
* One maximum size Ethernet packet takes twenty four of them.
|
|
|
|
|
* For high speed, each frame comfortably fits almost 36 max size
|
|
|
|
|
* Ethernet packets (so queues should be bigger).
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
*
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
* The goal is to let the USB host controller be busy for 5msec or
|
|
|
|
|
* more before an irq is required, under load. Jumbograms change
|
|
|
|
|
* the equation.
|
2005-04-17 06:20:36 +08:00
|
|
|
|
*/
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
#define MAX_QUEUE_MEMORY (60 * 1518)
|
|
|
|
|
#define RX_QLEN(dev) ((dev)->rx_qlen)
|
|
|
|
|
#define TX_QLEN(dev) ((dev)->tx_qlen)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
// reawaken network queue this soon after stopping; else watchdog barks
|
|
|
|
|
#define TX_TIMEOUT_JIFFIES (5*HZ)
|
|
|
|
|
|
2014-09-19 23:32:23 +08:00
|
|
|
|
/* throttle rx/tx briefly after some faults, so hub_wq might disconnect()
|
|
|
|
|
* us (it polls at HZ/4 usually) before we report too many false errors.
|
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
|
#define THROTTLE_JIFFIES (HZ/8)
|
|
|
|
|
|
|
|
|
|
// between wakeups
|
|
|
|
|
#define UNLINK_TIMEOUT_MS 3
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
// randomly generated ethernet address
|
|
|
|
|
static u8 node_id [ETH_ALEN];
|
|
|
|
|
|
|
|
|
|
static const char driver_name [] = "usbnet";
|
|
|
|
|
|
|
|
|
|
/* use ethtool to change the level for any given device */
|
|
|
|
|
static int msg_level = -1;
|
|
|
|
|
module_param (msg_level, int, 0);
|
|
|
|
|
MODULE_PARM_DESC (msg_level, "Override default message level");
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/* handles CDC Ethernet and many other network "bulk data" interfaces */
|
2005-09-01 00:53:10 +08:00
|
|
|
|
int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
int tmp;
|
|
|
|
|
struct usb_host_interface *alt = NULL;
|
|
|
|
|
struct usb_host_endpoint *in = NULL, *out = NULL;
|
|
|
|
|
struct usb_host_endpoint *status = NULL;
|
|
|
|
|
|
|
|
|
|
for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
|
|
|
|
|
unsigned ep;
|
|
|
|
|
|
|
|
|
|
in = out = status = NULL;
|
|
|
|
|
alt = intf->altsetting + tmp;
|
|
|
|
|
|
|
|
|
|
/* take the first altsetting with in-bulk + out-bulk;
|
|
|
|
|
* remember any status endpoint, just in case;
|
2011-05-10 16:16:21 +08:00
|
|
|
|
* ignore other endpoints and altsettings.
|
2005-04-17 06:20:36 +08:00
|
|
|
|
*/
|
|
|
|
|
for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
|
|
|
|
|
struct usb_host_endpoint *e;
|
|
|
|
|
int intr = 0;
|
|
|
|
|
|
|
|
|
|
e = alt->endpoint + ep;
|
|
|
|
|
switch (e->desc.bmAttributes) {
|
|
|
|
|
case USB_ENDPOINT_XFER_INT:
|
2006-10-27 00:03:01 +08:00
|
|
|
|
if (!usb_endpoint_dir_in(&e->desc))
|
2005-04-17 06:20:36 +08:00
|
|
|
|
continue;
|
|
|
|
|
intr = 1;
|
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
|
case USB_ENDPOINT_XFER_BULK:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-10-27 00:03:01 +08:00
|
|
|
|
if (usb_endpoint_dir_in(&e->desc)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (!intr && !in)
|
|
|
|
|
in = e;
|
|
|
|
|
else if (intr && !status)
|
|
|
|
|
status = e;
|
|
|
|
|
} else {
|
|
|
|
|
if (!out)
|
|
|
|
|
out = e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (in && out)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!alt || !in || !out)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if (alt->desc.bAlternateSetting != 0 ||
|
|
|
|
|
!(dev->driver_info->flags & FLAG_NO_SETINT)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber,
|
|
|
|
|
alt->desc.bAlternateSetting);
|
|
|
|
|
if (tmp < 0)
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
2007-02-16 10:52:30 +08:00
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev->in = usb_rcvbulkpipe (dev->udev,
|
|
|
|
|
in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
|
|
|
|
|
dev->out = usb_sndbulkpipe (dev->udev,
|
|
|
|
|
out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
|
|
|
|
|
dev->status = status;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2005-09-01 00:53:10 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2009-04-18 15:24:17 +08:00
|
|
|
|
int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
|
|
|
|
|
{
|
2015-01-23 05:27:12 +08:00
|
|
|
|
int tmp = -1, ret;
|
2009-04-18 15:24:17 +08:00
|
|
|
|
unsigned char buf [13];
|
|
|
|
|
|
2015-01-23 05:27:12 +08:00
|
|
|
|
ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf);
|
|
|
|
|
if (ret == 12)
|
|
|
|
|
tmp = hex2bin(dev->net->dev_addr, buf, 6);
|
|
|
|
|
if (tmp < 0) {
|
2009-04-18 15:24:17 +08:00
|
|
|
|
dev_dbg(&dev->udev->dev,
|
|
|
|
|
"bad MAC string %d fetch, %d\n", iMACAddress, tmp);
|
2015-01-23 05:27:12 +08:00
|
|
|
|
if (ret >= 0)
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
return ret;
|
2009-04-18 15:24:17 +08:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr);
|
|
|
|
|
|
2012-06-11 23:19:44 +08:00
|
|
|
|
static void intr_complete (struct urb *urb)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = urb->context;
|
|
|
|
|
int status = urb->status;
|
|
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
|
/* success */
|
|
|
|
|
case 0:
|
|
|
|
|
dev->driver_info->status(dev, urb);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* software-driven interface shutdown */
|
|
|
|
|
case -ENOENT: /* urb killed */
|
|
|
|
|
case -ESHUTDOWN: /* hardware gone */
|
|
|
|
|
netif_dbg(dev, ifdown, dev->net,
|
|
|
|
|
"intr shutdown, code %d\n", status);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* NOTE: not throttling like RX/TX, since this endpoint
|
|
|
|
|
* already polls infrequently
|
|
|
|
|
*/
|
|
|
|
|
default:
|
|
|
|
|
netdev_dbg(dev->net, "intr status %d\n", status);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = usb_submit_urb (urb, GFP_ATOMIC);
|
|
|
|
|
if (status != 0)
|
|
|
|
|
netif_err(dev, timer, dev->net,
|
|
|
|
|
"intr resubmit --> %d\n", status);
|
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
static int init_status (struct usbnet *dev, struct usb_interface *intf)
|
|
|
|
|
{
|
|
|
|
|
char *buf = NULL;
|
|
|
|
|
unsigned pipe = 0;
|
|
|
|
|
unsigned maxp;
|
|
|
|
|
unsigned period;
|
|
|
|
|
|
|
|
|
|
if (!dev->driver_info->status)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
pipe = usb_rcvintpipe (dev->udev,
|
|
|
|
|
dev->status->desc.bEndpointAddress
|
|
|
|
|
& USB_ENDPOINT_NUMBER_MASK);
|
|
|
|
|
maxp = usb_maxpacket (dev->udev, pipe, 0);
|
|
|
|
|
|
|
|
|
|
/* avoid 1 msec chatter: min 8 msec poll rate */
|
|
|
|
|
period = max ((int) dev->status->desc.bInterval,
|
|
|
|
|
(dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
|
|
|
|
|
|
2006-12-07 12:33:17 +08:00
|
|
|
|
buf = kmalloc (maxp, GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (buf) {
|
2006-12-07 12:33:17 +08:00
|
|
|
|
dev->interrupt = usb_alloc_urb (0, GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (!dev->interrupt) {
|
|
|
|
|
kfree (buf);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
} else {
|
|
|
|
|
usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
|
|
|
|
|
buf, maxp, intr_complete, dev, period);
|
2012-04-30 06:51:02 +08:00
|
|
|
|
dev->interrupt->transfer_flags |= URB_FREE_BUFFER;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev_dbg(&intf->dev,
|
|
|
|
|
"status ep%din, %d bytes period %d\n",
|
|
|
|
|
usb_pipeendpoint(pipe), maxp, period);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-05-26 03:31:32 +08:00
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 19:29:23 +08:00
|
|
|
|
/* Submit the interrupt URB if not previously submitted, increasing refcount */
|
|
|
|
|
int usbnet_status_start(struct usbnet *dev, gfp_t mem_flags)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
WARN_ON_ONCE(dev->interrupt == NULL);
|
|
|
|
|
if (dev->interrupt) {
|
|
|
|
|
mutex_lock(&dev->interrupt_mutex);
|
|
|
|
|
|
|
|
|
|
if (++dev->interrupt_count == 1)
|
|
|
|
|
ret = usb_submit_urb(dev->interrupt, mem_flags);
|
|
|
|
|
|
|
|
|
|
dev_dbg(&dev->udev->dev, "incremented interrupt URB count to %d\n",
|
|
|
|
|
dev->interrupt_count);
|
|
|
|
|
mutex_unlock(&dev->interrupt_mutex);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_status_start);
|
|
|
|
|
|
|
|
|
|
/* For resume; submit interrupt URB if previously submitted */
|
|
|
|
|
static int __usbnet_status_start_force(struct usbnet *dev, gfp_t mem_flags)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dev->interrupt_mutex);
|
|
|
|
|
if (dev->interrupt_count) {
|
|
|
|
|
ret = usb_submit_urb(dev->interrupt, mem_flags);
|
|
|
|
|
dev_dbg(&dev->udev->dev,
|
|
|
|
|
"submitted interrupt URB for resume\n");
|
|
|
|
|
}
|
|
|
|
|
mutex_unlock(&dev->interrupt_mutex);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Kill the interrupt URB if all submitters want it killed */
|
|
|
|
|
void usbnet_status_stop(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
if (dev->interrupt) {
|
|
|
|
|
mutex_lock(&dev->interrupt_mutex);
|
|
|
|
|
WARN_ON(dev->interrupt_count == 0);
|
|
|
|
|
|
|
|
|
|
if (dev->interrupt_count && --dev->interrupt_count == 0)
|
|
|
|
|
usb_kill_urb(dev->interrupt);
|
|
|
|
|
|
|
|
|
|
dev_dbg(&dev->udev->dev,
|
|
|
|
|
"decremented interrupt URB count to %d\n",
|
|
|
|
|
dev->interrupt_count);
|
|
|
|
|
mutex_unlock(&dev->interrupt_mutex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_status_stop);
|
|
|
|
|
|
|
|
|
|
/* For suspend; always kill interrupt URB */
|
|
|
|
|
static void __usbnet_status_stop_force(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
if (dev->interrupt) {
|
|
|
|
|
mutex_lock(&dev->interrupt_mutex);
|
|
|
|
|
usb_kill_urb(dev->interrupt);
|
|
|
|
|
dev_dbg(&dev->udev->dev, "killed interrupt URB for suspend\n");
|
|
|
|
|
mutex_unlock(&dev->interrupt_mutex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-01 00:53:10 +08:00
|
|
|
|
/* Passes this packet up the stack, updating its accounting.
|
|
|
|
|
* Some link protocols batch packets, so their rx_fixup paths
|
|
|
|
|
* can return clones as well as just modify the original skb.
|
|
|
|
|
*/
|
|
|
|
|
void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
int status;
|
|
|
|
|
|
2009-08-12 03:57:16 +08:00
|
|
|
|
if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
|
|
|
|
|
skb_queue_tail(&dev->rxq_pause, skb);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
skb->protocol = eth_type_trans (skb, dev->net);
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.rx_packets++;
|
|
|
|
|
dev->net->stats.rx_bytes += skb->len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
|
|
|
|
|
skb->len + sizeof (struct ethhdr), skb->protocol);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
memset (skb->cb, 0, sizeof (struct skb_data));
|
2011-09-29 12:06:26 +08:00
|
|
|
|
|
|
|
|
|
if (skb_defer_rx_timestamp(skb))
|
|
|
|
|
return;
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
status = netif_rx (skb);
|
2010-02-17 18:30:24 +08:00
|
|
|
|
if (status != NET_RX_SUCCESS)
|
|
|
|
|
netif_dbg(dev, rx_err, dev->net,
|
|
|
|
|
"netif_rx status %d\n", status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2005-09-01 00:53:10 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_skb_return);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
/* must be called if hard_mtu or rx_urb_size changed */
|
|
|
|
|
void usbnet_update_max_qlen(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
enum usb_device_speed speed = dev->udev->speed;
|
|
|
|
|
|
|
|
|
|
switch (speed) {
|
|
|
|
|
case USB_SPEED_HIGH:
|
|
|
|
|
dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size;
|
|
|
|
|
dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu;
|
|
|
|
|
break;
|
2013-07-25 13:47:54 +08:00
|
|
|
|
case USB_SPEED_SUPER:
|
|
|
|
|
/*
|
|
|
|
|
* Not take default 5ms qlen for super speed HC to
|
|
|
|
|
* save memory, and iperf tests show 2.5ms qlen can
|
|
|
|
|
* work well
|
|
|
|
|
*/
|
|
|
|
|
dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size;
|
|
|
|
|
dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu;
|
|
|
|
|
break;
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
default:
|
|
|
|
|
dev->rx_qlen = dev->tx_qlen = 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_update_max_qlen);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Network Device Driver (peer link to "Host Device", from USB host)
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
|
|
|
|
|
2009-03-21 03:35:54 +08:00
|
|
|
|
int usbnet_change_mtu (struct net_device *net, int new_mtu)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
int ll_mtu = new_mtu + net->hard_header_len;
|
2006-07-28 02:17:28 +08:00
|
|
|
|
int old_hard_mtu = dev->hard_mtu;
|
|
|
|
|
int old_rx_urb_size = dev->rx_urb_size;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2006-07-28 02:17:28 +08:00
|
|
|
|
if (new_mtu <= 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return -EINVAL;
|
|
|
|
|
// no second zero-length packet read wanted after mtu-sized packets
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
if ((ll_mtu % dev->maxpacket) == 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return -EDOM;
|
|
|
|
|
net->mtu = new_mtu;
|
2006-07-28 02:17:28 +08:00
|
|
|
|
|
|
|
|
|
dev->hard_mtu = net->mtu + net->hard_header_len;
|
|
|
|
|
if (dev->rx_urb_size == old_hard_mtu) {
|
|
|
|
|
dev->rx_urb_size = dev->hard_mtu;
|
|
|
|
|
if (dev->rx_urb_size > old_rx_urb_size)
|
|
|
|
|
usbnet_unlink_rx_urbs(dev);
|
|
|
|
|
}
|
|
|
|
|
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
/* max qlen depend on hard_mtu and rx_urb_size */
|
|
|
|
|
usbnet_update_max_qlen(dev);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2009-03-21 03:35:54 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_change_mtu);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2012-04-26 11:33:46 +08:00
|
|
|
|
/* The caller must hold list->lock */
|
|
|
|
|
static void __usbnet_queue_skb(struct sk_buff_head *list,
|
|
|
|
|
struct sk_buff *newsk, enum skb_state state)
|
|
|
|
|
{
|
|
|
|
|
struct skb_data *entry = (struct skb_data *) newsk->cb;
|
|
|
|
|
|
|
|
|
|
__skb_queue_tail(list, newsk);
|
|
|
|
|
entry->state = state;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from
|
|
|
|
|
* completion callbacks. 2.5 should have fixed those bugs...
|
|
|
|
|
*/
|
|
|
|
|
|
2012-04-26 11:33:46 +08:00
|
|
|
|
static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb,
|
|
|
|
|
struct sk_buff_head *list, enum skb_state state)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
2012-04-26 11:33:46 +08:00
|
|
|
|
enum skb_state old_state;
|
|
|
|
|
struct skb_data *entry = (struct skb_data *) skb->cb;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2005-08-10 10:25:21 +08:00
|
|
|
|
spin_lock_irqsave(&list->lock, flags);
|
2012-04-26 11:33:46 +08:00
|
|
|
|
old_state = entry->state;
|
|
|
|
|
entry->state = state;
|
2005-08-10 10:25:21 +08:00
|
|
|
|
__skb_unlink(skb, list);
|
usbnet: Fix a race between usbnet_stop() and the BH
The race may happen when a device (e.g. YOTA 4G LTE Modem) is
unplugged while the system is downloading a large file from the Net.
Hardware breakpoints and Kprobes with delays were used to confirm that
the race does actually happen.
The race is on skb_queue ('next' pointer) between usbnet_stop()
and rx_complete(), which, in turn, calls usbnet_bh().
Here is a part of the call stack with the code where the changes to the
queue happen. The line numbers are for the kernel 4.1.0:
*0 __skb_unlink (skbuff.h:1517)
prev->next = next;
*1 defer_bh (usbnet.c:430)
spin_lock_irqsave(&list->lock, flags);
old_state = entry->state;
entry->state = state;
__skb_unlink(skb, list);
spin_unlock(&list->lock);
spin_lock(&dev->done.lock);
__skb_queue_tail(&dev->done, skb);
if (dev->done.qlen == 1)
tasklet_schedule(&dev->bh);
spin_unlock_irqrestore(&dev->done.lock, flags);
*2 rx_complete (usbnet.c:640)
state = defer_bh(dev, skb, &dev->rxq, state);
At the same time, the following code repeatedly checks if the queue is
empty and reads these values concurrently with the above changes:
*0 usbnet_terminate_urbs (usbnet.c:765)
/* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq)
&& !skb_queue_empty(&dev->txq)
&& !skb_queue_empty(&dev->done)) {
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp);
}
*1 usbnet_stop (usbnet.c:806)
if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
usbnet_terminate_urbs(dev);
As a result, it is possible, for example, that the skb is removed from
dev->rxq by __skb_unlink() before the check
"!skb_queue_empty(&dev->rxq)" in usbnet_terminate_urbs() is made. It is
also possible in this case that the skb is added to dev->done queue
after "!skb_queue_empty(&dev->done)" is checked. So
usbnet_terminate_urbs() may stop waiting and return while dev->done
queue still has an item.
Locking in defer_bh() and usbnet_terminate_urbs() was revisited to avoid
this race.
Signed-off-by: Eugene Shatokhin <eugene.shatokhin@rosalab.ru>
Reviewed-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Oliver Neukum <oneukum@suse.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-09-01 22:05:33 +08:00
|
|
|
|
|
|
|
|
|
/* defer_bh() is never called with list == &dev->done.
|
|
|
|
|
* spin_lock_nested() tells lockdep that it is OK to take
|
|
|
|
|
* dev->done.lock here with list->lock held.
|
|
|
|
|
*/
|
|
|
|
|
spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING);
|
|
|
|
|
|
2005-08-10 10:25:21 +08:00
|
|
|
|
__skb_queue_tail(&dev->done, skb);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (dev->done.qlen == 1)
|
2005-08-10 10:25:21 +08:00
|
|
|
|
tasklet_schedule(&dev->bh);
|
usbnet: Fix a race between usbnet_stop() and the BH
The race may happen when a device (e.g. YOTA 4G LTE Modem) is
unplugged while the system is downloading a large file from the Net.
Hardware breakpoints and Kprobes with delays were used to confirm that
the race does actually happen.
The race is on skb_queue ('next' pointer) between usbnet_stop()
and rx_complete(), which, in turn, calls usbnet_bh().
Here is a part of the call stack with the code where the changes to the
queue happen. The line numbers are for the kernel 4.1.0:
*0 __skb_unlink (skbuff.h:1517)
prev->next = next;
*1 defer_bh (usbnet.c:430)
spin_lock_irqsave(&list->lock, flags);
old_state = entry->state;
entry->state = state;
__skb_unlink(skb, list);
spin_unlock(&list->lock);
spin_lock(&dev->done.lock);
__skb_queue_tail(&dev->done, skb);
if (dev->done.qlen == 1)
tasklet_schedule(&dev->bh);
spin_unlock_irqrestore(&dev->done.lock, flags);
*2 rx_complete (usbnet.c:640)
state = defer_bh(dev, skb, &dev->rxq, state);
At the same time, the following code repeatedly checks if the queue is
empty and reads these values concurrently with the above changes:
*0 usbnet_terminate_urbs (usbnet.c:765)
/* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq)
&& !skb_queue_empty(&dev->txq)
&& !skb_queue_empty(&dev->done)) {
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp);
}
*1 usbnet_stop (usbnet.c:806)
if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
usbnet_terminate_urbs(dev);
As a result, it is possible, for example, that the skb is removed from
dev->rxq by __skb_unlink() before the check
"!skb_queue_empty(&dev->rxq)" in usbnet_terminate_urbs() is made. It is
also possible in this case that the skb is added to dev->done queue
after "!skb_queue_empty(&dev->done)" is checked. So
usbnet_terminate_urbs() may stop waiting and return while dev->done
queue still has an item.
Locking in defer_bh() and usbnet_terminate_urbs() was revisited to avoid
this race.
Signed-off-by: Eugene Shatokhin <eugene.shatokhin@rosalab.ru>
Reviewed-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Oliver Neukum <oneukum@suse.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-09-01 22:05:33 +08:00
|
|
|
|
spin_unlock(&dev->done.lock);
|
|
|
|
|
spin_unlock_irqrestore(&list->lock, flags);
|
2012-04-26 11:33:46 +08:00
|
|
|
|
return old_state;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* some work can't be done in tasklets, so we use keventd
|
|
|
|
|
*
|
|
|
|
|
* NOTE: annoying asymmetry: if it's active, schedule_work() fails,
|
|
|
|
|
* but tasklet_schedule() doesn't. hope the failure is rare.
|
|
|
|
|
*/
|
2005-09-01 00:53:10 +08:00
|
|
|
|
void usbnet_defer_kevent (struct usbnet *dev, int work)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
set_bit (work, &dev->flags);
|
2012-11-08 14:26:21 +08:00
|
|
|
|
if (!schedule_work (&dev->kevent)) {
|
|
|
|
|
if (net_ratelimit())
|
|
|
|
|
netdev_err(dev->net, "kevent %d may have been dropped\n", work);
|
|
|
|
|
} else {
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_dbg(dev->net, "kevent %d scheduled\n", work);
|
2012-11-08 14:26:21 +08:00
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2005-09-01 00:53:10 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
|
static void rx_complete (struct urb *urb);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2010-08-10 17:50:55 +08:00
|
|
|
|
static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
struct skb_data *entry;
|
|
|
|
|
int retval = 0;
|
|
|
|
|
unsigned long lockflags;
|
2005-09-01 00:53:10 +08:00
|
|
|
|
size_t size = dev->rx_urb_size;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2013-01-29 07:51:28 +08:00
|
|
|
|
/* prevent rx skb allocation when error ratio is high */
|
|
|
|
|
if (test_bit(EVENT_RX_KILL, &dev->flags)) {
|
|
|
|
|
usb_free_urb(urb);
|
|
|
|
|
return -ENOLINK;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-14 14:56:25 +08:00
|
|
|
|
skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
|
|
|
|
|
if (!skb) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
|
2005-09-01 00:53:10 +08:00
|
|
|
|
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
usb_free_urb (urb);
|
2010-08-10 17:50:55 +08:00
|
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry = (struct skb_data *) skb->cb;
|
|
|
|
|
entry->urb = urb;
|
|
|
|
|
entry->dev = dev;
|
|
|
|
|
entry->length = 0;
|
|
|
|
|
|
|
|
|
|
usb_fill_bulk_urb (urb, dev->udev, dev->in,
|
|
|
|
|
skb->data, size, rx_complete, skb);
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave (&dev->rxq.lock, lockflags);
|
|
|
|
|
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if (netif_running (dev->net) &&
|
|
|
|
|
netif_device_present (dev->net) &&
|
2009-12-04 07:31:18 +08:00
|
|
|
|
!test_bit (EVENT_RX_HALT, &dev->flags) &&
|
|
|
|
|
!test_bit (EVENT_DEV_ASLEEP, &dev->flags)) {
|
2007-05-26 03:31:32 +08:00
|
|
|
|
switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
case -EPIPE:
|
2005-09-01 00:53:10 +08:00
|
|
|
|
usbnet_defer_kevent (dev, EVENT_RX_HALT);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
case -ENOMEM:
|
2005-09-01 00:53:10 +08:00
|
|
|
|
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
case -ENODEV:
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, ifdown, dev->net, "device gone\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
netif_device_detach (dev->net);
|
|
|
|
|
break;
|
2010-08-10 17:50:55 +08:00
|
|
|
|
case -EHOSTUNREACH:
|
|
|
|
|
retval = -ENOLINK;
|
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
default:
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_err, dev->net,
|
|
|
|
|
"rx submit, %d\n", retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
tasklet_schedule (&dev->bh);
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
2012-04-26 11:33:46 +08:00
|
|
|
|
__usbnet_queue_skb(&dev->rxq, skb, rx_start);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, ifdown, dev->net, "rx: stopped\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
retval = -ENOLINK;
|
|
|
|
|
}
|
|
|
|
|
spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
|
|
|
|
|
if (retval) {
|
|
|
|
|
dev_kfree_skb_any (skb);
|
|
|
|
|
usb_free_urb (urb);
|
|
|
|
|
}
|
2010-08-10 17:50:55 +08:00
|
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
|
|
|
|
|
{
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if (dev->driver_info->rx_fixup &&
|
2011-03-28 20:56:33 +08:00
|
|
|
|
!dev->driver_info->rx_fixup (dev, skb)) {
|
|
|
|
|
/* With RX_ASSEMBLE, rx_fixup() must update counters */
|
|
|
|
|
if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE))
|
|
|
|
|
dev->net->stats.rx_errors++;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// else network stack removes extra byte if we forced a short packet
|
|
|
|
|
|
2014-02-14 00:50:19 +08:00
|
|
|
|
/* all data was already cloned from skb inside the driver */
|
|
|
|
|
if (dev->driver_info->flags & FLAG_MULTI_PACKET)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
if (skb->len < ETH_HLEN) {
|
|
|
|
|
dev->net->stats.rx_errors++;
|
|
|
|
|
dev->net->stats.rx_length_errors++;
|
|
|
|
|
netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
|
|
|
|
|
} else {
|
|
|
|
|
usbnet_skb_return(dev, skb);
|
2010-11-30 07:23:27 +08:00
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2010-11-30 07:23:27 +08:00
|
|
|
|
|
2011-03-28 20:56:33 +08:00
|
|
|
|
done:
|
2010-11-30 07:23:27 +08:00
|
|
|
|
skb_queue_tail(&dev->done, skb);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
|
static void rx_complete (struct urb *urb)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct sk_buff *skb = (struct sk_buff *) urb->context;
|
|
|
|
|
struct skb_data *entry = (struct skb_data *) skb->cb;
|
|
|
|
|
struct usbnet *dev = entry->dev;
|
|
|
|
|
int urb_status = urb->status;
|
2012-04-26 11:33:46 +08:00
|
|
|
|
enum skb_state state;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
skb_put (skb, urb->actual_length);
|
2012-04-26 11:33:46 +08:00
|
|
|
|
state = rx_done;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
entry->urb = NULL;
|
|
|
|
|
|
|
|
|
|
switch (urb_status) {
|
2007-05-26 03:31:32 +08:00
|
|
|
|
/* success */
|
|
|
|
|
case 0:
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
|
2007-05-26 03:31:32 +08:00
|
|
|
|
/* stalls need manual reset. this is rare ... except that
|
|
|
|
|
* when going through USB 2.0 TTs, unplug appears this way.
|
2009-06-04 22:20:28 +08:00
|
|
|
|
* we avoid the highspeed version of the ETIMEDOUT/EILSEQ
|
2007-05-26 03:31:32 +08:00
|
|
|
|
* storm, recovering as needed.
|
|
|
|
|
*/
|
|
|
|
|
case -EPIPE:
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.rx_errors++;
|
2005-09-01 00:53:10 +08:00
|
|
|
|
usbnet_defer_kevent (dev, EVENT_RX_HALT);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// FALLTHROUGH
|
|
|
|
|
|
2007-05-26 03:31:32 +08:00
|
|
|
|
/* software-driven interface shutdown */
|
|
|
|
|
case -ECONNRESET: /* async unlink */
|
|
|
|
|
case -ESHUTDOWN: /* hardware gone */
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, ifdown, dev->net,
|
|
|
|
|
"rx shutdown, code %d\n", urb_status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
goto block;
|
|
|
|
|
|
2014-09-19 23:32:23 +08:00
|
|
|
|
/* we get controller i/o faults during hub_wq disconnect() delays.
|
2007-05-26 03:31:32 +08:00
|
|
|
|
* throttle down resubmits, to avoid log floods; just temporarily,
|
2014-09-19 23:32:23 +08:00
|
|
|
|
* so we still recover when the fault isn't a hub_wq delay.
|
2007-05-26 03:31:32 +08:00
|
|
|
|
*/
|
|
|
|
|
case -EPROTO:
|
|
|
|
|
case -ETIME:
|
|
|
|
|
case -EILSEQ:
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.rx_errors++;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (!timer_pending (&dev->delay)) {
|
|
|
|
|
mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, link, dev->net,
|
|
|
|
|
"rx throttle %d\n", urb_status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
block:
|
2012-04-26 11:33:46 +08:00
|
|
|
|
state = rx_cleanup;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
entry->urb = urb;
|
|
|
|
|
urb = NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
2007-05-26 03:31:32 +08:00
|
|
|
|
/* data overrun ... flush fifo? */
|
|
|
|
|
case -EOVERFLOW:
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.rx_over_errors++;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// FALLTHROUGH
|
2007-02-16 10:52:30 +08:00
|
|
|
|
|
2007-05-26 03:31:32 +08:00
|
|
|
|
default:
|
2012-04-26 11:33:46 +08:00
|
|
|
|
state = rx_cleanup;
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.rx_errors++;
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-29 07:51:28 +08:00
|
|
|
|
/* stop rx if packet error rate is high */
|
|
|
|
|
if (++dev->pkt_cnt > 30) {
|
|
|
|
|
dev->pkt_cnt = 0;
|
|
|
|
|
dev->pkt_err = 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (state == rx_cleanup)
|
|
|
|
|
dev->pkt_err++;
|
|
|
|
|
if (dev->pkt_err > 20)
|
|
|
|
|
set_bit(EVENT_RX_KILL, &dev->flags);
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-26 11:33:46 +08:00
|
|
|
|
state = defer_bh(dev, skb, &dev->rxq, state);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
if (urb) {
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if (netif_running (dev->net) &&
|
2012-04-26 11:33:46 +08:00
|
|
|
|
!test_bit (EVENT_RX_HALT, &dev->flags) &&
|
|
|
|
|
state != unlink_start) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
rx_submit (dev, urb, GFP_ATOMIC);
|
2012-03-04 01:45:07 +08:00
|
|
|
|
usb_mark_last_busy(dev->udev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
usb_free_urb (urb);
|
|
|
|
|
}
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2009-08-12 03:57:16 +08:00
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
void usbnet_pause_rx(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
set_bit(EVENT_RX_PAUSED, &dev->flags);
|
|
|
|
|
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_status, dev->net, "paused rx queue enabled\n");
|
2009-08-12 03:57:16 +08:00
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_pause_rx);
|
|
|
|
|
|
|
|
|
|
void usbnet_resume_rx(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
|
|
clear_bit(EVENT_RX_PAUSED, &dev->flags);
|
|
|
|
|
|
|
|
|
|
while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) {
|
|
|
|
|
usbnet_skb_return(dev, skb);
|
|
|
|
|
num++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tasklet_schedule(&dev->bh);
|
|
|
|
|
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, rx_status, dev->net,
|
|
|
|
|
"paused rx queue disabled, %d skbs requeued\n", num);
|
2009-08-12 03:57:16 +08:00
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_resume_rx);
|
|
|
|
|
|
|
|
|
|
void usbnet_purge_paused_rxq(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
skb_queue_purge(&dev->rxq_pause);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
// unlink pending rx/tx; completion handlers do all other cleanup
|
|
|
|
|
|
|
|
|
|
static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
2012-04-26 11:33:46 +08:00
|
|
|
|
struct sk_buff *skb;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave (&q->lock, flags);
|
2012-04-26 11:33:46 +08:00
|
|
|
|
while (!skb_queue_empty(q)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
struct skb_data *entry;
|
|
|
|
|
struct urb *urb;
|
|
|
|
|
int retval;
|
|
|
|
|
|
2012-04-26 11:33:46 +08:00
|
|
|
|
skb_queue_walk(q, skb) {
|
|
|
|
|
entry = (struct skb_data *) skb->cb;
|
|
|
|
|
if (entry->state != unlink_start)
|
|
|
|
|
goto found;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
found:
|
|
|
|
|
entry->state = unlink_start;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
urb = entry->urb;
|
|
|
|
|
|
2012-03-22 11:22:18 +08:00
|
|
|
|
/*
|
|
|
|
|
* Get reference count of the URB to avoid it to be
|
|
|
|
|
* freed during usb_unlink_urb, which may trigger
|
|
|
|
|
* use-after-free problem inside usb_unlink_urb since
|
|
|
|
|
* usb_unlink_urb is always racing with .complete
|
|
|
|
|
* handler(include defer_bh).
|
|
|
|
|
*/
|
|
|
|
|
usb_get_urb(urb);
|
2012-03-07 18:19:28 +08:00
|
|
|
|
spin_unlock_irqrestore(&q->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// during some PM-driven resume scenarios,
|
|
|
|
|
// these (async) unlinks complete immediately
|
|
|
|
|
retval = usb_unlink_urb (urb);
|
|
|
|
|
if (retval != -EINPROGRESS && retval != 0)
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
else
|
|
|
|
|
count++;
|
2012-03-22 11:22:18 +08:00
|
|
|
|
usb_put_urb(urb);
|
2012-03-07 18:19:28 +08:00
|
|
|
|
spin_lock_irqsave(&q->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
spin_unlock_irqrestore (&q->lock, flags);
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2006-07-28 02:17:28 +08:00
|
|
|
|
// Flush all pending rx urbs
|
|
|
|
|
// minidrivers may need to do this when the MTU changes
|
|
|
|
|
|
|
|
|
|
void usbnet_unlink_rx_urbs(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
if (netif_running(dev->net)) {
|
|
|
|
|
(void) unlink_urbs (dev, &dev->rxq);
|
|
|
|
|
tasklet_schedule(&dev->bh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
usbnet: Fix a race between usbnet_stop() and the BH
The race may happen when a device (e.g. YOTA 4G LTE Modem) is
unplugged while the system is downloading a large file from the Net.
Hardware breakpoints and Kprobes with delays were used to confirm that
the race does actually happen.
The race is on skb_queue ('next' pointer) between usbnet_stop()
and rx_complete(), which, in turn, calls usbnet_bh().
Here is a part of the call stack with the code where the changes to the
queue happen. The line numbers are for the kernel 4.1.0:
*0 __skb_unlink (skbuff.h:1517)
prev->next = next;
*1 defer_bh (usbnet.c:430)
spin_lock_irqsave(&list->lock, flags);
old_state = entry->state;
entry->state = state;
__skb_unlink(skb, list);
spin_unlock(&list->lock);
spin_lock(&dev->done.lock);
__skb_queue_tail(&dev->done, skb);
if (dev->done.qlen == 1)
tasklet_schedule(&dev->bh);
spin_unlock_irqrestore(&dev->done.lock, flags);
*2 rx_complete (usbnet.c:640)
state = defer_bh(dev, skb, &dev->rxq, state);
At the same time, the following code repeatedly checks if the queue is
empty and reads these values concurrently with the above changes:
*0 usbnet_terminate_urbs (usbnet.c:765)
/* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq)
&& !skb_queue_empty(&dev->txq)
&& !skb_queue_empty(&dev->done)) {
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp);
}
*1 usbnet_stop (usbnet.c:806)
if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
usbnet_terminate_urbs(dev);
As a result, it is possible, for example, that the skb is removed from
dev->rxq by __skb_unlink() before the check
"!skb_queue_empty(&dev->rxq)" in usbnet_terminate_urbs() is made. It is
also possible in this case that the skb is added to dev->done queue
after "!skb_queue_empty(&dev->done)" is checked. So
usbnet_terminate_urbs() may stop waiting and return while dev->done
queue still has an item.
Locking in defer_bh() and usbnet_terminate_urbs() was revisited to avoid
this race.
Signed-off-by: Eugene Shatokhin <eugene.shatokhin@rosalab.ru>
Reviewed-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Oliver Neukum <oneukum@suse.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-09-01 22:05:33 +08:00
|
|
|
|
static void wait_skb_queue_empty(struct sk_buff_head *q)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&q->lock, flags);
|
|
|
|
|
while (!skb_queue_empty(q)) {
|
|
|
|
|
spin_unlock_irqrestore(&q->lock, flags);
|
|
|
|
|
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
|
|
|
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
|
|
spin_lock_irqsave(&q->lock, flags);
|
|
|
|
|
}
|
|
|
|
|
spin_unlock_irqrestore(&q->lock, flags);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// precondition: never called in_interrupt
|
2009-12-04 07:31:18 +08:00
|
|
|
|
static void usbnet_terminate_urbs(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
DECLARE_WAITQUEUE(wait, current);
|
|
|
|
|
int temp;
|
|
|
|
|
|
|
|
|
|
/* ensure there are no more active urbs */
|
2014-03-26 21:32:51 +08:00
|
|
|
|
add_wait_queue(&dev->wait, &wait);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
|
|
temp = unlink_urbs(dev, &dev->txq) +
|
|
|
|
|
unlink_urbs(dev, &dev->rxq);
|
|
|
|
|
|
|
|
|
|
/* maybe wait for deletions to finish. */
|
usbnet: Fix a race between usbnet_stop() and the BH
The race may happen when a device (e.g. YOTA 4G LTE Modem) is
unplugged while the system is downloading a large file from the Net.
Hardware breakpoints and Kprobes with delays were used to confirm that
the race does actually happen.
The race is on skb_queue ('next' pointer) between usbnet_stop()
and rx_complete(), which, in turn, calls usbnet_bh().
Here is a part of the call stack with the code where the changes to the
queue happen. The line numbers are for the kernel 4.1.0:
*0 __skb_unlink (skbuff.h:1517)
prev->next = next;
*1 defer_bh (usbnet.c:430)
spin_lock_irqsave(&list->lock, flags);
old_state = entry->state;
entry->state = state;
__skb_unlink(skb, list);
spin_unlock(&list->lock);
spin_lock(&dev->done.lock);
__skb_queue_tail(&dev->done, skb);
if (dev->done.qlen == 1)
tasklet_schedule(&dev->bh);
spin_unlock_irqrestore(&dev->done.lock, flags);
*2 rx_complete (usbnet.c:640)
state = defer_bh(dev, skb, &dev->rxq, state);
At the same time, the following code repeatedly checks if the queue is
empty and reads these values concurrently with the above changes:
*0 usbnet_terminate_urbs (usbnet.c:765)
/* maybe wait for deletions to finish. */
while (!skb_queue_empty(&dev->rxq)
&& !skb_queue_empty(&dev->txq)
&& !skb_queue_empty(&dev->done)) {
schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS));
set_current_state(TASK_UNINTERRUPTIBLE);
netif_dbg(dev, ifdown, dev->net,
"waited for %d urb completions\n", temp);
}
*1 usbnet_stop (usbnet.c:806)
if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
usbnet_terminate_urbs(dev);
As a result, it is possible, for example, that the skb is removed from
dev->rxq by __skb_unlink() before the check
"!skb_queue_empty(&dev->rxq)" in usbnet_terminate_urbs() is made. It is
also possible in this case that the skb is added to dev->done queue
after "!skb_queue_empty(&dev->done)" is checked. So
usbnet_terminate_urbs() may stop waiting and return while dev->done
queue still has an item.
Locking in defer_bh() and usbnet_terminate_urbs() was revisited to avoid
this race.
Signed-off-by: Eugene Shatokhin <eugene.shatokhin@rosalab.ru>
Reviewed-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Oliver Neukum <oneukum@suse.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-09-01 22:05:33 +08:00
|
|
|
|
wait_skb_queue_empty(&dev->rxq);
|
|
|
|
|
wait_skb_queue_empty(&dev->txq);
|
|
|
|
|
wait_skb_queue_empty(&dev->done);
|
|
|
|
|
netif_dbg(dev, ifdown, dev->net,
|
|
|
|
|
"waited for %d urb completions\n", temp);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
set_current_state(TASK_RUNNING);
|
2014-03-26 21:32:51 +08:00
|
|
|
|
remove_wait_queue(&dev->wait, &wait);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2009-03-21 03:35:54 +08:00
|
|
|
|
int usbnet_stop (struct net_device *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
2009-06-16 22:17:27 +08:00
|
|
|
|
struct driver_info *info = dev->driver_info;
|
2015-08-25 04:13:42 +08:00
|
|
|
|
int retval, pm, mpn;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
usbnet: runtime pm: fix out of memory
This patch makes use of the EVENT_DEV_OPEN flag introduced recently to
fix one out of memory issue, which can be reproduced on omap3/4 based
pandaboard/beagle XM easily with steps below:
- enable runtime pm
echo auto > /sys/devices/platform/usbhs-omap.0/ehci-omap.0/usb1/1-1/1-1.1/power/control
- ifconfig eth0 up
- then out of memroy happened, see [1] for kernel message.
Follows my analysis:
- 'ifconfig eth0 up' brings eth0 out of suspend, and usbnet_resume
is called to schedule dev->bh, then rx urbs are submited to prepare for
recieving data;
- some usbnet devices will produce garbage rx packets flood if
info->reset is not called in usbnet_open.
- so there is no enough chances for usbnet_bh to handle and release
recieved skb buffers since many rx interrupts consumes cpu, so out of memory
for atomic allocation in rx_submit happened.
This patch fixes the issue by simply not allowing schedule of usbnet_bh until device
is opened.
[1], dmesg
[ 234.712005] smsc95xx 1-1.1:1.0: rpm_resume flags 0x4
[ 234.712066] usb 1-1.1: rpm_resume flags 0x0
[ 234.712066] usb 1-1: rpm_resume flags 0x0
[ 234.712097] usb usb1: rpm_resume flags 0x0
[ 234.712127] usb usb1: usb auto-resume
[ 234.712158] ehci-omap ehci-omap.0: resume root hub
[ 234.754028] hub 1-0:1.0: hub_resume
[ 234.754821] hub 1-0:1.0: port 1: status 0507 change 0000
[ 234.756011] hub 1-0:1.0: state 7 ports 3 chg 0000 evt 0000
[ 234.756042] hub 1-0:1.0: rpm_resume flags 0x4
[ 234.756072] usb usb1: rpm_resume flags 0x0
[ 234.756164] usb usb1: rpm_resume returns 1
[ 234.756195] hub 1-0:1.0: rpm_resume returns 0
[ 234.756195] hub 1-0:1.0: rpm_suspend flags 0x4
[ 234.756225] hub 1-0:1.0: rpm_suspend returns 0
[ 234.756256] usb usb1: rpm_resume returns 0
[ 234.757141] usb 1-1: usb auto-resume
[ 234.793151] ehci-omap ehci-omap.0: GetStatus port:1 status 001005 0 ACK POWER sig=se0 PE CONNECT
[ 234.816558] usb 1-1: finish resume
[ 234.817871] hub 1-1:1.0: hub_resume
[ 234.818420] hub 1-1:1.0: port 1: status 0507 change 0000
[ 234.820495] ehci-omap ehci-omap.0: reused qh eec50220 schedule
[ 234.820495] usb 1-1: link qh256-0001/eec50220 start 1 [1/0 us]
[ 234.820587] usb 1-1: rpm_resume returns 0
[ 234.820800] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0000
[ 234.820800] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.820831] hub 1-1:1.0: rpm_resume returns 0
[ 234.820861] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.820861] hub 1-1:1.0: rpm_suspend returns 0
[ 234.821777] usb 1-1.1: usb auto-resume
[ 234.868591] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0002
[ 234.868591] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.868621] hub 1-1:1.0: rpm_resume returns 0
[ 234.868652] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.868652] hub 1-1:1.0: rpm_suspend returns 0
[ 234.879486] usb 1-1.1: finish resume
[ 234.880279] usb 1-1.1: rpm_resume returns 0
[ 234.880310] smsc95xx 1-1.1:1.0: rpm_resume returns 0
[ 238.880187] ksoftirqd/0: page allocation failure. order:0, mode:0x20
[ 238.880218] Backtrace:
[ 238.880249] [<c01b9800>] (dump_backtrace+0x0/0xf8) from [<c065e1dc>] (dump_stack+0x18/0x1c)
[ 238.880249] r6:00000000 r5:00000000 r4:00000020 r3:00000002
[ 238.880310] [<c065e1c4>] (dump_stack+0x0/0x1c) from [<c026ece4>] (__alloc_pages_nodemask+0x620/0x724)
[ 238.880340] [<c026e6c4>] (__alloc_pages_nodemask+0x0/0x724) from [<c02986d4>] (kmem_getpages.clone.34+0x34/0xc8)
[ 238.880371] [<c02986a0>] (kmem_getpages.clone.34+0x0/0xc8) from [<c02988f8>] (cache_grow.clone.42+0x84/0x154)
[ 238.880371] r6:ef871aa4 r5:ef871a80 r4:ef81fd40 r3:00000020
[ 238.880401] [<c0298874>] (cache_grow.clone.42+0x0/0x154) from [<c0298b64>] (cache_alloc_refill+0x19c/0x1f0)
[ 238.880432] [<c02989c8>] (cache_alloc_refill+0x0/0x1f0) from [<c0299804>] (kmem_cache_alloc+0x90/0x190)
[ 238.880462] [<c0299774>] (kmem_cache_alloc+0x0/0x190) from [<c052e260>] (__alloc_skb+0x34/0xe8)
[ 238.880493] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.880523] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf050d38>] (rx_complete+0x19c/0x1b0 [usbnet])
[ 238.880737] [<bf050b9c>] (rx_complete+0x0/0x1b0 [usbnet]) from [<bf006fd0>] (usb_hcd_giveback_urb+0xa8/0xf4 [usbcore])
[ 238.880737] r8:eeeced34 r7:eeecec00 r6:eeecec00 r5:00000000 r4:eec2dd20
[ 238.880767] r3:bf050b9c
[ 238.880859] [<bf006f28>] (usb_hcd_giveback_urb+0x0/0xf4 [usbcore]) from [<bf03c8f8>] (ehci_urb_done+0xb0/0xbc [ehci_hcd])
[ 238.880859] r6:00000000 r5:eec2dd20 r4:eeeced44 r3:eec2dd34
[ 238.880920] [<bf03c848>] (ehci_urb_done+0x0/0xbc [ehci_hcd]) from [<bf040204>] (qh_completions+0x308/0x3bc [ehci_hcd])
[ 238.880920] r7:00000000 r6:eeda21a0 r5:ffdfe3c0 r4:eeda21ac
[ 238.880981] [<bf03fefc>] (qh_completions+0x0/0x3bc [ehci_hcd]) from [<bf040ef8>] (scan_async+0xb0/0x16c [ehci_hcd])
[ 238.881011] [<bf040e48>] (scan_async+0x0/0x16c [ehci_hcd]) from [<bf040fec>] (ehci_work+0x38/0x90 [ehci_hcd])
[ 238.881042] [<bf040fb4>] (ehci_work+0x0/0x90 [ehci_hcd]) from [<bf042940>] (ehci_irq+0x300/0x34c [ehci_hcd])
[ 238.881072] r4:eeeced34 r3:00000001
[ 238.881134] [<bf042640>] (ehci_irq+0x0/0x34c [ehci_hcd]) from [<bf006828>] (usb_hcd_irq+0x40/0xac [usbcore])
[ 238.881195] [<bf0067e8>] (usb_hcd_irq+0x0/0xac [usbcore]) from [<c0239764>] (handle_irq_event_percpu+0xb8/0x240)
[ 238.881225] r6:eec504e0 r5:0000006d r4:eec504e0 r3:bf0067e8
[ 238.881256] [<c02396ac>] (handle_irq_event_percpu+0x0/0x240) from [<c0239930>] (handle_irq_event+0x44/0x64)
[ 238.881256] [<c02398ec>] (handle_irq_event+0x0/0x64) from [<c023bbd0>] (handle_level_irq+0xe0/0x114)
[ 238.881286] r6:0000006d r5:c080c14c r4:c080c100 r3:00020000
[ 238.881317] [<c023baf0>] (handle_level_irq+0x0/0x114) from [<c01ab090>] (asm_do_IRQ+0x90/0xd0)
[ 238.881317] r5:00000000 r4:0000006d
[ 238.881347] [<c01ab000>] (asm_do_IRQ+0x0/0xd0) from [<c06624d0>] (__irq_svc+0x50/0x134)
[ 238.881378] Exception stack(0xef837e20 to 0xef837e68)
[ 238.881378] 7e20: 00000001 00185610 016cc000 c00490c0 eb380000 ef800540 00000020 00004ae0
[ 238.881408] 7e40: 00000020 bf0509f4 60000013 ef837e9c ef837e40 ef837e68 c0226f0c c0298ca0
[ 238.881408] 7e60: 20000013 ffffffff
[ 238.881408] r5:fa240100 r4:ffffffff
[ 238.881439] [<c0298bb8>] (__kmalloc_track_caller+0x0/0x1d0) from [<c052e284>] (__alloc_skb+0x58/0xe8)
[ 238.881469] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.881500] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf0513d8>] (usbnet_bh+0x1b4/0x250 [usbnet])
[ 238.881530] [<bf051224>] (usbnet_bh+0x0/0x250 [usbnet]) from [<c01f912c>] (tasklet_action+0xb0/0x1f8)
[ 238.881530] r6:00000000 r5:ef9757f0 r4:ef9757ec r3:bf051224
[ 238.881561] [<c01f907c>] (tasklet_action+0x0/0x1f8) from [<c01f97ac>] (__do_softirq+0x140/0x290)
[ 238.881561] r8:00000006 r7:00000101 r6:00000000 r5:c0806098 r4:00000001
[ 238.881591] r3:c01f907c
[ 238.881622] [<c01f966c>] (__do_softirq+0x0/0x290) from [<c01f99cc>] (run_ksoftirqd+0xd0/0x1f4)
[ 238.881622] [<c01f98fc>] (run_ksoftirqd+0x0/0x1f4) from [<c02113b0>] (kthread+0x90/0x98)
[ 238.881652] r7:00000013 r6:c01f98fc r5:00000000 r4:ef831efc
[ 238.881683] [<c0211320>] (kthread+0x0/0x98) from [<c01f62f4>] (do_exit+0x0/0x374)
[ 238.881713] r6:c01f62f4 r5:c0211320 r4:ef831efc
[ 238.881713] Mem-info:
[ 238.881744] Normal per-cpu:
[ 238.881744] CPU 0: hi: 186, btch: 31 usd: 38
[ 238.881744] CPU 1: hi: 186, btch: 31 usd: 169
[ 238.881774] HighMem per-cpu:
[ 238.881774] CPU 0: hi: 90, btch: 15 usd: 66
[ 238.881774] CPU 1: hi: 90, btch: 15 usd: 86
[ 238.881805] active_anon:544 inactive_anon:71 isolated_anon:0
[ 238.881805] active_file:926 inactive_file:2538 isolated_file:0
[ 238.881805] unevictable:0 dirty:10 writeback:0 unstable:0
[ 238.881805] free:57782 slab_reclaimable:864 slab_unreclaimable:186898
[ 238.881805] mapped:632 shmem:144 pagetables:50 bounce:0
[ 238.881835] Normal free:1328kB min:3532kB low:4412kB high:5296kB active_anon:0kB inactive_anon:0kB active_file:880kB inactive_file:848kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:780288kB mlocked:0kB dirty:36kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:3456kB slab_unreclaimable:747592kB kernel_stack:392kB pagetables:200kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881866] lowmem_reserve[]: 0 1904 1904
[ 238.881896] HighMem free:229800kB min:236kB low:508kB high:784kB active_anon:2176kB inactive_anon:284kB active_file:2824kB inactive_file:9304kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:243712kB mlocked:0kB dirty:4kB writeback:0kB mapped:2528kB shmem:576kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881927] lowmem_reserve[]: 0 0 0
[ 238.881958] Normal: 0*4kB 4*8kB 6*16kB 0*32kB 1*64kB 1*128kB 0*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1344kB
[ 238.882019] HighMem: 6*4kB 2*8kB 4*16kB 4*32kB 1*64kB 1*128kB 0*256kB 2*512kB 3*1024kB 0*2048kB 55*4096kB = 229800kB
[ 238.882080] 3610 total pagecache pages
[ 238.882080] 0 pages in swap cache
[ 238.882080] Swap cache stats: add 0, delete 0, find 0/0
[ 238.882110] Free swap = 0kB
[ 238.882110] Total swap = 0kB
[ 238.933776] 262144 pages of RAM
[ 238.933776] 58240 free pages
[ 238.933776] 10503 reserved pages
[ 238.933776] 187773 slab pages
[ 238.933807] 2475 pages shared
[ 238.933807] 0 pages swap cached
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2011-04-29 06:37:09 +08:00
|
|
|
|
clear_bit(EVENT_DEV_OPEN, &dev->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
netif_stop_queue (net);
|
|
|
|
|
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_info(dev, ifdown, dev->net,
|
2010-06-08 16:20:59 +08:00
|
|
|
|
"stop stats: rx/tx %lu/%lu, errs %lu/%lu\n",
|
2010-02-17 18:30:24 +08:00
|
|
|
|
net->stats.rx_packets, net->stats.tx_packets,
|
|
|
|
|
net->stats.rx_errors, net->stats.tx_errors);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2014-03-26 21:32:51 +08:00
|
|
|
|
/* to not race resume */
|
|
|
|
|
pm = usb_autopm_get_interface(dev->intf);
|
2009-06-16 22:17:27 +08:00
|
|
|
|
/* allow minidriver to stop correctly (wireless devices to turn off
|
|
|
|
|
* radio etc) */
|
|
|
|
|
if (info->stop) {
|
|
|
|
|
retval = info->stop(dev);
|
2010-02-17 18:30:24 +08:00
|
|
|
|
if (retval < 0)
|
|
|
|
|
netif_info(dev, ifdown, dev->net,
|
|
|
|
|
"stop fail (%d) usbnet usb-%s-%s, %s\n",
|
|
|
|
|
retval,
|
|
|
|
|
dev->udev->bus->bus_name, dev->udev->devpath,
|
|
|
|
|
info->description);
|
2009-06-16 22:17:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2009-12-04 07:31:18 +08:00
|
|
|
|
if (!(info->flags & FLAG_AVOID_UNLINK_URBS))
|
|
|
|
|
usbnet_terminate_urbs(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2013-05-06 19:29:23 +08:00
|
|
|
|
usbnet_status_stop(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2009-08-12 03:57:16 +08:00
|
|
|
|
usbnet_purge_paused_rxq(dev);
|
|
|
|
|
|
2015-08-25 04:13:42 +08:00
|
|
|
|
mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
/* deferred work (task, timer, softirq) must also stop.
|
|
|
|
|
* can't flush_scheduled_work() until we drop rtnl (later),
|
|
|
|
|
* else workers could deadlock; so make workers a NOP.
|
|
|
|
|
*/
|
|
|
|
|
dev->flags = 0;
|
|
|
|
|
del_timer_sync (&dev->delay);
|
|
|
|
|
tasklet_kill (&dev->bh);
|
2014-03-26 21:32:51 +08:00
|
|
|
|
if (!pm)
|
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
|
2015-08-25 04:13:42 +08:00
|
|
|
|
if (info->manage_power && mpn)
|
2009-12-04 07:31:18 +08:00
|
|
|
|
info->manage_power(dev, 0);
|
|
|
|
|
else
|
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2009-03-21 03:35:54 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_stop);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
// posts reads, and enables write queuing
|
|
|
|
|
|
|
|
|
|
// precondition: never called in_interrupt
|
|
|
|
|
|
2009-03-21 03:35:54 +08:00
|
|
|
|
int usbnet_open (struct net_device *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
2007-08-03 19:52:19 +08:00
|
|
|
|
int retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
struct driver_info *info = dev->driver_info;
|
|
|
|
|
|
2007-08-03 19:52:19 +08:00
|
|
|
|
if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_info(dev, ifup, dev->net,
|
|
|
|
|
"resumption fail (%d) usbnet usb-%s-%s, %s\n",
|
|
|
|
|
retval,
|
|
|
|
|
dev->udev->bus->bus_name,
|
|
|
|
|
dev->udev->devpath,
|
|
|
|
|
info->description);
|
2007-08-03 19:52:19 +08:00
|
|
|
|
goto done_nopm;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// put into "known safe" state
|
|
|
|
|
if (info->reset && (retval = info->reset (dev)) < 0) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_info(dev, ifup, dev->net,
|
|
|
|
|
"open reset fail (%d) usbnet usb-%s-%s, %s\n",
|
|
|
|
|
retval,
|
|
|
|
|
dev->udev->bus->bus_name,
|
|
|
|
|
dev->udev->devpath,
|
|
|
|
|
info->description);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
/* hard_mtu or rx_urb_size may change in reset() */
|
|
|
|
|
usbnet_update_max_qlen(dev);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// insist peer be connected
|
|
|
|
|
if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* start any status interrupt transfer */
|
|
|
|
|
if (dev->interrupt) {
|
2013-05-06 19:29:23 +08:00
|
|
|
|
retval = usbnet_status_start(dev, GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (retval < 0) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_err(dev, ifup, dev->net,
|
|
|
|
|
"intr submit %d\n", retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-28 13:43:37 +08:00
|
|
|
|
set_bit(EVENT_DEV_OPEN, &dev->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
netif_start_queue (net);
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_info(dev, ifup, dev->net,
|
|
|
|
|
"open: enable queueing (rx %d, tx %d) mtu %d %s framing\n",
|
|
|
|
|
(int)RX_QLEN(dev), (int)TX_QLEN(dev),
|
|
|
|
|
dev->net->mtu,
|
|
|
|
|
(dev->driver_info->flags & FLAG_FRAMING_NC) ? "NetChip" :
|
|
|
|
|
(dev->driver_info->flags & FLAG_FRAMING_GL) ? "GeneSys" :
|
|
|
|
|
(dev->driver_info->flags & FLAG_FRAMING_Z) ? "Zaurus" :
|
|
|
|
|
(dev->driver_info->flags & FLAG_FRAMING_RN) ? "RNDIS" :
|
|
|
|
|
(dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" :
|
|
|
|
|
"simple");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2013-01-29 07:51:28 +08:00
|
|
|
|
/* reset rx error state */
|
|
|
|
|
dev->pkt_cnt = 0;
|
|
|
|
|
dev->pkt_err = 0;
|
|
|
|
|
clear_bit(EVENT_RX_KILL, &dev->flags);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// delay posting reads until we're fully open
|
|
|
|
|
tasklet_schedule (&dev->bh);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
if (info->manage_power) {
|
|
|
|
|
retval = info->manage_power(dev, 1);
|
2012-12-18 12:45:29 +08:00
|
|
|
|
if (retval < 0) {
|
|
|
|
|
retval = 0;
|
|
|
|
|
set_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
|
|
|
|
|
} else {
|
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
}
|
2009-12-04 07:31:18 +08:00
|
|
|
|
}
|
2007-08-03 19:52:19 +08:00
|
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
done:
|
2007-08-03 19:52:19 +08:00
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
done_nopm:
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return retval;
|
|
|
|
|
}
|
2009-03-21 03:35:54 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_open);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
2005-09-01 00:53:10 +08:00
|
|
|
|
/* ethtool methods; minidrivers may need to add some more, but
|
|
|
|
|
* they'll probably want to use this base set.
|
|
|
|
|
*/
|
|
|
|
|
|
2006-10-09 06:08:01 +08:00
|
|
|
|
int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
|
|
|
|
if (!dev->mii.mdio_read)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
return mii_ethtool_gset(&dev->mii, cmd);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_get_settings);
|
|
|
|
|
|
|
|
|
|
int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
if (!dev->mii.mdio_write)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
retval = mii_ethtool_sset(&dev->mii, cmd);
|
|
|
|
|
|
|
|
|
|
/* link speed/duplex might have changed */
|
|
|
|
|
if (dev->driver_info->link_reset)
|
|
|
|
|
dev->driver_info->link_reset(dev);
|
|
|
|
|
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
/* hard_mtu or rx_urb_size may change in link_reset() */
|
|
|
|
|
usbnet_update_max_qlen(dev);
|
|
|
|
|
|
2006-10-09 06:08:01 +08:00
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_set_settings);
|
|
|
|
|
|
|
|
|
|
u32 usbnet_get_link (struct net_device *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
/* If a check_connect is defined, return its result */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (dev->driver_info->check_connect)
|
|
|
|
|
return dev->driver_info->check_connect (dev) == 0;
|
|
|
|
|
|
2006-10-09 06:08:01 +08:00
|
|
|
|
/* if the device has mii operations, use those */
|
|
|
|
|
if (dev->mii.mdio_read)
|
|
|
|
|
return mii_link_ok(&dev->mii);
|
|
|
|
|
|
2009-03-02 12:45:40 +08:00
|
|
|
|
/* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */
|
|
|
|
|
return ethtool_op_get_link(net);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2006-10-09 06:08:01 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_get_link);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2006-11-03 04:29:12 +08:00
|
|
|
|
int usbnet_nway_reset(struct net_device *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
2006-11-03 04:29:12 +08:00
|
|
|
|
if (!dev->mii.mdio_write)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
return mii_nway_restart(&dev->mii);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2006-11-03 04:29:12 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_nway_reset);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2006-11-03 04:29:12 +08:00
|
|
|
|
void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
2012-06-14 09:18:42 +08:00
|
|
|
|
strlcpy (info->driver, dev->driver_name, sizeof info->driver);
|
|
|
|
|
strlcpy (info->version, DRIVER_VERSION, sizeof info->version);
|
|
|
|
|
strlcpy (info->fw_version, dev->driver_info->description,
|
2006-11-03 04:29:12 +08:00
|
|
|
|
sizeof info->fw_version);
|
|
|
|
|
usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2006-11-03 04:29:12 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2006-11-03 04:29:12 +08:00
|
|
|
|
u32 usbnet_get_msglevel (struct net_device *net)
|
2006-10-09 06:08:01 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
2006-11-03 04:29:12 +08:00
|
|
|
|
return dev->msg_enable;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_get_msglevel);
|
2006-10-09 06:08:01 +08:00
|
|
|
|
|
2006-11-03 04:29:12 +08:00
|
|
|
|
void usbnet_set_msglevel (struct net_device *net, u32 level)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
|
|
|
|
dev->msg_enable = level;
|
2006-10-09 06:08:01 +08:00
|
|
|
|
}
|
2006-11-03 04:29:12 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
|
2006-10-09 06:08:01 +08:00
|
|
|
|
|
2005-09-01 00:53:10 +08:00
|
|
|
|
/* drivers may override default ethtool_ops in their bind() routine */
|
2009-09-02 16:03:33 +08:00
|
|
|
|
static const struct ethtool_ops usbnet_ethtool_ops = {
|
2006-10-09 06:08:01 +08:00
|
|
|
|
.get_settings = usbnet_get_settings,
|
|
|
|
|
.set_settings = usbnet_set_settings,
|
2005-09-01 00:53:10 +08:00
|
|
|
|
.get_link = usbnet_get_link,
|
2006-10-09 06:08:01 +08:00
|
|
|
|
.nway_reset = usbnet_nway_reset,
|
2006-11-03 04:29:12 +08:00
|
|
|
|
.get_drvinfo = usbnet_get_drvinfo,
|
2005-09-01 00:53:10 +08:00
|
|
|
|
.get_msglevel = usbnet_get_msglevel,
|
|
|
|
|
.set_msglevel = usbnet_set_msglevel,
|
2012-04-04 06:59:41 +08:00
|
|
|
|
.get_ts_info = ethtool_op_get_ts_info,
|
2005-09-01 00:53:10 +08:00
|
|
|
|
};
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk
pipes are responsible for transfering packets, so it is reasonable
to stop bulk transfer after link is reported as off.
Two adavantages may be obtained with stopping bulk transfer
after link becomes off:
- USB bus bandwidth is saved(USB bus is shared bus except for
USB3.0), for example, lots of 'IN' token packets and 'NYET'
handshake packets is transfered on 2.0 bus.
- probabaly power might be saved for usb host controller since
cancelling bulk transfer may disable the asynchronous schedule of
host controller.
With this patch, when link becomes off, about ~10% performance
boost can be found on bulk transfer of anther usb device which
is attached to same bus with the usbnet device, see below
test on next-20130410:
- read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard
with below command after unplugging ethernet cable:
dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800
- without the patch
1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s
2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s
3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s
4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s
5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s
average: 23.6MB/s
- with the patch
1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s
2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s
3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s
4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s
5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s
average: 26.1MB/s
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-11 12:40:40 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
/* hard_mtu or rx_urb_size may change during link change */
|
|
|
|
|
usbnet_update_max_qlen(dev);
|
|
|
|
|
|
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk
pipes are responsible for transfering packets, so it is reasonable
to stop bulk transfer after link is reported as off.
Two adavantages may be obtained with stopping bulk transfer
after link becomes off:
- USB bus bandwidth is saved(USB bus is shared bus except for
USB3.0), for example, lots of 'IN' token packets and 'NYET'
handshake packets is transfered on 2.0 bus.
- probabaly power might be saved for usb host controller since
cancelling bulk transfer may disable the asynchronous schedule of
host controller.
With this patch, when link becomes off, about ~10% performance
boost can be found on bulk transfer of anther usb device which
is attached to same bus with the usbnet device, see below
test on next-20130410:
- read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard
with below command after unplugging ethernet cable:
dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800
- without the patch
1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s
2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s
3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s
4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s
5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s
average: 23.6MB/s
- with the patch
1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s
2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s
3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s
4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s
5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s
average: 26.1MB/s
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-11 12:40:40 +08:00
|
|
|
|
clear_bit(EVENT_LINK_CHANGE, &dev->flags);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-25 01:43:00 +08:00
|
|
|
|
static void usbnet_set_rx_mode(struct net_device *net)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
|
|
|
|
usbnet_defer_kevent(dev, EVENT_SET_RX_MODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __handle_set_rx_mode(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
if (dev->driver_info->set_rx_mode)
|
|
|
|
|
(dev->driver_info->set_rx_mode)(dev);
|
|
|
|
|
|
|
|
|
|
clear_bit(EVENT_SET_RX_MODE, &dev->flags);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
/* work that cannot be done in interrupt context uses keventd.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: with 2.5 we could do more of this using completion callbacks,
|
|
|
|
|
* especially now that control transfers can be queued.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2015-04-09 16:09:04 +08:00
|
|
|
|
usbnet_deferred_kevent (struct work_struct *work)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
2006-11-22 22:57:56 +08:00
|
|
|
|
struct usbnet *dev =
|
|
|
|
|
container_of(work, struct usbnet, kevent);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
int status;
|
|
|
|
|
|
|
|
|
|
/* usb_clear_halt() needs a thread context */
|
|
|
|
|
if (test_bit (EVENT_TX_HALT, &dev->flags)) {
|
|
|
|
|
unlink_urbs (dev, &dev->txq);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
status = usb_autopm_get_interface(dev->intf);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
goto fail_pipe;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
status = usb_clear_halt (dev->udev, dev->out);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if (status < 0 &&
|
|
|
|
|
status != -EPIPE &&
|
|
|
|
|
status != -ESHUTDOWN) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (netif_msg_tx_err (dev))
|
2009-12-04 07:31:18 +08:00
|
|
|
|
fail_pipe:
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_err(dev->net, "can't clear tx halt, status %d\n",
|
|
|
|
|
status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
} else {
|
|
|
|
|
clear_bit (EVENT_TX_HALT, &dev->flags);
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
if (status != -ESHUTDOWN)
|
|
|
|
|
netif_wake_queue (dev->net);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (test_bit (EVENT_RX_HALT, &dev->flags)) {
|
|
|
|
|
unlink_urbs (dev, &dev->rxq);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
status = usb_autopm_get_interface(dev->intf);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
goto fail_halt;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
status = usb_clear_halt (dev->udev, dev->in);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if (status < 0 &&
|
|
|
|
|
status != -EPIPE &&
|
|
|
|
|
status != -ESHUTDOWN) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (netif_msg_rx_err (dev))
|
2009-12-04 07:31:18 +08:00
|
|
|
|
fail_halt:
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_err(dev->net, "can't clear rx halt, status %d\n",
|
|
|
|
|
status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
} else {
|
|
|
|
|
clear_bit (EVENT_RX_HALT, &dev->flags);
|
|
|
|
|
tasklet_schedule (&dev->bh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* tasklet could resubmit itself forever if memory is tight */
|
|
|
|
|
if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
|
|
|
|
|
struct urb *urb = NULL;
|
2010-08-10 17:50:55 +08:00
|
|
|
|
int resched = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
if (netif_running (dev->net))
|
|
|
|
|
urb = usb_alloc_urb (0, GFP_KERNEL);
|
|
|
|
|
else
|
|
|
|
|
clear_bit (EVENT_RX_MEMORY, &dev->flags);
|
|
|
|
|
if (urb != NULL) {
|
|
|
|
|
clear_bit (EVENT_RX_MEMORY, &dev->flags);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
status = usb_autopm_get_interface(dev->intf);
|
2011-02-10 18:58:45 +08:00
|
|
|
|
if (status < 0) {
|
|
|
|
|
usb_free_urb(urb);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
goto fail_lowmem;
|
2011-02-10 18:58:45 +08:00
|
|
|
|
}
|
2010-08-10 17:50:55 +08:00
|
|
|
|
if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK)
|
|
|
|
|
resched = 0;
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
fail_lowmem:
|
2010-08-10 17:50:55 +08:00
|
|
|
|
if (resched)
|
|
|
|
|
tasklet_schedule (&dev->bh);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-23 06:07:02 +08:00
|
|
|
|
if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
|
2007-02-16 10:52:30 +08:00
|
|
|
|
struct driver_info *info = dev->driver_info;
|
2005-04-23 06:07:02 +08:00
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
|
|
clear_bit (EVENT_LINK_RESET, &dev->flags);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
status = usb_autopm_get_interface(dev->intf);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
goto skip_reset;
|
2005-04-23 06:07:02 +08:00
|
|
|
|
if(info->link_reset && (retval = info->link_reset(dev)) < 0) {
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
skip_reset:
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_info(dev->net, "link reset failed (%d) usbnet usb-%s-%s, %s\n",
|
|
|
|
|
retval,
|
|
|
|
|
dev->udev->bus->bus_name,
|
|
|
|
|
dev->udev->devpath,
|
|
|
|
|
info->description);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
} else {
|
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
2005-04-23 06:07:02 +08:00
|
|
|
|
}
|
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk
pipes are responsible for transfering packets, so it is reasonable
to stop bulk transfer after link is reported as off.
Two adavantages may be obtained with stopping bulk transfer
after link becomes off:
- USB bus bandwidth is saved(USB bus is shared bus except for
USB3.0), for example, lots of 'IN' token packets and 'NYET'
handshake packets is transfered on 2.0 bus.
- probabaly power might be saved for usb host controller since
cancelling bulk transfer may disable the asynchronous schedule of
host controller.
With this patch, when link becomes off, about ~10% performance
boost can be found on bulk transfer of anther usb device which
is attached to same bus with the usbnet device, see below
test on next-20130410:
- read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard
with below command after unplugging ethernet cable:
dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800
- without the patch
1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s
2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s
3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s
4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s
5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s
average: 23.6MB/s
- with the patch
1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s
2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s
3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s
4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s
5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s
average: 26.1MB/s
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-11 12:40:40 +08:00
|
|
|
|
|
|
|
|
|
/* handle link change from link resetting */
|
|
|
|
|
__handle_link_change(dev);
|
2005-04-23 06:07:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk
pipes are responsible for transfering packets, so it is reasonable
to stop bulk transfer after link is reported as off.
Two adavantages may be obtained with stopping bulk transfer
after link becomes off:
- USB bus bandwidth is saved(USB bus is shared bus except for
USB3.0), for example, lots of 'IN' token packets and 'NYET'
handshake packets is transfered on 2.0 bus.
- probabaly power might be saved for usb host controller since
cancelling bulk transfer may disable the asynchronous schedule of
host controller.
With this patch, when link becomes off, about ~10% performance
boost can be found on bulk transfer of anther usb device which
is attached to same bus with the usbnet device, see below
test on next-20130410:
- read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard
with below command after unplugging ethernet cable:
dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800
- without the patch
1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s
2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s
3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s
4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s
5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s
average: 23.6MB/s
- with the patch
1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s
2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s
3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s
4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s
5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s
average: 26.1MB/s
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-11 12:40:40 +08:00
|
|
|
|
if (test_bit (EVENT_LINK_CHANGE, &dev->flags))
|
|
|
|
|
__handle_link_change(dev);
|
|
|
|
|
|
2014-10-25 01:43:00 +08:00
|
|
|
|
if (test_bit (EVENT_SET_RX_MODE, &dev->flags))
|
|
|
|
|
__handle_set_rx_mode(dev);
|
|
|
|
|
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (dev->flags)
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
|
static void tx_complete (struct urb *urb)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct sk_buff *skb = (struct sk_buff *) urb->context;
|
|
|
|
|
struct skb_data *entry = (struct skb_data *) skb->cb;
|
|
|
|
|
struct usbnet *dev = entry->dev;
|
|
|
|
|
|
|
|
|
|
if (urb->status == 0) {
|
2015-02-27 03:34:37 +08:00
|
|
|
|
dev->net->stats.tx_packets += entry->packets;
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.tx_bytes += entry->length;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
} else {
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.tx_errors++;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
switch (urb->status) {
|
|
|
|
|
case -EPIPE:
|
2005-09-01 00:53:10 +08:00
|
|
|
|
usbnet_defer_kevent (dev, EVENT_TX_HALT);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* software-driven interface shutdown */
|
|
|
|
|
case -ECONNRESET: // async unlink
|
|
|
|
|
case -ESHUTDOWN: // hardware gone
|
|
|
|
|
break;
|
|
|
|
|
|
2014-09-19 23:32:23 +08:00
|
|
|
|
/* like rx, tx gets controller i/o faults during hub_wq
|
|
|
|
|
* delays and so it uses the same throttling mechanism.
|
|
|
|
|
*/
|
2006-09-19 13:49:02 +08:00
|
|
|
|
case -EPROTO:
|
|
|
|
|
case -ETIME:
|
|
|
|
|
case -EILSEQ:
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_mark_last_busy(dev->udev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (!timer_pending (&dev->delay)) {
|
|
|
|
|
mod_timer (&dev->delay,
|
|
|
|
|
jiffies + THROTTLE_JIFFIES);
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, link, dev->net,
|
|
|
|
|
"tx throttle %d\n", urb->status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
netif_stop_queue (dev->net);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, tx_err, dev->net,
|
|
|
|
|
"tx err %d\n", entry->urb->status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface_async(dev->intf);
|
2012-04-26 11:33:46 +08:00
|
|
|
|
(void) defer_bh(dev, skb, &dev->txq, tx_done);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
2009-03-21 03:35:54 +08:00
|
|
|
|
void usbnet_tx_timeout (struct net_device *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
|
|
|
|
|
|
|
|
|
unlink_urbs (dev, &dev->txq);
|
|
|
|
|
tasklet_schedule (&dev->bh);
|
2014-08-01 20:01:51 +08:00
|
|
|
|
/* this needs to be handled individually because the generic layer
|
|
|
|
|
* doesn't know what is sufficient and could not restore private
|
|
|
|
|
* information if a remedy of an unconditional reset were used.
|
|
|
|
|
*/
|
|
|
|
|
if (dev->driver_info->recover)
|
|
|
|
|
(dev->driver_info->recover)(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2009-03-21 03:35:54 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_tx_timeout);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
2013-08-08 21:48:24 +08:00
|
|
|
|
static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
|
|
|
|
|
{
|
|
|
|
|
unsigned num_sgs, total_len = 0;
|
|
|
|
|
int i, s = 0;
|
|
|
|
|
|
|
|
|
|
num_sgs = skb_shinfo(skb)->nr_frags + 1;
|
|
|
|
|
if (num_sgs == 1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2013-09-23 20:59:35 +08:00
|
|
|
|
/* reserve one for zero packet */
|
|
|
|
|
urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist),
|
|
|
|
|
GFP_ATOMIC);
|
2013-08-08 21:48:24 +08:00
|
|
|
|
if (!urb->sg)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
urb->num_sgs = num_sgs;
|
2014-01-11 06:10:17 +08:00
|
|
|
|
sg_init_table(urb->sg, urb->num_sgs + 1);
|
2013-08-08 21:48:24 +08:00
|
|
|
|
|
|
|
|
|
sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));
|
|
|
|
|
total_len += skb_headlen(skb);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
|
|
|
struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i];
|
|
|
|
|
|
|
|
|
|
total_len += skb_frag_size(f);
|
|
|
|
|
sg_set_page(&urb->sg[i + s], f->page.p, f->size,
|
|
|
|
|
f->page_offset);
|
|
|
|
|
}
|
|
|
|
|
urb->transfer_buffer_length = total_len;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-01 03:50:45 +08:00
|
|
|
|
netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
|
|
|
|
struct net_device *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = netdev_priv(net);
|
2015-05-06 21:09:40 +08:00
|
|
|
|
unsigned int length;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
struct urb *urb = NULL;
|
|
|
|
|
struct skb_data *entry;
|
|
|
|
|
struct driver_info *info = dev->driver_info;
|
|
|
|
|
unsigned long flags;
|
2009-09-01 03:50:45 +08:00
|
|
|
|
int retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2011-11-07 13:54:58 +08:00
|
|
|
|
if (skb)
|
|
|
|
|
skb_tx_timestamp(skb);
|
2011-09-29 12:06:26 +08:00
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// some devices want funky USB-level framing, for
|
|
|
|
|
// win32 driver (usually) and/or hardware quirks
|
|
|
|
|
if (info->tx_fixup) {
|
|
|
|
|
skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
|
|
|
|
|
if (!skb) {
|
2013-01-31 16:36:05 +08:00
|
|
|
|
/* packet collected; minidriver waiting for more */
|
|
|
|
|
if (info->flags & FLAG_MULTI_PACKET)
|
2010-11-30 07:23:27 +08:00
|
|
|
|
goto not_drop;
|
2013-01-31 16:36:05 +08:00
|
|
|
|
netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
|
|
|
|
|
goto drop;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, tx_err, dev->net, "no urb\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
goto drop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry = (struct skb_data *) skb->cb;
|
|
|
|
|
entry->urb = urb;
|
|
|
|
|
entry->dev = dev;
|
|
|
|
|
|
|
|
|
|
usb_fill_bulk_urb (urb, dev->udev, dev->out,
|
|
|
|
|
skb->data, skb->len, tx_complete, skb);
|
2013-08-08 21:48:24 +08:00
|
|
|
|
if (dev->can_dma_sg) {
|
|
|
|
|
if (build_dma_sg(skb, urb) < 0)
|
|
|
|
|
goto drop;
|
|
|
|
|
}
|
2013-09-23 20:59:35 +08:00
|
|
|
|
length = urb->transfer_buffer_length;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/* don't assume the hardware handles USB_ZERO_PACKET
|
|
|
|
|
* NOTE: strictly conforming cdc-ether devices should expect
|
|
|
|
|
* the ZLP here, but ignore the one-byte packet.
|
2010-11-30 07:23:27 +08:00
|
|
|
|
* NOTE2: CDC NCM specification is different from CDC ECM when
|
|
|
|
|
* handling ZLP/short packets, so cdc_ncm driver will make short
|
|
|
|
|
* packet itself if needed.
|
2005-04-17 06:20:36 +08:00
|
|
|
|
*/
|
2010-04-06 22:23:07 +08:00
|
|
|
|
if (length % dev->maxpacket == 0) {
|
|
|
|
|
if (!(info->flags & FLAG_SEND_ZLP)) {
|
2010-11-30 07:23:27 +08:00
|
|
|
|
if (!(info->flags & FLAG_MULTI_PACKET)) {
|
2013-09-23 20:59:35 +08:00
|
|
|
|
length++;
|
|
|
|
|
if (skb_tailroom(skb) && !urb->num_sgs) {
|
2010-11-30 07:23:27 +08:00
|
|
|
|
skb->data[skb->len] = 0;
|
|
|
|
|
__skb_put(skb, 1);
|
2013-09-23 20:59:35 +08:00
|
|
|
|
} else if (urb->num_sgs)
|
|
|
|
|
sg_set_buf(&urb->sg[urb->num_sgs++],
|
|
|
|
|
dev->padding_pkt, 1);
|
2010-04-06 22:23:07 +08:00
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
urb->transfer_flags |= URB_ZERO_PACKET;
|
2007-06-27 14:48:15 +08:00
|
|
|
|
}
|
2015-03-26 04:41:33 +08:00
|
|
|
|
urb->transfer_buffer_length = length;
|
|
|
|
|
|
|
|
|
|
if (info->flags & FLAG_MULTI_PACKET) {
|
|
|
|
|
/* Driver has set number of packets and a length delta.
|
|
|
|
|
* Calculate the complete length and ensure that it's
|
|
|
|
|
* positive.
|
|
|
|
|
*/
|
|
|
|
|
entry->length += length;
|
|
|
|
|
if (WARN_ON_ONCE(entry->length <= 0))
|
|
|
|
|
entry->length = length;
|
|
|
|
|
} else {
|
|
|
|
|
usbnet_set_skb_tx_stats(skb, 1, length);
|
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2009-12-04 07:31:18 +08:00
|
|
|
|
spin_lock_irqsave(&dev->txq.lock, flags);
|
|
|
|
|
retval = usb_autopm_get_interface_async(dev->intf);
|
|
|
|
|
if (retval < 0) {
|
|
|
|
|
spin_unlock_irqrestore(&dev->txq.lock, flags);
|
|
|
|
|
goto drop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
|
/* if this triggers the device is still a sleep */
|
|
|
|
|
if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) {
|
|
|
|
|
/* transmission will be done in resume */
|
|
|
|
|
usb_anchor_urb(urb, &dev->deferred);
|
|
|
|
|
/* no use to process more packets */
|
|
|
|
|
netif_stop_queue(net);
|
2012-10-26 02:17:54 +08:00
|
|
|
|
usb_put_urb(urb);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
spin_unlock_irqrestore(&dev->txq.lock, flags);
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_dbg(dev->net, "Delaying transmission for resumption\n");
|
2009-12-04 07:31:18 +08:00
|
|
|
|
goto deferred;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
|
|
|
|
|
case -EPIPE:
|
|
|
|
|
netif_stop_queue (net);
|
2005-09-01 00:53:10 +08:00
|
|
|
|
usbnet_defer_kevent (dev, EVENT_TX_HALT);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface_async(dev->intf);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_autopm_put_interface_async(dev->intf);
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, tx_err, dev->net,
|
|
|
|
|
"tx: submit urb err %d\n", retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
net->trans_start = jiffies;
|
2012-04-26 11:33:46 +08:00
|
|
|
|
__usbnet_queue_skb(&dev->txq, skb, tx_start);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (dev->txq.qlen >= TX_QLEN (dev))
|
|
|
|
|
netif_stop_queue (net);
|
|
|
|
|
}
|
|
|
|
|
spin_unlock_irqrestore (&dev->txq.lock, flags);
|
|
|
|
|
|
|
|
|
|
if (retval) {
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
drop:
|
2009-06-30 00:53:28 +08:00
|
|
|
|
dev->net->stats.tx_dropped++;
|
2010-11-30 07:23:27 +08:00
|
|
|
|
not_drop:
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (skb)
|
|
|
|
|
dev_kfree_skb_any (skb);
|
2013-08-08 21:48:24 +08:00
|
|
|
|
if (urb) {
|
|
|
|
|
kfree(urb->sg);
|
|
|
|
|
usb_free_urb(urb);
|
|
|
|
|
}
|
2010-02-17 18:30:24 +08:00
|
|
|
|
} else
|
|
|
|
|
netif_dbg(dev, tx_queued, dev->net,
|
2015-05-06 21:09:40 +08:00
|
|
|
|
"> tx, len %u, type 0x%x\n", length, skb->protocol);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
|
deferred:
|
|
|
|
|
#endif
|
2009-09-01 03:50:45 +08:00
|
|
|
|
return NETDEV_TX_OK;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
2009-03-21 03:35:54 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_start_xmit);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2012-09-03 06:26:18 +08:00
|
|
|
|
static int rx_alloc_submit(struct usbnet *dev, gfp_t flags)
|
2012-06-20 05:15:53 +08:00
|
|
|
|
{
|
|
|
|
|
struct urb *urb;
|
|
|
|
|
int i;
|
2012-09-03 06:26:18 +08:00
|
|
|
|
int ret = 0;
|
2012-06-20 05:15:53 +08:00
|
|
|
|
|
|
|
|
|
/* don't refill the queue all at once */
|
|
|
|
|
for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
|
|
|
|
|
urb = usb_alloc_urb(0, flags);
|
|
|
|
|
if (urb != NULL) {
|
2012-09-03 06:26:18 +08:00
|
|
|
|
ret = rx_submit(dev, urb, flags);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
} else {
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
|
goto err;
|
2012-06-20 05:15:53 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-03 06:26:18 +08:00
|
|
|
|
err:
|
|
|
|
|
return ret;
|
2012-06-20 05:15:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
// tasklet (work deferred from completions, in_irq) or timer
|
|
|
|
|
|
|
|
|
|
static void usbnet_bh (unsigned long param)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = (struct usbnet *) param;
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
struct skb_data *entry;
|
|
|
|
|
|
|
|
|
|
while ((skb = skb_dequeue (&dev->done))) {
|
|
|
|
|
entry = (struct skb_data *) skb->cb;
|
|
|
|
|
switch (entry->state) {
|
2007-05-26 03:31:32 +08:00
|
|
|
|
case rx_done:
|
2005-04-17 06:20:36 +08:00
|
|
|
|
entry->state = rx_cleanup;
|
|
|
|
|
rx_process (dev, skb);
|
|
|
|
|
continue;
|
2007-05-26 03:31:32 +08:00
|
|
|
|
case tx_done:
|
2013-08-08 21:48:24 +08:00
|
|
|
|
kfree(entry->urb->sg);
|
2007-05-26 03:31:32 +08:00
|
|
|
|
case rx_cleanup:
|
2005-04-17 06:20:36 +08:00
|
|
|
|
usb_free_urb (entry->urb);
|
|
|
|
|
dev_kfree_skb (skb);
|
|
|
|
|
continue;
|
2007-05-26 03:31:32 +08:00
|
|
|
|
default:
|
2010-02-17 18:30:23 +08:00
|
|
|
|
netdev_dbg(dev->net, "bogus skb state %d\n", entry->state);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-29 07:51:28 +08:00
|
|
|
|
/* restart RX again after disabling due to high error rate */
|
|
|
|
|
clear_bit(EVENT_RX_KILL, &dev->flags);
|
|
|
|
|
|
2014-03-26 21:32:51 +08:00
|
|
|
|
/* waiting for all pending urbs to complete?
|
|
|
|
|
* only then can we forgo submitting anew
|
|
|
|
|
*/
|
|
|
|
|
if (waitqueue_active(&dev->wait)) {
|
|
|
|
|
if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
|
|
|
|
|
wake_up_all(&dev->wait);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
// or are we maybe short a few urbs?
|
2009-12-03 15:58:21 +08:00
|
|
|
|
} else if (netif_running (dev->net) &&
|
|
|
|
|
netif_device_present (dev->net) &&
|
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk
pipes are responsible for transfering packets, so it is reasonable
to stop bulk transfer after link is reported as off.
Two adavantages may be obtained with stopping bulk transfer
after link becomes off:
- USB bus bandwidth is saved(USB bus is shared bus except for
USB3.0), for example, lots of 'IN' token packets and 'NYET'
handshake packets is transfered on 2.0 bus.
- probabaly power might be saved for usb host controller since
cancelling bulk transfer may disable the asynchronous schedule of
host controller.
With this patch, when link becomes off, about ~10% performance
boost can be found on bulk transfer of anther usb device which
is attached to same bus with the usbnet device, see below
test on next-20130410:
- read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard
with below command after unplugging ethernet cable:
dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800
- without the patch
1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s
2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s
3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s
4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s
5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s
average: 23.6MB/s
- with the patch
1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s
2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s
3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s
4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s
5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s
average: 26.1MB/s
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-11 12:40:40 +08:00
|
|
|
|
netif_carrier_ok(dev->net) &&
|
2009-12-03 15:58:21 +08:00
|
|
|
|
!timer_pending (&dev->delay) &&
|
|
|
|
|
!test_bit (EVENT_RX_HALT, &dev->flags)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
int temp = dev->rxq.qlen;
|
2012-06-20 05:15:53 +08:00
|
|
|
|
|
|
|
|
|
if (temp < RX_QLEN(dev)) {
|
2012-09-03 06:26:18 +08:00
|
|
|
|
if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK)
|
|
|
|
|
return;
|
2010-02-17 18:30:24 +08:00
|
|
|
|
if (temp != dev->rxq.qlen)
|
|
|
|
|
netif_dbg(dev, link, dev->net,
|
|
|
|
|
"rxqlen %d --> %d\n",
|
|
|
|
|
temp, dev->rxq.qlen);
|
2012-06-20 05:15:53 +08:00
|
|
|
|
if (dev->rxq.qlen < RX_QLEN(dev))
|
2005-04-17 06:20:36 +08:00
|
|
|
|
tasklet_schedule (&dev->bh);
|
|
|
|
|
}
|
|
|
|
|
if (dev->txq.qlen < TX_QLEN (dev))
|
|
|
|
|
netif_wake_queue (dev->net);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* USB Device Driver support
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
2007-02-16 10:52:30 +08:00
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// precondition: never called in_interrupt
|
|
|
|
|
|
2005-09-01 00:52:45 +08:00
|
|
|
|
void usbnet_disconnect (struct usb_interface *intf)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev;
|
|
|
|
|
struct usb_device *xdev;
|
|
|
|
|
struct net_device *net;
|
|
|
|
|
|
|
|
|
|
dev = usb_get_intfdata(intf);
|
|
|
|
|
usb_set_intfdata(intf, NULL);
|
|
|
|
|
if (!dev)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
xdev = interface_to_usbdev (intf);
|
|
|
|
|
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_info(dev, probe, dev->net, "unregister '%s' usb-%s-%s, %s\n",
|
|
|
|
|
intf->dev.driver->name,
|
|
|
|
|
xdev->bus->bus_name, xdev->devpath,
|
|
|
|
|
dev->driver_info->description);
|
2007-02-16 10:52:30 +08:00
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
net = dev->net;
|
|
|
|
|
unregister_netdev (net);
|
|
|
|
|
|
2010-12-12 23:45:14 +08:00
|
|
|
|
cancel_work_sync(&dev->kevent);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2012-10-26 02:17:54 +08:00
|
|
|
|
usb_scuttle_anchored_urbs(&dev->deferred);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
if (dev->driver_info->unbind)
|
|
|
|
|
dev->driver_info->unbind (dev, intf);
|
|
|
|
|
|
2011-04-28 13:43:37 +08:00
|
|
|
|
usb_kill_urb(dev->interrupt);
|
|
|
|
|
usb_free_urb(dev->interrupt);
|
2013-09-23 20:59:35 +08:00
|
|
|
|
kfree(dev->padding_pkt);
|
2011-04-28 13:43:37 +08:00
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
free_netdev(net);
|
|
|
|
|
}
|
2005-09-01 00:52:45 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_disconnect);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2009-03-21 03:35:54 +08:00
|
|
|
|
static const struct net_device_ops usbnet_netdev_ops = {
|
|
|
|
|
.ndo_open = usbnet_open,
|
|
|
|
|
.ndo_stop = usbnet_stop,
|
|
|
|
|
.ndo_start_xmit = usbnet_start_xmit,
|
|
|
|
|
.ndo_tx_timeout = usbnet_tx_timeout,
|
2014-10-25 01:43:00 +08:00
|
|
|
|
.ndo_set_rx_mode = usbnet_set_rx_mode,
|
2009-03-21 03:35:54 +08:00
|
|
|
|
.ndo_change_mtu = usbnet_change_mtu,
|
|
|
|
|
.ndo_set_mac_address = eth_mac_addr,
|
|
|
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
|
|
|
};
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
// precondition: never called in_interrupt
|
|
|
|
|
|
2009-10-02 13:15:26 +08:00
|
|
|
|
static struct device_type wlan_type = {
|
|
|
|
|
.name = "wlan",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct device_type wwan_type = {
|
|
|
|
|
.name = "wwan",
|
|
|
|
|
};
|
|
|
|
|
|
2005-09-01 00:52:45 +08:00
|
|
|
|
int
|
2005-04-17 06:20:36 +08:00
|
|
|
|
usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
|
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev;
|
2007-02-16 10:52:30 +08:00
|
|
|
|
struct net_device *net;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
struct usb_host_interface *interface;
|
|
|
|
|
struct driver_info *info;
|
|
|
|
|
struct usb_device *xdev;
|
|
|
|
|
int status;
|
2007-04-18 07:10:10 +08:00
|
|
|
|
const char *name;
|
2010-11-01 22:11:54 +08:00
|
|
|
|
struct usb_driver *driver = to_usb_driver(udev->dev.driver);
|
|
|
|
|
|
|
|
|
|
/* usbnet already took usb runtime pm, so have to enable the feature
|
|
|
|
|
* for usb interface, otherwise usb_autopm_get_interface may return
|
2013-05-02 00:13:54 +08:00
|
|
|
|
* failure if RUNTIME_PM is enabled.
|
2010-11-01 22:11:54 +08:00
|
|
|
|
*/
|
|
|
|
|
if (!driver->supports_autosuspend) {
|
|
|
|
|
driver->supports_autosuspend = 1;
|
|
|
|
|
pm_runtime_enable(&udev->dev);
|
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2007-04-18 07:10:10 +08:00
|
|
|
|
name = udev->dev.driver->name;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
info = (struct driver_info *) prod->driver_info;
|
|
|
|
|
if (!info) {
|
2007-04-18 07:10:10 +08:00
|
|
|
|
dev_dbg (&udev->dev, "blacklisted by %s\n", name);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
xdev = interface_to_usbdev (udev);
|
|
|
|
|
interface = udev->cur_altsetting;
|
|
|
|
|
|
|
|
|
|
status = -ENOMEM;
|
|
|
|
|
|
|
|
|
|
// set up our own records
|
|
|
|
|
net = alloc_etherdev(sizeof(*dev));
|
2012-01-29 21:47:52 +08:00
|
|
|
|
if (!net)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
goto out;
|
|
|
|
|
|
2010-07-03 12:49:02 +08:00
|
|
|
|
/* netdev_printk() needs this so do it as early as possible */
|
|
|
|
|
SET_NETDEV_DEV(net, &udev->dev);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev = netdev_priv(net);
|
|
|
|
|
dev->udev = xdev;
|
2007-08-03 19:52:19 +08:00
|
|
|
|
dev->intf = udev;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev->driver_info = info;
|
2007-04-18 07:10:10 +08:00
|
|
|
|
dev->driver_name = name;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
|
|
|
|
|
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
|
2014-03-26 21:32:51 +08:00
|
|
|
|
init_waitqueue_head(&dev->wait);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
skb_queue_head_init (&dev->rxq);
|
|
|
|
|
skb_queue_head_init (&dev->txq);
|
|
|
|
|
skb_queue_head_init (&dev->done);
|
2009-08-12 03:57:16 +08:00
|
|
|
|
skb_queue_head_init(&dev->rxq_pause);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev->bh.func = usbnet_bh;
|
|
|
|
|
dev->bh.data = (unsigned long) dev;
|
2015-04-09 16:09:04 +08:00
|
|
|
|
INIT_WORK (&dev->kevent, usbnet_deferred_kevent);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
init_usb_anchor(&dev->deferred);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev->delay.function = usbnet_bh;
|
|
|
|
|
dev->delay.data = (unsigned long) dev;
|
|
|
|
|
init_timer (&dev->delay);
|
2006-10-09 06:08:02 +08:00
|
|
|
|
mutex_init (&dev->phy_mutex);
|
2013-05-06 19:29:23 +08:00
|
|
|
|
mutex_init(&dev->interrupt_mutex);
|
|
|
|
|
dev->interrupt_count = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
dev->net = net;
|
|
|
|
|
strcpy (net->name, "usb%d");
|
|
|
|
|
memcpy (net->dev_addr, node_id, sizeof node_id);
|
|
|
|
|
|
2005-09-01 00:53:10 +08:00
|
|
|
|
/* rx and tx sides can use different message sizes;
|
|
|
|
|
* bind() should set rx_urb_size in that case.
|
|
|
|
|
*/
|
|
|
|
|
dev->hard_mtu = net->mtu + net->hard_header_len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
#if 0
|
|
|
|
|
// dma_supported() is deeply broken on almost all architectures
|
|
|
|
|
// possible with some EHCI controllers
|
2009-04-07 10:01:13 +08:00
|
|
|
|
if (dma_supported (&udev->dev, DMA_BIT_MASK(64)))
|
2005-04-17 06:20:36 +08:00
|
|
|
|
net->features |= NETIF_F_HIGHDMA;
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-03-21 03:35:54 +08:00
|
|
|
|
net->netdev_ops = &usbnet_netdev_ops;
|
|
|
|
|
net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
net->ethtool_ops = &usbnet_ethtool_ops;
|
|
|
|
|
|
|
|
|
|
// allow device-specific bind/init procedures
|
|
|
|
|
// NOTE net->name still not usable ...
|
|
|
|
|
if (info->bind) {
|
|
|
|
|
status = info->bind (dev, udev);
|
2007-02-16 10:52:30 +08:00
|
|
|
|
if (status < 0)
|
|
|
|
|
goto out1;
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
// heuristic: "usb%d" for links we know are two-host,
|
|
|
|
|
// else "eth%d" when there's reasonable doubt. userspace
|
|
|
|
|
// can rename the link if it knows better.
|
2009-12-03 15:58:21 +08:00
|
|
|
|
if ((dev->driver_info->flags & FLAG_ETHER) != 0 &&
|
usbnet: use eth%d name for known ethernet devices
The documentation for the USB ethernet devices suggests that
only some devices are supposed to use usb0 as the network interface
name instead of eth0. The logic used there, and documented in
Kconfig for CDC is that eth0 will be used when the mac address
is a globally assigned one, but usb0 is used for the locally
managed range that is typically used on point-to-point links.
Unfortunately, this has caused a lot of pain on the smsc95xx
device that is used on the popular pandaboard without an
EEPROM to store the MAC address, which causes the driver to
call random_ether_address().
Obviously, there should be a proper MAC addressed assigned to
the device, and discussions are ongoing about how to solve
this, but this patch at least makes sure that the default
interface naming gets a little saner and matches what the
user can expect based on the documentation, including for
new devices.
The approach taken here is to flag whether a device might be a
point-to-point link with the new FLAG_POINTTOPOINT setting in
the usbnet driver_info. A driver can set both FLAG_POINTTOPOINT
and FLAG_ETHER if it is not sure (e.g. cdc_ether), or just one
of the two. The usbnet framework only looks at the MAC address
for device naming if both flags are set, otherwise it trusts the
flag.
Signed-off-by: Arnd Bergmann <arnd.bergmann@linaro.org>
Tested-by: Andy Green <andy.green@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2011-04-02 11:12:02 +08:00
|
|
|
|
((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 ||
|
|
|
|
|
(net->dev_addr [0] & 0x02) == 0))
|
2005-04-17 06:20:36 +08:00
|
|
|
|
strcpy (net->name, "eth%d");
|
2008-01-26 06:51:06 +08:00
|
|
|
|
/* WLAN devices should always be named "wlan%d" */
|
|
|
|
|
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
|
|
|
|
|
strcpy(net->name, "wlan%d");
|
2009-10-02 13:15:25 +08:00
|
|
|
|
/* WWAN devices should always be named "wwan%d" */
|
|
|
|
|
if ((dev->driver_info->flags & FLAG_WWAN) != 0)
|
|
|
|
|
strcpy(net->name, "wwan%d");
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
|
2013-01-21 14:00:31 +08:00
|
|
|
|
/* devices that cannot do ARP */
|
|
|
|
|
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
|
|
|
|
|
net->flags |= IFF_NOARP;
|
|
|
|
|
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
/* maybe the remote can't receive an Ethernet MTU */
|
|
|
|
|
if (net->mtu > (dev->hard_mtu - net->hard_header_len))
|
|
|
|
|
net->mtu = dev->hard_mtu - net->hard_header_len;
|
2005-09-01 00:53:10 +08:00
|
|
|
|
} else if (!info->in || !info->out)
|
|
|
|
|
status = usbnet_get_endpoints (dev, udev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
else {
|
|
|
|
|
dev->in = usb_rcvbulkpipe (xdev, info->in);
|
|
|
|
|
dev->out = usb_sndbulkpipe (xdev, info->out);
|
|
|
|
|
if (!(info->flags & FLAG_NO_SETINT))
|
|
|
|
|
status = usb_set_interface (xdev,
|
|
|
|
|
interface->desc.bInterfaceNumber,
|
|
|
|
|
interface->desc.bAlternateSetting);
|
|
|
|
|
else
|
|
|
|
|
status = 0;
|
|
|
|
|
|
|
|
|
|
}
|
2007-07-03 06:46:42 +08:00
|
|
|
|
if (status >= 0 && dev->status)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
status = init_status (dev, udev);
|
|
|
|
|
if (status < 0)
|
2007-02-16 10:52:30 +08:00
|
|
|
|
goto out3;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2005-09-01 00:53:10 +08:00
|
|
|
|
if (!dev->rx_urb_size)
|
|
|
|
|
dev->rx_urb_size = dev->hard_mtu;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
|
2007-02-16 10:52:30 +08:00
|
|
|
|
|
2013-09-04 15:42:32 +08:00
|
|
|
|
/* let userspace know we have a random address */
|
|
|
|
|
if (ether_addr_equal(net->dev_addr, node_id))
|
|
|
|
|
net->addr_assign_type = NET_ADDR_RANDOM;
|
|
|
|
|
|
2009-10-02 13:15:26 +08:00
|
|
|
|
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
|
|
|
|
|
SET_NETDEV_DEVTYPE(net, &wlan_type);
|
|
|
|
|
if ((dev->driver_info->flags & FLAG_WWAN) != 0)
|
|
|
|
|
SET_NETDEV_DEVTYPE(net, &wwan_type);
|
|
|
|
|
|
USBNET: centralize computing of max rx/tx qlen
This patch centralizes computing of max rx/tx qlen, because:
- RX_QLEN()/TX_QLEN() is called in hot path
- computing depends on device's usb speed, now we have ls/fs, hs, ss,
so more checks need to be involved
- in fact, max rx/tx qlen should not only depend on device USB
speed, but also depend on ethernet link speed, so we need to
consider that in future.
- if SG support is done, max tx qlen may need change too
Generally, hard_mtu and rx_urb_size are changed in bind(), reset()
and link_reset() callback, and change mtu network operation, this
patches introduces the API of usbnet_update_max_qlen(), and calls
it in above path.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-07-25 13:47:53 +08:00
|
|
|
|
/* initialize max rx_qlen and tx_qlen */
|
|
|
|
|
usbnet_update_max_qlen(dev);
|
|
|
|
|
|
2013-09-23 20:59:35 +08:00
|
|
|
|
if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) &&
|
|
|
|
|
!(info->flags & FLAG_MULTI_PACKET)) {
|
|
|
|
|
dev->padding_pkt = kzalloc(1, GFP_KERNEL);
|
2013-10-12 14:24:08 +08:00
|
|
|
|
if (!dev->padding_pkt) {
|
|
|
|
|
status = -ENOMEM;
|
2013-09-23 20:59:35 +08:00
|
|
|
|
goto out4;
|
2013-10-12 14:24:08 +08:00
|
|
|
|
}
|
2013-09-23 20:59:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
status = register_netdev (net);
|
|
|
|
|
if (status)
|
2013-09-23 20:59:35 +08:00
|
|
|
|
goto out5;
|
2010-02-17 18:30:24 +08:00
|
|
|
|
netif_info(dev, probe, dev->net,
|
|
|
|
|
"register '%s' at usb-%s-%s, %s, %pM\n",
|
|
|
|
|
udev->dev.driver->name,
|
|
|
|
|
xdev->bus->bus_name, xdev->devpath,
|
|
|
|
|
dev->driver_info->description,
|
|
|
|
|
net->dev_addr);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
// ok, it's ready to go.
|
|
|
|
|
usb_set_intfdata (udev, dev);
|
|
|
|
|
|
|
|
|
|
netif_device_attach (net);
|
|
|
|
|
|
2009-11-04 23:29:52 +08:00
|
|
|
|
if (dev->driver_info->flags & FLAG_LINK_INTR)
|
2013-04-11 12:40:39 +08:00
|
|
|
|
usbnet_link_change(dev, 0, 0);
|
2009-11-04 23:29:52 +08:00
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
2013-09-23 20:59:35 +08:00
|
|
|
|
out5:
|
|
|
|
|
kfree(dev->padding_pkt);
|
2012-04-30 06:51:03 +08:00
|
|
|
|
out4:
|
|
|
|
|
usb_free_urb(dev->interrupt);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
out3:
|
|
|
|
|
if (info->unbind)
|
|
|
|
|
info->unbind (dev, udev);
|
|
|
|
|
out1:
|
|
|
|
|
free_netdev(net);
|
|
|
|
|
out:
|
|
|
|
|
return status;
|
|
|
|
|
}
|
2005-09-01 00:52:45 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_probe);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
2007-04-30 16:37:44 +08:00
|
|
|
|
/*
|
|
|
|
|
* suspend the whole driver as soon as the first interface is suspended
|
|
|
|
|
* resume only when the last interface is resumed
|
2005-09-01 00:52:45 +08:00
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2005-09-01 00:52:45 +08:00
|
|
|
|
int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = usb_get_intfdata(intf);
|
2007-02-16 10:52:30 +08:00
|
|
|
|
|
2007-04-30 16:37:44 +08:00
|
|
|
|
if (!dev->suspend_count++) {
|
2009-12-04 07:31:18 +08:00
|
|
|
|
spin_lock_irq(&dev->txq.lock);
|
|
|
|
|
/* don't autosuspend while transmitting */
|
2011-08-20 05:49:48 +08:00
|
|
|
|
if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
|
2012-06-20 05:15:52 +08:00
|
|
|
|
dev->suspend_count--;
|
2009-12-04 07:31:18 +08:00
|
|
|
|
spin_unlock_irq(&dev->txq.lock);
|
|
|
|
|
return -EBUSY;
|
|
|
|
|
} else {
|
|
|
|
|
set_bit(EVENT_DEV_ASLEEP, &dev->flags);
|
|
|
|
|
spin_unlock_irq(&dev->txq.lock);
|
|
|
|
|
}
|
2007-08-03 19:52:19 +08:00
|
|
|
|
/*
|
|
|
|
|
* accelerate emptying of the rx and queues, to avoid
|
2007-04-30 16:37:44 +08:00
|
|
|
|
* having everything error out.
|
|
|
|
|
*/
|
|
|
|
|
netif_device_detach (dev->net);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usbnet_terminate_urbs(dev);
|
2013-05-06 19:29:23 +08:00
|
|
|
|
__usbnet_status_stop_force(dev);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
|
2007-08-03 19:52:19 +08:00
|
|
|
|
/*
|
|
|
|
|
* reattach so runtime management can use and
|
|
|
|
|
* wake the device
|
|
|
|
|
*/
|
|
|
|
|
netif_device_attach (dev->net);
|
2007-04-30 16:37:44 +08:00
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2005-09-01 00:52:45 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_suspend);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2005-09-01 00:52:45 +08:00
|
|
|
|
int usbnet_resume (struct usb_interface *intf)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
struct usbnet *dev = usb_get_intfdata(intf);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
struct urb *res;
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
if (!--dev->suspend_count) {
|
2013-05-06 19:29:23 +08:00
|
|
|
|
/* resume interrupt URB if it was previously submitted */
|
|
|
|
|
__usbnet_status_start_force(dev, GFP_NOIO);
|
2011-04-28 13:43:37 +08:00
|
|
|
|
|
2009-12-04 07:31:18 +08:00
|
|
|
|
spin_lock_irq(&dev->txq.lock);
|
|
|
|
|
while ((res = usb_get_from_anchor(&dev->deferred))) {
|
|
|
|
|
|
|
|
|
|
skb = (struct sk_buff *)res->context;
|
|
|
|
|
retval = usb_submit_urb(res, GFP_ATOMIC);
|
|
|
|
|
if (retval < 0) {
|
|
|
|
|
dev_kfree_skb_any(skb);
|
2013-08-08 21:48:24 +08:00
|
|
|
|
kfree(res->sg);
|
2009-12-04 07:31:18 +08:00
|
|
|
|
usb_free_urb(res);
|
|
|
|
|
usb_autopm_put_interface_async(dev->intf);
|
|
|
|
|
} else {
|
|
|
|
|
dev->net->trans_start = jiffies;
|
|
|
|
|
__skb_queue_tail(&dev->txq, skb);
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2009-12-04 07:31:18 +08:00
|
|
|
|
smp_mb();
|
|
|
|
|
clear_bit(EVENT_DEV_ASLEEP, &dev->flags);
|
|
|
|
|
spin_unlock_irq(&dev->txq.lock);
|
usbnet: runtime pm: fix out of memory
This patch makes use of the EVENT_DEV_OPEN flag introduced recently to
fix one out of memory issue, which can be reproduced on omap3/4 based
pandaboard/beagle XM easily with steps below:
- enable runtime pm
echo auto > /sys/devices/platform/usbhs-omap.0/ehci-omap.0/usb1/1-1/1-1.1/power/control
- ifconfig eth0 up
- then out of memroy happened, see [1] for kernel message.
Follows my analysis:
- 'ifconfig eth0 up' brings eth0 out of suspend, and usbnet_resume
is called to schedule dev->bh, then rx urbs are submited to prepare for
recieving data;
- some usbnet devices will produce garbage rx packets flood if
info->reset is not called in usbnet_open.
- so there is no enough chances for usbnet_bh to handle and release
recieved skb buffers since many rx interrupts consumes cpu, so out of memory
for atomic allocation in rx_submit happened.
This patch fixes the issue by simply not allowing schedule of usbnet_bh until device
is opened.
[1], dmesg
[ 234.712005] smsc95xx 1-1.1:1.0: rpm_resume flags 0x4
[ 234.712066] usb 1-1.1: rpm_resume flags 0x0
[ 234.712066] usb 1-1: rpm_resume flags 0x0
[ 234.712097] usb usb1: rpm_resume flags 0x0
[ 234.712127] usb usb1: usb auto-resume
[ 234.712158] ehci-omap ehci-omap.0: resume root hub
[ 234.754028] hub 1-0:1.0: hub_resume
[ 234.754821] hub 1-0:1.0: port 1: status 0507 change 0000
[ 234.756011] hub 1-0:1.0: state 7 ports 3 chg 0000 evt 0000
[ 234.756042] hub 1-0:1.0: rpm_resume flags 0x4
[ 234.756072] usb usb1: rpm_resume flags 0x0
[ 234.756164] usb usb1: rpm_resume returns 1
[ 234.756195] hub 1-0:1.0: rpm_resume returns 0
[ 234.756195] hub 1-0:1.0: rpm_suspend flags 0x4
[ 234.756225] hub 1-0:1.0: rpm_suspend returns 0
[ 234.756256] usb usb1: rpm_resume returns 0
[ 234.757141] usb 1-1: usb auto-resume
[ 234.793151] ehci-omap ehci-omap.0: GetStatus port:1 status 001005 0 ACK POWER sig=se0 PE CONNECT
[ 234.816558] usb 1-1: finish resume
[ 234.817871] hub 1-1:1.0: hub_resume
[ 234.818420] hub 1-1:1.0: port 1: status 0507 change 0000
[ 234.820495] ehci-omap ehci-omap.0: reused qh eec50220 schedule
[ 234.820495] usb 1-1: link qh256-0001/eec50220 start 1 [1/0 us]
[ 234.820587] usb 1-1: rpm_resume returns 0
[ 234.820800] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0000
[ 234.820800] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.820831] hub 1-1:1.0: rpm_resume returns 0
[ 234.820861] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.820861] hub 1-1:1.0: rpm_suspend returns 0
[ 234.821777] usb 1-1.1: usb auto-resume
[ 234.868591] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0002
[ 234.868591] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.868621] hub 1-1:1.0: rpm_resume returns 0
[ 234.868652] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.868652] hub 1-1:1.0: rpm_suspend returns 0
[ 234.879486] usb 1-1.1: finish resume
[ 234.880279] usb 1-1.1: rpm_resume returns 0
[ 234.880310] smsc95xx 1-1.1:1.0: rpm_resume returns 0
[ 238.880187] ksoftirqd/0: page allocation failure. order:0, mode:0x20
[ 238.880218] Backtrace:
[ 238.880249] [<c01b9800>] (dump_backtrace+0x0/0xf8) from [<c065e1dc>] (dump_stack+0x18/0x1c)
[ 238.880249] r6:00000000 r5:00000000 r4:00000020 r3:00000002
[ 238.880310] [<c065e1c4>] (dump_stack+0x0/0x1c) from [<c026ece4>] (__alloc_pages_nodemask+0x620/0x724)
[ 238.880340] [<c026e6c4>] (__alloc_pages_nodemask+0x0/0x724) from [<c02986d4>] (kmem_getpages.clone.34+0x34/0xc8)
[ 238.880371] [<c02986a0>] (kmem_getpages.clone.34+0x0/0xc8) from [<c02988f8>] (cache_grow.clone.42+0x84/0x154)
[ 238.880371] r6:ef871aa4 r5:ef871a80 r4:ef81fd40 r3:00000020
[ 238.880401] [<c0298874>] (cache_grow.clone.42+0x0/0x154) from [<c0298b64>] (cache_alloc_refill+0x19c/0x1f0)
[ 238.880432] [<c02989c8>] (cache_alloc_refill+0x0/0x1f0) from [<c0299804>] (kmem_cache_alloc+0x90/0x190)
[ 238.880462] [<c0299774>] (kmem_cache_alloc+0x0/0x190) from [<c052e260>] (__alloc_skb+0x34/0xe8)
[ 238.880493] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.880523] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf050d38>] (rx_complete+0x19c/0x1b0 [usbnet])
[ 238.880737] [<bf050b9c>] (rx_complete+0x0/0x1b0 [usbnet]) from [<bf006fd0>] (usb_hcd_giveback_urb+0xa8/0xf4 [usbcore])
[ 238.880737] r8:eeeced34 r7:eeecec00 r6:eeecec00 r5:00000000 r4:eec2dd20
[ 238.880767] r3:bf050b9c
[ 238.880859] [<bf006f28>] (usb_hcd_giveback_urb+0x0/0xf4 [usbcore]) from [<bf03c8f8>] (ehci_urb_done+0xb0/0xbc [ehci_hcd])
[ 238.880859] r6:00000000 r5:eec2dd20 r4:eeeced44 r3:eec2dd34
[ 238.880920] [<bf03c848>] (ehci_urb_done+0x0/0xbc [ehci_hcd]) from [<bf040204>] (qh_completions+0x308/0x3bc [ehci_hcd])
[ 238.880920] r7:00000000 r6:eeda21a0 r5:ffdfe3c0 r4:eeda21ac
[ 238.880981] [<bf03fefc>] (qh_completions+0x0/0x3bc [ehci_hcd]) from [<bf040ef8>] (scan_async+0xb0/0x16c [ehci_hcd])
[ 238.881011] [<bf040e48>] (scan_async+0x0/0x16c [ehci_hcd]) from [<bf040fec>] (ehci_work+0x38/0x90 [ehci_hcd])
[ 238.881042] [<bf040fb4>] (ehci_work+0x0/0x90 [ehci_hcd]) from [<bf042940>] (ehci_irq+0x300/0x34c [ehci_hcd])
[ 238.881072] r4:eeeced34 r3:00000001
[ 238.881134] [<bf042640>] (ehci_irq+0x0/0x34c [ehci_hcd]) from [<bf006828>] (usb_hcd_irq+0x40/0xac [usbcore])
[ 238.881195] [<bf0067e8>] (usb_hcd_irq+0x0/0xac [usbcore]) from [<c0239764>] (handle_irq_event_percpu+0xb8/0x240)
[ 238.881225] r6:eec504e0 r5:0000006d r4:eec504e0 r3:bf0067e8
[ 238.881256] [<c02396ac>] (handle_irq_event_percpu+0x0/0x240) from [<c0239930>] (handle_irq_event+0x44/0x64)
[ 238.881256] [<c02398ec>] (handle_irq_event+0x0/0x64) from [<c023bbd0>] (handle_level_irq+0xe0/0x114)
[ 238.881286] r6:0000006d r5:c080c14c r4:c080c100 r3:00020000
[ 238.881317] [<c023baf0>] (handle_level_irq+0x0/0x114) from [<c01ab090>] (asm_do_IRQ+0x90/0xd0)
[ 238.881317] r5:00000000 r4:0000006d
[ 238.881347] [<c01ab000>] (asm_do_IRQ+0x0/0xd0) from [<c06624d0>] (__irq_svc+0x50/0x134)
[ 238.881378] Exception stack(0xef837e20 to 0xef837e68)
[ 238.881378] 7e20: 00000001 00185610 016cc000 c00490c0 eb380000 ef800540 00000020 00004ae0
[ 238.881408] 7e40: 00000020 bf0509f4 60000013 ef837e9c ef837e40 ef837e68 c0226f0c c0298ca0
[ 238.881408] 7e60: 20000013 ffffffff
[ 238.881408] r5:fa240100 r4:ffffffff
[ 238.881439] [<c0298bb8>] (__kmalloc_track_caller+0x0/0x1d0) from [<c052e284>] (__alloc_skb+0x58/0xe8)
[ 238.881469] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.881500] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf0513d8>] (usbnet_bh+0x1b4/0x250 [usbnet])
[ 238.881530] [<bf051224>] (usbnet_bh+0x0/0x250 [usbnet]) from [<c01f912c>] (tasklet_action+0xb0/0x1f8)
[ 238.881530] r6:00000000 r5:ef9757f0 r4:ef9757ec r3:bf051224
[ 238.881561] [<c01f907c>] (tasklet_action+0x0/0x1f8) from [<c01f97ac>] (__do_softirq+0x140/0x290)
[ 238.881561] r8:00000006 r7:00000101 r6:00000000 r5:c0806098 r4:00000001
[ 238.881591] r3:c01f907c
[ 238.881622] [<c01f966c>] (__do_softirq+0x0/0x290) from [<c01f99cc>] (run_ksoftirqd+0xd0/0x1f4)
[ 238.881622] [<c01f98fc>] (run_ksoftirqd+0x0/0x1f4) from [<c02113b0>] (kthread+0x90/0x98)
[ 238.881652] r7:00000013 r6:c01f98fc r5:00000000 r4:ef831efc
[ 238.881683] [<c0211320>] (kthread+0x0/0x98) from [<c01f62f4>] (do_exit+0x0/0x374)
[ 238.881713] r6:c01f62f4 r5:c0211320 r4:ef831efc
[ 238.881713] Mem-info:
[ 238.881744] Normal per-cpu:
[ 238.881744] CPU 0: hi: 186, btch: 31 usd: 38
[ 238.881744] CPU 1: hi: 186, btch: 31 usd: 169
[ 238.881774] HighMem per-cpu:
[ 238.881774] CPU 0: hi: 90, btch: 15 usd: 66
[ 238.881774] CPU 1: hi: 90, btch: 15 usd: 86
[ 238.881805] active_anon:544 inactive_anon:71 isolated_anon:0
[ 238.881805] active_file:926 inactive_file:2538 isolated_file:0
[ 238.881805] unevictable:0 dirty:10 writeback:0 unstable:0
[ 238.881805] free:57782 slab_reclaimable:864 slab_unreclaimable:186898
[ 238.881805] mapped:632 shmem:144 pagetables:50 bounce:0
[ 238.881835] Normal free:1328kB min:3532kB low:4412kB high:5296kB active_anon:0kB inactive_anon:0kB active_file:880kB inactive_file:848kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:780288kB mlocked:0kB dirty:36kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:3456kB slab_unreclaimable:747592kB kernel_stack:392kB pagetables:200kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881866] lowmem_reserve[]: 0 1904 1904
[ 238.881896] HighMem free:229800kB min:236kB low:508kB high:784kB active_anon:2176kB inactive_anon:284kB active_file:2824kB inactive_file:9304kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:243712kB mlocked:0kB dirty:4kB writeback:0kB mapped:2528kB shmem:576kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881927] lowmem_reserve[]: 0 0 0
[ 238.881958] Normal: 0*4kB 4*8kB 6*16kB 0*32kB 1*64kB 1*128kB 0*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1344kB
[ 238.882019] HighMem: 6*4kB 2*8kB 4*16kB 4*32kB 1*64kB 1*128kB 0*256kB 2*512kB 3*1024kB 0*2048kB 55*4096kB = 229800kB
[ 238.882080] 3610 total pagecache pages
[ 238.882080] 0 pages in swap cache
[ 238.882080] Swap cache stats: add 0, delete 0, find 0/0
[ 238.882110] Free swap = 0kB
[ 238.882110] Total swap = 0kB
[ 238.933776] 262144 pages of RAM
[ 238.933776] 58240 free pages
[ 238.933776] 10503 reserved pages
[ 238.933776] 187773 slab pages
[ 238.933807] 2475 pages shared
[ 238.933807] 0 pages swap cached
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2011-04-29 06:37:09 +08:00
|
|
|
|
|
|
|
|
|
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
|
2014-03-26 21:32:51 +08:00
|
|
|
|
/* handle remote wakeup ASAP
|
|
|
|
|
* we cannot race against stop
|
|
|
|
|
*/
|
|
|
|
|
if (netif_device_present(dev->net) &&
|
2012-06-20 05:15:53 +08:00
|
|
|
|
!timer_pending(&dev->delay) &&
|
|
|
|
|
!test_bit(EVENT_RX_HALT, &dev->flags))
|
2012-08-27 04:41:38 +08:00
|
|
|
|
rx_alloc_submit(dev, GFP_NOIO);
|
2012-06-20 05:15:53 +08:00
|
|
|
|
|
usbnet: runtime pm: fix out of memory
This patch makes use of the EVENT_DEV_OPEN flag introduced recently to
fix one out of memory issue, which can be reproduced on omap3/4 based
pandaboard/beagle XM easily with steps below:
- enable runtime pm
echo auto > /sys/devices/platform/usbhs-omap.0/ehci-omap.0/usb1/1-1/1-1.1/power/control
- ifconfig eth0 up
- then out of memroy happened, see [1] for kernel message.
Follows my analysis:
- 'ifconfig eth0 up' brings eth0 out of suspend, and usbnet_resume
is called to schedule dev->bh, then rx urbs are submited to prepare for
recieving data;
- some usbnet devices will produce garbage rx packets flood if
info->reset is not called in usbnet_open.
- so there is no enough chances for usbnet_bh to handle and release
recieved skb buffers since many rx interrupts consumes cpu, so out of memory
for atomic allocation in rx_submit happened.
This patch fixes the issue by simply not allowing schedule of usbnet_bh until device
is opened.
[1], dmesg
[ 234.712005] smsc95xx 1-1.1:1.0: rpm_resume flags 0x4
[ 234.712066] usb 1-1.1: rpm_resume flags 0x0
[ 234.712066] usb 1-1: rpm_resume flags 0x0
[ 234.712097] usb usb1: rpm_resume flags 0x0
[ 234.712127] usb usb1: usb auto-resume
[ 234.712158] ehci-omap ehci-omap.0: resume root hub
[ 234.754028] hub 1-0:1.0: hub_resume
[ 234.754821] hub 1-0:1.0: port 1: status 0507 change 0000
[ 234.756011] hub 1-0:1.0: state 7 ports 3 chg 0000 evt 0000
[ 234.756042] hub 1-0:1.0: rpm_resume flags 0x4
[ 234.756072] usb usb1: rpm_resume flags 0x0
[ 234.756164] usb usb1: rpm_resume returns 1
[ 234.756195] hub 1-0:1.0: rpm_resume returns 0
[ 234.756195] hub 1-0:1.0: rpm_suspend flags 0x4
[ 234.756225] hub 1-0:1.0: rpm_suspend returns 0
[ 234.756256] usb usb1: rpm_resume returns 0
[ 234.757141] usb 1-1: usb auto-resume
[ 234.793151] ehci-omap ehci-omap.0: GetStatus port:1 status 001005 0 ACK POWER sig=se0 PE CONNECT
[ 234.816558] usb 1-1: finish resume
[ 234.817871] hub 1-1:1.0: hub_resume
[ 234.818420] hub 1-1:1.0: port 1: status 0507 change 0000
[ 234.820495] ehci-omap ehci-omap.0: reused qh eec50220 schedule
[ 234.820495] usb 1-1: link qh256-0001/eec50220 start 1 [1/0 us]
[ 234.820587] usb 1-1: rpm_resume returns 0
[ 234.820800] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0000
[ 234.820800] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.820831] hub 1-1:1.0: rpm_resume returns 0
[ 234.820861] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.820861] hub 1-1:1.0: rpm_suspend returns 0
[ 234.821777] usb 1-1.1: usb auto-resume
[ 234.868591] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0002
[ 234.868591] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.868621] hub 1-1:1.0: rpm_resume returns 0
[ 234.868652] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.868652] hub 1-1:1.0: rpm_suspend returns 0
[ 234.879486] usb 1-1.1: finish resume
[ 234.880279] usb 1-1.1: rpm_resume returns 0
[ 234.880310] smsc95xx 1-1.1:1.0: rpm_resume returns 0
[ 238.880187] ksoftirqd/0: page allocation failure. order:0, mode:0x20
[ 238.880218] Backtrace:
[ 238.880249] [<c01b9800>] (dump_backtrace+0x0/0xf8) from [<c065e1dc>] (dump_stack+0x18/0x1c)
[ 238.880249] r6:00000000 r5:00000000 r4:00000020 r3:00000002
[ 238.880310] [<c065e1c4>] (dump_stack+0x0/0x1c) from [<c026ece4>] (__alloc_pages_nodemask+0x620/0x724)
[ 238.880340] [<c026e6c4>] (__alloc_pages_nodemask+0x0/0x724) from [<c02986d4>] (kmem_getpages.clone.34+0x34/0xc8)
[ 238.880371] [<c02986a0>] (kmem_getpages.clone.34+0x0/0xc8) from [<c02988f8>] (cache_grow.clone.42+0x84/0x154)
[ 238.880371] r6:ef871aa4 r5:ef871a80 r4:ef81fd40 r3:00000020
[ 238.880401] [<c0298874>] (cache_grow.clone.42+0x0/0x154) from [<c0298b64>] (cache_alloc_refill+0x19c/0x1f0)
[ 238.880432] [<c02989c8>] (cache_alloc_refill+0x0/0x1f0) from [<c0299804>] (kmem_cache_alloc+0x90/0x190)
[ 238.880462] [<c0299774>] (kmem_cache_alloc+0x0/0x190) from [<c052e260>] (__alloc_skb+0x34/0xe8)
[ 238.880493] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.880523] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf050d38>] (rx_complete+0x19c/0x1b0 [usbnet])
[ 238.880737] [<bf050b9c>] (rx_complete+0x0/0x1b0 [usbnet]) from [<bf006fd0>] (usb_hcd_giveback_urb+0xa8/0xf4 [usbcore])
[ 238.880737] r8:eeeced34 r7:eeecec00 r6:eeecec00 r5:00000000 r4:eec2dd20
[ 238.880767] r3:bf050b9c
[ 238.880859] [<bf006f28>] (usb_hcd_giveback_urb+0x0/0xf4 [usbcore]) from [<bf03c8f8>] (ehci_urb_done+0xb0/0xbc [ehci_hcd])
[ 238.880859] r6:00000000 r5:eec2dd20 r4:eeeced44 r3:eec2dd34
[ 238.880920] [<bf03c848>] (ehci_urb_done+0x0/0xbc [ehci_hcd]) from [<bf040204>] (qh_completions+0x308/0x3bc [ehci_hcd])
[ 238.880920] r7:00000000 r6:eeda21a0 r5:ffdfe3c0 r4:eeda21ac
[ 238.880981] [<bf03fefc>] (qh_completions+0x0/0x3bc [ehci_hcd]) from [<bf040ef8>] (scan_async+0xb0/0x16c [ehci_hcd])
[ 238.881011] [<bf040e48>] (scan_async+0x0/0x16c [ehci_hcd]) from [<bf040fec>] (ehci_work+0x38/0x90 [ehci_hcd])
[ 238.881042] [<bf040fb4>] (ehci_work+0x0/0x90 [ehci_hcd]) from [<bf042940>] (ehci_irq+0x300/0x34c [ehci_hcd])
[ 238.881072] r4:eeeced34 r3:00000001
[ 238.881134] [<bf042640>] (ehci_irq+0x0/0x34c [ehci_hcd]) from [<bf006828>] (usb_hcd_irq+0x40/0xac [usbcore])
[ 238.881195] [<bf0067e8>] (usb_hcd_irq+0x0/0xac [usbcore]) from [<c0239764>] (handle_irq_event_percpu+0xb8/0x240)
[ 238.881225] r6:eec504e0 r5:0000006d r4:eec504e0 r3:bf0067e8
[ 238.881256] [<c02396ac>] (handle_irq_event_percpu+0x0/0x240) from [<c0239930>] (handle_irq_event+0x44/0x64)
[ 238.881256] [<c02398ec>] (handle_irq_event+0x0/0x64) from [<c023bbd0>] (handle_level_irq+0xe0/0x114)
[ 238.881286] r6:0000006d r5:c080c14c r4:c080c100 r3:00020000
[ 238.881317] [<c023baf0>] (handle_level_irq+0x0/0x114) from [<c01ab090>] (asm_do_IRQ+0x90/0xd0)
[ 238.881317] r5:00000000 r4:0000006d
[ 238.881347] [<c01ab000>] (asm_do_IRQ+0x0/0xd0) from [<c06624d0>] (__irq_svc+0x50/0x134)
[ 238.881378] Exception stack(0xef837e20 to 0xef837e68)
[ 238.881378] 7e20: 00000001 00185610 016cc000 c00490c0 eb380000 ef800540 00000020 00004ae0
[ 238.881408] 7e40: 00000020 bf0509f4 60000013 ef837e9c ef837e40 ef837e68 c0226f0c c0298ca0
[ 238.881408] 7e60: 20000013 ffffffff
[ 238.881408] r5:fa240100 r4:ffffffff
[ 238.881439] [<c0298bb8>] (__kmalloc_track_caller+0x0/0x1d0) from [<c052e284>] (__alloc_skb+0x58/0xe8)
[ 238.881469] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.881500] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf0513d8>] (usbnet_bh+0x1b4/0x250 [usbnet])
[ 238.881530] [<bf051224>] (usbnet_bh+0x0/0x250 [usbnet]) from [<c01f912c>] (tasklet_action+0xb0/0x1f8)
[ 238.881530] r6:00000000 r5:ef9757f0 r4:ef9757ec r3:bf051224
[ 238.881561] [<c01f907c>] (tasklet_action+0x0/0x1f8) from [<c01f97ac>] (__do_softirq+0x140/0x290)
[ 238.881561] r8:00000006 r7:00000101 r6:00000000 r5:c0806098 r4:00000001
[ 238.881591] r3:c01f907c
[ 238.881622] [<c01f966c>] (__do_softirq+0x0/0x290) from [<c01f99cc>] (run_ksoftirqd+0xd0/0x1f4)
[ 238.881622] [<c01f98fc>] (run_ksoftirqd+0x0/0x1f4) from [<c02113b0>] (kthread+0x90/0x98)
[ 238.881652] r7:00000013 r6:c01f98fc r5:00000000 r4:ef831efc
[ 238.881683] [<c0211320>] (kthread+0x0/0x98) from [<c01f62f4>] (do_exit+0x0/0x374)
[ 238.881713] r6:c01f62f4 r5:c0211320 r4:ef831efc
[ 238.881713] Mem-info:
[ 238.881744] Normal per-cpu:
[ 238.881744] CPU 0: hi: 186, btch: 31 usd: 38
[ 238.881744] CPU 1: hi: 186, btch: 31 usd: 169
[ 238.881774] HighMem per-cpu:
[ 238.881774] CPU 0: hi: 90, btch: 15 usd: 66
[ 238.881774] CPU 1: hi: 90, btch: 15 usd: 86
[ 238.881805] active_anon:544 inactive_anon:71 isolated_anon:0
[ 238.881805] active_file:926 inactive_file:2538 isolated_file:0
[ 238.881805] unevictable:0 dirty:10 writeback:0 unstable:0
[ 238.881805] free:57782 slab_reclaimable:864 slab_unreclaimable:186898
[ 238.881805] mapped:632 shmem:144 pagetables:50 bounce:0
[ 238.881835] Normal free:1328kB min:3532kB low:4412kB high:5296kB active_anon:0kB inactive_anon:0kB active_file:880kB inactive_file:848kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:780288kB mlocked:0kB dirty:36kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:3456kB slab_unreclaimable:747592kB kernel_stack:392kB pagetables:200kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881866] lowmem_reserve[]: 0 1904 1904
[ 238.881896] HighMem free:229800kB min:236kB low:508kB high:784kB active_anon:2176kB inactive_anon:284kB active_file:2824kB inactive_file:9304kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:243712kB mlocked:0kB dirty:4kB writeback:0kB mapped:2528kB shmem:576kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881927] lowmem_reserve[]: 0 0 0
[ 238.881958] Normal: 0*4kB 4*8kB 6*16kB 0*32kB 1*64kB 1*128kB 0*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1344kB
[ 238.882019] HighMem: 6*4kB 2*8kB 4*16kB 4*32kB 1*64kB 1*128kB 0*256kB 2*512kB 3*1024kB 0*2048kB 55*4096kB = 229800kB
[ 238.882080] 3610 total pagecache pages
[ 238.882080] 0 pages in swap cache
[ 238.882080] Swap cache stats: add 0, delete 0, find 0/0
[ 238.882110] Free swap = 0kB
[ 238.882110] Total swap = 0kB
[ 238.933776] 262144 pages of RAM
[ 238.933776] 58240 free pages
[ 238.933776] 10503 reserved pages
[ 238.933776] 187773 slab pages
[ 238.933807] 2475 pages shared
[ 238.933807] 0 pages swap cached
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2011-04-29 06:37:09 +08:00
|
|
|
|
if (!(dev->txq.qlen >= TX_QLEN(dev)))
|
2012-03-14 12:00:24 +08:00
|
|
|
|
netif_tx_wake_all_queues(dev->net);
|
usbnet: runtime pm: fix out of memory
This patch makes use of the EVENT_DEV_OPEN flag introduced recently to
fix one out of memory issue, which can be reproduced on omap3/4 based
pandaboard/beagle XM easily with steps below:
- enable runtime pm
echo auto > /sys/devices/platform/usbhs-omap.0/ehci-omap.0/usb1/1-1/1-1.1/power/control
- ifconfig eth0 up
- then out of memroy happened, see [1] for kernel message.
Follows my analysis:
- 'ifconfig eth0 up' brings eth0 out of suspend, and usbnet_resume
is called to schedule dev->bh, then rx urbs are submited to prepare for
recieving data;
- some usbnet devices will produce garbage rx packets flood if
info->reset is not called in usbnet_open.
- so there is no enough chances for usbnet_bh to handle and release
recieved skb buffers since many rx interrupts consumes cpu, so out of memory
for atomic allocation in rx_submit happened.
This patch fixes the issue by simply not allowing schedule of usbnet_bh until device
is opened.
[1], dmesg
[ 234.712005] smsc95xx 1-1.1:1.0: rpm_resume flags 0x4
[ 234.712066] usb 1-1.1: rpm_resume flags 0x0
[ 234.712066] usb 1-1: rpm_resume flags 0x0
[ 234.712097] usb usb1: rpm_resume flags 0x0
[ 234.712127] usb usb1: usb auto-resume
[ 234.712158] ehci-omap ehci-omap.0: resume root hub
[ 234.754028] hub 1-0:1.0: hub_resume
[ 234.754821] hub 1-0:1.0: port 1: status 0507 change 0000
[ 234.756011] hub 1-0:1.0: state 7 ports 3 chg 0000 evt 0000
[ 234.756042] hub 1-0:1.0: rpm_resume flags 0x4
[ 234.756072] usb usb1: rpm_resume flags 0x0
[ 234.756164] usb usb1: rpm_resume returns 1
[ 234.756195] hub 1-0:1.0: rpm_resume returns 0
[ 234.756195] hub 1-0:1.0: rpm_suspend flags 0x4
[ 234.756225] hub 1-0:1.0: rpm_suspend returns 0
[ 234.756256] usb usb1: rpm_resume returns 0
[ 234.757141] usb 1-1: usb auto-resume
[ 234.793151] ehci-omap ehci-omap.0: GetStatus port:1 status 001005 0 ACK POWER sig=se0 PE CONNECT
[ 234.816558] usb 1-1: finish resume
[ 234.817871] hub 1-1:1.0: hub_resume
[ 234.818420] hub 1-1:1.0: port 1: status 0507 change 0000
[ 234.820495] ehci-omap ehci-omap.0: reused qh eec50220 schedule
[ 234.820495] usb 1-1: link qh256-0001/eec50220 start 1 [1/0 us]
[ 234.820587] usb 1-1: rpm_resume returns 0
[ 234.820800] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0000
[ 234.820800] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.820831] hub 1-1:1.0: rpm_resume returns 0
[ 234.820861] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.820861] hub 1-1:1.0: rpm_suspend returns 0
[ 234.821777] usb 1-1.1: usb auto-resume
[ 234.868591] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0002
[ 234.868591] hub 1-1:1.0: rpm_resume flags 0x4
[ 234.868621] hub 1-1:1.0: rpm_resume returns 0
[ 234.868652] hub 1-1:1.0: rpm_suspend flags 0x4
[ 234.868652] hub 1-1:1.0: rpm_suspend returns 0
[ 234.879486] usb 1-1.1: finish resume
[ 234.880279] usb 1-1.1: rpm_resume returns 0
[ 234.880310] smsc95xx 1-1.1:1.0: rpm_resume returns 0
[ 238.880187] ksoftirqd/0: page allocation failure. order:0, mode:0x20
[ 238.880218] Backtrace:
[ 238.880249] [<c01b9800>] (dump_backtrace+0x0/0xf8) from [<c065e1dc>] (dump_stack+0x18/0x1c)
[ 238.880249] r6:00000000 r5:00000000 r4:00000020 r3:00000002
[ 238.880310] [<c065e1c4>] (dump_stack+0x0/0x1c) from [<c026ece4>] (__alloc_pages_nodemask+0x620/0x724)
[ 238.880340] [<c026e6c4>] (__alloc_pages_nodemask+0x0/0x724) from [<c02986d4>] (kmem_getpages.clone.34+0x34/0xc8)
[ 238.880371] [<c02986a0>] (kmem_getpages.clone.34+0x0/0xc8) from [<c02988f8>] (cache_grow.clone.42+0x84/0x154)
[ 238.880371] r6:ef871aa4 r5:ef871a80 r4:ef81fd40 r3:00000020
[ 238.880401] [<c0298874>] (cache_grow.clone.42+0x0/0x154) from [<c0298b64>] (cache_alloc_refill+0x19c/0x1f0)
[ 238.880432] [<c02989c8>] (cache_alloc_refill+0x0/0x1f0) from [<c0299804>] (kmem_cache_alloc+0x90/0x190)
[ 238.880462] [<c0299774>] (kmem_cache_alloc+0x0/0x190) from [<c052e260>] (__alloc_skb+0x34/0xe8)
[ 238.880493] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.880523] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf050d38>] (rx_complete+0x19c/0x1b0 [usbnet])
[ 238.880737] [<bf050b9c>] (rx_complete+0x0/0x1b0 [usbnet]) from [<bf006fd0>] (usb_hcd_giveback_urb+0xa8/0xf4 [usbcore])
[ 238.880737] r8:eeeced34 r7:eeecec00 r6:eeecec00 r5:00000000 r4:eec2dd20
[ 238.880767] r3:bf050b9c
[ 238.880859] [<bf006f28>] (usb_hcd_giveback_urb+0x0/0xf4 [usbcore]) from [<bf03c8f8>] (ehci_urb_done+0xb0/0xbc [ehci_hcd])
[ 238.880859] r6:00000000 r5:eec2dd20 r4:eeeced44 r3:eec2dd34
[ 238.880920] [<bf03c848>] (ehci_urb_done+0x0/0xbc [ehci_hcd]) from [<bf040204>] (qh_completions+0x308/0x3bc [ehci_hcd])
[ 238.880920] r7:00000000 r6:eeda21a0 r5:ffdfe3c0 r4:eeda21ac
[ 238.880981] [<bf03fefc>] (qh_completions+0x0/0x3bc [ehci_hcd]) from [<bf040ef8>] (scan_async+0xb0/0x16c [ehci_hcd])
[ 238.881011] [<bf040e48>] (scan_async+0x0/0x16c [ehci_hcd]) from [<bf040fec>] (ehci_work+0x38/0x90 [ehci_hcd])
[ 238.881042] [<bf040fb4>] (ehci_work+0x0/0x90 [ehci_hcd]) from [<bf042940>] (ehci_irq+0x300/0x34c [ehci_hcd])
[ 238.881072] r4:eeeced34 r3:00000001
[ 238.881134] [<bf042640>] (ehci_irq+0x0/0x34c [ehci_hcd]) from [<bf006828>] (usb_hcd_irq+0x40/0xac [usbcore])
[ 238.881195] [<bf0067e8>] (usb_hcd_irq+0x0/0xac [usbcore]) from [<c0239764>] (handle_irq_event_percpu+0xb8/0x240)
[ 238.881225] r6:eec504e0 r5:0000006d r4:eec504e0 r3:bf0067e8
[ 238.881256] [<c02396ac>] (handle_irq_event_percpu+0x0/0x240) from [<c0239930>] (handle_irq_event+0x44/0x64)
[ 238.881256] [<c02398ec>] (handle_irq_event+0x0/0x64) from [<c023bbd0>] (handle_level_irq+0xe0/0x114)
[ 238.881286] r6:0000006d r5:c080c14c r4:c080c100 r3:00020000
[ 238.881317] [<c023baf0>] (handle_level_irq+0x0/0x114) from [<c01ab090>] (asm_do_IRQ+0x90/0xd0)
[ 238.881317] r5:00000000 r4:0000006d
[ 238.881347] [<c01ab000>] (asm_do_IRQ+0x0/0xd0) from [<c06624d0>] (__irq_svc+0x50/0x134)
[ 238.881378] Exception stack(0xef837e20 to 0xef837e68)
[ 238.881378] 7e20: 00000001 00185610 016cc000 c00490c0 eb380000 ef800540 00000020 00004ae0
[ 238.881408] 7e40: 00000020 bf0509f4 60000013 ef837e9c ef837e40 ef837e68 c0226f0c c0298ca0
[ 238.881408] 7e60: 20000013 ffffffff
[ 238.881408] r5:fa240100 r4:ffffffff
[ 238.881439] [<c0298bb8>] (__kmalloc_track_caller+0x0/0x1d0) from [<c052e284>] (__alloc_skb+0x58/0xe8)
[ 238.881469] [<c052e22c>] (__alloc_skb+0x0/0xe8) from [<bf0509f4>] (rx_submit+0x2c/0x1d4 [usbnet])
[ 238.881500] [<bf0509c8>] (rx_submit+0x0/0x1d4 [usbnet]) from [<bf0513d8>] (usbnet_bh+0x1b4/0x250 [usbnet])
[ 238.881530] [<bf051224>] (usbnet_bh+0x0/0x250 [usbnet]) from [<c01f912c>] (tasklet_action+0xb0/0x1f8)
[ 238.881530] r6:00000000 r5:ef9757f0 r4:ef9757ec r3:bf051224
[ 238.881561] [<c01f907c>] (tasklet_action+0x0/0x1f8) from [<c01f97ac>] (__do_softirq+0x140/0x290)
[ 238.881561] r8:00000006 r7:00000101 r6:00000000 r5:c0806098 r4:00000001
[ 238.881591] r3:c01f907c
[ 238.881622] [<c01f966c>] (__do_softirq+0x0/0x290) from [<c01f99cc>] (run_ksoftirqd+0xd0/0x1f4)
[ 238.881622] [<c01f98fc>] (run_ksoftirqd+0x0/0x1f4) from [<c02113b0>] (kthread+0x90/0x98)
[ 238.881652] r7:00000013 r6:c01f98fc r5:00000000 r4:ef831efc
[ 238.881683] [<c0211320>] (kthread+0x0/0x98) from [<c01f62f4>] (do_exit+0x0/0x374)
[ 238.881713] r6:c01f62f4 r5:c0211320 r4:ef831efc
[ 238.881713] Mem-info:
[ 238.881744] Normal per-cpu:
[ 238.881744] CPU 0: hi: 186, btch: 31 usd: 38
[ 238.881744] CPU 1: hi: 186, btch: 31 usd: 169
[ 238.881774] HighMem per-cpu:
[ 238.881774] CPU 0: hi: 90, btch: 15 usd: 66
[ 238.881774] CPU 1: hi: 90, btch: 15 usd: 86
[ 238.881805] active_anon:544 inactive_anon:71 isolated_anon:0
[ 238.881805] active_file:926 inactive_file:2538 isolated_file:0
[ 238.881805] unevictable:0 dirty:10 writeback:0 unstable:0
[ 238.881805] free:57782 slab_reclaimable:864 slab_unreclaimable:186898
[ 238.881805] mapped:632 shmem:144 pagetables:50 bounce:0
[ 238.881835] Normal free:1328kB min:3532kB low:4412kB high:5296kB active_anon:0kB inactive_anon:0kB active_file:880kB inactive_file:848kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:780288kB mlocked:0kB dirty:36kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:3456kB slab_unreclaimable:747592kB kernel_stack:392kB pagetables:200kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881866] lowmem_reserve[]: 0 1904 1904
[ 238.881896] HighMem free:229800kB min:236kB low:508kB high:784kB active_anon:2176kB inactive_anon:284kB active_file:2824kB inactive_file:9304kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:243712kB mlocked:0kB dirty:4kB writeback:0kB mapped:2528kB shmem:576kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
[ 238.881927] lowmem_reserve[]: 0 0 0
[ 238.881958] Normal: 0*4kB 4*8kB 6*16kB 0*32kB 1*64kB 1*128kB 0*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1344kB
[ 238.882019] HighMem: 6*4kB 2*8kB 4*16kB 4*32kB 1*64kB 1*128kB 0*256kB 2*512kB 3*1024kB 0*2048kB 55*4096kB = 229800kB
[ 238.882080] 3610 total pagecache pages
[ 238.882080] 0 pages in swap cache
[ 238.882080] Swap cache stats: add 0, delete 0, find 0/0
[ 238.882110] Free swap = 0kB
[ 238.882110] Total swap = 0kB
[ 238.933776] 262144 pages of RAM
[ 238.933776] 58240 free pages
[ 238.933776] 10503 reserved pages
[ 238.933776] 187773 slab pages
[ 238.933807] 2475 pages shared
[ 238.933807] 0 pages swap cached
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2011-04-29 06:37:09 +08:00
|
|
|
|
tasklet_schedule (&dev->bh);
|
|
|
|
|
}
|
2009-12-04 07:31:18 +08:00
|
|
|
|
}
|
2012-10-11 10:50:10 +08:00
|
|
|
|
|
|
|
|
|
if (test_and_clear_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags))
|
|
|
|
|
usb_autopm_get_interface_no_resume(intf);
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2005-09-01 00:52:45 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_resume);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2012-10-11 10:50:10 +08:00
|
|
|
|
/*
|
|
|
|
|
* Either a subdriver implements manage_power, then it is assumed to always
|
|
|
|
|
* be ready to be suspended or it reports the readiness to be suspended
|
|
|
|
|
* explicitly
|
|
|
|
|
*/
|
|
|
|
|
void usbnet_device_suggests_idle(struct usbnet *dev)
|
|
|
|
|
{
|
|
|
|
|
if (!test_and_set_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) {
|
|
|
|
|
dev->intf->needs_remote_wakeup = 1;
|
|
|
|
|
usb_autopm_put_interface_async(dev->intf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL(usbnet_device_suggests_idle);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2012-12-18 12:45:52 +08:00
|
|
|
|
/*
|
|
|
|
|
* For devices that can do without special commands
|
|
|
|
|
*/
|
|
|
|
|
int usbnet_manage_power(struct usbnet *dev, int on)
|
|
|
|
|
{
|
|
|
|
|
dev->intf->needs_remote_wakeup = on;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL(usbnet_manage_power);
|
|
|
|
|
|
2013-04-11 12:40:30 +08:00
|
|
|
|
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);
|
usbnet: handle link change
The link change is detected via the interrupt pipe, and bulk
pipes are responsible for transfering packets, so it is reasonable
to stop bulk transfer after link is reported as off.
Two adavantages may be obtained with stopping bulk transfer
after link becomes off:
- USB bus bandwidth is saved(USB bus is shared bus except for
USB3.0), for example, lots of 'IN' token packets and 'NYET'
handshake packets is transfered on 2.0 bus.
- probabaly power might be saved for usb host controller since
cancelling bulk transfer may disable the asynchronous schedule of
host controller.
With this patch, when link becomes off, about ~10% performance
boost can be found on bulk transfer of anther usb device which
is attached to same bus with the usbnet device, see below
test on next-20130410:
- read from usb mass storage(Sandisk Extreme USB 3.0) on pandaboard
with below command after unplugging ethernet cable:
dd if=/dev/sda iflag=direct of=/dev/null bs=1M count=800
- without the patch
1, 838860800 bytes (839 MB) copied, 36.2216 s, 23.2 MB/s
2, 838860800 bytes (839 MB) copied, 35.8368 s, 23.4 MB/s
3, 838860800 bytes (839 MB) copied, 35.823 s, 23.4 MB/s
4, 838860800 bytes (839 MB) copied, 35.937 s, 23.3 MB/s
5, 838860800 bytes (839 MB) copied, 35.7365 s, 23.5 MB/s
average: 23.6MB/s
- with the patch
1, 838860800 bytes (839 MB) copied, 32.3817 s, 25.9 MB/s
2, 838860800 bytes (839 MB) copied, 31.7389 s, 26.4 MB/s
3, 838860800 bytes (839 MB) copied, 32.438 s, 25.9 MB/s
4, 838860800 bytes (839 MB) copied, 32.5492 s, 25.8 MB/s
5, 838860800 bytes (839 MB) copied, 31.6178 s, 26.5 MB/s
average: 26.1MB/s
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-04-11 12:40:40 +08:00
|
|
|
|
else
|
|
|
|
|
usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
|
2013-04-11 12:40:30 +08:00
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL(usbnet_link_change);
|
|
|
|
|
|
2012-10-25 03:46:54 +08:00
|
|
|
|
/*-------------------------------------------------------------------------*/
|
2012-11-06 12:53:04 +08:00
|
|
|
|
static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, void *data, u16 size)
|
2012-10-25 03:46:54 +08:00
|
|
|
|
{
|
|
|
|
|
void *buf = NULL;
|
|
|
|
|
int err = -ENOMEM;
|
|
|
|
|
|
|
|
|
|
netdev_dbg(dev->net, "usbnet_read_cmd cmd=0x%02x reqtype=%02x"
|
|
|
|
|
" value=0x%04x index=0x%04x size=%d\n",
|
|
|
|
|
cmd, reqtype, value, index, size);
|
|
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
|
buf = kmalloc(size, GFP_KERNEL);
|
|
|
|
|
if (!buf)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
|
|
|
|
|
cmd, reqtype, value, index, buf, size,
|
|
|
|
|
USB_CTRL_GET_TIMEOUT);
|
|
|
|
|
if (err > 0 && err <= size)
|
|
|
|
|
memcpy(data, buf, err);
|
|
|
|
|
kfree(buf);
|
|
|
|
|
out:
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-06 12:53:04 +08:00
|
|
|
|
static int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, const void *data,
|
|
|
|
|
u16 size)
|
2012-10-25 03:46:54 +08:00
|
|
|
|
{
|
|
|
|
|
void *buf = NULL;
|
|
|
|
|
int err = -ENOMEM;
|
|
|
|
|
|
|
|
|
|
netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x"
|
|
|
|
|
" value=0x%04x index=0x%04x size=%d\n",
|
|
|
|
|
cmd, reqtype, value, index, size);
|
|
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
|
buf = kmemdup(data, size, GFP_KERNEL);
|
|
|
|
|
if (!buf)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
|
|
|
|
|
cmd, reqtype, value, index, buf, size,
|
|
|
|
|
USB_CTRL_SET_TIMEOUT);
|
|
|
|
|
kfree(buf);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2012-11-06 12:53:04 +08:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The function can't be called inside suspend/resume callback,
|
|
|
|
|
* otherwise deadlock will be caused.
|
|
|
|
|
*/
|
|
|
|
|
int usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, void *data, u16 size)
|
|
|
|
|
{
|
2012-11-06 12:53:08 +08:00
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (usb_autopm_get_interface(dev->intf) < 0)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
ret = __usbnet_read_cmd(dev, cmd, reqtype, value, index,
|
|
|
|
|
data, size);
|
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
return ret;
|
2012-11-06 12:53:04 +08:00
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_read_cmd);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The function can't be called inside suspend/resume callback,
|
|
|
|
|
* otherwise deadlock will be caused.
|
|
|
|
|
*/
|
|
|
|
|
int usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, const void *data, u16 size)
|
|
|
|
|
{
|
2012-11-06 12:53:08 +08:00
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (usb_autopm_get_interface(dev->intf) < 0)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
ret = __usbnet_write_cmd(dev, cmd, reqtype, value, index,
|
|
|
|
|
data, size);
|
|
|
|
|
usb_autopm_put_interface(dev->intf);
|
|
|
|
|
return ret;
|
2012-11-06 12:53:04 +08:00
|
|
|
|
}
|
2012-10-25 03:46:54 +08:00
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_write_cmd);
|
|
|
|
|
|
2012-11-06 12:53:04 +08:00
|
|
|
|
/*
|
|
|
|
|
* The function can be called inside suspend/resume callback safely
|
|
|
|
|
* and should only be called by suspend/resume callback generally.
|
|
|
|
|
*/
|
|
|
|
|
int usbnet_read_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, void *data, u16 size)
|
|
|
|
|
{
|
|
|
|
|
return __usbnet_read_cmd(dev, cmd, reqtype, value, index,
|
|
|
|
|
data, size);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_read_cmd_nopm);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The function can be called inside suspend/resume callback safely
|
|
|
|
|
* and should only be called by suspend/resume callback generally.
|
|
|
|
|
*/
|
|
|
|
|
int usbnet_write_cmd_nopm(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, const void *data,
|
|
|
|
|
u16 size)
|
|
|
|
|
{
|
|
|
|
|
return __usbnet_write_cmd(dev, cmd, reqtype, value, index,
|
|
|
|
|
data, size);
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_write_cmd_nopm);
|
|
|
|
|
|
2012-10-25 03:46:54 +08:00
|
|
|
|
static void usbnet_async_cmd_cb(struct urb *urb)
|
|
|
|
|
{
|
|
|
|
|
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
|
|
|
|
|
int status = urb->status;
|
|
|
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
|
dev_dbg(&urb->dev->dev, "%s failed with %d",
|
|
|
|
|
__func__, status);
|
|
|
|
|
|
|
|
|
|
kfree(req);
|
|
|
|
|
usb_free_urb(urb);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-06 12:53:04 +08:00
|
|
|
|
/*
|
|
|
|
|
* The caller must make sure that device can't be put into suspend
|
|
|
|
|
* state until the control URB completes.
|
|
|
|
|
*/
|
2012-10-25 03:46:54 +08:00
|
|
|
|
int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
|
|
|
|
|
u16 value, u16 index, const void *data, u16 size)
|
|
|
|
|
{
|
|
|
|
|
struct usb_ctrlrequest *req = NULL;
|
|
|
|
|
struct urb *urb;
|
|
|
|
|
int err = -ENOMEM;
|
|
|
|
|
void *buf = NULL;
|
|
|
|
|
|
|
|
|
|
netdev_dbg(dev->net, "usbnet_write_cmd cmd=0x%02x reqtype=%02x"
|
|
|
|
|
" value=0x%04x index=0x%04x size=%d\n",
|
|
|
|
|
cmd, reqtype, value, index, size);
|
|
|
|
|
|
|
|
|
|
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
|
|
|
|
if (!urb) {
|
|
|
|
|
netdev_err(dev->net, "Error allocating URB in"
|
|
|
|
|
" %s!\n", __func__);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
|
buf = kmemdup(data, size, GFP_ATOMIC);
|
|
|
|
|
if (!buf) {
|
|
|
|
|
netdev_err(dev->net, "Error allocating buffer"
|
|
|
|
|
" in %s!\n", __func__);
|
|
|
|
|
goto fail_free;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
|
2013-02-04 01:28:11 +08:00
|
|
|
|
if (!req)
|
2012-10-25 03:46:54 +08:00
|
|
|
|
goto fail_free_buf;
|
|
|
|
|
|
|
|
|
|
req->bRequestType = reqtype;
|
|
|
|
|
req->bRequest = cmd;
|
|
|
|
|
req->wValue = cpu_to_le16(value);
|
|
|
|
|
req->wIndex = cpu_to_le16(index);
|
|
|
|
|
req->wLength = cpu_to_le16(size);
|
|
|
|
|
|
|
|
|
|
usb_fill_control_urb(urb, dev->udev,
|
|
|
|
|
usb_sndctrlpipe(dev->udev, 0),
|
|
|
|
|
(void *)req, buf, size,
|
|
|
|
|
usbnet_async_cmd_cb, req);
|
|
|
|
|
urb->transfer_flags |= URB_FREE_BUFFER;
|
|
|
|
|
|
|
|
|
|
err = usb_submit_urb(urb, GFP_ATOMIC);
|
|
|
|
|
if (err < 0) {
|
|
|
|
|
netdev_err(dev->net, "Error submitting the control"
|
|
|
|
|
" message: status=%d\n", err);
|
|
|
|
|
goto fail_free;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
fail_free_buf:
|
|
|
|
|
kfree(buf);
|
|
|
|
|
fail_free:
|
|
|
|
|
kfree(req);
|
|
|
|
|
usb_free_urb(urb);
|
|
|
|
|
fail:
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
EXPORT_SYMBOL_GPL(usbnet_write_cmd_async);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
static int __init usbnet_init(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
2011-04-18 08:49:21 +08:00
|
|
|
|
/* Compiler should optimize this out. */
|
|
|
|
|
BUILD_BUG_ON(
|
|
|
|
|
FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
2012-07-13 03:33:07 +08:00
|
|
|
|
eth_random_addr(node_id);
|
2007-02-16 10:52:30 +08:00
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
}
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
module_init(usbnet_init);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
static void __exit usbnet_exit(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
{
|
|
|
|
|
}
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
module_exit(usbnet_exit);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
MODULE_AUTHOR("David Brownell");
|
2005-09-01 00:54:50 +08:00
|
|
|
|
MODULE_DESCRIPTION("USB network driver framework");
|
[PATCH] USB: usbnet (1/9) clean up framing
This starts to prepare the core of "usbnet" to know less about various
framing protocols that map Ethernet packets onto USB, so "minidrivers"
can be modules that just plug into the core.
- Remove some framing-specific code that cluttered the core:
* net->hard_header_len records how much space to preallocate;
now drivers that add their own framing (Net1080, GeneLink,
Zaurus, and RNDIS) will have smoother TX paths. Even for
the drivers (Zaurus, Net1080) that need trailers.
* defines new dev->hard_mtu, using this "hardware" limit to
check changes to the link's settable "software" mtu.
* now net->hard_header_len and dev->hard_mtu are set up in the
driver bind() routines, if needed.
- Transaction ID is no longer specific to the Net1080 framing;
RNDIS needs one too.
- Creates a new "usbnet.h" header with declarations that are shared
between the core and what will be separate modules.
- Plus a couple other minor tweaks, like recognizing -ESHUTDOWN
means the keventd work should just shut itself down asap.
The core code is only about 1/3 of this large file. Splitting out the
minidrivers into separate modules (e.g. ones for ASIX adapters,
Zaurii and similar, CDC Ethernet, etc), in later patches, will
improve maintainability and shrink typical runtime footprints.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-09-01 00:52:31 +08:00
|
|
|
|
MODULE_LICENSE("GPL");
|