* Re: net-next: 2.6.34-rc1 regression: panic when running diagnostic on interface with IPv6
From: David Miller @ 2010-04-05 23:53 UTC (permalink / raw)
To: emil.s.tantilov; +Cc: shemminger, netdev
In-Reply-To: <EA929A9653AAE14F841771FB1DE5A1365FE4E2E334@rrsmsx501.amr.corp.intel.com>
From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
Date: Mon, 5 Apr 2010 17:50:38 -0600
> David Miller wrote:
>> From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
>> Date: Mon, 5 Apr 2010 17:03:56 -0600
>>
>>> David Miller wrote:
>>>> From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
>>>> Date: Tue, 23 Mar 2010 12:28:08 -0600
>>>>
>>>>> Bisecting points to this patch:
>>>>> http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=84e8b803f1e16f3a2b8b80f80a63fa2f2f8a9be6
>>>>>
>>>>> And I confirmed that the issue goes away after reverting it.
>>>>>
>>>>> Steps to reproduce:
>>>>> 1. Load the driver and configure IPv6 address.
>>>>> 2. Run ethtool diag:
>>>>> ethtool -t eth0
>>>>>
>>>>> 3. If this doesn't brake it try again, or just do ifdown/up. Other
>>>>> operations on the interface will eventually panic the system:
>>>>
>>>> Stephen please fix this, thanks.
>>>
>>> Just FYI - I still see this issue with latest pull from net-2.6.
>>
>> It's net-next-2.6 that introduced the problem and has the follow-on
>> fixes, not net-2.6
>
> Same in net-next:
Ok, Stephen please look into this, we've had this regression
for almost two weeks now.
^ permalink raw reply
* Re: [PATCH] [V3] Add non-Virtex5 support for LL TEMAC driver
From: Grant Likely @ 2010-04-06 0:08 UTC (permalink / raw)
To: John Linn
Cc: netdev, linuxppc-dev, jwboyer, john.williams, michal.simek,
John Tyner, David Miller
In-Reply-To: <d9134316-bd07-46a8-91d4-c30f27baeb60@SG2EHSMHS007.ehs.local>
On Mon, Apr 5, 2010 at 3:11 PM, John Linn <john.linn@xilinx.com> wrote:
> This patch adds support for using the LL TEMAC Ethernet driver on
> non-Virtex 5 platforms by adding support for accessing the Soft DMA
> registers as if they were memory mapped instead of solely through the
> DCR's (available on the Virtex 5).
>
> The patch also updates the driver so that it runs on the MicroBlaze.
> The changes were tested on the PowerPC 440, PowerPC 405, and the
> MicroBlaze platforms.
>
> Signed-off-by: John Tyner <jtyner@cs.ucr.edu>
> Signed-off-by: John Linn <john.linn@xilinx.com>
>
> ---
>
> V2 - Incorporated comments from Grant and added more logic to allow the driver
> to work on MicroBlaze.
>
> V3 - Only updated it to apply to head, minor change to include slab.h. Also
> verified that it now builds for MicroBlaze. Retested on PowerPC and MicroBlaze.
> ---
> drivers/net/Kconfig | 1 -
> drivers/net/ll_temac.h | 17 +++++-
> drivers/net/ll_temac_main.c | 124 ++++++++++++++++++++++++++++++++++---------
> 3 files changed, 113 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 0ba5b8e..17044dc 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2435,7 +2435,6 @@ config MV643XX_ETH
> config XILINX_LL_TEMAC
> tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
> select PHYLIB
> - depends on PPC_DCR_NATIVE
> help
> This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
> core used in Xilinx Spartan and Virtex FPGAs
This still at the very least needs to depend on CONFIG_OF. Otherwise
allmodconfig and allyesconfig on x86 and others will break. The
driver also doesn't build on sparc, so you'll need to either exclude
CONFIG_SPARC or depend on (PPC || MICROBLAZE) too.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [RFC PATCH 1/2] netdev: buffer infrastructure to log network driver's information
From: Neil Horman @ 2010-04-06 0:10 UTC (permalink / raw)
To: David Miller
Cc: eric.dumazet, sanagi.koki, netdev, izumi.taku, kaneshige.kenji,
jeffrey.t.kirsher, jesse.brandeburg, bruce.w.allan,
alexander.h.duyck, peter.p.waskiewicz.jr, john.ronciak
In-Reply-To: <20100405.123155.263974951.davem@davemloft.net>
On Mon, Apr 05, 2010 at 12:31:55PM -0700, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Mon, 05 Apr 2010 10:42:26 +0200
>
> > Le lundi 05 avril 2010 à 15:52 +0900, Koki Sanagi a écrit :
> >> This patch implements buffer infrastructure under driver/net.
> >> This buffer records information from network driver.
> >>
> >> Signed-off-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
> >> ---
> >> drivers/net/Kconfig | 8 +
> >> drivers/net/Makefile | 1 +
> >> drivers/net/ndrvbuf.c | 535 +++++++++++++++++++++++++++++++++++++++++++++++
> >> include/linux/ndrvbuf.h | 57 +++++
> >> 4 files changed, 601 insertions(+), 0 deletions(-)
> >>
> >
> > Wow, 600 lines... thats what I call bloat...
>
> And we have all sorts of facilities for creating filesystem
> streams and ring buffers of debug information.
>
> You could even hook into 'perf' to log and process these
> events in probably like 12 lines of code.
>
I'm still having a hard time understanding why this approach is preferable to
the previous approach you took using tracepoints. Granted you can't get driver
internal state as easily, but its generic and doesn't do...this.
Neil
^ permalink raw reply
* [PATCH 1/2] TIPC: Updated topology subscription protocol according to latest spec
From: Jon Maloy @ 2010-04-06 1:16 UTC (permalink / raw)
To: David Miller; +Cc: Maloy, netdev, tipc-discussion, Jon
In-Reply-To: <../outgoing_patches/>
---
include/linux/tipc.h | 30 ++++++++++++------------------
net/tipc/core.c | 2 +-
net/tipc/subscr.c | 15 ++++++++++-----
3 files changed, 23 insertions(+), 24 deletions(-)
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
index 3d92396..9536d8a 100644
--- a/include/linux/tipc.h
+++ b/include/linux/tipc.h
@@ -127,23 +127,17 @@ static inline unsigned int tipc_node(__u32 addr)
* TIPC topology subscription service definitions
*/
-#define TIPC_SUB_PORTS 0x01 /* filter for port availability */
-#define TIPC_SUB_SERVICE 0x02 /* filter for service availability */
-#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
-#if 0
-/* The following filter options are not currently implemented */
-#define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */
-#define TIPC_SUB_NO_UNBIND_EVTS 0x08 /* filter out "withdraw" events */
-#define TIPC_SUB_SINGLE_EVT 0x10 /* expire after first event */
-#endif
+#define TIPC_SUB_SERVICE 0x00 /* Filter for service availability */
+#define TIPC_SUB_PORTS 0x01 /* Filter for port availability */
+#define TIPC_SUB_CANCEL 0x04 /* Cancel a subscription */
#define TIPC_WAIT_FOREVER ~0 /* timeout for permanent subscription */
struct tipc_subscr {
- struct tipc_name_seq seq; /* name sequence of interest */
- __u32 timeout; /* subscription duration (in ms) */
- __u32 filter; /* bitmask of filter options */
- char usr_handle[8]; /* available for subscriber use */
+ struct tipc_name_seq seq; /* NBO. Name sequence of interest */
+ __u32 timeout; /* NBO. Subscription duration (in ms) */
+ __u32 filter; /* NBO. Bitmask of filter options */
+ char usr_handle[8]; /* Opaque. Available for subscriber use */
};
#define TIPC_PUBLISHED 1 /* publication event */
@@ -151,11 +145,11 @@ struct tipc_subscr {
#define TIPC_SUBSCR_TIMEOUT 3 /* subscription timeout event */
struct tipc_event {
- __u32 event; /* event type */
- __u32 found_lower; /* matching name seq instances */
- __u32 found_upper; /* " " " " */
- struct tipc_portid port; /* associated port */
- struct tipc_subscr s; /* associated subscription */
+ __u32 event; /* NBO. Event type, as defined above */
+ __u32 found_lower; /* NBO. Matching name seq instances */
+ __u32 found_upper; /* " " " " " */
+ struct tipc_portid port; /* NBO. Associated port */
+ struct tipc_subscr s; /* Original, associated subscription */
};
/*
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 52c571f..4e84c84 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -49,7 +49,7 @@
#include "config.h"
-#define TIPC_MOD_VER "1.6.4"
+#define TIPC_MOD_VER "2.0.0"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index ff123e5..ab6eab4 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -274,7 +274,7 @@ static void subscr_cancel(struct tipc_subscr *s,
{
struct subscription *sub;
struct subscription *sub_temp;
- __u32 type, lower, upper;
+ __u32 type, lower, upper, timeout, filter;
int found = 0;
/* Find first matching subscription, exit if not found */
@@ -282,12 +282,18 @@ static void subscr_cancel(struct tipc_subscr *s,
type = ntohl(s->seq.type);
lower = ntohl(s->seq.lower);
upper = ntohl(s->seq.upper);
+ timeout = ntohl(s->timeout);
+ filter = ntohl(s->filter) & ~TIPC_SUB_CANCEL;
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) {
if ((type == sub->seq.type) &&
(lower == sub->seq.lower) &&
- (upper == sub->seq.upper)) {
+ (upper == sub->seq.upper) &&
+ (timeout == sub->timeout) &&
+ (filter == sub->filter) &&
+ !memcmp(s->usr_handle,sub->evt.s.usr_handle,
+ sizeof(s->usr_handle)) ){
found = 1;
break;
}
@@ -304,7 +310,7 @@ static void subscr_cancel(struct tipc_subscr *s,
k_term_timer(&sub->timer);
spin_lock_bh(subscriber->lock);
}
- dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
+ dbg("Cancel: removing sub %u,%u,%u from subscriber %p list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
subscr_del(sub);
}
@@ -352,8 +358,7 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s,
sub->seq.upper = ntohl(s->seq.upper);
sub->timeout = ntohl(s->timeout);
sub->filter = ntohl(s->filter);
- if ((!(sub->filter & TIPC_SUB_PORTS) ==
- !(sub->filter & TIPC_SUB_SERVICE)) ||
+ if ((sub->filter && (sub->filter != TIPC_SUB_PORTS)) ||
(sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
--
1.5.4.3
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
^ permalink raw reply related
* [PATCH 2/2] TIPC: Minor change to comment field in API
From: Jon Maloy @ 2010-04-06 1:16 UTC (permalink / raw)
To: David Miller; +Cc: Maloy, netdev, tipc-discussion, Jon
In-Reply-To: <../outgoing_patches/>
---
include/linux/tipc.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
index 9536d8a..ab2e551 100644
--- a/include/linux/tipc.h
+++ b/include/linux/tipc.h
@@ -86,7 +86,7 @@ static inline unsigned int tipc_node(__u32 addr)
*/
#define TIPC_CFG_SRV 0 /* configuration service name type */
-#define TIPC_TOP_SRV 1 /* topology service name type */
+#define TIPC_TOP_SRV 1 /* topology service name type and instance*/
#define TIPC_RESERVED_TYPES 64 /* lowest user-publishable name type */
/*
--
1.5.4.3
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
^ permalink raw reply related
* [PATCH] cnic: Fix crash during bnx2x MTU change.
From: Michael Chan @ 2010-04-06 1:44 UTC (permalink / raw)
To: davem; +Cc: netdev
cnic_service_bnx2x() irq handler can be called during chip reset from
MTU change. Need to check that the cnic's device state is up before
handling the irq.
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
drivers/net/cnic.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 9781942..4b451a7 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -2334,13 +2334,13 @@ static int cnic_service_bnx2x(void *data, void *status_blk)
struct cnic_local *cp = dev->cnic_priv;
u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
- prefetch(cp->status_blk.bnx2x);
- prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+ if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
+ prefetch(cp->status_blk.bnx2x);
+ prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
- if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
tasklet_schedule(&cp->cnic_irq_task);
-
- cnic_chk_pkt_rings(cp);
+ cnic_chk_pkt_rings(cp);
+ }
return 0;
}
--
1.6.4.GIT
^ permalink raw reply related
* re-submit3 [ANNOUNCEMENT] NET: usb: sierra_net.c driver
From: Elina Pasheva @ 2010-04-06 1:39 UTC (permalink / raw)
To: dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f
Cc: epasheva-ywE8TTl5eJHWpu6QEFMNjNBPR1lH4CV8,
rfiler-ywE8TTl5eJHWpu6QEFMNjNBPR1lH4CV8,
linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
Subject: re-submit3 [ANNOUNCEMENT] NET: usb: sierra_net.c driver
From: Elina Pasheva <epasheva-ywE8TTl5eJHWpu6QEFMNjNBPR1lH4CV8@public.gmane.org>
The following is a new Linux driver which exposes certain models of Sierra
Wireless modems to the operating system as Network Interface Cards (NICs).
This driver requires a version of the sierra.c driver which supports
blacklisting to work properly. The blacklist in sierra.c rejects the interfaces
claimed by sierra_net.c. Likewise, the sierra_net.c driver only accepts
(i.e. whitelists) the interface(s) used for USB-to-WWAN traffic.
The version of sierra.c which supports blacklisting is
available from the sierra wireless knowledge base page for older kernels. It is
also available in Linux kernel starting from version 2.6.31.
This driver works with all Sierra Wireless devices configured with PID=68A3
like USB305, USB306 provided the corresponding firmware version is I2.0
(for USB305) or M3.0 (for USB306) and later.
This driver will not work with earlier firmware versions than the ones shown
above. In this case the driver will issue an error message indicating
incompatibility and will not serve the device's USB-to-WWAN interface.
Sierra_net.c sits atop a pre-existing Linux driver called usbnet.c.
A series of hook functions are provided in sierra_net.c which are called by
usbnet.c in response to a particular condition such as receipt or transmission
of a data packet. As such, usbnet.c does most of the work of making
a modem appear to the system as a network device and for properly exchanging
traffic between the USB subsystem and the Network card interface.
Sierra_net.c is concerned with managing the data exchanged between the
USB-to-WWAN interface and the upper layers of the operating system.
The version number of sierra_net.c driver is set to 2.0.
This patch has been tested on kernel-2.6.34-rc3.
This patch has been checked against net-2.6 tree.
Signed-off-by: Elina Pasheva <epasheva-ywE8TTl5eJHWpu6QEFMNjNBPR1lH4CV8@public.gmane.org>
Signed-off-by: Rory Filer <rfiler-ywE8TTl5eJHWpu6QEFMNjNBPR1lH4CV8@public.gmane.org>
---
drivers/net/usb/Kconfig | 10
drivers/net/usb/Makefile | 2
drivers/net/usb/sierra_net.c | 970 +++++++++++++++++++++++++++++++++
3 files changed, 982 insertions(+)
--- a/drivers/net/usb/Kconfig 2010-04-01 10:10:56.000000000 -0700
+++ b/drivers/net/usb/Kconfig 2010-04-01 13:09:20.000000000 -0700
@@ -385,4 +385,14 @@ config USB_CDC_PHONET
cellular modem, as found on most Nokia handsets with the
"PC suite" USB profile.
+config USB_SIERRA_NET
+ tristate "USB-to-WWAN Driver for Sierra Wireless modems"
+ depends on USB_USBNET
+ default y
+ help
+ Choose this option if you have a Sierra Wireless USB-to-WWAN device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sierra_net.
+
endmenu
--- a/drivers/net/usb/Makefile 2010-04-01 10:10:45.000000000 -0700
+++ b/drivers/net/usb/Makefile 2010-04-01 10:12:16.000000000 -0700
@@ -23,4 +23,6 @@ obj-$(CONFIG_USB_NET_MCS7830) += mcs7830
obj-$(CONFIG_USB_USBNET) += usbnet.o
obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o
obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o
+obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o
+
--- a/drivers/net/usb/sierra_net.c 2010-04-01 16:43:34.000000000 -0700
+++ b/drivers/net/usb/sierra_net.c 2010-04-01 17:12:59.000000000 -0700
@@ -1 +1,971 @@
+/*
+ * USB-to-WWAN Driver for Sierra Wireless modems
+ *
+ * Copyright (C) 2008, 2009, 2010 Paxton Smith, Matthew Safar, Rory Filer
+ * <linux-ywE8TTl5eJHWpu6QEFMNjNBPR1lH4CV8@public.gmane.org>
+ *
+ * Portions of this based on the cdc_ether driver by David Brownell (2003-2005)
+ * and Ole Andre Vadla Ravnas (ActiveSync) (2006).
+ *
+ * IMPORTANT DISCLAIMER: This driver is not commercially supported by
+ * Sierra Wireless. Use at your own risk.
+ *
+ * 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
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define DRIVER_VERSION "v.2.0"
+#define DRIVER_AUTHOR "Paxton Smith, Matthew Safar, Rory Filer"
+#define DRIVER_DESC "USB-to-WWAN Driver for Sierra Wireless modems"
+static const char driver_name[] = "sierra_net";
+
+/* if defined debug messages enabled */
+/*#define DEBUG*/
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <net/ip.h>
+#include <net/udp.h>
+#include <asm/unaligned.h>
+#include <linux/usb/usbnet.h>
+
+#define SWI_USB_REQUEST_GET_FW_ATTR 0x06
+#define SWI_GET_FW_ATTR_MASK 0x08
+
+/* atomic counter partially included in MAC address to make sure 2 devices
+ * do not end up with the same MAC - concept breaks in case of > 255 ifaces
+ */
+static atomic_t iface_counter = ATOMIC_INIT(0);
+
+/*
+ * SYNC Timer Delay definition used to set the expiry time
+ */
+#define SIERRA_NET_SYNCDELAY (2*HZ)
+
+/* Max. MTU supported. The modem buffers are limited to 1500 */
+#define SIERRA_NET_MAX_SUPPORTED_MTU 1500
+
+/* The SIERRA_NET_USBCTL_BUF_LEN defines a buffer size allocated for control
+ * message reception ... and thus the max. received packet.
+ * (May be the cause for parse_hip returning -3)
+ */
+#define SIERRA_NET_USBCTL_BUF_LEN 1024
+
+/* list of interface numbers - used for constructing interface lists */
+struct sierra_net_iface_info {
+ const u32 infolen; /* number of interface numbers on list */
+ const u8 *ifaceinfo; /* pointer to the array holding the numbers */
+};
+
+struct sierra_net_info_data {
+ u16 rx_urb_size;
+ struct sierra_net_iface_info whitelist;
+};
+
+/* Private data structure */
+struct sierra_net_data {
+
+ u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */
+
+ u16 link_up; /* air link up or down */
+ u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */
+
+ u8 sync_msg[4]; /* SYNC message */
+ u8 shdwn_msg[4]; /* Shutdown message */
+
+ /* Backpointer to the container */
+ struct usbnet *usbnet;
+
+ u8 ifnum; /* interface number */
+
+/* Bit masks, must be a power of 2 */
+#define SIERRA_NET_EVENT_RESP_AVAIL 0x01
+#define SIERRA_NET_TIMER_EXPIRY 0x02
+ unsigned long kevent_flags;
+ struct work_struct sierra_net_kevent;
+ struct timer_list sync_timer; /* For retrying SYNC sequence */
+};
+
+struct param {
+ int is_present;
+ union {
+ void *ptr;
+ u32 dword;
+ u16 word;
+ u8 byte;
+ };
+};
+
+/* HIP message type */
+#define SIERRA_NET_HIP_EXTENDEDID 0x7F
+#define SIERRA_NET_HIP_HSYNC_ID 0x60 /* Modem -> host */
+#define SIERRA_NET_HIP_RESTART_ID 0x62 /* Modem -> host */
+#define SIERRA_NET_HIP_MSYNC_ID 0x20 /* Host -> modem */
+#define SIERRA_NET_HIP_SHUTD_ID 0x26 /* Host -> modem */
+
+#define SIERRA_NET_HIP_EXT_IP_IN_ID 0x0202
+#define SIERRA_NET_HIP_EXT_IP_OUT_ID 0x0002
+
+/* 3G UMTS Link Sense Indication definitions */
+#define SIERRA_NET_HIP_LSI_UMTSID 0x78
+
+/* Reverse Channel Grant Indication HIP message */
+#define SIERRA_NET_HIP_RCGI 0x64
+
+/* LSI Protocol types */
+#define SIERRA_NET_PROTOCOL_UMTS 0x01
+/* LSI Coverage */
+#define SIERRA_NET_COVERAGE_NONE 0x00
+#define SIERRA_NET_COVERAGE_NOPACKET 0x01
+
+/* LSI Session */
+#define SIERRA_NET_SESSION_IDLE 0x00
+/* LSI Link types */
+#define SIERRA_NET_AS_LINK_TYPE_IPv4 0x00
+
+typedef struct s_lsi_umts {
+ u8 protocol;
+ u8 unused1;
+ __be16 length;
+ /* eventually use a union for the rest - assume umts for now */
+ u8 coverage;
+ u8 unused2[41];
+ u8 session_state;
+ u8 unused3[33];
+ u8 link_type;
+ u8 pdp_addr_len; /* NW-supplied PDP address len */
+ u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */
+ u8 unused4[23];
+ u8 dns1_addr_len; /* NW-supplied 1st DNS address len (bigendian) */
+ u8 dns1_addr[16]; /* NW-supplied 1st DNS address */
+ u8 dns2_addr_len; /* NW-supplied 2nd DNS address len */
+ u8 dns2_addr[16]; /* NW-supplied 2nd DNS address (bigendian)*/
+ u8 wins1_addr_len; /* NW-supplied 1st Wins address len */
+ u8 wins1_addr[16]; /* NW-supplied 1st Wins address (bigendian)*/
+ u8 wins2_addr_len; /* NW-supplied 2nd Wins address len */
+ u8 wins2_addr[16]; /* NW-supplied 2nd Wins address (bigendian) */
+ u8 unused5[4];
+ u8 gw_addr_len; /* NW-supplied GW address len */
+ u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */
+ u8 reserved[8];
+} __attribute__ ((packed)) lsi_umts_t;
+
+#define SIERRA_NET_LSI_COMMON_LEN 4
+#define SIERRA_NET_LSI_UMTS_LEN (sizeof(lsi_umts_t))
+#define SIERRA_NET_LSI_UMTS_STATUS_LEN \
+ (SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN)
+
+/* Forward definitions */
+extern void sierra_sync_timer(unsigned long syncdata);
+static int sierra_net_change_mtu(struct net_device *net, int new_mtu);
+
+/* Our own net device operations structure */
+static const struct net_device_ops sierra_net_device_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = sierra_net_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/* get private data associated with passed in usbnet device */
+static inline struct sierra_net_data *sierra_net_get_private(struct usbnet *dev)
+{
+ return (struct sierra_net_data *)dev->data[0];
+}
+
+/* set private data associated with passed in usbnet device */
+static inline void sierra_net_set_private(struct usbnet *dev,
+ struct sierra_net_data *priv)
+{
+ dev->data[0] = (unsigned long)priv;
+}
+
+/* is packet IPv4 */
+static inline int is_ip(struct sk_buff *skb)
+{
+ return (skb->protocol == cpu_to_be16(ETH_P_IP));
+}
+
+/*
+ * check passed in packet and make sure that:
+ * - it is linear (no scatter/gather)
+ * - it is ethernet (mac_header properly set)
+ */
+static int check_ethip_packet(struct sk_buff *skb, struct usbnet *dev)
+{
+ skb_reset_mac_header(skb); /* ethernet header */
+
+ if (skb_is_nonlinear(skb)) {
+ netdev_err(dev->net, "Non linear buffer-dropping");
+ return 0;
+ }
+
+ if (!pskb_may_pull(skb, ETH_HLEN))
+ return 0;
+ skb->protocol = eth_hdr(skb)->h_proto;
+
+ return 1;
+}
+
+static const u8 *save16bit(struct param *p, const u8 *datap)
+{
+ p->is_present = 1;
+ p->word = get_unaligned_be16(datap);
+ return datap + sizeof(p->word);
+}
+
+static const u8 *save8bit(struct param *p, const u8 *datap)
+{
+ p->is_present = 1;
+ p->byte = *datap;
+ return datap + sizeof(p->byte);
+}
+
+/*----------------------------------------------------------------------------*
+ * BEGIN HIP *
+ *----------------------------------------------------------------------------*/
+/* HIP header */
+#define SIERRA_NET_HIP_HDR_LEN 4
+/* Extended HIP header */
+#define SIERRA_NET_HIP_EXT_HDR_LEN 6
+
+struct hip_hdr {
+ int hdrlen;
+ struct param payload_len;
+ struct param msgid;
+ struct param msgspecific;
+ struct param extmsgid;
+};
+
+static int parse_hip(const u8 *buf, const u32 buflen, struct hip_hdr *hh)
+{
+ const u8 *curp = buf;
+ int padded;
+
+ if (buflen < SIERRA_NET_HIP_HDR_LEN)
+ return -1;
+
+ curp = save16bit(&hh->payload_len, curp);
+ curp = save8bit(&hh->msgid, curp);
+ curp = save8bit(&hh->msgspecific, curp);
+
+ padded = hh->msgid.byte & 0x80;
+ hh->msgid.byte &= 0x7F; /* 7 bits */
+
+ hh->extmsgid.is_present = (hh->msgid.byte == SIERRA_NET_HIP_EXTENDEDID);
+ if (hh->extmsgid.is_present) {
+ if (buflen < SIERRA_NET_HIP_EXT_HDR_LEN)
+ return -2;
+
+ hh->payload_len.word &= 0x3FFF; /* 14 bits */
+
+ curp = save16bit(&hh->extmsgid, curp);
+ hh->extmsgid.word &= 0x03FF; /* 10 bits */
+
+ hh->hdrlen = SIERRA_NET_HIP_EXT_HDR_LEN;
+ } else {
+ hh->payload_len.word &= 0x07FF; /* 11 bits */
+ hh->hdrlen = SIERRA_NET_HIP_HDR_LEN;
+ }
+
+ if (padded) {
+ hh->hdrlen++;
+ hh->payload_len.word--;
+ }
+
+ /* if real packet shorter than the claimed length */
+ if (buflen < (hh->hdrlen + hh->payload_len.word))
+ return -3;
+
+ return 0;
+}
+
+static void build_hip(u8 *buf, const u16 payloadlen,
+ struct sierra_net_data *priv)
+{
+ /* the following doesn't have the full functionality. We
+ * currently build only one kind of header, so it is faster this way
+ */
+ put_unaligned_be16(payloadlen, buf);
+ memcpy(buf+2, priv->tx_hdr_template, sizeof(priv->tx_hdr_template));
+}
+/*----------------------------------------------------------------------------*
+ * END HIP *
+ *----------------------------------------------------------------------------*/
+
+static void sierra_net_send_cmd(struct usbnet *dev,
+ u8 *cmd, int cmdlen, const char * cmd_name)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+ int status;
+
+ status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_CDC_SEND_ENCAPSULATED_COMMAND,
+ USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE, 0,
+ priv->ifnum, cmd, cmdlen, 0);
+
+ if (status != cmdlen && status != -ENODEV)
+ netdev_err(dev->net, "Submit %s failed %d", cmd_name, status);
+}
+
+static void sierra_net_send_sync(struct usbnet *dev)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ sierra_net_send_cmd(dev, priv->sync_msg,
+ sizeof(priv->sync_msg), "SYNC");
+}
+
+static void sierra_net_send_shutdown(struct usbnet *dev)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ sierra_net_send_cmd(dev, priv->shdwn_msg,
+ sizeof(priv->shdwn_msg), "Shutdown");
+}
+
+static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix)
+{
+ dev_dbg(&(priv->usbnet->udev->dev), "%s %d", __func__, ctx_ix);
+ priv->tx_hdr_template[0] = 0x3F;
+ priv->tx_hdr_template[1] = ctx_ix;
+ *((u16 *)&priv->tx_hdr_template[2]) =
+ cpu_to_be16(SIERRA_NET_HIP_EXT_IP_OUT_ID);
+}
+
+static inline int sierra_net_is_valid_addrlen(u8 len)
+{
+ return (len == sizeof(struct in_addr));
+}
+
+static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
+{
+ lsi_umts_t *lsi = (lsi_umts_t *)data;
+
+ if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) {
+ netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, expected %u",
+ __func__, be16_to_cpu(lsi->length),
+ (u32)SIERRA_NET_LSI_UMTS_STATUS_LEN);
+ return -1;
+ }
+
+ /* Validate the protocol - only support UMTS for now */
+ if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) {
+ netdev_err(dev->net, "Protocol unsupported, 0x%02x",
+ lsi->protocol);
+ return -1;
+ }
+
+ /* Validate the link type */
+ if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) {
+ netdev_err(dev->net, "Link type unsupported: 0x%02x",
+ lsi->link_type);
+ return -1;
+ }
+
+ /* Validate the coverage */
+ if (lsi->coverage == SIERRA_NET_COVERAGE_NONE
+ || lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
+ netdev_err(dev->net, "No coverage, 0x%02x", lsi->coverage);
+ return 0;
+ }
+
+ /* Validate the session state */
+ if (lsi->session_state == SIERRA_NET_SESSION_IDLE) {
+ netdev_err(dev->net, "Session idle, 0x%02x",
+ lsi->session_state);
+ return 0;
+ }
+
+ /* Set link_sense true */
+ return 1;
+}
+
+static void sierra_net_handle_lsi(struct usbnet *dev, char *data,
+ struct hip_hdr *hh)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+ int link_up;
+
+ link_up = sierra_net_parse_lsi(dev, data + hh->hdrlen,
+ hh->payload_len.word);
+ if (link_up < 0) {
+ netdev_err(dev->net, "Invalid LSI");
+ return;
+ }
+ if (link_up) {
+ sierra_net_set_ctx_index(priv, hh->msgspecific.byte);
+ priv->link_up = 1;
+ netif_carrier_on(dev->net);
+ } else {
+ priv->link_up = 0;
+ netif_carrier_off(dev->net);
+ }
+}
+
+static void sierra_net_dosync(struct usbnet *dev)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ /* tell modem we are ready */
+ sierra_net_send_sync(dev);
+ sierra_net_send_sync(dev);
+
+ /* Now, start a timer and make sure we get the Restart Indication */
+ priv->sync_timer.function = sierra_sync_timer;
+ priv->sync_timer.data = (unsigned long) dev;
+ priv->sync_timer.expires = jiffies + SIERRA_NET_SYNCDELAY;
+ add_timer(&priv->sync_timer);
+}
+
+static void sierra_net_kevent(struct work_struct *work)
+{
+ struct sierra_net_data *priv =
+ container_of(work, struct sierra_net_data, sierra_net_kevent);
+ struct usbnet *dev = priv->usbnet;
+ int len;
+ int err;
+ u8 *buf;
+ u8 ifnum;
+
+ if (test_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags)) {
+ clear_bit(SIERRA_NET_EVENT_RESP_AVAIL, &priv->kevent_flags);
+
+ /* Query the modem for the LSI message */
+ buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL);
+ if (!buf) {
+ netdev_err(dev->net,
+ "failed to allocate buf for LS msg");
+ return;
+ }
+ ifnum = priv->ifnum;
+ len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+ USB_CDC_GET_ENCAPSULATED_RESPONSE,
+ USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE,
+ 0, ifnum, buf, SIERRA_NET_USBCTL_BUF_LEN, 0);
+
+ if (unlikely(len < 0)) {
+ netdev_err(dev->net,
+ "usb_control_msg failed, status %d", len);
+ } else {
+ struct hip_hdr hh;
+
+ dev_dbg(&dev->udev->dev, "%s: Received status message,"
+ " %04x bytes", __func__, len);
+
+ err = parse_hip(buf, len, &hh);
+ if (err) {
+ netdev_err(dev->net, "%s: Bad packet,"
+ " parse result %d", __func__, err);
+ kfree(buf);
+ return;
+ }
+
+ /* Validate packet length */
+ if (len != hh.hdrlen + hh.payload_len.word) {
+ netdev_err(dev->net, "%s: Bad packet, received"
+ " %d, expected %d", __func__, len,
+ hh.hdrlen + hh.payload_len.word);
+ kfree(buf);
+ return;
+ }
+
+ /* Switch on received message types */
+ switch (hh.msgid.byte) {
+ case SIERRA_NET_HIP_LSI_UMTSID:
+ dev_dbg(&dev->udev->dev, "LSI for ctx:%d",
+ hh.msgspecific.byte);
+ sierra_net_handle_lsi(dev, buf, &hh);
+ break;
+ case SIERRA_NET_HIP_RESTART_ID:
+ dev_dbg(&dev->udev->dev, "Restart reported: %d,"
+ " stopping sync timer",
+ hh.msgspecific.byte);
+ /* Got sync resp - stop timer & clear mask */
+ del_timer_sync(&priv->sync_timer);
+ clear_bit(SIERRA_NET_TIMER_EXPIRY,
+ &priv->kevent_flags);
+ break;
+ case SIERRA_NET_HIP_HSYNC_ID:
+ dev_dbg(&dev->udev->dev, "SYNC received");
+ sierra_net_send_sync(dev);
+ break;
+ case SIERRA_NET_HIP_EXTENDEDID:
+ netdev_err(dev->net, "Unrecognized HIP msg, "
+ "extmsgid 0x%04x", hh.extmsgid.word);
+ break;
+ case SIERRA_NET_HIP_RCGI:
+ /* Ignored */
+ break;
+ default:
+ netdev_err(dev->net, "Unrecognized HIP msg, "
+ "msgid 0x%02x", hh.msgid.byte);
+ break;
+ }
+ }
+ kfree(buf);
+ }
+ /* The sync timer bit might be set */
+ if (test_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags)) {
+ clear_bit(SIERRA_NET_TIMER_EXPIRY, &priv->kevent_flags);
+ dev_dbg(&dev->udev->dev, "Deferred sync timer expiry");
+ sierra_net_dosync(priv->usbnet);
+ }
+
+ if (priv->kevent_flags)
+ dev_dbg(&dev->udev->dev, "sierra_net_kevent done, "
+ "kevent_flags = 0x%lx", priv->kevent_flags);
+}
+
+static void sierra_net_defer_kevent(struct usbnet *dev, int work)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+ set_bit(work, &priv->kevent_flags);
+ schedule_work(&priv->sierra_net_kevent);
+}
+
+/*
+ * Sync Retransmit Timer Handler. On expiry, kick the work queue
+ */
+void sierra_sync_timer(unsigned long syncdata)
+{
+ struct usbnet *dev = (struct usbnet *)syncdata;
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+ /* Kick the tasklet */
+ sierra_net_defer_kevent(dev, SIERRA_NET_TIMER_EXPIRY);
+}
+
+static void sierra_net_status(struct usbnet *dev, struct urb *urb)
+{
+ struct usb_cdc_notification *event;
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ if (urb->actual_length < sizeof *event)
+ return;
+
+ /* Add cases to handle other standard notifications. */
+ event = urb->transfer_buffer;
+ switch (event->bNotificationType) {
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+ case USB_CDC_NOTIFY_SPEED_CHANGE:
+ /* USB 305 sends those */
+ break;
+ case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
+ sierra_net_defer_kevent(dev, SIERRA_NET_EVENT_RESP_AVAIL);
+ break;
+ default:
+ netdev_err(dev->net, ": unexpected notification %02x!",
+ event->bNotificationType);
+ break;
+ }
+}
+
+static void sierra_net_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+ strncpy(info->driver, driver_name, sizeof info->driver);
+ strncpy(info->version, DRIVER_VERSION, sizeof info->version);
+}
+
+static u32 sierra_net_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ /* Report link is down whenever the interface is down */
+ return sierra_net_get_private(dev)->link_up && netif_running(net);
+}
+
+static struct ethtool_ops sierra_net_ethtool_ops = {
+ .get_drvinfo = sierra_net_get_drvinfo,
+ .get_link = sierra_net_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+/* MTU can not be more than 1500 bytes, enforce it. */
+static int sierra_net_change_mtu(struct net_device *net, int new_mtu)
+{
+ if (new_mtu > SIERRA_NET_MAX_SUPPORTED_MTU)
+ return -EINVAL;
+
+ return usbnet_change_mtu(net, new_mtu);
+}
+
+static int is_whitelisted(const u8 ifnum,
+ const struct sierra_net_iface_info *whitelist)
+{
+ if (whitelist) {
+ const u8 *list = whitelist->ifaceinfo;
+ int i;
+
+ for (i = 0; i < whitelist->infolen; i++) {
+ if (list[i] == ifnum)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
+{
+ int result = 0;
+ u16 *attrdata;
+
+ attrdata = kmalloc(sizeof(*attrdata), GFP_KERNEL);
+ if (!attrdata)
+ return -ENOMEM;
+
+ result = usb_control_msg(
+ dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ /* _u8 vendor specific request */
+ SWI_USB_REQUEST_GET_FW_ATTR,
+ USB_DIR_IN | USB_TYPE_VENDOR, /* __u8 request type */
+ 0x0000, /* __u16 value not used */
+ 0x0000, /* __u16 index not used */
+ attrdata, /* char *data */
+ sizeof(*attrdata), /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+
+ if (result < 0) {
+ kfree(attrdata);
+ return -EIO;
+ }
+
+ *datap = *attrdata;
+
+ kfree(attrdata);
+ return result;
+}
+
+/*
+ * collects the bulk endpoints, the status endpoint.
+ */
+static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ u8 ifacenum;
+ u8 numendpoints;
+ u16 fwattr = 0;
+ int status;
+ struct ethhdr *eth;
+ struct sierra_net_data *priv;
+ static const u8 sync_tmplate[sizeof(priv->sync_msg)] = {
+ 0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00};
+ static const u8 shdwn_tmplate[sizeof(priv->shdwn_msg)] = {
+ 0x00, 0x00, SIERRA_NET_HIP_SHUTD_ID, 0x00};
+
+ struct sierra_net_info_data *data =
+ (struct sierra_net_info_data *)dev->driver_info->data;
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ ifacenum = intf->cur_altsetting->desc.bInterfaceNumber;
+ /* We only accept certain interfaces */
+ if (!is_whitelisted(ifacenum, &data->whitelist)) {
+ dev_dbg(&dev->udev->dev, "Ignoring interface: %d", ifacenum);
+ return -ENODEV;
+ }
+ numendpoints = intf->cur_altsetting->desc.bNumEndpoints;
+ /* We have three endpoints, bulk in and out, and a status */
+ if (numendpoints != 3) {
+ dev_err(&dev->udev->dev, "Expected 3 endpoints, found: %d",
+ numendpoints);
+ return -ENODEV;
+ }
+ /* Status endpoint set in usbnet_get_endpoints() */
+ dev->status = NULL;
+ status = usbnet_get_endpoints(dev, intf);
+ if (status < 0) {
+ dev_err(&dev->udev->dev, "Error in usbnet_get_endpoints (%d)",
+ status);
+ return -ENODEV;
+ }
+ /* Initialize sierra private data */
+ priv = kzalloc(sizeof *priv, GFP_KERNEL);
+ if (!priv) {
+ dev_err(&dev->udev->dev, "No memory");
+ return -ENOMEM;
+ }
+
+ priv->usbnet = dev;
+ priv->ifnum = ifacenum;
+ dev->net->netdev_ops = &sierra_net_device_ops;
+
+ /* change MAC addr to include, ifacenum, and to be unique */
+ dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter);
+ dev->net->dev_addr[ETH_ALEN-1] = ifacenum;
+
+ /* we will have to manufacture ethernet headers, prepare template */
+ eth = (struct ethhdr *)priv->ethr_hdr_tmpl;
+ memcpy(ð->h_dest, dev->net->dev_addr, ETH_ALEN);
+ eth->h_proto = cpu_to_be16(ETH_P_IP);
+
+ /* prepare shutdown message template */
+ memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg));
+ /* set context index initially to 0 - prepares tx hdr template */
+ sierra_net_set_ctx_index(priv, 0);
+
+ /* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */
+ dev->rx_urb_size = data->rx_urb_size;
+ if (dev->udev->speed != USB_SPEED_HIGH)
+ dev->rx_urb_size = min_t(size_t, 4096, data->rx_urb_size);
+
+ dev->net->hard_header_len += SIERRA_NET_HIP_EXT_HDR_LEN;
+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+
+ /* Set up the netdev */
+ dev->net->flags |= IFF_NOARP;
+ dev->net->ethtool_ops = &sierra_net_ethtool_ops;
+ netif_carrier_off(dev->net);
+
+ sierra_net_set_private(dev, priv);
+
+ priv->kevent_flags = 0;
+
+ /* Use the shared workqueue */
+ INIT_WORK(&priv->sierra_net_kevent, sierra_net_kevent);
+
+ /* Only need to do this once */
+ init_timer(&priv->sync_timer);
+
+ /* verify fw attributes */
+ status = sierra_net_get_fw_attr(dev, &fwattr);
+ dev_dbg(&dev->udev->dev, "Fw attr: %x\n", fwattr);
+
+ /* test whether firmware supports DHCP */
+ if (!(status == sizeof(fwattr) && (fwattr & SWI_GET_FW_ATTR_MASK))) {
+ /* found incompatible firmware version */
+ dev_err(&dev->udev->dev, "Incompatible driver and firmware"
+ " versions\n");
+ kfree(priv);
+ return -ENODEV;
+ }
+ /* prepare sync message from template */
+ memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg));
+
+ /* initiate the sync sequence */
+ sierra_net_dosync(dev);
+
+ return 0;
+}
+
+static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ /* Kill the timer then flush the work queue */
+ del_timer_sync(&priv->sync_timer);
+
+ flush_scheduled_work();
+
+ /* tell modem we are going away */
+ sierra_net_send_shutdown(dev);
+
+ sierra_net_set_private(dev, NULL);
+
+ kfree(priv);
+}
+
+static struct sk_buff *sierra_net_skb_clone(struct usbnet *dev,
+ struct sk_buff *skb, int len)
+{
+ struct sk_buff *new_skb;
+
+ /* clone skb */
+ new_skb = skb_clone(skb, GFP_ATOMIC);
+
+ /* remove len bytes from original */
+ skb_pull(skb, len);
+
+ /* trim next packet to it's length */
+ if (new_skb) {
+ skb_trim(new_skb, len);
+ } else {
+ if (netif_msg_rx_err(dev))
+ netdev_err(dev->net, "failed to get skb");
+ dev->net->stats.rx_dropped++;
+ }
+
+ return new_skb;
+}
+
+/* ---------------------------- Receive data path ----------------------*/
+static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ int err;
+ struct hip_hdr hh;
+ struct sk_buff *new_skb;
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+
+ /* could contain multiple packets */
+ while (likely(skb->len)) {
+ err = parse_hip(skb->data, skb->len, &hh);
+ if (err) {
+ if (netif_msg_rx_err(dev))
+ netdev_err(dev->net, "Invalid HIP header %d",
+ err);
+ /* dev->net->stats.rx_errors incremented by caller */
+ dev->net->stats.rx_length_errors++;
+ return 0;
+ }
+
+ /* Validate Extended HIP header */
+ if (!hh.extmsgid.is_present
+ || hh.extmsgid.word != SIERRA_NET_HIP_EXT_IP_IN_ID) {
+ if (netif_msg_rx_err(dev))
+ netdev_err(dev->net, "HIP/ETH: Invalid packet");
+
+ dev->net->stats.rx_frame_errors++;
+ /* dev->net->stats.rx_errors incremented by caller */;
+ return 0;
+ }
+
+ skb_pull(skb, hh.hdrlen);
+
+ /* We are going to accept this packet, prepare it */
+ memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl,
+ ETH_HLEN);
+
+ /* Last packet in batch handled by usbnet */
+ if (hh.payload_len.word == skb->len)
+ return 1;
+
+ new_skb = sierra_net_skb_clone(dev, skb, hh.payload_len.word);
+ if (new_skb)
+ usbnet_skb_return(dev, new_skb);
+
+ } /* while */
+
+ return 0;
+}
+
+/* ---------------------------- Transmit data path ----------------------*/
+struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ struct sierra_net_data *priv = sierra_net_get_private(dev);
+ u16 len;
+
+ dev_dbg(&dev->udev->dev, "%s", __func__);
+ if (priv->link_up && check_ethip_packet(skb, dev) && is_ip(skb)) {
+ /* enough head room as is? */
+ if (SIERRA_NET_HIP_EXT_HDR_LEN <= skb_headroom(skb)) {
+ /* Save the Eth/IP length and set up HIP hdr */
+ len = skb->len;
+ skb_push(skb, SIERRA_NET_HIP_EXT_HDR_LEN);
+ build_hip(skb->data, len, priv);
+ return skb;
+ } else {
+ /*
+ * compensate in the future if necessary
+ */
+ netdev_err(dev->net, "tx_fixup: no room for HIP");
+ } /* headroom */
+ }
+
+ if (!priv->link_up)
+ dev->net->stats.tx_carrier_errors++;
+
+ /* tx_dropped incremented by usbnet */
+
+ /* filter the packet out, release it */
+ dev_kfree_skb_any(skb);
+ return NULL;
+}
+
+static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 };
+static const struct sierra_net_info_data sierra_net_info_data_68A3 = {
+ .rx_urb_size = 8 * 1024,
+ .whitelist = {
+ .infolen = ARRAY_SIZE(sierra_net_ifnum_list),
+ .ifaceinfo = sierra_net_ifnum_list
+ }
+};
+
+static const struct driver_info sierra_net_info_68A3 = {
+ .description = "Sierra Wireless USB-to-WWAN Modem",
+ .flags = FLAG_WWAN | FLAG_SEND_ZLP,
+ .bind = sierra_net_bind,
+ .unbind = sierra_net_unbind,
+ .status = sierra_net_status,
+ .rx_fixup = sierra_net_rx_fixup,
+ .tx_fixup = sierra_net_tx_fixup,
+ .data = (unsigned long)&sierra_net_info_data_68A3,
+};
+
+static const struct usb_device_id products[] = {
+ {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
+ .driver_info = (unsigned long) &sierra_net_info_68A3},
+
+ {}, /* last item */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+/* We are based on usbnet, so let it handle the USB driver specifics */
+static struct usb_driver sierra_net_driver = {
+ .name = "sierra_net",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+ .no_dynamic_id = 1,
+};
+
+static int __init sierra_net_init(void)
+{
+ BUILD_BUG_ON(FIELD_SIZEOF(struct usbnet, data)
+ < sizeof(struct cdc_state));
+
+ return usb_register(&sierra_net_driver);
+}
+
+static void __exit sierra_net_exit(void)
+{
+ usb_deregister(&sierra_net_driver);
+}
+
+module_exit(sierra_net_exit);
+module_init(sierra_net_init);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] TIPC: Updated topology subscription protocol according to latest spec
From: David Miller @ 2010-04-06 2:18 UTC (permalink / raw)
To: jon.maloy; +Cc: netdev, tipc-discussion
In-Reply-To: <1270516572-27789-1-git-send-email-jon.maloy@ericsson.com>
You're going to need to provide a descriptive commit log message with
these changes explaining what exactly is changing and why, as well as
provide a proper signoff for the patch.
Please read Documentation/SubmittingPatches at a minimum...
^ permalink raw reply
* Re: net-next: 2.6.34-rc1 regression: panic when running diagnostic on interface with IPv6
From: Stephen Hemminger @ 2010-04-06 2:15 UTC (permalink / raw)
To: Tantilov, Emil S; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <EA929A9653AAE14F841771FB1DE5A1365FE4E2E334@rrsmsx501.amr.corp.intel.com>
On Mon, 5 Apr 2010 17:50:38 -0600
"Tantilov, Emil S" <emil.s.tantilov@intel.com> wrote:
> David Miller wrote:
> > From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
> > Date: Mon, 5 Apr 2010 17:03:56 -0600
> >
> >> David Miller wrote:
> >>> From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
> >>> Date: Tue, 23 Mar 2010 12:28:08 -0600
> >>>
> >>>> Bisecting points to this patch:
> >>>> http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=84e8b803f1e16f3a2b8b80f80a63fa2f2f8a9be6
> >>>>
> >>>> And I confirmed that the issue goes away after reverting it.
> >>>>
> >>>> Steps to reproduce:
> >>>> 1. Load the driver and configure IPv6 address.
> >>>> 2. Run ethtool diag:
> >>>> ethtool -t eth0
> >>>>
> >>>> 3. If this doesn't brake it try again, or just do ifdown/up. Other
> >>>> operations on the interface will eventually panic the system:
> >>>
> >>> Stephen please fix this, thanks.
> >>
> >> Just FYI - I still see this issue with latest pull from net-2.6.
> >
> > It's net-next-2.6 that introduced the problem and has the follow-on
> > fixes, not net-2.6
>
> Same in net-next:
>
> [ 55.706583] WARNING: at net/ipv6/ip6_fib.c:1170 fib6_del+0x44/0x39f [ipv6]()
> [ 55.714851] Hardware name: S5520HC
> [ 55.719037] Modules linked in: ipv6 e1000e e1000
> [ 55.724866] Pid: 5599, comm: ifconfig Not tainted 2.6.34-rc1-net-next-e1000e-040510 #9
> [ 55.734418] Call Trace:
> [ 55.737540] [<ffffffff81033a3e>] ? __wake_up+0x43/0x50
> [ 55.743773] [<ffffffffa006cb4e>] ? fib6_del+0x44/0x39f [ipv6]
> [ 55.750687] [<ffffffff81038b1e>] warn_slowpath_common+0x77/0x8f
> [ 55.757793] [<ffffffff81038b45>] warn_slowpath_null+0xf/0x11
> [ 55.764608] [<ffffffffa006cb4e>] fib6_del+0x44/0x39f [ipv6]
> [ 55.771314] [<ffffffffa006a13b>] __ip6_del_rt+0x49/0x68 [ipv6]
> [ 55.778319] [<ffffffffa006a2aa>] ip6_del_rt+0x38/0x3a [ipv6]
> [ 55.785136] [<ffffffffa0065573>] __ipv6_ifa_notify+0x141/0x17d [ipv6]
> [ 55.792816] [<ffffffffa00660a4>] addrconf_ifdown+0x1ed/0x2cb [ipv6]
> [ 55.800300] [<ffffffffa0067126>] addrconf_notify+0x705/0x7b6 [ipv6]
> [ 55.807788] [<ffffffff810456ce>] ? spin_unlock_irqrestore+0x9/0xb
> [ 55.815088] [<ffffffff81045b80>] ? __mod_timer+0x125/0x137
> [ 55.821703] [<ffffffff8144eb60>] ? _raw_write_unlock_bh+0x12/0x14
> [ 55.828995] [<ffffffff8103e37d>] ? local_bh_enable_ip+0x9/0xb
> [ 55.835906] [<ffffffff8144ec75>] ? _raw_spin_unlock_bh+0x12/0x14
> [ 55.843109] [<ffffffffa006ca9b>] ? fib6_run_gc+0xca/0xcf [ipv6]
> [ 55.850213] [<ffffffff81451b29>] notifier_call_chain+0x33/0x5b
> [ 55.857216] [<ffffffff81055575>] __raw_notifier_call_chain+0x9/0xb
> [ 55.864604] [<ffffffff81055586>] raw_notifier_call_chain+0xf/0x11
> [ 55.871901] [<ffffffff81397d8f>] call_netdevice_notifiers+0x16/0x18
> [ 55.879390] [<ffffffff81397eb2>] __dev_notify_flags+0x35/0x59
> [ 55.886293] [<ffffffff81397f1c>] dev_change_flags+0x46/0x52
> [ 55.893007] [<ffffffff813f0844>] devinet_ioctl+0x27f/0x54b
> [ 55.899614] [<ffffffff813f2c18>] inet_ioctl+0x8a/0xa2
> [ 55.905733] [<ffffffff81387275>] sock_do_ioctl+0x26/0x46
> [ 55.912149] [<ffffffff81387490>] sock_ioctl+0x1fb/0x20e
> [ 55.918461] [<ffffffff810e7b4b>] vfs_ioctl+0x2a/0x9d
> [ 55.924495] [<ffffffff810e80c2>] do_vfs_ioctl+0x48c/0x4dd
> [ 55.930999] [<ffffffff810e816a>] sys_ioctl+0x57/0x7a
> [ 55.937033] [<ffffffff81002a2b>] system_call_fastpath+0x16/0x1b
> [ 55.944123] ---[ end trace c1c390412f982fb6 ]---
> [ 55.949677] Freeing alive inet6 address ffff8801eee32000
> [ 56.034060] fib6_clean_node: del failed: rt=ffff8801ec984e00@(null) err=-2
>
Which driver is this, the test function is driver dependent?
--
^ permalink raw reply
* RE: net-next: 2.6.34-rc1 regression: panic when running diagnostic on interface with IPv6
From: Tantilov, Emil S @ 2010-04-06 2:37 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <20100405191524.2a7848f3@nehalam>
Stephen Hemminger wrote:
> On Mon, 5 Apr 2010 17:50:38 -0600
> "Tantilov, Emil S" <emil.s.tantilov@intel.com> wrote:
>
>> David Miller wrote:
>>> From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
>>> Date: Mon, 5 Apr 2010 17:03:56 -0600
>>>
>>>> David Miller wrote:
>>>>> From: "Tantilov, Emil S" <emil.s.tantilov@intel.com>
>>>>> Date: Tue, 23 Mar 2010 12:28:08 -0600
>>>>>
>>>>>> Bisecting points to this patch:
>>>>>> http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=84e8b803f1e16f3a2b8b80f80a63fa2f2f8a9be6
>>>>>>
>>>>>> And I confirmed that the issue goes away after reverting it.
>>>>>>
>>>>>> Steps to reproduce:
>>>>>> 1. Load the driver and configure IPv6 address.
>>>>>> 2. Run ethtool diag:
>>>>>> ethtool -t eth0
>>>>>>
>>>>>> 3. If this doesn't brake it try again, or just do ifdown/up.
>>>>>> Other operations on the interface will eventually panic the
>>>>>> system:
>>>>>
>>>>> Stephen please fix this, thanks.
>>>>
>>>> Just FYI - I still see this issue with latest pull from net-2.6.
>>>
>>> It's net-next-2.6 that introduced the problem and has the follow-on
>>> fixes, not net-2.6
>>
>> Same in net-next:
>>
>> [ 55.706583] WARNING: at net/ipv6/ip6_fib.c:1170
>> fib6_del+0x44/0x39f [ipv6]() [ 55.714851] Hardware name: S5520HC
>> [ 55.719037] Modules linked in: ipv6 e1000e e1000
>> [ 55.724866] Pid: 5599, comm: ifconfig Not tainted
>> 2.6.34-rc1-net-next-e1000e-040510 #9 [ 55.734418] Call Trace: [
>> 55.737540] [<ffffffff81033a3e>] ? __wake_up+0x43/0x50 [
>> 55.743773] [<ffffffffa006cb4e>] ? fib6_del+0x44/0x39f [ipv6] [
>> 55.750687] [<ffffffff81038b1e>] warn_slowpath_common+0x77/0x8f [
>> 55.757793] [<ffffffff81038b45>] warn_slowpath_null+0xf/0x11 [
>> 55.764608] [<ffffffffa006cb4e>] fib6_del+0x44/0x39f [ipv6] [
>> 55.771314] [<ffffffffa006a13b>] __ip6_del_rt+0x49/0x68 [ipv6] [
>> 55.778319] [<ffffffffa006a2aa>] ip6_del_rt+0x38/0x3a [ipv6] [
>> 55.785136] [<ffffffffa0065573>] __ipv6_ifa_notify+0x141/0x17d
>> [ipv6] [ 55.792816] [<ffffffffa00660a4>]
>> addrconf_ifdown+0x1ed/0x2cb [ipv6] [ 55.800300]
>> [<ffffffffa0067126>] addrconf_notify+0x705/0x7b6 [ipv6] [
>> 55.807788] [<ffffffff810456ce>] ? spin_unlock_irqrestore+0x9/0xb [
>> 55.815088] [<ffffffff81045b80>] ? __mod_timer+0x125/0x137 [
>> 55.821703] [<ffffffff8144eb60>] ? _raw_write_unlock_bh+0x12/0x14 [
>> 55.828995] [<ffffffff8103e37d>] ? local_bh_enable_ip+0x9/0xb [
>> 55.835906] [<ffffffff8144ec75>] ? _raw_spin_unlock_bh+0x12/0x14 [
>> 55.843109] [<ffffffffa006ca9b>] ? fib6_run_gc+0xca/0xcf [ipv6] [
>> 55.850213] [<ffffffff81451b29>] notifier_call_chain+0x33/0x5b [
>> 55.857216] [<ffffffff81055575>] __raw_notifier_call_chain+0x9/0xb [
>> 55.864604] [<ffffffff81055586>] raw_notifier_call_chain+0xf/0x11 [
>> 55.871901] [<ffffffff81397d8f>] call_netdevice_notifiers+0x16/0x18
>> [ 55.879390] [<ffffffff81397eb2>] __dev_notify_flags+0x35/0x59 [
>> 55.886293] [<ffffffff81397f1c>] dev_change_flags+0x46/0x52 [
>> 55.893007] [<ffffffff813f0844>] devinet_ioctl+0x27f/0x54b [
>> 55.899614] [<ffffffff813f2c18>] inet_ioctl+0x8a/0xa2 [ 55.905733]
>> [<ffffffff81387275>] sock_do_ioctl+0x26/0x46 [ 55.912149]
>> [<ffffffff81387490>] sock_ioctl+0x1fb/0x20e [ 55.918461]
>> [<ffffffff810e7b4b>] vfs_ioctl+0x2a/0x9d [ 55.924495]
>> [<ffffffff810e80c2>] do_vfs_ioctl+0x48c/0x4dd [ 55.930999]
>> [<ffffffff810e816a>] sys_ioctl+0x57/0x7a [ 55.937033]
>> [<ffffffff81002a2b>] system_call_fastpath+0x16/0x1b [ 55.944123]
>> ---[ end trace c1c390412f982fb6 ]--- [ 55.949677] Freeing alive
>> inet6 address ffff8801eee32000 [ 56.034060] fib6_clean_node: del
>> failed: rt=ffff8801ec984e00@(null) err=-2
>>
>
> Which driver is this, the test function is driver dependent?
I have seen the panic with e1000e and bnx2.
Emil
^ permalink raw reply
* Re: [v2 Patch 3/3] bonding: make bonding support netpoll
From: Cong Wang @ 2010-04-06 2:43 UTC (permalink / raw)
To: Andy Gospodarek
Cc: linux-kernel, Matt Mackall, netdev, bridge, Andy Gospodarek,
Neil Horman, Jeff Moyer, Stephen Hemminger, bonding-devel,
Jay Vosburgh, David Miller
In-Reply-To: <20100405194356.GA10488@gospo.rdu.redhat.com>
Andy Gospodarek wrote:
>
> I tried these patches on top of Linus' latest tree and still get
> deadlocks. Your line numbers might differ a bit, but you should be
> seeing them too.
>
Yeah, my local clone is some days behind Linus' latest tree. :)
> # echo 7 4 1 7 > /proc/sys/kernel/printk
> # ifup bond0
> bonding: bond0: setting mode to balance-rr (0).
> bonding: bond0: Setting MII monitoring interval to 1000.
> ADDRCONF(NETDEV_UP): bond0: link is not ready
> bonding: bond0: Adding slave eth4.
> bnx2 0000:10:00.0: eth4: using MSIX
> bonding: bond0: enslaving eth4 as an active interface with a down link.
> bonding: bond0: Adding slave eth5.
> bnx2 0000:10:00.1: eth5: using MSIX
> bonding: bond0: enslaving eth5 as an active interface with a down link.
> bnx2 0000:10:00.0: eth4: NIC Copper Link is Up, 100 Mbps full duplex,
> receive & transmit flow control ON
> bonding: bond0: link status definitely up for interface eth4.
> ADDRCONF(NETDEV_CHANGE): bond0: link becomes ready
> bnx2 0000:10:00.1: eth5: NIC Copper Link is Up, 100 Mbps full duplex,
> receive & transmit flow control ON
> bond0: IPv6 duplicate address fe80::210:18ff:fe36:ad4 detected!
> bonding: bond0: link status definitely up for interface eth5.
> # cat /proc/net/bonding/bond0
> Ethernet Channel Bonding Driver: v3.6.0 (September 26, 2009)
>
> Bonding Mode: load balancing (round-robin)
> MII Status: up
> MII Polling Interval (ms): 1000
> Up Delay (ms): 0
> Down Delay (ms): 0
>
> Slave Interface: eth4
> MII Status: up
> Link Failure Count: 0
> Permanent HW addr: 00:10:18:36:0a:d4
>
> Slave Interface: eth5
> MII Status: up
> Link Failure Count: 0
> Permanent HW addr: 00:10:18:36:0a:d6
> # modprobe netconsole
> netconsole: local port 1234
> netconsole: local IP 10.0.100.2
> netconsole: interface 'bond0'
> netconsole: remote port 6666
> netconsole: remote IP 10.0.100.1
> netconsole: remote ethernet address 00:e0:81:71:ee:aa
> console [netcon0] enabled
> netconsole: network logging started
> # echo -eth4 > /sys/class/net/bond0/bonding/slaves
> bonding: bond0: Removing slave eth4
>
> [ now the system is hung ]
>
> My suspicion from dealing with this problem in the past is that there is
> contention over bond->lock.
>
> Since there statements that will result in netconsole messages inside
> the write_lock_bh in bond_release:
>
> 1882 write_lock_bh(&bond->lock);
> 1883
> 1884 slave = bond_get_slave_by_dev(bond, slave_dev);
> 1885 if (!slave) {
> 1886 /* not a slave of this bond */
> 1887 pr_info("%s: %s not enslaved\n",
> 1888 bond_dev->name, slave_dev->name);
> 1889 write_unlock_bh(&bond->lock);
> 1890 return -EINVAL;
> 1891 }
> 1892
> 1893 if (!bond->params.fail_over_mac) {
> 1894 if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) &&
> 1895 bond->slave_cnt > 1)
> 1896 pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s.
>
> we are getting stuck at 1986 since bond_xmit_roundrobin (in my case)
> will try and acquire bond->lock for reading.
>
> One valuable aspect netpoll_start_xmit routine was that is could be used
> to check to be sure that bond->lock could be taken for writing. This
> made us sure that we were not in a call stack that has already taken the
> lock and queuing the skb to be sent later would prevent the imminent
> deadlock.
>
> A way to prevent this is needed and a first-pass might be to do
> something similar to what I below above for all the xmit routines. I
> confirmed the following patch prevents that deadlock:
>
> # git diff drivers/net/bonding/
> diff --git a/drivers/net/bonding/bond_main.c
> b/drivers/net/bonding/bond_main.c
> index 4a41886..53b39cc 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -4232,7 +4232,8 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struc
> int i, slave_no, res = 1;
> struct iphdr *iph = ip_hdr(skb);
>
> - read_lock(&bond->lock);
> + if (!read_trylock(&bond->lock))
> + return NETDEV_TX_BUSY;
>
> if (!BOND_IS_OK(bond))
> goto out;
>
> The kernel no longer hangs, but a new warning message shows up (over
> netconsole even!):
>
> ------------[ cut here ]------------
> WARNING: at kernel/softirq.c:143 local_bh_enable+0x43/0xba()
> Hardware name: HP xw4400 Workstation
> Modules linked in: tg3 netconsole bonding ipt_REJECT bridge stp autofs4
> i2c_dev i2c_core hidp rfcomm l2cap crc16 bluetooth rfkill sunrpc 8021q
> iptable_filter ip_tables ip6t_REJECT xt_tcpudp ip6table_filter
> ip6_tables x_tables ipv6 cpufreq_ondemand acpi_cpufreq dm_multipath
> video output sbs sbshc battery acpi_memhotplug ac lp sg ide_cd_mod
> tpm_tis rtc_cmos rtc_core serio_raw cdrom libphy e1000e floppy
> parport_pc parport button tpm tpm_bios bnx2 rtc_lib tulip pcspkr shpchp
> dm_snapshot dm_zero dm_mirror dm_region_hash dm_log dm_mod ata_piix ahci
> libata sd_mod scsi_mod ext3 jbd uhci_hcd ohci_hcd ehci_hcd [last
> unloaded: tg3]
> Pid: 9, comm: events/0 Not tainted 2.6.34-rc3 #6
> Call Trace:
> [<ffffffff81058754>] ? cpu_clock+0x2d/0x41
> [<ffffffff810404d9>] ? local_bh_enable+0x43/0xba
> [<ffffffff8103a350>] warn_slowpath_common+0x77/0x8f
> [<ffffffff812a4659>] ? dev_queue_xmit+0x408/0x467
> [<ffffffff8103a377>] warn_slowpath_null+0xf/0x11
> [<ffffffff810404d9>] local_bh_enable+0x43/0xba
> [<ffffffff812a4659>] dev_queue_xmit+0x408/0x467
> [<ffffffff812a435e>] ? dev_queue_xmit+0x10d/0x467
> [<ffffffffa04a3868>] bond_dev_queue_xmit+0x1cd/0x1f9 [bonding]
> [<ffffffffa04a4217>] bond_start_xmit+0x139/0x3e9 [bonding]
> [<ffffffff812b0e9a>] queue_process+0xa8/0x160
> [<ffffffff812b0df2>] ? queue_process+0x0/0x160
> [<ffffffff81003794>] kernel_thread_helper+0x4/0x10
> [<ffffffff813362bc>] ? restore_args+0x0/0x30
> [<ffffffff81053884>] ? kthread+0x0/0x85
>
> to point out possible locking issues (probably in netpoll_send_skb) that
> I would suggest you investigate further. It may point to why we cannot
> perform an:
>
> # rmmod bonding
>
> without the system deadlocking (even with my patch above).
>
Thanks a lot for testing!
Before I try to reproduce it, could you please try to replace the 'read_lock()'
in slaves_support_netpoll() with 'read_lock_bh()'? (read_unlock() too) Try if this helps.
After I reproduce this, I will try it too.
^ permalink raw reply
* [PATCH] IPVS: replace sprintf to snprintf to avoid stack buffer overflow
From: wzt.wzt @ 2010-04-06 2:50 UTC (permalink / raw)
To: linux-kernel; +Cc: wensong, netdev, lvs-devel
IPVS not check the length of pp->name, use sprintf will cause stack buffer overflow.
struct ip_vs_protocol{} declare name as char *, if register a protocol as:
struct ip_vs_protocol ip_vs_test = {
.name = "aaaaaaaa....128...aaa",
.debug_packet = ip_vs_tcpudp_debug_packet,
};
when called ip_vs_tcpudp_debug_packet(), sprintf(buf, "%s TRUNCATED", pp->name);
will cause stack buffer overflow.
Signed-off-by: Zhitong Wang <zhitong.wangzt@alibaba-inc.com>
---
net/netfilter/ipvs/ip_vs_proto.c | 16 ++++++++--------
net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 8 ++++----
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 0e58455..8143318 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -166,9 +166,9 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
- sprintf(buf, "%s TRUNCATED", pp->name);
+ snprintf(buf, sizeof(buf), "%s TRUNCATED", pp->name);
else if (ih->frag_off & htons(IP_OFFSET))
- sprintf(buf, "%s %pI4->%pI4 frag",
+ snprintf(buf, sizeof(buf), "%s %pI4->%pI4 frag",
pp->name, &ih->saddr, &ih->daddr);
else {
__be16 _ports[2], *pptr
@@ -176,10 +176,10 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
pptr = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_ports), _ports);
if (pptr == NULL)
- sprintf(buf, "%s TRUNCATED %pI4->%pI4",
+ snprintf(buf, sizeof(buf), "%s TRUNCATED %pI4->%pI4",
pp->name, &ih->saddr, &ih->daddr);
else
- sprintf(buf, "%s %pI4:%u->%pI4:%u",
+ snprintf(buf, sizeof(buf), "%s %pI4:%u->%pI4:%u",
pp->name,
&ih->saddr, ntohs(pptr[0]),
&ih->daddr, ntohs(pptr[1]));
@@ -200,9 +200,9 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
- sprintf(buf, "%s TRUNCATED", pp->name);
+ snprintf(buf, sizeof(buf), "%s TRUNCATED", pp->name);
else if (ih->nexthdr == IPPROTO_FRAGMENT)
- sprintf(buf, "%s %pI6->%pI6 frag",
+ snprintf(buf, sizeof(buf), "%s %pI6->%pI6 frag",
pp->name, &ih->saddr, &ih->daddr);
else {
__be16 _ports[2], *pptr;
@@ -210,10 +210,10 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
sizeof(_ports), _ports);
if (pptr == NULL)
- sprintf(buf, "%s TRUNCATED %pI6->%pI6",
+ snprintf(buf, sizeof(buf), "%s TRUNCATED %pI6->%pI6",
pp->name, &ih->saddr, &ih->daddr);
else
- sprintf(buf, "%s %pI6:%u->%pI6:%u",
+ snprintf(buf, sizeof(buf), "%s %pI6:%u->%pI6:%u",
pp->name,
&ih->saddr, ntohs(pptr[0]),
&ih->daddr, ntohs(pptr[1]));
diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
index c30b43c..ce795ab 100644
--- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
@@ -136,9 +136,9 @@ ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
- sprintf(buf, "%s TRUNCATED", pp->name);
+ snprintf(buf, sizeof(buf), "%s TRUNCATED", pp->name);
else
- sprintf(buf, "%s %pI4->%pI4",
+ snprintf(buf, sizeof(buf), "%s %pI4->%pI4",
pp->name, &ih->saddr, &ih->daddr);
pr_debug("%s: %s\n", msg, buf);
@@ -154,9 +154,9 @@ ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
- sprintf(buf, "%s TRUNCATED", pp->name);
+ snprintf(buf, sizeof(buf), "%s TRUNCATED", pp->name);
else
- sprintf(buf, "%s %pI6->%pI6",
+ snprintf(buf, sizeof(buf), "%s %pI6->%pI6",
pp->name, &ih->saddr, &ih->daddr);
pr_debug("%s: %s\n", msg, buf);
--
1.6.5.3
^ permalink raw reply related
* Re: [PATCH] IPVS: replace sprintf to snprintf to avoid stack buffer overflow
From: Changli Gao @ 2010-04-06 2:58 UTC (permalink / raw)
To: wzt.wzt; +Cc: linux-kernel, wensong, netdev, lvs-devel
In-Reply-To: <20100406025020.GA2741@localhost.localdomain>
On Tue, Apr 6, 2010 at 10:50 AM, <wzt.wzt@gmail.com> wrote:
> IPVS not check the length of pp->name, use sprintf will cause stack buffer overflow.
> struct ip_vs_protocol{} declare name as char *, if register a protocol as:
> struct ip_vs_protocol ip_vs_test = {
> .name = "aaaaaaaa....128...aaa",
> .debug_packet = ip_vs_tcpudp_debug_packet,
> };
>
> when called ip_vs_tcpudp_debug_packet(), sprintf(buf, "%s TRUNCATED", pp->name);
> will cause stack buffer overflow.
>
Long messages will be truncated instead of buffer overflow. We need to
find a way to handle long messages elegantly.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [PATCH] virtio-net: move sg off stack
From: Rusty Russell @ 2010-04-06 3:14 UTC (permalink / raw)
To: David Miller; +Cc: mst, jpirko, xma, netdev, linux-kernel
In-Reply-To: <20100401.192648.185498218.davem@davemloft.net>
On Fri, 2 Apr 2010 12:56:48 pm David Miller wrote:
> From: "Michael S. Tsirkin" <mst@redhat.com>
> Date: Wed, 31 Mar 2010 15:41:58 +0300
>
> > Move sg structure off stack and into virtnet_info structure.
> > This helps remove extra sg_init_table calls as well as reduce
> > stack usage.
> >
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > ---
> >
> > Compile-tested only for now.
> > Shirley, Rusty Russell, does this fix CONFIG_DEBUG_SG=y for you?
Yes, this fixes the BUG_ON() for me (trivial changes to base on Linus'
tree only).
Thanks,
Rusty.
^ permalink raw reply
* Re: [PATCH] IPVS: replace sprintf to snprintf to avoid stack buffer overflow
From: Simon Horman @ 2010-04-06 3:22 UTC (permalink / raw)
To: wzt.wzt
Cc: linux-kernel, Wensong Zhang, Julian Anastasov, netdev, lvs-devel,
Patrick McHardy
In-Reply-To: <20100406025020.GA2741@localhost.localdomain>
On Tue, Apr 06, 2010 at 10:50:20AM +0800, wzt.wzt@gmail.com wrote:
> IPVS not check the length of pp->name, use sprintf will cause stack buffer overflow.
> struct ip_vs_protocol{} declare name as char *, if register a protocol as:
> struct ip_vs_protocol ip_vs_test = {
> .name = "aaaaaaaa....128...aaa",
> .debug_packet = ip_vs_tcpudp_debug_packet,
> };
>
> when called ip_vs_tcpudp_debug_packet(), sprintf(buf, "%s TRUNCATED", pp->name);
> will cause stack buffer overflow.
>
> Signed-off-by: Zhitong Wang <zhitong.wangzt@alibaba-inc.com>
I think that the simple answer is, don't do that.
But your patch seems entirely reasonable to me.
Acked-by: Simon Horman <horms@verge.net.au>
Patrick, please consider merging this.
^ permalink raw reply
* Re: [PATCH] IPVS: replace sprintf to snprintf to avoid stack buffer overflow
From: Simon Horman @ 2010-04-06 3:26 UTC (permalink / raw)
To: Changli Gao
Cc: wzt.wzt, linux-kernel, wensong, Julian Anastasov, netdev,
lvs-devel, Patrick McHardy
In-Reply-To: <k2l412e6f7f1004051958h7c50f439r6b7a84379c35cba5@mail.gmail.com>
On Tue, Apr 06, 2010 at 10:58:28AM +0800, Changli Gao wrote:
> On Tue, Apr 6, 2010 at 10:50 AM, <wzt.wzt@gmail.com> wrote:
> > IPVS not check the length of pp->name, use sprintf will cause stack buffer overflow.
> > struct ip_vs_protocol{} declare name as char *, if register a protocol as:
> > struct ip_vs_protocol ip_vs_test = {
> > .name = "aaaaaaaa....128...aaa",
> > .debug_packet = ip_vs_tcpudp_debug_packet,
> > };
> >
> > when called ip_vs_tcpudp_debug_packet(), sprintf(buf, "%s TRUNCATED", pp->name);
> > will cause stack buffer overflow.
> >
>
> Long messages will be truncated instead of buffer overflow. We need to
> find a way to handle long messages elegantly.
Its really a corner case. In practice protocol modules don't have really
long names. And if one was merged that did, the buffer size could be increased
at that time.
So while I think its reasonable to protect against something unexpected
in a protocol-module name crashing the system. Especially as that
can be achieved without any real overhead. I don't think we need
to sanitise the output.
^ permalink raw reply
* Re: [v2 Patch 3/3] bonding: make bonding support netpoll
From: Cong Wang @ 2010-04-06 4:38 UTC (permalink / raw)
To: Andy Gospodarek
Cc: linux-kernel, Matt Mackall, netdev, bridge, Andy Gospodarek,
Neil Horman, Jeff Moyer, Stephen Hemminger, bonding-devel,
Jay Vosburgh, David Miller
In-Reply-To: <4BBA9FDB.4040909@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 279 bytes --]
Cong Wang wrote:
> Before I try to reproduce it, could you please try to replace the
> 'read_lock()'
> in slaves_support_netpoll() with 'read_lock_bh()'? (read_unlock() too)
> Try if this helps.
>
Confirmed. Please use the attached patch instead, for your testing.
Thanks!
[-- Attachment #2: bonding-support-netpoll.diff --]
[-- Type: text/x-patch, Size: 4225 bytes --]
Index: linux-2.6/drivers/net/bonding/bond_main.c
===================================================================
--- linux-2.6.orig/drivers/net/bonding/bond_main.c
+++ linux-2.6/drivers/net/bonding/bond_main.c
@@ -59,6 +59,7 @@
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
+#include <linux/netpoll.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/etherdevice.h>
@@ -430,7 +431,18 @@ int bond_dev_queue_xmit(struct bonding *
}
skb->priority = 1;
- dev_queue_xmit(skb);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (bond->dev->priv_flags & IFF_IN_NETPOLL) {
+ struct netpoll *np = bond->dev->npinfo->netpoll;
+ slave_dev->npinfo = bond->dev->npinfo;
+ np->real_dev = np->dev = skb->dev;
+ slave_dev->priv_flags |= IFF_IN_NETPOLL;
+ netpoll_send_skb(np, skb);
+ slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
+ np->dev = bond->dev;
+ } else
+#endif
+ dev_queue_xmit(skb);
return 0;
}
@@ -1329,6 +1341,61 @@ static void bond_detach_slave(struct bon
bond->slave_cnt--;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * You must hold read lock of bond->lock before calling this.
+ */
+static bool slaves_support_netpoll(struct net_device *bond_dev)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i = 0;
+ bool ret = true;
+
+ bond_for_each_slave(bond, slave, i) {
+ if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL)
+ || !slave->dev->netdev_ops->ndo_poll_controller)
+ ret = false;
+ }
+ return i != 0 && ret;
+}
+
+static void bond_poll_controller(struct net_device *bond_dev)
+{
+ struct net_device *dev = bond_dev->npinfo->netpoll->real_dev;
+ if (dev != bond_dev)
+ netpoll_poll_dev(dev);
+}
+
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ const struct net_device_ops *ops;
+ int i;
+
+ read_lock(&bond->lock);
+ bond_dev->npinfo = NULL;
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->dev) {
+ ops = slave->dev->netdev_ops;
+ if (ops->ndo_netpoll_cleanup)
+ ops->ndo_netpoll_cleanup(slave->dev);
+ else
+ slave->dev->npinfo = NULL;
+ }
+ }
+ read_unlock(&bond->lock);
+}
+
+#else
+
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+}
+
+#endif
+
/*---------------------------------- IOCTL ----------------------------------*/
static int bond_sethwaddr(struct net_device *bond_dev,
@@ -1735,6 +1802,18 @@ int bond_enslave(struct net_device *bond
bond_set_carrier(bond);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ if (slaves_support_netpoll(bond_dev)) {
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ if (bond_dev->npinfo)
+ slave_dev->npinfo = bond_dev->npinfo;
+ } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
+ bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
+ pr_info("New slave device %s does not support netpoll\n",
+ slave_dev->name);
+ pr_info("Disabling netpoll support for %s\n", bond_dev->name);
+ }
+#endif
read_unlock(&bond->lock);
res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1929,6 +2008,17 @@ int bond_release(struct net_device *bond
netdev_set_master(slave_dev, NULL);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ read_lock_bh(&bond->lock);
+ if (slaves_support_netpoll(bond_dev))
+ bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+ read_unlock_bh(&bond->lock);
+ if (slave_dev->netdev_ops->ndo_netpoll_cleanup)
+ slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev);
+ else
+ slave_dev->npinfo = NULL;
+#endif
+
/* close slave before restoring its mac address */
dev_close(slave_dev);
@@ -4448,6 +4538,10 @@ static const struct net_device_ops bond_
.ndo_vlan_rx_register = bond_vlan_rx_register,
.ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_netpoll_cleanup = bond_netpoll_cleanup,
+ .ndo_poll_controller = bond_poll_controller,
+#endif
};
static void bond_setup(struct net_device *bond_dev)
@@ -4533,6 +4627,8 @@ static void bond_uninit(struct net_devic
{
struct bonding *bond = netdev_priv(bond_dev);
+ bond_netpoll_cleanup(bond_dev);
+
/* Release the bonded slaves */
bond_release_all(bond_dev);
^ permalink raw reply
* [PATCH 0/2] net/irda: sh_sir: Bug fix patches
From: Kuninori Morimoto @ 2010-04-06 4:42 UTC (permalink / raw)
To: netdev; +Cc: Samuel Ortiz, David S. Miller
Dear David
Kuninori Morimoto (2):
net/irda: sh_sir: fixup err return value on sh_sir_open
net/irda: sh_sir: Modify iounmap wrong execution
These 2 patches are bug fix of sh_sir driver.
Best regards
--
Kuninori Morimoto
^ permalink raw reply
* [PATCH 1/2] net/irda: sh_sir: fixup err return value on sh_sir_open
From: Kuninori Morimoto @ 2010-04-06 4:43 UTC (permalink / raw)
To: netdev; +Cc: Samuel Ortiz, David S. Miller
In-Reply-To: <u39z96vk2.wl%kuninori.morimoto.gx@renesas.com>
On sh_sir_open function, there was a possibility that
err variable didn't have value even though it is return value.
This patch modify it.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
drivers/net/irda/sh_sir.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index d7c983d..761ed01 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -645,8 +645,10 @@ static int sh_sir_open(struct net_device *ndev)
sh_sir_set_baudrate(self, 9600);
self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
- if (!self->irlap)
+ if (!self->irlap) {
+ err = -ENODEV;
goto open_err;
+ }
/*
* Now enable the interrupt then start the queue
--
1.6.3.3
^ permalink raw reply related
* [PATCH 2/2] net/irda: sh_sir: Modify iounmap wrong execution
From: Kuninori Morimoto @ 2010-04-06 4:43 UTC (permalink / raw)
To: netdev; +Cc: Samuel Ortiz, David S. Miller
In-Reply-To: <u39z96vk2.wl%kuninori.morimoto.gx@renesas.com>
On sh_sir_probe function, there was a possibility that
iounmap is executed even though self->membase was NULL when error case.
This patch modify it.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
drivers/net/irda/sh_sir.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index a4677b8..bdfefa0 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -720,7 +720,6 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
struct sh_sir_self *self;
struct resource *res;
char clk_name[8];
- void __iomem *base;
unsigned int irq;
int err = -ENOMEM;
@@ -735,14 +734,14 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
if (!ndev)
goto exit;
- base = ioremap_nocache(res->start, resource_size(res));
- if (!base) {
+ self = netdev_priv(ndev);
+ self->membase = ioremap_nocache(res->start, resource_size(res));
+ if (!self->membase) {
err = -ENXIO;
dev_err(&pdev->dev, "Unable to ioremap.\n");
goto err_mem_1;
}
- self = netdev_priv(ndev);
err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
if (err)
goto err_mem_2;
@@ -759,7 +758,6 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
ndev->netdev_ops = &sh_sir_ndo;
ndev->irq = irq;
- self->membase = base;
self->ndev = ndev;
self->qos.baud_rate.bits &= IR_9600; /* FIXME */
self->qos.min_turn_time.bits = 1; /* 10 ms or more */
--
1.6.3.3
^ permalink raw reply related
* Re: net-next: 2.6.34-rc1 regression: panic when running diagnostic on interface with IPv6
From: Stephen Hemminger @ 2010-04-06 4:39 UTC (permalink / raw)
To: emil.s.tantilov; +Cc: David Miller, netdev
In-Reply-To: <20100405.165317.89399272.davem@davemloft.net>
I can not reproduce this with current net-next and e1000e.
Please recheck that you are running the right code.
# ip addr show dev eth3
6: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:15:17:c3:a9:fb brd ff:ff:ff:ff:ff:ff
inet6 2001:db8:0:f101::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::215:17ff:fec3:a9fb/64 scope link
valid_lft forever preferred_lft forever
# ip addr show dev eth3
6: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:15:17:c3:a9:fb brd ff:ff:ff:ff:ff:ff
inet 192.168.1.12/24 brd 192.168.1.255 scope global eth3
inet6 2001:db8:0:f101::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::215:17ff:fec3:a9fb/64 scope link
valid_lft forever preferred_lft forever
# ethtool -t eth3
The test result is PASS
The test extra info:
Register test (offline) 0
Eeprom test (offline) 0
Interrupt test (offline) 0
Loopback test (offline) 0
Link test (on/offline) 0
No failures, no backtrace, nothing?
$ git log net/ipv6/addrconf.c
commit 4b97efdf392563bf03b4917a0b5add2df65de39a
Author: Patrick McHardy <kaber@trash.net>
Date: Fri Mar 26 20:27:49 2010 -0700
net: fix netlink address dumping in IPv4/IPv6
When a dump is interrupted at the last device in a hash chain and
then continued, "idx" won't get incremented past s_idx, so s_ip_idx
is not reset when moving on to the next device. This means of all
following devices only the last n - s_ip_idx addresses are dumped.
Tested-by: Pawel Staszewski <pstaszewski@itcare.pl>
Signed-off-by: Patrick McHardy <kaber@trash.net>
commit b79d1d54cf0672f764402fe4711ef5306f917bd3
Author: David S. Miller <davem@davemloft.net>
Date: Thu Mar 25 21:39:21 2010 -0700
ipv6: Fix result generation in ipv6_get_ifaddr().
Finishing naturally from hlist_for_each_entry(x, ...) does not result
in 'x' being NULL.
Signed-off-by: David S. Miller <davem@davemloft.net>
commit b54c9b98bbfb4836b1f7441c5a9db24affd3c2e9
Author: David S. Miller <davem@davemloft.net>
Date: Thu Mar 25 21:25:30 2010 -0700
ipv6: Preserve pervious behavior in ipv6_link_dev_addr().
Use list_add_tail() to get the behavior we had before
the list_head conversion for ipv6 address lists.
Signed-off-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* [PATCH] net/irda: Add SuperH IrDA driver support
From: Kuninori Morimoto @ 2010-04-06 4:46 UTC (permalink / raw)
To: netdev; +Cc: Samuel Ortiz, David S. Miller
This is very simple driver for SuperH Mobile IrDA
which support SIR/MIR/FIR.
This patch add only SIR support for now.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
drivers/net/irda/Kconfig | 6 +
drivers/net/irda/Makefile | 1 +
drivers/net/irda/sh_irda.c | 865 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 872 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/irda/sh_irda.c
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index af10e97..25bb2a0 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -397,5 +397,11 @@ config MCS_FIR
To compile it as a module, choose M here: the module will be called
mcs7780.
+config SH_IRDA
+ tristate "SuperH IrDA driver"
+ depends on IRDA && ARCH_SHMOBILE
+ help
+ Say Y here if your want to enable SuperH IrDA devices.
+
endmenu
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index e030d47..dfc6453 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_VIA_FIR) += via-ircc.o
obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o
obj-$(CONFIG_MCS_FIR) += mcs7780.o
obj-$(CONFIG_AU1000_FIR) += au1k_ir.o
+obj-$(CONFIG_SH_IRDA) += sh_irda.o
# SIR drivers
obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
obj-$(CONFIG_BFIN_SIR) += bfin_sir.o
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
new file mode 100644
index 0000000..9a828b0
--- /dev/null
+++ b/drivers/net/irda/sh_irda.c
@@ -0,0 +1,865 @@
+/*
+ * SuperH IrDA Driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on sh_sir.c
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Copyright 2006-2009 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * CAUTION
+ *
+ * This driver is very simple.
+ * So, it doesn't have below support now
+ * - MIR/FIR support
+ * - DMA transfer support
+ * - FIFO mode support
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#define DRIVER_NAME "sh_irda"
+
+#if defined(CONFIG_ARCH_SH7367) || defined(CONFIG_ARCH_SH7377)
+#define __IRDARAM_LEN 0x13FF
+#else
+#define __IRDARAM_LEN 0x1039
+#endif
+
+#define IRTMR 0x1F00 /* Transfer mode */
+#define IRCFR 0x1F02 /* Configuration */
+#define IRCTR 0x1F04 /* IR control */
+#define IRTFLR 0x1F20 /* Transmit frame length */
+#define IRTCTR 0x1F22 /* Transmit control */
+#define IRRFLR 0x1F40 /* Receive frame length */
+#define IRRCTR 0x1F42 /* Receive control */
+#define SIRISR 0x1F60 /* SIR-UART mode interrupt source */
+#define SIRIMR 0x1F62 /* SIR-UART mode interrupt mask */
+#define SIRICR 0x1F64 /* SIR-UART mode interrupt clear */
+#define SIRBCR 0x1F68 /* SIR-UART mode baud rate count */
+#define MFIRISR 0x1F70 /* MIR/FIR mode interrupt source */
+#define MFIRIMR 0x1F72 /* MIR/FIR mode interrupt mask */
+#define MFIRICR 0x1F74 /* MIR/FIR mode interrupt clear */
+#define CRCCTR 0x1F80 /* CRC engine control */
+#define CRCIR 0x1F86 /* CRC engine input data */
+#define CRCCR 0x1F8A /* CRC engine calculation */
+#define CRCOR 0x1F8E /* CRC engine output data */
+#define FIFOCP 0x1FC0 /* FIFO current pointer */
+#define FIFOFP 0x1FC2 /* FIFO follow pointer */
+#define FIFORSMSK 0x1FC4 /* FIFO receive status mask */
+#define FIFORSOR 0x1FC6 /* FIFO receive status OR */
+#define FIFOSEL 0x1FC8 /* FIFO select */
+#define FIFORS 0x1FCA /* FIFO receive status */
+#define FIFORFL 0x1FCC /* FIFO receive frame length */
+#define FIFORAMCP 0x1FCE /* FIFO RAM current pointer */
+#define FIFORAMFP 0x1FD0 /* FIFO RAM follow pointer */
+#define BIFCTL 0x1FD2 /* BUS interface control */
+#define IRDARAM 0x0000 /* IrDA buffer RAM */
+#define IRDARAM_LEN __IRDARAM_LEN /* - 8/16/32 (read-only for 32) */
+
+/* IRTMR */
+#define TMD_MASK (0x3 << 14) /* Transfer Mode */
+#define TMD_SIR (0x0 << 14)
+#define TMD_MIR (0x3 << 14)
+#define TMD_FIR (0x2 << 14)
+
+#define FIFORIM (1 << 8) /* FIFO receive interrupt mask */
+#define MIM (1 << 4) /* MIR/FIR Interrupt Mask */
+#define SIM (1 << 0) /* SIR Interrupt Mask */
+#define xIM_MASK (FIFORIM | MIM | SIM)
+
+/* IRCFR */
+#define RTO_SHIFT 8 /* shift for Receive Timeout */
+#define RTO (0x3 << RTO_SHIFT)
+
+/* IRTCTR */
+#define ARMOD (1 << 15) /* Auto-Receive Mode */
+#define TE (1 << 0) /* Transmit Enable */
+
+/* IRRFLR */
+#define RFL_MASK (0x1FFF) /* mask for Receive Frame Length */
+
+/* IRRCTR */
+#define RE (1 << 0) /* Receive Enable */
+
+/*
+ * SIRISR, SIRIMR, SIRICR,
+ * MFIRISR, MFIRIMR, MFIRICR
+ */
+#define FRE (1 << 15) /* Frame Receive End */
+#define TROV (1 << 11) /* Transfer Area Overflow */
+#define xIR_9 (1 << 9)
+#define TOT xIR_9 /* for SIR Timeout */
+#define ABTD xIR_9 /* for MIR/FIR Abort Detection */
+#define xIR_8 (1 << 8)
+#define FER xIR_8 /* for SIR Framing Error */
+#define CRCER xIR_8 /* for MIR/FIR CRC error */
+#define FTE (1 << 7) /* Frame Transmit End */
+#define xIR_MASK (FRE | TROV | xIR_9 | xIR_8 | FTE)
+
+/* SIRBCR */
+#define BRC_MASK (0x3F) /* mask for Baud Rate Count */
+
+/* CRCCTR */
+#define CRC_RST (1 << 15) /* CRC Engine Reset */
+#define CRC_CT_MASK 0x0FFF /* mask for CRC Engine Input Data Count */
+
+/* CRCIR */
+#define CRC_IN_MASK 0x0FFF /* mask for CRC Engine Input Data */
+
+/************************************************************************
+
+
+ enum / structure
+
+
+************************************************************************/
+enum sh_irda_mode {
+ SH_IRDA_NONE = 0,
+ SH_IRDA_SIR,
+ SH_IRDA_MIR,
+ SH_IRDA_FIR,
+};
+
+struct sh_irda_self;
+struct sh_irda_xir_func {
+ int (*xir_fre) (struct sh_irda_self *self);
+ int (*xir_trov) (struct sh_irda_self *self);
+ int (*xir_9) (struct sh_irda_self *self);
+ int (*xir_8) (struct sh_irda_self *self);
+ int (*xir_fte) (struct sh_irda_self *self);
+};
+
+struct sh_irda_self {
+ void __iomem *membase;
+ unsigned int irq;
+ struct clk *clk;
+
+ struct net_device *ndev;
+
+ struct irlap_cb *irlap;
+ struct qos_info qos;
+
+ iobuff_t tx_buff;
+ iobuff_t rx_buff;
+
+ enum sh_irda_mode mode;
+ spinlock_t lock;
+
+ struct sh_irda_xir_func *xir_func;
+};
+
+/************************************************************************
+
+
+ common function
+
+
+************************************************************************/
+static void sh_irda_write(struct sh_irda_self *self, u32 offset, u16 data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&self->lock, flags);
+ iowrite16(data, self->membase + offset);
+ spin_unlock_irqrestore(&self->lock, flags);
+}
+
+static u16 sh_irda_read(struct sh_irda_self *self, u32 offset)
+{
+ unsigned long flags;
+ u16 ret;
+
+ spin_lock_irqsave(&self->lock, flags);
+ ret = ioread16(self->membase + offset);
+ spin_unlock_irqrestore(&self->lock, flags);
+
+ return ret;
+}
+
+static void sh_irda_update_bits(struct sh_irda_self *self, u32 offset,
+ u16 mask, u16 data)
+{
+ unsigned long flags;
+ u16 old, new;
+
+ spin_lock_irqsave(&self->lock, flags);
+ old = ioread16(self->membase + offset);
+ new = (old & ~mask) | data;
+ if (old != new)
+ iowrite16(data, self->membase + offset);
+ spin_unlock_irqrestore(&self->lock, flags);
+}
+
+/************************************************************************
+
+
+ mode function
+
+
+************************************************************************/
+/*=====================================
+ *
+ * common
+ *
+ *=====================================*/
+static void sh_irda_rcv_ctrl(struct sh_irda_self *self, int enable)
+{
+ struct device *dev = &self->ndev->dev;
+
+ sh_irda_update_bits(self, IRRCTR, RE, enable ? RE : 0);
+ dev_dbg(dev, "recv %s\n", enable ? "enable" : "disable");
+}
+
+static int sh_irda_set_timeout(struct sh_irda_self *self, int interval)
+{
+ struct device *dev = &self->ndev->dev;
+
+ if (SH_IRDA_SIR != self->mode)
+ interval = 0;
+
+ if (interval < 0 || interval > 2) {
+ dev_err(dev, "unsupported timeout interval\n");
+ return -EINVAL;
+ }
+
+ sh_irda_update_bits(self, IRCFR, RTO, interval << RTO_SHIFT);
+ return 0;
+}
+
+static int sh_irda_set_baudrate(struct sh_irda_self *self, int baudrate)
+{
+ struct device *dev = &self->ndev->dev;
+ u16 val;
+
+ if (baudrate < 0)
+ return 0;
+
+ if (SH_IRDA_SIR != self->mode) {
+ dev_err(dev, "it is not SIR mode\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Baud rate (bits/s) =
+ * (48 MHz / 26) / (baud rate counter value + 1) x 16
+ */
+ val = (48000000 / 26 / 16 / baudrate) - 1;
+ dev_dbg(dev, "baudrate = %d, val = 0x%02x\n", baudrate, val);
+
+ sh_irda_update_bits(self, SIRBCR, BRC_MASK, val);
+
+ return 0;
+}
+
+static int xir_get_rcv_length(struct sh_irda_self *self)
+{
+ return RFL_MASK & sh_irda_read(self, IRRFLR);
+}
+
+/*=====================================
+ *
+ * NONE MODE
+ *
+ *=====================================*/
+static int xir_fre(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ dev_err(dev, "none mode: frame recv\n");
+ return 0;
+}
+
+static int xir_trov(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ dev_err(dev, "none mode: buffer ram over\n");
+ return 0;
+}
+
+static int xir_9(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ dev_err(dev, "none mode: time over\n");
+ return 0;
+}
+
+static int xir_8(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ dev_err(dev, "none mode: framing error\n");
+ return 0;
+}
+
+static int xir_fte(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ dev_err(dev, "none mode: frame transmit end\n");
+ return 0;
+}
+
+static struct sh_irda_xir_func xir_func = {
+ .xir_fre = xir_fre,
+ .xir_trov = xir_trov,
+ .xir_9 = xir_9,
+ .xir_8 = xir_8,
+ .xir_fte = xir_fte,
+};
+
+/*=====================================
+ *
+ * MIR/FIR MODE
+ *
+ * MIR/FIR are not supported now
+ *=====================================*/
+static struct sh_irda_xir_func mfir_func = {
+ .xir_fre = xir_fre,
+ .xir_trov = xir_trov,
+ .xir_9 = xir_9,
+ .xir_8 = xir_8,
+ .xir_fte = xir_fte,
+};
+
+/*=====================================
+ *
+ * SIR MODE
+ *
+ *=====================================*/
+static int sir_fre(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ u16 data16;
+ u8 *data = (u8 *)&data16;
+ int len = xir_get_rcv_length(self);
+ int i, j;
+
+ if (len > IRDARAM_LEN)
+ len = IRDARAM_LEN;
+
+ dev_dbg(dev, "frame recv length = %d\n", len);
+
+ for (i = 0; i < len; i++) {
+ j = i % 2;
+ if (!j)
+ data16 = sh_irda_read(self, IRDARAM + i);
+
+ async_unwrap_char(self->ndev, &self->ndev->stats,
+ &self->rx_buff, data[j]);
+ }
+ self->ndev->last_rx = jiffies;
+
+ sh_irda_rcv_ctrl(self, 1);
+
+ return 0;
+}
+
+static int sir_trov(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+
+ dev_err(dev, "buffer ram over\n");
+ sh_irda_rcv_ctrl(self, 1);
+ return 0;
+}
+
+static int sir_tot(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+
+ dev_err(dev, "time over\n");
+ sh_irda_set_baudrate(self, 9600);
+ sh_irda_rcv_ctrl(self, 1);
+ return 0;
+}
+
+static int sir_fer(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+
+ dev_err(dev, "framing error\n");
+ sh_irda_rcv_ctrl(self, 1);
+ return 0;
+}
+
+static int sir_fte(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+
+ dev_dbg(dev, "frame transmit end\n");
+ netif_wake_queue(self->ndev);
+
+ return 0;
+}
+
+static struct sh_irda_xir_func sir_func = {
+ .xir_fre = sir_fre,
+ .xir_trov = sir_trov,
+ .xir_9 = sir_tot,
+ .xir_8 = sir_fer,
+ .xir_fte = sir_fte,
+};
+
+static void sh_irda_set_mode(struct sh_irda_self *self, enum sh_irda_mode mode)
+{
+ struct device *dev = &self->ndev->dev;
+ struct sh_irda_xir_func *func;
+ const char *name;
+ u16 data;
+
+ switch (mode) {
+ case SH_IRDA_SIR:
+ name = "SIR";
+ data = TMD_SIR;
+ func = &sir_func;
+ break;
+ case SH_IRDA_MIR:
+ name = "MIR";
+ data = TMD_MIR;
+ func = &mfir_func;
+ break;
+ case SH_IRDA_FIR:
+ name = "FIR";
+ data = TMD_FIR;
+ func = &mfir_func;
+ break;
+ default:
+ name = "NONE";
+ data = 0;
+ func = &xir_func;
+ break;
+ }
+
+ self->mode = mode;
+ self->xir_func = func;
+ sh_irda_update_bits(self, IRTMR, TMD_MASK, data);
+
+ dev_dbg(dev, "switch to %s mode", name);
+}
+
+/************************************************************************
+
+
+ irq function
+
+
+************************************************************************/
+static void sh_irda_set_irq_mask(struct sh_irda_self *self)
+{
+ u16 tmr_hole;
+ u16 xir_reg;
+
+ /* set all mask */
+ sh_irda_update_bits(self, IRTMR, xIM_MASK, xIM_MASK);
+ sh_irda_update_bits(self, SIRIMR, xIR_MASK, xIR_MASK);
+ sh_irda_update_bits(self, MFIRIMR, xIR_MASK, xIR_MASK);
+
+ /* clear irq */
+ sh_irda_update_bits(self, SIRICR, xIR_MASK, xIR_MASK);
+ sh_irda_update_bits(self, MFIRICR, xIR_MASK, xIR_MASK);
+
+ switch (self->mode) {
+ case SH_IRDA_SIR:
+ tmr_hole = SIM;
+ xir_reg = SIRIMR;
+ break;
+ case SH_IRDA_MIR:
+ case SH_IRDA_FIR:
+ tmr_hole = MIM;
+ xir_reg = MFIRIMR;
+ break;
+ default:
+ tmr_hole = 0;
+ xir_reg = 0;
+ break;
+ }
+
+ /* open mask */
+ if (xir_reg) {
+ sh_irda_update_bits(self, IRTMR, tmr_hole, 0);
+ sh_irda_update_bits(self, xir_reg, xIR_MASK, 0);
+ }
+}
+
+static irqreturn_t sh_irda_irq(int irq, void *dev_id)
+{
+ struct sh_irda_self *self = dev_id;
+ struct sh_irda_xir_func *func = self->xir_func;
+ u16 isr = sh_irda_read(self, SIRISR);
+
+ /* clear irq */
+ sh_irda_write(self, SIRICR, isr);
+
+ if (isr & FRE)
+ func->xir_fre(self);
+ if (isr & TROV)
+ func->xir_trov(self);
+ if (isr & xIR_9)
+ func->xir_9(self);
+ if (isr & xIR_8)
+ func->xir_8(self);
+ if (isr & FTE)
+ func->xir_fte(self);
+
+ return IRQ_HANDLED;
+}
+
+/************************************************************************
+
+
+ CRC function
+
+
+************************************************************************/
+static void sh_irda_crc_reset(struct sh_irda_self *self)
+{
+ sh_irda_write(self, CRCCTR, CRC_RST);
+}
+
+static void sh_irda_crc_add(struct sh_irda_self *self, u16 data)
+{
+ sh_irda_write(self, CRCIR, data & CRC_IN_MASK);
+}
+
+static u16 sh_irda_crc_cnt(struct sh_irda_self *self)
+{
+ return CRC_CT_MASK & sh_irda_read(self, CRCCTR);
+}
+
+static u16 sh_irda_crc_out(struct sh_irda_self *self)
+{
+ return sh_irda_read(self, CRCOR);
+}
+
+static int sh_irda_crc_init(struct sh_irda_self *self)
+{
+ struct device *dev = &self->ndev->dev;
+ int ret = -EIO;
+ u16 val;
+
+ sh_irda_crc_reset(self);
+
+ sh_irda_crc_add(self, 0xCC);
+ sh_irda_crc_add(self, 0xF5);
+ sh_irda_crc_add(self, 0xF1);
+ sh_irda_crc_add(self, 0xA7);
+
+ val = sh_irda_crc_cnt(self);
+ if (4 != val) {
+ dev_err(dev, "CRC count error %x\n", val);
+ goto crc_init_out;
+ }
+
+ val = sh_irda_crc_out(self);
+ if (0x51DF != val) {
+ dev_err(dev, "CRC result error%x\n", val);
+ goto crc_init_out;
+ }
+
+ ret = 0;
+
+crc_init_out:
+
+ sh_irda_crc_reset(self);
+ return ret;
+}
+
+/************************************************************************
+
+
+ iobuf function
+
+
+************************************************************************/
+static void sh_irda_remove_iobuf(struct sh_irda_self *self)
+{
+ kfree(self->rx_buff.head);
+
+ self->tx_buff.head = NULL;
+ self->tx_buff.data = NULL;
+ self->rx_buff.head = NULL;
+ self->rx_buff.data = NULL;
+}
+
+static int sh_irda_init_iobuf(struct sh_irda_self *self, int rxsize, int txsize)
+{
+ if (self->rx_buff.head ||
+ self->tx_buff.head) {
+ dev_err(&self->ndev->dev, "iobuff has already existed.");
+ return -EINVAL;
+ }
+
+ /* rx_buff */
+ self->rx_buff.head = kmalloc(rxsize, GFP_KERNEL);
+ if (!self->rx_buff.head)
+ return -ENOMEM;
+
+ self->rx_buff.truesize = rxsize;
+ self->rx_buff.in_frame = FALSE;
+ self->rx_buff.state = OUTSIDE_FRAME;
+ self->rx_buff.data = self->rx_buff.head;
+
+ /* tx_buff */
+ self->tx_buff.head = self->membase + IRDARAM;
+ self->tx_buff.truesize = IRDARAM_LEN;
+
+ return 0;
+}
+
+/************************************************************************
+
+
+ net_device_ops function
+
+
+************************************************************************/
+static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct sh_irda_self *self = netdev_priv(ndev);
+ struct device *dev = &self->ndev->dev;
+ int speed = irda_get_next_speed(skb);
+ int ret;
+
+ dev_dbg(dev, "hard xmit\n");
+
+ netif_stop_queue(ndev);
+ sh_irda_rcv_ctrl(self, 0);
+
+ ret = sh_irda_set_baudrate(self, speed);
+ if (ret < 0)
+ return ret;
+
+ self->tx_buff.len = 0;
+ if (skb->len) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&self->lock, flags);
+ self->tx_buff.len = async_wrap_skb(skb,
+ self->tx_buff.head,
+ self->tx_buff.truesize);
+ spin_unlock_irqrestore(&self->lock, flags);
+
+ if (self->tx_buff.len > self->tx_buff.truesize)
+ self->tx_buff.len = self->tx_buff.truesize;
+
+ sh_irda_write(self, IRTFLR, self->tx_buff.len);
+ sh_irda_write(self, IRTCTR, ARMOD | TE);
+ }
+
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static int sh_irda_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
+{
+ /*
+ * FIXME
+ *
+ * This function is needed for irda framework.
+ * But nothing to do now
+ */
+ return 0;
+}
+
+static struct net_device_stats *sh_irda_stats(struct net_device *ndev)
+{
+ struct sh_irda_self *self = netdev_priv(ndev);
+
+ return &self->ndev->stats;
+}
+
+static int sh_irda_open(struct net_device *ndev)
+{
+ struct sh_irda_self *self = netdev_priv(ndev);
+ int err;
+
+ clk_enable(self->clk);
+ err = sh_irda_crc_init(self);
+ if (err)
+ goto open_err;
+
+ sh_irda_set_mode(self, SH_IRDA_SIR);
+ sh_irda_set_timeout(self, 2);
+ sh_irda_set_baudrate(self, 9600);
+
+ self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
+ if (!self->irlap) {
+ err = -ENODEV;
+ goto open_err;
+ }
+
+ netif_start_queue(ndev);
+ sh_irda_rcv_ctrl(self, 1);
+ sh_irda_set_irq_mask(self);
+
+ dev_info(&ndev->dev, "opened\n");
+
+ return 0;
+
+open_err:
+ clk_disable(self->clk);
+
+ return err;
+}
+
+static int sh_irda_stop(struct net_device *ndev)
+{
+ struct sh_irda_self *self = netdev_priv(ndev);
+
+ /* Stop IrLAP */
+ if (self->irlap) {
+ irlap_close(self->irlap);
+ self->irlap = NULL;
+ }
+
+ netif_stop_queue(ndev);
+
+ dev_info(&ndev->dev, "stoped\n");
+
+ return 0;
+}
+
+static const struct net_device_ops sh_irda_ndo = {
+ .ndo_open = sh_irda_open,
+ .ndo_stop = sh_irda_stop,
+ .ndo_start_xmit = sh_irda_hard_xmit,
+ .ndo_do_ioctl = sh_irda_ioctl,
+ .ndo_get_stats = sh_irda_stats,
+};
+
+/************************************************************************
+
+
+ platform_driver function
+
+
+************************************************************************/
+static int __devinit sh_irda_probe(struct platform_device *pdev)
+{
+ struct net_device *ndev;
+ struct sh_irda_self *self;
+ struct resource *res;
+ char clk_name[8];
+ unsigned int irq;
+ int err = -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || irq < 0) {
+ dev_err(&pdev->dev, "Not enough platform resources.\n");
+ goto exit;
+ }
+
+ ndev = alloc_irdadev(sizeof(*self));
+ if (!ndev)
+ goto exit;
+
+ self = netdev_priv(ndev);
+ self->membase = ioremap_nocache(res->start, resource_size(res));
+ if (!self->membase) {
+ err = -ENXIO;
+ dev_err(&pdev->dev, "Unable to ioremap.\n");
+ goto err_mem_1;
+ }
+
+ err = sh_irda_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
+ if (err)
+ goto err_mem_2;
+
+ snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id);
+ self->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(self->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ goto err_mem_3;
+ }
+
+ irda_init_max_qos_capabilies(&self->qos);
+
+ ndev->netdev_ops = &sh_irda_ndo;
+ ndev->irq = irq;
+
+ self->ndev = ndev;
+ self->qos.baud_rate.bits &= IR_9600; /* FIXME */
+ self->qos.min_turn_time.bits = 1; /* 10 ms or more */
+ spin_lock_init(&self->lock);
+
+ irda_qos_bits_to_value(&self->qos);
+
+ err = register_netdev(ndev);
+ if (err)
+ goto err_mem_4;
+
+ platform_set_drvdata(pdev, ndev);
+
+ if (request_irq(irq, sh_irda_irq, IRQF_DISABLED, "sh_irda", self)) {
+ dev_warn(&pdev->dev, "Unable to attach sh_irda interrupt\n");
+ goto err_mem_4;
+ }
+
+ dev_info(&pdev->dev, "SuperH IrDA probed\n");
+
+ goto exit;
+
+err_mem_4:
+ clk_put(self->clk);
+err_mem_3:
+ sh_irda_remove_iobuf(self);
+err_mem_2:
+ iounmap(self->membase);
+err_mem_1:
+ free_netdev(ndev);
+exit:
+ return err;
+}
+
+static int __devexit sh_irda_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct sh_irda_self *self = netdev_priv(ndev);
+
+ if (!self)
+ return 0;
+
+ unregister_netdev(ndev);
+ clk_put(self->clk);
+ sh_irda_remove_iobuf(self);
+ iounmap(self->membase);
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver sh_irda_driver = {
+ .probe = sh_irda_probe,
+ .remove = __devexit_p(sh_irda_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init sh_irda_init(void)
+{
+ return platform_driver_register(&sh_irda_driver);
+}
+
+static void __exit sh_irda_exit(void)
+{
+ platform_driver_unregister(&sh_irda_driver);
+}
+
+module_init(sh_irda_init);
+module_exit(sh_irda_exit);
+
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_DESCRIPTION("SuperH IrDA driver");
+MODULE_LICENSE("GPL");
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH 1/2] TIPC: Updated topology subscriptionprotocol according to latest spec
From: Suryanarayana.Garlapati @ 2010-04-06 5:11 UTC (permalink / raw)
To: jon.maloy, davem; +Cc: netdev, tipc-discussion, Jon
In-Reply-To: <1270516572-27789-1-git-send-email-jon.maloy@ericsson.com>
Hi Jon,
Is this patch portable to versions TIPC 1.7.x?
Regards
Surya
> -----Original Message-----
> From: Jon Maloy [mailto:jon.maloy@ericsson.com]
> Sent: Tuesday, April 06, 2010 6:46 AM
> To: David Miller
> Cc: Maloy; netdev@vger.kernel.org;
> tipc-discussion@lists.sourceforge.net; Jon
> Subject: [tipc-discussion] [PATCH 1/2] TIPC: Updated topology
> subscriptionprotocol according to latest spec
>
> ---
> include/linux/tipc.h | 30 ++++++++++++------------------
> net/tipc/core.c | 2 +-
> net/tipc/subscr.c | 15 ++++++++++-----
> 3 files changed, 23 insertions(+), 24 deletions(-)
>
> diff --git a/include/linux/tipc.h b/include/linux/tipc.h
> index 3d92396..9536d8a 100644
> --- a/include/linux/tipc.h
> +++ b/include/linux/tipc.h
> @@ -127,23 +127,17 @@ static inline unsigned int tipc_node(__u32 addr)
> * TIPC topology subscription service definitions
> */
>
> -#define TIPC_SUB_PORTS 0x01 /* filter for port
> availability */
> -#define TIPC_SUB_SERVICE 0x02 /* filter for
> service availability */
> -#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
> -#if 0
> -/* The following filter options are not currently implemented */
> -#define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out
> "publish" events */
> -#define TIPC_SUB_NO_UNBIND_EVTS 0x08 /* filter out
> "withdraw" events */
> -#define TIPC_SUB_SINGLE_EVT 0x10 /* expire after first event */
> -#endif
> +#define TIPC_SUB_SERVICE 0x00 /* Filter for
> service availability */
> +#define TIPC_SUB_PORTS 0x01 /* Filter for port
> availability */
> +#define TIPC_SUB_CANCEL 0x04 /* Cancel a
> subscription */
>
> #define TIPC_WAIT_FOREVER ~0 /* timeout for
> permanent subscription */
>
> struct tipc_subscr {
> - struct tipc_name_seq seq; /* name sequence of interest */
> - __u32 timeout; /* subscription
> duration (in ms) */
> - __u32 filter; /* bitmask of filter options */
> - char usr_handle[8]; /* available for
> subscriber use */
> + struct tipc_name_seq seq; /* NBO. Name sequence
> of interest */
> + __u32 timeout; /* NBO. Subscription
> duration (in ms) */
> + __u32 filter; /* NBO. Bitmask of
> filter options */
> + char usr_handle[8]; /* Opaque. Available
> for subscriber use */
> };
>
> #define TIPC_PUBLISHED 1 /* publication event */
> @@ -151,11 +145,11 @@ struct tipc_subscr {
> #define TIPC_SUBSCR_TIMEOUT 3 /* subscription timeout event */
>
> struct tipc_event {
> - __u32 event; /* event type */
> - __u32 found_lower; /* matching name seq
> instances */
> - __u32 found_upper; /* " " "
> " */
> - struct tipc_portid port; /* associated port */
> - struct tipc_subscr s; /* associated subscription */
> + __u32 event; /* NBO. Event type, as
> defined above */
> + __u32 found_lower; /* NBO. Matching name
> seq instances */
> + __u32 found_upper; /* " " "
> " " */
> + struct tipc_portid port; /* NBO. Associated port
> */
> + struct tipc_subscr s; /* Original, associated
> subscription */
> };
>
> /*
> diff --git a/net/tipc/core.c b/net/tipc/core.c index
> 52c571f..4e84c84 100644
> --- a/net/tipc/core.c
> +++ b/net/tipc/core.c
> @@ -49,7 +49,7 @@
> #include "config.h"
>
>
> -#define TIPC_MOD_VER "1.6.4"
> +#define TIPC_MOD_VER "2.0.0"
>
> #ifndef CONFIG_TIPC_ZONES
> #define CONFIG_TIPC_ZONES 3
> diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index
> ff123e5..ab6eab4 100644
> --- a/net/tipc/subscr.c
> +++ b/net/tipc/subscr.c
> @@ -274,7 +274,7 @@ static void subscr_cancel(struct
> tipc_subscr *s, {
> struct subscription *sub;
> struct subscription *sub_temp;
> - __u32 type, lower, upper;
> + __u32 type, lower, upper, timeout, filter;
> int found = 0;
>
> /* Find first matching subscription, exit if not found
> */ @@ -282,12 +282,18 @@ static void subscr_cancel(struct
> tipc_subscr *s,
> type = ntohl(s->seq.type);
> lower = ntohl(s->seq.lower);
> upper = ntohl(s->seq.upper);
> + timeout = ntohl(s->timeout);
> + filter = ntohl(s->filter) & ~TIPC_SUB_CANCEL;
>
> list_for_each_entry_safe(sub, sub_temp,
> &subscriber->subscription_list,
> subscription_list) {
> if ((type == sub->seq.type) &&
> (lower == sub->seq.lower) &&
> - (upper == sub->seq.upper)) {
> + (upper == sub->seq.upper) &&
> + (timeout == sub->timeout) &&
> + (filter == sub->filter) &&
> +
> !memcmp(s->usr_handle,sub->evt.s.usr_handle,
> + sizeof(s->usr_handle)) ){
> found = 1;
> break;
> }
> @@ -304,7 +310,7 @@ static void subscr_cancel(struct tipc_subscr *s,
> k_term_timer(&sub->timer);
> spin_lock_bh(subscriber->lock);
> }
> - dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
> + dbg("Cancel: removing sub %u,%u,%u from subscriber %p list\n",
> sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
> subscr_del(sub);
> }
> @@ -352,8 +358,7 @@ static struct subscription
> *subscr_subscribe(struct tipc_subscr *s,
> sub->seq.upper = ntohl(s->seq.upper);
> sub->timeout = ntohl(s->timeout);
> sub->filter = ntohl(s->filter);
> - if ((!(sub->filter & TIPC_SUB_PORTS) ==
> - !(sub->filter & TIPC_SUB_SERVICE)) ||
> + if ((sub->filter && (sub->filter != TIPC_SUB_PORTS)) ||
> (sub->seq.lower > sub->seq.upper)) {
> warn("Subscription rejected, illegal request\n");
> kfree(sub);
> --
> 1.5.4.3
>
>
> --------------------------------------------------------------
> ----------------
> Download Intel® Parallel Studio Eval
> Try the new software tools for yourself. Speed compiling, find bugs
> proactively, and fine-tune applications for parallel performance.
> See why Intel Parallel Studio got high marks during beta.
> http://p.sf.net/sfu/intel-sw-dev
> _______________________________________________
> tipc-discussion mailing list
> tipc-discussion@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/tipc-discussion
>
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
^ permalink raw reply
* Re: [RFC PATCH 2/2] netdev: an usage example on igb
From: Koki Sanagi @ 2010-04-06 5:40 UTC (permalink / raw)
To: Eric Dumazet
Cc: netdev, izumi.taku, kaneshige.kenji, davem, nhorman,
jeffrey.t.kirsher, jesse.brandeburg, bruce.w.allan,
alexander.h.duyck, peter.p.waskiewicz.jr, john.ronciak
In-Reply-To: <1270456224.1971.15.camel@edumazet-laptop>
(2010/04/05 17:30), Eric Dumazet wrote:
> Le lundi 05 avril 2010 à 15:54 +0900, Koki Sanagi a écrit :
>> This patch is usage example of previous patch's buffer on igb.
>> The output is like below.
>>
>> # cat /sys/kernel/debug/ndrvbuf/igb-trace-0000\:03\:00.0/buffer
>> [ 1] 50462.369207: clean_tx qidx=1 ntu=154->156
>> [ 0] 50462.369241: clean_rx qidx=0 ntu=111->112
>> [ 0] 50462.369250: xmit qidx=1 ntu=156->158
>> [ 1] 50462.369256: clean_tx qidx=1 ntu=156->158
>> [ 1] 50462.369342: clean_rx qidx=0 ntu=113->114
>> [ 1] 50462.369439: clean_rx qidx=0 ntu=114->115
>>
>> This example outputs original print style, because it sets original print
>> function(igb_trace_read) when registered.
>>
>> register_ndrvbuf(buname, 1000000, igb_trace_read);
>>
>> If you set NULL to arg3, outputs by ndrvbuf default style.
>> If you set 0 to size(arg2), recording is disabled at first(but small buffer is
>> alloced).
>> When you set non-zero to size, recording becomes enabled.
>>
>> Signed-off-by: Koki Sanagi<sanagi.koki@jp.fujitsu.com>
>> ---
>> drivers/net/igb/Makefile | 2 +-
>> drivers/net/igb/igb.h | 1 +
>> drivers/net/igb/igb_main.c | 10 +++++-
>> drivers/net/igb/igb_trace.c | 81 +++++++++++++++++++++++++++++++++++++++++++
>> drivers/net/igb/igb_trace.h | 21 +++++++++++
>> 5 files changed, 113 insertions(+), 2 deletions(-)
>>
>
> This depends on NDRVBUF, yet I see no Kconfig change in this patch.
>
This igb can exist without ndrvbuf.
If ndrvbuf modules is not loaded, igb operates originally.
So this doesn't depend on ndrvbuf.
^ permalink raw reply
* RE: [PATCH 1/3] A device for zero-copy based on KVM virtio-net.
From: Xin, Xiaohui @ 2010-04-06 5:41 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: netdev@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, mingo@elte.hu,
jdike@c2.user-mode-linux.org, yzhao81@gmail.com
In-Reply-To: <20100401110841.GE3323@redhat.com>
Michael,
>>
>>For the DOS issue, I'm not sure how much the limit get_user_pages()
>> can pin is reasonable, should we compute the bindwidth to make it?
>There's a ulimit for locked memory. Can we use this, decreasing
>the value for rlimit array? We can do this when backend is
>enabled and re-increment when backend is disabled.
I have tried it with rlim[RLIMIT_MEMLOCK].rlim_cur, but I found
the initial value for it is 0x10000, after right shift PAGE_SHIFT,
it's only 16 pages we can lock then, it seems too small, since the
guest virito-net driver may submit a lot requests one time.
Thanks
Xiaohui
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox