Netdev List
 help / color / mirror / Atom feed
* [ANNOUNCE]: Release of iptables-1.4.11.1
From: Patrick McHardy @ 2011-06-08 13:54 UTC (permalink / raw)
  To: Netfilter Development Mailinglist, Linux Netdev List,
	netfilter-announce, "'netfilter@vger.kernel.org'

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

The netfilter coreteam presents:

    iptables version 1.4.11.1

a minor release containing bugfixes for problems discovered in
the 1.4.11 release as well as some minor documentation updates.

Due to the large number of changes in 1.4.11, some regressions
and a few minor bugs made it into the release. This version
addresses all identified problems:

- broken inversion support in the owner match

- broken inversion in implicitly loaded protocol extensions, most
  importantly causing "-p tcp ! --syn" to not negate --syn

- symlink installation fixes

- xml translation missing in IPv6 only builds

See the attached changelogs for the full list of changes.

Version 1.4.11.1 can be obtained from:

http://www.netfilter.org/projects/iptables/downloads.html
ftp://ftp.netfilter.org/pub/iptables/
git://git.netfilter.org/iptables.git

On behalf of the Netfilter Core Team.
Happy firewalling!

[-- Attachment #2: changes-iptables-1.4.11.1.txt --]
[-- Type: text/plain, Size: 1089 bytes --]

Elie De Brauwer (1):
      doc: fix trivial typo in libipt_SNAT

Jan Engelhardt (13):
      libxt_owner: restore inversion support
      build: remove dead code parts
      build: fix installation of symlinks
      build: fix absence of xml translator in IPv6-only builds
      doc: update GPL license text
      doc: iptables-xml should be in manpage section 1
      build: move basic preprocessor flags to regular_CPPFLAGS
      build: move kinclude's preprocessor flags to kinclude_CPPFLAGS
      src: move all libiptc pieces into its directory
      src: move all iptables pieces into a separate directory
      tests: add some sample rulesets to test save-restore cycle
      option: fix ignored negation before implicit extension loading
      build: re-add missing CPPFLAGS for libiptc

Maciej Żenczykowski (1):
      xtables-multi: fix absence of xml translator in IPv6-only builds

Mike Frysinger (1):
      build: move remaining preprocessor flags to CPPFLAGS

Patrick McHardy (1):
      Bump version to 1.4.11.1

Vlad Dogaru (1):
      doc: fix MASQUERADE section of man page


^ permalink raw reply

* Look for physical address from user space address/fixup - NET_DMA
From: Michal Simek @ 2011-06-08 14:45 UTC (permalink / raw)
  To: Eric Dumazet, netdev, David Miller, Andrew Morton, Ingo Molnar,
	Thomas 

Hi,

I do some investigation how to speedup memory operations 
(memcopy/memset/copy_tofrom_user/etc) by dma to improve ethernet performance 
(currently for PAGE_SIZE operations).

I profiled kernel and copy_tofrom_user is the weakest place for network 
operations. I have optimize it by loop unrolling which gave me 20% better 
throughput but still no enough.

Then I added hw dma to the design and changed u-boot mem operations (saved me 5s 
in bootup time - loading 20MB kernel through 100Mbit/s LAN) and also I have add 
support to Linux memcpy (haven't measured improvement but there is some).

For copy_tofrom_user is situation a little bit complicated but I have prototyped 
it by dma without fixup to see improvement. There could be next 20%.

Based on this I have measured spending time on this code and I found that most 
of the time is spent on looking for physical address from user space address.
I need to get physical address because dma requires it. It is around 70% of 
total time.

I use for Microblaze the part of code shown below but it is slow. Do you know 
how to do it faster?

	pmd_t *pmdp;
	pte_t *ptep;
	pmdp = pmd_offset(pud_offset(
			pgd_offset(current->mm, address),
					address), address);

	preempt_disable();
	ptep = pte_offset_map(pmdp, address);
	if (pte_present(*ptep)) {
		address = (unsigned long) page_address(pte_page(*ptep));
		/* MS: I need add offset in page */
		address += address & ~PAGE_MASK;
		/* MS address is virtual */
		address = virt_to_phys(address);
	}
	pte_unmap(ptep);
	preempt_enable();


Currently this is my bottleneck to get better improvement.

Not sure if someone has ever tried to replace by dma with fixup support. That's 
the second thing where I would like to hear your opinion. Would it be possible 
to simplify it by access user space address and address + PAGE_SIZE? Or any 
other scheme?

There is also one option NET_DMA where I expect that dma will be used instead of 
mem operations. Is it correct assumption? Because I see that there are no irqs 
coming from dma. Dma test is working well.

Eric, David: How is it supposed to work?


Thanks,
Michal


-- 
Michal Simek, Ing. (M.Eng)
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* [PATCH] netfilter: fix looped (broad|multi)cast's bogus MACs in NFQUEUE
From: Nicolas Cavallari @ 2011-06-08 15:18 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev

By default, when broadcast or multicast packet are sent from a local
application, they are sent to the interface then looped by the kernel
to other local applications, going throught netfilter hooks in the process.

These looped packet have their MAC header removed from the skb by the kernel
looping code.
This confuse netfilter's netlink queue because it tries to extract a hardware
address from these packets, but extracts a part of the IP header instead.

This patch prevent NFQUEUE to include a MAC header in the netlink message
if there is none.

Signed-off-by: Nicolas Cavallari <cavallar@lri.fr>
---
To reproduce the bug, run libnetfilter_queue's nfqnl_test.c and add
some iptables -j NFQUEUE rule in PREROUTING.
Then, either ping -b 255.255.255.255 or ping nonexistenthost.local (if
avahi or another multicast dns client is configured)

If you see MAC addresses like 40:00:ff:11:0d::70 (for mdns) or
 00:00:80:11:70:62 then you can see that they match this part of the packet's
ip header :

               |flags| fragment offset|
 |ttl| protocol|       checksum       |

patch done against 2.6.39.1 but should also apply to nf-next
---
--- linux-2.6.39.1/net/netfilter/nfnetlink_queue.c	2011-06-08 14:43:41.188003302 +0200
+++ linux-2.6.39.1/net/netfilter/nfnetlink_queue.c	2011-06-08 14:46:10.892003541 +0200
@@ -335,7 +335,8 @@ nfqnl_build_packet_message(struct nfqnl_
 	if (entskb->mark)
 		NLA_PUT_BE32(skb, NFQA_MARK, htonl(entskb->mark));
 
-	if (indev && entskb->dev) {
+	if (indev && entskb->dev &&
+	    entskb->network_header != entskb->mac_header) {
 		struct nfqnl_msg_packet_hw phw;
 		int len = dev_parse_header(entskb, phw.hw_addr);
 		if (len) {

^ permalink raw reply

* Re: [PATCH] netfilter: fix looped (broad|multi)cast's bogus MACs in NFQUEUE
From: Florian Westphal @ 2011-06-08 15:30 UTC (permalink / raw)
  To: Nicolas Cavallari; +Cc: Patrick McHardy, netfilter-devel, netdev
In-Reply-To: <20110608151817.C95E24587D@pc11-132.lri.fr>

Nicolas Cavallari <Nicolas.Cavallari@lri.fr> wrote:
> By default, when broadcast or multicast packet are sent from a local
> application, they are sent to the interface then looped by the kernel
> to other local applications, going throught netfilter hooks in the process.
> 
> These looped packet have their MAC header removed from the skb by the kernel
> looping code.
> This confuse netfilter's netlink queue because it tries to extract a hardware
> address from these packets, but extracts a part of the IP header instead.

[..]

> patch done against 2.6.39.1 but should also apply to nf-next
> ---
> --- linux-2.6.39.1/net/netfilter/nfnetlink_queue.c	2011-06-08 14:43:41.188003302 +0200
> +++ linux-2.6.39.1/net/netfilter/nfnetlink_queue.c	2011-06-08 14:46:10.892003541 +0200
> @@ -335,7 +335,8 @@ nfqnl_build_packet_message(struct nfqnl_
>  	if (entskb->mark)
>  		NLA_PUT_BE32(skb, NFQA_MARK, htonl(entskb->mark));
>  
> -	if (indev && entskb->dev) {
> +	if (indev && entskb->dev &&
> +	    entskb->network_header != entskb->mac_header) {

nfnetlink_log has the same problem.

^ permalink raw reply

* Fw: [Bug 36122] New: New cache learned PMTU information in inetpeer causes ssh to fail when tunneled via an IPSEC VPN
From: Stephen Hemminger @ 2011-06-08 15:43 UTC (permalink / raw)
  To: David Miller; +Cc: netdev



Begin forwarded message:

Date: Sat, 28 May 2011 21:50:29 GMT
From: bugzilla-daemon@bugzilla.kernel.org
To: shemminger@linux-foundation.org
Subject: [Bug 36122] New: New cache learned PMTU information in inetpeer causes ssh to fail when tunneled via an IPSEC VPN


https://bugzilla.kernel.org/show_bug.cgi?id=36122

               URL: http://bugs.gentoo.org/show_bug.cgi?id=369025
           Summary: New cache learned PMTU information in inetpeer causes
                    ssh to fail when tunneled via an IPSEC VPN
           Product: Networking
           Version: 2.5
    Kernel Version: 2.6.39
          Platform: All
        OS/Version: Linux
              Tree: Mainline
            Status: NEW
          Severity: normal
          Priority: P1
         Component: IPV4
        AssignedTo: shemminger@linux-foundation.org
        ReportedBy: blueness@gentoo.org
                CC: kernel@gentoo.org
        Regression: No


When trying to ssh from a box running 2.6.39 on one private subnet to another
box on another private subnet via an IPSEC vpn, ssh freezes and times out at:

   debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP

This was traced down to commit 2c8cec5c10bced2408082a6656170e74ac17231c.

This type of error is known to occur when there is fragmentation due to
mismatched mtu's which the commit addresses.

Notice the problem does not occur when ssh-ing directly, ie not via an IPSEC
tunnel.  I have not tested if other tunnels are affected.

Please see the downstream bug for more details.

-- 
Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

^ permalink raw reply

* Fw: [Bridge] IGMP snooping not filtering multicast messages
From: Stephen Hemminger @ 2011-06-08 15:44 UTC (permalink / raw)
  To: Herbert Xu; +Cc: netdev



Begin forwarded message:

Date: Tue, 31 May 2011 19:48:52 +0200 (CEST)
From: "maxd@inwind.it" <maxd@inwind.it>
To: bridge@lists.linux-foundation.org
Subject: [Bridge] IGMP snooping not filtering multicast messages


Hi. I have a partial mesh network composed by Linux nodes. Each linux node may 
have up to 4 ethernet interfaces, which are exploited to create point-to-point 
connections with other linux nodes. I have bridged the ethernet interfaces in 
each node, so that the whole network, which is physically composed by a set of 
network segments, appears as a single layer-2 domain. I have enabled spanning 
tree to avoid loops. In this scenario, I would like to exploit the IGMP 
snooping functionality, but it seems that it is not working properly. I am 
using iperf to set a multicast source (iperf client) and a few multicast sinks 
in the network (iperf servers). I am using tcpdump, instead, to check where 
multicast messages are received. What I notice is that there is apparently no 
filtering of the multicast messages, that are always flooded in the network. I 
tried to repeat the test varying the multicast address (paying attention not to 
get reserved addresses), with and without multicast clients set, with the 
multicast_router option set to 1 (default) and to 0. To double check that IGMP 
is working, I have also tried to disable it; the only difference I see is that 
tcpdump does not show IGMP query messages when the IGMP snooping is disabled. 
So, I am wondering if the IGMP snooping implementation currently available can 
deal with my scenario. In particular, I would stress the following points that 
I think might be relevant:
-I have no multicast router in my network (it looks like a single stand-alone 
lan)
-Each node acts as a bridge, so I have multiple bridges in my network, 
connected each other.
Any idea would be greatly appreciated!

Massimiliano
_______________________________________________
Bridge mailing list
Bridge@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/bridge

^ permalink raw reply

* [PATCH net-next-2.6] net: pmtu_expires fixes
From: Eric Dumazet @ 2011-06-08 16:07 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

commit 2c8cec5c10bc (ipv4: Cache learned PMTU information in inetpeer)
added some racy peer->pmtu_expires accesses.

As its value can be changed by another cpu/thread, we should be more
careful, reading its value once.

Add peer_pmtu_expired() and peer_pmtu_cleaned() helpers

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv4/route.c |   78 +++++++++++++++++++++++++--------------------
 1 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 52b0b95..045f0ec 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1316,6 +1316,23 @@ reject_redirect:
 	;
 }
 
+static bool peer_pmtu_expired(struct inet_peer *peer)
+{
+	unsigned long orig = ACCESS_ONCE(peer->pmtu_expires);
+
+	return orig &&
+	       time_after_eq(jiffies, orig) &&
+	       cmpxchg(&peer->pmtu_expires, orig, 0) == orig;
+}
+
+static bool peer_pmtu_cleaned(struct inet_peer *peer)
+{
+	unsigned long orig = ACCESS_ONCE(peer->pmtu_expires);
+
+	return orig &&
+	       cmpxchg(&peer->pmtu_expires, orig, 0) == orig;
+}
+
 static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 {
 	struct rtable *rt = (struct rtable *)dst;
@@ -1331,14 +1348,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 						rt_genid(dev_net(dst->dev)));
 			rt_del(hash, rt);
 			ret = NULL;
-		} else if (rt->peer &&
-			   rt->peer->pmtu_expires &&
-			   time_after_eq(jiffies, rt->peer->pmtu_expires)) {
-			unsigned long orig = rt->peer->pmtu_expires;
-
-			if (cmpxchg(&rt->peer->pmtu_expires, orig, 0) == orig)
-				dst_metric_set(dst, RTAX_MTU,
-					       rt->peer->pmtu_orig);
+		} else if (rt->peer && peer_pmtu_expired(rt->peer)) {
+			dst_metric_set(dst, RTAX_MTU, rt->peer->pmtu_orig);
 		}
 	}
 	return ret;
@@ -1531,8 +1542,10 @@ unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph,
 
 static void check_peer_pmtu(struct dst_entry *dst, struct inet_peer *peer)
 {
-	unsigned long expires = peer->pmtu_expires;
+	unsigned long expires = ACCESS_ONCE(peer->pmtu_expires);
 
+	if (!expires)
+		return;
 	if (time_before(jiffies, expires)) {
 		u32 orig_dst_mtu = dst_mtu(dst);
 		if (peer->pmtu_learned < orig_dst_mtu) {
@@ -1555,10 +1568,11 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 		rt_bind_peer(rt, rt->rt_dst, 1);
 	peer = rt->peer;
 	if (peer) {
+		unsigned long pmtu_expires = ACCESS_ONCE(peer->pmtu_expires);
+
 		if (mtu < ip_rt_min_pmtu)
 			mtu = ip_rt_min_pmtu;
-		if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
-			unsigned long pmtu_expires;
+		if (!pmtu_expires || mtu < peer->pmtu_learned) {
 
 			pmtu_expires = jiffies + ip_rt_mtu_expires;
 			if (!pmtu_expires)
@@ -1612,13 +1626,14 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
 			rt_bind_peer(rt, rt->rt_dst, 0);
 
 		peer = rt->peer;
-		if (peer && peer->pmtu_expires)
+		if (peer) {
 			check_peer_pmtu(dst, peer);
 
-		if (peer && peer->redirect_learned.a4 &&
-		    peer->redirect_learned.a4 != rt->rt_gateway) {
-			if (check_peer_redir(dst, peer))
-				return NULL;
+			if (peer->redirect_learned.a4 &&
+			    peer->redirect_learned.a4 != rt->rt_gateway) {
+				if (check_peer_redir(dst, peer))
+					return NULL;
+			}
 		}
 
 		rt->rt_peer_genid = rt_peer_genid();
@@ -1649,14 +1664,8 @@ static void ipv4_link_failure(struct sk_buff *skb)
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 
 	rt = skb_rtable(skb);
-	if (rt &&
-	    rt->peer &&
-	    rt->peer->pmtu_expires) {
-		unsigned long orig = rt->peer->pmtu_expires;
-
-		if (cmpxchg(&rt->peer->pmtu_expires, orig, 0) == orig)
-			dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig);
-	}
+	if (rt && rt->peer && peer_pmtu_cleaned(rt->peer))
+		dst_metric_set(&rt->dst, RTAX_MTU, rt->peer->pmtu_orig);
 }
 
 static int ip_rt_bug(struct sk_buff *skb)
@@ -1770,8 +1779,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
 			       sizeof(u32) * RTAX_MAX);
 		dst_init_metrics(&rt->dst, peer->metrics, false);
 
-		if (peer->pmtu_expires)
-			check_peer_pmtu(&rt->dst, peer);
+		check_peer_pmtu(&rt->dst, peer);
 		if (peer->redirect_learned.a4 &&
 		    peer->redirect_learned.a4 != rt->rt_gateway) {
 			rt->rt_gateway = peer->redirect_learned.a4;
@@ -2775,7 +2783,8 @@ static int rt_fill_info(struct net *net,
 	struct rtable *rt = skb_rtable(skb);
 	struct rtmsg *r;
 	struct nlmsghdr *nlh;
-	long expires;
+	long expires = 0;
+	const struct inet_peer *peer = rt->peer;
 	u32 id = 0, ts = 0, tsage = 0, error;
 
 	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
@@ -2823,15 +2832,16 @@ static int rt_fill_info(struct net *net,
 		NLA_PUT_BE32(skb, RTA_MARK, rt->rt_mark);
 
 	error = rt->dst.error;
-	expires = (rt->peer && rt->peer->pmtu_expires) ?
-		rt->peer->pmtu_expires - jiffies : 0;
-	if (rt->peer) {
+	if (peer) {
 		inet_peer_refcheck(rt->peer);
-		id = atomic_read(&rt->peer->ip_id_count) & 0xffff;
-		if (rt->peer->tcp_ts_stamp) {
-			ts = rt->peer->tcp_ts;
-			tsage = get_seconds() - rt->peer->tcp_ts_stamp;
+		id = atomic_read(&peer->ip_id_count) & 0xffff;
+		if (peer->tcp_ts_stamp) {
+			ts = peer->tcp_ts;
+			tsage = get_seconds() - peer->tcp_ts_stamp;
 		}
+		expires = ACCESS_ONCE(peer->pmtu_expires);
+		if (expires)
+			expires -= jiffies;
 	}
 
 	if (rt_is_input_route(rt)) {



^ permalink raw reply related

* Re: [RFC] should we care of COMPAT mode in bridge ?
From: Stephen Hemminger @ 2011-06-08 16:08 UTC (permalink / raw)
  To: David Miller; +Cc: eric.dumazet, netdev
In-Reply-To: <20110607.172727.634954568306893152.davem@davemloft.net>

On Tue, 07 Jun 2011 17:27:27 -0700 (PDT)
David Miller <davem@davemloft.net> wrote:

> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Tue, 7 Jun 2011 16:51:34 -0700
> 
> > The problem is that most of the other ioctl's won't work because of use of
> > SIOCDEVPRIVATE.
> 
> As we discussed we can pass SIOCDEVPRIVATE requests down to the driver
> just like we do for all kinds of other compat ioctls.

Ok. patches accepted, but not spending my time on it.

^ permalink raw reply

* Re: [PATCH] vlan: Fix the ingress VLAN_FLAG_REORDER_HDR check v2
From: Jiri Pirko @ 2011-06-08 16:28 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: David Miller, shemminger, greearb, nicolas.2p.debian, xiaosuo,
	netdev, kaber, fubar, eric.dumazet, andy, jesse
In-Reply-To: <m11uzcidvq.fsf_-_@fess.ebiederm.org>

Thu, Jun 02, 2011 at 03:03:53PM CEST, ebiederm@xmission.com wrote:
>
>Testing of VLAN_FLAG_REORDER_HDR does not belong in vlan_untag
>but rather in vlan_do_receive.  Otherwise the vlan header
>will not be properly put on the packet in the case of
>vlan header accelleration.
>
>As we remove the check from vlan_check_reorder_header
>rename it vlan_reorder_header to keep the naming clean.
>
>Fix up the skb->pkt_type early so we don't look at the packet
>after adding the vlan tag, which guarantees we don't goof
>and look at the wrong field.
>
>Use a simple if statement instead of a complicated switch
>statement to decided that we need to increment rx_stats
>for a multicast packet.
>
>Hopefully at somepoint we will just declare the case where
>VLAN_FLAG_REORDER_HDR is cleared as unsupported and remove
>the code.  Until then this keeps it working correctly.

Why we can't remove this right away?

^ permalink raw reply

* Re: KVM induced panic on 2.6.38[2367] & 2.6.39
From: Brad Campbell @ 2011-06-08 17:02 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Patrick McHardy, Bart De Schuymer, kvm, linux-mm, linux-kernel,
	netdev, netfilter-devel
In-Reply-To: <1307505541.3102.12.camel@edumazet-laptop>

On 08/06/11 11:59, Eric Dumazet wrote:

> Well, a bisection definitely should help, but needs a lot of time in
> your case.

Yes. compile, test, crash, walk out to the other building to press 
reset, lather, rinse, repeat.

I need a reset button on the end of a 50M wire, or a hardware watchdog!

Actually it's not so bad. If I turn off slub debugging the kernel panics 
and reboots itself.

This.. :
[    2.913034] netconsole: remote ethernet address 00:16:cb:a7:dd:d1
[    2.913066] netconsole: device eth0 not up yet, forcing it
[    3.660062] Refined TSC clocksource calibration: 3213.422 MHz.
[    3.660118] Switching to clocksource tsc
[   63.200273] r8169 0000:03:00.0: eth0: unable to load firmware patch 
rtl_nic/rtl8168e-1.fw (-2)
[   63.223513] r8169 0000:03:00.0: eth0: link down
[   63.223556] r8169 0000:03:00.0: eth0: link down

..is slowing down reboots considerably. 3.0-rc does _not_ like some 
timing hardware in my machine. Having said that, at least it does not 
randomly panic on SCSI like 2.6.39 does.

Ok, I've ruled out TCPMSS. Found out where it was being set and neutered 
it. I've replicated it with only the single DNAT rule.


> Could you try following patch, because this is the 'usual suspect' I had
> yesterday :
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 46cbd28..9f548f9 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -792,6 +792,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
>   		fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
>   	}
>
> +#if 0
>   	if (fastpath&&
>   	size + sizeof(struct skb_shared_info)<= ksize(skb->head)) {
>   		memmove(skb->head + size, skb_shinfo(skb),
> @@ -802,7 +803,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
>   		off = nhead;
>   		goto adjust_others;
>   	}
> -
> +#endif
>   	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
>   	if (!data)
>   		goto nodata;
>
>
>

Nope.. that's not it. <sigh> That might have changed the characteristic 
of the fault slightly, but unfortunately I got caught with a couple of 
fsck's, so I only got to test it 3 times tonight.

It's unfortunate that this is a production system, so I can only take it 
down between about 9pm and 1am. That would normally be pretty 
productive, except that an fsck of a 14TB ext4 can take 30 minutes if it 
panics at the wrong time.

I'm out of time tonight, but I'll have a crack at some bisection 
tomorrow night. Now I just have to go back far enough that it works, and 
be near enough not to have to futz around with /proc /sys or drivers.

I really, really, really appreciate you guys helping me with this. It 
has been driving me absolutely bonkers. If I'm ever in the same town as 
any of you, dinner and drinks are on me.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH] RFC2988bis + taking RTT sample from 3WHS for the passive open side
From: Jerry Chu @ 2011-06-08 17:04 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, Hagen Paul Pfeifer, tsunanet,
	netdev@vger.kernel.org
In-Reply-To: <1307550654.3057.70.camel@edumazet-laptop>

+netdev (add missing cc)

On Wed, Jun 8, 2011 at 9:30 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
> Le mardi 07 juin 2011 à 22:00 -0700, H.K. Jerry Chu a écrit :
> > From: Jerry Chu <hkchu@google.com>
> >
> > This patch lowers the default initRTO from 3secs to 1sec per
> > RFC2988bis. It falls back to 3secs if the SYN or SYN-ACK packet
> > has been retransmitted, AND the TCP timestamp option is not on.
> >
> > It also adds support to take RTT sample during 3WHS on the passive
> > open side, just like its active open counterpart, and uses it, if
> > valid, to seed the initRTO for the data transmission phase.
> >
> > The patch also resets ssthresh to its initial default at the
> > beginning of the data transmission phase, and reduces cwnd to 1 if
> > there has been MORE THAN ONE retransmission during 3WHS per RFC5681.
> >
> > Signed-off-by: H.K. Jerry Chu <hkchu@google.com>
> > ---
>
> ...
>
> > @@ -1854,7 +1859,7 @@ static int tcp_v4_init_sock(struct sock *sk)
> >        * algorithms that we must have the following bandaid to talk
> >        * efficiently to them.  -DaveM
> >        */
> > -     tp->snd_cwnd = 2;
> > +     tp->snd_cwnd = TCP_INIT_CWND;
>
> Hmm, are you sure this belongs to this patch ?
>
> >
> >       /* See draft-stevens-tcpca-spec-01 for discussion of the
> >        * initialization of these values.
> > diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
> > index 80b1f80..d2fe4e0 100644
> > --- a/net/ipv4/tcp_minisocks.c
> > +++ b/net/ipv4/tcp_minisocks.c
> > @@ -486,7 +486,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
> >                * algorithms that we must have the following bandaid to talk
> >                * efficiently to them.  -DaveM
> >                */
> > -             newtp->snd_cwnd = 2;
> > +             newtp->snd_cwnd = TCP_INIT_CWND;
>
> same here ?

It's part of the cwnd initialization stuff, which I included some fix
per RFC5681 (in
tcp_init_metrics()). The field is currently not being used anyway
until data-in-SYN is
supported. I fixed it here just because TCP_INIT_CWND is the right value.

>
> >               newtp->snd_cwnd_cnt = 0;
> >               newtp->bytes_acked = 0;
> >
> > @@ -720,6 +720,10 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
> >               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP);
> >               return NULL;
> >       }
> > +     if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)
> > +             tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;
> > +     else if (req->retrans) /* don't take RTT sample if retrans && ~TS */
> > +             tcp_rsk(req)->snt_synack = 0;
>
> Could you clarify why this is done in this order ?

What else is more appropriate? It needs to decide if we've got a valid
RTT sample.
If TS is on and rcv_tsec != 0 then we've got a valid RTT sample. Otherwise it
does not take sample if there has been retrans per Karn's algorithm.

Thanks,

Jerry

>
> Thanks !
>
>

^ permalink raw reply

* Configure Distributed Switch Architecture Via Device Tree
From: Barry G @ 2011-06-08 17:18 UTC (permalink / raw)
  To: netdev

Hello,

We are working on bringing up a powerpc platform that has a few
Marvell switches on it.  We would like to make use of the DSA
stuff in the kernel.

It appears all the devices currently in the kernel that use DSA
are done via the platform_add_devices route.  I was hoping
to use the device tree since most of the powerpc stuff does.

My main two questions right now are:
How do I pull together the various components into the
dsa structures and how do I register that structure with
the dsa subsystem.

I added the following to my device tree:
   virtual-device {
      compatible = "simple-bus";
      dsa {
         compatible = "vendor,my-dsa-of";
         ethernet-handle = <&enet0>;
         mdio-handle = <&mdio0>;
      };
   };

And wrote the attached driver.  It loads at boot, so I
know the compatible stuff is working and all, but
I am a little lost as to the next steps.  Any help
would be much appreciated.

Thanks,

Barry


Here is my first hack at a drive:
#include <linux/of.h>
#include <linux/kernel.h>
#include <linux/of_platform.h>
#include <net/dsa.h>

static struct dsa_chip_data switches[] = {
   {
      .sw_addr = 0,
      .port_names = {
         "eth%d", //0
         "eth%d", //1
         "eth%d", //2
         "eth%d", //3
         "eth%d", //4
         "eth%d", //5
         "eth%d", //6
         "eth%d", //7
         "dsa",   //8
         "dsa",   //9
      },
      .rtable = (s8 []){-1, 8, 9},
   },
   {
      .sw_addr = 1,
      .port_names = {
         "eth%d", //0
         "eth%d", //1
         "eth%d", //2
         "eth%d", //3
         "eth%d", //4
         "eth%d", //5
         "eth%d", //6
         "eth%d", //7
         "dsa",   //8
         "dsa",   //9
         "cpu",   //10
      },
      .rtable = (s8 []){9, -1, 8},
   },
   {
      .sw_addr = 2,
      .port_names = {
         "eth%d", //0
         "eth%d", //1
         "eth%d", //2
         "eth%d", //3
         "eth%d", //4
         "eth%d", //5
         "eth%d", //6
         "eth%d", //7
         "dsa",   //8
         "dsa",   //9
         NULL,    //10
      },
      .rtable = (s8 []){8, 9, -1},
   },
};

static struct dsa_platform_data my_switch_data = {
   .nr_chips = 3,
   .chip = switches,
};

static int __devinit dsa_probe(struct platform_device *);
static int __devexit dsa_remove(struct platform_device *);

static const struct of_device_id dsa_match[] = {
   {
      .compatible = "vendor,my-dsa-of",
   },
   {}
};

static struct platform_driver dsa_driver = {
   .driver = {
      .name = "dsa-driver",
      .owner = THIS_MODULE,
      .of_match_table = dsa_match,
   },
   .probe = dsa_probe,
   .remove = dsa_remove,
};

static int __devinit dsa_probe(struct platform_device *pdev)
{
   /* Question 1:
      I need to hookup the mii_bus in the dsa_chip_data and
      the netdev in the dsa_platform_data to the various
      struct device *s.  I could get access to the device nodes
      like:

      ph = of_get_property(np, "mdio-handle", NULL);
      mdio = of_find_node_by_phandle(*ph);

      Now I have the mdio device_node, but what do I do with
      it?  How do I get the device *?

      */

   /* Question 2: Whats the entry point into the DSA stuff
      now that I have my snazzy chips setup in the
      my_switch_data?  Usually it is added as a stamp device
      ad added with platform_add_devices.  Do I need to edit
      the DSA stuff to work with OF devices? */


   dev_info(&pdev->dev, "Initializing OF Marvell DSA driver\n");

   return 0;
}

static int __devexit dsa_remove(struct platform_device *pdev)
{
   printk("dsa_remove\n");
   return 0;
}


static int __init dsa_driver_init(void)
{
   printk("dsa_drver_init\n");
   return platform_driver_register(&dsa_driver);
}

static void __exit dsa_driver_cleanup(void)
{
   printk("dsa_driver_cleanup\n");
   platform_driver_unregister(&dsa_driver);
}

module_init(dsa_driver_init);
module_exit(dsa_driver_cleanup);

MODULE_DESCRIPTION("Marvell DSA OF driver");
MODULE_AUTHOR("Barry G <mr.scada@gmail.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:dsa-driver");

^ permalink raw reply

* [PATCH 0/3] Add support for MSM_IPC Router
From: Karthikeyan Ramasubramanian @ 2011-06-08 17:49 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-arm-msm, Karthikeyan Ramasubramanian

The following series of patches add support for Mobile Station Mode
IPC message Router. The MSM_IPC Router provides a connectionless
message oriented routing mechanism between the processes running
in Qualcomm MSM. Patch 1 adds support for routing functionality.
Patch 2 adds user-space interface support to the MSM_IPC Router.
Patch 3 adds support for the MSM_IPC Router to interface with the
MSM Shared Memory Driver.

This patch series applies to current net-next-2.6.

Please review and consider to apply,
Karthik

Karthikeyan Ramasubramanian (3):
  net: msm_ipc: Add Mobile Station Mode IPC Router
  net: msm_ipc: Add user-space support for MSM_IPC Router
  net: msm_ipc: Add SMD Transport to the MSM_IPC Router

 include/linux/msm_ipc.h               |   74 ++
 include/linux/socket.h                |    5 +-
 net/Kconfig                           |    2 +-
 net/Makefile                          |    1 +
 net/msm_ipc/Kconfig                   |   24 +
 net/msm_ipc/Makefile                  |    4 +
 net/msm_ipc/msm_ipc_router.c          | 1760 +++++++++++++++++++++++++++++++++
 net/msm_ipc/msm_ipc_router.h          |  195 ++++
 net/msm_ipc/msm_ipc_router_smd_xprt.c |  226 +++++
 net/msm_ipc/msm_ipc_socket.c          |  520 ++++++++++
 10 files changed, 2809 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/msm_ipc.h
 create mode 100644 net/msm_ipc/Kconfig
 create mode 100644 net/msm_ipc/Makefile
 create mode 100644 net/msm_ipc/msm_ipc_router.c
 create mode 100644 net/msm_ipc/msm_ipc_router.h
 create mode 100644 net/msm_ipc/msm_ipc_router_smd_xprt.c
 create mode 100644 net/msm_ipc/msm_ipc_socket.c

-- 
1.7.3.3

Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* [PATCH 1/3] net: msm_ipc: Add Mobile Station Mode IPC Router
From: Karthikeyan Ramasubramanian @ 2011-06-08 17:50 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-arm-msm, Karthikeyan Ramasubramanian

The MSM_IPC Router provides a connectionless message oriented
routing mechanism between the processes running in Qualcomm MSM.
The MSM_IPC Router uses the client/server model in order to provide
this routing service.

Change-Id: I0ad4e3453d4708956d732430aa341f201a81a41d
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
---
 include/linux/msm_ipc.h      |   27 +
 net/Kconfig                  |    2 +-
 net/Makefile                 |    1 +
 net/msm_ipc/Kconfig          |   15 +
 net/msm_ipc/Makefile         |    3 +
 net/msm_ipc/msm_ipc_router.c | 1671 ++++++++++++++++++++++++++++++++++++++++++
 net/msm_ipc/msm_ipc_router.h |  187 +++++
 7 files changed, 1905 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/msm_ipc.h
 create mode 100644 net/msm_ipc/Kconfig
 create mode 100644 net/msm_ipc/Makefile
 create mode 100644 net/msm_ipc/msm_ipc_router.c
 create mode 100644 net/msm_ipc/msm_ipc_router.h

diff --git a/include/linux/msm_ipc.h b/include/linux/msm_ipc.h
new file mode 100644
index 0000000..47d678c
--- /dev/null
+++ b/include/linux/msm_ipc.h
@@ -0,0 +1,27 @@
+#ifndef _LINUX_MSM_IPC_H_
+#define _LINUX_MSM_IPC_H_
+
+#include <linux/types.h>
+
+#define MSM_IPC_ADDR_NAME               1
+#define MSM_IPC_ADDR_ID                 2
+
+struct msm_ipc_port_addr {
+	uint32_t node_id;
+	uint32_t port_id;
+};
+
+struct msm_ipc_port_name {
+	uint32_t service;
+	uint32_t instance;
+};
+
+struct msm_ipc_addr {
+	unsigned char  addrtype;
+	union {
+		struct msm_ipc_port_addr port_addr;
+		struct msm_ipc_port_name port_name;
+	} addr;
+};
+
+#endif
diff --git a/net/Kconfig b/net/Kconfig
index 79cabf1..b2d8e4e 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -308,6 +308,6 @@ source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
 source "net/caif/Kconfig"
 source "net/ceph/Kconfig"
-
+source "net/msm_ipc/Kconfig"
 
 endif   # if NET
diff --git a/net/Makefile b/net/Makefile
index a51d946..0820826 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_WIMAX)		+= wimax/
 obj-$(CONFIG_DNS_RESOLVER)	+= dns_resolver/
 obj-$(CONFIG_CEPH_LIB)		+= ceph/
 obj-$(CONFIG_BATMAN_ADV)	+= batman-adv/
+obj-$(CONFIG_MSM_IPC)		+= msm_ipc/
diff --git a/net/msm_ipc/Kconfig b/net/msm_ipc/Kconfig
new file mode 100644
index 0000000..9114d7d
--- /dev/null
+++ b/net/msm_ipc/Kconfig
@@ -0,0 +1,15 @@
+#
+# MSM_IPC net configurations
+#
+
+menuconfig MSM_IPC
+	tristate "MSM_IPC support"
+	default n
+	---help---
+	The "Mobile Station Modem Inter-Process Communication" (MSM_IPC)
+	is a connectionless message/packet oriented Routing protocol
+	developed by Qualcomm for use with its modems. It is accessed
+	from user space as sockets (PF_MSM_IPC).
+
+	Say Y (or M) here if you build for a phone product (e.g. Android)
+	that uses MSM_IPC as transport, if unsure say N.
diff --git a/net/msm_ipc/Makefile b/net/msm_ipc/Makefile
new file mode 100644
index 0000000..461c510
--- /dev/null
+++ b/net/msm_ipc/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MSM_IPC) := msm_ipc.o
+
+msm_ipc-y += msm_ipc_router.o
diff --git a/net/msm_ipc/msm_ipc_router.c b/net/msm_ipc/msm_ipc_router.c
new file mode 100644
index 0000000..76deacb
--- /dev/null
+++ b/net/msm_ipc/msm_ipc_router.c
@@ -0,0 +1,1671 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <asm/byteorder.h>
+
+#include "msm_ipc_router.h"
+
+static LIST_HEAD(control_ports);
+static DEFINE_MUTEX(control_ports_lock);
+
+#define LP_HASH_SIZE 32
+static struct list_head local_ports[LP_HASH_SIZE];
+static DEFINE_MUTEX(local_ports_lock);
+
+#define SRV_HASH_SIZE 32
+static struct list_head server_list[SRV_HASH_SIZE];
+static DEFINE_MUTEX(server_list_lock);
+static wait_queue_head_t newserver_wait;
+
+struct msm_ipc_server {
+	struct list_head list;
+	struct msm_ipc_port_name name;
+	struct list_head server_port_list;
+};
+
+struct msm_ipc_server_port {
+	struct list_head list;
+	struct msm_ipc_port_addr server_addr;
+};
+
+#define RP_HASH_SIZE 32
+struct msm_ipc_router_remote_port {
+	struct list_head list;
+	uint32_t node_id;
+	uint32_t port_id;
+	wait_queue_head_t quota_wait;
+	uint32_t tx_quota_cnt;
+	struct mutex quota_lock;
+};
+
+struct msm_ipc_router_xprt_info {
+	struct list_head list;
+
+	struct msm_ipc_router_xprt *xprt;
+	uint32_t remote_node_id;
+	uint32_t initialized;
+	struct list_head pkt_list;
+	wait_queue_head_t read_wait;
+	struct mutex rx_lock;
+	struct mutex tx_lock;
+	uint32_t need_len;
+	struct work_struct read_data;
+	struct workqueue_struct *workqueue;
+};
+
+#define RT_HASH_SIZE 4
+struct msm_ipc_routing_table_entry {
+	struct list_head list;
+	uint32_t node_id;
+	struct list_head remote_port_list[RP_HASH_SIZE];
+	struct msm_ipc_router_xprt_info *xprt_info;
+	struct mutex lock;
+	unsigned long num_tx_bytes;
+	unsigned long num_rx_bytes;
+};
+
+static struct list_head routing_table[RT_HASH_SIZE];
+static DEFINE_MUTEX(routing_table_lock);
+static int routing_table_inited;
+
+static LIST_HEAD(msm_ipc_board_dev_list);
+static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
+
+static void do_read_data(struct work_struct *work);
+
+static LIST_HEAD(xprt_info_list);
+static DEFINE_MUTEX(xprt_info_list_lock);
+
+static uint32_t next_port_id;
+static DEFINE_MUTEX(next_port_id_lock);
+
+enum {
+	CLIENT_PORT,
+	SERVER_PORT,
+	CONTROL_PORT,
+};
+
+enum {
+	DOWN,
+	UP,
+};
+
+static void init_routing_table(void)
+{
+	int i;
+	for (i = 0; i < RT_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&routing_table[i]);
+}
+
+static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
+	uint32_t node_id)
+{
+	int i;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
+			   GFP_KERNEL);
+	if (!rt_entry) {
+		pr_err("%s: rt_entry allocation failed for %d\n",
+			__func__, node_id);
+		return NULL;
+	}
+
+	for (i = 0; i < RP_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
+
+	mutex_init(&rt_entry->lock);
+	rt_entry->node_id = node_id;
+	rt_entry->xprt_info = NULL;
+	return rt_entry;
+}
+
+/*Please take routing_table_lock before calling this function*/
+static int add_routing_table_entry(
+	struct msm_ipc_routing_table_entry *rt_entry)
+{
+	uint32_t key;
+
+	if (!rt_entry)
+		return -EINVAL;
+
+	key = (rt_entry->node_id % RT_HASH_SIZE);
+	list_add_tail(&rt_entry->list, &routing_table[key]);
+	return 0;
+}
+
+/*Please take routing_table_lock before calling this function*/
+static struct msm_ipc_routing_table_entry *lookup_routing_table(
+	uint32_t node_id)
+{
+	uint32_t key = (node_id % RT_HASH_SIZE);
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	list_for_each_entry(rt_entry, &routing_table[key], list) {
+		if (rt_entry->node_id == node_id)
+			return rt_entry;
+	}
+	return NULL;
+}
+
+struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
+{
+	struct rr_packet *temp_pkt;
+
+	if (!xprt_info)
+		return NULL;
+
+	mutex_lock(&xprt_info->rx_lock);
+	while (list_empty(&xprt_info->pkt_list)) {
+		mutex_unlock(&xprt_info->rx_lock);
+		wait_event(xprt_info->read_wait,
+			   !list_empty(&xprt_info->pkt_list));
+		mutex_lock(&xprt_info->rx_lock);
+	}
+	temp_pkt = list_first_entry(&xprt_info->pkt_list,
+				    struct rr_packet, list);
+	list_del(&temp_pkt->list);
+	mutex_unlock(&xprt_info->rx_lock);
+	return temp_pkt;
+}
+
+struct rr_packet *clone_pkt(struct rr_packet *pkt)
+{
+	struct rr_packet *cloned_pkt;
+	struct sk_buff *temp_skb, *cloned_skb;
+	struct sk_buff_head *pkt_fragment_q;
+
+	cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!cloned_pkt) {
+		pr_err("%s: failure\n", __func__);
+		return NULL;
+	}
+
+	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!pkt_fragment_q) {
+		pr_err("%s: pkt_frag_q alloc failure\n", __func__);
+		kfree(cloned_pkt);
+		return NULL;
+	}
+	skb_queue_head_init(pkt_fragment_q);
+
+	skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
+		cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
+		if (!cloned_skb)
+			goto fail_clone;
+		skb_queue_tail(pkt_fragment_q, cloned_skb);
+	}
+	cloned_pkt->pkt_fragment_q = pkt_fragment_q;
+	cloned_pkt->length = pkt->length;
+	return cloned_pkt;
+
+fail_clone:
+	while (!skb_queue_empty(pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	kfree(pkt_fragment_q);
+	kfree(cloned_pkt);
+	return NULL;
+}
+
+struct rr_packet *create_pkt(struct sk_buff_head *data)
+{
+	struct rr_packet *pkt;
+	struct sk_buff *temp_skb;
+
+	pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!pkt) {
+		pr_err("%s: failure\n", __func__);
+		return NULL;
+	}
+
+	pkt->pkt_fragment_q = data;
+	skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
+		pkt->length += temp_skb->len;
+	return pkt;
+}
+
+void release_pkt(struct rr_packet *pkt)
+{
+	struct sk_buff *temp_skb;
+
+	if (!pkt)
+		return;
+
+	if (!pkt->pkt_fragment_q) {
+		kfree(pkt);
+		return;
+	}
+
+	while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	kfree(pkt->pkt_fragment_q);
+	kfree(pkt);
+	return;
+}
+
+static int post_control_ports(struct rr_packet *pkt)
+{
+	struct msm_ipc_port *port_ptr;
+	struct rr_packet *cloned_pkt;
+
+	if (!pkt)
+		return -EINVAL;
+
+	mutex_lock(&control_ports_lock);
+	list_for_each_entry(port_ptr, &control_ports, list) {
+		mutex_lock(&port_ptr->port_rx_q_lock);
+		cloned_pkt = clone_pkt(pkt);
+		list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
+		wake_up(&port_ptr->port_rx_wait_q);
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+	}
+	mutex_unlock(&control_ports_lock);
+	return 0;
+}
+
+static uint32_t allocate_port_id(void)
+{
+	uint32_t port_id = 0, prev_port_id, key;
+	struct msm_ipc_port *port_ptr;
+
+	mutex_lock(&next_port_id_lock);
+	prev_port_id = next_port_id;
+	mutex_lock(&local_ports_lock);
+	do {
+		next_port_id++;
+		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+			next_port_id = 1;
+
+		key = (next_port_id & (LP_HASH_SIZE - 1));
+		if (list_empty(&local_ports[key])) {
+			port_id = next_port_id;
+			break;
+		}
+		list_for_each_entry(port_ptr, &local_ports[key], list) {
+			if (port_ptr->this_port.port_id == next_port_id) {
+				port_id = next_port_id;
+				break;
+			}
+		}
+		if (!port_id) {
+			port_id = next_port_id;
+			break;
+		}
+		port_id = 0;
+	} while (next_port_id != prev_port_id);
+	mutex_unlock(&local_ports_lock);
+	mutex_unlock(&next_port_id_lock);
+
+	return port_id;
+}
+
+void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
+{
+	uint32_t key;
+
+	if (!port_ptr)
+		return;
+
+	key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
+	mutex_lock(&local_ports_lock);
+	list_add_tail(&port_ptr->list, &local_ports[key]);
+	mutex_unlock(&local_ports_lock);
+}
+
+struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
+		void (*notify)(unsigned event, void *data,
+			       void *addr, void *priv),
+		void *priv)
+{
+	struct msm_ipc_port *port_ptr;
+
+	port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
+	if (!port_ptr)
+		return NULL;
+
+	port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
+	port_ptr->this_port.port_id = allocate_port_id();
+	if (!port_ptr->this_port.port_id) {
+		pr_err("%s: All port ids are in use\n", __func__);
+		kfree(port_ptr);
+		return NULL;
+	}
+
+	spin_lock_init(&port_ptr->port_lock);
+	INIT_LIST_HEAD(&port_ptr->incomplete);
+	mutex_init(&port_ptr->incomplete_lock);
+	INIT_LIST_HEAD(&port_ptr->port_rx_q);
+	mutex_init(&port_ptr->port_rx_q_lock);
+	init_waitqueue_head(&port_ptr->port_rx_wait_q);
+
+	port_ptr->endpoint = endpoint;
+	port_ptr->notify = notify;
+	port_ptr->priv = priv;
+
+	msm_ipc_router_add_local_port(port_ptr);
+	return port_ptr;
+}
+
+static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
+{
+	int key = (port_id & (LP_HASH_SIZE - 1));
+	struct msm_ipc_port *port_ptr;
+
+	mutex_lock(&local_ports_lock);
+	list_for_each_entry(port_ptr, &local_ports[key], list) {
+		if (port_ptr->this_port.port_id == port_id) {
+			mutex_unlock(&local_ports_lock);
+			return port_ptr;
+		}
+	}
+	mutex_unlock(&local_ports_lock);
+	return NULL;
+}
+
+static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
+						uint32_t node_id,
+						uint32_t port_id)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int key = (port_id & (RP_HASH_SIZE - 1));
+
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(node_id);
+	if (!rt_entry) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Node is not up\n", __func__);
+		return NULL;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	list_for_each_entry(rport_ptr,
+			    &rt_entry->remote_port_list[key], list) {
+		if (rport_ptr->port_id == port_id) {
+			mutex_unlock(&rt_entry->lock);
+			mutex_unlock(&routing_table_lock);
+			return rport_ptr;
+		}
+	}
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+	return NULL;
+}
+
+static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
+						uint32_t node_id,
+						uint32_t port_id)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int key = (port_id & (RP_HASH_SIZE - 1));
+
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(node_id);
+	if (!rt_entry) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Node is not up\n", __func__);
+		return NULL;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
+			    GFP_KERNEL);
+	if (!rport_ptr) {
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Remote port alloc failed\n", __func__);
+		return NULL;
+	}
+	rport_ptr->port_id = port_id;
+	rport_ptr->node_id = node_id;
+	rport_ptr->tx_quota_cnt = 0;
+	init_waitqueue_head(&rport_ptr->quota_wait);
+	mutex_init(&rport_ptr->quota_lock);
+	list_add_tail(&rport_ptr->list,
+		      &rt_entry->remote_port_list[key]);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+	return rport_ptr;
+}
+
+static void msm_ipc_router_destroy_remote_port(
+	struct msm_ipc_router_remote_port *rport_ptr)
+{
+	uint32_t node_id;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (!rport_ptr)
+		return;
+
+	node_id = rport_ptr->node_id;
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(node_id);
+	if (!rt_entry) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Node %d is not up\n", __func__, node_id);
+		return;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	list_del(&rport_ptr->list);
+	kfree(rport_ptr);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+	return;
+}
+
+static struct msm_ipc_server *msm_ipc_router_lookup_server(
+				uint32_t service,
+				uint32_t instance,
+				uint32_t node_id,
+				uint32_t port_id)
+{
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	int key = (instance & (SRV_HASH_SIZE - 1));
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server, &server_list[key], list) {
+		if ((server->name.service != service) ||
+		    (server->name.instance != instance))
+			continue;
+		if ((node_id == 0) && (port_id == 0)) {
+			mutex_unlock(&server_list_lock);
+			return server;
+		}
+		list_for_each_entry(server_port, &server->server_port_list,
+				    list) {
+			if ((server_port->server_addr.node_id == node_id) &&
+			    (server_port->server_addr.port_id == port_id)) {
+				mutex_unlock(&server_list_lock);
+				return server;
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+	return NULL;
+}
+
+static struct msm_ipc_server *msm_ipc_router_create_server(
+					uint32_t service,
+					uint32_t instance,
+					uint32_t node_id,
+					uint32_t port_id)
+{
+	struct msm_ipc_server *server = NULL;
+	struct msm_ipc_server_port *server_port;
+	int key = (instance & (SRV_HASH_SIZE - 1));
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server, &server_list[key], list) {
+		if ((server->name.service == service) &&
+		    (server->name.instance == instance))
+			goto create_srv_port;
+	}
+
+	server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
+	if (!server) {
+		mutex_unlock(&server_list_lock);
+		pr_err("%s: Server allocation failed\n", __func__);
+		return NULL;
+	}
+	server->name.service = service;
+	server->name.instance = instance;
+	INIT_LIST_HEAD(&server->server_port_list);
+	list_add_tail(&server->list, &server_list[key]);
+
+create_srv_port:
+	server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
+	if (!server_port) {
+		if (list_empty(&server->server_port_list)) {
+			list_del(&server->list);
+			kfree(server);
+		}
+		mutex_unlock(&server_list_lock);
+		pr_err("%s: Server Port allocation failed\n", __func__);
+		return NULL;
+	}
+	server_port->server_addr.node_id = node_id;
+	server_port->server_addr.port_id = port_id;
+	list_add_tail(&server_port->list, &server->server_port_list);
+	mutex_unlock(&server_list_lock);
+
+	return server;
+}
+
+static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
+					  uint32_t node_id, uint32_t port_id)
+{
+	struct msm_ipc_server_port *server_port;
+
+	if (!server)
+		return;
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server_port, &server->server_port_list, list) {
+		if ((server_port->server_addr.node_id == node_id) &&
+		    (server_port->server_addr.port_id == port_id))
+			break;
+	}
+	if (server_port) {
+		list_del(&server_port->list);
+		kfree(server_port);
+	}
+	if (list_empty(&server->server_port_list)) {
+		list_del(&server->list);
+		kfree(server);
+	}
+	mutex_unlock(&server_list_lock);
+	return;
+}
+
+static int msm_ipc_router_send_control_msg(
+		struct msm_ipc_router_xprt_info *xprt_info,
+		union rr_control_msg *msg)
+{
+	struct rr_packet *pkt;
+	struct sk_buff *ipc_rtr_pkt;
+	struct rr_header *hdr;
+	int pkt_size;
+	void *data;
+	struct sk_buff_head *pkt_fragment_q;
+	int ret;
+
+	if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
+	    !xprt_info->initialized)) {
+		pr_err("%s: xprt_info not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
+		return 0;
+
+	pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!pkt) {
+		pr_err("%s: pkt alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!pkt_fragment_q) {
+		pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+	skb_queue_head_init(pkt_fragment_q);
+
+	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
+	if (!ipc_rtr_pkt) {
+		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+
+	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
+	memcpy(data, msg, sizeof(*msg));
+	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: skb_push failed\n", __func__);
+		kfree_skb(ipc_rtr_pkt);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = msg->cmd;
+	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->src_port_id = IPC_ROUTER_ADDRESS;
+	hdr->confirm_rx = 0;
+	hdr->size = sizeof(*msg);
+	hdr->dst_node_id = xprt_info->remote_node_id;
+	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = pkt_size;
+
+	mutex_lock(&xprt_info->tx_lock);
+	ret = xprt_info->xprt->write(pkt, pkt_size, 0);
+	mutex_unlock(&xprt_info->tx_lock);
+
+	release_pkt(pkt);
+	return ret;
+}
+
+static int msm_ipc_router_send_server_list(
+		struct msm_ipc_router_xprt_info *xprt_info)
+{
+	union rr_control_msg ctl;
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	int i;
+
+	if (!xprt_info || !xprt_info->initialized) {
+		pr_err("%s: Xprt info not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
+
+	mutex_lock(&server_list_lock);
+	for (i = 0; i < SRV_HASH_SIZE; i++) {
+		list_for_each_entry(server, &server_list[i], list) {
+			ctl.srv.service = server->name.service;
+			ctl.srv.instance = server->name.instance;
+			list_for_each_entry(server_port,
+					    &server->server_port_list, list) {
+				if (server_port->server_addr.node_id ==
+				    xprt_info->remote_node_id)
+					continue;
+
+				ctl.srv.node_id =
+					server_port->server_addr.node_id;
+				ctl.srv.port_id =
+					server_port->server_addr.port_id;
+				msm_ipc_router_send_control_msg(xprt_info,
+								&ctl);
+			}
+		}
+	}
+	mutex_unlock(&server_list_lock);
+
+	return 0;
+}
+
+static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
+{
+	struct rr_packet *pkt;
+	struct sk_buff *ipc_rtr_pkt;
+	struct rr_header *hdr;
+	int pkt_size;
+	void *data;
+	struct sk_buff_head *pkt_fragment_q;
+	int ret;
+
+	pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+	if (!pkt) {
+		pr_err("%s: pkt alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!pkt_fragment_q) {
+		pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+	skb_queue_head_init(pkt_fragment_q);
+
+	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
+	if (!ipc_rtr_pkt) {
+		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+
+	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
+	memcpy(data, msg, sizeof(*msg));
+	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: skb_push failed\n", __func__);
+		kfree_skb(ipc_rtr_pkt);
+		kfree(pkt_fragment_q);
+		kfree(pkt);
+		return -ENOMEM;
+	}
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = msg->cmd;
+	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->src_port_id = IPC_ROUTER_ADDRESS;
+	hdr->confirm_rx = 0;
+	hdr->size = sizeof(*msg);
+	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = pkt_size;
+
+	ret = post_control_ports(pkt);
+	release_pkt(pkt);
+	return ret;
+}
+
+static int broadcast_ctl_msg(union rr_control_msg *ctl)
+{
+	struct msm_ipc_router_xprt_info *xprt_info;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(xprt_info, &xprt_info_list, list) {
+		msm_ipc_router_send_control_msg(xprt_info, ctl);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+
+	return 0;
+}
+
+static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
+		     struct rr_packet *pkt)
+{
+	struct msm_ipc_router_xprt_info *fwd_xprt_info;
+
+	if (!xprt_info || !pkt)
+		return -EINVAL;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
+		mutex_lock(&fwd_xprt_info->tx_lock);
+		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
+			fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+		mutex_unlock(&fwd_xprt_info->tx_lock);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+	return 0;
+}
+
+static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
+		       struct rr_packet *pkt)
+{
+	uint32_t dst_node_id;
+	struct sk_buff *head_pkt;
+	struct rr_header *hdr;
+	struct msm_ipc_router_xprt_info *fwd_xprt_info;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (!xprt_info || !pkt)
+		return -EINVAL;
+
+	head_pkt = skb_peek(pkt->pkt_fragment_q);
+	if (!head_pkt)
+		return -EINVAL;
+
+	hdr = (struct rr_header *)head_pkt->data;
+	dst_node_id = hdr->dst_node_id;
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(dst_node_id);
+	if (!(rt_entry) || !(rt_entry->xprt_info)) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Routing table not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	mutex_lock(&rt_entry->lock);
+	fwd_xprt_info = rt_entry->xprt_info;
+	mutex_lock(&fwd_xprt_info->tx_lock);
+	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
+		mutex_unlock(&fwd_xprt_info->tx_lock);
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Discarding Command to route back\n", __func__);
+		return -EINVAL;
+	}
+
+	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
+		mutex_unlock(&fwd_xprt_info->tx_lock);
+		mutex_unlock(&rt_entry->lock);
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: DST in the same cluster\n", __func__);
+		return 0;
+	}
+	fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
+	mutex_unlock(&fwd_xprt_info->tx_lock);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+
+	return 0;
+}
+
+static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
+			       struct rr_packet *pkt)
+{
+	union rr_control_msg ctl;
+	union rr_control_msg *msg;
+	struct msm_ipc_router_remote_port *rport_ptr;
+	int rc = 0;
+	struct sk_buff *temp_ptr;
+	struct rr_header *hdr;
+	struct msm_ipc_server *server;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
+			(IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+		return -EINVAL;
+	}
+
+	temp_ptr = skb_peek(pkt->pkt_fragment_q);
+	hdr = (struct rr_header *)temp_ptr->data;
+	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
+
+	switch (msg->cmd) {
+	case IPC_ROUTER_CTRL_CMD_HELLO:
+		xprt_info->remote_node_id = hdr->src_node_id;
+
+		mutex_lock(&routing_table_lock);
+		rt_entry = lookup_routing_table(hdr->src_node_id);
+		if (!rt_entry) {
+			rt_entry = alloc_routing_table_entry(hdr->src_node_id);
+			if (!rt_entry) {
+				mutex_unlock(&routing_table_lock);
+				pr_err("%s: rt_entry allocation failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+		}
+		mutex_lock(&rt_entry->lock);
+		rt_entry->xprt_info = xprt_info;
+		mutex_unlock(&rt_entry->lock);
+		add_routing_table_entry(rt_entry);
+		mutex_unlock(&routing_table_lock);
+
+		memset(&ctl, 0, sizeof(ctl));
+		ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+		msm_ipc_router_send_control_msg(xprt_info, &ctl);
+
+		xprt_info->initialized = 1;
+
+		/* Send list of servers one at a time */
+		msm_ipc_router_send_server_list(xprt_info);
+
+		break;
+	case IPC_ROUTER_CTRL_CMD_RESUME_TX:
+
+		rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+							msg->cli.port_id);
+		if (!rport_ptr) {
+			pr_err("%s: Unable to resume client\n", __func__);
+			break;
+		}
+		mutex_lock(&rport_ptr->quota_lock);
+		rport_ptr->tx_quota_cnt = 0;
+		mutex_unlock(&rport_ptr->quota_lock);
+		wake_up(&rport_ptr->quota_wait);
+		break;
+
+	case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
+		if (msg->srv.instance == 0) {
+			pr_err(
+			"rpcrouter: Server create rejected, version = 0, "
+			"service = %08x\n", msg->srv.service);
+			break;
+		}
+
+		mutex_lock(&routing_table_lock);
+		rt_entry = lookup_routing_table(msg->srv.node_id);
+		if (!rt_entry) {
+			rt_entry = alloc_routing_table_entry(msg->srv.node_id);
+			if (!rt_entry) {
+				mutex_unlock(&routing_table_lock);
+				pr_err("%s: rt_entry allocation failed\n",
+					__func__);
+				return -ENOMEM;
+			}
+			mutex_lock(&rt_entry->lock);
+			rt_entry->xprt_info = xprt_info;
+			mutex_unlock(&rt_entry->lock);
+			add_routing_table_entry(rt_entry);
+		}
+		mutex_unlock(&routing_table_lock);
+
+		server = msm_ipc_router_lookup_server(msg->srv.service,
+						      msg->srv.instance,
+						      msg->srv.node_id,
+						      msg->srv.port_id);
+		if (!server) {
+			server = msm_ipc_router_create_server(
+				msg->srv.service, msg->srv.instance,
+				msg->srv.node_id, msg->srv.port_id);
+			if (!server) {
+				pr_err("%s: Server Create failed\n", __func__);
+				return -ENOMEM;
+			}
+
+			if (!msm_ipc_router_lookup_remote_port(
+					msg->srv.node_id, msg->srv.port_id)) {
+				rport_ptr = msm_ipc_router_create_remote_port(
+					msg->srv.node_id, msg->srv.port_id);
+				if (!rport_ptr)
+					pr_err("%s: Remote port create "
+					       "failed\n", __func__);
+			}
+			wake_up(&newserver_wait);
+		}
+
+		relay_msg(xprt_info, pkt);
+		post_control_ports(pkt);
+		break;
+	case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
+		server = msm_ipc_router_lookup_server(msg->srv.service,
+						      msg->srv.instance,
+						      msg->srv.node_id,
+						      msg->srv.port_id);
+		if (server) {
+			msm_ipc_router_destroy_server(server,
+						      msg->srv.node_id,
+						      msg->srv.port_id);
+			relay_msg(xprt_info, pkt);
+			post_control_ports(pkt);
+		}
+		break;
+	case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
+		rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+							msg->cli.port_id);
+		if (rport_ptr)
+			msm_ipc_router_destroy_remote_port(rport_ptr);
+
+		relay_msg(xprt_info, pkt);
+		post_control_ports(pkt);
+		break;
+	case IPC_ROUTER_CTRL_CMD_PING:
+		/* No action needed for ping messages received */
+		break;
+	default:
+		rc = -ENOSYS;
+	}
+
+	return rc;
+}
+
+static void do_read_data(struct work_struct *work)
+{
+	struct rr_header *hdr;
+	struct rr_packet *pkt = NULL;
+	struct msm_ipc_port *port_ptr;
+	struct sk_buff *head_skb;
+	struct msm_ipc_port_addr *src_addr;
+	uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
+
+	struct msm_ipc_router_xprt_info *xprt_info =
+		container_of(work,
+			     struct msm_ipc_router_xprt_info,
+			     read_data);
+
+	pkt = rr_read(xprt_info);
+	if (!pkt) {
+		pr_err("%s: rr_read failed\n", __func__);
+		goto fail_io;
+	}
+
+	if (pkt->length < IPC_ROUTER_HDR_SIZE ||
+	    pkt->length > MAX_IPC_PKT_SIZE) {
+		pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
+		goto fail_data;
+	}
+
+	head_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!head_skb) {
+		pr_err("%s: head_skb is invalid\n", __func__);
+		goto fail_data;
+	}
+
+	hdr = (struct rr_header *)(head_skb->data);
+
+	if (hdr->version != IPC_ROUTER_VERSION) {
+		pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
+		goto fail_data;
+	}
+
+	if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
+	    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
+	     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
+		forward_msg(xprt_info, pkt);
+		release_pkt(pkt);
+		goto done;
+	}
+
+	if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
+	    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+		process_control_msg(xprt_info, pkt);
+		release_pkt(pkt);
+		goto done;
+	}
+
+	resume_tx = hdr->confirm_rx;
+	resume_tx_node_id = hdr->dst_node_id;
+	resume_tx_port_id = hdr->dst_port_id;
+
+	port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
+	if (!port_ptr) {
+		pr_err("%s: No local port id %08x\n", __func__,
+			hdr->dst_port_id);
+		release_pkt(pkt);
+		goto process_done;
+	}
+
+	if (!port_ptr->notify) {
+		mutex_lock(&port_ptr->port_rx_q_lock);
+		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+		wake_up(&port_ptr->port_rx_wait_q);
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+	} else {
+		src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
+				   GFP_KERNEL);
+		if (src_addr) {
+			src_addr->node_id = hdr->src_node_id;
+			src_addr->port_id = hdr->src_port_id;
+		}
+		skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
+		port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
+				 src_addr, port_ptr->priv);
+		pkt->pkt_fragment_q = NULL;
+		src_addr = NULL;
+		release_pkt(pkt);
+	}
+
+process_done:
+	if (resume_tx) {
+		union rr_control_msg msg;
+
+		msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+		msg.cli.node_id = resume_tx_node_id;
+		msg.cli.port_id = resume_tx_port_id;
+
+		msm_ipc_router_send_control_msg(xprt_info, &msg);
+	}
+
+done:
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
+	return;
+
+fail_data:
+	release_pkt(pkt);
+fail_io:
+	pr_err("ipc_router has died\n");
+}
+
+int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
+				   struct msm_ipc_addr *name)
+{
+	struct msm_ipc_server *server;
+	unsigned long flags;
+	union rr_control_msg ctl;
+
+	if (!port_ptr || !name)
+		return -EINVAL;
+
+	if (name->addrtype != MSM_IPC_ADDR_NAME)
+		return -EINVAL;
+
+	server = msm_ipc_router_lookup_server(name->addr.port_name.service,
+					      name->addr.port_name.instance,
+					      IPC_ROUTER_NID_LOCAL,
+					      port_ptr->this_port.port_id);
+	if (server) {
+		pr_err("%s: Server already present\n", __func__);
+		return -EINVAL;
+	}
+
+	server = msm_ipc_router_create_server(name->addr.port_name.service,
+					      name->addr.port_name.instance,
+					      IPC_ROUTER_NID_LOCAL,
+					      port_ptr->this_port.port_id);
+	if (!server) {
+		pr_err("%s: Server Creation failed\n", __func__);
+		return -EINVAL;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
+	ctl.srv.service = server->name.service;
+	ctl.srv.instance = server->name.instance;
+	ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
+	ctl.srv.port_id = port_ptr->this_port.port_id;
+	broadcast_ctl_msg(&ctl);
+	spin_lock_irqsave(&port_ptr->port_lock, flags);
+	port_ptr->type = SERVER_PORT;
+	port_ptr->port_name.service = server->name.service;
+	port_ptr->port_name.instance = server->name.instance;
+	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
+	return 0;
+}
+
+int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
+{
+	struct msm_ipc_server *server;
+	unsigned long flags;
+	union rr_control_msg ctl;
+
+	if (!port_ptr)
+		return -EINVAL;
+
+	if (port_ptr->type != SERVER_PORT) {
+		pr_err("%s: Trying to unregister a non-server port\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
+		pr_err("%s: Trying to unregister a remote server locally\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
+					      port_ptr->port_name.instance,
+					      port_ptr->this_port.node_id,
+					      port_ptr->this_port.port_id);
+	if (!server) {
+		pr_err("%s: Server lookup failed\n", __func__);
+		return -ENODEV;
+	}
+
+	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
+	ctl.srv.service = server->name.service;
+	ctl.srv.instance = server->name.instance;
+	ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
+	ctl.srv.port_id = port_ptr->this_port.port_id;
+	broadcast_ctl_msg(&ctl);
+	msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
+				      port_ptr->this_port.port_id);
+	spin_lock_irqsave(&port_ptr->port_lock, flags);
+	port_ptr->type = CLIENT_PORT;
+	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
+	return 0;
+}
+
+static int loopback_data(struct msm_ipc_port *src,
+			uint32_t port_id,
+			struct sk_buff_head *data)
+{
+	struct sk_buff *head_skb;
+	struct rr_header *hdr;
+	struct msm_ipc_port *port_ptr;
+	struct rr_packet *pkt;
+
+	if (!data) {
+		pr_err("%s: Invalid pkt pointer\n", __func__);
+		return -EINVAL;
+	}
+
+	pkt = create_pkt(data);
+	if (!pkt) {
+		pr_err("%s: New pkt create failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	head_skb = skb_peek(pkt->pkt_fragment_q);
+	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		release_pkt(pkt);
+		return -ENOMEM;
+	}
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
+	hdr->src_node_id = src->this_port.node_id;
+	hdr->src_port_id = src->this_port.port_id;
+	hdr->size = pkt->length;
+	hdr->confirm_rx = 0;
+	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
+	hdr->dst_port_id = port_id;
+	pkt->length += IPC_ROUTER_HDR_SIZE;
+
+	port_ptr = msm_ipc_router_lookup_local_port(port_id);
+	if (!port_ptr) {
+		pr_err("%s: Local port %d not present\n", __func__, port_id);
+		release_pkt(pkt);
+		return -ENODEV;
+	}
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+	wake_up(&port_ptr->port_rx_wait_q);
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	return pkt->length;
+}
+
+static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
+				struct msm_ipc_router_remote_port *rport_ptr,
+				struct rr_packet *pkt)
+{
+	struct sk_buff *head_skb;
+	struct rr_header *hdr;
+	struct msm_ipc_router_xprt_info *xprt_info;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int ret;
+	DEFINE_WAIT(__wait);
+
+	if (!rport_ptr || !src || !pkt)
+		return -EINVAL;
+
+	head_skb = skb_peek(pkt->pkt_fragment_q);
+	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
+	if (!hdr) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		return -ENOMEM;
+	}
+	hdr->version = IPC_ROUTER_VERSION;
+	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
+	hdr->src_node_id = src->this_port.node_id;
+	hdr->src_port_id = src->this_port.port_id;
+	hdr->size = pkt->length;
+	hdr->confirm_rx = 0;
+	hdr->dst_node_id = rport_ptr->node_id;
+	hdr->dst_port_id = rport_ptr->port_id;
+	pkt->length += IPC_ROUTER_HDR_SIZE;
+
+	for (;;) {
+		prepare_to_wait(&rport_ptr->quota_wait, &__wait,
+				TASK_INTERRUPTIBLE);
+		mutex_lock(&rport_ptr->quota_lock);
+		if (rport_ptr->tx_quota_cnt <
+		     IPC_ROUTER_DEFAULT_RX_QUOTA)
+			break;
+		if (signal_pending(current))
+			break;
+		mutex_unlock(&rport_ptr->quota_lock);
+		schedule();
+	}
+	finish_wait(&rport_ptr->quota_wait, &__wait);
+
+	if (signal_pending(current)) {
+		mutex_unlock(&rport_ptr->quota_lock);
+		return -ERESTARTSYS;
+	}
+	rport_ptr->tx_quota_cnt++;
+	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
+		hdr->confirm_rx = 1;
+	mutex_unlock(&rport_ptr->quota_lock);
+
+	mutex_lock(&routing_table_lock);
+	rt_entry = lookup_routing_table(hdr->dst_node_id);
+	if (!rt_entry || !rt_entry->xprt_info) {
+		mutex_unlock(&routing_table_lock);
+		pr_err("%s: Remote node %d not up\n",
+			__func__, hdr->dst_node_id);
+		return -ENODEV;
+	}
+	mutex_lock(&rt_entry->lock);
+	xprt_info = rt_entry->xprt_info;
+	mutex_lock(&xprt_info->tx_lock);
+	ret = xprt_info->xprt->write(pkt, pkt->length, 0);
+	mutex_unlock(&xprt_info->tx_lock);
+	mutex_unlock(&rt_entry->lock);
+	mutex_unlock(&routing_table_lock);
+
+	if (ret < 0) {
+		pr_err("%s: Write on XPRT failed\n", __func__);
+		return ret;
+	}
+
+	return pkt->length;
+}
+
+int msm_ipc_router_send_to(struct msm_ipc_port *src,
+			   struct sk_buff_head *data,
+			   struct msm_ipc_addr *dest)
+{
+	uint32_t dst_node_id = 0, dst_port_id = 0;
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	struct msm_ipc_router_remote_port *rport_ptr = NULL;
+	struct rr_packet *pkt;
+	int ret;
+
+	if (!src || !data || !dest) {
+		pr_err("%s: Invalid Parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	/* Resolve Address*/
+	if (dest->addrtype == MSM_IPC_ADDR_ID) {
+		dst_node_id = dest->addr.port_addr.node_id;
+		dst_port_id = dest->addr.port_addr.port_id;
+	} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
+		server = msm_ipc_router_lookup_server(
+					dest->addr.port_name.service,
+					dest->addr.port_name.instance,
+					0, 0);
+		if (!server) {
+			pr_err("%s: Destination not reachable\n", __func__);
+			return -ENODEV;
+		}
+		mutex_lock(&server_list_lock);
+		server_port = list_first_entry(&server->server_port_list,
+					       struct msm_ipc_server_port,
+					       list);
+		dst_node_id = server_port->server_addr.node_id;
+		dst_port_id = server_port->server_addr.port_id;
+		mutex_unlock(&server_list_lock);
+	}
+	if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
+		ret = loopback_data(src, dst_port_id, data);
+		return ret;
+	}
+
+	/* Achieve Flow control */
+	rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
+						      dst_port_id);
+	if (!rport_ptr) {
+		rport_ptr = msm_ipc_router_create_remote_port(dst_node_id,
+							      dst_port_id);
+		if (!rport_ptr) {
+			pr_err("%s: Could not create remote port\n", __func__);
+			return -ENOMEM;
+		}
+	}
+
+	pkt = create_pkt(data);
+	if (!pkt) {
+		pr_err("%s: Pkt creation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
+	release_pkt(pkt);
+
+	return ret;
+}
+
+int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
+			struct sk_buff_head **data,
+			size_t buf_len)
+{
+	struct rr_packet *pkt;
+	int ret;
+
+	if (!port_ptr || !data)
+		return -EINVAL;
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	if (list_empty(&port_ptr->port_rx_q)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		return -EAGAIN;
+	}
+
+	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
+	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		return -ETOOSMALL;
+	}
+	list_del(&pkt->list);
+	*data = pkt->pkt_fragment_q;
+	ret = pkt->length;
+	kfree(pkt);
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	return ret;
+}
+
+int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
+			     struct sk_buff_head **data,
+			     struct msm_ipc_addr *src,
+			     unsigned long timeout)
+{
+	int ret, data_len, align_size;
+	struct sk_buff *temp_skb;
+	struct rr_header *hdr = NULL;
+
+	if (!port_ptr || !data) {
+		pr_err("%s: Invalid pointers being passed\n", __func__);
+		return -EINVAL;
+	}
+
+	*data = NULL;
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	while (list_empty(&port_ptr->port_rx_q)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		if (timeout < 0) {
+			ret = wait_event_interruptible(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q));
+			if (ret)
+				return ret;
+		} else if (timeout > 0) {
+			timeout = wait_event_interruptible_timeout(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q),
+					timeout);
+			if (timeout < 0)
+				return -EFAULT;
+		}
+		if (timeout == 0)
+			return -ETIMEDOUT;
+		mutex_lock(&port_ptr->port_rx_q_lock);
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	ret = msm_ipc_router_read(port_ptr, data, 0);
+	if (ret <= 0 || !(*data))
+		return ret;
+
+	temp_skb = skb_peek(*data);
+	hdr = (struct rr_header *)(temp_skb->data);
+	if (src) {
+		src->addrtype = MSM_IPC_ADDR_ID;
+		src->addr.port_addr.node_id = hdr->src_node_id;
+		src->addr.port_addr.port_id = hdr->src_port_id;
+	}
+
+	data_len = hdr->size;
+	skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
+	align_size = ALIGN_SIZE(data_len);
+	if (align_size) {
+		temp_skb = skb_peek_tail(*data);
+		skb_trim(temp_skb, (temp_skb->len - align_size));
+	}
+	return data_len;
+}
+
+struct msm_ipc_port *msm_ipc_router_create_port(
+	void (*notify)(unsigned event, void *data, void *addr, void *priv),
+	void *priv)
+{
+	struct msm_ipc_port *port_ptr;
+
+	port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
+	if (!port_ptr)
+		pr_err("%s: port_ptr alloc failed\n", __func__);
+
+	return port_ptr;
+}
+
+int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
+{
+	union rr_control_msg msg;
+	struct rr_packet *pkt, *temp_pkt;
+	struct msm_ipc_server *server;
+
+	if (!port_ptr)
+		return -EINVAL;
+
+	if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
+		if (port_ptr->type == SERVER_PORT) {
+			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
+			msg.srv.service = port_ptr->port_name.service;
+			msg.srv.instance = port_ptr->port_name.instance;
+			msg.srv.node_id = port_ptr->this_port.node_id;
+			msg.srv.port_id = port_ptr->this_port.port_id;
+		} else if (port_ptr->type == CLIENT_PORT) {
+			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+			msg.cli.node_id = port_ptr->this_port.node_id;
+			msg.cli.port_id = port_ptr->this_port.port_id;
+		}
+		broadcast_ctl_msg(&msg);
+		broadcast_ctl_msg_locally(&msg);
+	}
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
+		list_del(&pkt->list);
+		release_pkt(pkt);
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	if (port_ptr->type == SERVER_PORT) {
+		server = msm_ipc_router_lookup_server(
+				port_ptr->port_name.service,
+				port_ptr->port_name.instance,
+				port_ptr->this_port.node_id,
+				port_ptr->this_port.port_id);
+		if (server)
+			msm_ipc_router_destroy_server(server,
+				port_ptr->this_port.node_id,
+				port_ptr->this_port.port_id);
+		mutex_lock(&local_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&local_ports_lock);
+	} else if (port_ptr->type == CLIENT_PORT) {
+		mutex_lock(&local_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&local_ports_lock);
+	} else if (port_ptr->type == CONTROL_PORT) {
+		mutex_lock(&control_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&control_ports_lock);
+	}
+
+	kfree(port_ptr);
+	return 0;
+}
+
+int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
+{
+	struct rr_packet *pkt;
+	int rc = 0;
+
+	if (!port_ptr)
+		return -EINVAL;
+
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	if (!list_empty(&port_ptr->port_rx_q)) {
+		pkt = list_first_entry(&port_ptr->port_rx_q,
+					struct rr_packet, list);
+		rc = pkt->length;
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	return rc;
+}
+
+int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
+{
+	if (!port_ptr)
+		return -EINVAL;
+
+	mutex_lock(&local_ports_lock);
+	list_del(&port_ptr->list);
+	mutex_unlock(&local_ports_lock);
+	port_ptr->type = CONTROL_PORT;
+	mutex_lock(&control_ports_lock);
+	list_add_tail(&port_ptr->list, &control_ports);
+	mutex_unlock(&control_ports_lock);
+
+	return 0;
+}
+
+int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
+				struct msm_ipc_port_addr *srv_addr,
+				int num_entries_in_array)
+{
+	struct msm_ipc_server *server;
+	struct msm_ipc_server_port *server_port;
+	int i = 0; /*num_entries_found*/
+
+	if (!srv_name || !srv_addr) {
+		pr_err("%s: Invalid srv_addr/name\n", __func__);
+		return -EINVAL;
+	}
+
+	server = msm_ipc_router_lookup_server(srv_name->service,
+					srv_name->instance, 0, 0);
+	if (!server)
+		return -ENODEV;
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server_port, &server->server_port_list, list) {
+		if (i < num_entries_in_array) {
+			srv_addr[i].node_id = server_port->server_addr.node_id;
+			srv_addr[i].port_id = server_port->server_addr.port_id;
+		}
+		i++;
+	}
+	mutex_unlock(&server_list_lock);
+
+	return i;
+}
+
+int msm_ipc_router_close(void)
+{
+	struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
+
+	mutex_lock(&xprt_info_list_lock);
+	list_for_each_entry_safe(xprt_info, tmp_xprt_info,
+				 &xprt_info_list, list) {
+		xprt_info->xprt->close();
+		list_del(&xprt_info->list);
+		kfree(xprt_info);
+	}
+	mutex_unlock(&xprt_info_list_lock);
+	return 0;
+}
+
+static int __init msm_ipc_router_init(void)
+{
+	int i;
+	struct msm_ipc_routing_table_entry *rt_entry;
+#if !defined(CONFIG_MSM_IPC_ROUTER_SMD_XPRT)
+	struct work_struct dummy_work;
+
+	INIT_WORK(&dummy_work, do_read_data);
+#endif
+
+	for (i = 0; i < SRV_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&server_list[i]);
+
+	for (i = 0; i < LP_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&local_ports[i]);
+
+	mutex_lock(&routing_table_lock);
+	if (!routing_table_inited) {
+		init_routing_table();
+		rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
+		add_routing_table_entry(rt_entry);
+		routing_table_inited = 1;
+	}
+	mutex_unlock(&routing_table_lock);
+
+	init_waitqueue_head(&newserver_wait);
+
+	return 0;
+}
+
+module_init(msm_ipc_router_init);
+MODULE_DESCRIPTION("MSM IPC Router");
+MODULE_LICENSE("GPL v2");
diff --git a/net/msm_ipc/msm_ipc_router.h b/net/msm_ipc/msm_ipc_router.h
new file mode 100644
index 0000000..4d30c8f
--- /dev/null
+++ b/net/msm_ipc/msm_ipc_router.h
@@ -0,0 +1,187 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_IPC_ROUTER_H
+#define _MSM_IPC_ROUTER_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <net/sock.h>
+#include <linux/msm_ipc.h>
+
+#include <mach/msm_smd.h>
+
+/* definitions for the R2R wire protcol */
+#define IPC_ROUTER_VERSION			1
+#define IPC_ROUTER_PROCESSORS_MAX		4
+
+#define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
+#define IPC_ROUTER_ADDRESS			0xfffffffe
+
+#define IPC_ROUTER_NID_LOCAL			1
+#define IPC_ROUTER_NID_REMOTE			0
+
+#define IPC_ROUTER_CTRL_CMD_DATA		1
+#define IPC_ROUTER_CTRL_CMD_HELLO		2
+#define IPC_ROUTER_CTRL_CMD_BYE			3
+#define IPC_ROUTER_CTRL_CMD_NEW_SERVER		4
+#define IPC_ROUTER_CTRL_CMD_REMOVE_SERVER	5
+#define IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT	6
+#define IPC_ROUTER_CTRL_CMD_RESUME_TX		7
+#define IPC_ROUTER_CTRL_CMD_EXIT		8
+#define IPC_ROUTER_CTRL_CMD_PING		9
+
+#define IPC_ROUTER_DEFAULT_RX_QUOTA	5
+
+#define IPC_ROUTER_XPRT_EVENT_DATA  1
+#define IPC_ROUTER_XPRT_EVENT_OPEN  2
+#define IPC_ROUTER_XPRT_EVENT_CLOSE 3
+
+#define NUM_NODES 2
+
+#define IPC_ROUTER_INFINITY -1
+#define DEFAULT_RCV_TIMEO IPC_ROUTER_INFINITY
+
+#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
+
+enum {
+	MSM_IPC_ROUTER_READ_CB = 0,
+	MSM_IPC_ROUTER_WRITE_DONE,
+};
+
+union rr_control_msg {
+	uint32_t cmd;
+	struct {
+		uint32_t cmd;
+		uint32_t service;
+		uint32_t instance;
+		uint32_t node_id;
+		uint32_t port_id;
+	} srv;
+	struct {
+		uint32_t cmd;
+		uint32_t node_id;
+		uint32_t port_id;
+	} cli;
+};
+
+struct rr_header {
+	uint32_t version;
+	uint32_t type;
+	uint32_t src_node_id;
+	uint32_t src_port_id;
+	uint32_t confirm_rx;
+	uint32_t size;
+	uint32_t dst_node_id;
+	uint32_t dst_port_id;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
+#define MAX_IPC_PKT_SIZE 66000
+/* internals */
+
+#define IPC_ROUTER_MAX_REMOTE_SERVERS		100
+
+struct rr_packet {
+	struct list_head list;
+	struct sk_buff_head *pkt_fragment_q;
+	uint32_t length;
+};
+
+struct msm_ipc_port {
+	struct list_head list;
+
+	struct msm_ipc_port_addr this_port;
+	struct msm_ipc_port_name port_name;
+	uint32_t type;
+	unsigned flags;
+	spinlock_t port_lock;
+
+	struct list_head incomplete;
+	struct mutex incomplete_lock;
+
+	struct list_head port_rx_q;
+	struct mutex port_rx_q_lock;
+	wait_queue_head_t port_rx_wait_q;
+
+	int restart_state;
+	spinlock_t restart_lock;
+	wait_queue_head_t restart_wait;
+
+	void *endpoint;
+	void (*notify)(unsigned event, void *data, void *addr, void *priv);
+
+	uint32_t num_tx;
+	uint32_t num_rx;
+	unsigned long num_tx_bytes;
+	unsigned long num_rx_bytes;
+	void *priv;
+};
+
+struct msm_ipc_router_xprt {
+	char *name;
+	uint32_t link_id;
+	void *priv;
+
+	int (*read_avail)(void);
+	int (*read)(void *data, uint32_t len);
+	int (*write_avail)(void);
+	int (*write)(void *data, uint32_t len, uint32_t type);
+	int (*close)(void);
+};
+
+extern struct completion msm_ipc_remote_router_up;
+
+void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
+				unsigned event,
+				void *data);
+
+
+struct rr_packet *clone_pkt(struct rr_packet *pkt);
+void release_pkt(struct rr_packet *pkt);
+
+
+struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
+		void (*notify)(unsigned event, void *data,
+			       void *addr, void *priv),
+		void *priv);
+int msm_ipc_router_send_to(struct msm_ipc_port *src,
+			   struct sk_buff_head *data,
+			   struct msm_ipc_addr *dest);
+int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
+			struct sk_buff_head **data,
+			size_t buf_len);
+int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr);
+int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
+int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
+				      struct msm_ipc_port_addr *port_addr,
+				      int num_entries_in_array);
+int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr);
+
+struct msm_ipc_port *msm_ipc_router_create_port(
+	void (*notify)(unsigned event, void *data,
+		       void *addr, void *priv),
+	void *priv);
+int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
+		      struct sk_buff_head **data,
+		      struct msm_ipc_addr *src_addr,
+		      unsigned long timeout);
+int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
+			    struct msm_ipc_addr *name);
+int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port);
+
+#endif
-- 
1.7.3.3

Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related

* [PATCH 2/3] net: msm_ipc: Add user-space support for MSM_IPC Router
From: Karthikeyan Ramasubramanian @ 2011-06-08 17:51 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-arm-msm, Karthikeyan Ramasubramanian

MSM_IPC Router exports socket interface to the user-space processes
to communicate with the processes in the remote processors

Change-Id: I2d4039dd1825117c125d6975b22aa7f144659643
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
---
 include/linux/msm_ipc.h      |   47 ++++
 include/linux/socket.h       |    5 +-
 net/msm_ipc/Makefile         |    2 +-
 net/msm_ipc/msm_ipc_router.c |    7 +-
 net/msm_ipc/msm_ipc_router.h |    8 +
 net/msm_ipc/msm_ipc_socket.c |  520 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 585 insertions(+), 4 deletions(-)
 create mode 100644 net/msm_ipc/msm_ipc_socket.c

diff --git a/include/linux/msm_ipc.h b/include/linux/msm_ipc.h
index 47d678c..2db5d6f 100644
--- a/include/linux/msm_ipc.h
+++ b/include/linux/msm_ipc.h
@@ -24,4 +24,51 @@ struct msm_ipc_addr {
 	} addr;
 };
 
+#define MSM_IPC_WAIT_FOREVER	(~0)
+
+/*
+ * Socket API
+ */
+
+#ifndef AF_MSM_IPC
+#define AF_MSM_IPC		39
+#endif
+
+#ifndef PF_MSM_IPC
+#define PF_MSM_IPC		AF_MSM_IPC
+#endif
+
+#define MSM_IPC_ADDR_NAME		1
+#define MSM_IPC_ADDR_ID			2
+
+struct sockaddr_msm_ipc {
+	unsigned short family;
+	struct msm_ipc_addr address;
+	unsigned char reserved;
+};
+
+#define IPC_ROUTER_IOCTL_MAGIC (0xC3)
+
+#define IPC_ROUTER_IOCTL_GET_VERSION \
+	_IOR(IPC_ROUTER_IOCTL_MAGIC, 0, unsigned int)
+
+#define IPC_ROUTER_IOCTL_GET_MTU \
+	_IOR(IPC_ROUTER_IOCTL_MAGIC, 1, unsigned int)
+
+#define IPC_ROUTER_IOCTL_LOOKUP_SERVER \
+	_IOWR(IPC_ROUTER_IOCTL_MAGIC, 2, struct sockaddr_msm_ipc)
+
+#define IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE \
+	_IOR(IPC_ROUTER_IOCTL_MAGIC, 3, unsigned int)
+
+#define IPC_ROUTER_IOCTL_BIND_CONTROL_PORT \
+	_IOR(IPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+
+struct server_lookup_args {
+	struct msm_ipc_port_name port_name;
+	int num_entries_in_array;
+	int num_entries_found;
+	struct msm_ipc_port_addr port_addr[0];
+};
+
 #endif
diff --git a/include/linux/socket.h b/include/linux/socket.h
index d2b5e98..a23198e 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -192,7 +192,8 @@ struct ucred {
 #define AF_IEEE802154	36	/* IEEE802154 sockets		*/
 #define AF_CAIF		37	/* CAIF sockets			*/
 #define AF_ALG		38	/* Algorithm sockets		*/
-#define AF_MAX		39	/* For now.. */
+#define AF_MSM_IPC	39	/* MSM_IPC sockets		*/
+#define AF_MAX		40	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -234,6 +235,7 @@ struct ucred {
 #define PF_IEEE802154	AF_IEEE802154
 #define PF_CAIF		AF_CAIF
 #define PF_ALG		AF_ALG
+#define PF_MSM_IPC	AF_MSM_IPC
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -308,6 +310,7 @@ struct ucred {
 #define SOL_IUCV	277
 #define SOL_CAIF	278
 #define SOL_ALG		279
+#define SOL_MSM_IPC	280
 
 /* IPX options */
 #define IPX_TYPE	1
diff --git a/net/msm_ipc/Makefile b/net/msm_ipc/Makefile
index 461c510..b9a0dfb 100644
--- a/net/msm_ipc/Makefile
+++ b/net/msm_ipc/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_MSM_IPC) := msm_ipc.o
 
-msm_ipc-y += msm_ipc_router.o
+msm_ipc-y += msm_ipc_router.o msm_ipc_socket.o
diff --git a/net/msm_ipc/msm_ipc_router.c b/net/msm_ipc/msm_ipc_router.c
index 76deacb..0cd0a02 100644
--- a/net/msm_ipc/msm_ipc_router.c
+++ b/net/msm_ipc/msm_ipc_router.c
@@ -1638,7 +1638,7 @@ int msm_ipc_router_close(void)
 
 static int __init msm_ipc_router_init(void)
 {
-	int i;
+	int i, ret;
 	struct msm_ipc_routing_table_entry *rt_entry;
 #if !defined(CONFIG_MSM_IPC_ROUTER_SMD_XPRT)
 	struct work_struct dummy_work;
@@ -1662,8 +1662,11 @@ static int __init msm_ipc_router_init(void)
 	mutex_unlock(&routing_table_lock);
 
 	init_waitqueue_head(&newserver_wait);
+	ret = msm_ipc_router_init_sockets();
+	if (ret < 0)
+		pr_err("%s: Init sockets failed\n", __func__);
 
-	return 0;
+	return ret;
 }
 
 module_init(msm_ipc_router_init);
diff --git a/net/msm_ipc/msm_ipc_router.h b/net/msm_ipc/msm_ipc_router.h
index 4d30c8f..ef47f11 100644
--- a/net/msm_ipc/msm_ipc_router.h
+++ b/net/msm_ipc/msm_ipc_router.h
@@ -132,6 +132,11 @@ struct msm_ipc_port {
 	void *priv;
 };
 
+struct msm_ipc_sock {
+	struct sock sk;
+	struct msm_ipc_port *port;
+};
+
 struct msm_ipc_router_xprt {
 	char *name;
 	uint32_t link_id;
@@ -184,4 +189,7 @@ int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
 			    struct msm_ipc_addr *name);
 int msm_ipc_router_unregister_server(struct msm_ipc_port *server_port);
 
+int msm_ipc_router_init_sockets(void);
+void msm_ipc_router_exit_sockets(void);
+
 #endif
diff --git a/net/msm_ipc/msm_ipc_socket.c b/net/msm_ipc/msm_ipc_socket.c
new file mode 100644
index 0000000..9d98691
--- /dev/null
+++ b/net/msm_ipc/msm_ipc_socket.c
@@ -0,0 +1,520 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/gfp.h>
+#include <linux/msm_ipc.h>
+#include <linux/string.h>
+#include <linux/atomic.h>
+
+#include <net/sock.h>
+
+#include "msm_ipc_router.h"
+
+#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
+#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
+#define MODEM_LOAD_TIMEOUT (10 * HZ)
+
+static int sockets_enabled;
+static struct proto msm_ipc_proto;
+static const struct proto_ops msm_ipc_proto_ops;
+
+static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
+					  struct iovec const *msg_sect,
+					  size_t total_len)
+{
+	struct sk_buff_head *msg_head;
+	struct sk_buff *msg;
+	int i, copied, first = 1;
+	int data_size = 0, request_size, offset;
+	void *data;
+
+	for (i = 0; i < num_sect; i++)
+		data_size += msg_sect[i].iov_len;
+
+	if (!data_size)
+		return NULL;
+
+	msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!msg_head) {
+		pr_err("%s: cannot allocate skb_head\n", __func__);
+		return NULL;
+	}
+	skb_queue_head_init(msg_head);
+
+	for (copied = 1, i = 0; copied && (i < num_sect); i++) {
+		data_size = msg_sect[i].iov_len;
+		offset = 0;
+		while (offset != msg_sect[i].iov_len) {
+			request_size = data_size;
+			if (first)
+				request_size += IPC_ROUTER_HDR_SIZE;
+
+			msg = alloc_skb(request_size, GFP_KERNEL);
+			if (!msg) {
+				if (request_size <= (PAGE_SIZE/2)) {
+					pr_err("%s: cannot allocated skb\n",
+						__func__);
+					goto msg_build_failure;
+				}
+				data_size = data_size / 2;
+				continue;
+			}
+
+			if (first) {
+				skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
+				first = 0;
+			}
+
+			data = skb_put(msg, data_size);
+			copied = !copy_from_user(msg->data,
+					msg_sect[i].iov_base + offset,
+					data_size);
+			if (!copied) {
+				pr_err("%s: copy_from_user failed\n",
+					__func__);
+				kfree_skb(msg);
+				goto msg_build_failure;
+			}
+			skb_queue_tail(msg_head, msg);
+			offset += data_size;
+			data_size = msg_sect[i].iov_len - offset;
+		}
+	}
+	return msg_head;
+
+msg_build_failure:
+	while (!skb_queue_empty(msg_head)) {
+		msg = skb_dequeue(msg_head);
+		kfree_skb(msg);
+	}
+	kfree(msg_head);
+	return NULL;
+}
+
+static int msm_ipc_router_extract_msg(struct msghdr *m,
+				      struct sk_buff_head *msg_head)
+{
+	struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)m->msg_name;
+	struct rr_header *hdr;
+	struct sk_buff *temp;
+	int offset = 0, data_len = 0, copy_len;
+
+	if (!m || !msg_head) {
+		pr_err("%s: Invalid pointers passed\n", __func__);
+		return -EINVAL;
+	}
+
+	temp = skb_peek(msg_head);
+	hdr = (struct rr_header *)(temp->data);
+	if (addr || (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+		addr->family = AF_MSM_IPC;
+		addr->address.addrtype = MSM_IPC_ADDR_ID;
+		addr->address.addr.port_addr.node_id = hdr->src_node_id;
+		addr->address.addr.port_addr.port_id = hdr->src_port_id;
+		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
+	}
+
+	data_len = hdr->size;
+	skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+	skb_queue_walk(msg_head, temp) {
+		copy_len = data_len < temp->len ? data_len : temp->len;
+		if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
+				 copy_len)) {
+			pr_err("%s: Copy to user failed\n", __func__);
+			return -EFAULT;
+		}
+		offset += copy_len;
+		data_len -= copy_len;
+	}
+	return offset;
+}
+
+static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
+{
+	struct sk_buff *temp;
+
+	if (!msg_head) {
+		pr_err("%s: Invalid msg pointer\n", __func__);
+		return;
+	}
+
+	while (!skb_queue_empty(msg_head)) {
+		temp = skb_dequeue(msg_head);
+		kfree_skb(temp);
+	}
+	kfree(msg_head);
+}
+
+static int msm_ipc_router_create(struct net *net,
+				 struct socket *sock,
+				 int protocol,
+				 int kern)
+{
+	struct sock *sk;
+	struct msm_ipc_port *port_ptr;
+
+	if (unlikely(protocol != 0)) {
+		pr_err("%s: Protocol not supported\n", __func__);
+		return -EPROTONOSUPPORT;
+	}
+
+	switch (sock->type) {
+	case SOCK_DGRAM:
+		break;
+	default:
+		pr_err("%s: Protocol type not supported\n", __func__);
+		return -EPROTOTYPE;
+	}
+
+	sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto);
+	if (!sk) {
+		pr_err("%s: sk_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
+	if (!port_ptr) {
+		pr_err("%s: port_ptr alloc failed\n", __func__);
+		sk_free(sk);
+		return -ENOMEM;
+	}
+
+	sock->ops = &msm_ipc_proto_ops;
+	sock_init_data(sock, sk);
+	sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
+
+	msm_ipc_sk(sk)->port = port_ptr;
+
+	return 0;
+}
+
+int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
+			       int uaddr_len)
+{
+	struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr;
+	int ret;
+
+	if (!sk)
+		return -EINVAL;
+
+	if (!uaddr_len) {
+		pr_err("%s: Invalid address length\n", __func__);
+		return -EINVAL;
+	}
+
+	if (addr->family != AF_MSM_IPC) {
+		pr_err("%s: Address family is incorrect\n", __func__);
+		return -EAFNOSUPPORT;
+	}
+
+	if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
+		pr_err("%s: Address type is incorrect\n", __func__);
+		return -EINVAL;
+	}
+
+	port_ptr = msm_ipc_sk_port(sk);
+	if (!port_ptr)
+		return -ENODEV;
+
+	lock_sock(sk);
+
+	ret = msm_ipc_router_register_server(port_ptr, &addr->address);
+	if (!ret)
+		sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
+
+	release_sock(sk);
+	return ret;
+}
+
+static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
+				  struct msghdr *m, size_t total_len)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
+	struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
+	struct sk_buff_head *msg;
+	int ret;
+
+	if (!dest)
+		return -EDESTADDRREQ;
+
+	if (m->msg_namelen < sizeof(*dest) || dest->family != AF_MSM_IPC)
+		return -EINVAL;
+
+	if (total_len > MAX_IPC_PKT_SIZE)
+		return -EINVAL;
+
+	lock_sock(sk);
+	msg = msm_ipc_router_build_msg(m->msg_iovlen, m->msg_iov, total_len);
+	if (!msg) {
+		pr_err("%s: Msg build failure\n", __func__);
+		ret = -ENOMEM;
+		goto out_sendmsg;
+	}
+
+	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
+	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
+		ret = total_len;
+
+out_sendmsg:
+	release_sock(sk);
+	return ret;
+}
+
+static int msm_ipc_router_recvmsg(struct kiocb *iocb, struct socket *sock,
+				  struct msghdr *m, size_t buf_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
+	struct sk_buff_head *msg;
+	long timeout;
+	int ret;
+
+	if (m->msg_iovlen != 1)
+		return -EOPNOTSUPP;
+
+	if (!buf_len)
+		return -EINVAL;
+
+	lock_sock(sk);
+	timeout = sk->sk_rcvtimeo;
+	mutex_lock(&port_ptr->port_rx_q_lock);
+	while (list_empty(&port_ptr->port_rx_q)) {
+		mutex_unlock(&port_ptr->port_rx_q_lock);
+		release_sock(sk);
+		if (timeout < 0) {
+			ret = wait_event_interruptible(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q));
+			if (ret)
+				return ret;
+		} else if (timeout > 0) {
+			timeout = wait_event_interruptible_timeout(
+					port_ptr->port_rx_wait_q,
+					!list_empty(&port_ptr->port_rx_q),
+					timeout);
+			if (timeout < 0)
+				return -EFAULT;
+		}
+
+		if (timeout == 0)
+			return -ETIMEDOUT;
+		lock_sock(sk);
+		mutex_lock(&port_ptr->port_rx_q_lock);
+	}
+	mutex_unlock(&port_ptr->port_rx_q_lock);
+
+	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
+	if (ret <= 0 || !msg) {
+		release_sock(sk);
+		return ret;
+	}
+
+	ret = msm_ipc_router_extract_msg(m, msg);
+	msm_ipc_router_release_msg(msg);
+	msg = NULL;
+	release_sock(sk);
+	return ret;
+}
+
+static int msm_ipc_router_ioctl(struct socket *sock,
+				unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr;
+	struct server_lookup_args server_arg;
+	struct msm_ipc_port_addr *port_addr = NULL;
+	unsigned int n, port_addr_sz = 0;
+	int ret;
+
+	if (!sk)
+		return -EINVAL;
+
+	lock_sock(sk);
+	port_ptr = msm_ipc_sk_port(sock->sk);
+	if (!port_ptr) {
+		release_sock(sk);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case IPC_ROUTER_IOCTL_GET_VERSION:
+		n = IPC_ROUTER_VERSION;
+		ret = put_user(n, (unsigned int *)arg);
+		break;
+
+	case IPC_ROUTER_IOCTL_GET_MTU:
+		n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
+		ret = put_user(n, (unsigned int *)arg);
+		break;
+
+	case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
+		ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
+		break;
+
+	case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
+		ret = copy_from_user(&server_arg, (void *)arg,
+				     sizeof(server_arg));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (server_arg.num_entries_in_array < 0) {
+			ret = -EINVAL;
+			break;
+		}
+		if (server_arg.num_entries_in_array) {
+			port_addr_sz = server_arg.num_entries_in_array *
+					sizeof(*port_addr);
+			port_addr = kmalloc(port_addr_sz, GFP_KERNEL);
+			if (!port_addr) {
+				ret = -ENOMEM;
+				break;
+			}
+		}
+		ret = msm_ipc_router_lookup_server_name(&server_arg.port_name,
+				port_addr, server_arg.num_entries_in_array);
+		if (ret < 0) {
+			pr_err("%s: Server not found\n", __func__);
+			ret = -ENODEV;
+			kfree(port_addr);
+			break;
+		}
+		server_arg.num_entries_found = ret;
+
+		ret = copy_to_user((void *)arg, &server_arg,
+				   sizeof(server_arg));
+		if (port_addr_sz) {
+			ret = copy_to_user((void *)(arg + sizeof(server_arg)),
+					   port_addr, port_addr_sz);
+			if (ret)
+				ret = -EFAULT;
+			kfree(port_addr);
+		}
+		break;
+
+	case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
+		ret = msm_ipc_router_bind_control_port(port_ptr);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	release_sock(sk);
+	return ret;
+}
+
+static unsigned int msm_ipc_router_poll(struct file *file,
+			struct socket *sock, poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr;
+	uint32_t mask = 0;
+
+	if (!sk)
+		return -EINVAL;
+
+	port_ptr = msm_ipc_sk_port(sk);
+	if (!port_ptr)
+		return -EINVAL;
+
+	poll_wait(file, &port_ptr->port_rx_wait_q, wait);
+
+	if (!list_empty(&port_ptr->port_rx_q))
+		mask |= (POLLRDNORM | POLLIN);
+
+	return mask;
+}
+
+static int msm_ipc_router_close(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
+	int ret;
+
+	lock_sock(sk);
+	ret = msm_ipc_router_close_port(port_ptr);
+	release_sock(sk);
+	sock_put(sk);
+	sock->sk = NULL;
+
+	return ret;
+}
+
+static const struct net_proto_family msm_ipc_family_ops = {
+	.owner		= THIS_MODULE,
+	.family		= AF_MSM_IPC,
+	.create		= msm_ipc_router_create
+};
+
+static const struct proto_ops msm_ipc_proto_ops = {
+	.owner		= THIS_MODULE,
+	.family         = AF_MSM_IPC,
+	.bind		= msm_ipc_router_bind,
+	.connect	= sock_no_connect,
+	.sendmsg	= msm_ipc_router_sendmsg,
+	.recvmsg	= msm_ipc_router_recvmsg,
+	.ioctl		= msm_ipc_router_ioctl,
+	.poll		= msm_ipc_router_poll,
+	.setsockopt	= sock_no_setsockopt,
+	.getsockopt	= sock_no_getsockopt,
+	.release	= msm_ipc_router_close,
+};
+
+static struct proto msm_ipc_proto = {
+	.name           = "MSM_IPC",
+	.owner          = THIS_MODULE,
+	.obj_size       = sizeof(struct msm_ipc_sock),
+};
+
+int msm_ipc_router_init_sockets(void)
+{
+	int ret;
+
+	ret = proto_register(&msm_ipc_proto, 1);
+	if (ret) {
+		pr_err("Failed to register MSM_IPC protocol type\n");
+		goto out_init_sockets;
+	}
+
+	ret = sock_register(&msm_ipc_family_ops);
+	if (ret) {
+		pr_err("Failed to register MSM_IPC socket type\n");
+		proto_unregister(&msm_ipc_proto);
+		goto out_init_sockets;
+	}
+
+	sockets_enabled = 1;
+out_init_sockets:
+	return ret;
+}
+
+void msm_ipc_router_exit_sockets(void)
+{
+	if (!sockets_enabled)
+		return;
+
+	sockets_enabled = 0;
+	sock_unregister(msm_ipc_family_ops.family);
+	proto_unregister(&msm_ipc_proto);
+}
-- 
1.7.3.3

Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related

* [PATCH 3/3] net: msm_ipc: Add SMD Transport to the MSM_IPC Router
From: Karthikeyan Ramasubramanian @ 2011-06-08 17:51 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-arm-msm, Karthikeyan Ramasubramanian

Add a packet oriented SMD Transport to be used by the MSM_IPC Router.

Change-Id: Id992a23acad5b7ad262138163730dfd5b7a56ab1
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
---
 net/msm_ipc/Kconfig                   |    9 ++
 net/msm_ipc/Makefile                  |    1 +
 net/msm_ipc/msm_ipc_router.c          |   86 +++++++++++++
 net/msm_ipc/msm_ipc_router_smd_xprt.c |  226 +++++++++++++++++++++++++++++++++
 4 files changed, 322 insertions(+), 0 deletions(-)
 create mode 100644 net/msm_ipc/msm_ipc_router_smd_xprt.c

diff --git a/net/msm_ipc/Kconfig b/net/msm_ipc/Kconfig
index 9114d7d..5368a40 100644
--- a/net/msm_ipc/Kconfig
+++ b/net/msm_ipc/Kconfig
@@ -13,3 +13,12 @@ menuconfig MSM_IPC
 
 	Say Y (or M) here if you build for a phone product (e.g. Android)
 	that uses MSM_IPC as transport, if unsure say N.
+
+config MSM_IPC_ROUTER_SMD_XPRT
+	tristate "MSM_IPC_ROUTER SMD Transport"
+	depends on MSM_IPC
+	depends on MSM_SMD
+	default n
+	---help---
+	This will provide a packet interface to the MSM_IPC Router over SMD.
+	Say Y if you will be using a MSM_IPC over SMD transport.
diff --git a/net/msm_ipc/Makefile b/net/msm_ipc/Makefile
index b9a0dfb..4f73e67 100644
--- a/net/msm_ipc/Makefile
+++ b/net/msm_ipc/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_MSM_IPC) := msm_ipc.o
+obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += msm_ipc_router_smd_xprt.o
 
 msm_ipc-y += msm_ipc_router.o msm_ipc_socket.o
diff --git a/net/msm_ipc/msm_ipc_router.c b/net/msm_ipc/msm_ipc_router.c
index 0cd0a02..80bd931 100644
--- a/net/msm_ipc/msm_ipc_router.c
+++ b/net/msm_ipc/msm_ipc_router.c
@@ -272,6 +272,7 @@ void release_pkt(struct rr_packet *pkt)
 	kfree(pkt);
 	return;
 }
+EXPORT_SYMBOL(release_pkt);
 
 static int post_control_ports(struct rr_packet *pkt)
 {
@@ -1636,6 +1637,91 @@ int msm_ipc_router_close(void)
 	return 0;
 }
 
+#if defined(CONFIG_MSM_IPC_ROUTER_SMD_XPRT)
+static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_xprt_info *xprt_info;
+	struct msm_ipc_routing_table_entry *rt_entry;
+
+	xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
+			    GFP_KERNEL);
+	if (!xprt_info)
+		return -ENOMEM;
+
+	xprt_info->xprt = xprt;
+	xprt_info->initialized = 0;
+	xprt_info->remote_node_id = -1;
+	INIT_LIST_HEAD(&xprt_info->pkt_list);
+	init_waitqueue_head(&xprt_info->read_wait);
+	mutex_init(&xprt_info->rx_lock);
+	mutex_init(&xprt_info->tx_lock);
+	xprt_info->need_len = 0;
+	INIT_WORK(&xprt_info->read_data, do_read_data);
+	INIT_LIST_HEAD(&xprt_info->list);
+
+	xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
+	if (!xprt_info->workqueue) {
+		kfree(xprt_info);
+		return -ENOMEM;
+	}
+
+	if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
+		xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
+		xprt_info->initialized = 1;
+	}
+
+	mutex_lock(&xprt_info_list_lock);
+	list_add_tail(&xprt_info->list, &xprt_info_list);
+	mutex_unlock(&xprt_info_list_lock);
+
+	mutex_lock(&routing_table_lock);
+	if (!routing_table_inited) {
+		init_routing_table();
+		rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
+		add_routing_table_entry(rt_entry);
+		routing_table_inited = 1;
+	}
+	mutex_unlock(&routing_table_lock);
+
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
+
+	xprt->priv = xprt_info;
+
+	return 0;
+}
+
+void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
+				unsigned event,
+				void *data)
+{
+	struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
+	struct rr_packet *pkt;
+
+	if (event == IPC_ROUTER_XPRT_EVENT_OPEN) {
+		msm_ipc_router_add_xprt(xprt);
+		return;
+	}
+
+	if (!data)
+		return;
+
+	while (!xprt_info) {
+		msleep(100);
+		xprt_info = xprt->priv;
+	}
+
+	pkt = clone_pkt((struct rr_packet *)data);
+	if (!pkt)
+		return;
+
+	mutex_lock(&xprt_info->rx_lock);
+	list_add_tail(&pkt->list, &xprt_info->pkt_list);
+	wake_up(&xprt_info->read_wait);
+	mutex_unlock(&xprt_info->rx_lock);
+}
+EXPORT_SYMBOL(msm_ipc_router_xprt_notify);
+#endif
+
 static int __init msm_ipc_router_init(void)
 {
 	int i, ret;
diff --git a/net/msm_ipc/msm_ipc_router_smd_xprt.c b/net/msm_ipc/msm_ipc_router_smd_xprt.c
new file mode 100644
index 0000000..1402a8b
--- /dev/null
+++ b/net/msm_ipc/msm_ipc_router_smd_xprt.c
@@ -0,0 +1,226 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * IPC ROUTER SMD XPRT module.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/msm_smd.h>
+
+#include "msm_ipc_router.h"
+
+#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
+
+struct msm_ipc_router_smd_xprt {
+	struct msm_ipc_router_xprt xprt;
+
+	smd_channel_t *channel;
+};
+
+static struct msm_ipc_router_smd_xprt smd_remote_xprt;
+
+static void smd_xprt_read_data(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_read_data, smd_xprt_read_data);
+static struct workqueue_struct *smd_xprt_workqueue;
+
+static wait_queue_head_t write_avail_wait_q;
+static struct rr_packet *in_pkt;
+static int is_partial_in_pkt;
+
+static int msm_ipc_router_smd_remote_write_avail(void)
+{
+	return smd_write_avail(smd_remote_xprt.channel);
+}
+
+static int msm_ipc_router_smd_remote_write(void *data,
+					   uint32_t len,
+					   uint32_t type)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *ipc_rtr_pkt;
+	int align_sz, align_data = 0;
+	int offset, sz_written = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	if (!len || pkt->length != len)
+		return -EINVAL;
+
+	align_sz = ALIGN_SIZE(pkt->length);
+
+	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
+		offset = 0;
+		while (offset < ipc_rtr_pkt->len) {
+			wait_event_interruptible_timeout(write_avail_wait_q,
+				smd_write_avail(smd_remote_xprt.channel),
+				msecs_to_jiffies(50));
+
+			sz_written = smd_write(smd_remote_xprt.channel,
+					  ipc_rtr_pkt->data + offset,
+					  (ipc_rtr_pkt->len - offset));
+			offset += sz_written;
+			sz_written = 0;
+		}
+	}
+
+	if (align_sz) {
+		wait_event_interruptible_timeout(write_avail_wait_q,
+			(smd_write_avail(smd_remote_xprt.channel) >=
+			 align_sz), msecs_to_jiffies(50));
+
+		smd_write(smd_remote_xprt.channel, &align_data, align_sz);
+	}
+	return len;
+}
+
+static int msm_ipc_router_smd_remote_close(void)
+{
+	return smd_close(smd_remote_xprt.channel);
+}
+
+static void smd_xprt_read_data(struct work_struct *work)
+{
+	int pkt_size, sz_read, sz;
+	struct sk_buff *ipc_rtr_pkt;
+	void *data;
+
+	while ((pkt_size = smd_cur_packet_size(smd_remote_xprt.channel)) &&
+		smd_read_avail(smd_remote_xprt.channel)) {
+		if (!is_partial_in_pkt) {
+			in_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
+			if (!in_pkt) {
+				pr_err("%s: Couldn't alloc rr_packet\n",
+					__func__);
+				return;
+			}
+
+			in_pkt->pkt_fragment_q = kmalloc(
+						  sizeof(struct sk_buff_head),
+						  GFP_KERNEL);
+			if (!in_pkt->pkt_fragment_q) {
+				pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+					__func__);
+				kfree(in_pkt);
+				return;
+			}
+			skb_queue_head_init(in_pkt->pkt_fragment_q);
+			is_partial_in_pkt = 1;
+		}
+
+		if ((pkt_size >= MIN_FRAG_SZ) &&
+		    (smd_read_avail(smd_remote_xprt.channel) < MIN_FRAG_SZ))
+			return;
+
+		sz = smd_read_avail(smd_remote_xprt.channel);
+		do {
+			ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
+			if (!ipc_rtr_pkt) {
+				if (sz <= (PAGE_SIZE/2)) {
+					queue_delayed_work(smd_xprt_workqueue,
+						   &work_read_data,
+						   msecs_to_jiffies(100));
+					return;
+				}
+				sz = sz / 2;
+			}
+		} while (!ipc_rtr_pkt);
+
+		data = skb_put(ipc_rtr_pkt, sz);
+		sz_read = smd_read(smd_remote_xprt.channel, data, sz);
+		if (sz_read != sz) {
+			pr_err("%s: Couldn't read completely\n", __func__);
+			kfree_skb(ipc_rtr_pkt);
+			release_pkt(in_pkt);
+			is_partial_in_pkt = 0;
+			return;
+		}
+		skb_queue_tail(in_pkt->pkt_fragment_q, ipc_rtr_pkt);
+		in_pkt->length += sz_read;
+		if (sz_read != pkt_size)
+			is_partial_in_pkt = 1;
+		else
+			is_partial_in_pkt = 0;
+
+		if (!is_partial_in_pkt) {
+			msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
+					   IPC_ROUTER_XPRT_EVENT_DATA,
+					   (void *)in_pkt);
+			release_pkt(in_pkt);
+			in_pkt = NULL;
+		}
+	}
+}
+
+static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
+{
+	if (event == SMD_EVENT_DATA) {
+		if (smd_read_avail(smd_remote_xprt.channel))
+			queue_delayed_work(smd_xprt_workqueue,
+					   &work_read_data, 0);
+		if (smd_write_avail(smd_remote_xprt.channel))
+			wake_up(&write_avail_wait_q);
+	}
+}
+
+static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	smd_xprt_workqueue = create_singlethread_workqueue("smd_xprt");
+	if (!smd_xprt_workqueue)
+		return -ENOMEM;
+
+	smd_remote_xprt.xprt.name = "msm_ipc_router_smd_xprt";
+	smd_remote_xprt.xprt.link_id = 1;
+	smd_remote_xprt.xprt.read_avail = NULL;
+	smd_remote_xprt.xprt.read = NULL;
+	smd_remote_xprt.xprt.write_avail =
+		msm_ipc_router_smd_remote_write_avail;
+	smd_remote_xprt.xprt.write = msm_ipc_router_smd_remote_write;
+	smd_remote_xprt.xprt.close = msm_ipc_router_smd_remote_close;
+	smd_remote_xprt.xprt.priv = NULL;
+
+	init_waitqueue_head(&write_avail_wait_q);
+
+	rc = smd_open("SMD_RPCRPY_CNTL", &smd_remote_xprt.channel, NULL,
+		      msm_ipc_router_smd_remote_notify);
+	if (rc < 0) {
+		destroy_workqueue(smd_xprt_workqueue);
+		return rc;
+	}
+
+	msm_ipc_router_xprt_notify(&smd_remote_xprt.xprt,
+				  IPC_ROUTER_XPRT_EVENT_OPEN,
+				  NULL);
+	return 0;
+}
+
+static struct platform_driver msm_ipc_router_smd_remote_driver = {
+	.probe		= msm_ipc_router_smd_remote_probe,
+	.driver		= {
+			.name	= "SMD_RPCRPY_CNTL",
+			.owner	= THIS_MODULE,
+	},
+};
+
+static int __init msm_ipc_router_smd_init(void)
+{
+	return platform_driver_register(&msm_ipc_router_smd_remote_driver);
+}
+
+module_init(msm_ipc_router_smd_init);
+MODULE_DESCRIPTION("RPC Router SMD XPRT");
+MODULE_LICENSE("GPL v2");
-- 
1.7.3.3

Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related

* Re: [af-packet 1/2] Enhance af-packet to provide (near zero)lossless packet capture functionality.
From: Stephen Hemminger @ 2011-06-08 16:03 UTC (permalink / raw)
  To: Chetan Loke; +Cc: netdev, davem, eric.dumazet, kaber, johann.baudy, Chetan Loke
In-Reply-To: <1307502786-1396-2-git-send-email-loke.chetan@gmail.com>

On Tue,  7 Jun 2011 23:13:05 -0400
Chetan Loke <loke.chetan@gmail.com> wrote:

> --- a/include/linux/if_packet.h
> +++ b/include/linux/if_packet.h
> @@ -24,7 +24,7 @@ struct sockaddr_ll {
>  #define PACKET_HOST		0		/* To us		*/
>  #define PACKET_BROADCAST	1		/* To all		*/
>  #define PACKET_MULTICAST	2		/* To group		*/
> -#define PACKET_OTHERHOST	3		/* To someone else 	*/
> +#define PACKET_OTHERHOST	3		/* To someone else	*/

Useless whitespace change in patch. It makes sense to review the resulting
diff and avoid this kind of stuff creeping in.

^ permalink raw reply

* [PATCH] RFC2988bis + taking RTT sample from 3WHS for the passive open side
From: Jerry Chu @ 2011-06-08 18:04 UTC (permalink / raw)
  To: David Miller, Eric Dumazet, Hagen Paul Pfeifer
  Cc: tsunanet, netdev@vger.kernel.org
In-Reply-To: <1307509203-30973-1-git-send-email-hkchu@google.com>

[resent to cc netdev]

This patch lowers the default initRTO from 3secs to 1sec per
RFC2988bis. It falls back to 3secs if the SYN or SYN-ACK packet
has been retransmitted, AND the TCP timestamp option is not on.

It also adds support to take RTT sample during 3WHS on the passive
open side, just like its active open counterpart, and uses it, if
valid, to seed the initRTO for the data transmission phase.

The patch also resets ssthresh to its initial default at the
beginning of the data transmission phase, and reduces cwnd to 1 if
there has been MORE THAN ONE retransmission during 3WHS per RFC5681.

Signed-off-by: H.K. Jerry Chu <hkchu@google.com>
---
 include/linux/tcp.h      |    1 +
 include/net/tcp.h        |   11 +++++++++--
 net/ipv4/syncookies.c    |    1 +
 net/ipv4/tcp_input.c     |   46 +++++++++++++++++++++++++---------------------
 net/ipv4/tcp_ipv4.c      |   11 ++++++++---
 net/ipv4/tcp_minisocks.c |    6 +++++-
 net/ipv6/syncookies.c    |    1 +
 net/ipv6/tcp_ipv6.c      |    5 +++++
 8 files changed, 55 insertions(+), 27 deletions(-)

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index e64f4c6..531ede8 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -282,6 +282,7 @@ struct tcp_request_sock {
 #endif
       u32                             rcv_isn;
       u32                             snt_isn;
+       u32                             snt_synack; /* synack sent time */
 };

 static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index cda30ea..149a415 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -122,7 +122,13 @@ extern void tcp_time_wait(struct sock *sk, int
state, int timeo);
 #endif
 #define TCP_RTO_MAX    ((unsigned)(120*HZ))
 #define TCP_RTO_MIN    ((unsigned)(HZ/5))
-#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ))    /* RFC 1122 initial
RTO value   */
+#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))    /* RFC2988bis initial
RTO value */
+#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ))        /* RFC 1122
initial RTO value, now
+                                                * used as a fallback
RTO for the
+                                                * initial data
transmission if no
+                                                * valid RTT sample
has been acquired,
+                                                * most likely due to
retrans in 3WHS.
+                                                */

 #define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal
interval between probes
                                                        * for local resources.
@@ -295,7 +301,7 @@ static inline void tcp_synq_overflow(struct sock *sk)
 static inline int tcp_synq_no_recent_overflow(const struct sock *sk)
 {
       unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
-       return time_after(jiffies, last_overflow + TCP_TIMEOUT_INIT);
+       return time_after(jiffies, last_overflow + TCP_TIMEOUT_FALLBACK);
 }

 extern struct proto tcp_prot;
@@ -508,6 +514,7 @@ extern void tcp_initialize_rcv_mss(struct sock *sk);
 extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
 extern int tcp_mss_to_mtu(struct sock *sk, int mss);
 extern void tcp_mtup_init(struct sock *sk);
+extern void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt);

 static inline void tcp_bound_rto(const struct sock *sk)
 {
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 2646149..92bb943 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -316,6 +316,7 @@ struct sock *cookie_v4_check(struct sock *sk,
struct sk_buff *skb,
       ireq->wscale_ok         = tcp_opt.wscale_ok;
       ireq->tstamp_ok         = tcp_opt.saw_tstamp;
       req->ts_recent          = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
+       treq->snt_synack        = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsecr : 0;

       /* We throwed the options of the initial SYN away, so we hope
        * the ACK carries the same options again (see RFC1122 4.2.3.8)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index bef9f04..ea0d218 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -880,6 +880,11 @@ static void tcp_init_metrics(struct sock *sk)
               tp->snd_ssthresh = dst_metric(dst, RTAX_SSTHRESH);
               if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
                       tp->snd_ssthresh = tp->snd_cwnd_clamp;
+       } else {
+               /* ssthresh may have been reduced unnecessarily during.
+                * 3WHS. Restore it back to its initial default.
+                */
+               tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
       }
       if (dst_metric(dst, RTAX_REORDERING) &&
           tp->reordering != dst_metric(dst, RTAX_REORDERING)) {
@@ -887,10 +892,7 @@ static void tcp_init_metrics(struct sock *sk)
               tp->reordering = dst_metric(dst, RTAX_REORDERING);
       }

-       if (dst_metric(dst, RTAX_RTT) == 0)
-               goto reset;
-
-       if (!tp->srtt && dst_metric_rtt(dst, RTAX_RTT) <
(TCP_TIMEOUT_INIT << 3))
+       if (dst_metric(dst, RTAX_RTT) == 0 || tp->srtt == 0)
               goto reset;

       /* Initial rtt is determined from SYN,SYN-ACK.
@@ -916,19 +918,26 @@ static void tcp_init_metrics(struct sock *sk)
               tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
       }
       tcp_set_rto(sk);
-       if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT &&
!tp->rx_opt.saw_tstamp) {
 reset:
-               /* Play conservative. If timestamps are not
-                * supported, TCP will fail to recalculate correct
-                * rtt, if initial rto is too small. FORGET ALL AND RESET!
+       if (tp->srtt == 0) {
+               /* RFC2988bis: We've failed to get a valid RTT sample from
+                * 3WHS. This is most likely due to retransmission,
+                * including spurious one. Reset the RTO back to 3secs
+                * from the more aggressive 1sec to avoid more spurious
+                * retransmission.
                */
-               if (!tp->rx_opt.saw_tstamp && tp->srtt) {
-                       tp->srtt = 0;
-                       tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_INIT;
-                       inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT;
-               }
+               tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_FALLBACK;
+               inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK;
       }
-       tp->snd_cwnd = tcp_init_cwnd(tp, dst);
+       /* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been
+        * retransmitted. In light of RFC2988bis' more aggressive 1sec
+        * initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK
+        * retransmission has occurred.
+        */
+       if (tp->total_retrans > 1)
+               tp->snd_cwnd = 1;
+       else
+               tp->snd_cwnd = tcp_init_cwnd(tp, dst);
       tp->snd_cwnd_stamp = tcp_time_stamp;
 }

@@ -3112,12 +3121,13 @@ static void tcp_fastretrans_alert(struct sock
*sk, int pkts_acked, int flag)
       tcp_xmit_retransmit_queue(sk);
 }

-static void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)
+void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)
 {
       tcp_rtt_estimator(sk, seq_rtt);
       tcp_set_rto(sk);
       inet_csk(sk)->icsk_backoff = 0;
 }
+EXPORT_SYMBOL(tcp_valid_rtt_meas);

 /* Read draft-ietf-tcplw-high-performance before mucking
 * with this code. (Supersedes RFC1323)
@@ -5806,12 +5816,6 @@ int tcp_rcv_state_process(struct sock *sk,
struct sk_buff *skb,
                                             tp->rx_opt.snd_wscale;
                               tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);

-                               /* tcp_ack considers this ACK as duplicate
-                                * and does not calculate rtt.
-                                * Force it here.
-                                */
-                               tcp_ack_update_rtt(sk, 0, 0);
-
                               if (tp->rx_opt.tstamp_ok)
                                       tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;

diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 3c8d9b6..5fb504b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -429,8 +429,8 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                       break;

               icsk->icsk_backoff--;
-               inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) <<
-                                        icsk->icsk_backoff;
+               inet_csk(sk)->icsk_rto = (tp->srtt ? __tcp_set_rto(tp) :
+                       TCP_TIMEOUT_INIT) << icsk->icsk_backoff;
               tcp_bound_rto(sk);

               skb = tcp_write_queue_head(sk);
@@ -1384,6 +1384,7 @@ int tcp_v4_conn_request(struct sock *sk, struct
sk_buff *skb)
               isn = tcp_v4_init_sequence(skb);
       }
       tcp_rsk(req)->snt_isn = isn;
+       tcp_rsk(req)->snt_synack = tcp_time_stamp;

       if (tcp_v4_send_synack(sk, dst, req,
                              (struct request_values *)&tmp_ext) ||
@@ -1458,6 +1459,10 @@ struct sock *tcp_v4_syn_recv_sock(struct sock
*sk, struct sk_buff *skb,
               newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;

       tcp_initialize_rcv_mss(newsk);
+       if (tcp_rsk(req)->snt_synack)
+               tcp_valid_rtt_meas(newsk,
+                   tcp_time_stamp - tcp_rsk(req)->snt_synack);
+       newtp->total_retrans = req->retrans;

 #ifdef CONFIG_TCP_MD5SIG
       /* Copy over the MD5 key from the original socket */
@@ -1854,7 +1859,7 @@ static int tcp_v4_init_sock(struct sock *sk)
        * algorithms that we must have the following bandaid to talk
        * efficiently to them.  -DaveM
        */
-       tp->snd_cwnd = 2;
+       tp->snd_cwnd = TCP_INIT_CWND;

       /* See draft-stevens-tcpca-spec-01 for discussion of the
        * initialization of these values.
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 80b1f80..d2fe4e0 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -486,7 +486,7 @@ struct sock *tcp_create_openreq_child(struct sock
*sk, struct request_sock *req,
                * algorithms that we must have the following bandaid to talk
                * efficiently to them.  -DaveM
                */
-               newtp->snd_cwnd = 2;
+               newtp->snd_cwnd = TCP_INIT_CWND;
               newtp->snd_cwnd_cnt = 0;
               newtp->bytes_acked = 0;

@@ -720,6 +720,10 @@ struct sock *tcp_check_req(struct sock *sk,
struct sk_buff *skb,
               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP);
               return NULL;
       }
+       if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)
+               tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;
+       else if (req->retrans) /* don't take RTT sample if retrans && ~TS */
+               tcp_rsk(req)->snt_synack = 0;

       /* OK, ACK is valid, create big socket and
        * feed this segment to it. It will repeat all
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 8b9644a..89d5bf8 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -223,6 +223,7 @@ struct sock *cookie_v6_check(struct sock *sk,
struct sk_buff *skb)
       ireq->wscale_ok         = tcp_opt.wscale_ok;
       ireq->tstamp_ok         = tcp_opt.saw_tstamp;
       req->ts_recent          = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
+       treq->snt_synack        = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsecr : 0;
       treq->rcv_isn = ntohl(th->seq) - 1;
       treq->snt_isn = cookie;

diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 8683664..e7d47e4 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1341,6 +1341,7 @@ static int tcp_v6_conn_request(struct sock *sk,
struct sk_buff *skb)
       }
 have_isn:
       tcp_rsk(req)->snt_isn = isn;
+       tcp_rsk(req)->snt_synack = tcp_time_stamp;

       security_inet_conn_request(sk, skb, req);

@@ -1509,6 +1510,10 @@ static struct sock *
tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
       tcp_sync_mss(newsk, dst_mtu(dst));
       newtp->advmss = dst_metric_advmss(dst);
       tcp_initialize_rcv_mss(newsk);
+       if (tcp_rsk(req)->snt_synack)
+               tcp_valid_rtt_meas(newsk,
+                   tcp_time_stamp - tcp_rsk(req)->snt_synack);
+       newtp->total_retrans = req->retrans;

       newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
       newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
--
1.7.3.1

^ permalink raw reply related

* [PATCH net-next] iph: use default get_stats
From: Stephen Hemminger @ 2011-06-08 18:09 UTC (permalink / raw)
  To: David Miller, netdev

This driver keeps stats in net_device stats therefore it
does not need to define it's own get_stats hook.

Also, use standard format for net_device_ops (without &).

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--- a/drivers/net/usb/ipheth.c	2011-05-12 08:39:09.000000000 -0700
+++ b/drivers/net/usb/ipheth.c	2011-06-08 11:03:50.011606145 -0700
@@ -409,12 +409,6 @@ static void ipheth_tx_timeout(struct net
 	usb_unlink_urb(dev->tx_urb);
 }
 
-static struct net_device_stats *ipheth_stats(struct net_device *net)
-{
-	struct ipheth_device *dev = netdev_priv(net);
-	return &dev->net->stats;
-}
-
 static u32 ipheth_ethtool_op_get_link(struct net_device *net)
 {
 	struct ipheth_device *dev = netdev_priv(net);
@@ -426,11 +420,10 @@ static struct ethtool_ops ops = {
 };
 
 static const struct net_device_ops ipheth_netdev_ops = {
-	.ndo_open = &ipheth_open,
-	.ndo_stop = &ipheth_close,
-	.ndo_start_xmit = &ipheth_tx,
-	.ndo_tx_timeout = &ipheth_tx_timeout,
-	.ndo_get_stats = &ipheth_stats,
+	.ndo_open = ipheth_open,
+	.ndo_stop = ipheth_close,
+	.ndo_start_xmit = ipheth_tx,
+	.ndo_tx_timeout = ipheth_tx_timeout,
 };
 
 static int ipheth_probe(struct usb_interface *intf,

^ permalink raw reply

* Re: [PATCH 4/5] ixgbe: Fix incorrect declaration of ixgbevf_mbx_ops
From: Jeff Kirsher @ 2011-06-08 19:04 UTC (permalink / raw)
  To: Rose, Gregory V
  Cc: Andi Kleen, linux-kernel@vger.kernel.org, Andi Kleen,
	Brandeburg, Jesse, netdev
In-Reply-To: <43F901BD926A4E43B106BF17856F0755018E536956@orsmsx508.amr.corp.intel.com>

On Tue, Jun 7, 2011 at 15:56, Rose, Gregory V <gregory.v.rose@intel.com> wrote:
>> -----Original Message-----
>> From: Andi Kleen [mailto:andi@firstfloor.org]
>> Sent: Tuesday, June 07, 2011 3:27 PM
>> To: linux-kernel@vger.kernel.org
>> Cc: Andi Kleen; Kirsher, Jeffrey T; Brandeburg, Jesse; Rose, Gregory V
>> Subject: [PATCH 4/5] ixgbe: Fix incorrect declaration of ixgbevf_mbx_ops
>>
>> From: Andi Kleen <ak@linux.intel.com>
>>
>> The header extern type of ixgbevf_mbx_ops disagreed with
>> the actual declaration. Fix this here.
>>
>> This is rather scary. I haven't tested it. Did this
>> ever work?
>>
>> Cc: jeffrey.t.kirsher@intel.com
>> Cc: jesse.brandeburg@intel.com
>> Cc: gregory.v.rose@intel.com
>> Signed-off-by: Andi Kleen <ak@linux.intel.com>
>> ---
>>  drivers/net/ixgbevf/ixgbevf.h |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ixgbevf/ixgbevf.h
>> index b703f60..a2bbbb3 100644
>> --- a/drivers/net/ixgbevf/ixgbevf.h
>> +++ b/drivers/net/ixgbevf/ixgbevf.h
>> @@ -279,7 +279,7 @@ enum ixgbevf_boards {
>>
>>  extern struct ixgbevf_info ixgbevf_82599_vf_info;
>>  extern struct ixgbevf_info ixgbevf_X540_vf_info;
>> -extern struct ixgbe_mac_operations ixgbevf_mbx_ops;
>> +extern struct ixgbe_mbx_operations ixgbevf_mbx_ops;
>>
>>  /* needed by ethtool.c */
>>  extern char ixgbevf_driver_name[];
>> --
>> 1.7.4.4
>
> [Greg Rose]
> Huh.
>
> Well, mbx ops is a table of 8 pointers and mac ops is a table of 11 pointers, so the copy would have over written 3 * pointer-size words of some other memory.  But the 8 ops copied would have been correct so to the extent that we called them they worked.
>
> Now that I look at it you missed a another spot where the copy is done that uses the ixgbe_mac_operations instead of the ixgbe_mbx_operations.
>
> I'll fix that up.
>
> Nice catch!
>
> - Greg
> --

I have an updated patch by Greg in my queue, which I will be
submitting through David Miller's networking tree.  Thanks Andi and
Greg!

-- 
Cheers,
Jeff

^ permalink raw reply

* pull request: wireless-next-2.6 2011-06-08
From: John W. Linville @ 2011-06-08 19:12 UTC (permalink / raw)
  To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

Dave,

Here is the first big wireless pull request for the 3.1 cycle.
As usual, this covers a lot of ground -- mostly driver updates.

Some highlights include some math algorithm additions to lib/ from
the Broadcom team, sizeable update series for rt2x00 and rtlwifi,
the usual iwlagn and ath9k updates from the Intel and Atheros teams
(and a few other folks), some more mwifiex updates from the Marvell
folks, and a bunch of bcma, ssb and b43 updates from Rafał Miłecki.

Please let me know if there are problems!

Thanks,

John

---

The following changes since commit ffbc03bc75b39c7bd412e7cc6d2185c11b0ffedd:

  net: add needed interrupt.h (2011-06-08 00:15:34 -0700)

are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6.git for-davem

Amitkumar Karwar (1):
      mwifiex: remove support for old chipsets W0/W1

Arend van Spriel (2):
      lib: crc8: add new library module providing crc8 algorithm
      lib: cordic: add library module providing cordic angle calculation

Daniel Drake (1):
      libertas_sdio: handle spurious interrupts

Daniel Halperin (1):
      iwlwifi: disambiguate invalid DMA index warnings

Emmanuel Grumbach (2):
      iwlagn: solve sparse warning
      iwlagn: free the ICT ISR when the request_irq failed

Fabrice Deyber (1):
      ath9k: Further fix for mesh beaconing

Felix Fietkau (3):
      ath9k: unify edma and non-edma tx code, improve tx fifo handling
      ath9k_hw: remove ath9k_hw_get_desc_link
      ath9k: show excessive-retry MPDUs in debugfs

Gertjan van Wingerde (6):
      rt2x00: Enable PA_PE bits in TX_PIN_CFG according to active band.
      rt2x00: Don't disable G0 PA_PE bit in case of BT coexistence.
      rt2x00: Add support for RT3572/RT3592/RT3592+Bluetooth combo card
      rt2x00: Interface sequence lock doesn't have to disable interrupts.
      rt2x00: Move rt2800_txdone and rt2800_txdone_entry_check to rt2800usb.
      rt2x00: Enabled rt35xx device support by default.

Greg Dietsche (6):
      iwlegacy: remove unreachable code
      iwlegacy: remove unecessary if statement
      iwlegacy: return -EINVAL instead of -1
      iwlegacy: propagate error return value
      iwlegacy: add missing null check
      iwlwifi: remove unecessary if statement

Javier Lopez (1):
      mac80211_hwsim driver support userspace frame tx/rx

Johannes Berg (3):
      iwlagn: fix dual-mode RXON
      iwlagn: advertise interface combinations
      iwlagn: fix interface combinations

John W. Linville (3):
      Revert "mac80211: Skip tailroom reservation for full HW-crypto devices"
      Merge branch 'master' of git://git.kernel.org/.../linville/wireless-2.6
      Merge branch 'master' of git://git.kernel.org/.../linville/wireless-next-2.6 into for-davem

Larry Finger (9):
      b43: Fix warnings from gcc 4.6.0
      rtlwifi: Fix warnings from gcc 4.6.0
      rtl8192c-common: Fix warnings from gcc 4.6.0
      rtl8192ce: Fix warnings from gcc 4.6.0
      rtl8192cu: Fix warnings from gcc 4.6.0
      rtl8192se: Fix warnings from gcc 4.6.0
      b43legacy: Fix warnings from gcc 4.6.0
      rtlwifi: rtl8192se: Use write barrier when assigning ownership
      rtlwifi: rtl8192se: Synchronize IRQ after disabling it

Luis R. Rodriguez (1):
      cfg80211: skip disabled channels on channel survey

Mike McCormack (8):
      rtlwifi: Synchronize IRQ after disabling it
      rtlwifi: Remove set_rfpowerstate_inprogress
      rtlwifi: Store loop index in local variable
      rtlwifi: Run IPS leave work in a tasklet
      rtlwifi: Don't block interrupts in spinlocks
      rtlwifi: Assign rx buffer ownership to hardware last
      rtlwifi: Use write barrier when assigning ownership
      rtlwifi: Fix logic in rx_interrupt

Mohammed Shafi Shajakhan (7):
      ath9k: remove redundant if check
      ath9k: make ath9k_setpower function as static
      ath9k: mark few functions as static
      ath9k: wake up chip before initializing PAPRD table
      ath9k: Add a debug entry to start/stop ANI
      ath9k: better position PAPRD debug message
      ath9k: make use of a helper to get paprd scale factor

Nick Kossifidis (1):
      ath5k: Disable fast channel switching by default

Rafał Miłecki (21):
      b43: rename ssb_device variable in ssb specific functions
      b43: add bus device abstraction layer
      b43: bus: abstract R/W operations
      b43: bus: abstract 80211 core info
      b43: bus: abstract SPROM
      b43: bus: abstract device structs and irq
      b43: bus: abstract chip info
      b43: bus: abstract board info
      b43: bus: abstract bus and core operations
      bcma: add IRQ number and pointer to DMA dev
      bcma: pci: implement interrupts control
      b43: LP-PHY: use new pointers path to access ssb_device
      b43: SDIO: use new pointers path to access ssb_device
      b43: use new pointers path to access ssb_device in SSB specific places
      b43: bus: add helpers for checking host type
      bcma: host pci: implement block R/W operations
      ssb: fix PCI(e) driver regression causing oops on PCI cards
      b43: do not use SSB specific flags when calling core reset function
      bcma: read SPROM and extract MAC from it
      b43: add an option to register BROKEN bcma driver
      b43: add BCMA 80211 core specific defines

Rajkumar Manoharan (2):
      ath9k: Remove ATH9K_BEACON_PERIOD mask
      ath9k: Handle IBSS status changes in BSS_CHANGED_IBSS

Shahar Levi (2):
      mac80211: Stop BA session event from device
      wl12xx: Stop BA session event from device

Stanislaw Gruszka (5):
      iwlagn: fix channel switch locking
      iwlagn: use cts-to-self protection on 5000 adapters series
      rt2x00: fix rmmod crash
      iwl4965: set tx power after rxon_assoc
      iwlagn: refactor iwlagn_mac_channel_switch

Thadeu Lima de Souza Cascardo (1):
      mac80211: call dev_alloc_name before copying name to sdata

Wey-Yi Guy (10):
      nl80211: add testmode dump support
      iwlagn: send tx power command if defer cause by RXON not match
      iwlagn: remove un-necessary tx power ops
      iwlagn: change the logging level for aggregation enable check
      iwlagn: change log to better represent the state of aggregation process
      iwlagn: save the latest smps mode
      iwlagn: set smps mode after assoc for 1000 device
      iwlagn: move all post scan functions in one place
      iwlagn: direct call to post_scan function
      iwlagn: call commit_rxon function directly

Yogesh Ashok Powar (4):
      mwifiex: remove list traversal in mwifiex_num_pkts_in_txq
      mwifiex: Remove redundant skb_queue_empty checks
      mwifiex: adding check for enough space before padding
      mwifiex: disable transmission buffer aggregation for AMSDU packets

Zefir Kurtisi (1):
      minstrel_ht: fixed rate mode through debugfs

 drivers/bcma/Kconfig                               |    5 +
 drivers/bcma/Makefile                              |    2 +-
 drivers/bcma/bcma_private.h                        |    3 +
 drivers/bcma/driver_pci.c                          |   23 +
 drivers/bcma/host_pci.c                            |   52 +++
 drivers/bcma/main.c                                |    9 +
 drivers/bcma/sprom.c                               |  162 +++++++
 drivers/net/wireless/ath/ath.h                     |    1 +
 drivers/net/wireless/ath/ath5k/base.c              |   11 +-
 drivers/net/wireless/ath/ath5k/reset.c             |    5 +-
 drivers/net/wireless/ath/ath9k/ar9002_mac.c        |    6 -
 drivers/net/wireless/ath/ath9k/ar9003_mac.c        |    8 -
 drivers/net/wireless/ath/ath9k/ar9003_paprd.c      |   24 +-
 drivers/net/wireless/ath/ath9k/ath9k.h             |    8 +-
 drivers/net/wireless/ath/ath9k/beacon.c            |   21 +-
 drivers/net/wireless/ath/ath9k/debug.c             |   59 +++-
 drivers/net/wireless/ath/ath9k/debug.h             |    1 +
 drivers/net/wireless/ath/ath9k/htc_drv_beacon.c    |    8 +-
 drivers/net/wireless/ath/ath9k/hw-ops.h            |    5 -
 drivers/net/wireless/ath/ath9k/hw.c                |    6 +-
 drivers/net/wireless/ath/ath9k/hw.h                |    2 -
 drivers/net/wireless/ath/ath9k/init.c              |    2 +-
 drivers/net/wireless/ath/ath9k/main.c              |  150 ++++---
 drivers/net/wireless/ath/ath9k/xmit.c              |  338 ++++++---------
 drivers/net/wireless/b43/Kconfig                   |    5 +
 drivers/net/wireless/b43/Makefile                  |    1 +
 drivers/net/wireless/b43/b43.h                     |   51 ++-
 drivers/net/wireless/b43/bus.c                     |  122 +++++
 drivers/net/wireless/b43/bus.h                     |   62 +++
 drivers/net/wireless/b43/dma.c                     |   38 +-
 drivers/net/wireless/b43/leds.c                    |   15 +-
 drivers/net/wireless/b43/lo.c                      |    6 +-
 drivers/net/wireless/b43/main.c                    |  234 ++++++----
 drivers/net/wireless/b43/main.h                    |    2 +-
 drivers/net/wireless/b43/phy_a.c                   |   21 +-
 drivers/net/wireless/b43/phy_common.c              |    8 +-
 drivers/net/wireless/b43/phy_g.c                   |   92 ++--
 drivers/net/wireless/b43/phy_lp.c                  |  135 +++---
 drivers/net/wireless/b43/phy_n.c                   |   37 +-
 drivers/net/wireless/b43/pio.c                     |   10 +-
 drivers/net/wireless/b43/rfkill.c                  |    9 +-
 drivers/net/wireless/b43/sdio.c                    |    4 +-
 drivers/net/wireless/b43/sysfs.c                   |    4 +-
 drivers/net/wireless/b43/tables_lpphy.c            |   15 +-
 drivers/net/wireless/b43/wa.c                      |   24 +-
 drivers/net/wireless/b43/xmit.c                    |    2 +-
 drivers/net/wireless/b43legacy/dma.c               |   10 +-
 drivers/net/wireless/b43legacy/main.c              |    8 +-
 drivers/net/wireless/b43legacy/xmit.c              |    2 -
 drivers/net/wireless/iwlegacy/iwl-4965-rs.c        |    3 +
 drivers/net/wireless/iwlegacy/iwl-4965.c           |    9 +-
 drivers/net/wireless/iwlegacy/iwl-eeprom.c         |    1 -
 drivers/net/wireless/iwlwifi/iwl-1000.c            |    2 +-
 drivers/net/wireless/iwlwifi/iwl-2000.c            |   75 ----
 drivers/net/wireless/iwlwifi/iwl-5000.c            |    5 -
 drivers/net/wireless/iwlwifi/iwl-6000.c            |    4 -
 drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c        |   15 +-
 drivers/net/wireless/iwlwifi/iwl-agn-lib.c         |    7 +-
 drivers/net/wireless/iwlwifi/iwl-agn-rs.c          |    2 +-
 drivers/net/wireless/iwlwifi/iwl-agn-rxon.c        |   91 +++-
 drivers/net/wireless/iwlwifi/iwl-agn-tx.c          |   10 +-
 drivers/net/wireless/iwlwifi/iwl-agn.c             |  206 ++++++---
 drivers/net/wireless/iwlwifi/iwl-core.c            |   13 +-
 drivers/net/wireless/iwlwifi/iwl-core.h            |   15 +-
 drivers/net/wireless/iwlwifi/iwl-dev.h             |   13 +-
 drivers/net/wireless/iwlwifi/iwl-rx.c              |   24 +-
 drivers/net/wireless/iwlwifi/iwl-scan.c            |   10 +-
 drivers/net/wireless/iwlwifi/iwl-tx.c              |    6 +-
 drivers/net/wireless/libertas/if_sdio.c            |   21 +-
 drivers/net/wireless/mac80211_hwsim.c              |  462 +++++++++++++++++++-
 drivers/net/wireless/mac80211_hwsim.h              |  133 ++++++
 drivers/net/wireless/mwifiex/11n_aggr.c            |   54 ++-
 drivers/net/wireless/mwifiex/main.c                |   18 +-
 drivers/net/wireless/mwifiex/main.h                |   12 +-
 drivers/net/wireless/mwifiex/sdio.c                |    8 +-
 drivers/net/wireless/mwifiex/sdio.h                |    2 +
 drivers/net/wireless/mwifiex/wmm.c                 |   30 +-
 drivers/net/wireless/rt2x00/Kconfig                |    9 +-
 drivers/net/wireless/rt2x00/rt2800.h               |   16 +
 drivers/net/wireless/rt2x00/rt2800lib.c            |  376 ++++++++++++----
 drivers/net/wireless/rt2x00/rt2800lib.h            |    1 -
 drivers/net/wireless/rt2x00/rt2800pci.c            |    4 +-
 drivers/net/wireless/rt2x00/rt2800usb.c            |   83 ++++-
 drivers/net/wireless/rt2x00/rt2x00config.c         |    3 +-
 drivers/net/wireless/rt2x00/rt2x00dev.c            |    4 +
 drivers/net/wireless/rt2x00/rt2x00queue.c          |    5 +-
 drivers/net/wireless/rtlwifi/base.c                |    4 -
 drivers/net/wireless/rtlwifi/efuse.c               |    6 +-
 drivers/net/wireless/rtlwifi/pci.c                 |   41 +-
 drivers/net/wireless/rtlwifi/ps.c                  |   48 +--
 drivers/net/wireless/rtlwifi/regd.c                |   18 -
 drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c  |    2 -
 drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c |   12 +-
 drivers/net/wireless/rtlwifi/rtl8192ce/hw.c        |    9 +-
 drivers/net/wireless/rtlwifi/rtl8192ce/phy.c       |   14 +-
 drivers/net/wireless/rtlwifi/rtl8192ce/trx.c       |    4 +-
 drivers/net/wireless/rtlwifi/rtl8192cu/mac.c       |    2 -
 drivers/net/wireless/rtlwifi/rtl8192cu/phy.c       |    2 -
 drivers/net/wireless/rtlwifi/rtl8192se/dm.c        |    5 -
 drivers/net/wireless/rtlwifi/rtl8192se/fw.c        |    2 -
 drivers/net/wireless/rtlwifi/rtl8192se/hw.c        |   12 +-
 drivers/net/wireless/rtlwifi/rtl8192se/phy.c       |   18 +-
 drivers/net/wireless/rtlwifi/rtl8192se/trx.c       |    6 +-
 drivers/net/wireless/rtlwifi/wifi.h                |    2 +-
 drivers/net/wireless/wl12xx/boot.c                 |    3 +-
 drivers/net/wireless/wl12xx/event.c                |   23 +
 drivers/net/wireless/wl12xx/event.h                |   17 +-
 drivers/net/wireless/wl12xx/init.c                 |    1 +
 drivers/net/wireless/wl12xx/main.c                 |    5 +-
 drivers/net/wireless/wl12xx/wl12xx.h               |    1 +
 drivers/ssb/driver_pcicore.c                       |   10 +-
 include/linux/bcma/bcma.h                          |   25 +
 include/linux/bcma/bcma_driver_chipcommon.h        |    1 +
 include/linux/cordic.h                             |   48 ++
 include/linux/crc8.h                               |  101 +++++
 include/net/cfg80211.h                             |   11 +
 include/net/mac80211.h                             |   21 +
 lib/Kconfig                                        |   14 +
 lib/Makefile                                       |    3 +
 lib/cordic.c                                       |  101 +++++
 lib/crc8.c                                         |   86 ++++
 net/mac80211/agg-rx.c                              |   15 +
 net/mac80211/cfg.c                                 |   14 +
 net/mac80211/ht.c                                  |    6 +
 net/mac80211/ieee80211_i.h                         |    3 -
 net/mac80211/iface.c                               |    4 +
 net/mac80211/key.c                                 |   21 +-
 net/mac80211/rc80211_minstrel.c                    |    9 +
 net/mac80211/rc80211_minstrel.h                    |   12 +
 net/mac80211/rc80211_minstrel_ht.c                 |    7 +
 net/mac80211/sta_info.h                            |    3 +
 net/mac80211/tx.c                                  |    7 +-
 net/wireless/nl80211.c                             |  107 +++++-
 133 files changed, 3173 insertions(+), 1293 deletions(-)
 create mode 100644 drivers/bcma/sprom.c
 create mode 100644 drivers/net/wireless/b43/bus.c
 create mode 100644 drivers/net/wireless/b43/bus.h
 create mode 100644 drivers/net/wireless/mac80211_hwsim.h
 create mode 100644 include/linux/cordic.h
 create mode 100644 include/linux/crc8.h
 create mode 100644 lib/cordic.c
 create mode 100644 lib/crc8.c

Omnibus patch available here:

	http://www.kernel.org/pub/linux/kernel/people/linville/wireless-next-2.6-2011-06-08.patch.bz2

-- 
John W. Linville		Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org			might be all we have.  Be ready.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] bnx2i: fix bnx2i driver to test for physical device support of iscsi early
From: Neil Horman @ 2011-06-08 19:29 UTC (permalink / raw)
  To: netdev; +Cc: Neil Horman, Michael Chan, Mike Christie, David S. Miller

Recently reported error message indicating the following error:
bnx2 0003:01:00.1: eth1: Failed waiting for ULP up call to complete

The card in question is:
eth0: Broadcom NetXtreme II BCM5709 1000Base-SX (C0)

Which doesn't appear to support isci.  The undrlying cause of the error above is
the fact that bnx2i assumes that every bnx2 card supports iscsi, and doesn't
actually test for support until the iscsi virtual adapter is being brought up in
bnx2i_start (pointed to by cnic_start).  bnx2i_start tests for
cnic->max_iscsi_conn, and if that value is zero, attempts to unregister the
device from the cnic framework.  Unfortunately, cnic_unregister_device (pointed
to by cnic->unregister_device), waits for the ULP_F_CALL_PENDING to be cleared
before completing, and if that doesn't occur within a few tenths of a second, we
issue the above warning.  Since that flag gets set prior to the call to
bnx2i_start and cleared on its return, we're guaranteed to get this error for
any bnx2 adapter not supporting iscsi.

It seems the correct fix is to detect earlier if an adapter supports iscsi and
not even try to register the device with cnic if it doesn't.  This is already
what bnx2x does, so this patch clones the functionality of that driver for bnx2.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Michael Chan <mchan@broadcom.com>
CC: Mike Christie <michaelc@cs.wisc.edu>
CC: "David S. Miller" <davem@davemloft.net>
---
 drivers/net/bnx2.c              |    2 +-
 drivers/net/cnic.c              |   15 +++------------
 drivers/scsi/bnx2i/bnx2i_init.c |   29 +++++++++++++++--------------
 3 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 57d3293..927e3e6 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -423,7 +423,7 @@ struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
 	cp->drv_ctl = bnx2_drv_ctl;
 	cp->drv_register_cnic = bnx2_register_cnic;
 	cp->drv_unregister_cnic = bnx2_unregister_cnic;
-
+	cp->max_iscsi_conn = bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN);
 	return cp;
 }
 EXPORT_SYMBOL(bnx2_cnic_probe);
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 11a92af..b6f6211 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -2420,13 +2420,11 @@ static int cnic_bnx2x_fcoe_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
 
 static int cnic_bnx2x_fcoe_fw_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
 {
-	struct fcoe_kwqe_destroy *req;
 	union l5cm_specific_data l5_data;
 	struct cnic_local *cp = dev->cnic_priv;
 	int ret;
 	u32 cid;
 
-	req = (struct fcoe_kwqe_destroy *) kwqe;
 	cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
 
 	memset(&l5_data, 0, sizeof(l5_data));
@@ -4218,14 +4216,6 @@ static void cnic_enable_bnx2_int(struct cnic_dev *dev)
 		BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
 }
 
-static void cnic_get_bnx2_iscsi_info(struct cnic_dev *dev)
-{
-	u32 max_conn;
-
-	max_conn = cnic_reg_rd_ind(dev, BNX2_FW_MAX_ISCSI_CONN);
-	dev->max_iscsi_conn = max_conn;
-}
-
 static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
 {
 	struct cnic_local *cp = dev->cnic_priv;
@@ -4550,8 +4540,6 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 		return err;
 	}
 
-	cnic_get_bnx2_iscsi_info(dev);
-
 	return 0;
 }
 
@@ -5230,6 +5218,9 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
 	cp->close_conn = cnic_close_bnx2_conn;
 	cp->next_idx = cnic_bnx2_next_idx;
 	cp->hw_idx = cnic_bnx2_hw_idx;
+
+	cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
+
 	return cdev;
 
 cnic_err:
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 1d24a28..263bc60 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -163,21 +163,14 @@ void bnx2i_start(void *handle)
 	struct bnx2i_hba *hba = handle;
 	int i = HZ;
 
-	if (!hba->cnic->max_iscsi_conn) {
-		printk(KERN_ALERT "bnx2i: dev %s does not support "
-			"iSCSI\n", hba->netdev->name);
+	/**
+	 * We should never register devices that don't support iscsi
+	 * (see bnx2i_init_one), so something is wrong if we try to
+	 * to start an iscsi adapter on hardware wtih 0 supported
+	 * iscsi connections
+	 */
+	BUG_ON(!hba->cnic->max_iscsi_conn);
 
-		if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
-			mutex_lock(&bnx2i_dev_lock);
-			list_del_init(&hba->link);
-			adapter_count--;
-			hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
-			clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-			mutex_unlock(&bnx2i_dev_lock);
-			bnx2i_free_hba(hba);
-		}
-		return;
-	}
 	bnx2i_send_fw_iscsi_init_msg(hba);
 	while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
 		msleep(BNX2I_INIT_POLL_TIME);
@@ -281,6 +274,13 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
 	int rc;
 
 	mutex_lock(&bnx2i_dev_lock);
+	if (!cnic->max_iscsi_conn) {
+		printk(KERN_ALERT "bnx2i: dev %s does not support "
+			"iSCSI\n", hba->netdev->name);
+		rc = -EOPNOTSUPP;
+		goto out;
+	}
+
 	hba->cnic = cnic;
 	rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
 	if (!rc) {
@@ -298,6 +298,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
 	else
 		printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
 
+out:
 	mutex_unlock(&bnx2i_dev_lock);
 
 	return rc;
-- 
1.7.5.2


^ permalink raw reply related

* Re: [PATCH] bnx2i: fix bnx2i driver to test for physical device support of iscsi early
From: Randy Dunlap @ 2011-06-08 19:36 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev, Michael Chan, Mike Christie, David S. Miller
In-Reply-To: <1307561363-11677-1-git-send-email-nhorman@tuxdriver.com>

On Wed,  8 Jun 2011 15:29:23 -0400 Neil Horman wrote:


> ---
>  drivers/net/bnx2.c              |    2 +-
>  drivers/net/cnic.c              |   15 +++------------
>  drivers/scsi/bnx2i/bnx2i_init.c |   29 +++++++++++++++--------------
>  3 files changed, 19 insertions(+), 27 deletions(-)
> 

> diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
> index 1d24a28..263bc60 100644
> --- a/drivers/scsi/bnx2i/bnx2i_init.c
> +++ b/drivers/scsi/bnx2i/bnx2i_init.c
> @@ -163,21 +163,14 @@ void bnx2i_start(void *handle)
>  	struct bnx2i_hba *hba = handle;
>  	int i = HZ;
>  
> -	if (!hba->cnic->max_iscsi_conn) {
> -		printk(KERN_ALERT "bnx2i: dev %s does not support "
> -			"iSCSI\n", hba->netdev->name);
> +	/**

Just use /* here.

> +	 * We should never register devices that don't support iscsi
> +	 * (see bnx2i_init_one), so something is wrong if we try to
> +	 * to start an iscsi adapter on hardware wtih 0 supported
> +	 * iscsi connections
> +	 */
> +	BUG_ON(!hba->cnic->max_iscsi_conn);
>  
> -		if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
> -			mutex_lock(&bnx2i_dev_lock);
> -			list_del_init(&hba->link);
> -			adapter_count--;
> -			hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
> -			clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
> -			mutex_unlock(&bnx2i_dev_lock);
> -			bnx2i_free_hba(hba);
> -		}
> -		return;
> -	}
>  	bnx2i_send_fw_iscsi_init_msg(hba);
>  	while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
>  		msleep(BNX2I_INIT_POLL_TIME);


---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

^ permalink raw reply

* Re: [PATCH] bnx2i: fix bnx2i driver to test for physical device support of iscsi early
From: Michael Chan @ 2011-06-08 20:04 UTC (permalink / raw)
  To: Neil Horman; +Cc: netdev@vger.kernel.org, Mike Christie, David S. Miller
In-Reply-To: <1307561363-11677-1-git-send-email-nhorman@tuxdriver.com>


On Wed, 2011-06-08 at 12:29 -0700, Neil Horman wrote:
> Recently reported error message indicating the following error:
> bnx2 0003:01:00.1: eth1: Failed waiting for ULP up call to complete
> 
> The card in question is:
> eth0: Broadcom NetXtreme II BCM5709 1000Base-SX (C0)
> 
> Which doesn't appear to support isci.  The undrlying cause of the error above is
> the fact that bnx2i assumes that every bnx2 card supports iscsi, and doesn't
> actually test for support until the iscsi virtual adapter is being brought up in
> bnx2i_start (pointed to by cnic_start).  bnx2i_start tests for
> cnic->max_iscsi_conn, and if that value is zero, attempts to unregister the
> device from the cnic framework.  Unfortunately, cnic_unregister_device (pointed
> to by cnic->unregister_device), waits for the ULP_F_CALL_PENDING to be cleared
> before completing, and if that doesn't occur within a few tenths of a second, we
> issue the above warning.  Since that flag gets set prior to the call to
> bnx2i_start and cleared on its return, we're guaranteed to get this error for
> any bnx2 adapter not supporting iscsi.
> 
> It seems the correct fix is to detect earlier if an adapter supports iscsi and
> not even try to register the device with cnic if it doesn't.  This is already
> what bnx2x does, so this patch clones the functionality of that driver for bnx2.

Thanks Neil.  We have a similar patch almost ready to be posted.  The
main difference is that cp->max_iscsi_conn is read ahead of time during
bnx2_init_one().  We cannot read registers in bnx2_cnic_probe() because
it may be called when the device is already down.  I'll send out that
patchset very soon.  Thanks again.

> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> CC: Michael Chan <mchan@broadcom.com>
> CC: Mike Christie <michaelc@cs.wisc.edu>
> CC: "David S. Miller" <davem@davemloft.net>
> ---
>  drivers/net/bnx2.c              |    2 +-
>  drivers/net/cnic.c              |   15 +++------------
>  drivers/scsi/bnx2i/bnx2i_init.c |   29 +++++++++++++++--------------
>  3 files changed, 19 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
> index 57d3293..927e3e6 100644
> --- a/drivers/net/bnx2.c
> +++ b/drivers/net/bnx2.c
> @@ -423,7 +423,7 @@ struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
>  	cp->drv_ctl = bnx2_drv_ctl;
>  	cp->drv_register_cnic = bnx2_register_cnic;
>  	cp->drv_unregister_cnic = bnx2_unregister_cnic;
> -
> +	cp->max_iscsi_conn = bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN);
>  	return cp;
>  }
>  EXPORT_SYMBOL(bnx2_cnic_probe);
> diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
> index 11a92af..b6f6211 100644
> --- a/drivers/net/cnic.c
> +++ b/drivers/net/cnic.c
> @@ -2420,13 +2420,11 @@ static int cnic_bnx2x_fcoe_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
>  
>  static int cnic_bnx2x_fcoe_fw_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
>  {
> -	struct fcoe_kwqe_destroy *req;
>  	union l5cm_specific_data l5_data;
>  	struct cnic_local *cp = dev->cnic_priv;
>  	int ret;
>  	u32 cid;
>  
> -	req = (struct fcoe_kwqe_destroy *) kwqe;
>  	cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
>  
>  	memset(&l5_data, 0, sizeof(l5_data));
> @@ -4218,14 +4216,6 @@ static void cnic_enable_bnx2_int(struct cnic_dev *dev)
>  		BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
>  }
>  
> -static void cnic_get_bnx2_iscsi_info(struct cnic_dev *dev)
> -{
> -	u32 max_conn;
> -
> -	max_conn = cnic_reg_rd_ind(dev, BNX2_FW_MAX_ISCSI_CONN);
> -	dev->max_iscsi_conn = max_conn;
> -}
> -
>  static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
>  {
>  	struct cnic_local *cp = dev->cnic_priv;
> @@ -4550,8 +4540,6 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
>  		return err;
>  	}
>  
> -	cnic_get_bnx2_iscsi_info(dev);
> -
>  	return 0;
>  }
>  
> @@ -5230,6 +5218,9 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
>  	cp->close_conn = cnic_close_bnx2_conn;
>  	cp->next_idx = cnic_bnx2_next_idx;
>  	cp->hw_idx = cnic_bnx2_hw_idx;
> +
> +	cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
> +
>  	return cdev;
>  
>  cnic_err:
> diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
> index 1d24a28..263bc60 100644
> --- a/drivers/scsi/bnx2i/bnx2i_init.c
> +++ b/drivers/scsi/bnx2i/bnx2i_init.c
> @@ -163,21 +163,14 @@ void bnx2i_start(void *handle)
>  	struct bnx2i_hba *hba = handle;
>  	int i = HZ;
>  
> -	if (!hba->cnic->max_iscsi_conn) {
> -		printk(KERN_ALERT "bnx2i: dev %s does not support "
> -			"iSCSI\n", hba->netdev->name);
> +	/**
> +	 * We should never register devices that don't support iscsi
> +	 * (see bnx2i_init_one), so something is wrong if we try to
> +	 * to start an iscsi adapter on hardware wtih 0 supported
> +	 * iscsi connections
> +	 */
> +	BUG_ON(!hba->cnic->max_iscsi_conn);
>  
> -		if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
> -			mutex_lock(&bnx2i_dev_lock);
> -			list_del_init(&hba->link);
> -			adapter_count--;
> -			hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
> -			clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
> -			mutex_unlock(&bnx2i_dev_lock);
> -			bnx2i_free_hba(hba);
> -		}
> -		return;
> -	}
>  	bnx2i_send_fw_iscsi_init_msg(hba);
>  	while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
>  		msleep(BNX2I_INIT_POLL_TIME);
> @@ -281,6 +274,13 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
>  	int rc;
>  
>  	mutex_lock(&bnx2i_dev_lock);
> +	if (!cnic->max_iscsi_conn) {
> +		printk(KERN_ALERT "bnx2i: dev %s does not support "
> +			"iSCSI\n", hba->netdev->name);
> +		rc = -EOPNOTSUPP;
> +		goto out;
> +	}
> +
>  	hba->cnic = cnic;
>  	rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
>  	if (!rc) {
> @@ -298,6 +298,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
>  	else
>  		printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
>  
> +out:
>  	mutex_unlock(&bnx2i_dev_lock);
>  
>  	return rc;



^ permalink raw reply

* [PATCH net-next] ipv6: generate link local address for GRE tunnel
From: Stephen Hemminger @ 2011-06-08 20:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Use same logic as SIT tunnel to handle link local address
for GRE tunnel. OSPFv3 requires link-local address to function.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/ipv6/addrconf.c	2011-05-23 16:56:36.000000000 -0700
+++ b/net/ipv6/addrconf.c	2011-06-08 13:41:36.447300763 -0700
@@ -1559,6 +1559,11 @@ static int addrconf_ifid_sit(u8 *eui, st
 	return -1;
 }
 
+static int addrconf_ifid_gre(u8 *eui, struct net_device *dev)
+{
+	return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr);
+}
+
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
 	switch (dev->type) {
@@ -1572,6 +1577,8 @@ static int ipv6_generate_eui64(u8 *eui, 
 		return addrconf_ifid_infiniband(eui, dev);
 	case ARPHRD_SIT:
 		return addrconf_ifid_sit(eui, dev);
+	case ARPHRD_IPGRE:
+		return addrconf_ifid_gre(eui, dev);
 	}
 	return -1;
 }
@@ -2423,6 +2430,29 @@ static void addrconf_sit_config(struct n
 }
 #endif
 
+#if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE)
+static void addrconf_gre_config(struct net_device *dev)
+{
+	struct inet6_dev *idev;
+	struct in6_addr addr;
+
+	pr_info("ipv6: addrconf_gre_config(%s)\n", dev->name);
+
+	ASSERT_RTNL();
+
+	if ((idev = ipv6_find_idev(dev)) == NULL) {
+		printk(KERN_DEBUG "init gre: add_dev failed\n");
+		return;
+	}
+
+	ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
+	addrconf_prefix_route(&addr, 64, dev, 0, 0);
+
+	if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
+		addrconf_add_linklocal(idev, &addr);
+}
+#endif
+
 static inline int
 ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
 {
@@ -2539,6 +2569,11 @@ static int addrconf_notify(struct notifi
 			addrconf_sit_config(dev);
 			break;
 #endif
+#if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE)
+		case ARPHRD_IPGRE:
+			addrconf_gre_config(dev);
+			break;
+#endif
 		case ARPHRD_TUNNEL6:
 			addrconf_ip6_tnl_config(dev);
 			break;

^ 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