Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net] net: Fix the rollback test in dev_change_name()
From: Eric Dumazet @ 2009-11-16 11:08 UTC (permalink / raw)
  To: David Miller; +Cc: jarkao2, netdev
In-Reply-To: <20091116.024936.14048478.davem@davemloft.net>

David Miller a écrit :
> From: Jarek Poplawski <jarkao2@gmail.com>
> Date: Mon, 16 Nov 2009 09:30:24 +0000
> 
>> From: Eric Dumazet <eric.dumazet@gmail.com>
>>
>> net: Fix the rollback test in dev_change_name()
>>
>> In dev_change_name() an err variable is used for storing the original
>> call_netdevice_notifiers() errno (negative) and testing for a rollback
>> error later, but the test for non-zero is wrong, because the err might
>> have positive value as well - from dev_alloc_name(). It means the
>> rollback for a netdevice with a number > 0 will never happen. (The err
>> test is reordered btw. to make it more readable.)
>>
>> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
>> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> 
> Ok.
> 
> Eric please give your signoff and I'll put this where it needs
> to go.
> 

I finaly understood why I got stuck on this one : I thought dev_alloc_name()
was returning 0 in case of success. The test was thus realy obscure for me.

So Jarek patch is pretty clear now I saw the light !

Thanks

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>


^ permalink raw reply

* Re: [net-next] bnx2x: Handle Rx and Tx together in NAPI
From: David Miller @ 2009-11-16 11:05 UTC (permalink / raw)
  To: B05799; +Cc: vladz, netdev, eilong
In-Reply-To: <9F4C7D19E8361D4C94921B95BE08B81B950BFF@zin33exm22.fsl.freescale.net>

From: "Kumar Gopalpet-B05799" <B05799@freescale.com>
Date: Mon, 16 Nov 2009 16:33:56 +0530

> I was talking about an independent napi routine for cleaning tx ring, I
> do not want to mix the rx and tx clean ring processes.

But you absolutely should do this, it will give optimal performance.

^ permalink raw reply

* RE: [net-next] bnx2x: Handle Rx and Tx together in NAPI
From: Kumar Gopalpet-B05799 @ 2009-11-16 11:03 UTC (permalink / raw)
  To: David Miller; +Cc: vladz, netdev, eilong
In-Reply-To: <20091116.024130.156214496.davem@davemloft.net>

 
>> Can we actually introduce NAPI mechanism for cleaning TX ring ??
>
>You really should if you can.
>
>Preferably you should combine it with RX work in a shared NAPI context
>(1 TX queue + 1 RX queue per NAPI context, for example), doing 
>the TX reclaim first in your ->poll() routine, before the RX 
>processing, because this TX reclaim provides freshly freed up 
>SKBs for RX work that generates responses (TCP ACKs, etc.)
>

I was talking about an independent napi routine for cleaning tx ring, I
do not want to mix the rx and tx clean ring processes.



--
Thanks
Sandee

^ permalink raw reply

* Re: [PATCH 2/2] act_mirred: optimization
From: David Miller @ 2009-11-16 10:58 UTC (permalink / raw)
  To: xiaosuo; +Cc: hadi, shemminger, netdev
In-Reply-To: <20091116.024839.257258321.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Mon, 16 Nov 2009 02:48:39 -0800 (PST)

> From: Changli Gao <xiaosuo@gmail.com>
> Date: Mon, 16 Nov 2009 17:53:29 +0800
> 
>> act_mirred: optimization.
>> 
>> move checking if eaction is valid in tcf_mirred_init()
>> 
>> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
>> Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
> 
> Also applied, thank you.

Nevermind, you're NOT TESTING the patches you are posting:

net/sched/act_mirred.c: In function ‘tcf_mirred’:
net/sched/act_mirred.c:168: error: label ‘out’ used but not defined
net/sched/act_mirred.c:158: warning: unused variable ‘err’
net/sched/act_mirred.c:158: warning: unused variable ‘retval’
make[2]: *** [net/sched/act_mirred.o] Error 1
make[1]: *** [net/sched] Error 2
make[1]: *** Waiting for unfinished jobs....

I'm thus reverting both changes.

Don't submit changes which are untested, it wastes my time.

^ permalink raw reply

* Re: [PATCH net] net: Fix the rollback test in dev_change_name()
From: David Miller @ 2009-11-16 10:49 UTC (permalink / raw)
  To: jarkao2; +Cc: eric.dumazet, netdev
In-Reply-To: <20091116093024.GA13115@ff.dom.local>

From: Jarek Poplawski <jarkao2@gmail.com>
Date: Mon, 16 Nov 2009 09:30:24 +0000

> From: Eric Dumazet <eric.dumazet@gmail.com>
> 
> net: Fix the rollback test in dev_change_name()
> 
> In dev_change_name() an err variable is used for storing the original
> call_netdevice_notifiers() errno (negative) and testing for a rollback
> error later, but the test for non-zero is wrong, because the err might
> have positive value as well - from dev_alloc_name(). It means the
> rollback for a netdevice with a number > 0 will never happen. (The err
> test is reordered btw. to make it more readable.)
> 
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>

Ok.

Eric please give your signoff and I'll put this where it needs
to go.

Thanks.

^ permalink raw reply

* Re: [PATCH 2/2] act_mirred: optimization
From: David Miller @ 2009-11-16 10:48 UTC (permalink / raw)
  To: xiaosuo; +Cc: hadi, shemminger, netdev
In-Reply-To: <412e6f7f0911160153g31d5eado7c5569d9e95f7d01@mail.gmail.com>

From: Changli Gao <xiaosuo@gmail.com>
Date: Mon, 16 Nov 2009 17:53:29 +0800

> act_mirred: optimization.
> 
> move checking if eaction is valid in tcf_mirred_init()
> 
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
> Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>

Also applied, thank you.

^ permalink raw reply

* Re: [PATCH 1/2] act_mirred: cleanup
From: David Miller @ 2009-11-16 10:48 UTC (permalink / raw)
  To: hadi; +Cc: xiaosuo, shemminger, netdev
In-Reply-To: <1258363479.3251.25.camel@bigi>

From: jamal <hadi@cyberus.ca>
Date: Mon, 16 Nov 2009 04:24:39 -0500

> On Mon, 2009-11-16 at 16:33 +0800, Changli Gao wrote:
>> act_mirred: cleanup
>> 
>> 1. don't let go back using goto.
>> 2. don't call skb_act_clone() until it is necessary.
>> 3. one exit of the critical context.
>> 
>> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
> 
> Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>

Applied.

^ permalink raw reply

* Re: [net-next] bnx2x: Handle Rx and Tx together in NAPI
From: David Miller @ 2009-11-16 10:41 UTC (permalink / raw)
  To: B05799; +Cc: vladz, netdev, eilong
In-Reply-To: <9F4C7D19E8361D4C94921B95BE08B81B950BEF@zin33exm22.fsl.freescale.net>

From: "Kumar Gopalpet-B05799" <B05799@freescale.com>
Date: Mon, 16 Nov 2009 16:02:04 +0530

> Can we actually introduce NAPI mechanism for cleaning TX ring ??

You really should if you can.

Preferably you should combine it with RX work in a shared NAPI context
(1 TX queue + 1 RX queue per NAPI context, for example), doing the TX
reclaim first in your ->poll() routine, before the RX processing,
because this TX reclaim provides freshly freed up SKBs for RX work
that generates responses (TCP ACKs, etc.)

^ permalink raw reply

* Re: [patch 4/5] [PATCH] qeth: rework TSO functions
From: David Miller @ 2009-11-16 10:36 UTC (permalink / raw)
  To: blaschka; +Cc: netdev, linux-s390
In-Reply-To: <4B00F81D.8090106@linux.vnet.ibm.com>

From: Frank Blaschka <blaschka@linux.vnet.ibm.com>
Date: Mon, 16 Nov 2009 07:58:37 +0100

> I did not add any new sysfs knobs for TSO. The old one was just moved
> from the core part of the driver to the L3 discipline. I know ethtool
> is the way to configure TSO and I would be happy to drop sysfs off, but
> we have to keep this legacy interface because of our customers and
> distributors. If you say there is no way to keep it let me know and I
> will rework the patch.

Ok, if it's always been there :-/  It never should have been added
in the first place.

I'll add these patches to net-next-2.6, thanks.

^ permalink raw reply

* RE: [net-next] bnx2x: Handle Rx and Tx together in NAPI
From: Kumar Gopalpet-B05799 @ 2009-11-16 10:32 UTC (permalink / raw)
  To: David Miller, vladz; +Cc: netdev, eilong
In-Reply-To: <20091116.022012.81633492.davem@davemloft.net>

 

>From: "Vladislav Zolotarov" <vladz@broadcom.com>
>Date: Mon, 16 Nov 2009 12:01:09 +0200
>
>>   - Limit Tx work done in one iteration by the same number 
>of packets 
>> as Rx in order to ensure both fair work load balancing relatively to 
>> other devices scheduled for NAPI on the local CPU and sane Tx/Rx skb 
>> resource management from single QP perspective.
>
>You should not do this.

Can we actually introduce NAPI mechanism for cleaning TX ring ??
 
>RX is several orders of magnitude more work than TX is.  TX 
>therefore should not be charged against the NAPI polling quota.
>
>Don't try to be different from other drivers unless you have 
>detailed performance numbers from various situations (local 
>TCP flows _and_
>routing) to justify it. :-)
>
I tried (I am talking about gianfar driver) to introduce napi for
cleaning tx ring (similar to rx napi mechanism ) and found that it
actually improves performance for bi-directioanl flow on an SMP system
(performance is abt 1.6 times). 
If introducing napi mechansim for tx is logical then I will send out an
RFC patch
>All NAPI drivers ignore TX work when considering NAPI polling 
>quotas and you should too :-)
>--


--

Thanks
Sandeep

^ permalink raw reply

* Re: [PATCH 2/2] act_mirred: optimization
From: jamal @ 2009-11-16 10:24 UTC (permalink / raw)
  To: David Miller; +Cc: xiaosuo, shemminger, netdev
In-Reply-To: <20091116.022144.203823073.davem@davemloft.net>

On Mon, 2009-11-16 at 02:21 -0800, David Miller wrote:
> From: jamal <hadi@cyberus.ca>
> Date: Mon, 16 Nov 2009 05:06:30 -0500
 
> > One indent too many? 
> 
> It's actually fixing some stray space characters into a real proper
> tab character.

good enough for me then.

cheers,
jamal


^ permalink raw reply

* Re: [PATCH] net/can: add driver for mscan family & mpc52xx_mscan
From: Wolfram Sang @ 2009-11-16 10:24 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: Grant Likely, netdev-u79uwXL29TY76Z2rM5mHXA, David Miller,
	socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	linuxppc-dev-mnsaURCQ41sdnm+yROfE0A
In-Reply-To: <4B0110D5.6010405-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>


[-- Attachment #1.1: Type: text/plain, Size: 1209 bytes --]

Hi Wolfgang,

On Mon, Nov 16, 2009 at 09:44:05AM +0100, Wolfgang Grandegger wrote:
> Hi Wolfram,
> 
> thanks for pushing this driver to mainline. I think you should also add
> a CC to the Devicetree-discuss ML.

thank you very much for your review! I agree with nearly all of your points and will
send an update today. The only thing I have doubts about is removing those lines:

> +MODULE_AUTHOR("Andrey Volkov <avolkov-ppI4tVfbJvJWk0Htik3J/w@public.gmane.org>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("CAN port driver for a MSCAN based chips");

I looked around in the kernel sources and found that they are often present in
generic modules, even if they can't be used without a wrapper (examples are all
files in drivers/i2c/algos or drivers/net/wireless/iwlwifi/iwl-core.c). As I'm
also a bit anxious to fiddle with other people's authorship, I'd prefer to keep
them.

Finally, I'll also try to test suspend/resume, but I have to find out if it is
supported on that board in general.

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

^ permalink raw reply

* Re: [PATCH 2/2] act_mirred: optimization
From: David Miller @ 2009-11-16 10:21 UTC (permalink / raw)
  To: hadi; +Cc: xiaosuo, shemminger, netdev
In-Reply-To: <1258365990.3251.33.camel@bigi>

From: jamal <hadi@cyberus.ca>
Date: Mon, 16 Nov 2009 05:06:30 -0500

> On Mon, 2009-11-16 at 17:53 +0800, Changli Gao wrote:
> 
> Just one small comment; sorry, i missed this the first time:
> 
>> +		if (dev == NULL)
>>  			return -EINVAL;
>>  		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
>>  				     &mirred_idx_gen, &mirred_hash_info);
>>  		if (IS_ERR(pc))
>> -		    return PTR_ERR(pc);
>> +			return PTR_ERR(pc);
> 
> One indent too many? 

It's actually fixing some stray space characters into a real proper
tab character.

^ permalink raw reply

* Re: [PATCH] net/can: add driver for mscan family & mpc52xx_mscan
From: David Miller @ 2009-11-16 10:21 UTC (permalink / raw)
  To: w.sang; +Cc: wg, netdev, socketcan-core, linuxppc-dev, grant.likely
In-Reply-To: <20091116101205.GA30609@pengutronix.de>

From: Wolfram Sang <w.sang@pengutronix.de>
Date: Mon, 16 Nov 2009 11:12:05 +0100

>> >> Taken from socketcan-svn, fixed remaining todos, cleaned up, tested with a
>> >> phyCORE-MPC5200B-IO and a custom board.
>> >>
>> >> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
>> > 
>> > Applied.
>> 
>> Unfortunately too early. I will send my review tomorrow. Sorry for the
>> delay.
> 
> So, I'd assume that I now have to send an incremental patch instead of a V2?

Yes.

^ permalink raw reply

* Re: [net-next] bnx2x: Handle Rx and Tx together in NAPI
From: David Miller @ 2009-11-16 10:20 UTC (permalink / raw)
  To: vladz; +Cc: netdev, eilong
In-Reply-To: <1258365669.8392.3.camel@lb-tlvb-vladz.il.broadcom.com>

From: "Vladislav Zolotarov" <vladz@broadcom.com>
Date: Mon, 16 Nov 2009 12:01:09 +0200

>   - Limit Tx work done in one iteration by the same number of packets as
> Rx in order to ensure both fair work load balancing relatively to other
> devices scheduled for NAPI on the local CPU and sane Tx/Rx skb resource
> management from single QP perspective.

You should not do this.

RX is several orders of magnitude more work than TX is.  TX therefore
should not be charged against the NAPI polling quota.

Don't try to be different from other drivers unless you have detailed
performance numbers from various situations (local TCP flows _and_
routing) to justify it. :-)

All NAPI drivers ignore TX work when considering NAPI polling quotas
and you should too :-)

^ permalink raw reply

* Re: [PATCH 2/2] act_mirred: optimization
From: jamal @ 2009-11-16 10:06 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, Stephen Hemminger, netdev
In-Reply-To: <412e6f7f0911160153g31d5eado7c5569d9e95f7d01@mail.gmail.com>

On Mon, 2009-11-16 at 17:53 +0800, Changli Gao wrote:

Just one small comment; sorry, i missed this the first time:

> +		if (dev == NULL)
>  			return -EINVAL;
>  		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
>  				     &mirred_idx_gen, &mirred_hash_info);
>  		if (IS_ERR(pc))
> -		    return PTR_ERR(pc);
> +			return PTR_ERR(pc);

One indent too many? 

cheers,
jamal


^ permalink raw reply

* Re: [PATCH] net/can: add driver for mscan family & mpc52xx_mscan
From: Wolfram Sang @ 2009-11-16 10:12 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA, David Miller,
	grant.likely-s3s/WqlpOiPyB63q8FvJNQ,
	linuxppc-dev-mnsaURCQ41sdnm+yROfE0A
In-Reply-To: <4AFFEC2C.6000106-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>


[-- Attachment #1.1: Type: text/plain, Size: 599 bytes --]

David,

> >> Taken from socketcan-svn, fixed remaining todos, cleaned up, tested with a
> >> phyCORE-MPC5200B-IO and a custom board.
> >>
> >> Signed-off-by: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> > 
> > Applied.
> 
> Unfortunately too early. I will send my review tomorrow. Sorry for the
> delay.

So, I'd assume that I now have to send an incremental patch instead of a V2?

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

^ permalink raw reply

* [net-next] bnx2x: Handle Rx and Tx together in NAPI
From: Vladislav Zolotarov @ 2009-11-16 10:01 UTC (permalink / raw)
  To: davem; +Cc: netdev, eilong

Put Tx and Rx DPC to be handled in the NAPI:
  - Saves status blocks.
  - Moves the Tx work from hardIRQ to NAPI.
  - Limit Tx work done in one iteration by the same number of packets as
Rx in order to ensure both fair work load balancing relatively to other
devices scheduled for NAPI on the local CPU and sane Tx/Rx skb resource
management from single QP perspective.

Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/bnx2x.h      |   21 +--
 drivers/net/bnx2x_main.c |  356
+++++++++++++++++++---------------------------
 2 files changed, 155 insertions(+), 222 deletions(-)

diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 928942b..602ab86 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -259,9 +259,6 @@ struct bnx2x_eth_q_stats {
 struct bnx2x_fastpath {
 
 	struct napi_struct	napi;
-
-	u8			is_rx_queue;
-
 	struct host_status_block *status_blk;
 	dma_addr_t		status_blk_mapping;
 
@@ -970,8 +967,7 @@ struct bnx2x {
 #define BNX2X_STATE_ERROR		0xf000
 
 	int			multi_mode;
-	int			num_rx_queues;
-	int			num_tx_queues;
+	int			num_queues;
 
 	u32			rx_mode;
 #define BNX2X_RX_MODE_NONE		0
@@ -1074,20 +1070,15 @@ struct bnx2x {
 };
 
 
-#define BNX2X_MAX_QUEUES(bp)	(IS_E1HMF(bp) ? (MAX_CONTEXT/(2 *
E1HVN_MAX)) \
-					      : (MAX_CONTEXT/2))
-#define BNX2X_NUM_QUEUES(bp)	(bp->num_rx_queues + bp->num_tx_queues)
-#define is_multi(bp)		(BNX2X_NUM_QUEUES(bp) > 2)
+#define BNX2X_MAX_QUEUES(bp)	(IS_E1HMF(bp) ? (MAX_CONTEXT/E1HVN_MAX) \
+					      : MAX_CONTEXT)
+#define BNX2X_NUM_QUEUES(bp)	(bp->num_queues)
+#define is_multi(bp)		(BNX2X_NUM_QUEUES(bp) > 1)
 
-#define for_each_rx_queue(bp, var) \
-			for (var = 0; var < bp->num_rx_queues; var++)
-#define for_each_tx_queue(bp, var) \
-			for (var = bp->num_rx_queues; \
-			     var < BNX2X_NUM_QUEUES(bp); var++)
 #define for_each_queue(bp, var) \
 			for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++)
 #define for_each_nondefault_queue(bp, var) \
-			for (var = 1; var < bp->num_rx_queues; var++)
+			for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++)
 
 
 void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index e2cf686..75af1d4 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -57,7 +57,7 @@
 #include "bnx2x_init_ops.h"
 #include "bnx2x_dump.h"
 
-#define DRV_MODULE_VERSION	"1.52.1-4"
+#define DRV_MODULE_VERSION	"1.52.1-5"
 #define DRV_MODULE_RELDATE	"2009/11/09"
 #define BNX2X_BC_VER		0x040200
 
@@ -91,15 +91,10 @@ module_param(multi_mode, int, 0);
 MODULE_PARM_DESC(multi_mode, " Multi queue mode "
 			     "(0 Disable; 1 Enable (default))");
 
-static int num_rx_queues;
-module_param(num_rx_queues, int, 0);
-MODULE_PARM_DESC(num_rx_queues, " Number of Rx queues for multi_mode=1"
-				" (default is half number of CPUs)");
-
-static int num_tx_queues;
-module_param(num_tx_queues, int, 0);
-MODULE_PARM_DESC(num_tx_queues, " Number of Tx queues for multi_mode=1"
-				" (default is half number of CPUs)");
+static int num_queues;
+module_param(num_queues, int, 0);
+MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1"
+				" (default is as a number of CPUs)");
 
 static int disable_tpa;
 module_param(disable_tpa, int, 0);
@@ -558,7 +553,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
 		  bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
 
 	/* Rx */
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		BNX2X_ERR("fp%d: rx_bd_prod(%x)  rx_bd_cons(%x)"
@@ -575,7 +570,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
 	}
 
 	/* Tx */
-	for_each_tx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		BNX2X_ERR("fp%d: tx_pkt_prod(%x)  tx_pkt_cons(%x)"
@@ -590,7 +585,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
 
 	/* Rings */
 	/* Rx */
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
@@ -624,7 +619,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
 	}
 
 	/* Tx */
-	for_each_tx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
@@ -792,21 +787,13 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp,
u8 sb_id,
 	barrier();
 }
 
-static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
+static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
 {
 	struct host_status_block *fpsb = fp->status_blk;
-	u16 rc = 0;
 
 	barrier(); /* status block is written to by the chip */
-	if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) {
-		fp->fp_c_idx = fpsb->c_status_block.status_block_index;
-		rc |= 1;
-	}
-	if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) {
-		fp->fp_u_idx = fpsb->u_status_block.status_block_index;
-		rc |= 2;
-	}
-	return rc;
+	fp->fp_c_idx = fpsb->c_status_block.status_block_index;
+	fp->fp_u_idx = fpsb->u_status_block.status_block_index;
 }
 
 static u16 bnx2x_ack_int(struct bnx2x *bp)
@@ -846,6 +833,9 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp,
struct bnx2x_fastpath *fp,
 	u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
 	int nbd;
 
+	/* prefetch skb end pointer to speedup dev_kfree_skb() */
+	prefetch(&skb->end);
+
 	DP(BNX2X_MSG_OFF, "pkt_idx %d  buff @(%p)->skb %p\n",
 	   idx, tx_buf, skb);
 
@@ -890,7 +880,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp,
struct bnx2x_fastpath *fp,
 
 	/* release skb */
 	WARN_ON(!skb);
-	dev_kfree_skb_any(skb);
+	dev_kfree_skb(skb);
 	tx_buf->first_bd = 0;
 	tx_buf->skb = NULL;
 
@@ -920,23 +910,33 @@ static inline u16 bnx2x_tx_avail(struct
bnx2x_fastpath *fp)
 	return (s16)(fp->bp->tx_ring_size) - used;
 }
 
-static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
+static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
+{
+	u16 hw_cons;
+
+	/* Tell compiler that status block fields can change */
+	barrier();
+	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+	return hw_cons != fp->tx_pkt_cons;
+}
+
+static int bnx2x_tx_int(struct bnx2x_fastpath *fp, int num)
 {
 	struct bnx2x *bp = fp->bp;
 	struct netdev_queue *txq;
 	u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
-	int done = 0;
+	int cnt;
 
 #ifdef BNX2X_STOP_ON_ERROR
 	if (unlikely(bp->panic))
-		return;
+		return -1;
 #endif
 
-	txq = netdev_get_tx_queue(bp->dev, fp->index - bp->num_rx_queues);
+	txq = netdev_get_tx_queue(bp->dev, fp->index);
 	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
 	sw_cons = fp->tx_pkt_cons;
 
-	while (sw_cons != hw_cons) {
+	for (cnt = 0; (cnt < num) && (sw_cons != hw_cons); cnt++) {
 		u16 pkt_cons;
 
 		pkt_cons = TX_BD(sw_cons);
@@ -953,7 +953,6 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
 */
 		bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
 		sw_cons++;
-		done++;
 	}
 
 	fp->tx_pkt_cons = sw_cons;
@@ -975,6 +974,7 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
 		    (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
 			netif_tx_wake_queue(txq);
 	}
+	return (cnt >= num) ? 1 : 0;
 }
 
 #ifdef BCM_CNIC
@@ -1742,27 +1742,13 @@ static irqreturn_t bnx2x_msix_fp_int(int irq,
void *fp_cookie)
 	if (unlikely(bp->panic))
 		return IRQ_HANDLED;
 #endif
-	/* Handle Rx or Tx according to MSI-X vector */
-	if (fp->is_rx_queue) {
-		prefetch(fp->rx_cons_sb);
-		prefetch(&fp->status_blk->u_status_block.status_block_index);
-
-		napi_schedule(&bnx2x_fp(bp, fp->index, napi));
-
-	} else {
-		prefetch(fp->tx_cons_sb);
-		prefetch(&fp->status_blk->c_status_block.status_block_index);
 
-		bnx2x_update_fpsb_idx(fp);
-		rmb();
-		bnx2x_tx_int(fp);
-
-		/* Re-enable interrupts */
-		bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
-			     le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1);
-		bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
-			     le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1);
-	}
+	/* Handle Rx and Tx according to MSI-X vector */
+	prefetch(fp->rx_cons_sb);
+	prefetch(fp->tx_cons_sb);
+	prefetch(&fp->status_blk->u_status_block.status_block_index);
+	prefetch(&fp->status_blk->c_status_block.status_block_index);
+	napi_schedule(&bnx2x_fp(bp, fp->index, napi));
 
 	return IRQ_HANDLED;
 }
@@ -1797,31 +1783,14 @@ static irqreturn_t bnx2x_interrupt(int irq, void
*dev_instance)
 
 		mask = 0x2 << fp->sb_id;
 		if (status & mask) {
-			/* Handle Rx or Tx according to SB id */
-			if (fp->is_rx_queue) {
-				prefetch(fp->rx_cons_sb);
-				prefetch(&fp->status_blk->u_status_block.
-							status_block_index);
-
-				napi_schedule(&bnx2x_fp(bp, fp->index, napi));
-
-			} else {
-				prefetch(fp->tx_cons_sb);
-				prefetch(&fp->status_blk->c_status_block.
-							status_block_index);
-
-				bnx2x_update_fpsb_idx(fp);
-				rmb();
-				bnx2x_tx_int(fp);
-
-				/* Re-enable interrupts */
-				bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
-					     le16_to_cpu(fp->fp_u_idx),
-					     IGU_INT_NOP, 1);
-				bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
-					     le16_to_cpu(fp->fp_c_idx),
-					     IGU_INT_ENABLE, 1);
-			}
+			/* Handle Rx and Tx according to SB id */
+			prefetch(fp->rx_cons_sb);
+			prefetch(&fp->status_blk->u_status_block.
+						status_block_index);
+			prefetch(fp->tx_cons_sb);
+			prefetch(&fp->status_blk->c_status_block.
+						status_block_index);
+			napi_schedule(&bnx2x_fp(bp, fp->index, napi));
 			status &= ~mask;
 		}
 	}
@@ -4027,7 +3996,7 @@ static int bnx2x_storm_stats_update(struct bnx2x
*bp)
 	estats->no_buff_discard_hi = 0;
 	estats->no_buff_discard_lo = 0;
 
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 		int cl_id = fp->cl_id;
 		struct tstorm_per_client_stats *tclient =
@@ -4244,7 +4213,7 @@ static void bnx2x_net_stats_update(struct bnx2x
*bp)
 	nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
 
 	nstats->rx_dropped = estats->mac_discard;
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		nstats->rx_dropped +=
 			le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
 
@@ -4298,7 +4267,7 @@ static void bnx2x_drv_stats_update(struct bnx2x
*bp)
 	estats->rx_err_discard_pkt = 0;
 	estats->rx_skb_alloc_failed = 0;
 	estats->hw_csum_err = 0;
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats;
 
 		estats->driver_xoff += qstats->driver_xoff;
@@ -4329,7 +4298,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
 	if (bp->msglevel & NETIF_MSG_TIMER) {
 		struct bnx2x_fastpath *fp0_rx = bp->fp;
-		struct bnx2x_fastpath *fp0_tx = &(bp->fp[bp->num_rx_queues]);
+		struct bnx2x_fastpath *fp0_tx = bp->fp;
 		struct tstorm_per_client_stats *old_tclient =
 							&bp->fp->old_tclient;
 		struct bnx2x_eth_q_stats *qstats = &bp->fp->eth_q_stats;
@@ -4681,7 +4650,7 @@ static void bnx2x_timer(unsigned long data)
 		struct bnx2x_fastpath *fp = &bp->fp[0];
 		int rc;
 
-		bnx2x_tx_int(fp);
+		bnx2x_tx_int(fp, 1000);
 		rc = bnx2x_rx_int(fp, 1000);
 	}
 
@@ -4984,7 +4953,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
 
 	if (bp->flags & TPA_ENABLE_FLAG) {
 
-		for_each_rx_queue(bp, j) {
+		for_each_queue(bp, j) {
 			struct bnx2x_fastpath *fp = &bp->fp[j];
 
 			for (i = 0; i < max_agg_queues; i++) {
@@ -5007,16 +4976,13 @@ static void bnx2x_init_rx_rings(struct bnx2x
*bp)
 		}
 	}
 
-	for_each_rx_queue(bp, j) {
+	for_each_queue(bp, j) {
 		struct bnx2x_fastpath *fp = &bp->fp[j];
 
 		fp->rx_bd_cons = 0;
 		fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
 		fp->rx_bd_cons_sb = BNX2X_RX_SB_BD_INDEX;
 
-		/* Mark queue as Rx */
-		fp->is_rx_queue = 1;
-
 		/* "next page" elements initialization */
 		/* SGE ring */
 		for (i = 1; i <= NUM_RX_SGE_PAGES; i++) {
@@ -5122,7 +5088,7 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp)
 {
 	int i, j;
 
-	for_each_tx_queue(bp, j) {
+	for_each_queue(bp, j) {
 		struct bnx2x_fastpath *fp = &bp->fp[j];
 
 		for (i = 1; i <= NUM_TX_RINGS; i++) {
@@ -5148,10 +5114,6 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp)
 		fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
 		fp->tx_pkt = 0;
 	}
-
-	/* clean tx statistics */
-	for_each_rx_queue(bp, i)
-		bnx2x_fp(bp, i, tx_pkt) = 0;
 }
 
 static void bnx2x_init_sp_ring(struct bnx2x *bp)
@@ -5180,7 +5142,8 @@ static void bnx2x_init_context(struct bnx2x *bp)
 {
 	int i;
 
-	for_each_rx_queue(bp, i) {
+	/* Rx */
+	for_each_queue(bp, i) {
 		struct eth_context *context = bnx2x_sp(bp, context[i].eth);
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 		u8 cl_id = fp->cl_id;
@@ -5232,10 +5195,11 @@ static void bnx2x_init_context(struct bnx2x *bp)
 					       ETH_CONNECTION_TYPE);
 	}
 
-	for_each_tx_queue(bp, i) {
+	/* Tx */
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 		struct eth_context *context =
-			bnx2x_sp(bp, context[i - bp->num_rx_queues].eth);
+			bnx2x_sp(bp, context[i].eth);
 
 		context->cstorm_st_context.sb_index_number =
 						C_SB_ETH_TX_CQ_INDEX;
@@ -5263,7 +5227,7 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
 	for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
 		REG_WR8(bp, BAR_TSTRORM_INTMEM +
 			TSTORM_INDIRECTION_TABLE_OFFSET(func) + i,
-			bp->fp->cl_id + (i % bp->num_rx_queues));
+			bp->fp->cl_id + (i % bp->num_queues));
 }
 
 static void bnx2x_set_client_config(struct bnx2x *bp)
@@ -5507,7 +5471,7 @@ static void bnx2x_init_internal_func(struct bnx2x
*bp)
 		min((u32)(min((u32)8, (u32)MAX_SKB_FRAGS) *
 			  SGE_PAGE_SIZE * PAGES_PER_SGE),
 		    (u32)0xffff);
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		REG_WR(bp, BAR_USTRORM_INTMEM +
@@ -5542,7 +5506,7 @@ static void bnx2x_init_internal_func(struct bnx2x
*bp)
 		rx_pause.cqe_thr_high = 350;
 		rx_pause.sge_thr_high = 0;
 
-		for_each_rx_queue(bp, i) {
+		for_each_queue(bp, i) {
 			struct bnx2x_fastpath *fp = &bp->fp[i];
 
 			if (!fp->disable_tpa) {
@@ -5637,9 +5601,6 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32
load_code)
 #else
 		fp->sb_id = fp->cl_id;
 #endif
-		/* Suitable Rx and Tx SBs are served by the same client */
-		if (i >= bp->num_rx_queues)
-			fp->cl_id -= bp->num_rx_queues;
 		DP(NETIF_MSG_IFUP,
 		   "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  sb %d\n",
 		   i, bp, fp->status_blk, fp->cl_id, fp->sb_id);
@@ -6749,7 +6710,7 @@ static void bnx2x_free_mem(struct bnx2x *bp)
 			       sizeof(struct host_status_block));
 	}
 	/* Rx */
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 
 		/* fastpath rx rings: rx_buf rx_desc rx_comp */
 		BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
@@ -6769,7 +6730,7 @@ static void bnx2x_free_mem(struct bnx2x *bp)
 			       BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
 	}
 	/* Tx */
-	for_each_tx_queue(bp, i) {
+	for_each_queue(bp, i) {
 
 		/* fastpath tx rings: tx_buf tx_desc */
 		BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
@@ -6831,7 +6792,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
 				sizeof(struct host_status_block));
 	}
 	/* Rx */
-	for_each_rx_queue(bp, i) {
+	for_each_queue(bp, i) {
 
 		/* fastpath rx rings: rx_buf rx_desc rx_comp */
 		BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring),
@@ -6853,7 +6814,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
 				BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
 	}
 	/* Tx */
-	for_each_tx_queue(bp, i) {
+	for_each_queue(bp, i) {
 
 		/* fastpath tx rings: tx_buf tx_desc */
 		BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring),
@@ -6909,7 +6870,7 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
 {
 	int i;
 
-	for_each_tx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		u16 bd_cons = fp->tx_bd_cons;
@@ -6927,7 +6888,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
 {
 	int i, j;
 
-	for_each_rx_queue(bp, j) {
+	for_each_queue(bp, j) {
 		struct bnx2x_fastpath *fp = &bp->fp[j];
 
 		for (i = 0; i < NUM_RX_BD; i++) {
@@ -7042,12 +7003,8 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
 #endif
 	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
-
-		if (i < bp->num_rx_queues)
-			sprintf(fp->name, "%s-rx-%d", bp->dev->name, i);
-		else
-			sprintf(fp->name, "%s-tx-%d",
-				bp->dev->name, i - bp->num_rx_queues);
+		snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
+			 bp->dev->name, i);
 
 		rc = request_irq(bp->msix_table[i + offset].vector,
 				 bnx2x_msix_fp_int, 0, fp->name, fp);
@@ -7106,7 +7063,7 @@ static void bnx2x_napi_enable(struct bnx2x *bp)
 {
 	int i;
 
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		napi_enable(&bnx2x_fp(bp, i, napi));
 }
 
@@ -7114,7 +7071,7 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
 {
 	int i;
 
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		napi_disable(&bnx2x_fp(bp, i, napi));
 }
 
@@ -7410,88 +7367,60 @@ static int bnx2x_setup_multi(struct bnx2x *bp,
int index)
 
 static int bnx2x_poll(struct napi_struct *napi, int budget);
 
-static void bnx2x_set_int_mode_msix(struct bnx2x *bp, int
*num_rx_queues_out,
-				    int *num_tx_queues_out)
+static void bnx2x_set_num_queues_msix(struct bnx2x *bp)
 {
-	int _num_rx_queues = 0, _num_tx_queues = 0;
 
 	switch (bp->multi_mode) {
 	case ETH_RSS_MODE_DISABLED:
-		_num_rx_queues = 1;
-		_num_tx_queues = 1;
+		bp->num_queues = 1;
 		break;
 
 	case ETH_RSS_MODE_REGULAR:
-		if (num_rx_queues)
-			_num_rx_queues = min_t(u32, num_rx_queues,
-					       BNX2X_MAX_QUEUES(bp));
-		else
-			_num_rx_queues = min_t(u32, num_online_cpus(),
-					       BNX2X_MAX_QUEUES(bp));
-
-		if (num_tx_queues)
-			_num_tx_queues = min_t(u32, num_tx_queues,
-					       BNX2X_MAX_QUEUES(bp));
+		if (num_queues)
+			bp->num_queues = min_t(u32, num_queues,
+						  BNX2X_MAX_QUEUES(bp));
 		else
-			_num_tx_queues = min_t(u32, num_online_cpus(),
-					       BNX2X_MAX_QUEUES(bp));
-
-		/* There must be not more Tx queues than Rx queues */
-		if (_num_tx_queues > _num_rx_queues) {
-			BNX2X_ERR("number of tx queues (%d) > "
-				  "number of rx queues (%d)"
-				  "  defaulting to %d\n",
-				  _num_tx_queues, _num_rx_queues,
-				  _num_rx_queues);
-			_num_tx_queues = _num_rx_queues;
-		}
+			bp->num_queues = min_t(u32, num_online_cpus(),
+						  BNX2X_MAX_QUEUES(bp));
 		break;
 
 
 	default:
-		_num_rx_queues = 1;
-		_num_tx_queues = 1;
+		bp->num_queues = 1;
 		break;
 	}
-
-	*num_rx_queues_out = _num_rx_queues;
-	*num_tx_queues_out = _num_tx_queues;
 }
 
-static int bnx2x_set_int_mode(struct bnx2x *bp)
+static int bnx2x_set_num_queues(struct bnx2x *bp)
 {
 	int rc = 0;
 
 	switch (int_mode) {
 	case INT_MODE_INTx:
 	case INT_MODE_MSI:
-		bp->num_rx_queues = 1;
-		bp->num_tx_queues = 1;
+		bp->num_queues = 1;
 		DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
 		break;
 
 	case INT_MODE_MSIX:
 	default:
-		/* Set interrupt mode according to bp->multi_mode value */
-		bnx2x_set_int_mode_msix(bp, &bp->num_rx_queues,
-					&bp->num_tx_queues);
+		/* Set number of queues according to bp->multi_mode value */
+		bnx2x_set_num_queues_msix(bp);
 
-		DP(NETIF_MSG_IFUP, "set number of queues to: rx %d tx %d\n",
-		   bp->num_rx_queues, bp->num_tx_queues);
+		DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
+		   bp->num_queues);
 
 		/* if we can't use MSI-X we only need one fp,
 		 * so try to enable MSI-X with the requested number of fp's
 		 * and fallback to MSI or legacy INTx with one fp
 		 */
 		rc = bnx2x_enable_msix(bp);
-		if (rc) {
+		if (rc)
 			/* failed to enable MSI-X */
-			bp->num_rx_queues = 1;
-			bp->num_tx_queues = 1;
-		}
+			bp->num_queues = 1;
 		break;
 	}
-	bp->dev->real_num_tx_queues = bp->num_tx_queues;
+	bp->dev->real_num_tx_queues = bp->num_queues;
 	return rc;
 }
 
@@ -7513,16 +7442,16 @@ static int bnx2x_nic_load(struct bnx2x *bp, int
load_mode)
 
 	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
 
-	rc = bnx2x_set_int_mode(bp);
+	rc = bnx2x_set_num_queues(bp);
 
 	if (bnx2x_alloc_mem(bp))
 		return -ENOMEM;
 
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		bnx2x_fp(bp, i, disable_tpa) =
 					((bp->flags & TPA_ENABLE_FLAG) == 0);
 
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
 			       bnx2x_poll, 128);
 
@@ -7536,7 +7465,7 @@ static int bnx2x_nic_load(struct bnx2x *bp, int
load_mode)
 		}
 	} else {
 		/* Fall to INTx if failed to enable MSI-X due to lack of
-		   memory (in bnx2x_set_int_mode()) */
+		   memory (in bnx2x_set_num_queues()) */
 		if ((rc != -ENOMEM) && (int_mode != INT_MODE_INTx))
 			bnx2x_enable_msi(bp);
 		bnx2x_ack_int(bp);
@@ -7730,14 +7659,14 @@ load_error3:
 	bp->port.pmf = 0;
 	/* Free SKBs, SGEs, TPA pool and driver internals */
 	bnx2x_free_skbs(bp);
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
 load_error2:
 	/* Release IRQs */
 	bnx2x_free_irq(bp);
 load_error1:
 	bnx2x_napi_disable(bp);
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		netif_napi_del(&bnx2x_fp(bp, i, napi));
 	bnx2x_free_mem(bp);
 
@@ -7928,13 +7857,13 @@ static int bnx2x_nic_unload(struct bnx2x *bp,
int unload_mode)
 	bnx2x_free_irq(bp);
 
 	/* Wait until tx fastpath tasks complete */
-	for_each_tx_queue(bp, i) {
+	for_each_queue(bp, i) {
 		struct bnx2x_fastpath *fp = &bp->fp[i];
 
 		cnt = 1000;
 		while (bnx2x_has_tx_work_unload(fp)) {
 
-			bnx2x_tx_int(fp);
+			bnx2x_tx_int(fp, 1000);
 			if (!cnt) {
 				BNX2X_ERR("timeout waiting for queue[%d]\n",
 					  i);
@@ -8071,9 +8000,9 @@ unload_error:
 
 	/* Free SKBs, SGEs, TPA pool and driver internals */
 	bnx2x_free_skbs(bp);
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		netif_napi_del(&bnx2x_fp(bp, i, napi));
 	bnx2x_free_mem(bp);
 
@@ -10269,7 +10198,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp,
int loopback_mode, u8 link_up)
 	struct sk_buff *skb;
 	unsigned char *packet;
 	struct bnx2x_fastpath *fp_rx = &bp->fp[0];
-	struct bnx2x_fastpath *fp_tx = &bp->fp[bp->num_rx_queues];
+	struct bnx2x_fastpath *fp_tx = &bp->fp[0];
 	u16 tx_start_idx, tx_idx;
 	u16 rx_start_idx, rx_idx;
 	u16 pkt_prod, bd_prod;
@@ -10346,7 +10275,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp,
int loopback_mode, u8 link_up)
 
 	fp_tx->tx_db.data.prod += 2;
 	barrier();
-	DOORBELL(bp, fp_tx->index - bp->num_rx_queues, fp_tx->tx_db.raw);
+	DOORBELL(bp, fp_tx->index, fp_tx->tx_db.raw);
 
 	mmiowb();
 
@@ -10725,7 +10654,7 @@ static int bnx2x_get_sset_count(struct
net_device *dev, int stringset)
 	switch(stringset) {
 	case ETH_SS_STATS:
 		if (is_multi(bp)) {
-			num_stats = BNX2X_NUM_Q_STATS * bp->num_rx_queues;
+			num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
 			if (!IS_E1HMF_MODE_STAT(bp))
 				num_stats += BNX2X_NUM_STATS;
 		} else {
@@ -10756,7 +10685,7 @@ static void bnx2x_get_strings(struct net_device
*dev, u32 stringset, u8 *buf)
 	case ETH_SS_STATS:
 		if (is_multi(bp)) {
 			k = 0;
-			for_each_rx_queue(bp, i) {
+			for_each_queue(bp, i) {
 				for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
 					sprintf(buf + (k + j)*ETH_GSTRING_LEN,
 						bnx2x_q_stats_arr[j].string, i);
@@ -10793,7 +10722,7 @@ static void bnx2x_get_ethtool_stats(struct
net_device *dev,
 
 	if (is_multi(bp)) {
 		k = 0;
-		for_each_rx_queue(bp, i) {
+		for_each_queue(bp, i) {
 			hw_stats = (u32 *)&bp->fp[i].eth_q_stats;
 			for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
 				if (bnx2x_q_stats_arr[j].size == 0) {
@@ -10989,6 +10918,7 @@ static inline int bnx2x_has_rx_work(struct
bnx2x_fastpath *fp)
 
 static int bnx2x_poll(struct napi_struct *napi, int budget)
 {
+	int more_tx = 0;
 	struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
 						 napi);
 	struct bnx2x *bp = fp->bp;
@@ -11002,38 +10932,51 @@ static int bnx2x_poll(struct napi_struct
*napi, int budget)
 	prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb);
 	prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256);
 
-	bnx2x_update_fpsb_idx(fp);
+	if (bnx2x_has_tx_work(fp))
+		more_tx = bnx2x_tx_int(fp, budget);
 
-	if (bnx2x_has_rx_work(fp)) {
+	if (bnx2x_has_rx_work(fp))
 		work_done = bnx2x_rx_int(fp, budget);
 
-		/* must not complete if we consumed full budget */
-		if (work_done >= budget)
-			goto poll_again;
-	}
+	/* If there is more Tx work - push this NAPI to the
+	   end of the list. Give a runtime to other local NAPIs. */
+	if (more_tx)
+		work_done = budget;
 
-	/* bnx2x_has_rx_work() reads the status block, thus we need to
-	 * ensure that status block indices have been actually read
-	 * (bnx2x_update_fpsb_idx) prior to this check (bnx2x_has_rx_work)
-	 * so that we won't write the "newer" value of the status block to IGU
-	 * (if there was a DMA right after bnx2x_has_rx_work and
-	 * if there is no rmb, the memory reading (bnx2x_update_fpsb_idx)
-	 * may be postponed to right before bnx2x_ack_sb). In this case
-	 * there will never be another interrupt until there is another update
-	 * of the status block, while there is still unhandled work.
-	 */
-	rmb();
+	/* must not complete if we consumed full budget */
+	if (work_done >= budget)
+		goto poll_again;
 
-	if (!bnx2x_has_rx_work(fp)) {
+	/* Fall out from the NAPI loop if needed */
+	if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
 #ifdef BNX2X_STOP_ON_ERROR
 poll_panic:
 #endif
-		napi_complete(napi);
+		bnx2x_update_fpsb_idx(fp);
+		/*
+		 * bnx2x_has_rx_work() reads the status block, thus we need
+		 * to ensure that status block indices have been actually read
+		 * (bnx2x_update_fpsb_idx) prior to this check
+		 * (bnx2x_has_rx_work) so that we won't write the "newer"
+		 * value of the status block to IGU (if there was a DMA right
+		 * after bnx2x_has_rx_work and if there is no rmb, the memory
+		 * reading (bnx2x_update_fpsb_idx) may be postponed to right
+		 * before bnx2x_ack_sb). In this case there will never be
+		 * another interrupt until there is another update of the
+		 * status block, while there is still unhandled work.
+		 */
+		rmb();
 
-		bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
-			     le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1);
-		bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
-			     le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1);
+		if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+			napi_complete(napi);
+			/* Re-enable interrupts */
+			bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
+				     le16_to_cpu(fp->fp_c_idx),
+				     IGU_INT_NOP, 1);
+			bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
+				     le16_to_cpu(fp->fp_u_idx),
+				     IGU_INT_ENABLE, 1);
+		}
 	}
 
 poll_again:
@@ -11221,7 +11164,7 @@ exit_lbl:
 static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct
net_device *dev)
 {
 	struct bnx2x *bp = netdev_priv(dev);
-	struct bnx2x_fastpath *fp, *fp_stat;
+	struct bnx2x_fastpath *fp;
 	struct netdev_queue *txq;
 	struct sw_tx_bd *tx_buf;
 	struct eth_tx_start_bd *tx_start_bd;
@@ -11243,11 +11186,10 @@ static netdev_tx_t bnx2x_start_xmit(struct
sk_buff *skb, struct net_device *dev)
 	fp_index = skb_get_queue_mapping(skb);
 	txq = netdev_get_tx_queue(dev, fp_index);
 
-	fp = &bp->fp[fp_index + bp->num_rx_queues];
-	fp_stat = &bp->fp[fp_index];
+	fp = &bp->fp[fp_index];
 
 	if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) {
-		fp_stat->eth_q_stats.driver_xoff++;
+		fp->eth_q_stats.driver_xoff++;
 		netif_tx_stop_queue(txq);
 		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
 		return NETDEV_TX_BUSY;
@@ -11473,7 +11415,7 @@ static netdev_tx_t bnx2x_start_xmit(struct
sk_buff *skb, struct net_device *dev)
 
 	fp->tx_db.data.prod += nbd;
 	barrier();
-	DOORBELL(bp, fp->index - bp->num_rx_queues, fp->tx_db.raw);
+	DOORBELL(bp, fp->index, fp->tx_db.raw);
 
 	mmiowb();
 
@@ -11484,11 +11426,11 @@ static netdev_tx_t bnx2x_start_xmit(struct
sk_buff *skb, struct net_device *dev)
 		/* We want bnx2x_tx_int to "see" the updated tx_bd_prod
 		   if we put Tx into XOFF state. */
 		smp_mb();
-		fp_stat->eth_q_stats.driver_xoff++;
+		fp->eth_q_stats.driver_xoff++;
 		if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
 			netif_tx_wake_queue(txq);
 	}
-	fp_stat->tx_pkt++;
+	fp->tx_pkt++;
 
 	return NETDEV_TX_OK;
 }
@@ -12376,9 +12318,9 @@ static int bnx2x_eeh_nic_unload(struct bnx2x
*bp)
 
 	/* Free SKBs, SGEs, TPA pool and driver internals */
 	bnx2x_free_skbs(bp);
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-	for_each_rx_queue(bp, i)
+	for_each_queue(bp, i)
 		netif_napi_del(&bnx2x_fp(bp, i, napi));
 	bnx2x_free_mem(bp);
 
-- 
1.6.3.3





^ permalink raw reply related

* [PATCH 2/2] act_mirred: optimization
From: Changli Gao @ 2009-11-16  9:53 UTC (permalink / raw)
  To: Jamal Hadi Salim; +Cc: David S. Miller, Stephen Hemminger, netdev, Changli Gao

act_mirred: optimization.

move checking if eaction is valid in tcf_mirred_init()

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
----
 net/sched/act_mirred.c |   60
 +++++++++++++++++++++++--------------------------
  1 file changed, 29 insertions(+), 31 deletions(-)
--- a/net/sched/act_mirred.c	2009-11-16 16:21:21.000000000 +0800
+++ b/net/sched/act_mirred.c	2009-11-16 17:43:37.000000000 +0800
@@ -65,48 +65,53 @@
 	struct tc_mirred *parm;
 	struct tcf_mirred *m;
 	struct tcf_common *pc;
-	struct net_device *dev = NULL;
-	int ret = 0, err;
-	int ok_push = 0;
+	struct net_device *dev;
+	int ret, ok_push = 0;

 	if (nla == NULL)
 		return -EINVAL;
-
-	err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
-	if (err < 0)
-		return err;
-
+	ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
+	if (ret < 0)
+		return ret;
 	if (tb[TCA_MIRRED_PARMS] == NULL)
 		return -EINVAL;
 	parm = nla_data(tb[TCA_MIRRED_PARMS]);
-
+	switch (parm->eaction) {
+	case TCA_EGRESS_MIRROR:
+	case TCA_EGRESS_REDIR:
+		break;
+	default:
+		return -EINVAL;
+	}
 	if (parm->ifindex) {
 		dev = __dev_get_by_index(&init_net, parm->ifindex);
 		if (dev == NULL)
 			return -ENODEV;
 		switch (dev->type) {
-			case ARPHRD_TUNNEL:
-			case ARPHRD_TUNNEL6:
-			case ARPHRD_SIT:
-			case ARPHRD_IPGRE:
-			case ARPHRD_VOID:
-			case ARPHRD_NONE:
-				ok_push = 0;
-				break;
-			default:
-				ok_push = 1;
-				break;
+		case ARPHRD_TUNNEL:
+		case ARPHRD_TUNNEL6:
+		case ARPHRD_SIT:
+		case ARPHRD_IPGRE:
+		case ARPHRD_VOID:
+		case ARPHRD_NONE:
+			ok_push = 0;
+			break;
+		default:
+			ok_push = 1;
+			break;
 		}
+	} else {
+		dev = NULL;
 	}

 	pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
 	if (!pc) {
-		if (!parm->ifindex)
+		if (dev == NULL)
 			return -EINVAL;
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
 				     &mirred_idx_gen, &mirred_hash_info);
 		if (IS_ERR(pc))
-		    return PTR_ERR(pc);
+			return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
@@ -119,12 +124,12 @@
 	spin_lock_bh(&m->tcf_lock);
 	m->tcf_action = parm->action;
 	m->tcfm_eaction = parm->eaction;
-	if (parm->ifindex) {
+	if (dev != NULL) {
 		m->tcfm_ifindex = parm->ifindex;
 		if (ret != ACT_P_CREATED)
 			dev_put(m->tcfm_dev);
-		m->tcfm_dev = dev;
 		dev_hold(dev);
+		m->tcfm_dev = dev;
 		m->tcfm_ok_push = ok_push;
 	}
 	spin_unlock_bh(&m->tcf_lock);
@@ -154,13 +159,6 @@

 	spin_lock(&m->tcf_lock);
 	m->tcf_tm.lastuse = jiffies;
-	if (m->tcfm_eaction != TCA_EGRESS_MIRROR &&
-	    m->tcfm_eaction != TCA_EGRESS_REDIR) {
-		if (net_ratelimit())
-			printk("tcf_mirred unknown action %d\n",
-			       m->tcfm_eaction);
-		goto out;
-	}

 	dev = m->tcfm_dev;
 	if (!(dev->flags & IFF_UP)) {

^ permalink raw reply

* Re: [PATCH 2/2] act_mirred: optimization
From: Changli Gao @ 2009-11-16  9:40 UTC (permalink / raw)
  To: hadi; +Cc: David S. Miller, Stephen Hemminger, netdev
In-Reply-To: <1258363789.3251.30.camel@bigi>

On Mon, Nov 16, 2009 at 5:29 PM, jamal <hadi@cyberus.ca> wrote:
> On Mon, 2009-11-16 at 16:56 +0800, Changli Gao wrote:
>> act_mirred: optimization.
>>
>> 1. move checking if eaction is valid in tcf_mirred_init()
>
> This one looks ok - and like i mentioned earlier it should be
> a patch on its own. Can you please make it a separate patch,
> test it and add my signed-off?
>
>> 2. fixed a race condition between __dev_get_by_index() and dev_get()
>
> This one i am not sure. What broke to motivate the patch?
> Also note: if you moved things into _init() I am pretty sure
> we have at least rtnl held.
>

OK, I'll use the old __dev_get_by_index() and post the patch with your
signed-off again. Thanks.



-- 
Regards,
Changli Gao(xiaosuo@gmail.com)

^ permalink raw reply

* [PATCH net] net: Fix the rollback test in dev_change_name()
From: Jarek Poplawski @ 2009-11-16  9:30 UTC (permalink / raw)
  To: David Miller; +Cc: Eric Dumazet, netdev
In-Reply-To: <20091102.000549.114598716.davem@davemloft.net>

On Mon, Nov 02, 2009 at 12:05:49AM -0800, David Miller wrote:
> From: Jarek Poplawski <jarkao2@gmail.com>
> Date: Sat, 31 Oct 2009 00:50:09 +0100
> 
> > I don't think so: err stores the previous ret meaning rollback and
> > is checked for this later. But somebody forgot err can store previous
> > (positive) value here, so IMHO you're right: there is a bug in this
> > place ;-)
> 
> Just not the one Eric is specifically fixing :-)

Since this bug looks quite serious (consider -stable), here is a
proposal in case we forget what is Eric specifically fixing. ;-)

Thanks,
Jarek P.

---------------->
From: Eric Dumazet <eric.dumazet@gmail.com>

net: Fix the rollback test in dev_change_name()

In dev_change_name() an err variable is used for storing the original
call_netdevice_notifiers() errno (negative) and testing for a rollback
error later, but the test for non-zero is wrong, because the err might
have positive value as well - from dev_alloc_name(). It means the
rollback for a netdevice with a number > 0 will never happen. (The err
test is reordered btw. to make it more readable.)

Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
---

 net/core/dev.c |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index b8f74cf..fe10551 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -942,14 +942,15 @@ rollback:
 	ret = notifier_to_errno(ret);
 
 	if (ret) {
-		if (err) {
-			printk(KERN_ERR
-			       "%s: name change rollback failed: %d.\n",
-			       dev->name, ret);
-		} else {
+		/* err >= 0 after dev_alloc_name() or stores the first errno */
+		if (err >= 0) {
 			err = ret;
 			memcpy(dev->name, oldname, IFNAMSIZ);
 			goto rollback;
+		} else {
+			printk(KERN_ERR
+			       "%s: name change rollback failed: %d.\n",
+			       dev->name, ret);
 		}
 	}
 

^ permalink raw reply related

* Re: [PATCH 2/2] act_mirred: optimization
From: jamal @ 2009-11-16  9:29 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, Stephen Hemminger, netdev
In-Reply-To: <412e6f7f0911160056k6718dd55w6dcd7c7e673459c4@mail.gmail.com>

On Mon, 2009-11-16 at 16:56 +0800, Changli Gao wrote:
> act_mirred: optimization.
> 
> 1. move checking if eaction is valid in tcf_mirred_init()

This one looks ok - and like i mentioned earlier it should be
a patch on its own. Can you please make it a separate patch,
test it and add my signed-off?

> 2. fixed a race condition between __dev_get_by_index() and dev_get()

This one i am not sure. What broke to motivate the patch?
Also note: if you moved things into _init() I am pretty sure
we have at least rtnl held.

cheers,
jamal




^ permalink raw reply

* Re: [PATCH 1/2] act_mirred: cleanup
From: jamal @ 2009-11-16  9:24 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, Stephen Hemminger, netdev
In-Reply-To: <412e6f7f0911160033h649b44b2o669196b8b14bf6fc@mail.gmail.com>

On Mon, 2009-11-16 at 16:33 +0800, Changli Gao wrote:
> act_mirred: cleanup
> 
> 1. don't let go back using goto.
> 2. don't call skb_act_clone() until it is necessary.
> 3. one exit of the critical context.
> 
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>

Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>


cheers,
jamal


^ permalink raw reply

* KS8695: problem with ethernet driver
From: zeal @ 2009-11-16  9:23 UTC (permalink / raw)
  To: netdev; +Cc: Figo.zhang, Vincent Sanders, Ben Dooks

Hi,

I've two questions on the ks8695.

1. We knew recently Figo.zhang has added NAPI support for ks8695 net driver.
Thanks him. But on our ks8695 board it couldn't work well as i thought.
We used net-next-git kernel.

IP layer cannot receive any frame from lan or wan port(s).

After dig into the driver, I found the rx interrupt occurs,
but the corresponding status bit is not set. So it won't go into napi
schedule block.

        if (status & mask_bit) {
                if (napi_schedule_prep(&ksp->napi)) {
                        /*disable rx interrupt*/
                        status &= ~mask_bit;
                        writel(status , KS8695_IRQ_VA + KS8695_INTEN);
                        __napi_schedule(&ksp->napi);
                }
        }

Does anybody tested this NAPI driver succeeded before? If so it maybe
hardware issue.

2. It's a extend topic about ks8695. Does the cpu port can tell the
source port (i.e. lan port ID)
when it receive a frame from LAN ports? I think a smart switch need
know where the frame come from
and then decide where it to go. And many switch-chip in this way.
The manual can't help me at all as i've done according to it.

Any hint is appreciated.

-- 
Thanks & Regards

zeal

^ permalink raw reply

* [PATCH 2/2] act_mirred: optimization
From: Changli Gao @ 2009-11-16  8:56 UTC (permalink / raw)
  To: Jamal Hadi Salim; +Cc: David S. Miller, Stephen Hemminger, netdev, Changli Gao

act_mirred: optimization.

1. move checking if eaction is valid in tcf_mirred_init()
2. fixed a race condition between __dev_get_by_index() and dev_get()

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
 act_mirred.c |   67
 +++++++++++++++++++++++++++++------------------------------
  1 file changed, 34 insertions(+), 33 deletions(-)
--- a/net/sched/act_mirred.c	2009-11-16 16:21:21.000000000 +0800
+++ b/net/sched/act_mirred.c	2009-11-16 16:25:37.000000000 +0800
@@ -65,52 +65,61 @@
 	struct tc_mirred *parm;
 	struct tcf_mirred *m;
 	struct tcf_common *pc;
-	struct net_device *dev = NULL;
-	int ret = 0, err;
-	int ok_push = 0;
+	struct net_device *dev;
+	int ret, ok_push = 0;

 	if (nla == NULL)
 		return -EINVAL;
-
-	err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
-	if (err < 0)
-		return err;
-
+	ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
+	if (ret < 0)
+		return ret;
 	if (tb[TCA_MIRRED_PARMS] == NULL)
 		return -EINVAL;
 	parm = nla_data(tb[TCA_MIRRED_PARMS]);
-
+	switch (parm->eaction) {
+	case TCA_EGRESS_MIRROR:
+	case TCA_EGRESS_REDIR:
+		break;
+	default:
+		return -EINVAL;
+	}
 	if (parm->ifindex) {
-		dev = __dev_get_by_index(&init_net, parm->ifindex);
+		dev = dev_get_by_index(&init_net, parm->ifindex);
 		if (dev == NULL)
 			return -ENODEV;
 		switch (dev->type) {
-			case ARPHRD_TUNNEL:
-			case ARPHRD_TUNNEL6:
-			case ARPHRD_SIT:
-			case ARPHRD_IPGRE:
-			case ARPHRD_VOID:
-			case ARPHRD_NONE:
-				ok_push = 0;
-				break;
-			default:
-				ok_push = 1;
-				break;
+		case ARPHRD_TUNNEL:
+		case ARPHRD_TUNNEL6:
+		case ARPHRD_SIT:
+		case ARPHRD_IPGRE:
+		case ARPHRD_VOID:
+		case ARPHRD_NONE:
+			ok_push = 0;
+			break;
+		default:
+			ok_push = 1;
+			break;
 		}
+	} else {
+		dev = NULL;
 	}

 	pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
 	if (!pc) {
-		if (!parm->ifindex)
+		if (dev == NULL)
 			return -EINVAL;
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
 				     &mirred_idx_gen, &mirred_hash_info);
-		if (IS_ERR(pc))
-		    return PTR_ERR(pc);
+		if (IS_ERR(pc)) {
+			dev_put(dev);
+			return PTR_ERR(pc);
+		}
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
 			tcf_mirred_release(to_mirred(pc), bind);
+			if (dev != NULL)
+				dev_put(dev);
 			return -EEXIST;
 		}
 	}
@@ -119,12 +128,11 @@
 	spin_lock_bh(&m->tcf_lock);
 	m->tcf_action = parm->action;
 	m->tcfm_eaction = parm->eaction;
-	if (parm->ifindex) {
+	if (dev != NULL) {
 		m->tcfm_ifindex = parm->ifindex;
 		if (ret != ACT_P_CREATED)
 			dev_put(m->tcfm_dev);
 		m->tcfm_dev = dev;
-		dev_hold(dev);
 		m->tcfm_ok_push = ok_push;
 	}
 	spin_unlock_bh(&m->tcf_lock);
@@ -154,13 +162,6 @@

 	spin_lock(&m->tcf_lock);
 	m->tcf_tm.lastuse = jiffies;
-	if (m->tcfm_eaction != TCA_EGRESS_MIRROR &&
-	    m->tcfm_eaction != TCA_EGRESS_REDIR) {
-		if (net_ratelimit())
-			printk("tcf_mirred unknown action %d\n",
-			       m->tcfm_eaction);
-		goto out;
-	}

 	dev = m->tcfm_dev;
 	if (!(dev->flags & IFF_UP)) {

^ 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