Netdev List
 help / color / mirror / Atom feed
* [Patch net-next v2 1/8] net: introduce generic union inet_addr
From: Cong Wang @ 2013-08-02  7:14 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Daniel Borkmann, Joe Perches, linux-kernel,
	Cong Wang
In-Reply-To: <1375427674-21735-1-git-send-email-amwang@redhat.com>

From: Cong Wang <amwang@redhat.com>

Introduce a generic IP address type, union inet_addr, so that
subsystems don't have to use their own definitions. Because
netpoll already defines union inet_addr, just move it to global.
Some of the helper functions will be used by VXLAN IPv6 code too.

This patch also reuses the "%pIS" specifier, to make it accept
union inet_addr instead of struct sockaddr.

Cc: Daniel Borkmann <dborkman@redhat.com>
Cc: Joe Perches <joe@perches.com>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Cong Wang <amwang@redhat.com>
---
 Documentation/printk-formats.txt |   20 ++++++------
 drivers/net/netconsole.c         |   22 ++++++-------
 include/linux/netpoll.h          |    9 +-----
 include/net/inet_addr.h          |   62 ++++++++++++++++++++++++++++++++++++++
 lib/vsprintf.c                   |   29 ++++++++----------
 net/core/netpoll.c               |   52 ++++++++++++++-----------------
 net/sctp/associola.c             |    6 ++--
 net/sctp/protocol.c              |    6 ++--
 net/sctp/sm_sideeffect.c         |    2 +-
 net/sctp/socket.c                |    4 +-
 10 files changed, 129 insertions(+), 83 deletions(-)
 create mode 100644 include/net/inet_addr.h

diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 3e8cb73..3521cc9 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -123,15 +123,15 @@ IPv6 addresses:
 
 IPv4/IPv6 addresses (generic, with port, flowinfo, scope):
 
-	%pIS	1.2.3.4		or 0001:0002:0003:0004:0005:0006:0007:0008
-	%piS	001.002.003.004	or 00010002000300040005000600070008
-	%pISc	1.2.3.4		or 1:2:3:4:5:6:7:8
-	%pISpc	1.2.3.4:12345	or [1:2:3:4:5:6:7:8]:12345
-	%p[Ii]S[pfschnbl]
+	%pIA	1.2.3.4		or 0001:0002:0003:0004:0005:0006:0007:0008
+	%piA	001.002.003.004	or 00010002000300040005000600070008
+	%pIAc	1.2.3.4		or 1:2:3:4:5:6:7:8
+	%pIApc	1.2.3.4:12345	or [1:2:3:4:5:6:7:8]:12345
+	%p[Ii]A[pfschnbl]
 
 	For printing an IP address without the need to distinguish whether it's
-	of type AF_INET or AF_INET6, a pointer to a valid 'struct sockaddr',
-	specified through 'IS' or 'iS', can be passed to this format specifier.
+	of type AF_INET or AF_INET6, a pointer to a valid 'union inet_addr',
+	specified through 'IA' or 'iA', can be passed to this format specifier.
 
 	The additional 'p', 'f', and 's' specifiers are used to specify port
 	(IPv4, IPv6), flowinfo (IPv6) and scope (IPv6). Ports have a ':' prefix,
@@ -149,9 +149,9 @@ IPv4/IPv6 addresses (generic, with port, flowinfo, scope):
 
 	Further examples:
 
-	%pISfc		1.2.3.4		or [1:2:3:4:5:6:7:8]/123456789
-	%pISsc		1.2.3.4		or [1:2:3:4:5:6:7:8]%1234567890
-	%pISpfc		1.2.3.4:12345	or [1:2:3:4:5:6:7:8]:12345/123456789
+	%pIAfc		1.2.3.4		or [1:2:3:4:5:6:7:8]/123456789
+	%pIAsc		1.2.3.4		or [1:2:3:4:5:6:7:8]%1234567890
+	%pIApfc		1.2.3.4:12345	or [1:2:3:4:5:6:7:8]:12345/123456789
 
 UUID/GUID addresses:
 
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 4822aaf..28234f8 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -270,18 +270,12 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-	if (nt->np.ipv6)
-		return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
-	else
-		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+	return snprintf(buf, PAGE_SIZE, "%pIA\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-	if (nt->np.ipv6)
-		return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
-	else
-		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+	return snprintf(buf, PAGE_SIZE, "%pIA\n", &nt->np.remote_ip);
 }
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -419,17 +413,19 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
 
 	if (strnchr(buf, count, ':')) {
 		const char *end;
-		if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
+		if (in6_pton(buf, count, nt->np.local_ip.sin6.sin6_addr.s6_addr, -1, &end) > 0) {
 			if (*end && *end != '\n') {
 				printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
 				return -EINVAL;
 			}
+			nt->np.local_ip.sa.sa_family = AF_INET6;
 			nt->np.ipv6 = true;
 		} else
 			return -EINVAL;
 	} else {
 		if (!nt->np.ipv6) {
-			nt->np.local_ip.ip = in_aton(buf);
+			nt->np.local_ip.sin.sin_addr.s_addr = in_aton(buf);
+			nt->np.local_ip.sa.sa_family = AF_INET;
 		} else
 			return -EINVAL;
 	}
@@ -450,17 +446,19 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
 
 	if (strnchr(buf, count, ':')) {
 		const char *end;
-		if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
+		if (in6_pton(buf, count, nt->np.remote_ip.sin6.sin6_addr.s6_addr, -1, &end) > 0) {
 			if (*end && *end != '\n') {
 				printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
 				return -EINVAL;
 			}
+			nt->np.remote_ip.sa.sa_family = AF_INET6;
 			nt->np.ipv6 = true;
 		} else
 			return -EINVAL;
 	} else {
 		if (!nt->np.ipv6) {
-			nt->np.remote_ip.ip = in_aton(buf);
+			nt->np.remote_ip.sin.sin_addr.s_addr = in_aton(buf);
+			nt->np.remote_ip.sa.sa_family = AF_INET;
 		} else
 			return -EINVAL;
 	}
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index f3c7c24..3884834 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -11,14 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/rcupdate.h>
 #include <linux/list.h>
-
-union inet_addr {
-	__u32		all[4];
-	__be32		ip;
-	__be32		ip6[4];
-	struct in_addr	in;
-	struct in6_addr	in6;
-};
+#include <net/inet_addr.h>
 
 struct netpoll {
 	struct net_device *dev;
diff --git a/include/net/inet_addr.h b/include/net/inet_addr.h
new file mode 100644
index 0000000..66a16fe
--- /dev/null
+++ b/include/net/inet_addr.h
@@ -0,0 +1,62 @@
+#ifndef _INET_ADDR_H
+#define _INET_ADDR_H
+
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/socket.h>
+#include <net/addrconf.h>
+
+union inet_addr {
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
+	struct sockaddr sa;
+};
+
+#if IS_ENABLED(CONFIG_IPV6)
+static inline
+bool inet_addr_equal(const union inet_addr *a, const union inet_addr *b)
+{
+	if (a->sa.sa_family != b->sa.sa_family)
+		return false;
+	if (a->sa.sa_family == AF_INET6)
+		return ipv6_addr_equal(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
+	else
+		return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
+}
+
+static inline bool inet_addr_any(const union inet_addr *ipa)
+{
+	if (ipa->sa.sa_family == AF_INET6)
+		return ipv6_addr_any(&ipa->sin6.sin6_addr);
+	else
+		return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
+}
+
+static inline bool inet_addr_multicast(const union inet_addr *ipa)
+{
+	if (ipa->sa.sa_family == AF_INET6)
+		return ipv6_addr_is_multicast(&ipa->sin6.sin6_addr);
+	else
+		return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
+}
+
+#else /* !CONFIG_IPV6 */
+
+static inline
+bool inet_addr_equal(const union inet_addr *a, const union inet_addr *b)
+{
+	return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
+}
+
+static inline bool inet_addr_any(const union inet_addr *ipa)
+{
+	return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
+}
+
+static inline bool inet_addr_multicast(const union inet_addr *ipa)
+{
+	return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
+}
+#endif
+
+#endif
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 739a363..49618d0 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -27,6 +27,7 @@
 #include <linux/uaccess.h>
 #include <linux/ioport.h>
 #include <net/addrconf.h>
+#include <net/inet_addr.h>
 
 #include <asm/page.h>		/* for PAGE_SIZE */
 #include <asm/sections.h>	/* for dereference_function_descriptor() */
@@ -1104,14 +1105,14 @@ int kptr_restrict __read_mostly;
  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
  *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
  *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
- *       [S][pfs]
- *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
+ *       [A][pfs]
+ *       Generic IPv4/IPv6 address (union inet_addr *) that falls back to
  *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
  * - 'i' [46] for 'raw' IPv4/IPv6 addresses
  *       IPv6 omits the colons (01020304...0f)
  *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
- *       [S][pfs]
- *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
+ *       [A][pfs]
+ *       Generic IPv4/IPv6 address (union inet_addr *) that falls back to
  *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
  * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
  * - 'I[6S]c' for IPv6 addresses printed as specified by
@@ -1196,18 +1197,14 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 			return ip6_addr_string(buf, end, ptr, spec, fmt);
 		case '4':
 			return ip4_addr_string(buf, end, ptr, spec, fmt);
-		case 'S': {
-			const union {
-				struct sockaddr		raw;
-				struct sockaddr_in	v4;
-				struct sockaddr_in6	v6;
-			} *sa = ptr;
-
-			switch (sa->raw.sa_family) {
+		case 'A': {
+			const union inet_addr *sa = ptr;
+
+			switch (sa->sa.sa_family) {
 			case AF_INET:
-				return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt);
+				return ip4_addr_string_sa(buf, end, &sa->sin, spec, fmt);
 			case AF_INET6:
-				return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt);
+				return ip6_addr_string_sa(buf, end, &sa->sin6, spec, fmt);
 			default:
 				return string(buf, end, "(invalid address)", spec);
 			}}
@@ -1488,8 +1485,8 @@ qualifier:
  * %pI6 print an IPv6 address with colons
  * %pi6 print an IPv6 address without colons
  * %pI6c print an IPv6 address as specified by RFC 5952
- * %pIS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
- * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
+ * %pIA depending on sa_family of 'union inet_addr *' print IPv4/IPv6 address
+ * %piA depending on sa_family of 'union inet_addr *' print IPv4/IPv6 address
  * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
  *   case.
  * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 2c637e9..e7d4388 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -456,8 +456,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 
 	if (np->ipv6) {
 		udph->check = 0;
-		udph->check = csum_ipv6_magic(&np->local_ip.in6,
-					      &np->remote_ip.in6,
+		udph->check = csum_ipv6_magic(&np->local_ip.sin6.sin6_addr,
+					      &np->remote_ip.sin6.sin6_addr,
 					      udp_len, IPPROTO_UDP,
 					      csum_partial(udph, udp_len, 0));
 		if (udph->check == 0)
@@ -476,16 +476,16 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 		ip6h->payload_len = htons(sizeof(struct udphdr) + len);
 		ip6h->nexthdr = IPPROTO_UDP;
 		ip6h->hop_limit = 32;
-		ip6h->saddr = np->local_ip.in6;
-		ip6h->daddr = np->remote_ip.in6;
+		ip6h->saddr = np->local_ip.sin6.sin6_addr;
+		ip6h->daddr = np->remote_ip.sin6.sin6_addr;
 
 		eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
 		skb_reset_mac_header(skb);
 		skb->protocol = eth->h_proto = htons(ETH_P_IPV6);
 	} else {
 		udph->check = 0;
-		udph->check = csum_tcpudp_magic(np->local_ip.ip,
-						np->remote_ip.ip,
+		udph->check = csum_tcpudp_magic(np->local_ip.sin.sin_addr.s_addr,
+						np->remote_ip.sin.sin_addr.s_addr,
 						udp_len, IPPROTO_UDP,
 						csum_partial(udph, udp_len, 0));
 		if (udph->check == 0)
@@ -504,8 +504,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 		iph->ttl      = 64;
 		iph->protocol = IPPROTO_UDP;
 		iph->check    = 0;
-		put_unaligned(np->local_ip.ip, &(iph->saddr));
-		put_unaligned(np->remote_ip.ip, &(iph->daddr));
+		put_unaligned(np->local_ip.sin.sin_addr.s_addr, &(iph->saddr));
+		put_unaligned(np->remote_ip.sin.sin_addr.s_addr, &(iph->daddr));
 		iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
 
 		eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
@@ -589,7 +589,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
 
 		spin_lock_irqsave(&npinfo->rx_lock, flags);
 		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-			if (tip != np->local_ip.ip)
+			if (tip != np->local_ip.sin.sin_addr.s_addr)
 				continue;
 
 			hlen = LL_RESERVED_SPACE(np->dev);
@@ -677,7 +677,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
 
 		spin_lock_irqsave(&npinfo->rx_lock, flags);
 		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-			if (!ipv6_addr_equal(daddr, &np->local_ip.in6))
+			if (!ipv6_addr_equal(daddr, &np->local_ip.sin6.sin6_addr))
 				continue;
 
 			hlen = LL_RESERVED_SPACE(np->dev);
@@ -827,9 +827,11 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 		if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
 			goto out;
 		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-			if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
+			__be32 daddr = np->local_ip.sin.sin_addr.s_addr;
+			__be32 saddr = np->remote_ip.sin.sin_addr.s_addr;
+			if (daddr && daddr != iph->daddr)
 				continue;
-			if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
+			if (saddr && saddr != iph->saddr)
 				continue;
 			if (np->local_port && np->local_port != ntohs(uh->dest))
 				continue;
@@ -865,9 +867,9 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 		if (udp6_csum_init(skb, uh, IPPROTO_UDP))
 			goto out;
 		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-			if (!ipv6_addr_equal(&np->local_ip.in6, &ip6h->daddr))
+			if (!ipv6_addr_equal(&np->local_ip.sin6.sin6_addr, &ip6h->daddr))
 				continue;
-			if (!ipv6_addr_equal(&np->remote_ip.in6, &ip6h->saddr))
+			if (!ipv6_addr_equal(&np->remote_ip.sin6.sin6_addr, &ip6h->saddr))
 				continue;
 			if (np->local_port && np->local_port != ntohs(uh->dest))
 				continue;
@@ -898,16 +900,10 @@ out:
 void netpoll_print_options(struct netpoll *np)
 {
 	np_info(np, "local port %d\n", np->local_port);
-	if (np->ipv6)
-		np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
-	else
-		np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
+	np_info(np, "local IPv6 address %pIA\n", &np->local_ip);
 	np_info(np, "interface '%s'\n", np->dev_name);
 	np_info(np, "remote port %d\n", np->remote_port);
-	if (np->ipv6)
-		np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
-	else
-		np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
+	np_info(np, "remote IPv6 address %pIA\n", &np->remote_ip);
 	np_info(np, "remote ethernet address %pM\n", np->remote_mac);
 }
 EXPORT_SYMBOL(netpoll_print_options);
@@ -921,7 +917,7 @@ static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
 		if (!*end)
 			return 0;
 	}
-	if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) {
+	if (in6_pton(str, -1, addr->sin6.sin6_addr.s6_addr, -1, &end) > 0) {
 #if IS_ENABLED(CONFIG_IPV6)
 		if (!*end)
 			return 1;
@@ -1140,7 +1136,7 @@ int netpoll_setup(struct netpoll *np)
 		rtnl_lock();
 	}
 
-	if (!np->local_ip.ip) {
+	if (!np->local_ip.sin.sin_addr.s_addr) {
 		if (!np->ipv6) {
 			in_dev = __in_dev_get_rtnl(ndev);
 
@@ -1151,8 +1147,8 @@ int netpoll_setup(struct netpoll *np)
 				goto put;
 			}
 
-			np->local_ip.ip = in_dev->ifa_list->ifa_local;
-			np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+			np->local_ip.sin.sin_addr.s_addr = in_dev->ifa_list->ifa_local;
+			np_info(np, "local IP %pI4\n", &np->local_ip.sin.sin_addr.s_addr);
 		} else {
 #if IS_ENABLED(CONFIG_IPV6)
 			struct inet6_dev *idev;
@@ -1166,7 +1162,7 @@ int netpoll_setup(struct netpoll *np)
 				list_for_each_entry(ifp, &idev->addr_list, if_list) {
 					if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
 						continue;
-					np->local_ip.in6 = ifp->addr;
+					np->local_ip.sin6.sin6_addr = ifp->addr;
 					err = 0;
 					break;
 				}
@@ -1177,7 +1173,7 @@ int netpoll_setup(struct netpoll *np)
 				       np->dev_name);
 				goto put;
 			} else
-				np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
+				np_info(np, "local IPv6 %pI6c\n", &np->local_ip.sin6.sin6_addr);
 #else
 			np_err(np, "IPv6 is not supported %s, aborting\n",
 			       np->dev_name);
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index e425ba0..07aff2b 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -540,7 +540,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
 	struct list_head	*pos;
 	struct sctp_transport	*transport;
 
-	pr_debug("%s: association:%p addr:%pISpc\n",
+	pr_debug("%s: association:%p addr:%pIApc\n",
 		 __func__, asoc, &peer->ipaddr.sa);
 
 	/* If we are to remove the current retran_path, update it
@@ -637,7 +637,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
 	/* AF_INET and AF_INET6 share common port field. */
 	port = ntohs(addr->v4.sin_port);
 
-	pr_debug("%s: association:%p addr:%pISpc state:%d\n", __func__,
+	pr_debug("%s: association:%p addr:%pIApc state:%d\n", __func__,
 		 asoc, &addr->sa, peer_state);
 
 	/* Set the port if it has not been set yet.  */
@@ -1347,7 +1347,7 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
 	else
 		t = asoc->peer.retran_path;
 
-	pr_debug("%s: association:%p addr:%pISpc\n", __func__, asoc,
+	pr_debug("%s: association:%p addr:%pIApc\n", __func__, asoc,
 		 &t->ipaddr.sa);
 }
 
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index b52ec25..1928862 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -604,7 +604,7 @@ static void sctp_addr_wq_timeout_handler(unsigned long arg)
 	spin_lock_bh(&net->sctp.addr_wq_lock);
 
 	list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
-		pr_debug("%s: the first ent in wq:%p is addr:%pISc for cmd:%d at "
+		pr_debug("%s: the first ent in wq:%p is addr:%pIAc for cmd:%d at "
 			 "entry:%p\n", __func__, &net->sctp.addr_waitq, &addrw->a.sa,
 			 addrw->state, addrw);
 
@@ -709,7 +709,7 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
 	addrw = sctp_addr_wq_lookup(net, addr);
 	if (addrw) {
 		if (addrw->state != cmd) {
-			pr_debug("%s: offsets existing entry for %d, addr:%pISc "
+			pr_debug("%s: offsets existing entry for %d, addr:%pIAc "
 				 "in wq:%p\n", __func__, addrw->state, &addrw->a.sa,
 				 &net->sctp.addr_waitq);
 
@@ -729,7 +729,7 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
 	addrw->state = cmd;
 	list_add_tail(&addrw->list, &net->sctp.addr_waitq);
 
-	pr_debug("%s: add new entry for cmd:%d, addr:%pISc in wq:%p\n",
+	pr_debug("%s: add new entry for cmd:%d, addr:%pIAc in wq:%p\n",
 		 __func__, addrw->state, &addrw->a.sa, &net->sctp.addr_waitq);
 
 	if (!timer_pending(&net->sctp.addr_wq_timer)) {
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index f1f3aac..fae93e7 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -520,7 +520,7 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
 
 	if (transport->state != SCTP_INACTIVE &&
 	    (transport->error_count > transport->pathmaxrxt)) {
-		pr_debug("%s: association:%p transport addr:%pISpc failed\n",
+		pr_debug("%s: association:%p transport addr:%pIApc failed\n",
 			 __func__, asoc, &transport->ipaddr.sa);
 
 		sctp_assoc_control_transport(asoc, transport,
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 0245712..851093f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -349,7 +349,7 @@ static int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 
 	snum = ntohs(addr->v4.sin_port);
 
-	pr_debug("%s: sk:%p, new addr:%pISc, port:%d, new port:%d, len:%d\n",
+	pr_debug("%s: sk:%p, new addr:%pIAc, port:%d, new port:%d, len:%d\n",
 		 __func__, sk, &addr->sa, bp->port, snum, len);
 
 	/* PF specific bind() address verification. */
@@ -803,7 +803,7 @@ static int sctp_send_asconf_del_ip(struct sock		*sk,
 				asoc->asconf_addr_del_pending->v6.sin6_addr = sin6->sin6_addr;
 			}
 
-			pr_debug("%s: keep the last address asoc:%p %pISc at %p\n",
+			pr_debug("%s: keep the last address asoc:%p %pIAc at %p\n",
 				 __func__, asoc, &asoc->asconf_addr_del_pending->sa,
 				 asoc->asconf_addr_del_pending);
 
-- 
1.7.7.6

^ permalink raw reply related

* Re: [PATCH net-next v3 0/5] qlcnic: Mailbox refactoring
From: David Miller @ 2013-08-02  6:04 UTC (permalink / raw)
  To: himanshu.madhani; +Cc: netdev, Dept_NX_Linux_NIC_Driver
In-Reply-To: <cover.1375438720.git.himanshu.madhani@qlogic.com>

From: Himanshu Madhani <himanshu.madhani@qlogic.com>
Date: Fri, 2 Aug 2013 00:57:38 -0400

> From: Himanshu Madhani <himanshu.madhani@qlogic.com>
> 
> This series contains following patches 
> 
> o in v2 series, we received feedback on return codes to use standard error
>   codes instead of mixing custom error codes. We have modified patch for 
>   loopback diagnostic test to return standard error codes.
> 
> o rest of the 3 patches in the series are for mailbox refactoring
> 
>   Current driver-firmware mailbox interface was operating in polling mode
>   because of some limitations with the earlier versions of 83xx adapter
>   firmware. These issues are resolved now and we are implementing the
>   mailbox interface in interrupt mode.
> 
>   There are three patches which refactors mailbox handling:
>   * Interrupt mode mailbox implantation.
>   * Replace poll mode mailbox interfaces with interrupt mode interfaces.
>   * Operate mailbox in poll mode when interrupts are not available.
> 
> changes from v2 -> v3
>  * Addressed review feedback to use standard return codes for loopback
>    diagnostic test.
> 
> Please consider applying these patches to net-next.

Series applied, thanks.

^ permalink raw reply

* Re: [Patch net-next 1/2] net: fix a compile error when CONFIG_NET_LL_RX_POLL is not set
From: David Miller @ 2013-08-02  5:51 UTC (permalink / raw)
  To: eliezer.tamir; +Cc: amwang, netdev
In-Reply-To: <51FB21AB.6090003@linux.intel.com>

From: Eliezer Tamir <eliezer.tamir@linux.intel.com>
Date: Fri, 02 Aug 2013 06:04:11 +0300

> On 01/08/2013 23:03, David Miller wrote:
>> From: Cong Wang <amwang@redhat.com>
>> Date: Thu, 01 Aug 2013 16:08:07 +0800
>> 
>>> Thinking about it again, what is the point of your commit commit
>>> 89bf1b5a683df497c572c4d3bd3f9c9aa919d773 (net: remove NET_LL_RX_POLL
>>> config menue)? After that commit, CONFIG_NET_LL_RX_POLL is not visible
>>> by user and no other configs select it, also since it defaults to y, it
>>> will be _always_ enabled. If this is really what you want, we can simply
>>> remove all !CONFIG_NET_LL_RX_POLL code.
>> 
>> Yes we could do that, it has no dependencies which is the usual reason
>> to have a hidden Kconfig var like this.
> 
> I think we still need a config option that depends on net and the
> placeholder code.
> What happens then if someone does not configure networking?
> Won't this break select and poll?

Good point.

^ permalink raw reply

* Re: [Bug 60669] Kernel panic when using negative priority for HTB class
From: Stephen Hemminger @ 2013-08-02  5:31 UTC (permalink / raw)
  To: Cong Wang; +Cc: netdev
In-Reply-To: <ktfdq8$882$1@ger.gmane.org>

On Fri, 2 Aug 2013 04:50:16 +0000 (UTC)
Cong Wang <xiyou.wangcong@gmail.com> wrote:

> On Fri, 02 Aug 2013 at 04:12 GMT, Stephen Hemminger <stephen@networkplumber.org> wrote:
> >
> > --- Comment #2 from _Vi <vi0oss@gmail.com> ---
> > Reproducible on 3.11.0-rc3
> >
> > Looks like negative priority value is essential for the kernel panic.
> >
> 
> There is a check for prio:
> 
>                 if ((cl->prio = hopt->prio) >= TC_HTB_NUMPRIO)
> 		                        cl->prio = TC_HTB_NUMPRIO - 1;
> 					

This maybe related to or old bugs, 64 bit with current
iproute2 the error is caught at the command level.

The issue is that hopt->prio is u32 but cl->prio is int.

Example:
int main()
{
	int x = -1;
	uint32_t prio = x;
	int cl;

	if ((cl = prio) >= TC_HTB_NUMPRIO)
		cl = TC_HTB_NUMPRIO - 1;

	printf("%d %u %d\n", x, prio, cl);
	return 0;
}
-1 4294967295 -1

Signed/unsigned conversions can bite.

^ permalink raw reply

* [PATCH net-next] htb: fix sign extension bug
From: Stephen Hemminger @ 2013-08-02  5:32 UTC (permalink / raw)
  To: David Miller; +Cc: Cong Wang, netdev
In-Reply-To: <20130801221936.24d4b31e@nehalam.linuxnetplumber.net>

When userspace passes a large priority value 
the assignment of the unsigned value hopt->prio
to  signed int cl->prio causes cl->prio to become negative and the
comparison is with TC_HTB_NUMPRIO is always false.

The result is that HTB crashes by referencing outside
the array when processing packets. With this patch the large value
wraps around like other values outside the normal range.

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

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

--- a/net/sched/sch_htb.c	2013-06-20 09:22:46.489542435 -0700
+++ b/net/sched/sch_htb.c	2013-08-01 22:12:43.736307055 -0700
@@ -100,7 +100,7 @@ struct htb_class {
 	struct psched_ratecfg	ceil;
 	s64			buffer, cbuffer;/* token bucket depth/rate */
 	s64			mbuffer;	/* max wait time */
-	int			prio;		/* these two are used only by leaves... */
+	u32			prio;		/* these two are used only by leaves... */
 	int			quantum;	/* but stored for parent-to-leaf return */
 
 	struct tcf_proto	*filter_list;	/* class attached filters */

^ permalink raw reply

* [PATCH net-next v3 3/5] qlcnic: Replace poll mode mailbox interface with interrupt based mailbox interface
From: Himanshu Madhani @ 2013-08-02  4:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Manish Chopra, himanshu.madhani
In-Reply-To: <cover.1375438720.git.himanshu.madhani@qlogic.com>

From: Manish Chopra <manish.chopra@qlogic.com>

Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |   1 -
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    | 260 ++++++++++-----------
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |   2 -
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c  |  81 +++++--
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |  18 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   | 134 ++++-------
 6 files changed, 232 insertions(+), 264 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 5a49b64..cd95442 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -466,7 +466,6 @@ struct qlcnic_hardware_context {
 	u32 *ext_reg_tbl;
 	u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
 	u32 mbox_reg[4];
-	spinlock_t mbx_lock;
 	struct qlcnic_mailbox *mailbox;
 };
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 74c8d84..1eeeed8 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -362,6 +362,10 @@ static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
 				     struct qlcnic_cmd_args *cmd)
 {
 	int i;
+
+	if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP)
+		return;
+
 	for (i = 0; i < cmd->rsp.num; i++)
 		cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));
 }
@@ -406,22 +410,25 @@ static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
 
 static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
 {
-	u32 resp, event;
+	u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 	unsigned long flags;
 
-	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
-
+	spin_lock_irqsave(&mbx->aen_lock, flags);
 	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
 	if (!(resp & QLCNIC_SET_OWNER))
 		goto out;
 
 	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-	if (event &  QLCNIC_MBX_ASYNC_EVENT)
+	if (event &  QLCNIC_MBX_ASYNC_EVENT) {
 		__qlcnic_83xx_process_aen(adapter);
-
+	} else {
+		if (atomic_read(&mbx->rsp_status) != rsp_status)
+			qlcnic_83xx_notify_mbx_response(mbx);
+	}
 out:
 	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
-	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+	spin_unlock_irqrestore(&mbx->aen_lock, flags);
 }
 
 irqreturn_t qlcnic_83xx_intr(int irq, void *data)
@@ -694,6 +701,9 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
 {
 	int i;
 
+	if (cmd->op_type == QLC_83XX_MBX_POST_BC_OP)
+		return;
+
 	dev_info(&adapter->pdev->dev,
 		 "Host MBX regs(%d)\n", cmd->req.num);
 	for (i = 0; i < cmd->req.num; i++) {
@@ -712,120 +722,74 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
 	pr_info("\n");
 }
 
-/* Mailbox response for mac rcode */
-u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
+static inline void
+qlcnic_83xx_poll_for_mbx_completion(struct qlcnic_adapter *adapter,
+				    struct qlcnic_cmd_args *cmd)
 {
-	u32 fw_data;
-	u8 mac_cmd_rcode;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int opcode = LSW(cmd->req.arg[0]);
+	unsigned long max_loops;
 
-	fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
-	mac_cmd_rcode = (u8)fw_data;
-	if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
-	    mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
-	    mac_cmd_rcode == QLC_83XX_MAC_ABSENT)
-		return QLCNIC_RCODE_SUCCESS;
-	return 1;
-}
+	max_loops = cmd->total_cmds * QLC_83XX_MBX_CMD_LOOP;
 
-u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter, u32 *wait_time)
-{
-	u32 data;
-	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	/* wait for mailbox completion */
-	do {
-		data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
-		if (++(*wait_time) > QLCNIC_MBX_TIMEOUT) {
-			data = QLCNIC_RCODE_TIMEOUT;
-			break;
-		}
-		mdelay(1);
-	} while (!data);
-	return data;
+	for (; max_loops; max_loops--) {
+		if (atomic_read(&cmd->rsp_status) ==
+		    QLC_83XX_MBX_RESPONSE_ARRIVED)
+			return;
+
+		udelay(1);
+	}
+
+	dev_err(&adapter->pdev->dev,
+		"%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+		__func__, opcode, cmd->type, ahw->pci_func, ahw->op_mode);
+	flush_workqueue(ahw->mailbox->work_q);
+	return;
 }
 
 int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,
 			  struct qlcnic_cmd_args *cmd)
 {
-	int i;
-	u16 opcode;
-	u8 mbx_err_code;
-	unsigned long flags;
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, wait_time = 0;
+	int cmd_type, err, opcode;
+	unsigned long timeout;
 
 	opcode = LSW(cmd->req.arg[0]);
-	if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
-		dev_info(&adapter->pdev->dev,
-			 "Mailbox cmd attempted, 0x%x\n", opcode);
-		dev_info(&adapter->pdev->dev, "Mailbox detached\n");
-		return 0;
+	cmd_type = cmd->type;
+	err = mbx->ops->enqueue_cmd(adapter, cmd, &timeout);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Mailbox not available, cmd_op=0x%x, cmd_context=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+			__func__, opcode, cmd->type, ahw->pci_func,
+			ahw->op_mode);
+		return err;
 	}
 
-	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
-	mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
-
-	if (mbx_val) {
-		QLCDB(adapter, DRV,
-		      "Mailbox cmd attempted, 0x%x\n", opcode);
-		QLCDB(adapter, DRV,
-		      "Mailbox not available, 0x%x, collect FW dump\n",
-		      mbx_val);
-		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
-		spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-		return cmd->rsp.arg[0];
-	}
-
-	/* Fill in mailbox registers */
-	mbx_cmd = cmd->req.arg[0];
-	writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
-	for (i = 1; i < cmd->req.num; i++)
-		writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
-
-	/* Signal FW about the impending command */
-	QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
-poll:
-	rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time);
-	if (rsp != QLCNIC_RCODE_TIMEOUT) {
-		/* Get the FW response data */
-		fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
-		if (fw_data &  QLCNIC_MBX_ASYNC_EVENT) {
-			__qlcnic_83xx_process_aen(adapter);
-			goto poll;
-		}
-		mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
-		rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
-		opcode = QLCNIC_MBX_RSP(fw_data);
-		qlcnic_83xx_get_mbx_data(adapter, cmd);
-
-		switch (mbx_err_code) {
-		case QLCNIC_MBX_RSP_OK:
-		case QLCNIC_MBX_PORT_RSP_OK:
-			rsp = QLCNIC_RCODE_SUCCESS;
-			break;
-		default:
-			if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
-				rsp = qlcnic_83xx_mac_rcode(adapter);
-				if (!rsp)
-					goto out;
-			}
+	switch (cmd_type) {
+	case QLC_83XX_MBX_CMD_WAIT:
+		if (!wait_for_completion_timeout(&cmd->completion, timeout)) {
 			dev_err(&adapter->pdev->dev,
-				"MBX command 0x%x failed with err:0x%x\n",
-				opcode, mbx_err_code);
-			rsp = mbx_err_code;
-			qlcnic_dump_mbx(adapter, cmd);
-			break;
+				"%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+				__func__, opcode, cmd_type, ahw->pci_func,
+				ahw->op_mode);
+			flush_workqueue(mbx->work_q);
 		}
-		goto out;
+		break;
+	case QLC_83XX_MBX_CMD_NO_WAIT:
+		return 0;
+	case QLC_83XX_MBX_CMD_BUSY_WAIT:
+		qlcnic_83xx_poll_for_mbx_completion(adapter, cmd);
+		break;
+	default:
+		dev_err(&adapter->pdev->dev,
+			"%s: Invalid mailbox command, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+			__func__, opcode, cmd_type, ahw->pci_func,
+			ahw->op_mode);
+		qlcnic_83xx_detach_mailbox_work(adapter);
 	}
 
-	dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
-		QLCNIC_MBX_RSP(mbx_cmd));
-	rsp = QLCNIC_RCODE_TIMEOUT;
-out:
-	/* clear fw mbx control register */
-	QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
-	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-	return rsp;
+	return cmd->rsp_opcode;
 }
 
 int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
@@ -858,6 +822,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
 			memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
 			temp = adapter->ahw->fw_hal_version << 29;
 			mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
+			mbx->cmd_op = type;
 			return 0;
 		}
 	}
@@ -941,20 +906,23 @@ void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
 
 static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
 {
+	u32 resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	u32 resp, event;
+	struct qlcnic_mailbox *mbx = ahw->mailbox;
 	unsigned long flags;
 
-	spin_lock_irqsave(&ahw->mbx_lock, flags);
-
+	spin_lock_irqsave(&mbx->aen_lock, flags);
 	resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
 	if (resp & QLCNIC_SET_OWNER) {
 		event = readl(QLCNIC_MBX_FW(ahw, 0));
-		if (event &  QLCNIC_MBX_ASYNC_EVENT)
+		if (event &  QLCNIC_MBX_ASYNC_EVENT) {
 			__qlcnic_83xx_process_aen(adapter);
+		} else {
+			if (atomic_read(&mbx->rsp_status) != rsp_status)
+				qlcnic_83xx_notify_mbx_response(mbx);
+		}
 	}
-
-	spin_unlock_irqrestore(&ahw->mbx_lock, flags);
+	spin_unlock_irqrestore(&mbx->aen_lock, flags);
 }
 
 static void qlcnic_83xx_mbx_poll_work(struct work_struct *work)
@@ -1627,26 +1595,33 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,
 
 int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
 {
-	int err;
+	struct qlcnic_cmd_args *cmd = NULL;
 	u32 temp = 0;
-	struct qlcnic_cmd_args cmd;
+	int err;
 
 	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
 		return -EIO;
 
-	err = qlcnic_alloc_mbx_args(&cmd, adapter,
+	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	err = qlcnic_alloc_mbx_args(cmd, adapter,
 				    QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
 	if (err)
-		return err;
+		goto out;
 
+	cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
 	qlcnic_83xx_set_interface_id_promisc(adapter, &temp);
-	cmd.req.arg[1] = (mode ? 1 : 0) | temp;
-	err = qlcnic_issue_cmd(adapter, &cmd);
-	if (err)
-		dev_info(&adapter->pdev->dev,
-			 "Promiscous mode config failed\n");
+	cmd->req.arg[1] = (mode ? 1 : 0) | temp;
+	err = qlcnic_issue_cmd(adapter, cmd);
+	if (!err)
+		return err;
 
-	qlcnic_free_mbx_args(&cmd);
+	qlcnic_free_mbx_args(cmd);
+
+out:
+	kfree(cmd);
 	return err;
 }
 
@@ -1967,25 +1942,31 @@ static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter,
 int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
 				   u16 vlan_id, u8 op)
 {
-	int err;
-	u32 *buf, temp = 0;
-	struct qlcnic_cmd_args cmd;
+	struct qlcnic_cmd_args *cmd = NULL;
 	struct qlcnic_macvlan_mbx mv;
+	u32 *buf, temp = 0;
+	int err;
 
 	if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
 		return -EIO;
 
-	err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
+	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	err = qlcnic_alloc_mbx_args(cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
 	if (err)
-		return err;
+		goto out;
+
+	cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
 
 	if (vlan_id)
 		op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?
 		     QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL;
 
-	cmd.req.arg[1] = op | (1 << 8);
+	cmd->req.arg[1] = op | (1 << 8);
 	qlcnic_83xx_set_interface_id_macaddr(adapter, &temp);
-	cmd.req.arg[1] |= temp;
+	cmd->req.arg[1] |= temp;
 	mv.vlan = vlan_id;
 	mv.mac_addr0 = addr[0];
 	mv.mac_addr1 = addr[1];
@@ -1993,14 +1974,15 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
 	mv.mac_addr3 = addr[3];
 	mv.mac_addr4 = addr[4];
 	mv.mac_addr5 = addr[5];
-	buf = &cmd.req.arg[2];
+	buf = &cmd->req.arg[2];
 	memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
-	err = qlcnic_issue_cmd(adapter, &cmd);
-	if (err)
-		dev_err(&adapter->pdev->dev,
-			"MAC-VLAN %s to CAM failed, err=%d.\n",
-			((op == 1) ? "add " : "delete "), err);
-	qlcnic_free_mbx_args(&cmd);
+	err = qlcnic_issue_cmd(adapter, cmd);
+	if (!err)
+		return err;
+
+	qlcnic_free_mbx_args(cmd);
+out:
+	kfree(cmd);
 	return err;
 }
 
@@ -2109,10 +2091,12 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
 irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 {
 	struct qlcnic_adapter *adapter = data;
-	unsigned long flags;
+	struct qlcnic_mailbox *mbx;
 	u32 mask, resp, event;
+	unsigned long flags;
 
-	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+	mbx = adapter->ahw->mailbox;
+	spin_lock_irqsave(&mbx->aen_lock, flags);
 	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
 	if (!(resp & QLCNIC_SET_OWNER))
 		goto out;
@@ -2120,11 +2104,13 @@ irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
 	if (event &  QLCNIC_MBX_ASYNC_EVENT)
 		__qlcnic_83xx_process_aen(adapter);
+	else
+		qlcnic_83xx_notify_mbx_response(mbx);
+
 out:
 	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
 	writel(0, adapter->ahw->pci_base0 + mask);
-	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-
+	spin_unlock_irqrestore(&mbx->aen_lock, flags);
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 542b58d..9993705 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -644,8 +644,6 @@ int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state);
 int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
 int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);
 int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);
-u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
-u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *, u32 *);
 void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *);
 void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *);
 void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index 0c5110c..bb7c649 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -399,6 +399,7 @@ static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
 	struct net_device *netdev = adapter->netdev;
 
 	netif_device_detach(netdev);
+	qlcnic_83xx_detach_mailbox_work(adapter);
 
 	/* Disable mailbox interrupt */
 	qlcnic_83xx_disable_mbx_intr(adapter);
@@ -610,6 +611,9 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
 {
 	int err;
 
+	qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox);
+	qlcnic_83xx_enable_mbx_interrupt(adapter);
+
 	/* register for NIC IDC AEN Events */
 	qlcnic_83xx_register_nic_idc_func(adapter, 1);
 
@@ -640,7 +644,6 @@ static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
 
 	qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
-	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
 	qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
 	set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
 
@@ -810,9 +813,10 @@ static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter)
  **/
 static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
 {
-	u32 val;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_mailbox *mbx = ahw->mailbox;
 	int ret = 0;
+	u32 val;
 
 	/* Perform NIC configuration based ready state entry actions */
 	if (ahw->idc.state_entry(adapter))
@@ -824,7 +828,7 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
 			dev_err(&adapter->pdev->dev,
 				"Error: device temperature %d above limits\n",
 				adapter->ahw->temp);
-			clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+			clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 			set_bit(__QLCNIC_RESETTING, &adapter->state);
 			qlcnic_83xx_idc_detach_driver(adapter);
 			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
@@ -837,7 +841,7 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
 	if (ret) {
 		adapter->flags |= QLCNIC_FW_HANG;
 		if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
-			clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+			clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 			set_bit(__QLCNIC_RESETTING, &adapter->state);
 			qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
 		}
@@ -845,6 +849,8 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
 	}
 
 	if ((val & QLC_83XX_IDC_GRACEFULL_RESET) || ahw->idc.collect_dump) {
+		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
+
 		/* Move to need reset state and prepare for reset */
 		qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
 		return ret;
@@ -882,12 +888,13 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
  **/
 static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
 {
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 	int ret = 0;
 
 	if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
 		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
 		set_bit(__QLCNIC_RESETTING, &adapter->state);
-		clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 		if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
 			qlcnic_83xx_disable_vnic_mode(adapter, 1);
 
@@ -1079,7 +1086,6 @@ static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter)
 	adapter->ahw->idc.name = (char **)qlc_83xx_idc_states;
 
 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
-	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
 	set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
 
 	/* Check if reset recovery is disabled */
@@ -1190,6 +1196,9 @@ void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)
 {
 	u32 val;
 
+	if (qlcnic_sriov_vf_check(adapter))
+		return;
+
 	if (qlcnic_83xx_lock_driver(adapter)) {
 		dev_err(&adapter->pdev->dev,
 			"%s:failed, please retry\n", __func__);
@@ -2110,17 +2119,35 @@ static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
 int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
 {
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int err = 0;
 
-	if (qlcnic_sriov_vf_check(adapter))
-		return qlcnic_sriov_vf_init(adapter, pci_using_dac);
+	ahw->msix_supported = !!qlcnic_use_msi_x;
+	err = qlcnic_83xx_init_mailbox_work(adapter);
+	if (err)
+		goto exit;
 
-	if (qlcnic_83xx_check_hw_status(adapter))
-		return -EIO;
+	if (qlcnic_sriov_vf_check(adapter)) {
+		err = qlcnic_sriov_vf_init(adapter, pci_using_dac);
+		if (err)
+			goto detach_mbx;
+		else
+			return err;
+	}
 
-	/* Initilaize 83xx mailbox spinlock */
-	spin_lock_init(&ahw->mbx_lock);
+	err = qlcnic_83xx_check_hw_status(adapter);
+	if (err)
+		goto detach_mbx;
+
+	err = qlcnic_setup_intr(adapter, 0);
+	if (err) {
+		dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
+		goto disable_intr;
+	}
+
+	err = qlcnic_83xx_setup_mbx_intr(adapter);
+	if (err)
+		goto disable_mbx_intr;
 
-	set_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
 	qlcnic_83xx_clear_function_resources(adapter);
 
 	/* register for NIC IDC AEN Events */
@@ -2129,21 +2156,35 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
 	if (!qlcnic_83xx_read_flash_descriptor_table(adapter))
 		qlcnic_83xx_read_flash_mfg_id(adapter);
 
-	if (qlcnic_83xx_idc_init(adapter))
-		return -EIO;
+	err = qlcnic_83xx_idc_init(adapter);
+	if (err)
+		goto disable_mbx_intr;
 
 	/* Configure default, SR-IOV or Virtual NIC mode of operation */
-	if (qlcnic_83xx_configure_opmode(adapter))
-		return -EIO;
+	err = qlcnic_83xx_configure_opmode(adapter);
+	if (err)
+		goto disable_mbx_intr;
 
 	/* Perform operating mode specific initialization */
-	if (adapter->nic_ops->init_driver(adapter))
-		return -EIO;
+	err = adapter->nic_ops->init_driver(adapter);
+	if (err)
+		goto disable_mbx_intr;
 
 	INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
 
 	/* Periodically monitor device status */
 	qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
+	return 0;
 
-	return adapter->ahw->idc.err_code;
+disable_mbx_intr:
+	qlcnic_83xx_free_mbx_intr(adapter);
+
+disable_intr:
+	qlcnic_teardown_intr(adapter);
+
+detach_mbx:
+	qlcnic_83xx_detach_mailbox_work(adapter);
+	qlcnic_83xx_free_mailbox(ahw->mailbox);
+exit:
+	return err;
 }
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 4528f8e..cdc24e4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2141,16 +2141,12 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		dev_warn(&pdev->dev,
 			 "83xx adapter do not support MSI interrupts\n");
 
-	err = qlcnic_setup_intr(adapter, 0);
-	if (err) {
-		dev_err(&pdev->dev, "Failed to setup interrupt\n");
-		goto err_out_disable_msi;
-	}
-
-	if (qlcnic_83xx_check(adapter)) {
-		err = qlcnic_83xx_setup_mbx_intr(adapter);
-		if (err)
+	if (qlcnic_82xx_check(adapter)) {
+		err = qlcnic_setup_intr(adapter, 0);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to setup interrupt\n");
 			goto err_out_disable_msi;
+		}
 	}
 
 	err = qlcnic_get_act_pci_func(adapter);
@@ -2237,9 +2233,11 @@ static void qlcnic_remove(struct pci_dev *pdev)
 	qlcnic_sriov_cleanup(adapter);
 
 	if (qlcnic_83xx_check(adapter)) {
-		qlcnic_83xx_free_mbx_intr(adapter);
 		qlcnic_83xx_register_nic_idc_func(adapter, 0);
 		cancel_delayed_work_sync(&adapter->idc_aen_work);
+		qlcnic_83xx_free_mbx_intr(adapter);
+		qlcnic_83xx_detach_mailbox_work(adapter);
+		qlcnic_83xx_free_mailbox(ahw->mailbox);
 	}
 
 	qlcnic_detach(adapter);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index d9c6ae5..e58c1d4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -286,96 +286,38 @@ void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
 static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
 				    u32 *pay, u8 pci_func, u8 size)
 {
-	u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val, wait_time = 0;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	unsigned long flags;
-	u16 opcode;
-	u8 mbx_err_code;
-	int i, j;
-
-	opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
-
-	if (!test_bit(QLC_83XX_MBX_READY, &ahw->idc.status)) {
-		dev_info(&adapter->pdev->dev,
-			 "Mailbox cmd attempted, 0x%x\n", opcode);
-		dev_info(&adapter->pdev->dev, "Mailbox detached\n");
-		return 0;
-	}
-
-	spin_lock_irqsave(&ahw->mbx_lock, flags);
-
-	mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
-	if (mbx_val) {
-		QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode);
-		spin_unlock_irqrestore(&ahw->mbx_lock, flags);
-		return QLCNIC_RCODE_TIMEOUT;
-	}
-	/* Fill in mailbox registers */
-	val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
-	mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29);
-
-	writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
-	mbx_cmd = 0x1 | (1 << 4);
-
-	if (qlcnic_sriov_pf_check(adapter))
-		mbx_cmd |= (pci_func << 5);
+	struct qlcnic_mailbox *mbx = ahw->mailbox;
+	struct qlcnic_cmd_args cmd;
+	unsigned long timeout;
+	int err;
 
-	writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));
-	for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
-			i++, j++) {
-		writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i));
+	memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
+	cmd.hdr = hdr;
+	cmd.pay = pay;
+	cmd.pay_size = size;
+	cmd.func_num = pci_func;
+	cmd.op_type = QLC_83XX_MBX_POST_BC_OP;
+	cmd.cmd_op = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
+
+	err = mbx->ops->enqueue_cmd(adapter, &cmd, &timeout);
+	if (err) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Mailbox not available, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+			__func__, cmd.cmd_op, cmd.type, ahw->pci_func,
+			ahw->op_mode);
+		return err;
 	}
-	for (j = 0; j < size; j++, i++)
-		writel(*(pay++), QLCNIC_MBX_HOST(ahw, i));
 
-	/* Signal FW about the impending command */
-	QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
-
-	/* Waiting for the mailbox cmd to complete and while waiting here
-	 * some AEN might arrive. If more than 5 seconds expire we can
-	 * assume something is wrong.
-	 */
-poll:
-	rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time);
-	if (rsp != QLCNIC_RCODE_TIMEOUT) {
-		/* Get the FW response data */
-		fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
-		if (fw_data &  QLCNIC_MBX_ASYNC_EVENT) {
-			__qlcnic_83xx_process_aen(adapter);
-			goto poll;
-		}
-		mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
-		rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
-		opcode = QLCNIC_MBX_RSP(fw_data);
-
-		switch (mbx_err_code) {
-		case QLCNIC_MBX_RSP_OK:
-		case QLCNIC_MBX_PORT_RSP_OK:
-			rsp = QLCNIC_RCODE_SUCCESS;
-			break;
-		default:
-			if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
-				rsp = qlcnic_83xx_mac_rcode(adapter);
-				if (!rsp)
-					goto out;
-			}
-			dev_err(&adapter->pdev->dev,
-				"MBX command 0x%x failed with err:0x%x\n",
-				opcode, mbx_err_code);
-			rsp = mbx_err_code;
-			break;
-		}
-		goto out;
+	if (!wait_for_completion_timeout(&cmd.completion, timeout)) {
+		dev_err(&adapter->pdev->dev,
+			"%s: Mailbox command timed out, cmd_op=0x%x, cmd_type=0x%x, pci_func=0x%x, op_mode=0x%x\n",
+			__func__, cmd.cmd_op, cmd.type, ahw->pci_func,
+			ahw->op_mode);
+		flush_workqueue(mbx->work_q);
 	}
 
-	dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
-		QLCNIC_MBX_RSP(mbx_cmd));
-	rsp = QLCNIC_RCODE_TIMEOUT;
-out:
-	/* clear fw mbx control register */
-	QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
-	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-	return rsp;
+	return cmd.rsp_opcode;
 }
 
 static void qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter *adapter)
@@ -522,8 +464,8 @@ static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter)
 
 static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
 {
-	struct qlcnic_info nic_info;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_info nic_info;
 	int err;
 
 	err = qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, 0);
@@ -637,8 +579,6 @@ int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac)
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	int err;
 
-	spin_lock_init(&ahw->mbx_lock);
-	set_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
 	set_bit(QLC_83XX_MODULE_LOADED, &ahw->idc.status);
 	ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
 	ahw->reset_context = 0;
@@ -1395,6 +1335,7 @@ static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
 				  struct qlcnic_cmd_args *cmd)
 {
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_mailbox *mbx = ahw->mailbox;
 	struct device *dev = &adapter->pdev->dev;
 	struct qlcnic_bc_trans *trans;
 	int err;
@@ -1411,7 +1352,7 @@ static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
 		goto cleanup_transaction;
 
 retry:
-	if (!test_bit(QLC_83XX_MBX_READY, &ahw->idc.status)) {
+	if (!test_bit(QLC_83XX_MBX_READY, &mbx->status)) {
 		rsp = -EIO;
 		QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
 		      QLCNIC_MBX_RSP(cmd->req.arg[0]), func);
@@ -1454,7 +1395,7 @@ err_out:
 	if (rsp == QLCNIC_RCODE_TIMEOUT) {
 		ahw->reset_context = 1;
 		adapter->need_fw_reset = 1;
-		clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 	}
 
 cleanup_transaction:
@@ -1657,8 +1598,10 @@ static void qlcnic_sriov_vf_detach(struct qlcnic_adapter *adapter)
 	struct net_device *netdev = adapter->netdev;
 	u8 i, max_ints = ahw->num_msix - 1;
 
-	qlcnic_83xx_disable_mbx_intr(adapter);
 	netif_device_detach(netdev);
+	qlcnic_83xx_detach_mailbox_work(adapter);
+	qlcnic_83xx_disable_mbx_intr(adapter);
+
 	if (netif_running(netdev))
 		qlcnic_down(adapter, netdev);
 
@@ -1702,6 +1645,7 @@ static int qlcnic_sriov_vf_handle_dev_ready(struct qlcnic_adapter *adapter)
 static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_mailbox *mbx = ahw->mailbox;
 	struct device *dev = &adapter->pdev->dev;
 	struct qlc_83xx_idc *idc = &ahw->idc;
 	u8 func = ahw->pci_func;
@@ -1712,7 +1656,7 @@ static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter)
 	/* Skip the context reset and check if FW is hung */
 	if (adapter->reset_ctx_cnt < 3) {
 		adapter->need_fw_reset = 1;
-		clear_bit(QLC_83XX_MBX_READY, &idc->status);
+		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 		dev_info(dev,
 			 "Resetting context, wait here to check if FW is in failed state\n");
 		return 0;
@@ -1737,7 +1681,7 @@ static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter)
 		 __func__, adapter->reset_ctx_cnt, func);
 	set_bit(__QLCNIC_RESETTING, &adapter->state);
 	adapter->need_fw_reset = 1;
-	clear_bit(QLC_83XX_MBX_READY, &idc->status);
+	clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 	qlcnic_sriov_vf_detach(adapter);
 	adapter->need_fw_reset = 0;
 
@@ -1787,6 +1731,7 @@ static int qlcnic_sriov_vf_idc_failed_state(struct qlcnic_adapter *adapter)
 static int
 qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter)
 {
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 	struct qlc_83xx_idc *idc = &adapter->ahw->idc;
 
 	dev_info(&adapter->pdev->dev, "Device is in quiescent state\n");
@@ -1794,7 +1739,7 @@ qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter)
 		set_bit(__QLCNIC_RESETTING, &adapter->state);
 		adapter->tx_timeo_cnt = 0;
 		adapter->reset_ctx_cnt = 0;
-		clear_bit(QLC_83XX_MBX_READY, &idc->status);
+		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 		qlcnic_sriov_vf_detach(adapter);
 	}
 
@@ -1803,6 +1748,7 @@ qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter)
 
 static int qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter *adapter)
 {
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 	struct qlc_83xx_idc *idc = &adapter->ahw->idc;
 	u8 func = adapter->ahw->pci_func;
 
@@ -1812,7 +1758,7 @@ static int qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter *adapter)
 		set_bit(__QLCNIC_RESETTING, &adapter->state);
 		adapter->tx_timeo_cnt = 0;
 		adapter->reset_ctx_cnt = 0;
-		clear_bit(QLC_83XX_MBX_READY, &idc->status);
+		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
 		qlcnic_sriov_vf_detach(adapter);
 	}
 	return 0;
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next v3 5/5] qlcnic: Update version to 5.2.45
From: Himanshu Madhani @ 2013-08-02  4:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <cover.1375438720.git.himanshu.madhani@qlogic.com>

From: Himanshu Madhani <himanshu.madhani@qlogic.com>

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index cd95442..eae41bc 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -37,8 +37,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 2
-#define _QLCNIC_LINUX_SUBVERSION 44
-#define QLCNIC_LINUX_VERSIONID  "5.2.44"
+#define _QLCNIC_LINUX_SUBVERSION 45
+#define QLCNIC_LINUX_VERSIONID  "5.2.45"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next v3 4/5] qlcnic: Enable mailbox interface in poll mode when interrupts are not available
From: Himanshu Madhani @ 2013-08-02  4:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Manish Chopra, himanshu.madhani
In-Reply-To: <cover.1375438720.git.himanshu.madhani@qlogic.com>

From: Manish Chopra <manish.chopra@qlogic.com>

Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 1eeeed8..948ab72 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -945,6 +945,7 @@ void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *adapter)
 		return;
 
 	INIT_DELAYED_WORK(&adapter->mbx_poll_work, qlcnic_83xx_mbx_poll_work);
+	queue_delayed_work(adapter->qlcnic_wq, &adapter->mbx_poll_work, 0);
 }
 
 void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *adapter)
@@ -1331,8 +1332,10 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,
 
 	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
 		/* disable and free mailbox interrupt */
-		if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+			qlcnic_83xx_enable_mbx_poll(adapter);
 			qlcnic_83xx_free_mbx_intr(adapter);
+		}
 		adapter->ahw->loopback_state = 0;
 		adapter->ahw->hw_ops->setup_link_event(adapter, 1);
 	}
@@ -1353,6 +1356,8 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
 		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 			sds_ring = &adapter->recv_ctx->sds_rings[ring];
 			qlcnic_83xx_disable_intr(adapter, sds_ring);
+			if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+				qlcnic_83xx_enable_mbx_poll(adapter);
 		}
 	}
 
@@ -1362,6 +1367,7 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
 	if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
 		if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
 			err = qlcnic_83xx_setup_mbx_intr(adapter);
+			qlcnic_83xx_disable_mbx_poll(adapter);
 			if (err) {
 				dev_err(&adapter->pdev->dev,
 					"%s: failed to setup mbx interrupt\n",
@@ -1378,6 +1384,10 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
 
 	if (netif_running(netdev))
 		__qlcnic_up(adapter, netdev);
+
+	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST &&
+	    !(adapter->flags & QLCNIC_MSIX_ENABLED))
+		qlcnic_83xx_disable_mbx_poll(adapter);
 out:
 	netif_device_attach(netdev);
 }
@@ -1662,8 +1672,6 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
 	/* Poll for link up event before running traffic */
 	do {
 		msleep(QLC_83XX_LB_MSLEEP_COUNT);
-		if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
-			qlcnic_83xx_process_aen(adapter);
 
 		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
 			netdev_info(netdev,
@@ -1740,8 +1748,6 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 	/* Wait for Link and IDC Completion AEN */
 	do {
 		msleep(QLC_83XX_LB_MSLEEP_COUNT);
-		if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
-			qlcnic_83xx_process_aen(adapter);
 
 		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
 			netdev_info(netdev,
@@ -1789,8 +1795,6 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 	/* Wait for Link and IDC Completion AEN */
 	do {
 		msleep(QLC_83XX_LB_MSLEEP_COUNT);
-		if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
-			qlcnic_83xx_process_aen(adapter);
 
 		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
 			netdev_info(netdev,
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next v3 2/5] qlcnic: Interrupt based driver firmware mailbox mechanism
From: Himanshu Madhani @ 2013-08-02  4:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Manish Chopra, himanshu.madhani
In-Reply-To: <cover.1375438720.git.himanshu.madhani@qlogic.com>

From: Manish Chopra <manish.chopra@qlogic.com>

o Driver firmware mailbox interface was operating in polling mode
  because of limitations with the earlier versions of 83xx adapter firmware.
  These issues are resolved and we are implementing interrupt based mailbox
  mechanism.

o Data structures and API's for interrupt mode mailbox mechanism.

Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |  48 +++-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    | 314 ++++++++++++++++++++-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |  25 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c  |   4 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   |  18 +-
 5 files changed, 388 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index aa0e68e..5a49b64 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -20,7 +20,6 @@
 #include <linux/tcp.h>
 #include <linux/skbuff.h>
 #include <linux/firmware.h>
-
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/timer.h>
@@ -468,6 +467,7 @@ struct qlcnic_hardware_context {
 	u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
 	u32 mbox_reg[4];
 	spinlock_t mbx_lock;
+	struct qlcnic_mailbox *mailbox;
 };
 
 struct qlcnic_adapter_stats {
@@ -966,6 +966,21 @@ struct qlcnic_filter_hash {
 	u16 fbucket_size;
 };
 
+/* Mailbox specific data structures */
+struct qlcnic_mailbox {
+	struct workqueue_struct	*work_q;
+	struct qlcnic_adapter	*adapter;
+	struct qlcnic_mbx_ops	*ops;
+	struct work_struct	work;
+	struct completion	completion;
+	struct list_head	cmd_q;
+	unsigned long		status;
+	spinlock_t		queue_lock;	/* Mailbox queue lock */
+	spinlock_t		aen_lock;	/* Mailbox response/AEN lock */
+	atomic_t		rsp_status;
+	u32			num_cmds;
+};
+
 struct qlcnic_adapter {
 	struct qlcnic_hardware_context *ahw;
 	struct qlcnic_recv_context *recv_ctx;
@@ -1379,9 +1394,20 @@ struct _cdrp_cmd {
 };
 
 struct qlcnic_cmd_args {
-	struct _cdrp_cmd req;
-	struct _cdrp_cmd rsp;
-	int op_type;
+	struct completion	completion;
+	struct list_head	list;
+	struct _cdrp_cmd	req;
+	struct _cdrp_cmd	rsp;
+	atomic_t		rsp_status;
+	int			pay_size;
+	u32			rsp_opcode;
+	u32			total_cmds;
+	u32			op_type;
+	u32			type;
+	u32			cmd_op;
+	u32			*hdr;	/* Back channel message header */
+	u32			*pay;	/* Back channel message payload */
+	u8			func_num;
 };
 
 int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
@@ -1594,6 +1620,20 @@ struct qlcnic_nic_template {
 	int (*resume)(struct qlcnic_adapter *);
 };
 
+struct qlcnic_mbx_ops {
+	int (*enqueue_cmd) (struct qlcnic_adapter *,
+			    struct qlcnic_cmd_args *, unsigned long *);
+	void (*dequeue_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+	void (*decode_resp) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+	void (*encode_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+	void (*nofity_fw) (struct qlcnic_adapter *, u8);
+};
+
+int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *);
+void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *);
+void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx);
+void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx);
+
 /* Adapter hardware abstraction */
 struct qlcnic_hardware_ops {
 	void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index cda188d..74c8d84 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -149,7 +149,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
 	.get_mac_address		= qlcnic_83xx_get_mac_address,
 	.setup_intr			= qlcnic_83xx_setup_intr,
 	.alloc_mbx_args			= qlcnic_83xx_alloc_mbx_args,
-	.mbx_cmd			= qlcnic_83xx_mbx_op,
+	.mbx_cmd			= qlcnic_83xx_issue_cmd,
 	.get_func_no			= qlcnic_83xx_get_func_no,
 	.api_lock			= qlcnic_83xx_cam_lock,
 	.api_unlock			= qlcnic_83xx_cam_unlock,
@@ -398,6 +398,12 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 	return IRQ_HANDLED;
 }
 
+static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
+{
+	atomic_set(&mbx->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
+	complete(&mbx->completion);
+}
+
 static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
 {
 	u32 resp, event;
@@ -515,7 +521,7 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
 	}
 
 	/* Enable mailbox interrupt */
-	qlcnic_83xx_enable_mbx_intrpt(adapter);
+	qlcnic_83xx_enable_mbx_interrupt(adapter);
 
 	return err;
 }
@@ -629,7 +635,7 @@ void qlcnic_83xx_set_mac_filter_count(struct qlcnic_adapter *adapter)
 	ahw->max_uc_count = count;
 }
 
-void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
+void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *adapter)
 {
 	u32 val;
 
@@ -737,8 +743,8 @@ u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter, u32 *wait_time)
 	return data;
 }
 
-int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
-		       struct qlcnic_cmd_args *cmd)
+int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,
+			  struct qlcnic_cmd_args *cmd)
 {
 	int i;
 	u16 opcode;
@@ -829,6 +835,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
 	u32 temp;
 	const struct qlcnic_mailbox_metadata *mbx_tbl;
 
+	memset(mbx, 0, sizeof(struct qlcnic_cmd_args));
 	mbx_tbl = qlcnic_83xx_mbx_tbl;
 	size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
 	for (i = 0; i < size; i++) {
@@ -3455,3 +3462,300 @@ int qlcnic_83xx_resume(struct qlcnic_adapter *adapter)
 			     idc->delay);
 	return err;
 }
+
+void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx)
+{
+	INIT_COMPLETION(mbx->completion);
+	set_bit(QLC_83XX_MBX_READY, &mbx->status);
+}
+
+void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx)
+{
+	destroy_workqueue(mbx->work_q);
+	kfree(mbx);
+}
+
+static inline void
+qlcnic_83xx_notify_cmd_completion(struct qlcnic_adapter *adapter,
+				  struct qlcnic_cmd_args *cmd)
+{
+	atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
+
+	if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) {
+		qlcnic_free_mbx_args(cmd);
+		kfree(cmd);
+		return;
+	}
+	complete(&cmd->completion);
+}
+
+static inline void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
+	struct list_head *head = &mbx->cmd_q;
+	struct qlcnic_cmd_args *cmd = NULL;
+
+	spin_lock(&mbx->queue_lock);
+
+	while (!list_empty(head)) {
+		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
+		list_del(&cmd->list);
+		mbx->num_cmds--;
+		qlcnic_83xx_notify_cmd_completion(adapter, cmd);
+	}
+
+	spin_unlock(&mbx->queue_lock);
+}
+
+static inline int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_mailbox *mbx = ahw->mailbox;
+	u32 host_mbx_ctrl;
+
+	if (!test_bit(QLC_83XX_MBX_READY, &mbx->status))
+		return -EBUSY;
+
+	host_mbx_ctrl = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+	if (host_mbx_ctrl) {
+		ahw->idc.collect_dump = 1;
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline void qlcnic_83xx_signal_mbx_cmd(struct qlcnic_adapter *adapter,
+					      u8 issue_cmd)
+{
+	if (issue_cmd)
+		QLCWRX(adapter->ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
+	else
+		QLCWRX(adapter->ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+}
+
+static inline void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter,
+					       struct qlcnic_cmd_args *cmd)
+{
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
+
+	spin_lock(&mbx->queue_lock);
+
+	list_del(&cmd->list);
+	mbx->num_cmds--;
+
+	spin_unlock(&mbx->queue_lock);
+
+	qlcnic_83xx_notify_cmd_completion(adapter, cmd);
+}
+
+static void qlcnic_83xx_encode_mbx_cmd(struct qlcnic_adapter *adapter,
+				       struct qlcnic_cmd_args *cmd)
+{
+	u32 mbx_cmd, fw_hal_version, hdr_size, total_size, tmp;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	int i, j;
+
+	if (cmd->op_type != QLC_83XX_MBX_POST_BC_OP) {
+		mbx_cmd = cmd->req.arg[0];
+		writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+		for (i = 1; i < cmd->req.num; i++)
+			writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
+	} else {
+		fw_hal_version = ahw->fw_hal_version;
+		hdr_size = sizeof(struct qlcnic_bc_hdr) / sizeof(u32);
+		total_size = cmd->pay_size + hdr_size;
+		tmp = QLCNIC_CMD_BC_EVENT_SETUP | total_size << 16;
+		mbx_cmd = tmp | fw_hal_version << 29;
+		writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+
+		/* Back channel specific operations bits */
+		mbx_cmd = 0x1 | 1 << 4;
+
+		if (qlcnic_sriov_pf_check(adapter))
+			mbx_cmd |= cmd->func_num << 5;
+
+		writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));
+
+		for (i = 2, j = 0; j < hdr_size; i++, j++)
+			writel(*(cmd->hdr++), QLCNIC_MBX_HOST(ahw, i));
+		for (j = 0; j < cmd->pay_size; j++, i++)
+			writel(*(cmd->pay++), QLCNIC_MBX_HOST(ahw, i));
+	}
+}
+
+void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
+
+	clear_bit(QLC_83XX_MBX_READY, &mbx->status);
+	complete(&mbx->completion);
+	cancel_work_sync(&mbx->work);
+	flush_workqueue(mbx->work_q);
+	qlcnic_83xx_flush_mbx_queue(adapter);
+}
+
+static inline int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,
+					      struct qlcnic_cmd_args *cmd,
+					      unsigned long *timeout)
+{
+	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
+
+	if (test_bit(QLC_83XX_MBX_READY, &mbx->status)) {
+		atomic_set(&cmd->rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
+		init_completion(&cmd->completion);
+		cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
+
+		spin_lock(&mbx->queue_lock);
+
+		list_add_tail(&cmd->list, &mbx->cmd_q);
+		mbx->num_cmds++;
+		cmd->total_cmds = mbx->num_cmds;
+		*timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
+		queue_work(mbx->work_q, &mbx->work);
+
+		spin_unlock(&mbx->queue_lock);
+
+		return 0;
+	}
+
+	return -EBUSY;
+}
+
+static inline int qlcnic_83xx_check_mac_rcode(struct qlcnic_adapter *adapter,
+					      struct qlcnic_cmd_args *cmd)
+{
+	u8 mac_cmd_rcode;
+	u32 fw_data;
+
+	if (cmd->cmd_op == QLCNIC_CMD_CONFIG_MAC_VLAN) {
+		fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
+		mac_cmd_rcode = (u8)fw_data;
+		if (mac_cmd_rcode == QLC_83XX_NO_NIC_RESOURCE ||
+		    mac_cmd_rcode == QLC_83XX_MAC_PRESENT ||
+		    mac_cmd_rcode == QLC_83XX_MAC_ABSENT) {
+			cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS;
+			return QLCNIC_RCODE_SUCCESS;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void qlcnic_83xx_decode_mbx_rsp(struct qlcnic_adapter *adapter,
+				       struct qlcnic_cmd_args *cmd)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct device *dev = &adapter->pdev->dev;
+	u8 mbx_err_code;
+	u32 fw_data;
+
+	fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
+	mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
+	qlcnic_83xx_get_mbx_data(adapter, cmd);
+
+	switch (mbx_err_code) {
+	case QLCNIC_MBX_RSP_OK:
+	case QLCNIC_MBX_PORT_RSP_OK:
+		cmd->rsp_opcode = QLCNIC_RCODE_SUCCESS;
+		break;
+	default:
+		if (!qlcnic_83xx_check_mac_rcode(adapter, cmd))
+			break;
+
+		dev_err(dev, "%s: Mailbox command failed, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x, error=0x%x\n",
+			__func__, cmd->cmd_op, cmd->type, ahw->pci_func,
+			ahw->op_mode, mbx_err_code);
+		cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_FAILED;
+		qlcnic_dump_mbx(adapter, cmd);
+	}
+
+	return;
+}
+
+static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
+{
+	struct qlcnic_mailbox *mbx = container_of(work, struct qlcnic_mailbox,
+						  work);
+	struct qlcnic_adapter *adapter = mbx->adapter;
+	struct qlcnic_mbx_ops *mbx_ops = mbx->ops;
+	struct device *dev = &adapter->pdev->dev;
+	atomic_t *rsp_status = &mbx->rsp_status;
+	struct list_head *head = &mbx->cmd_q;
+	struct qlcnic_hardware_context *ahw;
+	struct qlcnic_cmd_args *cmd = NULL;
+
+	ahw = adapter->ahw;
+
+	while (true) {
+		if (qlcnic_83xx_check_mbx_status(adapter))
+			return;
+
+		atomic_set(rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
+
+		spin_lock(&mbx->queue_lock);
+
+		if (list_empty(head)) {
+			spin_unlock(&mbx->queue_lock);
+			return;
+		}
+		cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
+
+		spin_unlock(&mbx->queue_lock);
+
+		mbx_ops->encode_cmd(adapter, cmd);
+		mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
+
+		if (wait_for_completion_timeout(&mbx->completion,
+						QLC_83XX_MBX_TIMEOUT)) {
+			mbx_ops->decode_resp(adapter, cmd);
+			mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_COMPLETION);
+		} else {
+			dev_err(dev, "%s: Mailbox command timeout, opcode=0x%x, cmd_type=0x%x, func=0x%x, op_mode=0x%x\n",
+				__func__, cmd->cmd_op, cmd->type, ahw->pci_func,
+				ahw->op_mode);
+			clear_bit(QLC_83XX_MBX_READY, &mbx->status);
+			qlcnic_83xx_idc_request_reset(adapter,
+						      QLCNIC_FORCE_FW_DUMP_KEY);
+			cmd->rsp_opcode = QLCNIC_RCODE_TIMEOUT;
+		}
+		mbx_ops->dequeue_cmd(adapter, cmd);
+	}
+}
+
+static struct qlcnic_mbx_ops qlcnic_83xx_mbx_ops = {
+	.enqueue_cmd    = qlcnic_83xx_enqueue_mbx_cmd,
+	.dequeue_cmd    = qlcnic_83xx_dequeue_mbx_cmd,
+	.decode_resp    = qlcnic_83xx_decode_mbx_rsp,
+	.encode_cmd     = qlcnic_83xx_encode_mbx_cmd,
+	.nofity_fw      = qlcnic_83xx_signal_mbx_cmd,
+};
+
+int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	struct qlcnic_mailbox *mbx;
+
+	ahw->mailbox = kzalloc(sizeof(*mbx), GFP_KERNEL);
+	if (!ahw->mailbox)
+		return -ENOMEM;
+
+	mbx = ahw->mailbox;
+	mbx->ops = &qlcnic_83xx_mbx_ops;
+	mbx->adapter = adapter;
+
+	spin_lock_init(&mbx->queue_lock);
+	spin_lock_init(&mbx->aen_lock);
+	INIT_LIST_HEAD(&mbx->cmd_q);
+	init_completion(&mbx->completion);
+
+	mbx->work_q = create_singlethread_workqueue("qlcnic_mailbox");
+	if (mbx->work_q == NULL) {
+		kfree(mbx);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&mbx->work, qlcnic_83xx_mailbox_worker);
+	set_bit(QLC_83XX_MBX_READY, &mbx->status);
+	return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 2548d14..542b58d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -89,6 +89,13 @@
 
 #define QLC_83XX_MAX_RESET_SEQ_ENTRIES	16
 
+#define QLC_83XX_MBX_POST_BC_OP		0x1
+#define QLC_83XX_MBX_COMPLETION		0x0
+#define QLC_83XX_MBX_REQUEST		0x1
+
+#define QLC_83XX_MBX_TIMEOUT		(5 * HZ)
+#define QLC_83XX_MBX_CMD_LOOP		5000000
+
 /* status descriptor mailbox data
  * @phy_addr_{low|high}: physical address of buffer
  * @sds_ring_size: buffer size
@@ -449,6 +456,20 @@ enum qlcnic_83xx_states {
 #define QLC_83xx_FLASH_MAX_WAIT_USEC		100
 #define QLC_83XX_FLASH_LOCK_TIMEOUT		10000
 
+enum qlc_83xx_mbx_cmd_type {
+	QLC_83XX_MBX_CMD_WAIT = 0,
+	QLC_83XX_MBX_CMD_NO_WAIT,
+	QLC_83XX_MBX_CMD_BUSY_WAIT,
+};
+
+enum qlc_83xx_mbx_response_states {
+	QLC_83XX_MBX_RESPONSE_WAIT = 0,
+	QLC_83XX_MBX_RESPONSE_ARRIVED,
+};
+
+#define QLC_83XX_MBX_RESPONSE_FAILED	0x2
+#define QLC_83XX_MBX_RESPONSE_UNKNOWN	0x3
+
 /* Additional registers in 83xx */
 enum qlc_83xx_ext_regs {
 	QLCNIC_GLOBAL_RESET = 0,
@@ -498,7 +519,7 @@ enum qlc_83xx_ext_regs {
 
 /* 83xx funcitons */
 int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
-int qlcnic_83xx_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
 int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
 void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
 int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
@@ -551,7 +572,7 @@ void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,
 void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
 irqreturn_t qlcnic_83xx_handle_aen(int, void *);
 int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
-void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
+void qlcnic_83xx_enable_mbx_interrupt(struct qlcnic_adapter *);
 void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *);
 irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
 irqreturn_t qlcnic_83xx_intr(int, void *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index f41dfab..0c5110c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -617,7 +617,7 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
 	if (err)
 		return err;
 
-	qlcnic_83xx_enable_mbx_intrpt(adapter);
+	qlcnic_83xx_enable_mbx_interrupt(adapter);
 
 	if (qlcnic_83xx_configure_opmode(adapter)) {
 		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
@@ -2120,7 +2120,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
 	/* Initilaize 83xx mailbox spinlock */
 	spin_lock_init(&ahw->mbx_lock);
 
-	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+	set_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
 	qlcnic_83xx_clear_function_resources(adapter);
 
 	/* register for NIC IDC AEN Events */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 62380ce..d9c6ae5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -33,7 +33,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *, u32);
 static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *);
 static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
 static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
-static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
+static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *,
 				  struct qlcnic_cmd_args *);
 static void qlcnic_sriov_process_bc_cmd(struct work_struct *);
 
@@ -45,7 +45,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
 	.get_mac_address		= qlcnic_83xx_get_mac_address,
 	.setup_intr			= qlcnic_83xx_setup_intr,
 	.alloc_mbx_args			= qlcnic_83xx_alloc_mbx_args,
-	.mbx_cmd			= qlcnic_sriov_vf_mbx_op,
+	.mbx_cmd			= qlcnic_sriov_issue_cmd,
 	.get_func_no			= qlcnic_83xx_get_func_no,
 	.api_lock			= qlcnic_83xx_cam_lock,
 	.api_unlock			= qlcnic_83xx_cam_unlock,
@@ -295,7 +295,7 @@ static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
 
 	opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
 
-	if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+	if (!test_bit(QLC_83XX_MBX_READY, &ahw->idc.status)) {
 		dev_info(&adapter->pdev->dev,
 			 "Mailbox cmd attempted, 0x%x\n", opcode);
 		dev_info(&adapter->pdev->dev, "Mailbox detached\n");
@@ -1083,6 +1083,7 @@ static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
 	if (test_bit(QLC_BC_VF_FLR, &vf->state))
 		return;
 
+	memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
 	trans = list_first_entry(&vf->rcv_act.wait_list,
 				 struct qlcnic_bc_trans, list);
 	adapter = vf->adapter;
@@ -1232,6 +1233,7 @@ static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
 		return;
 	}
 
+	memset(&cmd, 0, sizeof(struct qlcnic_cmd_args));
 	cmd_op = hdr->cmd_op;
 	if (qlcnic_sriov_alloc_bc_trans(&trans))
 		return;
@@ -1357,7 +1359,7 @@ int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable)
 	if (enable)
 		cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
 
-	err = qlcnic_83xx_mbx_op(adapter, &cmd);
+	err = qlcnic_83xx_issue_cmd(adapter, &cmd);
 
 	if (err != QLCNIC_RCODE_SUCCESS) {
 		dev_err(&adapter->pdev->dev,
@@ -1389,7 +1391,7 @@ static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter,
 	return -EIO;
 }
 
-static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter,
+static int qlcnic_sriov_issue_cmd(struct qlcnic_adapter *adapter,
 				  struct qlcnic_cmd_args *cmd)
 {
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -1409,7 +1411,7 @@ static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter,
 		goto cleanup_transaction;
 
 retry:
-	if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+	if (!test_bit(QLC_83XX_MBX_READY, &ahw->idc.status)) {
 		rsp = -EIO;
 		QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
 		      QLCNIC_MBX_RSP(cmd->req.arg[0]), func);
@@ -1612,7 +1614,7 @@ static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
 	int err;
 
 	set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
-	qlcnic_83xx_enable_mbx_intrpt(adapter);
+	qlcnic_83xx_enable_mbx_interrupt(adapter);
 
 	err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
 	if (err)
@@ -1988,7 +1990,7 @@ int qlcnic_sriov_vf_resume(struct qlcnic_adapter *adapter)
 	int err;
 
 	set_bit(QLC_83XX_MODULE_LOADED, &idc->status);
-	qlcnic_83xx_enable_mbx_intrpt(adapter);
+	qlcnic_83xx_enable_mbx_interrupt(adapter);
 	err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
 	if (err)
 		return err;
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next v3 1/5] qlcnic: Enhance diagnostic loopback error codes.
From: Himanshu Madhani @ 2013-08-02  4:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Jitendra Kalsaria,
	himanshu.madhani
In-Reply-To: <cover.1375438720.git.himanshu.madhani@qlogic.com>

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

o Enhanced the driver to use standard Linux error codes
o Return a unique error code to indicate loopback is in progress

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |  6 ------
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    | 23 +++++++++++++++-------
 .../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c    |  6 +++---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c     |  6 +++---
 4 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index b00cf56..aa0e68e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -950,12 +950,6 @@ struct qlcnic_ipaddr {
 #define QLCNIC_READD_AGE	20
 #define QLCNIC_LB_MAX_FILTERS	64
 #define QLCNIC_LB_BUCKET_SIZE	32
-
-/* QLCNIC Driver Error Code */
-#define QLCNIC_FW_NOT_RESPOND		51
-#define QLCNIC_TEST_IN_PROGRESS		52
-#define QLCNIC_UNDEFINED_ERROR		53
-#define QLCNIC_LB_CABLE_NOT_CONN	54
 #define QLCNIC_ILB_MAX_RCV_LOOP	10
 
 struct qlcnic_filter {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 0913c62..cda188d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -1652,7 +1652,7 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
 	if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
 		netdev_warn(netdev,
 			    "Loopback test not supported in non privileged mode\n");
-		return ret;
+		return -ENOTSUPP;
 	}
 
 	if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
@@ -1686,13 +1686,13 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
 		if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
 			netdev_info(netdev,
 				    "Device is resetting, free LB test resources\n");
-			ret = -EIO;
+			ret = -EBUSY;
 			goto free_diag_res;
 		}
 		if (loop++ > QLC_83XX_LB_WAIT_COUNT) {
 			netdev_info(netdev,
 				    "Firmware didn't sent link up event to loopback request\n");
-			ret = -QLCNIC_FW_NOT_RESPOND;
+			ret = -ETIMEDOUT;
 			qlcnic_83xx_clear_lb_mode(adapter, mode);
 			goto free_diag_res;
 		}
@@ -1729,6 +1729,15 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 		return status;
 
 	config = ahw->port_config;
+
+	/* Check if port is already in loopback mode */
+	if ((config & QLC_83XX_CFG_LOOPBACK_HSS) ||
+	    (config & QLC_83XX_CFG_LOOPBACK_EXT)) {
+		netdev_err(netdev,
+			   "Port already in Loopback mode.\n");
+		return -EINPROGRESS;
+	}
+
 	set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
 
 	if (mode == QLCNIC_ILB_MODE)
@@ -1756,14 +1765,14 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 			netdev_info(netdev,
 				    "Device is resetting, free LB test resources\n");
 			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
-			return -EIO;
+			return -EBUSY;
 		}
 		if (loop++ > QLC_83XX_LB_WAIT_COUNT) {
 			netdev_err(netdev,
 				   "Did not receive IDC completion AEN\n");
 			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
 			qlcnic_83xx_clear_lb_mode(adapter, mode);
-			return -EIO;
+			return -ETIMEDOUT;
 		}
 	} while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
 
@@ -1805,14 +1814,14 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 			netdev_info(netdev,
 				    "Device is resetting, free LB test resources\n");
 			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
-			return -EIO;
+			return -EBUSY;
 		}
 
 		if (loop++ > QLC_83XX_LB_WAIT_COUNT) {
 			netdev_err(netdev,
 				   "Did not receive IDC completion AEN\n");
 			clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
-			return -EIO;
+			return -ETIMEDOUT;
 		}
 	} while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 700a463..94a728d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -980,9 +980,9 @@ int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 		msleep(500);
 		qlcnic_process_rcv_ring_diag(sds_ring);
 		if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
-			netdev_info(netdev, "firmware didnt respond to loopback"
-				" configure request\n");
-			ret = -QLCNIC_FW_NOT_RESPOND;
+			netdev_info(netdev,
+				    "Firmware didn't sent link up event to loopback request\n");
+			ret = -ETIMEDOUT;
 			goto free_res;
 		} else if (adapter->ahw->diag_cnt) {
 			ret = adapter->ahw->diag_cnt;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index d3f8797..1994b44 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -919,17 +919,17 @@ static void qlcnic_handle_fw_message(int desc_cnt, int index,
 			break;
 		case 1:
 			dev_info(dev, "loopback already in progress\n");
-			adapter->ahw->diag_cnt = -QLCNIC_TEST_IN_PROGRESS;
+			adapter->ahw->diag_cnt = -EINPROGRESS;
 			break;
 		case 2:
 			dev_info(dev, "loopback cable is not connected\n");
-			adapter->ahw->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
+			adapter->ahw->diag_cnt = -ENODEV;
 			break;
 		default:
 			dev_info(dev,
 				 "loopback configure request failed, err %x\n",
 				 ret);
-			adapter->ahw->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
+			adapter->ahw->diag_cnt = -EIO;
 			break;
 		}
 		break;
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net-next v3 0/5] qlcnic: Mailbox refactoring
From: Himanshu Madhani @ 2013-08-02  4:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani

From: Himanshu Madhani <himanshu.madhani@qlogic.com>

This series contains following patches 

o in v2 series, we received feedback on return codes to use standard error
  codes instead of mixing custom error codes. We have modified patch for 
  loopback diagnostic test to return standard error codes.

o rest of the 3 patches in the series are for mailbox refactoring

  Current driver-firmware mailbox interface was operating in polling mode
  because of some limitations with the earlier versions of 83xx adapter
  firmware. These issues are resolved now and we are implementing the
  mailbox interface in interrupt mode.

  There are three patches which refactors mailbox handling:
  * Interrupt mode mailbox implantation.
  * Replace poll mode mailbox interfaces with interrupt mode interfaces.
  * Operate mailbox in poll mode when interrupts are not available.

changes from v2 -> v3
 * Addressed review feedback to use standard return codes for loopback
   diagnostic test.

Please consider applying these patches to net-next.

Thanks,
Himanshu

Himanshu Madhani (1):
  qlcnic: Update version to 5.2.45

Jitendra Kalsaria (1):
  qlcnic: Enhance diagnostic loopback error codes.

Manish Chopra (3):
  qlcnic: Interrupt based driver firmware mailbox mechanism
  qlcnic: Replace poll mode mailbox interface with interrupt based
    mailbox interface
  qlcnic: Enable mailbox interface in poll mode when interrupts are not
    available

 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |  59 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    | 615 +++++++++++++++------
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |  27 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c  |  83 ++-
 .../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c    |   6 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c     |   6 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |  18 +-
 .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c   | 146 ++---
 8 files changed, 651 insertions(+), 309 deletions(-)

-- 
1.8.1.4

^ permalink raw reply

* [PATCH ethtool] ethtool: Add string/define to display Port Type for Backplane Ethernet
From: Somnath Kotur @ 2013-08-02  5:06 UTC (permalink / raw)
  To: bhutchings; +Cc: netdev, Somnath Kotur

Signed-off-by: Somnath Kotur <somnath.kotur@emulex.com>
---
 ethtool-copy.h |    1 +
 ethtool.c      |    3 +++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/ethtool-copy.h b/ethtool-copy.h
index b5515c2..33ff7d3 100644
--- a/ethtool-copy.h
+++ b/ethtool-copy.h
@@ -989,6 +989,7 @@ enum ethtool_sfeatures_retval_bits {
 #define PORT_FIBRE		0x03
 #define PORT_BNC		0x04
 #define PORT_DA			0x05
+#define PORT_BACKPLANE		0x06
 #define PORT_NONE		0xef
 #define PORT_OTHER		0xff
 
diff --git a/ethtool.c b/ethtool.c
index b24b572..4db42b3 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -625,6 +625,9 @@ static int dump_ecmd(struct ethtool_cmd *ep)
 	case PORT_DA:
 		fprintf(stdout, "Direct Attach Copper\n");
 		break;
+	case PORT_BACKPLANE:
+		fprintf(stdout, "BackPlane\n");
+		break;
 	case PORT_NONE:
 		fprintf(stdout, "None\n");
 		break;
-- 
1.7.1

^ permalink raw reply related

* Re: minimum ICMPv6 message size vs. RPL's DIS
From: Werner Almesberger @ 2013-08-02  4:51 UTC (permalink / raw)
  To: David Miller; +Cc: hannes, netdev
In-Reply-To: <20130801.181022.1784276332134390788.davem@davemloft.net>

David Miller wrote:
> FWIW I think this is a safe change.

Thanks !

Regarding the change to icmpv6.h, I found that the introduction
of the otherwise very nice and tidy "struct icmp6hdr_head" creates
a conflict with net/bridge/br_multicast.c:br_multicast_ipv6_rcv
which has a variable called "icmp6_type".

While it would be easy enough to rename that variable, this makes
me wonder if the change isn't too intrusive after all, I think
I'd rather go with my original idea and just change the size to 4,
with a comment why and what this is.

I'll post the patches in a bit.

- Werner

^ permalink raw reply

* Re: Fw: [Bug 60669] Kernel panic when using negative priority for HTB class
From: Cong Wang @ 2013-08-02  4:50 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20130801211231.1b25c3be@nehalam.linuxnetplumber.net>

On Fri, 02 Aug 2013 at 04:12 GMT, Stephen Hemminger <stephen@networkplumber.org> wrote:
>
> --- Comment #2 from _Vi <vi0oss@gmail.com> ---
> Reproducible on 3.11.0-rc3
>
> Looks like negative priority value is essential for the kernel panic.
>

There is a check for prio:

                if ((cl->prio = hopt->prio) >= TC_HTB_NUMPRIO)
		                        cl->prio = TC_HTB_NUMPRIO - 1;
					

^ permalink raw reply

* Fw: [Bug 60669] Kernel panic when using negative priority for HTB class
From: Stephen Hemminger @ 2013-08-02  4:12 UTC (permalink / raw)
  To: netdev



Begin forwarded message:

Date: Thu, 1 Aug 2013 02:38:53 -0700
From: "bugzilla-daemon@bugzilla.kernel.org" <bugzilla-daemon@bugzilla.kernel.org>
To: "stephen@networkplumber.org" <stephen@networkplumber.org>
Subject: [Bug 60669] Kernel panic when using negative priority for HTB class


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

_Vi <vi0oss@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|Kernel panic when using HTB |Kernel panic when using
                   |qdisc                       |negative priority for HTB
                   |                            |class

--- Comment #2 from _Vi <vi0oss@gmail.com> ---
Reproducible on 3.11.0-rc3

Looks like negative priority value is essential for the kernel panic.

-- 
You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* Re: Question regarding failure utilizing bonding mode 5 (balance-tlb)
From: Jay Vosburgh @ 2013-08-02  3:09 UTC (permalink / raw)
  To: Yuval Mintz; +Cc: netdev@vger.kernel.org, Ariel Elior
In-Reply-To: <1375333968.21294.30.camel@lb-tlvb-yuvalmin.il.broadcom.com>

Yuval Mintz <yuvalmin@broadcom.com> wrote:

>We've had reports that load/unload tests using bonding driver in
>balance-tlb mode over bnx2x interfaces results in loss of traffic.

	I've also been looking into what I suspect is the same thing,
although using bnx2 and not bnx2x.

>When investigating, we've found out that the bonding driver uses the ndo
>(ndo_change_mac_addr()) during ifenslave to override the slaves' HW MAC
>address. It then directly goes and changes the slaves netdevices'
>dev_addr so that each network interface would posses a distinguish MAC
>address (as seen in ifconfig), while the FW/HW of both interfaces is
>still configured by the MAC passed by the ndo.

	Yes.

>When the active slave is unloaded, the ifconfig MAC (dev_addr) is
>swapped between the slaves directly, i.e., without calling the ndo. Once
>the interface of the previously active slave will be reloaded, it will
>configure it's HW MAC according to that dev_addr value  (i.e., the
>bonding driver takes no additional measures to force it's own MAC on the
>interface when re-loading), causing it to have a configured MAC which
>differs from the one that is held by the bonding driver.

	I'm not sure I follow this part, looking at the code.
Basically, and correct me if I'm missing something, what you're
describing is this:

	1. Add and remove some slaves until the removed slave ends up
with dev_addr set to something stale (not it's nominal permanent
hardware address).

	2. Enslave that device, bond_enslave calls dev_open, and the
driver's open function programs the device's MAC to what's in dev_addr

	The part I don't follow is that in bond_enslave, this sequence
occurs:

	1. bond_enslave calls dev_set_mac_address ("the ndo") to program
the newly added slave with the master's MAC.  The ndo_set_mac_address
functions for bnx2x and bnx2 both set dev_addr to the new address.

	2. bond_enslave calls dev_open, and the driver's open function
programs the device's MAC to what's in dev_addr, which is now the
master's MAC address.

	The above is true, unless fail_over_mac is enabled, and that's
not a valid option for tlb mode.  

	Also, in theory the bond will reset the slave's MAC address to
its "permanent" address when it is released from the bond.  The
"permanent" address is whatever was in dev_addr when the device was
enslaved.

	Am I misunderstanding something here?

>If this is done an additional time (on the newly active slave), both
>slave devices will be configured to a MAC which differs from the one
>held by the bond interface (i.e., the bond interface holds the MAC of
>the original active slave, while both interfaces configured the MAC of
>the original inactive slave). This obviously prevents any traffic from
>being successfully sent/received.

	Now, this part does explain the end result that we see as well,
although it's been more random here (we did not have a specific recipe
to induce it, so I'll be trying out yours as soon as I can).  The device
can TX just fine, but all incoming traffic is dropped.  Placing the
device into promiscuous mode works around the problem for as long as
promisc is enabled.

>bnx2x uses dev_addr directly for MAC configuration, which I think is the
>default behaviour for most network drivers - ixgbe has a shadow value
>which it uses instead, but I think that's the exception and not the
>rule.
>
>As I see it, either:
>
>   1. The bonding driver is flawed in balance-tlb mode and should be
>fixed.
>
>   2. bnx2x's behaviour is flawed - it should have some persistent
>shadow MAC which should contain the last MAC set - either factory value
>or what was configured by the ndo, and use it instead of dev_addr when
>configuring the HW MAC.
>This would probably indicate that other drivers are flawed as well.
>
>   3. The test itself is flawed, since user should not unload slave
>interfaces.
>
>What's the correct approach for fixing the issue?

	Well, I suspect it's not going to be #2.  Loading and unloading
slaves ought to work, and I'm willing to believe that bonding is doing
something odd, but I don't see what it is from the above.

	-J

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

^ permalink raw reply

* Re: [Patch net-next 1/2] net: fix a compile error when CONFIG_NET_LL_RX_POLL is not set
From: Eliezer Tamir @ 2013-08-02  3:04 UTC (permalink / raw)
  To: David Miller; +Cc: amwang, netdev
In-Reply-To: <20130801.130338.1147816900371465134.davem@davemloft.net>

On 01/08/2013 23:03, David Miller wrote:
> From: Cong Wang <amwang@redhat.com>
> Date: Thu, 01 Aug 2013 16:08:07 +0800
> 
>> Thinking about it again, what is the point of your commit commit
>> 89bf1b5a683df497c572c4d3bd3f9c9aa919d773 (net: remove NET_LL_RX_POLL
>> config menue)? After that commit, CONFIG_NET_LL_RX_POLL is not visible
>> by user and no other configs select it, also since it defaults to y, it
>> will be _always_ enabled. If this is really what you want, we can simply
>> remove all !CONFIG_NET_LL_RX_POLL code.
> 
> Yes we could do that, it has no dependencies which is the usual reason
> to have a hidden Kconfig var like this.

I think we still need a config option that depends on net and the
placeholder code.
What happens then if someone does not configure networking?
Won't this break select and poll?

^ permalink raw reply

* Re: PROBLEM: 3.11.0-rc2+ lost of connectivity
From: Cong Wang @ 2013-08-02  2:47 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev
In-Reply-To: <CAOSRKdTOcYOZ4fD5gXe_57dA028rGmR30T32FQ6MeruAq2p04g@mail.gmail.com>

On Thu, 01 Aug 2013 at 14:34 GMT, Sebastiano Spicuglia <spicuglia.sebastiano@gmail.com> wrote:
>
> The machine suddenly stops to be connected to the network.
> Running "ifdown eth0" "ifup eth0" the network starts to work
> again for few minutes and then the failure happens again.
> It is not even possible to ping the machine.
> /var/log/messages does not report anything wrong.
>
> I instrumented the kernel with SystemTap to see what happens when the
> machine is in the failure state.
>
> the function ip_rcv is invoked.
> the function ip_rcv_finish is invoked.
> the function ip_local_deliver is invoked
> the function ip_local_deliver_finish is invoked
> the function tcp_v4_rcv is NOT invoked
>
> When the network works the function tcp_v4_rcv is invoked.
>

Please turn off your firewall and run dropwatch to see where the
packets are dropped.

^ permalink raw reply

* [PATCH net-next] sctp: Don't lookup dst if transport dst is still valid
From: Fan Du @ 2013-08-02  2:45 UTC (permalink / raw)
  To: vyasevich, nhorman; +Cc: davem, netdev

When sctp sits on IPv6, sctp_transport_dst_check pass cookie as ZERO,
as a result ip6_dst_check always fail out. This behaviour makes
transport->dst useless, because every sctp_packet_transmit must look
for valid dst.

Add a dst_cookie into sctp_transport, and set the cookie whenever we
get new dst for sctp_transport. So dst validness could be checked
against it.

Since I have split genid for IPv4 and IPv6, also delete/add IPv6 address
will also bump IPv6 genid. So issues we discussed in:
http://marc.info/?l=linux-netdev&m=137404469219410&w=4
have all been sloved for this patch.

Signed-off-by: Fan Du <fan.du@windriver.com>
---
 include/net/sctp/sctp.h    |    2 +-
 include/net/sctp/structs.h |    1 +
 net/sctp/ipv6.c            |    2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 554cf88..cb28df9 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -613,7 +613,7 @@ static inline void sctp_v4_map_v6(union sctp_addr *addr)
  */
 static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t)
 {
-	if (t->dst && !dst_check(t->dst, 0)) {
+	if (t->dst && !dst_check(t->dst, t->dst_cookie)) {
 		dst_release(t->dst);
 		t->dst = NULL;
 	}
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 75c4c16..c0f4e29 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -946,6 +946,7 @@ struct sctp_transport {
 	__u64 hb_nonce;
 
 	struct rcu_head rcu;
+	u32 dst_cookie;
 };
 
 struct sctp_transport *sctp_transport_new(struct net *, const union sctp_addr *,
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 85d688f..5a9402e 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -351,7 +351,7 @@ out:
 
 		rt = (struct rt6_info *)dst;
 		t->dst = dst;
-
+		t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
 		pr_debug("rt6_dst:%pI6 rt6_src:%pI6\n", &rt->rt6i_dst.addr,
 			 &fl6->saddr);
 	} else {
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH] xfrm: Refactor xfrm_state timer management
From: Fan Du @ 2013-08-02  2:14 UTC (permalink / raw)
  To: David Miller; +Cc: steffen.klassert, herbert, netdev
In-Reply-To: <20130801.153512.307039655614237376.davem@davemloft.net>



On 2013年08月02日 06:35, David Miller wrote:
> From: Fan Du<fan.du@windriver.com>
> Date: Thu, 1 Aug 2013 15:39:50 +0800
>
>> Current xfrm_state timer management is vulnerable in below several ways:
>>
>> - Use hrtimer for timer, the timer handler use wall clock checking expire events
>>    commit e3c0d047 "Fix unexpected SA hard expiration after changing date" fix
>>    the partial problem by notify IKED with soft ->  expire sequence when user
>>    changing system time forward. But it didn't fix the issue when use changing
>>    system time backwards, which is most crucial as SAs lifetime will be a *bigger*
>>    one when doing so, thus buy much time for cracker.
>>
>>    In short words, changing system time forward/backward can either result in
>>    long long lifetime SAs or sudden SA hard expired first.
>>
>>    It actually can be fixed this by adding more flags, and with more complicated
>>    checking whether system time is being turned forward or backward. I did it and
>>    eventually works well. But it's only for "add time expire", taking care of
>>    "use time expire" will add more logic into timer handler, and much more
>>    complicated.
>>
>> - When user give "use lifetime" by xfrm user configuration
>>    interface, current xfrm_state timer management will actually turn the timer on
>>    even when no IP packet hit policy, and the "use lifetime" eventually become
>>    "add lifetime".
>>
>> The culprit is: with one timer for both "add lifetime" and "use lifetime", at the
>> same time using wall clock to check two expire events. This patch tries to solve
>> it by:
>> - Switch real time timer with monotonic timer against any system time changing
>> - Use "add lifetime" to override "use lifetime" when both applied, as most popular
>>    IKED like Racoon2/StrongSwan use "add lifetime" only.
>> - Start "add lifetime" timer only when xfrm_state is updated/added
>> - Start "use lifetime" timer when actually SAs is used.
>> - Start the timer with soft lifetime interval first, and then in timer handler
>>    rearm timer with hard lifetime to get rid of using wall clock.
>>
>> Signed-off-by: Fan Du<fan.du@windriver.com>
>
> This is getting way too complicated, there must be a much better way
> to handle this.
>
> I suspect the thing to do is to have system time changes generate a
> notifier when clock_was_set() is called.
>
> The XFRM code would walk the rules and pretend that we hit the soft
> timeout for every rule that we haven't hit the soft timeout yet
> already.
>
> If a rule hit the soft timeout, force a hard timeout.
>
> When forcing a soft timeout, adjust the hard timeout to be
> (hard_timeout - soft_timeout) into the future.
>
> Because these other approaches are extremely fragile and
> unmaintainable.
>
Hi, Dave

Your idea is my initial approach to this issue :) but please let me try
to explain this clearly to you.

soft timeout and hard timeout should be independent of system clock,
for example, set SA hard lifetime to 180s, soft lifetime to 153s,
in this configuration, soft timeout is expected to happen after exactly
153s, notifying IKED soft timeout from kernel has nothing to do with
currently wall clock. The same is true for hard timeout. This is the way
this patch following.

But original xfrm design is using wall clock to check whether soft/hard
timeout happen. That's because original designer think by "add lifetime",
the starting point for timing is when alloc this SA(xfrm_state_alloc).
This is improper, because the SA only takes effect when it's ready,
and its lifetime should be timing from IKED has added/updated this SA
(xfrm_state_add/update).

Also original xfrm design doesn't start timer with soft lifetime first,
A 1 second timeout is initiated to drive timer handler to calculate
soft timeout, and then in the next timer interrupt calculate hard timeout.
So this timer actually timeout three times. And I think we don't need to
that at all.

Last but not least, "use lifetime" should be started in
xfrm_state_check_expire when this SA is indeed used for the first time.
Original design mingle "add lifetime" and "use lifetime" together.

That's the problem we have in current XFRM layer. I thought about whenever
system clock is updated, notify XFRM layer, again transverse all xfrm_state
need to take locks. And what about the SA when it just enter timer handler
and system clock is update. Notifier will delay quite a bit.

The initiative to rework xfrm_state timer independent of system clock is
host needs to calibrate local time with GPS or ntp frequently, and SAs
lifetime shouldn't be impacted.


-- 
浮沉随浪只记今朝笑

--fan

^ permalink raw reply

* Re: [PATCH net] xfrm: Delete hold_timer when destroy policy
From: Fan Du @ 2013-08-02  1:22 UTC (permalink / raw)
  To: Steffen Klassert; +Cc: davem, netdev
In-Reply-To: <20130801120146.GD25511@secunet.com>



On 2013年08月01日 20:01, Steffen Klassert wrote:
> On Thu, Aug 01, 2013 at 06:08:36PM +0800, Fan Du wrote:
>> Both policy timer and hold_timer need to be deleted when destroy policy
>> Bad mood today, maybe I'm wrong about this...
>>
>> Signed-off-by: Fan Du<fan.du@windriver.com>
>> ---
>>   net/xfrm/xfrm_policy.c |    2 +-
>>   1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
>> index d8da6b8..f7078eb 100644
>> --- a/net/xfrm/xfrm_policy.c
>> +++ b/net/xfrm/xfrm_policy.c
>> @@ -308,7 +308,7 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
>>   {
>>   	BUG_ON(!policy->walk.dead);
>>
>> -	if (del_timer(&policy->timer))
>> +	if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
>>   		BUG();
>>
>
> The timers should be already deleted when xfrm_policy_destroy() is
> called. This is just to check if that really happened and to
> catch this bug if not. So it's not a bug fix, it just helps to
> catch a potential bug. I'll consider to take this into ipsec-next
> after some testing.
>

On the contrary, please take a look at callers of xfrm_policy_destroy.
Code flow is as below:

   xfrm_policy_alloc() /* setup timer/hold_timer here */ (1)

   /* do something with this policy, insert or something else */

   goto err; /* bail out if bad things happens */

   return ok

err:
   xfrm_policy_destroy() /*So both timers in (1) need to be deleted */

-- 
浮沉随浪只记今朝笑

--fan

^ permalink raw reply

* Re: [PATCH 1/3] af_packet: when sending ethernet frames, parse header for skb->protocol
From: David Miller @ 2013-08-02  1:12 UTC (permalink / raw)
  To: phil; +Cc: netdev
In-Reply-To: <20130801103509.GB27563@orbit.nwl.cc>

From: Phil Sutter <phil@nwl.cc>
Date: Thu, 1 Aug 2013 12:35:09 +0200

> Is it OK to rely on eth_type_trans() setting skb->dev after all?

Yes, it is.

^ permalink raw reply

* Re: minimum ICMPv6 message size vs. RPL's DIS
From: David Miller @ 2013-08-02  1:10 UTC (permalink / raw)
  To: hannes; +Cc: werner, netdev
In-Reply-To: <20130801054844.GC3688@order.stressinduktion.org>

From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Thu, 1 Aug 2013 07:48:44 +0200

> I would go ahead and post this as an offical patch submission now
> and let David Miller have a look.

FWIW I think this is a safe change.

^ permalink raw reply

* Re: linux-next: manual merge of the driver-core tree with the net-next tree
From: Greg KH @ 2013-08-02  0:28 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: linux-next, linux-kernel, Jiri Pirko, David Miller, netdev
In-Reply-To: <20130801152148.c98a281ec6e076646edeb7cb@canb.auug.org.au>

On Thu, Aug 01, 2013 at 03:21:48PM +1000, Stephen Rothwell wrote:
> Hi Greg,
> 
> Today's linux-next merge of the driver-core tree got a conflict in
> net/core/net-sysfs.c between commit ff80e519ab1b ("net: export physical
> port id via sysfs") from the net-next tree and commit 6be8aeef348a ("net:
> core: convert class code to use dev_groups") from the driver-core tree.
> 
> I fixed it up (see below) and can carry the fix as necessary (no action
> is required).

Looks good to me, thanks.

greg k-h

^ permalink raw reply

* Re: [PATCH] vlan: cleanup the usage of *vlan in vlan_dev_hard_header
From: David Miller @ 2013-08-02  0:12 UTC (permalink / raw)
  To: shhuiw; +Cc: kaber, netdev
In-Reply-To: <51FAF636.1090802@gmail.com>

From: Wang Sheng-Hui <shhuiw@gmail.com>
Date: Fri, 02 Aug 2013 07:58:46 +0800

> On 2013年08月02日 04:12, David Miller wrote:
>> From: Wang Sheng-Hui <shhuiw@gmail.com>
>> Date: Thu, 01 Aug 2013 14:10:23 +0800
>>
>>> We can use vlan directly after we get the pointer at the beginning
>>>      *vlan = vlan_dev_priv(dev)
>>> and do not use vlan_dev_priv(dev) to access its fields afterwards.
>>>
>>> Signed-off-by: Wang Sheng-Hui <shhuiw@gmail.com>
>>
>> This patch was corrupted by your email client.
>>
> 
> Sorry. Please recheck the patch below.

Please make a fresh patch posting, don't use a reply to this thread.

Thank you.

^ 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