Netdev List
 help / color / mirror / Atom feed
* Re: linux-next: manual merge of the net tree with the net-current tree
From: Herbert Xu @ 2010-06-23  4:14 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: David Miller, netdev, linux-next, linux-kernel, Changli Gao,
	Eric Dumazet
In-Reply-To: <20100623125116.1370bdd4.sfr@canb.auug.org.au>

On Wed, Jun 23, 2010 at 12:51:16PM +1000, Stephen Rothwell wrote:
> Hi all,
> 
> Today's linux-next merge of the net tree got a conflict in
> net/ipv4/ip_output.c between commit
> 26cde9f7e2747b6d254b704594eed87ab959afa5 ("udp: Fix bogus UFO packet
> generation") from the net-current tree and commit
> d8d1f30b95a635dbd610dcc5eb641aca8f4768cf ("net-next: remove useless union
> keyword") from the net tree.
> 
> Just context changes. I fixed it up (see below) and can carry the fix as
> necessary.

Looks good to me.

Thanks,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* linux-next: manual merge of the wireless tree with the net tree
From: Stephen Rothwell @ 2010-06-23  2:51 UTC (permalink / raw)
  To: John W. Linville
  Cc: linux-next, linux-kernel, Eric Dumazet, David Miller, netdev,
	Kiran Divekar, Amitkumar Karwar

Hi John,

Today's linux-next merge of the wireless tree got a conflict in
drivers/net/wireless/libertas/host.h between commit
ba2d3587912f82d1ab4367975b1df460db60fb1e ("drivers/net: use __packed
annotation") from the net tree and commit
c2af450168af531b70564e3ceb20983199a66216 ("Libertas: Added 11d support
using cfg80211") from the wireless tree.

Just a white space change clashing with a real change!  I fixed it up
(and changed some newly added "__attribute__ ((packed))" to "__packed" as
well ...) (see below) and can carry the fix as necessary.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --cc drivers/net/wireless/libertas/host.h
index 3bd5d3b,112fbf1..0000000
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@@ -387,8 -387,32 +387,32 @@@ struct enc_key 
  struct lbs_offset_value {
  	u32 offset;
  	u32 value;
 -} __attribute__ ((packed));
 +} __packed;
  
+ #define MRVDRV_MAX_TRIPLET_802_11D              83
+ 
+ #define COUNTRY_CODE_LEN                        3
+ 
+ struct mrvl_ie_domain_param_set {
+ 	struct mrvl_ie_header header;
+ 
+ 	u8 countrycode[COUNTRY_CODE_LEN];
+ 	struct ieee80211_country_ie_triplet triplet[1];
 -} __attribute__ ((packed));
++} __packed;
+ 
+ struct cmd_ds_802_11d_domain_info {
+ 	__le16 action;
+ 	struct mrvl_ie_domain_param_set domain;
 -} __attribute__ ((packed));
++} __packed;
+ 
+ struct lbs_802_11d_domain_reg {
+ 	/** Country code*/
+ 	u8 country_code[COUNTRY_CODE_LEN];
+ 	/** No. of triplet*/
+ 	u8 no_triplet;
+ 	struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D];
 -} __attribute__ ((packed));
++} __packed;
+ 
  /*
   * Define data structure for CMD_GET_HW_SPEC
   * This structure defines the response for the GET_HW_SPEC command

^ permalink raw reply

* linux-next: manual merge of the net tree with the net-current tree
From: Stephen Rothwell @ 2010-06-23  2:51 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: linux-next, linux-kernel, Herbert Xu, Changli Gao, Eric Dumazet

Hi all,

Today's linux-next merge of the net tree got a conflict in
net/ipv4/ip_output.c between commit
26cde9f7e2747b6d254b704594eed87ab959afa5 ("udp: Fix bogus UFO packet
generation") from the net-current tree and commit
d8d1f30b95a635dbd610dcc5eb641aca8f4768cf ("net-next: remove useless union
keyword") from the net tree.

Just context changes. I fixed it up (see below) and can carry the fix as
necessary.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --cc net/ipv4/ip_output.c
index 041d41d,6cbeb2e..0000000
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@@ -873,12 -873,10 +873,12 @@@ int ip_append_data(struct sock *sk
  	    !exthdrlen)
  		csummode = CHECKSUM_PARTIAL;
  
 +	skb = skb_peek_tail(&sk->sk_write_queue);
 +
  	inet->cork.length += length;
 -	if (((length> mtu) || !skb_queue_empty(&sk->sk_write_queue)) &&
 +	if (((length > mtu) || (skb && skb_is_gso(skb))) &&
  	    (sk->sk_protocol == IPPROTO_UDP) &&
- 	    (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ 	    (rt->dst.dev->features & NETIF_F_UFO)) {
  		err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
  					 fragheaderlen, transhdrlen, mtu,
  					 flags);
@@@ -1123,9 -1121,8 +1123,9 @@@ ssize_t	ip_append_page(struct sock *sk
  		return -EINVAL;
  
  	inet->cork.length += size;
 -	if ((sk->sk_protocol == IPPROTO_UDP) &&
 +	if ((size + skb->len > mtu) &&
 +	    (sk->sk_protocol == IPPROTO_UDP) &&
- 	    (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ 	    (rt->dst.dev->features & NETIF_F_UFO)) {
  		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
  		skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
  	}

^ permalink raw reply

* Re: bnx2 fails to compile on parisc because of missing get_dma_ops()
From: FUJITA Tomonori @ 2010-06-23  0:38 UTC (permalink / raw)
  To: James.Bottomley
  Cc: fujita.tomonori, lethal, davem, mchan, vapier, netdev,
	linux-parisc, linux-kernel
In-Reply-To: <1277227564.9374.7.camel@mulgrave.site>

On Tue, 22 Jun 2010 12:26:04 -0500
James Bottomley <James.Bottomley@HansenPartnership.com> wrote:

> > As I wrote, there is only one user of this API and we can remove it
> > easily. Then I'm not sure it's worth fixing dma_is_consistent() in
> > many architectures. I prefer to add this to
> > feature-removal-schedule.txt to see if driver writers oppose.
> 
> Let me check our two drivers: lasi and 53c700; they're the only ones we
> support on the architecture that can't do any coherence.  I think we
> don't need to tell because the dma_sync_cache calls which replace
> coherent memory handling are indirected on the platform so we don't need
> a global dma_is_coherent() flag.

There is only one place where 53c700 uses dma_is_consistent() (lasi
doesn't use it):

	BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment());

I think that we can remove the above checking since the existing
parisc systems that can't allocate coherent memory pass this checking.

53c700 and lasi call dma_cache_sync() unconditionally so we can live
without dma_is_consistent().

^ permalink raw reply

* iproute addr flush question
From: Ben Greear @ 2010-06-22 22:46 UTC (permalink / raw)
  To: NetDev

Is this supposed to work?  I was hoping there was some way to
flush all secondary IPs with a single command:

[root@atom lanforge]# ./local/sbin/ip addr flush dev eth5 secondary
[root@atom lanforge]#  ip addr show dev eth5
8: eth5: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
     link/ether 00:90:0b:13:f4:e9 brd ff:ff:ff:ff:ff:ff
     inet 6.6.6.1/24 brd 6.6.6.255 scope global eth5
     inet 6.6.6.2/24 scope global secondary eth5
     inet 6.6.6.3/24 scope global secondary eth5

This is .34 kernel and .34 matching iproute.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* [PATCH net-next-2.6] loopback: use u64_stats_sync infrastructure
From: Eric Dumazet @ 2010-06-22 22:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Commit 6b10de38f0ef (loopback: Implement 64bit stats on 32bit arches)
introduced 64bit stats in loopback driver, using a private seqcount and
private helpers.

David suggested to introduce a generic infrastructure, added in (net:
Introduce u64_stats_sync infrastructure)

This patch reimplements loopback 64bit stats using the u64_stats_sync
infrastructure.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 drivers/net/loopback.c |   62 ++++++++++-----------------------------
 1 file changed, 16 insertions(+), 46 deletions(-)

diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 09334f8..4dd0510 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -58,53 +58,15 @@
 #include <linux/tcp.h>
 #include <linux/percpu.h>
 #include <net/net_namespace.h>
+#include <linux/u64_stats_sync.h>
 
 struct pcpu_lstats {
-	u64 packets;
-	u64 bytes;
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
-	seqcount_t seq;
-#endif
-	unsigned long drops;
+	u64			packets;
+	u64			bytes;
+	struct u64_stats_sync	syncp;
+	unsigned long		drops;
 };
 
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
-static void inline lstats_update_begin(struct pcpu_lstats *lstats)
-{
-	write_seqcount_begin(&lstats->seq);
-}
-static void inline lstats_update_end(struct pcpu_lstats *lstats)
-{
-	write_seqcount_end(&lstats->seq);
-}
-static void inline lstats_fetch_and_add(u64 *packets, u64 *bytes, const struct pcpu_lstats *lstats)
-{
-	u64 tpackets, tbytes;
-	unsigned int seq;
-
-	do {
-		seq = read_seqcount_begin(&lstats->seq);
-		tpackets = lstats->packets;
-		tbytes = lstats->bytes;
-	} while (read_seqcount_retry(&lstats->seq, seq));
-
-	*packets += tpackets;
-	*bytes += tbytes;
-}
-#else
-static void inline lstats_update_begin(struct pcpu_lstats *lstats)
-{
-}
-static void inline lstats_update_end(struct pcpu_lstats *lstats)
-{
-}
-static void inline lstats_fetch_and_add(u64 *packets, u64 *bytes, const struct pcpu_lstats *lstats)
-{
-	*packets += lstats->packets;
-	*bytes += lstats->bytes;
-}
-#endif
-
 /*
  * The higher levels take care of making this non-reentrant (it's
  * called with bh's disabled).
@@ -126,10 +88,10 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 
 	len = skb->len;
 	if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
-		lstats_update_begin(lb_stats);
+		u64_stats_update_begin(&lb_stats->syncp);
 		lb_stats->bytes += len;
 		lb_stats->packets++;
-		lstats_update_end(lb_stats);
+		u64_stats_update_end(&lb_stats->syncp);
 	} else
 		lb_stats->drops++;
 
@@ -148,10 +110,18 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev)
 	pcpu_lstats = (void __percpu __force *)dev->ml_priv;
 	for_each_possible_cpu(i) {
 		const struct pcpu_lstats *lb_stats;
+		u64 tbytes, tpackets;
+		unsigned int start;
 
 		lb_stats = per_cpu_ptr(pcpu_lstats, i);
-		lstats_fetch_and_add(&packets, &bytes, lb_stats);
+		do {
+			start = u64_stats_fetch_begin(&lb_stats->syncp);
+			tbytes = lb_stats->bytes;
+			tpackets = lb_stats->packets;
+		} while (u64_stats_fetch_retry(&lb_stats->syncp, start));
 		drops   += lb_stats->drops;
+		bytes   += tbytes;
+		packets += tpackets;
 	}
 	stats->rx_packets = packets;
 	stats->tx_packets = packets;



^ permalink raw reply related

* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: Andrew Morton @ 2010-06-22 22:25 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <1277244162.2591.198.camel@edumazet-laptop>

On Wed, 23 Jun 2010 00:02:42 +0200
Eric Dumazet <eric.dumazet@gmail.com> wrote:

> ss is kind of "netstat" with advanced features.

Someone call the namespace police!

> Well, they are faster and more predictable ways to reboot a machine, if
> you ask me :)
> 
> man rmmod
> 
>        -f --force

doh, I missed that.  Yes, that was a bit self-inflicted.


^ permalink raw reply

* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: Eric Dumazet @ 2010-06-22 22:02 UTC (permalink / raw)
  To: Andrew Morton; +Cc: netdev, bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <20100622141232.4b8f1d4a.akpm@linux-foundation.org>

Le mardi 22 juin 2010 à 14:12 -0700, Andrew Morton a écrit :
> (switched to email.  Please respond via emailed reply-to-all, not via the
> bugzilla web interface).
> 
> On Tue, 22 Jun 2010 00:43:37 GMT
> bugzilla-daemon@bugzilla.kernel.org wrote:
> 
> > https://bugzilla.kernel.org/show_bug.cgi?id=16268
> > 
> >            Summary: kernel oops when rmmod the tcp_diag modules
> >            Product: Networking
> >            Version: 2.5
> >     Kernel Version: 2.6.35-rc3
> >           Platform: All
> >         OS/Version: Linux
> >               Tree: Mainline
> >             Status: NEW
> >           Severity: high
> >           Priority: P1
> >          Component: IPV4
> >         AssignedTo: shemminger@linux-foundation.org
> >         ReportedBy: lyw@cn.fujitsu.com
> >         Regression: No
> > 
> > 
> > I found a crash problem use following scripts and steps
> > 
> > #cat run_ss.sh
> >  while [ 1 ]
> >  do
> >      ss -a
> >  done
> > 
> > #cat rmmod.sh
> >  while [ 1 ]
> >  do 
> >      rmmod -f tcp_diag >/dev/null 2>&1
> >      rmmod -f inet_diag >/dev/null 2>&1
> >  done
> > 
> > step1:
> >   # sh run_sh.sh
> > step2:
> >   # sh rmmod.sh
> 
> I assume the rmmod script runs in pararallel with run_ss.sh.
> 
> What is "ss"?  Something which triggers a load of kernel modules,
> presumably.  Which ones?
> 

ss is kind of "netstat" with advanced features.

It loads inet_diag & tcp_diag modules.

> > After step2, the kernel oopsed.
> 
> yeah, that was a pretty nasty test ;)

Well, they are faster and more predictable ways to reboot a machine, if
you ask me :)

man rmmod

       -f --force
              This  option can be extremely dangerous: it has no effect unless
              CONFIG_MODULE_FORCE_UNLOAD was set when the kernel was compiled.
              With  this  option, you can remove modules which are being used,
              or which are not designed to be removed, or have been marked  as
              unsafe (see lsmod(8)).


I guess Linux is supposed to respect admin choice to live in a dangerous world.



^ permalink raw reply

* [PATCH v3] caif-driver: Add CAIF-SPI Protocol driver.
From: sjur.brandeland @ 2010-06-22 21:53 UTC (permalink / raw)
  To: davem
  Cc: sjurbr, netdev, marcel, daniel.martensson, linus.walleij,
	Sjur Braendeland

From: Sjur Braendeland <sjur.brandeland@stericsson.com>

This patch introduces the CAIF SPI Protocol Driver for
CAIF Link Layer.

This driver implements a platform driver to accommodate for a
platform specific SPI device. A general platform driver is not
possible as there are no SPI Slave side Kernel API defined.
A sample CAIF SPI Platform device can be found in
.../Documentation/networking/caif/spi_porting.txt

Signed-off-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
---
== RECENT CHANGES:
o Removed CONFIG_* defines from Makefile.
o Changed uint8_t to u8 et. al.
o Using netif_rx_ni instead of netif_rx from workqueue.

 Documentation/networking/caif/spi_porting.txt |  208 ++++++
 drivers/net/caif/Kconfig                      |   20 +
 drivers/net/caif/Makefile                     |    4 +
 drivers/net/caif/caif_spi.c                   |  847 +++++++++++++++++++++++++
 drivers/net/caif/caif_spi_slave.c             |  252 ++++++++
 include/net/caif/caif_spi.h                   |  153 +++++
 6 files changed, 1484 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/networking/caif/spi_porting.txt
 create mode 100644 drivers/net/caif/caif_spi.c
 create mode 100644 drivers/net/caif/caif_spi_slave.c
 create mode 100644 include/net/caif/caif_spi.h

diff --git a/Documentation/networking/caif/spi_porting.txt b/Documentation/networking/caif/spi_porting.txt
new file mode 100644
index 0000000..61d7c92
--- /dev/null
+++ b/Documentation/networking/caif/spi_porting.txt
@@ -0,0 +1,208 @@
+- CAIF SPI porting -
+
+- CAIF SPI basics:
+
+Running CAIF over SPI needs some extra setup, owing to the nature of SPI.
+Two extra GPIOs have been added in order to negotiate the transfers
+ between the master and the slave. The minimum requirement for running
+CAIF over SPI is a SPI slave chip and two GPIOs (more details below).
+Please note that running as a slave implies that you need to keep up
+with the master clock. An overrun or underrun event is fatal.
+
+- CAIF SPI framework:
+
+To make porting as easy as possible, the CAIF SPI has been divided in
+two parts. The first part (called the interface part) deals with all
+generic functionality such as length framing, SPI frame negotiation
+and SPI frame delivery and transmission. The other part is the CAIF
+SPI slave device part, which is the module that you have to write if
+you want to run SPI CAIF on a new hardware. This part takes care of
+the physical hardware, both with regard to SPI and to GPIOs.
+
+- Implementing a CAIF SPI device:
+
+	- Functionality provided by the CAIF SPI slave device:
+
+	In order to implement a SPI device you will, as a minimum,
+	need to implement the following
+	functions:
+
+	int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev):
+
+	This function is called by the CAIF SPI interface to give
+	you a chance to set up your hardware to be ready to receive
+	a stream of data from the master. The xfer structure contains
+	both physical and logical adresses, as well as the total length
+	of the transfer in both directions.The dev parameter can be used
+	to map to different CAIF SPI slave devices.
+
+	void (*sig_xfer) (bool xfer, struct cfspi_dev *dev):
+
+	This function is called by the CAIF SPI interface when the output
+	(SPI_INT) GPIO needs to change state. The boolean value of the xfer
+	variable indicates whether the GPIO should be asserted (HIGH) or
+	deasserted (LOW). The dev parameter can be used to map to different CAIF
+	SPI slave devices.
+
+	- Functionality provided by the CAIF SPI interface:
+
+	void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+
+	This function is called by the CAIF SPI slave device in order to
+	signal a change of state of the input GPIO (SS) to the interface.
+	Only active edges are mandatory to be reported.
+	This function can be called from IRQ context (recommended in order
+	not to introduce latency). The ifc parameter should be the pointer
+	returned from the platform probe function in the SPI device structure.
+
+	void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+
+	This function is called by the CAIF SPI slave device in order to
+	report that a transfer is completed. This function should only be
+	called once both the transmission and the reception are completed.
+	This function can be called from IRQ context (recommended in order
+	not to introduce latency). The ifc parameter should be the pointer
+	returned from the platform probe function in the SPI device structure.
+
+	- Connecting the bits and pieces:
+
+		- Filling in the SPI slave device structure:
+
+		Connect the necessary callback functions.
+		Indicate clock speed (used to calculate toggle delays).
+		Chose a suitable name (helps debugging if you use several CAIF
+		SPI slave devices).
+		Assign your private data (can be used to map to your structure).
+
+		- Filling in the SPI slave platform device structure:
+		Add name of driver to connect to ("cfspi_sspi").
+		Assign the SPI slave device structure as platform data.
+
+- Padding:
+
+In order to optimize throughput, a number of SPI padding options are provided.
+Padding can be enabled independently for uplink and downlink transfers.
+Padding can be enabled for the head, the tail and for the total frame size.
+The padding needs to be correctly configured on both sides of the link.
+The padding can be changed via module parameters in cfspi_sspi.c or via
+the sysfs directory of the cfspi_sspi driver (before device registration).
+
+- CAIF SPI device template:
+
+/*
+ *	Copyright (C) ST-Ericsson AB 2010
+ *	Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ *	License terms: GNU General Public License (GPL), version 2.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <net/caif/caif_spi.h>
+
+MODULE_LICENSE("GPL");
+
+struct sspi_struct {
+	struct cfspi_dev sdev;
+	struct cfspi_xfer *xfer;
+};
+
+static struct sspi_struct slave;
+static struct platform_device slave_device;
+
+static irqreturn_t sspi_irq(int irq, void *arg)
+{
+	/* You only need to trigger on an edge to the active state of the
+	 * SS signal. Once a edge is detected, the ss_cb() function should be
+	 * called with the parameter assert set to true. It is OK
+	 * (and even advised) to call the ss_cb() function in IRQ context in
+	 * order not to add any delay. */
+
+	return IRQ_HANDLED;
+}
+
+static void sspi_complete(void *context)
+{
+	/* Normally the DMA or the SPI framework will call you back
+	 * in something similar to this. The only thing you need to
+	 * do is to call the xfer_done_cb() function, providing the pointer
+	 * to the CAIF SPI interface. It is OK to call this function
+	 * from IRQ context. */
+}
+
+static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev)
+{
+	/* Store transfer info. For a normal implementation you should
+	 * set up your DMA here and make sure that you are ready to
+	 * receive the data from the master SPI. */
+
+	struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+
+	sspi->xfer = xfer;
+
+	return 0;
+}
+
+void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev)
+{
+	/* If xfer is true then you should assert the SPI_INT to indicate to
+	 * the master that you are ready to recieve the data from the master
+	 * SPI. If xfer is false then you should de-assert SPI_INT to indicate
+	 * that the transfer is done.
+	 */
+
+	struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
+}
+
+static void sspi_release(struct device *dev)
+{
+	/*
+	 * Here you should release your SPI device resources.
+	 */
+}
+
+static int __init sspi_init(void)
+{
+	/* Here you should initialize your SPI device by providing the
+	 * necessary functions, clock speed, name and private data. Once
+	 * done, you can register your device with the
+	 * platform_device_register() function. This function will return
+	 * with the CAIF SPI interface initialized. This is probably also
+	 * the place where you should set up your GPIOs, interrupts and SPI
+	 * resources. */
+
+	int res = 0;
+
+	/* Initialize slave device. */
+	slave.sdev.init_xfer = sspi_init_xfer;
+	slave.sdev.sig_xfer = sspi_sig_xfer;
+	slave.sdev.clk_mhz = 13;
+	slave.sdev.priv = &slave;
+	slave.sdev.name = "spi_sspi";
+	slave_device.dev.release = sspi_release;
+
+	/* Initialize platform device. */
+	slave_device.name = "cfspi_sspi";
+	slave_device.dev.platform_data = &slave.sdev;
+
+	/* Register platform device. */
+	res = platform_device_register(&slave_device);
+	if (res) {
+		printk(KERN_WARNING "sspi_init: failed to register dev.\n");
+		return -ENODEV;
+	}
+
+	return res;
+}
+
+static void __exit sspi_exit(void)
+{
+	platform_device_del(&slave_device);
+}
+
+module_init(sspi_init);
+module_exit(sspi_exit);
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 0b28e01..372508e 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -14,4 +14,24 @@ config CAIF_TTY
 	identified as N_CAIF. When this ldisc is opened from user space
 	it will redirect the TTY's traffic into the CAIF stack.
 
+config CAIF_SPI_SLAVE
+	tristate "CAIF SPI transport driver for slave interface"
+	default n
+	---help---
+	The CAIF Link layer SPI Protocol driver for Slave SPI interface.
+	This driver implements a platform driver to accommodate for a
+	platform specific SPI device. A sample CAIF SPI Platform device is
+	provided in Documentation/networking/caif/spi_porting.txt
+
+if CAIF_SPI_SLAVE
+config CAIF_SPI_SYNC
+	bool "Next command and length in start of frame"
+	default n
+	---help---
+	Putting the next command and length in the start of the frame can
+	help to synchronize to the next transfer in case of over or under-runs.
+	This option also needs to be enabled on the modem.
+
+endif # CAIF_SPI_SLAVE
+
 endif # CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 52b6d1f..6cbe4b6 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -10,3 +10,7 @@ clean-files:= Module.symvers modules.order *.cmd *~ \
 
 # Serial interface
 obj-$(CONFIG_CAIF_TTY) += caif_serial.o
+
+# SPI slave physical interfaces module
+cfspi_slave-objs := caif_spi.o caif_spi_slave.o
+obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
new file mode 100644
index 0000000..03049e8
--- /dev/null
+++ b/drivers/net/caif/caif_spi.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author:  Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/if_arp.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define FLAVOR "Flavour: Vanilla.\n"
+#else
+#define FLAVOR "Flavour: Master CMD&LEN at start.\n"
+#endif /* CONFIG_CAIF_SPI_SYNC */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF SPI driver");
+
+static int spi_loop;
+module_param(spi_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
+
+/* SPI frame alignment. */
+module_param(spi_frm_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
+
+/* SPI padding options. */
+module_param(spi_up_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
+
+module_param(spi_up_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment.");
+
+module_param(spi_down_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment.");
+
+module_param(spi_down_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment.");
+
+#ifdef CONFIG_ARM
+#define BYTE_HEX_FMT "%02X"
+#else
+#define BYTE_HEX_FMT "%02hhX"
+#endif
+
+#define SPI_MAX_PAYLOAD_SIZE 4096
+/*
+ * Threshold values for the SPI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * deasserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK   100
+#define HIGH_WATER_MARK  (LOW_WATER_MARK*5)
+
+#ifdef CONFIG_UML
+
+/*
+ * We sometimes use UML for debugging, but it cannot handle
+ * dma_alloc_coherent so we have to wrap it.
+ */
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+	return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+	kfree(cpu_addr);
+}
+
+#else
+
+static inline void *dma_alloc(dma_addr_t *daddr)
+{
+	return dma_alloc_coherent(NULL, SPI_DMA_BUF_LEN, daddr,
+				GFP_KERNEL);
+}
+
+static inline void dma_free(void *cpu_addr, dma_addr_t handle)
+{
+	dma_free_coherent(NULL, SPI_DMA_BUF_LEN, cpu_addr, handle);
+}
+#endif	/* CONFIG_UML */
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_BUF_SIZE	4096
+
+static struct dentry *dbgfs_root;
+
+static inline void driver_debugfs_create(void)
+{
+	dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL);
+}
+
+static inline void driver_debugfs_remove(void)
+{
+	debugfs_remove(dbgfs_root);
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+	debugfs_remove(cfspi->dbgfs_frame);
+	debugfs_remove(cfspi->dbgfs_state);
+	debugfs_remove(cfspi->dbgfs_dir);
+}
+
+static int dbgfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	char *buf;
+	int len = 0;
+	ssize_t size;
+	struct cfspi *cfspi = (struct cfspi *)file->private_data;
+
+	buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	/* Print out debug information. */
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"CAIF SPI debug information:\n");
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"STATE: %d\n", cfspi->dbg_state);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Previous CMD: 0x%x\n", cfspi->pcmd);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current CMD: 0x%x\n", cfspi->cmd);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Previous TX len: %d\n", cfspi->tx_ppck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Previous RX len: %d\n", cfspi->rx_ppck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current TX len: %d\n", cfspi->tx_cpck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current RX len: %d\n", cfspi->rx_cpck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Next TX len: %d\n", cfspi->tx_npck_len);
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Next RX len: %d\n", cfspi->rx_npck_len);
+
+	size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return size;
+}
+
+static ssize_t print_frame(char *buf, size_t size, char *frm,
+			   size_t count, size_t cut)
+{
+	int len = 0;
+	int i;
+	for (i = 0; i < count; i++) {
+		len += snprintf((buf + len), (size - len),
+					"[0x" BYTE_HEX_FMT "]",
+					frm[i]);
+		if ((i == cut) && (count > (cut * 2))) {
+			/* Fast forward. */
+			i = count - cut;
+			len += snprintf((buf + len), (size - len),
+					"--- %u bytes skipped ---\n",
+					(int)(count - (cut * 2)));
+		}
+
+		if ((!(i % 10)) && i) {
+			len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+					"\n");
+		}
+	}
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
+	return len;
+}
+
+static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	char *buf;
+	int len = 0;
+	ssize_t size;
+	struct cfspi *cfspi;
+
+	cfspi = (struct cfspi *)file->private_data;
+	buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	/* Print out debug information. */
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Current frame:\n");
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Tx data (Len: %d):\n", cfspi->tx_cpck_len);
+
+	len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+			   cfspi->xfer.va_tx,
+			   (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
+
+	len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+			"Rx data (Len: %d):\n", cfspi->rx_cpck_len);
+
+	len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
+			   cfspi->xfer.va_rx,
+			   (cfspi->rx_cpck_len + SPI_CMD_SZ), 100);
+
+	size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+
+	return size;
+}
+
+static const struct file_operations dbgfs_state_fops = {
+	.open = dbgfs_open,
+	.read = dbgfs_state,
+	.owner = THIS_MODULE
+};
+
+static const struct file_operations dbgfs_frame_fops = {
+	.open = dbgfs_open,
+	.read = dbgfs_frame,
+	.owner = THIS_MODULE
+};
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+	cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root);
+	cfspi->dbgfs_state = debugfs_create_file("state", S_IRUGO,
+						 cfspi->dbgfs_dir, cfspi,
+						 &dbgfs_state_fops);
+	cfspi->dbgfs_frame = debugfs_create_file("frame", S_IRUGO,
+						 cfspi->dbgfs_dir, cfspi,
+						 &dbgfs_frame_fops);
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+	cfspi->dbg_state = state;
+};
+#else
+
+static inline void driver_debugfs_create(void)
+{
+}
+
+static inline void driver_debugfs_remove(void)
+{
+}
+
+static inline void dev_debugfs_add(struct cfspi *cfspi)
+{
+}
+
+static inline void dev_debugfs_rem(struct cfspi *cfspi)
+{
+}
+
+inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
+{
+}
+#endif				/* CONFIG_DEBUG_FS */
+
+static LIST_HEAD(cfspi_list);
+static spinlock_t cfspi_list_lock;
+
+/* SPI uplink head alignment. */
+static ssize_t show_up_head_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_up_head_align);
+}
+
+static DRIVER_ATTR(up_head_align, S_IRUSR, show_up_head_align, NULL);
+
+/* SPI uplink tail alignment. */
+static ssize_t show_up_tail_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_up_tail_align);
+}
+
+static DRIVER_ATTR(up_tail_align, S_IRUSR, show_up_tail_align, NULL);
+
+/* SPI downlink head alignment. */
+static ssize_t show_down_head_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_down_head_align);
+}
+
+static DRIVER_ATTR(down_head_align, S_IRUSR, show_down_head_align, NULL);
+
+/* SPI downlink tail alignment. */
+static ssize_t show_down_tail_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_down_tail_align);
+}
+
+static DRIVER_ATTR(down_tail_align, S_IRUSR, show_down_tail_align, NULL);
+
+/* SPI frame alignment. */
+static ssize_t show_frame_align(struct device_driver *driver, char *buf)
+{
+	return sprintf(buf, "%d\n", spi_frm_align);
+}
+
+static DRIVER_ATTR(frame_align, S_IRUSR, show_frame_align, NULL);
+
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+	u8 *dst = buf;
+	caif_assert(buf);
+
+	do {
+		struct sk_buff *skb;
+		struct caif_payload_info *info;
+		int spad = 0;
+		int epad;
+
+		skb = skb_dequeue(&cfspi->chead);
+		if (!skb)
+			break;
+
+		/*
+		 * Calculate length of frame including SPI padding.
+		 * The payload position is found in the control buffer.
+		 */
+		info = (struct caif_payload_info *)&skb->cb;
+
+		/*
+		 * Compute head offset i.e. number of bytes to add to
+		 * get the start of the payload aligned.
+		 */
+		if (spi_up_head_align) {
+			spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+			*dst = (u8)(spad - 1);
+			dst += spad;
+		}
+
+		/* Copy in CAIF frame. */
+		skb_copy_bits(skb, 0, dst, skb->len);
+		dst += skb->len;
+		cfspi->ndev->stats.tx_packets++;
+		cfspi->ndev->stats.tx_bytes += skb->len;
+
+		/*
+		 * Compute tail offset i.e. number of bytes to add to
+		 * get the complete CAIF frame aligned.
+		 */
+		epad = (skb->len + spad) & spi_up_tail_align;
+		dst += epad;
+
+		dev_kfree_skb(skb);
+
+	} while ((dst - buf) < len);
+
+	return dst - buf;
+}
+
+int cfspi_xmitlen(struct cfspi *cfspi)
+{
+	struct sk_buff *skb = NULL;
+	int frm_len = 0;
+	int pkts = 0;
+
+	/*
+	 * Decommit previously commited frames.
+	 * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead)
+	 */
+	while (skb_peek(&cfspi->chead)) {
+		skb = skb_dequeue_tail(&cfspi->chead);
+		skb_queue_head(&cfspi->qhead, skb);
+	}
+
+	do {
+		struct caif_payload_info *info = NULL;
+		int spad = 0;
+		int epad = 0;
+
+		skb = skb_dequeue(&cfspi->qhead);
+		if (!skb)
+			break;
+
+		/*
+		 * Calculate length of frame including SPI padding.
+		 * The payload position is found in the control buffer.
+		 */
+		info = (struct caif_payload_info *)&skb->cb;
+
+		/*
+		 * Compute head offset i.e. number of bytes to add to
+		 * get the start of the payload aligned.
+		 */
+		if (spi_up_head_align)
+			spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+
+		/*
+		 * Compute tail offset i.e. number of bytes to add to
+		 * get the complete CAIF frame aligned.
+		 */
+		epad = (skb->len + spad) & spi_up_tail_align;
+
+		if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
+			skb_queue_tail(&cfspi->chead, skb);
+			pkts++;
+			frm_len += skb->len + spad + epad;
+		} else {
+			/* Put back packet. */
+			skb_queue_head(&cfspi->qhead, skb);
+		}
+	} while (pkts <= CAIF_MAX_SPI_PKTS);
+
+	/*
+	 * Send flow on if previously sent flow off
+	 * and now go below the low water mark
+	 */
+	if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark &&
+		cfspi->cfdev.flowctrl) {
+		cfspi->flow_off_sent = 0;
+		cfspi->cfdev.flowctrl(cfspi->ndev, 1);
+	}
+
+	return frm_len;
+}
+
+static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
+{
+	struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+	if (!in_interrupt())
+		spin_lock(&cfspi->lock);
+	if (assert) {
+		set_bit(SPI_SS_ON, &cfspi->state);
+		set_bit(SPI_XFER, &cfspi->state);
+	} else {
+		set_bit(SPI_SS_OFF, &cfspi->state);
+	}
+	if (!in_interrupt())
+		spin_unlock(&cfspi->lock);
+
+	/* Wake up the xfer thread. */
+	wake_up_interruptible(&cfspi->wait);
+}
+
+static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
+{
+	struct cfspi *cfspi = (struct cfspi *)ifc->priv;
+
+	/* Transfer done, complete work queue */
+	complete(&cfspi->comp);
+}
+
+static int cfspi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct cfspi *cfspi = NULL;
+	unsigned long flags;
+	if (!dev)
+		return -EINVAL;
+
+	cfspi = netdev_priv(dev);
+
+	skb_queue_tail(&cfspi->qhead, skb);
+
+	spin_lock_irqsave(&cfspi->lock, flags);
+	if (!test_and_set_bit(SPI_XFER, &cfspi->state)) {
+		/* Wake up xfer thread. */
+		wake_up_interruptible(&cfspi->wait);
+	}
+	spin_unlock_irqrestore(&cfspi->lock, flags);
+
+	/* Send flow off if number of bytes is above high water mark */
+	if (!cfspi->flow_off_sent &&
+		cfspi->qhead.qlen > cfspi->qd_high_mark &&
+		cfspi->cfdev.flowctrl) {
+		cfspi->flow_off_sent = 1;
+		cfspi->cfdev.flowctrl(cfspi->ndev, 0);
+	}
+
+	return 0;
+}
+
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
+{
+	u8 *src = buf;
+
+	caif_assert(buf != NULL);
+
+	do {
+		int res;
+		struct sk_buff *skb = NULL;
+		int spad = 0;
+		int epad = 0;
+		u8 *dst = NULL;
+		int pkt_len = 0;
+
+		/*
+		 * Compute head offset i.e. number of bytes added to
+		 * get the start of the payload aligned.
+		 */
+		if (spi_down_head_align) {
+			spad = 1 + *src;
+			src += spad;
+		}
+
+		/* Read length of CAIF frame (little endian). */
+		pkt_len = *src;
+		pkt_len |= ((*(src+1)) << 8) & 0xFF00;
+		pkt_len += 2;	/* Add FCS fields. */
+
+		/* Get a suitable caif packet and copy in data. */
+
+		skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1);
+		caif_assert(skb != NULL);
+
+		dst = skb_put(skb, pkt_len);
+		memcpy(dst, src, pkt_len);
+		src += pkt_len;
+
+		skb->protocol = htons(ETH_P_CAIF);
+		skb_reset_mac_header(skb);
+		skb->dev = cfspi->ndev;
+
+		/*
+		 * Push received packet up the stack.
+		 */
+		if (!spi_loop)
+			res = netif_rx_ni(skb);
+		else
+			res = cfspi_xmit(skb, cfspi->ndev);
+
+		if (!res) {
+			cfspi->ndev->stats.rx_packets++;
+			cfspi->ndev->stats.rx_bytes += pkt_len;
+		} else
+			cfspi->ndev->stats.rx_dropped++;
+
+		/*
+		 * Compute tail offset i.e. number of bytes added to
+		 * get the complete CAIF frame aligned.
+		 */
+		epad = (pkt_len + spad) & spi_down_tail_align;
+		src += epad;
+	} while ((src - buf) < len);
+
+	return src - buf;
+}
+
+static int cfspi_open(struct net_device *dev)
+{
+	netif_wake_queue(dev);
+	return 0;
+}
+
+static int cfspi_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+static const struct net_device_ops cfspi_ops = {
+	.ndo_open = cfspi_open,
+	.ndo_stop = cfspi_close,
+	.ndo_start_xmit = cfspi_xmit
+};
+
+static void cfspi_setup(struct net_device *dev)
+{
+	struct cfspi *cfspi = netdev_priv(dev);
+	dev->features = 0;
+	dev->netdev_ops = &cfspi_ops;
+	dev->type = ARPHRD_CAIF;
+	dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+	dev->tx_queue_len = 0;
+	dev->mtu = SPI_MAX_PAYLOAD_SIZE;
+	dev->destructor = free_netdev;
+	skb_queue_head_init(&cfspi->qhead);
+	skb_queue_head_init(&cfspi->chead);
+	cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+	cfspi->cfdev.use_frag = false;
+	cfspi->cfdev.use_stx = false;
+	cfspi->cfdev.use_fcs = false;
+	cfspi->ndev = dev;
+}
+
+int cfspi_spi_probe(struct platform_device *pdev)
+{
+	struct cfspi *cfspi = NULL;
+	struct net_device *ndev;
+	struct cfspi_dev *dev;
+	int res;
+	dev = (struct cfspi_dev *)pdev->dev.platform_data;
+
+	ndev = alloc_netdev(sizeof(struct cfspi),
+			"cfspi%d", cfspi_setup);
+	if (!dev)
+		return -ENODEV;
+
+	cfspi = netdev_priv(ndev);
+	netif_stop_queue(ndev);
+	cfspi->ndev = ndev;
+	cfspi->pdev = pdev;
+
+	/* Set flow info */
+	cfspi->flow_off_sent = 0;
+	cfspi->qd_low_mark = LOW_WATER_MARK;
+	cfspi->qd_high_mark = HIGH_WATER_MARK;
+
+	/* Assign the SPI device. */
+	cfspi->dev = dev;
+	/* Assign the device ifc to this SPI interface. */
+	dev->ifc = &cfspi->ifc;
+
+	/* Allocate DMA buffers. */
+	cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx);
+	if (!cfspi->xfer.va_tx) {
+		printk(KERN_WARNING
+		       "CFSPI: failed to allocate dma TX buffer.\n");
+		res = -ENODEV;
+		goto err_dma_alloc_tx;
+	}
+
+	cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
+
+	if (!cfspi->xfer.va_rx) {
+		printk(KERN_WARNING
+		       "CFSPI: failed to allocate dma TX buffer.\n");
+		res = -ENODEV;
+		goto err_dma_alloc_rx;
+	}
+
+	/* Initialize the work queue. */
+	INIT_WORK(&cfspi->work, cfspi_xfer);
+
+	/* Initialize spin locks. */
+	spin_lock_init(&cfspi->lock);
+
+	/* Initialize flow control state. */
+	cfspi->flow_stop = false;
+
+	/* Initialize wait queue. */
+	init_waitqueue_head(&cfspi->wait);
+
+	/* Create work thread. */
+	cfspi->wq = create_singlethread_workqueue(dev->name);
+	if (!cfspi->wq) {
+		printk(KERN_WARNING "CFSPI: failed to create work queue.\n");
+		res = -ENODEV;
+		goto err_create_wq;
+	}
+
+	/* Initialize work queue. */
+	init_completion(&cfspi->comp);
+
+	/* Create debugfs entries. */
+	dev_debugfs_add(cfspi);
+
+	/* Set up the ifc. */
+	cfspi->ifc.ss_cb = cfspi_ss_cb;
+	cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb;
+	cfspi->ifc.priv = cfspi;
+
+	/* Add CAIF SPI device to list. */
+	spin_lock(&cfspi_list_lock);
+	list_add_tail(&cfspi->list, &cfspi_list);
+	spin_unlock(&cfspi_list_lock);
+
+	/* Schedule the work queue. */
+	queue_work(cfspi->wq, &cfspi->work);
+
+	/* Register network device. */
+	res = register_netdev(ndev);
+	if (res) {
+		printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
+		goto err_net_reg;
+	}
+	return res;
+
+ err_net_reg:
+	dev_debugfs_rem(cfspi);
+	set_bit(SPI_TERMINATE, &cfspi->state);
+	wake_up_interruptible(&cfspi->wait);
+	destroy_workqueue(cfspi->wq);
+ err_create_wq:
+	dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+ err_dma_alloc_rx:
+	dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+ err_dma_alloc_tx:
+	free_netdev(ndev);
+
+	return res;
+}
+
+int cfspi_spi_remove(struct platform_device *pdev)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct cfspi *cfspi = NULL;
+	struct cfspi_dev *dev;
+
+	dev = (struct cfspi_dev *)pdev->dev.platform_data;
+	spin_lock(&cfspi_list_lock);
+	list_for_each_safe(list_node, n, &cfspi_list) {
+		cfspi = list_entry(list_node, struct cfspi, list);
+		/* Find the corresponding device. */
+		if (cfspi->dev == dev) {
+			/* Remove from list. */
+			list_del(list_node);
+			/* Free DMA buffers. */
+			dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
+			dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx);
+			set_bit(SPI_TERMINATE, &cfspi->state);
+			wake_up_interruptible(&cfspi->wait);
+			destroy_workqueue(cfspi->wq);
+			/* Destroy debugfs directory and files. */
+			dev_debugfs_rem(cfspi);
+			unregister_netdev(cfspi->ndev);
+			spin_unlock(&cfspi_list_lock);
+			return 0;
+		}
+	}
+	spin_unlock(&cfspi_list_lock);
+	return -ENODEV;
+}
+
+static void __exit cfspi_exit_module(void)
+{
+	struct list_head *list_node;
+	struct list_head *n;
+	struct cfspi *cfspi = NULL;
+
+	list_for_each_safe(list_node, n, &cfspi_list) {
+		cfspi = list_entry(list_node, struct cfspi, list);
+		platform_device_unregister(cfspi->pdev);
+	}
+
+	/* Destroy sysfs files. */
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_head_align);
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_tail_align);
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_head_align);
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_tail_align);
+	driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align);
+	/* Unregister platform driver. */
+	platform_driver_unregister(&cfspi_spi_driver);
+	/* Destroy debugfs root directory. */
+	driver_debugfs_remove();
+}
+
+static int __init cfspi_init_module(void)
+{
+	int result;
+
+	/* Initialize spin lock. */
+	spin_lock_init(&cfspi_list_lock);
+
+	/* Register platform driver. */
+	result = platform_driver_register(&cfspi_spi_driver);
+	if (result) {
+		printk(KERN_ERR "Could not register platform SPI driver.\n");
+		goto err_dev_register;
+	}
+
+	/* Create sysfs files. */
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_up_head_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 1.\n");
+		goto err_create_up_head_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_up_tail_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 2.\n");
+		goto err_create_up_tail_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_down_head_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 3.\n");
+		goto err_create_down_head_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_down_tail_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 4.\n");
+		goto err_create_down_tail_align;
+	}
+
+	result =
+	    driver_create_file(&cfspi_spi_driver.driver,
+			       &driver_attr_frame_align);
+	if (result) {
+		printk(KERN_ERR "Sysfs creation failed 5.\n");
+		goto err_create_frame_align;
+	}
+	driver_debugfs_create();
+	return result;
+
+ err_create_frame_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_tail_align);
+ err_create_down_tail_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_down_head_align);
+ err_create_down_head_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_tail_align);
+ err_create_up_tail_align:
+	driver_remove_file(&cfspi_spi_driver.driver,
+			   &driver_attr_up_head_align);
+ err_create_up_head_align:
+ err_dev_register:
+	return result;
+}
+
+module_init(cfspi_init_module);
+module_exit(cfspi_exit_module);
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
new file mode 100644
index 0000000..077ccf8
--- /dev/null
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author:  Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <net/caif/caif_spi.h>
+
+#ifndef CONFIG_CAIF_SPI_SYNC
+#define SPI_DATA_POS SPI_CMD_SZ
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+	return cfspi->rx_cpck_len;
+}
+#else
+#define SPI_DATA_POS 0
+static inline int forward_to_spi_cmd(struct cfspi *cfspi)
+{
+	return 0;
+}
+#endif
+
+int spi_frm_align = 2;
+int spi_up_head_align = 1;
+int spi_up_tail_align;
+int spi_down_head_align = 3;
+int spi_down_tail_align = 1;
+
+#ifdef CONFIG_DEBUG_FS
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+	/* Store previous command for debugging reasons.*/
+	cfspi->pcmd = cfspi->cmd;
+	/* Store previous transfer. */
+	cfspi->tx_ppck_len = cfspi->tx_cpck_len;
+	cfspi->rx_ppck_len = cfspi->rx_cpck_len;
+}
+#else
+static inline void debugfs_store_prev(struct cfspi *cfspi)
+{
+}
+#endif
+
+void cfspi_xfer(struct work_struct *work)
+{
+	struct cfspi *cfspi;
+	u8 *ptr = NULL;
+	unsigned long flags;
+	int ret;
+	cfspi = container_of(work, struct cfspi, work);
+
+	/* Initialize state. */
+	cfspi->cmd = SPI_CMD_EOT;
+
+	for (;;) {
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
+
+		/* Wait for master talk or transmit event. */
+		wait_event_interruptible(cfspi->wait,
+				 test_bit(SPI_XFER, &cfspi->state) ||
+				 test_bit(SPI_TERMINATE, &cfspi->state));
+
+		if (test_bit(SPI_TERMINATE, &cfspi->state))
+			return;
+
+#if CFSPI_DBG_PREFILL
+		/* Prefill buffers for easier debugging. */
+		memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
+		memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
+#endif	/* CFSPI_DBG_PREFILL */
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
+
+	/* Check whether we have a committed frame. */
+		if (cfspi->tx_cpck_len) {
+			int len;
+
+			cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
+
+			/* Copy commited SPI frames after the SPI indication. */
+			ptr = (u8 *) cfspi->xfer.va_tx;
+			ptr += SPI_IND_SZ;
+			len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
+			WARN_ON(len != cfspi->tx_cpck_len);
+	}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
+
+		/* Get length of next frame to commit. */
+		cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
+
+		WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
+
+		/*
+		 * Add indication and length at the beginning of the frame,
+		 * using little endian.
+		 */
+		ptr = (u8 *) cfspi->xfer.va_tx;
+		*ptr++ = SPI_CMD_IND;
+		*ptr++ = (SPI_CMD_IND  & 0xFF00) >> 8;
+		*ptr++ = cfspi->tx_npck_len & 0x00FF;
+		*ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
+
+		/* Calculate length of DMAs. */
+		cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
+		cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
+
+		/* Add SPI TX frame alignment padding, if necessary. */
+		if (cfspi->tx_cpck_len &&
+			(cfspi->xfer.tx_dma_len % spi_frm_align)) {
+
+			cfspi->xfer.tx_dma_len += spi_frm_align -
+			    (cfspi->xfer.tx_dma_len % spi_frm_align);
+		}
+
+		/* Add SPI RX frame alignment padding, if necessary. */
+		if (cfspi->rx_cpck_len &&
+			(cfspi->xfer.rx_dma_len % spi_frm_align)) {
+
+			cfspi->xfer.rx_dma_len += spi_frm_align -
+			    (cfspi->xfer.rx_dma_len % spi_frm_align);
+		}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
+
+		/* Start transfer. */
+		ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
+		WARN_ON(ret);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
+
+		/*
+		 * TODO: We might be able to make an assumption if this is the
+		 * first loop. Make sure that minimum toggle time is respected.
+		 */
+		udelay(MIN_TRANSITION_TIME_USEC);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
+
+		/* Signal that we are ready to recieve data. */
+		cfspi->dev->sig_xfer(true, cfspi->dev);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
+
+		/* Wait for transfer completion. */
+		wait_for_completion(&cfspi->comp);
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
+
+		if (cfspi->cmd == SPI_CMD_EOT) {
+			/*
+			 * Clear the master talk bit. A xfer is always at
+			 *  least two bursts.
+			 */
+			clear_bit(SPI_SS_ON, &cfspi->state);
+		}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
+
+		/* Make sure that the minimum toggle time is respected. */
+		if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
+					cfspi->dev->clk_mhz) <
+			MIN_TRANSITION_TIME_USEC) {
+
+			udelay(MIN_TRANSITION_TIME_USEC -
+				SPI_XFER_TIME_USEC
+				(cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
+		}
+
+		cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
+
+		/* De-assert transfer signal. */
+		cfspi->dev->sig_xfer(false, cfspi->dev);
+
+		/* Check whether we received a CAIF packet. */
+		if (cfspi->rx_cpck_len) {
+			int len;
+
+			cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
+
+			/* Parse SPI frame. */
+			ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
+
+			len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
+			WARN_ON(len != cfspi->rx_cpck_len);
+		}
+
+		/* Check the next SPI command and length. */
+		ptr = (u8 *) cfspi->xfer.va_rx;
+
+		ptr += forward_to_spi_cmd(cfspi);
+
+		cfspi->cmd = *ptr++;
+		cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
+		cfspi->rx_npck_len = *ptr++;
+		cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
+
+		WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
+		WARN_ON(cfspi->cmd > SPI_CMD_EOT);
+
+		debugfs_store_prev(cfspi);
+
+		/* Check whether the master issued an EOT command. */
+		if (cfspi->cmd == SPI_CMD_EOT) {
+			/* Reset state. */
+			cfspi->tx_cpck_len = 0;
+			cfspi->rx_cpck_len = 0;
+		} else {
+			/* Update state. */
+			cfspi->tx_cpck_len = cfspi->tx_npck_len;
+			cfspi->rx_cpck_len = cfspi->rx_npck_len;
+		}
+
+		/*
+		 * Check whether we need to clear the xfer bit.
+		 * Spin lock needed for packet insertion.
+		 * Test and clear of different bits
+		 * are not supported.
+		 */
+		spin_lock_irqsave(&cfspi->lock, flags);
+		if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
+			&& !test_bit(SPI_SS_ON, &cfspi->state))
+			clear_bit(SPI_XFER, &cfspi->state);
+
+		spin_unlock_irqrestore(&cfspi->lock, flags);
+	}
+}
+
+struct platform_driver cfspi_spi_driver = {
+	.probe = cfspi_spi_probe,
+	.remove = cfspi_spi_remove,
+	.driver = {
+		   .name = "cfspi_sspi",
+		   .owner = THIS_MODULE,
+		   },
+};
diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h
new file mode 100644
index 0000000..ce4570d
--- /dev/null
+++ b/include/net/caif/caif_spi.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:	Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_SPI_H_
+#define CAIF_SPI_H_
+
+#include <net/caif/caif_device.h>
+
+#define SPI_CMD_WR			0x00
+#define SPI_CMD_RD			0x01
+#define SPI_CMD_EOT			0x02
+#define SPI_CMD_IND			0x04
+
+#define SPI_DMA_BUF_LEN			8192
+
+#define WL_SZ				2	/* 16 bits. */
+#define SPI_CMD_SZ			4	/* 32 bits. */
+#define SPI_IND_SZ			4	/* 32 bits. */
+
+#define SPI_XFER			0
+#define SPI_SS_ON			1
+#define SPI_SS_OFF			2
+#define SPI_TERMINATE			3
+
+/* Minimum time between different levels is 50 microseconds. */
+#define MIN_TRANSITION_TIME_USEC	50
+
+/* Defines for calculating duration of SPI transfers for a particular
+ * number of bytes.
+ */
+#define SPI_MASTER_CLK_MHZ		13
+#define SPI_XFER_TIME_USEC(bytes, clk) (((bytes) * 8) / clk)
+
+/* Normally this should be aligned on the modem in order to benefit from full
+ * duplex transfers. However a size of 8188 provokes errors when running with
+ * the modem. These errors occur when packet sizes approaches 4 kB of data.
+ */
+#define CAIF_MAX_SPI_FRAME 4092
+
+/* Maximum number of uplink CAIF frames that can reside in the same SPI frame.
+ * This number should correspond with the modem setting. The application side
+ * CAIF accepts any number of embedded downlink CAIF frames.
+ */
+#define CAIF_MAX_SPI_PKTS 9
+
+/* Decides if SPI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFSPI_DBG_PREFILL		0
+
+/* Structure describing a SPI transfer. */
+struct cfspi_xfer {
+	u16 tx_dma_len;
+	u16 rx_dma_len;
+	void *va_tx;
+	dma_addr_t pa_tx;
+	void *va_rx;
+	dma_addr_t pa_rx;
+};
+
+/* Structure implemented by the SPI interface. */
+struct cfspi_ifc {
+	void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
+	void (*xfer_done_cb) (struct cfspi_ifc *ifc);
+	void *priv;
+};
+
+/* Structure implemented by SPI clients. */
+struct cfspi_dev {
+	int (*init_xfer) (struct cfspi_xfer *xfer, struct cfspi_dev *dev);
+	void (*sig_xfer) (bool xfer, struct cfspi_dev *dev);
+	struct cfspi_ifc *ifc;
+	char *name;
+	u32 clk_mhz;
+	void *priv;
+};
+
+/* Enumeration describing the CAIF SPI state. */
+enum cfspi_state {
+	CFSPI_STATE_WAITING = 0,
+	CFSPI_STATE_AWAKE,
+	CFSPI_STATE_FETCH_PKT,
+	CFSPI_STATE_GET_NEXT,
+	CFSPI_STATE_INIT_XFER,
+	CFSPI_STATE_WAIT_ACTIVE,
+	CFSPI_STATE_SIG_ACTIVE,
+	CFSPI_STATE_WAIT_XFER_DONE,
+	CFSPI_STATE_XFER_DONE,
+	CFSPI_STATE_WAIT_INACTIVE,
+	CFSPI_STATE_SIG_INACTIVE,
+	CFSPI_STATE_DELIVER_PKT,
+	CFSPI_STATE_MAX,
+};
+
+/* Structure implemented by SPI physical interfaces. */
+struct cfspi {
+	struct caif_dev_common cfdev;
+	struct net_device *ndev;
+	struct platform_device *pdev;
+	struct sk_buff_head qhead;
+	struct sk_buff_head chead;
+	u16 cmd;
+	u16 tx_cpck_len;
+	u16 tx_npck_len;
+	u16 rx_cpck_len;
+	u16 rx_npck_len;
+	struct cfspi_ifc ifc;
+	struct cfspi_xfer xfer;
+	struct cfspi_dev *dev;
+	unsigned long state;
+	struct work_struct work;
+	struct workqueue_struct *wq;
+	struct list_head list;
+	int    flow_off_sent;
+	u32 qd_low_mark;
+	u32 qd_high_mark;
+	struct completion comp;
+	wait_queue_head_t wait;
+	spinlock_t lock;
+	bool flow_stop;
+#ifdef CONFIG_DEBUG_FS
+	enum cfspi_state dbg_state;
+	u16 pcmd;
+	u16 tx_ppck_len;
+	u16 rx_ppck_len;
+	struct dentry *dbgfs_dir;
+	struct dentry *dbgfs_state;
+	struct dentry *dbgfs_frame;
+#endif				/* CONFIG_DEBUG_FS */
+};
+
+extern int spi_frm_align;
+extern int spi_up_head_align;
+extern int spi_up_tail_align;
+extern int spi_down_head_align;
+extern int spi_down_tail_align;
+extern struct platform_driver cfspi_spi_driver;
+
+void cfspi_dbg_state(struct cfspi *cfspi, int state);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_spi_remove(struct platform_device *pdev);
+int cfspi_spi_probe(struct platform_device *pdev);
+int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+int cfspi_xmitlen(struct cfspi *cfspi);
+int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len);
+void cfspi_xfer(struct work_struct *work);
+
+#endif				/* CAIF_SPI_H_ */
-- 
1.6.3.3


^ permalink raw reply related

* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: David Miller @ 2010-06-22 21:21 UTC (permalink / raw)
  To: akpm; +Cc: netdev, bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <20100622141232.4b8f1d4a.akpm@linux-foundation.org>

From: Andrew Morton <akpm@linux-foundation.org>
Date: Tue, 22 Jun 2010 14:12:32 -0700

> What is "ss"?  Something which triggers a load of kernel modules,
> presumably.  Which ones?

'ss' is the tool which dumps sockets using netlink

^ permalink raw reply

* Re: [Bugme-new] [Bug 16268] New: kernel oops when rmmod the tcp_diag modules
From: Andrew Morton @ 2010-06-22 21:12 UTC (permalink / raw)
  To: netdev; +Cc: bugzilla-daemon, bugme-daemon, lyw
In-Reply-To: <bug-16268-10286@https.bugzilla.kernel.org/>


(switched to email.  Please respond via emailed reply-to-all, not via the
bugzilla web interface).

On Tue, 22 Jun 2010 00:43:37 GMT
bugzilla-daemon@bugzilla.kernel.org wrote:

> https://bugzilla.kernel.org/show_bug.cgi?id=16268
> 
>            Summary: kernel oops when rmmod the tcp_diag modules
>            Product: Networking
>            Version: 2.5
>     Kernel Version: 2.6.35-rc3
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: high
>           Priority: P1
>          Component: IPV4
>         AssignedTo: shemminger@linux-foundation.org
>         ReportedBy: lyw@cn.fujitsu.com
>         Regression: No
> 
> 
> I found a crash problem use following scripts and steps
> 
> #cat run_ss.sh
>  while [ 1 ]
>  do
>      ss -a
>  done
> 
> #cat rmmod.sh
>  while [ 1 ]
>  do 
>      rmmod -f tcp_diag >/dev/null 2>&1
>      rmmod -f inet_diag >/dev/null 2>&1
>  done
> 
> step1:
>   # sh run_sh.sh
> step2:
>   # sh rmmod.sh

I assume the rmmod script runs in pararallel with run_ss.sh.

What is "ss"?  Something which triggers a load of kernel modules,
presumably.  Which ones?

> After step2, the kernel oopsed.

yeah, that was a pretty nasty test ;)

> ========================================================
> Jun 22 08:44:33 RHEL6Beta kernel: Disabling lock debugging due to kernel taint
> Jun 22 08:44:33 RHEL6Beta kernel: BUG: unable to handle kernel NULL pointer
> dereference at (null)
> Jun 22 08:44:33 RHEL6Beta kernel: IP: [<f982d140>] 0xf982d140
> Jun 22 08:44:33 RHEL6Beta kernel: *pdpt = 0000000033af2001 *pde =
> 000000007d9cf067
> Jun 22 08:44:33 RHEL6Beta kernel: Oops: 0002 [#1] SMP
> Jun 22 08:44:33 RHEL6Beta kernel: last sysfs file:
> /sys/module/inet_diag/initstate
> Jun 22 08:44:33 RHEL6Beta kernel: Modules linked in: tcp_diag inet_diag
> p4_clockmod ipv6 dm_mirror dm_region_hash dm_log dm_mod snd_intel8x0
> snd_ac97_codec ac97_bus snd_seq snd_mpu401 snd_mpu401_uart snd_pcm snd_rawmidi
> snd_seq_device snd_timer snd r8169 8139too ppdev 8139cp soundcore mii
> parport_pc floppy sr_mod cdrom parport ns558 gameport sg iTCO_wdt
> iTCO_vendor_support snd_page_alloc pcspkr i2c_i801 ext3 jbd mbcache sd_mod
> crc_t10dif ata_generic pata_acpi ata_piix i915 drm_kms_helper drm i2c_algo_bit
> i2c_core video output [last unloaded: inet_diag]
> Jun 22 08:44:33 RHEL6Beta kernel:
> Jun 22 08:44:33 RHEL6Beta kernel: Pid: 27392, comm: ss Tainted: G  R        
> 2.6.35-rc3 #1 F61MV/AcerPower S100
> Jun 22 08:44:33 RHEL6Beta kernel: EIP: 0060:[<f982d140>] EFLAGS: 00010282 CPU:
> 0
> Jun 22 08:44:33 RHEL6Beta kernel: EIP is at 0xf982d140
> Jun 22 08:44:33 RHEL6Beta kernel: EAX: 00000000 EBX: 00000012 ECX: 00000001
> EDX: 00000000
> Jun 22 08:44:33 RHEL6Beta kernel: ESI: f4217b80 EDI: f4239f00 EBP: f4239f00
> ESP: f3b07bcc
> Jun 22 08:44:33 RHEL6Beta kernel: DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> Jun 22 08:44:33 RHEL6Beta kernel: Process ss (pid: 27392, ti=f3b06000
> task=f4152a50 task.ti=f3b06000)
> Jun 22 08:44:33 RHEL6Beta kernel: Stack:
> Jun 22 08:44:33 RHEL6Beta kernel: 00000001 f982e6b0 00000010 00000004 00000012
> f5a74400 f982debb c064256f
> Jun 22 08:44:33 RHEL6Beta kernel: <0> 0196b67e 00000014 c09fb3e0 90e7b493
> f3b07c38 f3b07c38 f4217b80 00000344
> Jun 22 08:44:33 RHEL6Beta kernel: <0> f4239f00 00000246 f3b07d80 00000246
> 00021453 000000d0 000000d0 c0746d84
> Jun 22 08:44:33 RHEL6Beta kernel: Call Trace:
> Jun 22 08:44:33 RHEL6Beta kernel: [<c064256f>] ?
> mix_pool_bytes_extract+0x4f/0x150
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:33 RHEL6Beta kernel: [<c074333c>] ? sock_rmalloc+0x4c/0x90
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076d6e3>] ? netlink_dump+0x53/0x1b0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076f2e0>] ? netlink_dump_start+0x130/0x1b0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076f18e>] ? netlink_rcv_skb+0x7e/0xa0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076eab0>] ? netlink_unicast+0x250/0x280
> Jun 22 08:44:33 RHEL6Beta kernel: [<c076f81c>] ? netlink_sendmsg+0x1bc/0x2a0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0740982>] ? sock_sendmsg+0xd2/0x110
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04374bd>] ? kmap_atomic_prot+0x11d/0x150
> Jun 22 08:44:33 RHEL6Beta kernel: [<c043750c>] ? kmap_atomic+0x1c/0x30
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0437357>] ? kunmap_atomic+0x67/0x80
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04ca242>] ?
> get_page_from_freelist+0x242/0x4d0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c07418e3>] ? sys_sendmsg+0x163/0x260
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c05787ed>] ?
> selinux_sk_alloc_security+0x6d/0xe0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04f53ac>] ? kmem_cache_alloc+0xfc/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c074303e>] ? sock_init_data+0xae/0x1d0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c046df2d>] ? creds_are_invalid+0x1d/0x40
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0502ea3>] ? get_empty_filp+0x123/0x1c0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0502fc7>] ? alloc_file+0x87/0xb0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c073f6f6>] ? sock_alloc_file+0xa6/0x120
> Jun 22 08:44:33 RHEL6Beta kernel: [<c04ffeb6>] ? fd_install+0x26/0x50
> Jun 22 08:44:33 RHEL6Beta kernel: [<c073f78b>] ? sock_map_fd+0x1b/0x30
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0741fcd>] ? sys_socketcall+0xed/0x2c0
> Jun 22 08:44:33 RHEL6Beta kernel: [<c0409fdf>] ? sysenter_do_call+0x12/0x28
> Jun 22 08:44:33 RHEL6Beta kernel: Code: 00 00 00 00 00 00 00 00 00 00 00 00 00
> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> 00 00 00 00 <00> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> Jun 22 08:44:33 RHEL6Beta kernel: EIP: [<f982d140>] 0xf982d140 SS:ESP
> 0068:f3b07bcc
> Jun 22 08:44:33 RHEL6Beta kernel: CR2: 0000000000000000
> Jun 22 08:44:33 RHEL6Beta kernel: ---[ end trace 443475da32e0e7d3 ]---
> Jun 22 08:44:34 RHEL6Beta kernel: BUG: unable to handle kernel paging request
> at 0135b004
> Jun 22 08:44:34 RHEL6Beta kernel: IP: [<c047e34e>] module_put+0x1e/0x90
> Jun 22 08:44:34 RHEL6Beta kernel: *pdpt = 0000000000ab8001 *pde =
> 0000000000000000
> Jun 22 08:44:34 RHEL6Beta kernel: Oops: 0002 [#2] SMP
> Jun 22 08:44:34 RHEL6Beta kernel: last sysfs file:
> /sys/module/inet_diag/initstate
> Jun 22 08:44:34 RHEL6Beta kernel: Modules linked in: p4_clockmod ipv6 dm_mirror
> dm_region_hash dm_log dm_mod snd_intel8x0 snd_ac97_codec ac97_bus snd_seq
> snd_mpu401 snd_mpu401_uart snd_pcm snd_rawmidi snd_seq_device snd_timer snd
> r8169 8139too ppdev 8139cp soundcore mii parport_pc floppy sr_mod cdrom parport
> ns558 gameport sg iTCO_wdt iTCO_vendor_support snd_page_alloc pcspkr i2c_i801
> ext3 jbd mbcache sd_mod crc_t10dif ata_generic pata_acpi ata_piix i915
> drm_kms_helper drm i2c_algo_bit i2c_core video output [last unloaded:
> inet_diag]
> Jun 22 08:44:34 RHEL6Beta kernel:
> Jun 22 08:44:34 RHEL6Beta kernel: Pid: 27392, comm: ss Tainted: G  R   D    
> 2.6.35-rc3 #1 F61MV/AcerPower S100
> Jun 22 08:44:34 RHEL6Beta kernel: EIP: 0060:[<c047e34e>] EFLAGS: 00010286 CPU:
> 0
> Jun 22 08:44:34 RHEL6Beta kernel: EIP is at module_put+0x1e/0x90
> Jun 22 08:44:34 RHEL6Beta kernel: EAX: 00000000 EBX: f982e7a0 ECX: f3b07a00
> EDX: 00000001
> Jun 22 08:44:34 RHEL6Beta kernel: ESI: f5486e00 EDI: f4095ee8 EBP: f5486e1c
> ESP: f3b079e8
> Jun 22 08:44:34 RHEL6Beta kernel: DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> Jun 22 08:44:34 RHEL6Beta kernel: Process ss (pid: 27392, ti=f3b06000
> task=f4152a50 task.ti=f3b06000)
> Jun 22 08:44:34 RHEL6Beta kernel: Stack:
> Jun 22 08:44:34 RHEL6Beta kernel: f4095e00 f5486e00 f4095ee8 f5486e1c c076e568
> 00000000 c0b641a0 00006b00
> Jun 22 08:44:34 RHEL6Beta kernel: <0> 00000004 f5486e00 00000000 f57c8cf0
> c073f86a 00000000 f5ada600 00000008
> Jun 22 08:44:34 RHEL6Beta kernel: <0> c073f8df f5486e1c c05032ab 00000003
> 00000000 00000000 f7022580 f57c8cf0
> Jun 22 08:44:34 RHEL6Beta kernel: Call Trace:
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076e568>] ? netlink_release+0xe8/0x210
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f86a>] ? sock_release+0x1a/0x80
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f8df>] ? sock_close+0xf/0x30
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05032ab>] ? fput+0x10b/0x220
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04fff67>] ? filp_close+0x47/0x80
> Jun 22 08:44:34 RHEL6Beta kernel: [<c044efda>] ? put_files_struct+0x5a/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c044fbdf>] ? do_exit+0x13f/0x750
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0801d45>] ? apic_timer_interrupt+0x31/0x38
> Jun 22 08:44:34 RHEL6Beta kernel: [<c044e531>] ? kmsg_dump+0x71/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c07ff121>] ? printk+0x17/0x1e
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0802b5c>] ? oops_end+0x8c/0xd0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0431202>] ? no_context+0xc2/0x190
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04314bf>] ? bad_area+0xf/0x20
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0804d44>] ? do_page_fault+0x3c4/0x3f0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c046341a>] ? __request_module+0x12a/0x1c0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0804980>] ? do_page_fault+0x0/0x3f0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0801fb7>] ? error_code+0x73/0x78
> Jun 22 08:44:34 RHEL6Beta kernel: [<c064256f>] ?
> mix_pool_bytes_extract+0x4f/0x150
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0746d84>] ? __alloc_skb+0x54/0x100
> Jun 22 08:44:34 RHEL6Beta kernel: [<c074333c>] ? sock_rmalloc+0x4c/0x90
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076d6e3>] ? netlink_dump+0x53/0x1b0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076f2e0>] ? netlink_dump_start+0x130/0x1b0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076f18e>] ? netlink_rcv_skb+0x7e/0xa0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076eab0>] ? netlink_unicast+0x250/0x280
> Jun 22 08:44:34 RHEL6Beta kernel: [<c076f81c>] ? netlink_sendmsg+0x1bc/0x2a0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0740982>] ? sock_sendmsg+0xd2/0x110
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04374bd>] ? kmap_atomic_prot+0x11d/0x150
> Jun 22 08:44:34 RHEL6Beta kernel: [<c043750c>] ? kmap_atomic+0x1c/0x30
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0437357>] ? kunmap_atomic+0x67/0x80
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04ca242>] ?
> get_page_from_freelist+0x242/0x4d0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05b8fa5>] ? _copy_from_user+0x35/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c07418e3>] ? sys_sendmsg+0x163/0x260
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04f529e>] ?
> kmem_cache_alloc_notrace+0x9e/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c05787ed>] ?
> selinux_sk_alloc_security+0x6d/0xe0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04f53ac>] ? kmem_cache_alloc+0xfc/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c074303e>] ? sock_init_data+0xae/0x1d0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c046df2d>] ? creds_are_invalid+0x1d/0x40
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0502ea3>] ? get_empty_filp+0x123/0x1c0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0502fc7>] ? alloc_file+0x87/0xb0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f6f6>] ? sock_alloc_file+0xa6/0x120
> Jun 22 08:44:34 RHEL6Beta kernel: [<c04ffeb6>] ? fd_install+0x26/0x50
> Jun 22 08:44:34 RHEL6Beta kernel: [<c073f78b>] ? sock_map_fd+0x1b/0x30
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0741fcd>] ? sys_socketcall+0xed/0x2c0
> Jun 22 08:44:34 RHEL6Beta kernel: [<c0409fdf>] ? sysenter_do_call+0x12/0x28
> Jun 22 08:44:34 RHEL6Beta kernel: Code: e8 b8 f5 13 00 31 c0 c3 90 8d 74 26 00
> 83 ec 10 85 c0 89 1c 24 89 c3 89 74 24 04 89 7c 24 08 89 6c 24 0c 74 1d 8b 80
> 60 01 00 00 <64> ff 40 04 8b 3d e4 4b a1 c0 8b 74 24 10 85 ff 75 18 83 3b 02
> Jun 22 08:44:34 RHEL6Beta kernel: EIP: [<c047e34e>] module_put+0x1e/0x90 SS:ESP
> 0068:f3b079e8
> Jun 22 08:44:34 RHEL6Beta kernel: CR2: 000000000135b004
> Jun 22 08:44:34 RHEL6Beta kernel: ---[ end trace 443475da32e0e7d4 ]---
> 


^ permalink raw reply

* Re: Can I limit number of rx queues for igb (and other Intel drivers)?
From: Ben Greear @ 2010-06-22 19:54 UTC (permalink / raw)
  To: Wyborny, Carolyn; +Cc: NetDev
In-Reply-To: <EDC0E76513226749BFBC9C3FB031318FD7874B40@orsmsx508.amr.corp.intel.com>

On 06/21/2010 04:35 PM, Wyborny, Carolyn wrote:
>
>
>> -----Original Message-----
>> From: netdev-owner@vger.kernel.org
>> [mailto:netdev-owner@vger.kernel.org] On Behalf Of Ben Greear
>> Sent: Friday, June 18, 2010 3:40 PM
>> To: NetDev
>> Subject: Can I limit number of rx queues for igb (and other
>> Intel drivers)?
>>
>> I'm using pktgen to send a stream of packets with varying
>> source and destination
>> IP addresses.  It appears that the fancy rx logic of the NIC
>> (I'm using igb for this test)
>> causes the received packets to appear on random rx queues and
>> so be received out
>> of order in the network core.
>>
>> I do not see the out-of-order issue when using a single
>> source/dest IP address
>> for the pktgen packets.
>>
>> So, is there a way to tell igb to use only a single rx queue?
>>
>> Thanks,
>> Ben
>>
>> --
>> Ben Greear<greearb@candelatech.com>
>> Candela Technologies Inc  http://www.candelatech.com
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
> Hello,
>
> There is not a way to tell igb to use a single queue and ethtool does not currently have a way to do this.
>
> We also maintain an out of kernel version of the driver at SourceForge that has module parameters to do this.
>
> If you need to do this with the kernel version, we'd need to modify ethtool to be able to do this.

A module parameter would be OK, but an ethtool command to change this live
would be really nice!  It may be a day or two before I get back to testing
this, but will try your out-of-tree driver with proper mod-parm invocation
then.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* Re: [PATCH 1/5 v2]wireless:hostap_main.c warning: variable 'iface' set but not used
From: Justin P. Mattock @ 2010-06-22 18:34 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20100622181320.GD2583@tuxdriver.com>

On 06/22/2010 11:13 AM, John W. Linville wrote:
> On Mon, Jun 21, 2010 at 03:02:13PM -0700, Justin P. Mattock wrote:
>> This is a resend from version one due to trying a different approach
>> than the original(probably important to leave netdev_priv() in).
>>
>> In any case have a look, if there's another approach let me know
>> and ill test it out. The below patch fixes a warning im seeing
>> when compiling with gcc 4.6.0
>>
>> CC [M]  drivers/net/wireless/hostap/hostap_main.o
>> drivers/net/wireless/hostap/hostap_main.c: In function 'hostap_set_multicast_list_queue':
>> drivers/net/wireless/hostap/hostap_main.c:744:27: warning: variable 'iface' set but not used
>>   Signed-off-by: Justin P. Mattock<justinmattock@gmail.com>
>
> I already applied the other version to wireless-next-2.6.  I can't
> imagine what you mean to accomplish by leaving in a call to netdev_priv
> w/o assigning the result to something.
>
> John

alright..
as for the netdev_priv, I was getting confused on this one.

Thanks for taking the time to look at this.

Justin P. Mattock

^ permalink raw reply

* Re: can multi app capture on same NIC?(use packet_mmap)
From: Paul LeoNerd Evans @ 2010-06-22 18:31 UTC (permalink / raw)
  To: Jon Zhou, netdev
In-Reply-To: <4A6A2125329CFD4D8CC40C9E8ABCAB9F24985FE8F8@MILEXCH2.ds.jdsu.net>

[-- Attachment #1: Type: text/plain, Size: 1884 bytes --]

On Tue, Jun 22, 2010 at 02:40:13AM -0700, Jon Zhou wrote:
> I'd like to know multi-app can work with packet_mmap (or traditional AF_PACKET system call)?
> i.e.
> app1 & app2 capture on the same NIC
> 
> will both of them receive the same packet? 
> 
> Or this situation will happen?
> 
> 1.app1 start to receive a packet#1
> 2.app1 complete receiving, then set the packet_status->TP_STATUS_KERNEL
> 3.how about app2 at this time? Will it see packet_status=KERNEL, then packet#1 got lost?

Sure; each PF_PACKET socket gets its own memory buffer.

> I tried to find the relevant code in af_packet.c, seems it doesn't guarantee multi-app capture on same NIC?
> Can someone help to point it out?

That's because af_packet.c doesn't need to care. All the relevant code
is found in net/core/dev.c

PF_PACKET sockets get installed into the ptype_all list:

  void dev_add_pack(struct packet_type *pt)
  {
          int hash;

          spin_lock_bh(&ptype_lock);
          if (pt->type == htons(ETH_P_ALL))
                  list_add_rcu(&pt->list, &ptype_all);
  ...

Thereafter, every packet that's received is delivered, individually, to
every handler in that list:

  int netif_receive_skb(struct sk_buff *skb)
  {
  ...
          list_for_each_entry_rcu(ptype, &ptype_all, list) {
                  if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
                      ptype->dev == orig_dev) {
                          if (pt_prev)
                                  ret = deliver_skb(skb, pt_prev, orig_dev);
  ...

Finally, in net/packet/af_packet.c, each PF_PACKET socket gets a copy of
this skb anyway; look for the call to skb_copy_bits() in the function
tpacket_rcv()

Hope that helps,

-- 
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk
ICQ# 4135350       |  Registered Linux# 179460
http://www.leonerd.org.uk/

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply

* Re: [PATCH 1/5 v2]wireless:hostap_main.c warning: variable 'iface' set but not used
From: John W. Linville @ 2010-06-22 18:13 UTC (permalink / raw)
  To: Justin P. Mattock; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <1277157733-14071-1-git-send-email-justinmattock@gmail.com>

On Mon, Jun 21, 2010 at 03:02:13PM -0700, Justin P. Mattock wrote:
> This is a resend from version one due to trying a different approach
> than the original(probably important to leave netdev_priv() in).
> 
> In any case have a look, if there's another approach let me know
> and ill test it out. The below patch fixes a warning im seeing
> when compiling with gcc 4.6.0
> 
> CC [M]  drivers/net/wireless/hostap/hostap_main.o
> drivers/net/wireless/hostap/hostap_main.c: In function 'hostap_set_multicast_list_queue':
> drivers/net/wireless/hostap/hostap_main.c:744:27: warning: variable 'iface' set but not used
>  Signed-off-by: Justin P. Mattock <justinmattock@gmail.com>

I already applied the other version to wireless-next-2.6.  I can't
imagine what you mean to accomplish by leaving in a call to netdev_priv
w/o assigning the result to something.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: pull request: wireless-2.6 2010-06-22
From: David Miller @ 2010-06-22 17:54 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20100622174136.GC2583@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Tue, 22 Jun 2010 13:41:37 -0400

> Just a single fix this time, a patch for ath5k to avoid a null pointer
> dereference that can happen when executing certain operations against a
> newly created interface.  This is, of course, intended for 2.6.35.
> 
> Please let me know if there are problems!

Pulled, thanks John.

^ permalink raw reply

* [PATCH net-next-2.6] arp: RCU change in arp_solicit()
From: Eric Dumazet @ 2010-06-22 17:43 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Avoid two atomic ops in arp_solicit()

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv4/arp.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index cf78f41..09ead1b 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -333,11 +333,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 	struct net_device *dev = neigh->dev;
 	__be32 target = *(__be32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
-	struct in_device *in_dev = in_dev_get(dev);
+	struct in_device *in_dev;
 
-	if (!in_dev)
+	rcu_read_lock();
+	in_dev = __in_dev_get_rcu(dev);
+	if (!in_dev) {
+		rcu_read_unlock();
 		return;
-
+	}
 	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
 	default:
 	case 0:		/* By default announce any local IP */
@@ -358,9 +361,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 	case 2:		/* Avoid secondary IPs, get a primary/preferred one */
 		break;
 	}
+	rcu_read_unlock();
 
-	if (in_dev)
-		in_dev_put(in_dev);
 	if (!saddr)
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
 



^ permalink raw reply related

* pull request: wireless-2.6 2010-06-22
From: John W. Linville @ 2010-06-22 17:41 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev, linux-kernel

Dave,

Just a single fix this time, a patch for ath5k to avoid a null pointer
dereference that can happen when executing certain operations against a
newly created interface.  This is, of course, intended for 2.6.35.

Please let me know if there are problems!

Thanks,

John


---

The following changes since commit 25442e06d20aaba7d7b16438078a562b3e4cf19b:
  stephen hemminger (1):
        bridge: fdb cleanup runs too often

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master

Bob Copeland (1):
      ath5k: initialize ah->ah_current_channel

 drivers/net/wireless/ath/ath5k/attach.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index e0c244b..31c0080 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -126,6 +126,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
 	ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
 	ah->ah_noise_floor = -95;	/* until first NF calibration is run */
 	sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO;
+	ah->ah_current_channel = &sc->channels[0];
 
 	/*
 	 * Find the mac version
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply related

* Re: [PATCH net-next-2.6 v2] net: Introduce u64_stats_sync infrastructure
From: Eric Dumazet @ 2010-06-22 17:31 UTC (permalink / raw)
  To: David Miller; +Cc: npiggin, netdev, bhutchings
In-Reply-To: <20100622.102455.232729115.davem@davemloft.net>

Le mardi 22 juin 2010 à 10:24 -0700, David Miller a écrit :

> That's a really weird patch hunk for a newly added file.
> 
> The hunk header is saying that the new file start 1 line
> in.  Which doesn't make any sense, and GIT reject this
> saying that you're trying to make a modification to a
> file which doesn't exist.
> 
> I applied this by hand, but I really wonder how you managed
> to create such a patch :-)

Now you mention it, I remember I had problems about this newly added
file, and had to use several git commands to stabilize my tree.

I really dont know what happened exactly, sorry :!)

Thanks !



^ permalink raw reply

* Re: bnx2 fails to compile on parisc because of missing get_dma_ops()
From: James Bottomley @ 2010-06-22 17:26 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: lethal, davem, mchan, vapier, netdev, linux-parisc, linux-kernel
In-Reply-To: <20100622152823R.fujita.tomonori@lab.ntt.co.jp>

On Tue, 2010-06-22 at 15:30 +0900, FUJITA Tomonori wrote:
> On Fri, 18 Jun 2010 00:30:51 +0900
> Paul Mundt <lethal@linux-sh.org> wrote:
> 
> > On Thu, Jun 17, 2010 at 11:50:35PM +0900, FUJITA Tomonori wrote:
> > > On Thu, 17 Jun 2010 07:36:53 -0700 (PDT)
> > > David Miller <davem@davemloft.net> wrote:
> > > 
> > > > From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> > > > Date: Thu, 17 Jun 2010 21:21:13 +0900
> > > > 
> > > > > On Wed, 16 Jun 2010 23:24:44 -0700
> > > > > "Michael Chan" <mchan@broadcom.com> wrote:
> > > > > 
> > > > >> David, why is dma_is_consistent() always returning 1 on sparc?  The
> > > > >> streaming DMA is not consistent.
> > > > > 
> > > > > I think that there are some confusion about dma_is_consistent(). Some
> > > > > architectures think that dma_is_consistent() is supposed to return 1
> > > > > if they can allocate coherent memory (note that some architectures
> > > > > can't allocate coherent memory).
> > > > 
> > > > Right, and that's why it's defined this way.
> > > > 
> > > > If the desired meaning is different, just me know and I'll fix the
> > > > sparc definition.
> > > 
> > > I think that there are some other architectures do the same. We need
> > > to make sure that all the architectures define dma_is_consistent() in
> > > the same meaning if drivers need it. However, I'm not sure we really
> > > need dma_is_consistent(). There is only one user of it (and I think we
> > > could remove it).
> > > 
> > > In the bnx2 case, we can simply prefetch on all the archs (or just
> > > remove the optimization).
> > 
> > I think its worthwhile keeping, especially since the consistency can vary
> > on a per struct device level. If there's a benefit with these sorts of
> > prefetch micro-optimizations in drivers when it doesn't cost us that much
> > to provide the hint, I don't really see the harm. If dma_is_consistent()
> > is suddenly supposed to take on other meanings, or it's supposed to mean
> > something entirely different, then this is something we should deal with
> > separately.
> > 
> > I don't see any harm in letting drivers know whether we can support
> > consistent DMA allocs for a given struct device or not though, even if
> > the micro-optimization is marginal at best.
> 
> I'm happier with exporting less DMA APIs to drivers because looks like
> new original ways to use the APIs wrongly can be always invented.
> 
> 
> > At least I've conditionalized the definition on SH, and it seems other
> > archictures have done so too. It's not clear what we'd gain from throwing
> 
> >From a quick look, except for SH and POWERPC (and always-coherent
> architectures), everyone does differently?
> 
> There are architectures that need to turn off the CPU cache for
> coherent memory, I can't find none of them that see if an address is
> coherent or not in dma_is_consistent().

Yes, I fear ... parisc.  We have a class of machines where this is the
only way (and we also have a class of machines where the cache disable
doesn't work properly and we can't manufacture coherent memory at all).
All our pa2.0 systems are fully integrated between the iommu cache and
the CPU cache, so they can manufacture coherent memory properly, but the
pa1.0 systems are a mixed bag of dirty tricks.

> As I wrote, there is only one user of this API and we can remove it
> easily. Then I'm not sure it's worth fixing dma_is_consistent() in
> many architectures. I prefer to add this to
> feature-removal-schedule.txt to see if driver writers oppose.

Let me check our two drivers: lasi and 53c700; they're the only ones we
support on the architecture that can't do any coherence.  I think we
don't need to tell because the dma_sync_cache calls which replace
coherent memory handling are indirected on the platform so we don't need
a global dma_is_coherent() flag.

James



^ permalink raw reply

* Re: [PATCH net-next-2.6] bridge: 64bit rx/tx counters
From: David Miller @ 2010-06-22 17:25 UTC (permalink / raw)
  To: eric.dumazet; +Cc: shemminger, netdev, bhutchings, npiggin
In-Reply-To: <1276598376.2541.93.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 15 Jun 2010 12:39:36 +0200

> Note : should be applied after "net: Introduce 
> u64_stats_sync infrastructure", if accepted.
> 
> 
> Thanks
> 
> [PATCH net-next-2.6] bridge: 64bit rx/tx counters
> 
> Use u64_stats_sync infrastructure to provide 64bit rx/tx 
> counters even on 32bit hosts.
> 
> It is safe to use a single u64_stats_sync for rx and tx,
> because BH is disabled on both, and we use per_cpu data.
> 
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next-2.6 v2] net: Introduce u64_stats_sync infrastructure
From: David Miller @ 2010-06-22 17:24 UTC (permalink / raw)
  To: eric.dumazet; +Cc: npiggin, netdev, bhutchings
In-Reply-To: <1276608594.2541.119.camel@edumazet-laptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 15 Jun 2010 15:29:54 +0200

> diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h
> index e69de29..5a4f318 100644
> --- a/include/linux/u64_stats_sync.h
> +++ b/include/linux/u64_stats_sync.h
> @@ -0,0 +1,107 @@
> +#ifndef _LINUX_U64_STATS_SYNC_H
> +#define _LINUX_U64_STATS_SYNC_H
> +

That's a really weird patch hunk for a newly added file.

The hunk header is saying that the new file start 1 line
in.  Which doesn't make any sense, and GIT reject this
saying that you're trying to make a modification to a
file which doesn't exist.

I applied this by hand, but I really wonder how you managed
to create such a patch :-)

^ permalink raw reply

* Re: Link-local address handling for IPv4
From: Eric Dumazet @ 2010-06-22 17:21 UTC (permalink / raw)
  To: Fischer, Anna; +Cc: netdev
In-Reply-To: <0199E0D51A61344794750DC57738F58E739702DDAE@GVW1118EXC.americas.hpqcorp.net>

Le mardi 22 juin 2010 à 13:17 +0000, Fischer, Anna a écrit :
> Hi,
> 
> Does the Linux kernel network stack do any specific handling of 

> link-local address configuration and handling according to RFC 3927?

>  I know that there is user-level code like Zeroconf / Avahi and these

>  tools create ARP sockets directly on the specified network interfaces 

> in order to support link-local address handling. But if I do not 

> run any of these tools, does the kernel's ARP code take care of this, too?
> 

There is no RFC 3927 support in kernel, you need user space support (or
switch to DHCP ;) )

Note that ARP replies MUST also be broadcasted for this particular
169.254/16 network (RFC 3927, 2.5), you need a kernel patch too, this
was discussed 4 years ago on netdev, and nothing was decided/changed.

http://marc.info/?l=linux-netdev&m=114427223811197&w=2


BTW I believe that our forwarding path doesnt test source/destination
address not being part of 169.254/16 network, I am not sure it
is a real problem or not. A netfilter rule can fix it eventually.

7.  Router Considerations

   A router MUST NOT forward a packet with an IPv4 Link-Local source or
   destination address, irrespective of the router's default route
   configuration or routes obtained from dynamic routing protocols.

   A router which receives a packet with an IPv4 Link-Local source or
   destination address MUST NOT forward the packet.  This prevents
   forwarding of packets back onto the network segment from which they
   originated, or to any other segment.







^ permalink raw reply

* Re: inconsistent lock state
From: Paul E. McKenney @ 2010-06-22 17:17 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Sergey Senozhatsky, Alexander Viro, Peter Zijlstra, Sage Weil,
	linux-fsdevel, linux-kernel, Dominik Brodowski, Maciej Rutecki,
	Eric Dumazet, Lai Jiangshan, David S. Miller, netdev
In-Reply-To: <20100618133004.228c2223.akpm@linux-foundation.org>

On Fri, Jun 18, 2010 at 01:30:04PM -0700, Andrew Morton wrote:
> 
> This was also reported by Dominik and is being tracked at
> https://bugzilla.kernel.org/show_bug.cgi?id=16230
> 
> On Tue, 15 Jun 2010 14:24:34 +0300
> Sergey Senozhatsky <sergey.senozhatsky@gmail.com> wrote:
> 
> > Hello,
> > 
> > kernel: [ 3272.351191] 
> > kernel: [ 3272.351194] =================================
> > kernel: [ 3272.351199] [ INFO: inconsistent lock state ]
> > kernel: [ 3272.351204] 2.6.35-rc3-dbg-00106-ga75e02b-dirty #15
> > kernel: [ 3272.351206] ---------------------------------
> > kernel: [ 3272.351210] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
> > kernel: [ 3272.351215] X/3827 [HC0[0]:SC0[0]:HE1:SE1] takes:
> > kernel: [ 3272.351218]  (&(&new->fa_lock)->rlock){?.-...}, at: [<c10aefb4>] kill_fasync+0x37/0x71
> > kernel: [ 3272.351232] {IN-HARDIRQ-W} state was registered at:
> > kernel: [ 3272.351235]   [<c104e95c>] __lock_acquire+0x281/0xbe1
> > kernel: [ 3272.351243]   [<c104f652>] lock_acquire+0x59/0x70
> > kernel: [ 3272.351248]   [<c12c6c48>] _raw_spin_lock+0x25/0x34
> > kernel: [ 3272.351255]   [<c10aefb4>] kill_fasync+0x37/0x71
> > kernel: [ 3272.351261]   [<fd220c81>] evdev_event+0x135/0x190 [evdev]
> > kernel: [ 3272.351275]   [<c1232003>] input_pass_event+0x6f/0xae
> > kernel: [ 3272.351283]   [<c1232ef5>] input_handle_event+0x38d/0x396
> > kernel: [ 3272.351288]   [<c1232fbf>] input_event+0x4f/0x62
> > kernel: [ 3272.351293]   [<c12368e4>] input_sync+0xe/0x11
> > kernel: [ 3272.351299]   [<c1236d72>] atkbd_interrupt+0x48b/0x541
> > kernel: [ 3272.351304]   [<c122ecb2>] serio_interrupt+0x35/0x68
> > kernel: [ 3272.351309]   [<c122fbff>] i8042_interrupt+0x264/0x26e
> > kernel: [ 3272.351314]   [<c106bb02>] handle_IRQ_event+0x1d/0x98
> > kernel: [ 3272.351321]   [<c106d506>] handle_edge_irq+0xc0/0x107
> > kernel: [ 3272.351326]   [<c10045ca>] handle_irq+0x1a/0x20
> > kernel: [ 3272.351332]   [<c100435f>] do_IRQ+0x43/0x8d
> > kernel: [ 3272.351337]   [<c1002d75>] common_interrupt+0x35/0x3c
> > kernel: [ 3272.351342]   [<c124723d>] cpuidle_idle_call+0x6a/0xa0
> > kernel: [ 3272.351349]   [<c100170d>] cpu_idle+0x89/0xbe
> > kernel: [ 3272.351354]   [<c12b6d11>] rest_init+0xb5/0xba
> > kernel: [ 3272.351361]   [<c148a7bf>] start_kernel+0x33b/0x340
> > kernel: [ 3272.351368]   [<c148a0c9>] i386_start_kernel+0xc9/0xd0
> > kernel: [ 3272.351374] irq event stamp: 54104917
> > kernel: [ 3272.351377] hardirqs last  enabled at (54104917): [<c12c70f2>] _raw_spin_unlock_irqrestore+0x36/0x5b
> > kernel: [ 3272.351384] hardirqs last disabled at (54104916): [<c12c6ced>] _raw_spin_lock_irqsave+0x13/0x42
> > kernel: [ 3272.351391] softirqs last  enabled at (54104732): [<c1032cf2>] __do_softirq+0xfd/0x10c
> > kernel: [ 3272.351398] softirqs last disabled at (54104703): [<c1032d30>] do_softirq+0x2f/0x47
> > kernel: [ 3272.351404] 
> > kernel: [ 3272.351405] other info that might help us debug this:
> > kernel: [ 3272.351409] 3 locks held by X/3827:
> > kernel: [ 3272.351412]  #0:  (rcu_read_lock){.+.+..}, at: [<c124fdfa>] rcu_read_lock+0x0/0x26
> > kernel: [ 3272.351423]  #1:  (rcu_read_lock){.+.+..}, at: [<c124d5d9>] rcu_read_lock+0x0/0x26
> > kernel: [ 3272.351432]  #2:  (rcu_read_lock){.+.+..}, at: [<c10ae429>] rcu_read_lock+0x0/0x26
> > kernel: [ 3272.351442] 
> > kernel: [ 3272.351443] stack backtrace:
> > kernel: [ 3272.351448] Pid: 3827, comm: X Not tainted 2.6.35-rc3-dbg-00106-ga75e02b-dirty #15
> > kernel: [ 3272.351451] Call Trace:
> > kernel: [ 3272.351456]  [<c12c4ff1>] ? printk+0xf/0x11
> > kernel: [ 3272.351462]  [<c104e51a>] valid_state+0x133/0x141
> > kernel: [ 3272.351468]  [<c104e5f7>] mark_lock+0xcf/0x1b3
> > kernel: [ 3272.351473]  [<c104e54e>] ? mark_lock+0x26/0x1b3
> > kernel: [ 3272.351479]  [<c104dfd2>] ? check_usage_backwards+0x0/0x68
> > kernel: [ 3272.351484]  [<c104e9d0>] __lock_acquire+0x2f5/0xbe1
> > kernel: [ 3272.351489]  [<c104ea44>] ? __lock_acquire+0x369/0xbe1
> > kernel: [ 3272.351495]  [<c104ea44>] ? __lock_acquire+0x369/0xbe1
> > kernel: [ 3272.351502]  [<c102ab40>] ? try_to_wake_up+0x2a8/0x2bb
> > kernel: [ 3272.351508]  [<c104f652>] lock_acquire+0x59/0x70
> > kernel: [ 3272.351513]  [<c10aefb4>] ? kill_fasync+0x37/0x71
> > kernel: [ 3272.351519]  [<c12c6c48>] _raw_spin_lock+0x25/0x34
> > kernel: [ 3272.351524]  [<c10aefb4>] ? kill_fasync+0x37/0x71
> > kernel: [ 3272.351529]  [<c10aefb4>] kill_fasync+0x37/0x71
> > kernel: [ 3272.351534]  [<c124d694>] sock_wake_async+0x77/0x83
> > kernel: [ 3272.351540]  [<c124fe4d>] sk_wake_async+0x2d/0x32
> > kernel: [ 3272.351545]  [<c1250004>] sock_def_readable+0x45/0x51
> > kernel: [ 3272.351551]  [<c12b0247>] unix_stream_sendmsg+0x1e2/0x269
> > kernel: [ 3272.351557]  [<c124fe6e>] ? rcu_read_unlock+0x1c/0x1e
> > kernel: [ 3272.351562]  [<c124cf1a>] __sock_sendmsg+0x51/0x5a
> > kernel: [ 3272.351567]  [<c124cff7>] sock_aio_write+0xd4/0xdd
> > kernel: [ 3272.351575]  [<c10a4d95>] do_sync_readv_writev+0x84/0xb7
> > kernel: [ 3272.351582]  [<c10a4288>] ? copy_from_user+0x8/0xa
> > kernel: [ 3272.351587]  [<c10a4e69>] ? rw_copy_check_uvector+0x55/0xc7
> > kernel: [ 3272.351594]  [<c1164082>] ? security_file_permission+0xf/0x11
> > kernel: [ 3272.351599]  [<c10a47e5>] ? rw_verify_area+0x90/0xac
> > kernel: [ 3272.351605]  [<c10a4f58>] do_readv_writev+0x7d/0xdf
> > kernel: [ 3272.351610]  [<c124cf23>] ? sock_aio_write+0x0/0xdd
> > kernel: [ 3272.351615]  [<c1164082>] ? security_file_permission+0xf/0x11
> > kernel: [ 3272.351621]  [<c10a47e5>] ? rw_verify_area+0x90/0xac
> > kernel: [ 3272.351626]  [<c10a4ff3>] vfs_writev+0x39/0x42
> > kernel: [ 3272.351632]  [<c10a5102>] sys_writev+0x3b/0x8c
> > kernel: [ 3272.351637]  [<c10027d3>] sysenter_do_call+0x12/0x32
> > 
> 
> This, I think?
> 
> 
> From: Andrew Morton <akpm@linux-foundation.org>
> 
> Fix a lockdep-splat-causing regression introduced by
> 
> : commit 989a2979205dd34269382b357e6d4b4b6956b889
> : Author:     Eric Dumazet <eric.dumazet@gmail.com>
> : AuthorDate: Wed Apr 14 09:55:35 2010 +0000
> : Commit:     David S. Miller <davem@davemloft.net>
> : CommitDate: Wed Apr 21 16:19:29 2010 -0700
> : 
> :     fasync: RCU and fine grained locking
> 
> kill_fasync() can be called from both process and hard-irq context, so
> fa_lock must be taken with IRQs disabled.
> 
> Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16230
> 
> Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
> Reported-by: Dominik Brodowski <linux@dominikbrodowski.net>
> Cc: Maciej Rutecki <maciej.rutecki@gmail.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
> 
>  fs/fcntl.c |    6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff -puN fs/fcntl.c~fs-fcntlc-kill_fasync_rcu-fa_lock-must-be-irq-safe fs/fcntl.c
> --- a/fs/fcntl.c~fs-fcntlc-kill_fasync_rcu-fa_lock-must-be-irq-safe
> +++ a/fs/fcntl.c
> @@ -733,12 +733,14 @@ static void kill_fasync_rcu(struct fasyn
>  {
>  	while (fa) {
>  		struct fown_struct *fown;
> +		unsigned long flags;
> +
>  		if (fa->magic != FASYNC_MAGIC) {
>  			printk(KERN_ERR "kill_fasync: bad magic number in "
>  			       "fasync_struct!\n");
>  			return;
>  		}
> -		spin_lock(&fa->fa_lock);
> +		spin_lock_irqsave(&fa->fa_lock, flags);
>  		if (fa->fa_file) {
>  			fown = &fa->fa_file->f_owner;
>  			/* Don't send SIGURG to processes which have not set a
> @@ -747,7 +749,7 @@ static void kill_fasync_rcu(struct fasyn
>  			if (!(sig == SIGURG && fown->signum == 0))
>  				send_sigio(fown, fa->fa_fd, band);
>  		}
> -		spin_unlock(&fa->fa_lock);
> +		spin_unlock_irqrestore(&fa->fa_lock, flags);
>  		fa = rcu_dereference(fa->fa_next);
>  	}
>  }
> _
> 
> 
> afaict all other lockers of fa_lock are OK (but one never really knows
> with spin_lock_irq()).
> 
> Guys, please review-and-ack and I'll get it merged up.

Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

^ permalink raw reply

* Re: [RFC] [PATCH] ethtool: Flags for fibre speed switching
From: David Miller @ 2010-06-22 17:17 UTC (permalink / raw)
  To: bhutchings; +Cc: netdev, jgarzik, linux-net-drivers
In-Reply-To: <1276543562.2074.41.camel@achroite.uk.solarflarecom.com>

From: Ben Hutchings <bhutchings@solarflare.com>
Date: Mon, 14 Jun 2010 20:26:02 +0100

> ethtool.h currently defines only SUPPORTED_FIBRE to cover all fibre
> modes.  However, SFP+ slots support both 1G and 10G fibre modules and
> some modules are dual-speed.  Some drivers use the BASE-T flags for SFP+
> modules of all media types, but this is strictly incorrect and can be
> confusing as there are real BASE-T modules for SFP+.  There should be
> distinct flags for fibre modes.  However I'm not sure whether it's worth
> defining flags for each fibre mode (there are quite a few) or only for
> each speed.
> 
> Similarly there is only ADVERTISED_FIBRE to cover all fibre modes.
> Although there is no AN protocol for fibre, an SFP+ NIC effectively
> autonegotiates its speed with the module.  By default, an SFP+ NIC will
> accept both 1G and 10G modules and switch speed automatically.  With a
> dual-speed module, the NIC driver can allow forcing the speed through
> ethtool, but unless it maintains some hidden state it must reset the
> speed whenever the module is hotplugged (perhaps accidentally).  So it
> should be possible for the administrator to control speed selection in a
> sticky way through the advertising mask.

I'm fine with this, feel free to make a formal submission for
net-next-2.6

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox