Netdev List
 help / color / mirror / Atom feed
* [PATCH] sock.h: fix kernel-doc warning
From: Randy Dunlap @ 2010-05-25  5:22 UTC (permalink / raw)
  To: netdev, akpm; +Cc: davem

From: Randy Dunlap <randy.dunlap@oracle.com>

Fix sock.h kernel-doc warning:
Warning(include/net/sock.h:1438): No description found for parameter 'wq'

Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
---
 include/net/sock.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- lnx-2634-g8-kerndoc.orig/include/net/sock.h
+++ lnx-2634-g8-kerndoc/include/net/sock.h
@@ -1404,7 +1404,7 @@ static inline int sk_has_allocations(con
 
 /**
  * wq_has_sleeper - check if there are any waiting processes
- * @sk: struct socket_wq
+ * @wq: struct socket_wq
  *
  * Returns true if socket_wq has waiting processes
  *

^ permalink raw reply

* Re: linux-next: build failure after merge of the final tree
From: Herbert Xu @ 2010-05-25  5:14 UTC (permalink / raw)
  To: David Miller; +Cc: sfr, netdev, linux-next, linux-kernel
In-Reply-To: <20100524.215851.207470612.davem@davemloft.net>

On Mon, May 24, 2010 at 09:58:51PM -0700, David Miller wrote:
> 
> Herbert, can you take a look?

Sorry, I hadn't tested the built-in case.

cls_cgroup: Fix build error when built-in

There is a typo in cgroup_cls_state when cls_cgroup is built-in.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
index f9a0b01..4e75a1f 100644
--- a/include/net/cls_cgroup.h
+++ b/include/net/cls_cgroup.h
@@ -31,7 +31,7 @@ static inline u32 task_cls_classid(struct task_struct *p)
 		return 0;
 
 	return container_of(task_subsys_state(p, net_cls_subsys_id),
-			    struct cgroup_cls_state, css).classid;
+			    struct cgroup_cls_state, css)->classid;
 }
 #else
 extern int net_cls_subsys_id;

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

^ permalink raw reply related

* Re: linux-next: build failure after merge of the final tree
From: David Miller @ 2010-05-25  4:58 UTC (permalink / raw)
  To: sfr; +Cc: netdev, linux-next, linux-kernel, herbert
In-Reply-To: <20100525141046.975afe1f.sfr@canb.auug.org.au>

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 25 May 2010 14:10:46 +1000

> After merging the final tree, today's linux-next build (powerpc
> allyesconfig) failed like this:
> 
> In file included from net/socket.c:97:
> include/net/cls_cgroup.h: In function 'task_cls_classid':
> include/net/cls_cgroup.h:33: error: request for member 'classid' in something not a structure or union
> In file included from net/core/sock.c:126:
> include/net/cls_cgroup.h: In function 'task_cls_classid':
> include/net/cls_cgroup.h:33: error: request for member 'classid' in something not a structure or union
> In file included from net/sched/cls_cgroup.c:23:
> include/net/cls_cgroup.h: In function 'task_cls_classid':
> include/net/cls_cgroup.h:33: error: request for member 'classid' in something not a structure or union
> 
> CONFIG_CGROUPS=y, CONFIG_NET_CLS_CGROUP=y
> 
> Caused by commit f845172531fb7410c7fb7780b1a6e51ee6df7d52 ("cls_cgroup:
> Store classid in struct sock") from the net-current tree.
> 
> I have reverted that commit for today (and commit
> 8286274284e15b11b0f531b6ceeef21fbe00a8dd "tun: Update classid on packet
> injection" that depends on it).

Yuck, and we already went through two iterations of this patch fixing exactly
these kinds of build problems :-/

Herbert, can you take a look?

Thanks!

^ permalink raw reply

* Re: linux-next: build warning in Linus' tree
From: David Miller @ 2010-05-25  4:58 UTC (permalink / raw)
  To: sfr; +Cc: netdev, linux-next, linux-kernel, NeilJay
In-Reply-To: <20100525114614.fd61d822.sfr@canb.auug.org.au>

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 25 May 2010 11:46:14 +1000

> Hi Dave,
> 
> Today's linux-next build (x86_64 allmodconfig) produced this warning:
> 
> drivers/net/usb/asix.c: In function 'asix_rx_fixup':
> drivers/net/usb/asix.c:325: warning: cast from pointer to integer of different size
> drivers/net/usb/asix.c:354: warning: cast from pointer to integer of different size
> 
> Introduced by commit 3f78d1f210ff89af77f042ab7f4a8fee39feb1c9
> ("drivers/net/usb/asix.c: Fix unaligned accesses").  This commit casts
> skb->data to u32.

Thanks I'll look into this.

^ permalink raw reply

* linux-next: build failure after merge of the final tree
From: Stephen Rothwell @ 2010-05-25  4:10 UTC (permalink / raw)
  To: David Miller, netdev; +Cc: linux-next, linux-kernel, Herbert Xu

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

Hi Dave,

After merging the final tree, today's linux-next build (powerpc
allyesconfig) failed like this:

In file included from net/socket.c:97:
include/net/cls_cgroup.h: In function 'task_cls_classid':
include/net/cls_cgroup.h:33: error: request for member 'classid' in something not a structure or union
In file included from net/core/sock.c:126:
include/net/cls_cgroup.h: In function 'task_cls_classid':
include/net/cls_cgroup.h:33: error: request for member 'classid' in something not a structure or union
In file included from net/sched/cls_cgroup.c:23:
include/net/cls_cgroup.h: In function 'task_cls_classid':
include/net/cls_cgroup.h:33: error: request for member 'classid' in something not a structure or union

CONFIG_CGROUPS=y, CONFIG_NET_CLS_CGROUP=y

Caused by commit f845172531fb7410c7fb7780b1a6e51ee6df7d52 ("cls_cgroup:
Store classid in struct sock") from the net-current tree.

I have reverted that commit for today (and commit
8286274284e15b11b0f531b6ceeef21fbe00a8dd "tun: Update classid on packet
injection" that depends on it).
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

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

^ permalink raw reply

* Re: [PATCH] ipv4: Allow configuring subnets as local addresses
From: Stephen Hemminger @ 2010-05-25  3:29 UTC (permalink / raw)
  To: Tom Herbert; +Cc: davem, netdev
In-Reply-To: <alpine.DEB.1.00.1005232249380.18495@pokey.mtv.corp.google.com>

On Sun, 23 May 2010 22:54:12 -0700 (PDT)
Tom Herbert <therbert@google.com> wrote:

> This patch allows a host to be configured to respond to any address in
> a specified range as if it were local, without actually needing to
> configure the address on an interface.  This is done through routing
> table configuration.  For instance, to configure a host to respond
> to any address in 10.1/16 received on eth0 as a local address we can do:
> 
> ip rule add from all iif eth0 lookup 200
> ip route add local 10.1/16 dev lo proto kernel scope host src 127.0.0.1 table 200
> 
> This host is now reachable by any 10.1/16 address (route lookup on
> input for packets received on eth0 can find the route).  On output, the
> rule will not be matched so that this host can still send packets to
> 10.1/16 (not sent on loopback).  Presumably, external routing can be
> configured to make sense out of this.
> 
> To make this work, we needed to modify the logic in finding the
> interface which is assigned a given source address for output
> (dev_ip_find).  We perform a normal fib_lookup instead of just a
> lookup on the local table, and in the lookup we ignore the input
> interface for matching.
> 
> This patch is useful to implement IP-anycast for subnets of virtual
> addresses.
> 
> Signed-off-by: Tom Herbert <therbert@google.com>

It makes sense, no sure what else will break because of this.
This won't work so well with routing daemons like Quagga(BGP, Zebra)
etc because they believe loopback is special but they don't
handle multiple routing tables well anyway.

^ permalink raw reply

* [PATCH 2/2] rtl8192su: Fix procfs code for interfaces not named wlan0
From: Ben Hutchings @ 2010-05-25  3:25 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: devel, netdev
In-Reply-To: <1274757630.7908.12.camel@localhost>

The current code creates directories in procfs named after interfaces,
but doesn't handle renaming.  This can result in name collisions and
consequent WARNINGs.  It also means that the interface name cannot
reliably be used to remove the directory - in fact the current code
doesn't even try, and always uses "wlan0"!

Since the name of a proc_dir_entry is embedded in it, use that when
removing it.

Add a netdev notifier to catch interface renaming, and remove and
re-add the directory at this point.

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
This is compile-tested only.

All this procfs crap should really be replaced - stats should be exposed
through the proper wireless stats interface and registers through
debugfs or not at all.  But for now let's patch it up to avoid the
WARNING.

Ben.

 drivers/staging/rtl8192su/r8192U_core.c |   35 ++++++++++++++++++++++++++++--
 1 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index 90f2df4..4bd3710 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -27,6 +27,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/eeprom_93cx6.h>
+#include <linux/notifier.h>
 
 #undef LOOP_TEST
 #undef DUMP_RX
@@ -161,6 +162,8 @@ MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI");
 static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id);
 static void __devexit rtl8192_usb_disconnect(struct usb_interface *intf);
+static const struct net_device_ops rtl8192_netdev_ops;
+static struct notifier_block proc_netdev_notifier;
 
 static struct usb_driver rtl8192_usb_driver = {
 	.name		= RTL819xU_MODULE_NAME,	          /* Driver name   */
@@ -992,14 +995,22 @@ static int proc_get_stats_rx(char *page, char **start,
 
 int rtl8192_proc_module_init(void)
 {
+	int ret;
+
 	RT_TRACE(COMP_INIT, "Initializing proc filesystem");
 	rtl8192_proc=create_proc_entry(RTL819xU_MODULE_NAME, S_IFDIR, init_net.proc_net);
-	return rtl8192_proc ? 0 : -ENOMEM;
+	if (!rtl8192_proc)
+		return -ENOMEM;
+	ret = register_netdevice_notifier(&proc_netdev_notifier);
+	if (ret)
+		remove_proc_entry(RTL819xU_MODULE_NAME, init_net.proc_net);
+	return ret;
 }
 

 void rtl8192_proc_module_remove(void)
 {
+	unregister_netdevice_notifier(&proc_netdev_notifier);
 	remove_proc_entry(RTL819xU_MODULE_NAME, init_net.proc_net);
 }
 
@@ -1027,8 +1038,7 @@ void rtl8192_proc_remove_one(struct net_device *dev)
 		remove_proc_entry("registers-e", priv->dir_dev);
 	//	remove_proc_entry("cck-registers",priv->dir_dev);
 	//	remove_proc_entry("ofdm-registers",priv->dir_dev);
-		//remove_proc_entry(dev->name, rtl8192_proc);
-		remove_proc_entry("wlan0", rtl8192_proc);
+		remove_proc_entry(priv->dir_dev->name, rtl8192_proc);
 		priv->dir_dev = NULL;
 	}
 }
@@ -1145,6 +1155,25 @@ void rtl8192_proc_init_one(struct net_device *dev)
 		      dev->name);
 	}
 }
+
+static int proc_netdev_event(struct notifier_block *this,
+			     unsigned long event, void *ptr)
+{
+	struct net_device *net_dev = ptr;
+
+	if (net_dev->netdev_ops == &rtl8192_netdev_ops &&
+	    event == NETDEV_CHANGENAME) {
+		rtl8192_proc_remove_one(net_dev);
+		rtl8192_proc_init_one(net_dev);
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block proc_netdev_notifier = {
+	.notifier_call = proc_netdev_event,
+};
+
 /****************************************************************************
    -----------------------------MISC STUFF-------------------------
 *****************************************************************************/
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH] ipv4: Allow configuring subnets as local addresses
From: Mark Smith @ 2010-05-24 21:43 UTC (permalink / raw)
  To: Tom Herbert; +Cc: davem, netdev
In-Reply-To: <alpine.DEB.1.00.1005232249380.18495@pokey.mtv.corp.google.com>

Hi Tom,

On Sun, 23 May 2010 22:54:12 -0700 (PDT)
Tom Herbert <therbert@google.com> wrote:

> This patch allows a host to be configured to respond to any address in
> a specified range as if it were local, without actually needing to
> configure the address on an interface.  This is done through routing
> table configuration.  For instance, to configure a host to respond
> to any address in 10.1/16 received on eth0 as a local address we can do:
> 
> ip rule add from all iif eth0 lookup 200
> ip route add local 10.1/16 dev lo proto kernel scope host src 127.0.0.1 table 200
> 
> This host is now reachable by any 10.1/16 address (route lookup on
> input for packets received on eth0 can find the route).  On output, the
> rule will not be matched so that this host can still send packets to
> 10.1/16 (not sent on loopback).  Presumably, external routing can be
> configured to make sense out of this.
> 

I'd be careful about making that assumption. IIRC, a very popular
router vendor's IP implementation treats 'connected' routes fairly
specially, and won't let you create a static route that covers a subset
of connected addresses with a next hop. IOW, connected routes,
regardless of their prefix length, win over the longest match rule, and
can't have their preference lowered. I think I got around it by
assigning a /32 to the interface, and having a static route for the
rest of the local address space pointing out the interface. It was
mostly a bit of an experiment, and probably quite unobvious to most
people if they saw it in production. I probably wouldn't want to do it
that way for that reason.

The more traditional way to have a host support multiple addresses is
to have a static route towards it for address space that is different
to what is assigned to the link between the host and the router. e.g.
[router].1-- 172.16.0/24--.2[host][10.1/16], possibly with 10.1/16
addresses assigned to (the|a) loopback or dummy interface. Would your
code work in this scenario?

Regards,
Mark.


> To make this work, we needed to modify the logic in finding the
> interface which is assigned a given source address for output
> (dev_ip_find).  We perform a normal fib_lookup instead of just a
> lookup on the local table, and in the lookup we ignore the input
> interface for matching.
> 
> This patch is useful to implement IP-anycast for subnets of virtual
> addresses.
> 
> Signed-off-by: Tom Herbert <therbert@google.com>
> ---
> diff --git a/include/net/flow.h b/include/net/flow.h
> index bb08692..0ac3fb5 100644
> --- a/include/net/flow.h
> +++ b/include/net/flow.h
> @@ -49,6 +49,7 @@ struct flowi {
>  	__u8	proto;
>  	__u8	flags;
>  #define FLOWI_FLAG_ANYSRC 0x01
> +#define FLOWI_FLAG_MATCH_ANY_IIF 0x02
>  	union {
>  		struct {
>  			__be16	sport;
> diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
> index 42e84e0..f6e18b2 100644
> --- a/net/core/fib_rules.c
> +++ b/net/core/fib_rules.c
> @@ -182,7 +182,8 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
>  {
>  	int ret = 0;
>  
> -	if (rule->iifindex && (rule->iifindex != fl->iif))
> +	if (rule->iifindex && (rule->iifindex != fl->iif) &&
> +	    !(fl->flags & FLOWI_FLAG_MATCH_ANY_IIF))
>  		goto out;
>  
>  	if (rule->oifindex && (rule->oifindex != fl->oif))
> diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
> index 4f0ed45..64f953e 100644
> --- a/net/ipv4/fib_frontend.c
> +++ b/net/ipv4/fib_frontend.c
> @@ -153,17 +153,16 @@ static void fib_flush(struct net *net)
>  
>  struct net_device * ip_dev_find(struct net *net, __be32 addr)
>  {
> -	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
> +	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } },
> +			    .flags = FLOWI_FLAG_MATCH_ANY_IIF };
>  	struct fib_result res;
>  	struct net_device *dev = NULL;
> -	struct fib_table *local_table;
>  
>  #ifdef CONFIG_IP_MULTIPLE_TABLES
>  	res.r = NULL;
>  #endif
>  
> -	local_table = fib_get_table(net, RT_TABLE_LOCAL);
> -	if (!local_table || fib_table_lookup(local_table, &fl, &res))
> +	if (fib_lookup(net, &fl, &res))
>  		return NULL;
>  	if (res.type != RTN_LOCAL)
>  		goto out;
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* NULL Pointer Deference: NFS & Telnet
From: Arce, Abraham @ 2010-05-25  2:19 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-nfs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Hi,

I have 2 scenarios in which I am getting a NULL pointer dereference:

1) root filesystem over nfs
2) telnet connection

The issue appeared on this commit

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f8965467f366fd18f01feafb5db10512d7b4422c

The driver I am working with is drivers/net/ks8851.c
Any help will be highly appreciated...

---

Scenario 1 | root filesystem over nfs

Looking up port of RPC 100005/1 on 10.87.231.229
VFS: Mounted root (nfs filesystem) on device 0:10.
Freeing init memory: 128K
Unable to handle kernel NULL pointer dereference at virtual address 00000000
[..]
PC is at put_page+0xc/0x120
LR is at skb_release_data+0x74/0xb8
[..]
Backtrace:
[<c0086dd0>] (put_page+0x0/0x120)
[<c01d0a48>] (skb_release_data+0x0/0xb8)
[<c01d1044>] (skb_release_all+0x0/0x20)
[<c01d075c>] (__kfree_skb+0x0/0xbc)
[<c01d0818>] (consume_skb+0x0/0x58)
[<c01d39cc>] (skb_free_datagram+0x0/0x40)
[<c023ff74>] (xs_udp_data_ready+0x0/0x1e8)
[<c01ce034>] (sock_queue_rcv_skb+0x0/0x1c0)
[<c01fbba8>] (ip_queue_rcv_skb+0x0/0x58)
[<c02176c0>] (__udp_queue_rcv_skb+0x0/0x18c)
[<c0218e28>] (udp_queue_rcv_skb+0x0/0x348)
[<c02195a4>] (__udp4_lib_rcv+0x0/0x564)
[<c0219b08>] (udp_rcv+0x0/0x20)
[<c01f5f34>] (ip_local_deliver+0x0/0x264)
[<c01f586c>] (ip_rcv+0x0/0x6c8)
[<c01d7ec0>] (__netif_receive_skb+0x0/0x2d0)
[<c01d8190>] (process_backlog+0x0/0x16c)
[<c01d8e14>] (net_rx_action+0x0/0x18c)
[<c00521a0>] (__do_softirq+0x0/0x12c)
[<c00522cc>] (irq_exit+0x0/0x70)
[<c0028000>] (asm_do_IRQ+0x0/0xc8)

Complete log at http://pastebin.mozilla.org/728027

---

Scenario 2

 1. Root filesystem booted in ram
 2. eth0 brought up
 3. telnetd daemon started
 4. tried to connect through telnet

# Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = d98e8000
[..]
PC is at put_page+0xc/0x120
LR is at skb_release_data+0x74/0xb8
[..]
Backtrace:
[<c0086dd0>] (put_page+0x0/0x120)
[<c01d0a48>] (skb_release_data+0x0/0xb8)
[<c01d1044>] (skb_release_all+0x0/0x20)
[<c01d075c>] (__kfree_skb+0x0/0xbc)
[<c0202444>] (tcp_recvmsg+0x0/0x93c)
[<c02201e8>] (inet_recvmsg+0x0/0xec)
[<c01c7fd0>] (sock_aio_read+0x0/0xf8)
[<c00ab3ac>] (do_sync_read+0x0/0xec)
[<c00abfbc>] (vfs_read+0x0/0x164)
[<c00ac1a0>] (sys_read+0x0/0x70)
[<c0029100>] (ret_fast_syscall+0x0/0x30)

Complete log at http://pastebin.mozilla.org/728028

Best Regards
Abraham Arce
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* linux-next: build warning in Linus'  tree
From: Stephen Rothwell @ 2010-05-25  1:46 UTC (permalink / raw)
  To: David Miller, netdev; +Cc: linux-next, linux-kernel, Neil Jones

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

Hi Dave,

Today's linux-next build (x86_64 allmodconfig) produced this warning:

drivers/net/usb/asix.c: In function 'asix_rx_fixup':
drivers/net/usb/asix.c:325: warning: cast from pointer to integer of different size
drivers/net/usb/asix.c:354: warning: cast from pointer to integer of different size

Introduced by commit 3f78d1f210ff89af77f042ab7f4a8fee39feb1c9
("drivers/net/usb/asix.c: Fix unaligned accesses").  This commit casts
skb->data to u32.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

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

^ permalink raw reply

* Re: [PATCH net-2.6] macvlan: do a proper cleanup in macvlan_common_newlink()
From: David Miller @ 2010-05-25  1:41 UTC (permalink / raw)
  To: kaber; +Cc: jpirko, netdev
In-Reply-To: <4BFACBE0.4020109@trash.net>

From: Patrick McHardy <kaber@trash.net>
Date: Mon, 24 May 2010 20:56:32 +0200

> Jiri Pirko wrote:
>> Mon, May 24, 2010 at 05:58:58PM CEST, jpirko@
>> Subject: [PATCH net-2.6] macvlan: do proper cleanup in macvlan_common_newlink() V2
>> 
>> Fixes possible memory leak.
> 
> Looks good, thanks.
> 
>> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> 
> Acked-by: Patrick McHardy <kaber@trash.net>

Applied, thanks.

^ permalink raw reply

* Re: [PATCH net-2.6] be2net: Bug fix in init code in probe
From: David Miller @ 2010-05-25  1:39 UTC (permalink / raw)
  To: sarveshwarb; +Cc: netdev
In-Reply-To: <20100524112033.GA3666@serverengines.com>

From: Sarveshwar Bandi <sarveshwarb@serverengines.com>
Date: Mon, 24 May 2010 16:50:47 +0530

> PCI function reset needs to invoked after fw init ioctl is issued.
> 
> Signed-off-by: Sarveshwar Bandi <sarveshwarb@serverengines.com>

Applied, thanks.

^ permalink raw reply

* Re: net/dccp: expansion of error code size
From: David Miller @ 2010-05-25  1:37 UTC (permalink / raw)
  To: yuasa; +Cc: linux-mips, netdev
In-Reply-To: <20100524154508.10a40589.yuasa@linux-mips.org>

From: Yoichi Yuasa <yuasa@linux-mips.org>
Date: Mon, 24 May 2010 15:45:08 +0900

> Because MIPS's EDQUOT value is 1133(0x46d).
> It's larger than u8.
> 
> Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>

Applied, thank you.

^ permalink raw reply

* Re: [PATCH] ipvs: Add missing locking during connection table hashing and unhashing
From: Simon Horman @ 2010-05-24 23:56 UTC (permalink / raw)
  To: Sven Wegener; +Cc: Julian Anastasov, Wensong Zhang, netdev, lvs-devel
In-Reply-To: <alpine.LNX.2.00.1005202243480.22717@titan.stealer.net>

On Thu, May 20, 2010 at 10:55:32PM +0200, Sven Wegener wrote:
> The code that hashes and unhashes connections from the connection table
> is missing locking of the connection being modified, which opens up a
> race condition and results in memory corruption when this race condition
> is hit.
> 
> Here is what happens in pretty verbose form:
> 
> CPU 0					CPU 1
> ------------				------------
> An active connection is terminated and
> we schedule ip_vs_conn_expire() on this
> CPU to expire this connection.
> 
> 					IRQ assignment is changed to this CPU,
> 					but the expire timer stays scheduled on
> 					the other CPU.
> 
> 					New connection from same ip:port comes
> 					in right before the timer expires, we
> 					find the inactive connection in our
> 					connection table and get a reference to
> 					it. We proper lock the connection in
> 					tcp_state_transition() and read the
> 					connection flags in set_tcp_state().
> 
> ip_vs_conn_expire() gets called, we
> unhash the connection from our
> connection table and remove the hashed
> flag in ip_vs_conn_unhash(), without
> proper locking!
> 
> 					While still holding proper locks we
> 					write the connection flags in
> 					set_tcp_state() and this sets the hashed
> 					flag again.
> 
> ip_vs_conn_expire() fails to expire the
> connection, because the other CPU has
> incremented the reference count. We try
> to re-insert the connection into our
> connection table, but this fails in
> ip_vs_conn_hash(), because the hashed
> flag has been set by the other CPU. We
> re-schedule execution of
> ip_vs_conn_expire(). Now this connection
> has the hashed flag set, but isn't
> actually hashed in our connection table
> and has a dangling list_head.
> 
> 					We drop the reference we held on the
> 					connection and schedule the expire timer
> 					for timeouting the connection on this
> 					CPU. Further packets won't be able to
> 					find this connection in our connection
> 					table.
> 
> 					ip_vs_conn_expire() gets called again,
> 					we think it's already hashed, but the
> 					list_head is dangling and while removing
> 					the connection from our connection table
> 					we write to the memory location where
> 					this list_head points to.
> 
> The result will probably be a kernel oops at some other point in time.

Nice analysis.

> Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
> Cc: stable@kernel.org

Acked-by: Simon Horman <horms@verge.net.au>

> ---
>  net/netfilter/ipvs/ip_vs_conn.c |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)
> 
> This race condition is pretty subtle, but it can be triggered remotely.
> It needs the IRQ assignment change or another circumstance where packets
> coming from the same ip:port for the same service are being processed on
> different CPUs. And it involves hitting the exact time at which
> ip_vs_conn_expire() gets called. It can be avoided by making sure that
> all packets from one connection are always processed on the same CPU and
> can be made harder to exploit by changing the connection timeouts to
> some custom values.
> 
> diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
> index d8f7e8e..ff04e9e 100644
> --- a/net/netfilter/ipvs/ip_vs_conn.c
> +++ b/net/netfilter/ipvs/ip_vs_conn.c
> @@ -162,6 +162,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
>  	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
>  
>  	ct_write_lock(hash);
> +	spin_lock(&cp->lock);
>  
>  	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
>  		list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
> @@ -174,6 +175,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
>  		ret = 0;
>  	}
>  
> +	spin_unlock(&cp->lock);
>  	ct_write_unlock(hash);
>  
>  	return ret;
> @@ -193,6 +195,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
>  	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
>  
>  	ct_write_lock(hash);
> +	spin_lock(&cp->lock);
>  
>  	if (cp->flags & IP_VS_CONN_F_HASHED) {
>  		list_del(&cp->c_list);
> @@ -202,6 +205,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
>  	} else
>  		ret = 0;
>  
> +	spin_unlock(&cp->lock);
>  	ct_write_unlock(hash);
>  
>  	return ret;

^ permalink raw reply

* [PATCH 2/2] qlcnic: NIC Partitioning - non privileged mode
From: Anirban Chakraborty @ 2010-05-24 23:48 UTC (permalink / raw)
  To: David Miller, netdev@vger.kernel.org; +Cc: Ameen Rahman, Amit Salecha


Added support for non privileged mode of npar functions.
Bumped up version number to 5.0.3.

Please apply.
thanks,
Anirban


Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h      |   13 +---
 drivers/net/qlcnic/qlcnic_hdr.h  |   14 +++--
 drivers/net/qlcnic/qlcnic_main.c |  124 +++++++++++++++++++++++++++++++++++---
 3 files changed, 128 insertions(+), 23 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 31a0b43..02db363 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -51,8 +51,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 2
-#define QLCNIC_LINUX_VERSIONID  "5.0.2"
+#define _QLCNIC_LINUX_SUBVERSION 3
+#define QLCNIC_LINUX_VERSIONID  "5.0.3"
 #define QLCNIC_DRV_IDC_VER  0x01
 
 #define QLCNIC_VERSION_CODE(a, b, c)	(((a) << 24) + ((b) << 16) + (c))
@@ -891,6 +891,7 @@ struct qlcnic_mac_req {
 #define QLCNIC_LRO_ENABLED		0x08
 #define QLCNIC_BRIDGE_ENABLED       	0X10
 #define QLCNIC_DIAG_ENABLED		0x20
+#define QLCNIC_NPAR_ENABLED		0x40
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
 	((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
@@ -1159,13 +1160,6 @@ int qlcnic_check_loopback_buff(unsigned char *data);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
 
-/* Functions from qlcnic_vf.c */
-int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
-int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
-int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter);
-void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter);
-void qlcnicvf_set_port_mode(struct qlcnic_adapter *adapter);
-
 /* Management functions */
 int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
 int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
@@ -1234,6 +1228,7 @@ struct qlcnic_nic_template {
 	int (*config_led) (struct qlcnic_adapter *, u32, u32);
 	int (*set_ilb_mode) (struct qlcnic_adapter *);
 	void (*clear_ilb_mode) (struct qlcnic_adapter *);
+	int (*start_firmware) (struct qlcnic_adapter *);
 };
 
 #define QLCDB(adapter, lvl, _fmt, _args...) do {	\
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index 1bcfb12..7b81cab 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -701,10 +701,11 @@ enum {
 #define QLCNIC_CRB_DEV_REF_COUNT	(QLCNIC_CAM_RAM(0x138))
 #define QLCNIC_CRB_DEV_STATE		(QLCNIC_CAM_RAM(0x140))
 
-#define QLCNIC_CRB_DRV_STATE               (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH             (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO      (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_STATE		(QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH		(QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO	(QLCNIC_CAM_RAM(0x14c))
 #define QLCNIC_CRB_DRV_IDC_VER		(QLCNIC_CAM_RAM(0x174))
+#define QLCNIC_CRB_DEV_NPAR_STATE	(QLCNIC_CAM_RAM(0x19c))
 #define QLCNIC_ROM_DEV_INIT_TIMEOUT	(0x3e885c)
 #define QLCNIC_ROM_DRV_RESET_TIMEOUT	(0x3e8860)
 
@@ -717,6 +718,9 @@ enum {
 #define QLCNIC_DEV_FAILED		0x6
 #define QLCNIC_DEV_QUISCENT		0x7
 
+#define QLCNIC_DEV_NPAR_NOT_RDY	0
+#define QLCNIC_DEV_NPAR_RDY		1
+
 #define QLC_DEV_CHECK_ACTIVE(VAL, FN)		((VAL) &= (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)		((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)		((VAL) &= ~(1 << (FN * 4)))
@@ -732,8 +736,8 @@ enum {
 #define QLCNIC_TYPE_ISCSI		3
 
 #define QLCNIC_RCODE_DRIVER_INFO		0x20000000
-#define QLCNIC_RCODE_DRIVER_CAN_RELOAD		0x40000000
-#define QLCNIC_RCODE_FATAL_ERROR		0x80000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD		BIT_30
+#define QLCNIC_RCODE_FATAL_ERROR		BIT_31
 #define QLCNIC_FWERROR_PEGNUM(code)		((code) & 0xff)
 #define QLCNIC_FWERROR_CODE(code)		((code >> 8) & 0xfffff)
 
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 3b4fdb3..9a1b60f 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -103,7 +103,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data);
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
 static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
-
+static int qlcnic_start_firmware(struct qlcnic_adapter *);
+
+static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
+static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
 	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -375,7 +382,8 @@ static struct qlcnic_nic_template qlcnic_ops = {
 	.config_bridged_mode = qlcnic_config_bridged_mode,
 	.config_led = qlcnic_config_led,
 	.set_ilb_mode = qlcnic_set_ilb_mode,
-	.clear_ilb_mode = qlcnic_clear_ilb_mode
+	.clear_ilb_mode = qlcnic_clear_ilb_mode,
+	.start_firmware = qlcnic_start_firmware
 };
 
 static struct qlcnic_nic_template qlcnic_pf_ops = {
@@ -383,7 +391,17 @@ static struct qlcnic_nic_template qlcnic_pf_ops = {
 	.config_bridged_mode = qlcnic_config_bridged_mode,
 	.config_led = qlcnic_config_led,
 	.set_ilb_mode = qlcnic_set_ilb_mode,
-	.clear_ilb_mode = qlcnic_clear_ilb_mode
+	.clear_ilb_mode = qlcnic_clear_ilb_mode,
+	.start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_vf_ops = {
+	.get_mac_addr = qlcnic_get_mac_address,
+	.config_bridged_mode = qlcnicvf_config_bridged_mode,
+	.config_led = qlcnicvf_config_led,
+	.set_ilb_mode = qlcnicvf_set_ilb_mode,
+	.clear_ilb_mode = qlcnicvf_clear_ilb_mode,
+	.start_firmware = qlcnicvf_start_firmware
 };
 
 static void
@@ -467,7 +485,6 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
 		iounmap(adapter->ahw.pci_base0);
 }
 
-/* Use api lock to access this function */
 static int
 qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 {
@@ -567,6 +584,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 		/* Set privilege level for other functions */
 		if (qlcnic_config_npars)
 			qlcnic_set_function_modes(adapter);
+		qlcnic_dev_set_npar_ready(adapter);
 		dev_info(&adapter->pdev->dev,
 			"HAL Version: %d, Management function\n",
 			adapter->fw_hal_version);
@@ -578,6 +596,13 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 			adapter->fw_hal_version);
 		adapter->nic_ops = &qlcnic_pf_ops;
 		break;
+	case QLCNIC_NON_PRIV_FUNC:
+		adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+		dev_info(&adapter->pdev->dev,
+			"HAL Version: %d Non Privileged function\n",
+			adapter->fw_hal_version);
+		adapter->nic_ops = &qlcnic_vf_ops;
+		break;
 	default:
 		dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
 			priv_level);
@@ -772,6 +797,8 @@ wait_init:
 	QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
 	qlcnic_idc_debug_info(adapter, 1);
 
+	qlcnic_dev_set_npar_ready(adapter);
+
 	qlcnic_check_options(adapter);
 
 	if (adapter->fw_hal_version != QLCNIC_FW_BASE &&
@@ -1244,7 +1271,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (qlcnic_setup_idc_param(adapter))
 		goto err_out_iounmap;
 
-	err = qlcnic_start_firmware(adapter);
+	err = adapter->nic_ops->start_firmware(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
 		goto err_out_decr_ref;
@@ -1410,7 +1437,7 @@ qlcnic_resume(struct pci_dev *pdev)
 	pci_set_master(pdev);
 	pci_restore_state(pdev);
 
-	err = qlcnic_start_firmware(adapter);
+	err = adapter->nic_ops->start_firmware(adapter);
 	if (err) {
 		dev_err(&pdev->dev, "failed to start firmware\n");
 		return err;
@@ -2260,7 +2287,7 @@ qlcnic_fwinit_work(struct work_struct *work)
 {
 	struct qlcnic_adapter *adapter = container_of(work,
 			struct qlcnic_adapter, fw_work.work);
-	u32 dev_state = 0xf;
+	u32 dev_state = 0xf, npar_state;
 
 	if (qlcnic_api_lock(adapter))
 		goto err_ret;
@@ -2273,6 +2300,19 @@ qlcnic_fwinit_work(struct work_struct *work)
 		return;
 	}
 
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+		npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+		if (npar_state == QLCNIC_DEV_NPAR_RDY) {
+			qlcnic_api_unlock(adapter);
+			goto wait_npar;
+		} else {
+			qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+				FW_POLL_DELAY);
+			qlcnic_api_unlock(adapter);
+			return;
+		}
+	}
+
 	if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
 		dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
 					adapter->reset_ack_timeo);
@@ -2305,7 +2345,7 @@ skip_ack_check:
 
 		qlcnic_api_unlock(adapter);
 
-		if (!qlcnic_start_firmware(adapter)) {
+		if (!adapter->nic_ops->start_firmware(adapter)) {
 			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
 			return;
 		}
@@ -2314,6 +2354,7 @@ skip_ack_check:
 
 	qlcnic_api_unlock(adapter);
 
+wait_npar:
 	dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 	QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
@@ -2328,7 +2369,7 @@ skip_ack_check:
 		break;
 
 	default:
-		if (!qlcnic_start_firmware(adapter)) {
+		if (!adapter->nic_ops->start_firmware(adapter)) {
 			qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
 			return;
 		}
@@ -2402,6 +2443,30 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 	qlcnic_api_unlock(adapter);
 }
 
+/* Transit to NPAR READY state from NPAR NOT READY state */
+static void
+qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
+{
+	u32 state;
+
+	if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC ||
+		adapter->fw_hal_version == QLCNIC_FW_BASE)
+		return;
+
+	if (qlcnic_api_lock(adapter))
+		return;
+
+	state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+
+	if (state != QLCNIC_DEV_NPAR_RDY) {
+		QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+			QLCNIC_DEV_NPAR_RDY);
+		QLCDB(adapter, DRV, "NPAR READY state set\n");
+	}
+
+	qlcnic_api_unlock(adapter);
+}
+
 static void
 qlcnic_schedule_work(struct qlcnic_adapter *adapter,
 		work_func_t func, int delay)
@@ -2885,6 +2950,47 @@ done:
 	return NOTIFY_DONE;
 }
 
+static int
+qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
+{
+	int err;
+
+	err = qlcnic_can_start_firmware(adapter);
+	if (err)
+		return err;
+
+	qlcnic_check_options(adapter);
+
+	adapter->need_fw_reset = 0;
+
+	return err;
+}
+
+static int
+qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+	return -EOPNOTSUPP;
+}
+
+static void
+qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+	return;
+}
+
+
 static struct notifier_block	qlcnic_netdev_cb = {
 	.notifier_call = qlcnic_netdev_event,
 };
-- 
1.6.0.2


^ permalink raw reply related

* [PATCH 1/2] qlcnic: NIC Partitioning
From: Anirban Chakraborty @ 2010-05-24 23:48 UTC (permalink / raw)
  To: David Miller, netdev@vger.kernel.org; +Cc: Amit Salecha, Ameen Rahman

Following changes have been added to enable the adapter to work in
NIC partitioning mode where multiple PCI functions of an adapter port can
be configured to work as NIC functions. The first function that is enumerated on
the PCI bus assumes the role of management function which, besides being able
to do all the NIC functionality, can configure other NIC partitions. Other NIC
functions can be configured as privileged or non privileged functions.
Privileged function can not configure other NIC functions but can do all the
NIC functionality including any firmware initialization, chip reset etc. Non
privileged functions can do only basic IO. For chip reset etc, it depends on the 
privilege or management function.

1. Added code to determine PCI function number independent of kernel API.
2. Added Driver - FW version 2.0 support.
3. Changed producer and consumer register offset calculation.
4. Added management and privileged operation modes for npar functions. A module
   parameter has been added to control it.
6. Added support for configuring the eswitch in the adapter.

Please apply.
thanks,
Anirban

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h         |  121 ++++++++-
 drivers/net/qlcnic/qlcnic_ctx.c     |  513 +++++++++++++++++++++++++++++++++--
 drivers/net/qlcnic/qlcnic_ethtool.c |   11 +-
 drivers/net/qlcnic/qlcnic_hdr.h     |   70 +++++
 drivers/net/qlcnic/qlcnic_hw.c      |   14 +-
 drivers/net/qlcnic/qlcnic_init.c    |   40 ++-
 drivers/net/qlcnic/qlcnic_main.c    |  195 ++++++++++++--
 7 files changed, 890 insertions(+), 74 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 896d40d..31a0b43 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -197,8 +197,7 @@ struct cmd_desc_type0 {

        __le64 addr_buffer4;

-       __le32 reserved2;
-       __le16 reserved;
+       u8 eth_addr[ETH_ALEN];
        __le16 vlan_TCI;

 } __attribute__ ((aligned(64)));
@@ -315,6 +314,8 @@ struct uni_data_desc{
 #define QLCNIC_BRDTYPE_P3_10G_XFP      0x0032
 #define QLCNIC_BRDTYPE_P3_10G_TP       0x0080

+#define QLCNIC_MSIX_TABLE_OFFSET       0x44
+
 /* Flash memory map */
 #define QLCNIC_BRDCFG_START    0x4000          /* board config */
 #define QLCNIC_BOOTLD_START    0x10000         /* bootld */
@@ -542,7 +543,17 @@ struct qlcnic_recv_context {
 #define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS   0x0000001c
 #define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES   0x0000001d
 #define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e
-#define QLCNIC_CDRP_CMD_MAX                    0x0000001f
+#define QLCNIC_CDRP_CMD_MAC_ADDRESS            0x0000001f
+
+#define QLCNIC_CDRP_CMD_GET_PCI_INFO           0x00000020
+#define QLCNIC_CDRP_CMD_GET_NIC_INFO           0x00000021
+#define QLCNIC_CDRP_CMD_SET_NIC_INFO           0x00000022
+#define QLCNIC_CDRP_CMD_RESET_NPAR             0x00000023
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024
+#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH         0x00000025
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS     0x00000026
+#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING      0x00000027
+#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH      0x00000028

 #define QLCNIC_RCODE_SUCCESS           0
 #define QLCNIC_RCODE_TIMEOUT           17
@@ -560,7 +571,6 @@ struct qlcnic_recv_context {
 /*
  * Context state
  */
-#define QLCHAL_VERSION 1

 #define QLCNIC_HOST_CTX_STATE_ACTIVE   2

@@ -887,6 +897,7 @@ struct qlcnic_mac_req {
 #define MSIX_ENTRIES_PER_ADAPTER       NUM_STS_DESC_RINGS
 #define QLCNIC_MSIX_TBL_SPACE          8192
 #define QLCNIC_PCI_REG_MSIX_TBL        0x44
+#define QLCNIC_MSIX_TBL_PGSIZE         4096

 #define QLCNIC_NETDEV_WEIGHT   128
 #define QLCNIC_ADAPTER_UP_MAGIC 777
@@ -923,7 +934,6 @@ struct qlcnic_adapter {
        u8 mc_enabled;
        u8 max_mc_count;
        u8 rss_supported;
-       u8 rsrvd1;
        u8 fw_wait_cnt;
        u8 fw_fail_cnt;
        u8 tx_timeo_cnt;
@@ -940,6 +950,15 @@ struct qlcnic_adapter {
        u16 link_autoneg;
        u16 module_type;

+       u16 op_mode;
+       u16 switch_mode;
+       u16 max_tx_ques;
+       u16 max_rx_ques;
+       u16 min_tx_bw;
+       u16 max_tx_bw;
+       u16 max_mtu;
+
+       u32 fw_hal_version;
        u32 capabilities;
        u32 flags;
        u32 irq;
@@ -948,18 +967,22 @@ struct qlcnic_adapter {
        u32 int_vec_bit;
        u32 heartbit;

+       u8 max_mac_filters;
        u8 dev_state;
        u8 diag_test;
        u8 diag_cnt;
        u8 reset_ack_timeo;
        u8 dev_init_timeo;
-       u8 rsrd1;
        u16 msg_enable;

        u8 mac_addr[ETH_ALEN];

        u64 dev_rst_time;

+       struct qlcnic_pci_info *npars;
+       struct qlcnic_eswitch *eswitch;
+       struct qlcnic_nic_template *nic_ops;
+
        struct qlcnic_adapter_stats stats;

        struct qlcnic_recv_context recv_ctx;
@@ -984,6 +1007,53 @@ struct qlcnic_adapter {
        const struct firmware *fw;
 };

+struct qlcnic_info {
+       __le16  pci_func;
+       __le16  op_mode; /* 1 = Priv, 2 = NP, 3 = NP passthru */
+       __le16  phys_port;
+       __le16  switch_mode; /* 0 = disabled, 1 = int, 2 = ext */
+
+       __le32  capabilities;
+       u8      max_mac_filters;
+       u8      reserved1;
+       __le16  max_mtu;
+
+       __le16  max_tx_ques;
+       __le16  max_rx_ques;
+       __le16  min_tx_bw;
+       __le16  max_tx_bw;
+       u8      reserved2[104];
+};
+
+struct qlcnic_pci_info {
+       __le16  id; /* pci function id */
+       __le16  active; /* 1 = Enabled */
+       __le16  type; /* 1 = NIC, 2 = FCoE, 3 = iSCSI */
+       __le16  default_port; /* default port number */
+
+       __le16  tx_min_bw; /* Multiple of 100mbpc */
+       __le16  tx_max_bw;
+       __le16  reserved1[2];
+
+       u8      mac[ETH_ALEN];
+       u8      reserved2[106];
+};
+
+struct qlcnic_eswitch {
+       u8      port;
+       u8      active_vports;
+       u8      active_vlans;
+       u8      active_ucast_filters;
+       u8      max_ucast_filters;
+       u8      max_active_vlans;
+
+       u32     flags;
+#define QLCNIC_SWITCH_ENABLE           BIT_1
+#define QLCNIC_SWITCH_VLAN_FILTERING   BIT_2
+#define QLCNIC_SWITCH_PROMISC_MODE     BIT_3
+#define QLCNIC_SWITCH_PORT_MIRRORING   BIT_4
+};
+
 int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
 int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);

@@ -1070,13 +1140,14 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
 int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
 int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
 int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
 int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
                struct qlcnic_host_tx_ring *tx_ring);
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac);
 void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
 int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
+void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);

 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
@@ -1088,6 +1159,32 @@ int qlcnic_check_loopback_buff(unsigned char *data);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);

+/* Functions from qlcnic_vf.c */
+int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter);
+void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter);
+void qlcnicvf_set_port_mode(struct qlcnic_adapter *adapter);
+
+/* Management functions */
+int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_nic_info(struct qlcnic_adapter *, u8);
+int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_get_pci_info(struct qlcnic_adapter *);
+int qlcnic_reset_partition(struct qlcnic_adapter *, u8);
+
+/*  eSwitch management functions */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8,
+                               struct qlcnic_eswitch *);
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8,
+                               struct qlcnic_eswitch *);
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8,
+                       u8, u8, u16);
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
+extern int qlcnic_config_tso;
+
 /*
  * QLOGIC Board information
  */
@@ -1131,6 +1228,14 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)

 extern const struct ethtool_ops qlcnic_ethtool_ops;

+struct qlcnic_nic_template {
+       int (*get_mac_addr) (struct qlcnic_adapter *, u8*);
+       int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+       int (*config_led) (struct qlcnic_adapter *, u32, u32);
+       int (*set_ilb_mode) (struct qlcnic_adapter *);
+       void (*clear_ilb_mode) (struct qlcnic_adapter *);
+};
+
 #define QLCDB(adapter, lvl, _fmt, _args...) do {       \
        if (NETIF_MSG_##lvl & adapter->msg_enable)      \
                printk(KERN_INFO "%s: %s: " _fmt,       \
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index c2c1f5c..1e1dc58 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -88,12 +88,12 @@ qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)

        if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
                if (qlcnic_issue_cmd(adapter,
-                               adapter->ahw.pci_func,
-                               QLCHAL_VERSION,
-                               recv_ctx->context_id,
-                               mtu,
-                               0,
-                               QLCNIC_CDRP_CMD_SET_MTU)) {
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       recv_ctx->context_id,
+                       mtu,
+                       0,
+                       QLCNIC_CDRP_CMD_SET_MTU)) {

                        dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
                        return -EIO;
@@ -121,7 +121,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)

        int i, nrds_rings, nsds_rings;
        size_t rq_size, rsp_size;
-       u32 cap, reg, val;
+       u32 cap, reg, val, reg2;
        int err;

        struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -197,7 +197,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
        phys_addr = hostrq_phys_addr;
        err = qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
-                       QLCHAL_VERSION,
+                       adapter->fw_hal_version,
                        (u32)(phys_addr >> 32),
                        (u32)(phys_addr & 0xffffffff),
                        rq_size,
@@ -216,8 +216,12 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
                rds_ring = &recv_ctx->rds_rings[i];

                reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
-               rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
+               if (adapter->fw_hal_version == QLCNIC_FW_BASE)
+                       rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
                                QLCNIC_REG(reg - 0x200));
+               else
+                       rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 +
+                               reg;
        }

        prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -227,12 +231,18 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
                sds_ring = &recv_ctx->sds_rings[i];

                reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
-               sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_REG(reg - 0x200));
+               reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);

-               reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
-               sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
+               if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
+                       sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
                                QLCNIC_REG(reg - 0x200));
+                       sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_REG(reg2 - 0x200));
+               } else {
+                       sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 +
+                               reg;
+                       sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
+               }
        }

        recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
@@ -253,7 +263,7 @@ qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)

        if (qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
-                       QLCHAL_VERSION,
+                       adapter->fw_hal_version,
                        recv_ctx->context_id,
                        QLCNIC_DESTROY_CTX_RESET,
                        0,
@@ -319,7 +329,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        phys_addr = rq_phys_addr;
        err = qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
-                       QLCHAL_VERSION,
+                       adapter->fw_hal_version,
                        (u32)(phys_addr >> 32),
                        ((u32)phys_addr & 0xffffffff),
                        rq_size,
@@ -327,8 +337,12 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)

        if (err == QLCNIC_RCODE_SUCCESS) {
                temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
-               tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
+               if (adapter->fw_hal_version == QLCNIC_FW_BASE)
+                       tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
                                QLCNIC_REG(temp - 0x200));
+               else
+                       tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 +
+                               temp;

                adapter->tx_context_id =
                        le16_to_cpu(prsp->context_id);
@@ -351,7 +365,7 @@ qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
 {
        if (qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
-                       QLCHAL_VERSION,
+                       adapter->fw_hal_version,
                        adapter->tx_context_id,
                        QLCNIC_DESTROY_CTX_RESET,
                        0,
@@ -368,7 +382,7 @@ qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val)

        if (qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
-                       QLCHAL_VERSION,
+                       adapter->fw_hal_version,
                        reg,
                        0,
                        0,
@@ -385,7 +399,7 @@ qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val)
 {
        return qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
-                       QLCHAL_VERSION,
+                       adapter->fw_hal_version,
                        reg,
                        val,
                        0,
@@ -533,3 +547,464 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
        }
 }

+/* Set MAC address of a NIC partition */
+int qlcnic_set_mac_address(struct qlcnic_adapter *adapter, u8* mac)
+{
+       int err = 0;
+       u32 arg1, arg2, arg3;
+
+       arg1 = adapter->ahw.pci_func | BIT_9;
+       arg2 = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+       arg3 = mac[4] | (mac[5] << 16);
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       arg2,
+                       arg3,
+                       QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to set mac address%d\n", err);
+               err = -EIO;
+       }
+
+       return err;
+}
+
+/* Get MAC address of a NIC partition */
+int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+       int err;
+       u32 arg1;
+
+       arg1 = adapter->ahw.pci_func | BIT_8;
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               qlcnic_fetch_mac(adapter, QLCNIC_ARG1_CRB_OFFSET,
+                               QLCNIC_ARG2_CRB_OFFSET, 0, mac);
+               dev_info(&adapter->pdev->dev, "MAC address: %pM\n", mac);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get mac address%d\n", err);
+               err = -EIO;
+       }
+
+       return err;
+}
+
+/* Get info of a NIC partition */
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
+{
+       int     err;
+       dma_addr_t nic_dma_t;
+       struct qlcnic_info *nic_info;
+       void *nic_info_addr;
+       size_t  nic_size = sizeof(struct qlcnic_info);
+
+       nic_info_addr = pci_alloc_consistent(adapter->pdev,
+               nic_size, &nic_dma_t);
+       if (!nic_info_addr)
+               return -ENOMEM;
+       memset(nic_info_addr, 0, nic_size);
+
+       nic_info = (struct qlcnic_info *) nic_info_addr;
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       MSD(nic_dma_t),
+                       LSD(nic_dma_t),
+                       (func_id << 16 | nic_size),
+                       QLCNIC_CDRP_CMD_GET_NIC_INFO);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               adapter->physical_port = le16_to_cpu(nic_info->phys_port);
+               adapter->switch_mode = le16_to_cpu(nic_info->switch_mode);
+               adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+               adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+               adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+               adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+               adapter->max_mtu = le16_to_cpu(nic_info->max_mtu);
+               adapter->capabilities = le32_to_cpu(nic_info->capabilities);
+               adapter->max_mac_filters = nic_info->max_mac_filters;
+
+               dev_info(&adapter->pdev->dev,
+                       "phy port: %d switch_mode: %d,\n"
+                       "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
+                       "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
+                       adapter->physical_port, adapter->switch_mode,
+                       adapter->max_tx_ques, adapter->max_rx_ques,
+                       adapter->min_tx_bw, adapter->max_tx_bw,
+                       adapter->max_mtu, adapter->capabilities);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get nic info%d\n", err);
+               err = -EIO;
+       }
+
+       pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+       return err;
+}
+
+/* Configure a NIC partition */
+int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+{
+       int err = -EIO;
+       u32 func_state;
+       dma_addr_t nic_dma_t;
+       void *nic_info_addr;
+       struct qlcnic_info *nic_info;
+       size_t nic_size = sizeof(struct qlcnic_info);
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return err;
+
+       if (qlcnic_api_lock(adapter))
+               return err;
+
+       func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) {
+               qlcnic_api_unlock(adapter);
+               return err;
+       }
+
+       qlcnic_api_unlock(adapter);
+
+       nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
+                       &nic_dma_t);
+       if (!nic_info_addr)
+               return -ENOMEM;
+
+       memset(nic_info_addr, 0, nic_size);
+       nic_info = (struct qlcnic_info *)nic_info_addr;
+
+       nic_info->pci_func = cpu_to_le16(nic->pci_func);
+       nic_info->op_mode = cpu_to_le16(nic->op_mode);
+       nic_info->phys_port = cpu_to_le16(nic->phys_port);
+       nic_info->switch_mode = cpu_to_le16(nic->switch_mode);
+       nic_info->capabilities = cpu_to_le32(nic->capabilities);
+       nic_info->max_mac_filters = nic->max_mac_filters;
+       nic_info->max_tx_ques = cpu_to_le16(nic->max_tx_ques);
+       nic_info->max_rx_ques = cpu_to_le16(nic->max_rx_ques);
+       nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
+       nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       MSD(nic_dma_t),
+                       LSD(nic_dma_t),
+                       nic_size,
+                       QLCNIC_CDRP_CMD_SET_NIC_INFO);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to set nic info%d\n", err);
+               err = -EIO;
+       }
+
+       pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+       return err;
+}
+
+/* Get PCI Info of a partition */
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
+{
+       int err = 0, i;
+       dma_addr_t pci_info_dma_t;
+       struct qlcnic_pci_info *npar;
+       void *pci_info_addr;
+       size_t npar_size = sizeof(struct qlcnic_pci_info);
+       size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC;
+
+       pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size,
+                       &pci_info_dma_t);
+       if (!pci_info_addr)
+               return -ENOMEM;
+       memset(pci_info_addr, 0, pci_size);
+
+       if (!adapter->npars)
+               adapter->npars = kzalloc(pci_size, GFP_KERNEL);
+       if (!adapter->npars) {
+               err = -ENOMEM;
+               goto err_npar;
+       }
+
+       if (!adapter->eswitch)
+               adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+                               QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
+       if (!adapter->eswitch) {
+               err = -ENOMEM;
+               goto err_eswitch;
+       }
+
+       npar = (struct qlcnic_pci_info *) pci_info_addr;
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       MSD(pci_info_dma_t),
+                       LSD(pci_info_dma_t),
+                       pci_size,
+                       QLCNIC_CDRP_CMD_GET_PCI_INFO);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) {
+                       adapter->npars[i].id = le32_to_cpu(npar->id);
+                       adapter->npars[i].active = le32_to_cpu(npar->active);
+                       adapter->npars[i].type = le32_to_cpu(npar->type);
+                       adapter->npars[i].default_port =
+                               le32_to_cpu(npar->default_port);
+                       adapter->npars[i].tx_min_bw =
+                               le32_to_cpu(npar->tx_min_bw);
+                       adapter->npars[i].tx_max_bw =
+                               le32_to_cpu(npar->tx_max_bw);
+                       memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN);
+               }
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get PCI Info%d\n", err);
+               kfree(adapter->npars);
+               err = -EIO;
+       }
+       goto err_npar;
+
+err_eswitch:
+       kfree(adapter->npars);
+       adapter->npars = NULL;
+
+err_npar:
+       pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
+               pci_info_dma_t);
+       return err;
+}
+
+/* Reset a NIC partition */
+
+int qlcnic_reset_partition(struct qlcnic_adapter *adapter, u8 func_no)
+{
+       int err = -EIO;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return err;
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       func_no,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_RESET_NPAR);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to issue reset partition%d\n", err);
+               err = -EIO;
+       }
+
+       return err;
+}
+
+/* Get eSwitch Capabilities */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
+                                       struct qlcnic_eswitch *eswitch)
+{
+       int err = -EIO;
+       u32 arg1, arg2;
+
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+               return err;
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       port,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+               eswitch->port = arg1 & 0xf;
+               eswitch->active_vports = LSB(arg2);
+               eswitch->max_ucast_filters = MSB(arg2);
+               eswitch->max_active_vlans = LSB(MSW(arg2));
+               if (arg1 & BIT_6)
+                       eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+               if (arg1 & BIT_7)
+                       eswitch->flags |= QLCNIC_SWITCH_PROMISC_MODE;
+               if (arg1 & BIT_8)
+                       eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get eswitch capabilities%d\n", err);
+       }
+
+       return err;
+}
+
+/* Get current status of eswitch */
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *adapter, u8 port,
+                               struct qlcnic_eswitch *eswitch)
+{
+       int err = -EIO;
+       u32 arg1, arg2;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return err;
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       port,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+               eswitch->port = arg1 & 0xf;
+               eswitch->active_vports = LSB(arg2);
+               eswitch->active_ucast_filters = MSB(arg2);
+               eswitch->active_vlans = LSB(MSW(arg2));
+               if (arg1 & BIT_6)
+                       eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+               if (arg1 & BIT_8)
+                       eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get eswitch status%d\n", err);
+       }
+
+       return err;
+}
+
+/* Enable/Disable eSwitch */
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *adapter, u8 id, u8 enable)
+{
+       int err = -EIO;
+       u32 arg1, arg2;
+       struct qlcnic_eswitch *eswitch;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return err;
+
+       eswitch = &adapter->eswitch[id];
+       if (!eswitch)
+               return err;
+
+       arg1 = eswitch->port | (enable ? BIT_4 : 0);
+       arg2 = eswitch->active_vports | (eswitch->max_ucast_filters << 8) |
+               (eswitch->max_active_vlans << 16);
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       arg2,
+                       0,
+                       QLCNIC_CDRP_CMD_TOGGLE_ESWITCH);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to enable eswitch%d\n", eswitch->port);
+               eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
+               err = -EIO;
+       } else {
+               eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+               dev_info(&adapter->pdev->dev,
+                       "Enabled eSwitch for port %d\n", eswitch->port);
+       }
+
+       return err;
+}
+
+/* Configure eSwitch for port mirroring */
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
+                               u8 enable_mirroring, u8 pci_func)
+{
+       int err = -EIO;
+       u32 arg1;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
+               !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
+               return err;
+
+       arg1 = id | (enable_mirroring ? BIT_4 : 0);
+       arg1 |= pci_func << 8;
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to configure port mirroring%d on eswitch:%d\n",
+                       pci_func, id);
+       } else {
+               dev_info(&adapter->pdev->dev,
+                       "Configured eSwitch %d for port mirroring:%d\n",
+                       id, pci_func);
+       }
+
+       return err;
+}
+
+/* Configure eSwitch port */
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
+               int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
+               u8 mac_learn, u8 pci_func, u16 vlan_id)
+{
+       int err = -EIO;
+       u32 arg1;
+       struct qlcnic_eswitch *eswitch;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return err;
+
+       eswitch = &adapter->eswitch[id];
+       if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+               return err;
+
+       arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
+       arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
+       arg1 |= pci_func << 8;
+       if (vlan_tagging)
+               arg1 |= BIT_5 | (vlan_id << 16);
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to configure eswitch port%d\n", eswitch->port);
+               eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+       } else {
+               eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
+               dev_info(&adapter->pdev->dev,
+                       "Configured eSwitch for port %d\n", eswitch->port);
+       }
+
+       return err;
+}
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 3bd514e..3e4822a 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -683,13 +683,13 @@ static int qlcnic_loopback_test(struct net_device *netdev)
        if (ret)
                goto clear_it;

-       ret = qlcnic_set_ilb_mode(adapter);
+       ret = adapter->nic_ops->set_ilb_mode(adapter);
        if (ret)
                goto done;

        ret = qlcnic_do_ilb_test(adapter);

-       qlcnic_clear_ilb_mode(adapter);
+       adapter->nic_ops->clear_ilb_mode(adapter);

 done:
        qlcnic_diag_free_res(netdev, max_sds_rings);
@@ -715,7 +715,8 @@ static int qlcnic_irq_test(struct net_device *netdev)

        adapter->diag_cnt = 0;
        ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
-                       QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
+                       adapter->fw_hal_version, adapter->portnum,
+                       0, 0, 0x00000011);
        if (ret)
                goto done;

@@ -834,7 +835,7 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        int ret;

-       ret = qlcnic_config_led(adapter, 1, 0xf);
+       ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
        if (ret) {
                dev_err(&adapter->pdev->dev,
                        "Failed to set LED blink state.\n");
@@ -843,7 +844,7 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)

        msleep_interruptible(val * 1000);

-       ret = qlcnic_config_led(adapter, 0, 0xf);
+       ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
        if (ret) {
                dev_err(&adapter->pdev->dev,
                        "Failed to reset LED blink state.\n");
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index ad9d167..1bcfb12 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -208,6 +208,39 @@ enum {
        QLCNIC_HW_PX_MAP_CRB_PGR0
 };

+#define        BIT_0   0x1
+#define        BIT_1   0x2
+#define        BIT_2   0x4
+#define        BIT_3   0x8
+#define        BIT_4   0x10
+#define        BIT_5   0x20
+#define        BIT_6   0x40
+#define        BIT_7   0x80
+#define        BIT_8   0x100
+#define        BIT_9   0x200
+#define        BIT_10  0x400
+#define        BIT_11  0x800
+#define        BIT_12  0x1000
+#define        BIT_13  0x2000
+#define        BIT_14  0x4000
+#define        BIT_15  0x8000
+#define        BIT_16  0x10000
+#define        BIT_17  0x20000
+#define        BIT_18  0x40000
+#define        BIT_19  0x80000
+#define        BIT_20  0x100000
+#define        BIT_21  0x200000
+#define        BIT_22  0x400000
+#define        BIT_23  0x800000
+#define        BIT_24  0x1000000
+#define        BIT_25  0x2000000
+#define        BIT_26  0x4000000
+#define        BIT_27  0x8000000
+#define        BIT_28  0x10000000
+#define        BIT_29  0x20000000
+#define        BIT_30  0x40000000
+#define        BIT_31  0x80000000
+
 /*  This field defines CRB adr [31:20] of the agents */

 #define QLCNIC_HW_CRB_HUB_AGT_ADR_MN   \
@@ -684,12 +717,20 @@ enum {
 #define QLCNIC_DEV_FAILED              0x6
 #define QLCNIC_DEV_QUISCENT            0x7

+#define QLC_DEV_CHECK_ACTIVE(VAL, FN)          ((VAL) &= (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)           ((VAL) &= ~(1 << (FN * 4)))
 #define QLC_DEV_SET_RST_RDY(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_SET_QSCNT_RDY(VAL, FN)         ((VAL) |= (2 << (FN * 4)))
 #define QLC_DEV_CLR_RST_QSCNT(VAL, FN)         ((VAL) &= ~(3 << (FN * 4)))

+#define QLC_DEV_GET_DRV(VAL, FN)               (0xf & ((VAL) >> (FN * 4)))
+#define QLC_DEV_SET_DRV(VAL, FN)               ((VAL) << (FN * 4))
+
+#define QLCNIC_TYPE_NIC                1
+#define QLCNIC_TYPE_FCOE               2
+#define QLCNIC_TYPE_ISCSI              3
+
 #define QLCNIC_RCODE_DRIVER_INFO               0x20000000
 #define QLCNIC_RCODE_DRIVER_CAN_RELOAD         0x40000000
 #define QLCNIC_RCODE_FATAL_ERROR               0x80000000
@@ -721,6 +762,35 @@ struct qlcnic_legacy_intr_set {
        u32     pci_int_reg;
 };

+#define QLCNIC_FW_API          0x1b216c
+#define QLCNIC_DRV_OP_MODE     0x1b2170
+#define QLCNIC_MSIX_BASE       0x132110
+#define QLCNIC_MAX_PCI_FUNC    8
+
+/* PCI function operational mode */
+enum {
+       QLCNIC_MGMT_FUNC        = 0,
+       QLCNIC_PRIV_FUNC        = 1,
+       QLCNIC_NON_PRIV_FUNC    = 2
+};
+
+/* FW HAL api version */
+enum {
+       QLCNIC_FW_BASE  = 1,
+       QLCNIC_FW_NPAR  = 2
+};
+
+#define QLC_DEV_DRV_DEFAULT 0x11111111
+
+#define LSB(x) ((uint8_t)(x))
+#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8))
+
+#define LSW(x)  ((uint16_t)((uint32_t)(x)))
+#define MSW(x)  ((uint16_t)((uint32_t)(x) >> 16))
+
+#define LSD(x)  ((uint32_t)((uint64_t)(x)))
+#define MSD(x)  ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
+
 #define        QLCNIC_LEGACY_INTR_CONFIG                                       \
 {                                                                      \
        {                                                               \
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 0c2e1f0..f776956 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -538,7 +538,7 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
        return rv;
 }

-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
 {
        struct qlcnic_nic_req req;
        u64 word;
@@ -704,21 +704,15 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
        return rc;
 }

-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac)
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac)
 {
-       u32 crbaddr, mac_hi, mac_lo;
+       u32 crbaddr;
        int pci_func = adapter->ahw.pci_func;

        crbaddr = CRB_MAC_BLOCK_START +
                (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));

-       mac_lo = QLCRD32(adapter, crbaddr);
-       mac_hi = QLCRD32(adapter, crbaddr+4);
-
-       if (pci_func & 1)
-               *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
-       else
-               *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
+       qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac);

        return 0;
 }
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 71a4e66..635c990 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -520,17 +520,16 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
        int timeo;
        u32 val;

-       val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
-       val = (val >> (adapter->portnum * 4)) & 0xf;
-
-       if ((val & 0x3) != 1) {
-               dev_err(&adapter->pdev->dev, "Not an Ethernet NIC func=%u\n",
-                                                                       val);
-               return -EIO;
+       if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
+               val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+               val = QLC_DEV_GET_DRV(val, adapter->portnum);
+               if ((val & 0x3) != QLCNIC_TYPE_NIC) {
+                       dev_err(&adapter->pdev->dev,
+                               "Not an Ethernet NIC func=%u\n", val);
+                       return -EIO;
+               }
+               adapter->physical_port = (val >> 2);
        }
-
-       adapter->physical_port = (val >> 2);
-
        if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
                timeo = 30;

@@ -1701,3 +1700,24 @@ qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
        sds_ring->consumer = consumer;
        writel(consumer, sds_ring->crb_sts_consumer);
 }
+
+void
+qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
+                       u8 alt_mac, u8 *mac)
+{
+       u32 mac_low, mac_high;
+       int i;
+
+       mac_low = QLCRD32(adapter, off1);
+       mac_high = QLCRD32(adapter, off2);
+
+       if (alt_mac) {
+               mac_low |= (mac_low >> 16) | (mac_high << 16);
+               mac_high >>= 16;
+       }
+
+       for (i = 0; i < 2; i++)
+               mac[i] = (u8)(mac_high >> ((1 - i) * 8));
+       for (i = 2; i < 6; i++)
+               mac[i] = (u8)(mac_low >> ((5 - i) * 8));
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 1003eb7..3b4fdb3 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -65,6 +65,10 @@ static int load_fw_file;
 module_param(load_fw_file, int, 0644);
 MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");

+static int qlcnic_config_npars;
+module_param(qlcnic_config_npars, int, 0644);
+MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
+
 static int __devinit qlcnic_probe(struct pci_dev *pdev,
                const struct pci_device_id *ent);
 static void __devexit qlcnic_remove(struct pci_dev *pdev);
@@ -307,19 +311,14 @@ static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
 static int
 qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
 {
-       int i;
-       unsigned char *p;
-       u64 mac_addr;
+       u8 mac_addr[ETH_ALEN];
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;

-       if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+       if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
                return -EIO;

-       p = (unsigned char *)&mac_addr;
-       for (i = 0; i < 6; i++)
-               netdev->dev_addr[i] = *(p + 5 - i);
-
+       memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
        memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
        memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);

@@ -371,6 +370,22 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 #endif
 };

+static struct qlcnic_nic_template qlcnic_ops = {
+       .get_mac_addr = qlcnic_get_mac_addr,
+       .config_bridged_mode = qlcnic_config_bridged_mode,
+       .config_led = qlcnic_config_led,
+       .set_ilb_mode = qlcnic_set_ilb_mode,
+       .clear_ilb_mode = qlcnic_clear_ilb_mode
+};
+
+static struct qlcnic_nic_template qlcnic_pf_ops = {
+       .get_mac_addr = qlcnic_get_mac_address,
+       .config_bridged_mode = qlcnic_config_bridged_mode,
+       .config_led = qlcnic_config_led,
+       .set_ilb_mode = qlcnic_set_ilb_mode,
+       .clear_ilb_mode = qlcnic_clear_ilb_mode
+};
+
 static void
 qlcnic_setup_intr(struct qlcnic_adapter *adapter)
 {
@@ -452,6 +467,125 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
                iounmap(adapter->ahw.pci_base0);
 }

+/* Use api lock to access this function */
+static int
+qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
+{
+       u8 id;
+       u32 ref_count;
+       int i, ret = 1;
+       u32 data = QLCNIC_MGMT_FUNC;
+       void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+
+       /* If other drivers are not in use set their privilege level */
+       ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       ret = qlcnic_api_lock(adapter);
+       if (ret)
+               goto err_lock;
+       if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
+               goto err_npar;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               id = adapter->npars[i].id;
+               if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
+                       id == adapter->ahw.pci_func)
+                       continue;
+               data |= (qlcnic_config_npars & QLC_DEV_SET_DRV(0xf, id));
+       }
+       writel(data, priv_op);
+
+err_npar:
+       qlcnic_api_unlock(adapter);
+err_lock:
+       return ret;
+}
+
+static u8
+qlcnic_set_mgmt_driver(struct qlcnic_adapter *adapter)
+{
+       u8 i, ret = 0;
+
+       if (qlcnic_get_pci_info(adapter))
+               return ret;
+       /* Set the eswitch */
+       for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) {
+               if (!qlcnic_get_eswitch_capabilities(adapter, i,
+                       &adapter->eswitch[i])) {
+                       ret++;
+                       qlcnic_toggle_eswitch(adapter, i, ret);
+               }
+       }
+       return ret;
+}
+
+static u32
+qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+{
+       void __iomem *msix_base_addr;
+       void __iomem *priv_op;
+       u32 func;
+       u32 msix_base;
+       u32 op_mode, priv_level;
+
+       /* Determine FW API version */
+       adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+       if (adapter->fw_hal_version == ~0) {
+               adapter->nic_ops = &qlcnic_ops;
+               adapter->fw_hal_version = QLCNIC_FW_BASE;
+               adapter->ahw.pci_func = PCI_FUNC(adapter->pdev->devfn);
+               dev_info(&adapter->pdev->dev,
+                       "FW does not support nic partion\n");
+               return adapter->fw_hal_version;
+       }
+
+       /* Find PCI function number */
+       pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+       msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
+       msix_base = readl(msix_base_addr);
+       func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
+       adapter->ahw.pci_func = func;
+
+       /* Determine function privilege level */
+       priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+       op_mode = readl(priv_op);
+       if (op_mode == QLC_DEV_DRV_DEFAULT) {
+               priv_level = QLCNIC_MGMT_FUNC;
+               if (qlcnic_api_lock(adapter))
+                       return 0;
+               op_mode = (op_mode & ~QLC_DEV_SET_DRV(0xf, func)) |
+                               (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, func));
+               writel(op_mode, priv_op);
+               qlcnic_api_unlock(adapter);
+
+       } else
+               priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+       switch (priv_level) {
+       case QLCNIC_MGMT_FUNC:
+               adapter->op_mode = QLCNIC_MGMT_FUNC;
+               adapter->nic_ops = &qlcnic_pf_ops;
+               /* Set privilege level for other functions */
+               if (qlcnic_config_npars)
+                       qlcnic_set_function_modes(adapter);
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d, Management function\n",
+                       adapter->fw_hal_version);
+               break;
+       case QLCNIC_PRIV_FUNC:
+               adapter->op_mode = QLCNIC_PRIV_FUNC;
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d, Privileged function\n",
+                       adapter->fw_hal_version);
+               adapter->nic_ops = &qlcnic_pf_ops;
+               break;
+       default:
+               dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
+                       priv_level);
+               return 0;
+       }
+       return adapter->fw_hal_version;
+}
+
 static int
 qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
 {
@@ -460,7 +594,6 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        unsigned long mem_len, pci_len0 = 0;

        struct pci_dev *pdev = adapter->pdev;
-       int pci_func = adapter->ahw.pci_func;

        /* remap phys address */
        mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -483,8 +616,13 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        adapter->ahw.pci_base0 = mem_ptr0;
        adapter->ahw.pci_len0 = pci_len0;

+       if (!qlcnic_get_driver_mode(adapter)) {
+               iounmap(adapter->ahw.pci_base0);
+               return -EIO;
+       }
+
        adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
-               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));

        return 0;
 }
@@ -553,7 +691,10 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
        dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
                        fw_major, fw_minor, fw_build);

-       adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+       if (adapter->fw_hal_version == QLCNIC_FW_NPAR)
+               qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+       else
+               adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);

        adapter->flags &= ~QLCNIC_LRO_ENABLED;

@@ -633,6 +774,10 @@ wait_init:

        qlcnic_check_options(adapter);

+       if (adapter->fw_hal_version != QLCNIC_FW_BASE &&
+                       adapter->op_mode == QLCNIC_MGMT_FUNC)
+               qlcnic_set_mgmt_driver(adapter);
+
        adapter->need_fw_reset = 0;

        qlcnic_release_firmware(adapter);
@@ -977,12 +1122,11 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,

        SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);

-       netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
-       netdev->features |= (NETIF_F_GRO);
-       netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+       netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6);

-       netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
-       netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+       netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6);

        if (pci_using_dac) {
                netdev->features |= NETIF_F_HIGHDMA;
@@ -1036,7 +1180,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct net_device *netdev = NULL;
        struct qlcnic_adapter *adapter = NULL;
        int err;
-       int pci_func_id = PCI_FUNC(pdev->devfn);
        uint8_t revision_id;
        uint8_t pci_using_dac;

@@ -1072,7 +1215,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->netdev  = netdev;
        adapter->pdev    = pdev;
        adapter->dev_rst_time = jiffies;
-       adapter->ahw.pci_func  = pci_func_id;

        revision_id = pdev->revision;
        adapter->ahw.revision_id = revision_id;
@@ -1088,7 +1230,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_free_netdev;

        /* This will be reset for mezz cards  */
-       adapter->portnum = pci_func_id;
+       adapter->portnum = adapter->ahw.pci_func;

        err = qlcnic_get_board_info(adapter);
        if (err) {
@@ -1175,6 +1317,11 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)

        qlcnic_detach(adapter);

+       if (adapter->npars != NULL)
+               kfree(adapter->npars);
+       if (adapter->eswitch != NULL)
+               kfree(adapter->eswitch);
+
        qlcnic_clr_all_drv_state(adapter);

        clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1340,11 +1487,11 @@ qlcnic_tso_check(struct net_device *netdev,
        u8 opcode = TX_ETHER_PKT;
        __be16 protocol = skb->protocol;
        u16 flags = 0, vid = 0;
-       u32 producer;
        int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
        struct cmd_desc_type0 *hwdesc;
        struct vlan_ethhdr *vh;
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       u32 producer = tx_ring->producer;

        if (protocol == cpu_to_be16(ETH_P_8021Q)) {

@@ -1360,6 +1507,11 @@ qlcnic_tso_check(struct net_device *netdev,
                vlan_oob = 1;
        }

+       if (*(skb->data) & BIT_0) {
+               flags |= BIT_0;
+               memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+       }
+
        if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
                        skb_shinfo(skb)->gso_size > 0) {

@@ -1409,7 +1561,6 @@ qlcnic_tso_check(struct net_device *netdev,
        /* For LSO, we need to copy the MAC/IP/TCP headers into
         * the descriptor ring
         */
-       producer = tx_ring->producer;
        copied = 0;
        offset = 2;

@@ -2382,7 +2533,7 @@ qlcnic_store_bridged_mode(struct device *dev,
        if (strict_strtoul(buf, 2, &new))
                goto err_out;

-       if (!qlcnic_config_bridged_mode(adapter, !!new))
+       if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
                ret = len;

 err_out:
--
1.6.0.2


^ permalink raw reply related

* Re: [patch v2] caif: cleanup: remove duplicate checks
From: Sjur Brændeland @ 2010-05-24 20:47 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: walter harms, netdev, Sjur Braendeland, Stephen Rothwell,
	kernel-janitors, David S. Miller
In-Reply-To: <20100524162815.GA22515@bicker>

 Dan Carpenter <error27@gmail.com> wrote:
> "phyinfo" can never be null here because we assigned it an address, so I
> removed both the assert and the second check inside the if statement.  I
> removed the "phyinfo->phy_layer != NULL" check as well because that was
> asserted earlier.
>
> Walter Harms suggested I move the "phyinfo->phy_ref_count++;" outside
> the if condition for readability, so I have done that.
>
> Signed-off-by: Dan Carpenter <error27@gmail.com>
Acked-by: Sjur Braendeland <sjur.brandeland@stericsson.com>
Thanks, this looks good.

^ permalink raw reply

* Re: [PATCH 1/2] IPv6: keep route for tentative address
From: David Miller @ 2010-05-24 20:52 UTC (permalink / raw)
  To: greg; +Cc: shemminger, emils.tantilov, netdev, emil.s.tantilov, stable
In-Reply-To: <20100524184713.GA8627@kroah.com>

From: Greg KH <greg@kroah.com>
Date: Mon, 24 May 2010 11:47:13 -0700

> On Mon, May 24, 2010 at 11:31:18AM -0700, Stephen Hemminger wrote:
>> Recent changes preserve IPv6 address when link goes down (good).
>> But would cause address to point to dead dst entry (bad).
>> The simplest fix is to just not delete route if address is
>> being held for later use.
>> 
>> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
>> Signed-off-by: David S. Miller <davem@davemloft.net>
>> (cherry picked from commit 93fa159abe50d3c55c7f83622d3f5c09b6e06f4b)
>> ---
>> Patch is for 2.6.34-stable (problem doesn't exist in earlier kernel)
> 
> Normally I wait for David to send networking patches for the stable
> trees, so I would like to get David's ack on these two before I am
> willing to apply them.

These two are fine to go to -stable, Greg please integrate.

^ permalink raw reply

* Re: [PATCH net-next-2.6 0/8] CAIF: Bugfixes and updates
From: Sjur Brændeland @ 2010-05-24 20:50 UTC (permalink / raw)
  To: David Miller
  Cc: sjur.brandeland, netdev, marcel, daniel.martensson, linus.walleji
In-Reply-To: <20100520.152743.46361658.davem@davemloft.net>

David Miller <davem@davemloft.net> wrote:
>> Would you consider my patch where I fix MSG_TRUNC to work properly a bugfix?
>
> You're really pushing it, but fine...

Thanks Dave,

Regards
Sjur

^ permalink raw reply

* Re: [patch] sctp: dubious bitfields in sctp_transport
From: Vlad Yasevich @ 2010-05-24 20:12 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Sridhar Samudrala, David S. Miller, Wei Yongjun, linux-sctp,
	netdev, kernel-janitors
In-Reply-To: <20100522202024.GL22515@bicker>



Dan Carpenter wrote:
> Sparse complains because these one-bit bitfields are signed.
>   include/net/sctp/structs.h:879:24: error: dubious one-bit signed bitfield
>   include/net/sctp/structs.h:889:31: error: dubious one-bit signed bitfield
>   include/net/sctp/structs.h:895:26: error: dubious one-bit signed bitfield
>   include/net/sctp/structs.h:898:31: error: dubious one-bit signed bitfield
>   include/net/sctp/structs.h:901:27: error: dubious one-bit signed bitfield
> 
> It doesn't cause a problem in the current code, but it would be better
> to clean it up.  This was introduced by c0058a35aacc7: "sctp: Save some
> room in the sctp_transport by using bitfields".
> 
> Signed-off-by: Dan Carpenter <error27@gmail.com>
> ---
> It looks like this header is exported to user space.  I don't know if
> that makes a difference.

That shouldn't make a difference.

-vlad

> 
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index 6173c61..4b86011 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -876,7 +876,7 @@ struct sctp_transport {
>  
>  	/* Reference counting. */
>  	atomic_t refcnt;
> -	int	 dead:1,
> +	__u32	 dead:1,
>  		/* RTO-Pending : A flag used to track if one of the DATA
>  		 *		chunks sent to this address is currently being
>  		 *		used to compute a RTT. If this flag is 0,
> 

^ permalink raw reply

* Re: [patch] caif: remove unneeded null check in caif_connect()
From: Sjur Brændeland @ 2010-05-24 19:56 UTC (permalink / raw)
  To: Dan Carpenter, Sjur Braendeland, Eric Dumazet, David S. Miller,
	linux-kernel
In-Reply-To: <20100522204342.GV22515@bicker>

Dan Carpenter <error27@gmail.com> wrote:
> We already dereferenced uaddr towards the start of the function when we
> checked that "uaddr->sa_family != AF_CAIF".  Both the check here and the
> earlier check were added in bece7b2398d0: "caif: Rewritten socket
> implementation".  Before that patch, we assumed that we recieved a valid
> pointer for uaddr, and based on that, I have removed this check.
>
> Signed-off-by: Dan Carpenter <error27@gmail.com>
Thanks Looks good,
Acked-by: Sjur Braendeland <sjur.brandeland@stericsson.com>

^ permalink raw reply

* Re: [PATCH 03/12] caif: remove unused #include <linux/version.h>
From: Sjur Brændeland @ 2010-05-24 19:51 UTC (permalink / raw)
  To: Huang Weiyi; +Cc: davem, netdev
In-Reply-To: <1274548317-4044-1-git-send-email-weiyi.huang@gmail.com>

Huang Weiyi <weiyi.huang@gmail.com> wrote:
> Remove unused #include <linux/version.h>('s) in
>  net/caif/caif_dev.c
>  net/caif/chnl_net.c
>
> Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com>
Looks good thanks.
Acked-by: Sjur Braendeland <sjur.brandeland@stericsson.com>

,

^ permalink raw reply

* Re: [PATCH net-2.6] macvlan: do a proper cleanup in macvlan_common_newlink()
From: Patrick McHardy @ 2010-05-24 18:56 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem
In-Reply-To: <20100524170224.GA2816@psychotron.redhat.com>

Jiri Pirko wrote:
> Mon, May 24, 2010 at 05:58:58PM CEST, jpirko@
> Subject: [PATCH net-2.6] macvlan: do proper cleanup in macvlan_common_newlink() V2
> 
> Fixes possible memory leak.

Looks good, thanks.

> Signed-off-by: Jiri Pirko <jpirko@redhat.com>

Acked-by: Patrick McHardy <kaber@trash.net>

> ---
>  drivers/net/macvlan.c |    9 ++++++++-
>  1 files changed, 8 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
> index 4e238af..87e8d4c 100644
> --- a/drivers/net/macvlan.c
> +++ b/drivers/net/macvlan.c
> @@ -634,11 +634,18 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
>  
>  	err = register_netdevice(dev);
>  	if (err < 0)
> -		return err;
> +		goto destroy_port;
>  
>  	list_add_tail(&vlan->list, &port->vlans);
>  	netif_stacked_transfer_operstate(lowerdev, dev);
> +
>  	return 0;
> +
> +destroy_port:
> +	if (list_empty(&port->vlans))
> +		macvlan_port_destroy(lowerdev);
> +
> +	return err;
>  }
>  EXPORT_SYMBOL_GPL(macvlan_common_newlink);
>  


^ permalink raw reply

* Re: [PATCH 1/2] IPv6: keep route for tentative address
From: Greg KH @ 2010-05-24 18:47 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Emil S Tantilov, David S. Miller, NetDev, Tantilov, Emil S,
	stable
In-Reply-To: <20100524113118.47cc9852@nehalam>

On Mon, May 24, 2010 at 11:31:18AM -0700, Stephen Hemminger wrote:
> Recent changes preserve IPv6 address when link goes down (good).
> But would cause address to point to dead dst entry (bad).
> The simplest fix is to just not delete route if address is
> being held for later use.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> (cherry picked from commit 93fa159abe50d3c55c7f83622d3f5c09b6e06f4b)
> ---
> Patch is for 2.6.34-stable (problem doesn't exist in earlier kernel)

Normally I wait for David to send networking patches for the stable
trees, so I would like to get David's ack on these two before I am
willing to apply them.

thanks,

greg k-h

^ permalink raw reply

* 【免費的IPHONE等你來拿】
From: ella92260565 @ 2010-05-24 18:37 UTC (permalink / raw)
  To: artinodigesu, 3567520, ruby168can168, iablue88, jay32111,
	rj_jmyang, chuchi.com, apememessox

凡推薦成功立即免費擁有IPHONE手機一隻
只要邀友填寫免費體驗(http://fly2.ws/w6fEZsT )
就可輕鬆擁有唷!!

活動時間:2010/5/17-2010/6/30 限量10台 

獲得iphone二步驟: 
1.邀友填寫線上免費體驗單 (http://fly2.ws/w6fEZsT ) 
2.推薦成功立即擁有IPHONE一支。

您的身邊有過敏問題的朋友嗎?您是否對家中的空氣品質
感到不滿意呢?全程免費的體驗,又有機會拿IPHONE
這麼好康的活動,快到http://fly2.ws/w6fEZsT  填寫免費體驗單!


--------------------------------------------------------------
Ovi Store: New apps daily
http://store.ovi.com/?cid=ovistore-fw-bac-na-acq-na-ovimail-g0-na-3


^ 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