Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH]NET/KS8695: add support NAPI for Rx
From: Daniel Silverstone @ 2009-10-26 16:27 UTC (permalink / raw)
  To: Figo.zhang; +Cc: David S. Miller, netdev, Vincent Sanders, Ben Dooks
In-Reply-To: <1256572828.2148.5.camel@myhost>

On Tue, Oct 27, 2009 at 12:00:28AM +0800, Figo.zhang wrote:
> +#ifdef KS8695NET_NAPI
> +static irqreturn_t
> +ks8695_rx_irq(int irq, void *dev_id)

This routine lacks its documentation comment.  This driver is fully documented
in order to serve as a good example for others.  Indeed this lack of
documentation comments continues through your patch, I won't bring up each
instance, instead trusting you to go back over your patch and sort them out.

> +	status = __raw_readl(KS8695_IRQ_VA + KS8695_INTST);
[snip]
> +	__raw_writel(status | mask_bit , KS8695_IRQ_VA + KS8695_INTST);
[snip]
> +			__raw_writel(status , KS8695_IRQ_VA + KS8695_INTEN);
[snip]
> +	unsigned long isr = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
[snip]
> +		__raw_writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN);

Please don't use __raw_readl or __raw_writel.  This driver was nice and clean,
don't ruin it.

Also, as an aside, you seem to add a spinlock (rx_lock) which afaict is only
used by NAPI related routines, and yet you include it regardless of NAPI being
enabled or not.  Did I misread your patch, or is this an oversight?

Regards,

Daniel.

-- 
Daniel Silverstone                              http://www.simtec.co.uk/


^ permalink raw reply

* Re: [RFC] [PATCH] udp: Don't save dst in udpv6_sendmsg()
From: Rick Jones @ 2009-10-26 16:45 UTC (permalink / raw)
  To: David Miller; +Cc: krkumar2, netdev
In-Reply-To: <20091024.064010.145864194.davem@davemloft.net>

David Miller wrote:
> From: Krishna Kumar <krkumar2@in.ibm.com>
> Date: Fri, 23 Oct 2009 16:43:36 +0530
> 
> 
>>Performance: I ran netperf UDPv6 RR to use connected sockets.
>>Tested with a 70 min run, aggregate of 5 netperf runs for
>>each result.
> 
> 
> Who actually uses connected UDP sockets? :-)

Somebody must, they sent me patches to optionally connect() the endpoints in a 
UDP_RR test :)

rick jones

trying to decide if he should by default set SO_DONTROUTE on UDP sockets to 
cover the backsides of testers who cause link-down events on devices under test 
with systems connected to their employer's site lans with the default route 
pointing at same...

^ permalink raw reply

* Re: [PATCH v3 4/7] Add the no SACK route option feature
From: William Allen Simpson @ 2009-10-26 16:38 UTC (permalink / raw)
  To: Gilad Ben-Yossef; +Cc: netdev, ori
In-Reply-To: <1256544393-12450-5-git-send-email-gilad@codefidence.com>

Gilad Ben-Yossef wrote:
> Implement querying and acting upon the no sack bit in the features
> field.
> 
> Signed-off-by: Gilad Ben-Yossef <gilad@codefidence.com>
> Sigend-off-by: Ori Finkelman <ori@comsleep.com>
> Sigend-off-by: Yony Amit <yony@comsleep.com>
> 
Please explain how this code turns SACK on when it is off globally?

As both Eric and I asked?

^ permalink raw reply

* Re: iwl3945, after a while stops working with "No space for Tx"
From: reinette chatre @ 2009-10-26 16:25 UTC (permalink / raw)
  To: Frederik Nosi
  Cc: Zhu, Yi, Intel Linux Wireless, John W. Linville, Winkler, Tomas,
	Kolekar, Abhijeet, linux-wireless@vger.kernel.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <177253.23325.qm@web53903.mail.re2.yahoo.com>

On Sat, 2009-10-24 at 06:44 -0700, Frederik Nosi wrote:
> Hi,
> first sorry if somebody is not the right contact, got the adressess from ./scripts/get_maintainer.pl -f drivers/net/wireless/iwlwifi.
> From some kernel versions now, after some time that im using this card it stops working and on messages i get this errors:
> 
> Oct 24 14:38:24 kotys NetworkManager: <info>  Activation (wlan0) Stage 5 of 5 (IP Configure Commit) complete.
> [snip pulseaudio's stuppid log spam warning]
> Oct 24 14:40:07 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_TX_PWR_TABLE_CMD: time out after 500ms.
> Oct 24 14:40:09 kotys pulseaudio[16469]: sap.c: sendmsg() failed: Invalid argument
> Oct 24 14:40:10 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_SCAN_CMD: time out after 500ms.
> Oct 24 14:40:11 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_TX_PWR_TABLE_CMD: time out after 500ms.
> Oct 24 14:40:11 kotys kernel: iwl3945 0000:04:00.0: Error sending POWER_TABLE_CMD: time out after 500ms.
> Oct 24 14:40:14 kotys kernel: iwl3945 0000:04:00.0: set power fail, ret = -110
> Oct 24 14:40:14 kotys kernel: No probe response from AP 00:1c:df:82:63:c9 after 500ms, disconnecting.
> Oct 24 14:40:14 kotys NetworkManager: <info>  (wlan0): supplicant connection state:  completed -> disconnected
> Oct 24 14:40:14 kotys NetworkManager: <info>  (wlan0): supplicant connection state:  disconnected -> scanning
> Oct 24 14:40:14 kotys pulseaudio[16469]: sap.c: sendmsg() failed: Invalid argument
> Oct 24 14:40:14 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_RXON: time out after 500ms.
> Oct 24 14:40:14 kotys kernel: iwl3945 0000:04:00.0: Error setting new configuration (-110).
> Oct 24 14:40:15 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_SCAN_CMD: time out after 500ms.
> Oct 24 14:40:15 kotys kernel: wlan0: direct probe to AP 00:1c:df:82:63:c9 (try 1)
> Oct 24 14:40:15 kotys NetworkManager: <info>  (wlan0): supplicant connection state:  scanning -> associating
> Oct 24 14:40:15 kotys kernel: wlan0: direct probe to AP 00:1c:df:82:63:c9 (try 2)
> Oct 24 14:40:15 kotys kernel: wlan0: direct probe to AP 00:1c:df:82:63:c9 (try 3)
> Oct 24 14:40:15 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_RXON: time out after 500ms.
> Oct 24 14:40:15 kotys kernel: iwl3945 0000:04:00.0: Error setting new configuration (-110).
> Oct 24 14:40:15 kotys kernel: wlan0: direct probe to AP 00:1c:df:82:63:c9 timed out
> Oct 24 14:40:16 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_TX_PWR_TABLE_CMD: time out after 500ms.
> Oct 24 14:40:16 kotys kernel: iwl3945 0000:04:00.0: Error sending REPLY_RXON: time out after 500ms.
> Oct 24 14:40:16 kotys kernel: iwl3945 0000:04:00.0: Error setting new configuration (-110).
> 
> 
> When this happens i am able to use the card only after reloading the related modules, iwl3945 ecc. But the problem happens again after some minutes that im connected.
> 
> Kernel is 2.6.32-rc5 but his started happening around 2.6.31, not sure exactly what version as i update kernel often. Firmware is iwl3945-ucode-15.32.2.9.
> 
> Every other info that you need just ask. I hope i dont have to bisect as this is the laptop i use for work too, but if it's needed i'll do.
> 
> I'm not subscribed on any ML, so in case please cc me.
> 

We currently have a bug open for this issue. Could you please add this
information to
http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=1944 ?

Thank you

Reinette




^ permalink raw reply

* [PATCH] vlan: allow VLAN ID 0 to be used
From: Eric Dumazet @ 2009-10-26 16:13 UTC (permalink / raw)
  Cc: Benny Amorsen, Gertjan Hofman, Matt Carlson,
	netdev@vger.kernel.org, Patrick McHardy, David S. Miller
In-Reply-To: <4AE563C7.5070702@gmail.com>

Eric Dumazet a écrit :
> VLAN id 0 is not usable on current kernel because we use 16 bits in skb to
>  store vlan_tci, and vlan_tci = 0 means there is no VLAN tagging.
> 
> 
> We could use high order bit (0x8000) to tell if vlan tagging is set or not.
> 

Here is the patch I cooked that permitted VLAN 0 to be used with tg3
(and other HW accelerated vlan nics I suppose)

[PATCH] vlan: allow VLAN ID 0 to be used

We currently use a 16 bit field (vlan_tci) to store VLAN ID on a skb.

0 value is used a special value, meaning VLAN ID not set.
This forbids use of VLAN ID 0

As VLAN ID is 12 bits, we can use high order bit as a flag, and
allow VLAN ID 0

Reported-by: Gertjan Hofman <gertjan_hofman@yahoo.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 7ff9af1..7dfcdb5 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -105,8 +105,9 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
 	array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
 }
 
-#define vlan_tx_tag_present(__skb)	((__skb)->vlan_tci)
-#define vlan_tx_tag_get(__skb)		((__skb)->vlan_tci)
+#define VLAN_TAG_PRESENT		0x8000
+#define vlan_tx_tag_present(__skb)	((__skb)->vlan_tci & VLAN_TAG_PRESENT)
+#define vlan_tx_tag_get(__skb)		((__skb)->vlan_tci & 0x7fff)
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
@@ -231,7 +232,7 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
 static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
 						     u16 vlan_tci)
 {
-	skb->vlan_tci = vlan_tci;
+	skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci;
 	return skb;
 }
 
@@ -284,7 +285,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
 					 u16 *vlan_tci)
 {
 	if (vlan_tx_tag_present(skb)) {
-		*vlan_tci = skb->vlan_tci;
+		*vlan_tci = vlan_tx_tag_get(skb);
 		return 0;
 	} else {
 		*vlan_tci = 0;

^ permalink raw reply related

* [PATCH]NET/KS8695: add support NAPI for Rx
From: Figo.zhang @ 2009-10-26 16:00 UTC (permalink / raw)
  To: Daniel Silverstone, David S. Miller; +Cc: netdev, Vincent Sanders, Ben Dooks


Add support NAPI Rx API for KS8695NET driver.

Signed-off-by: Figo.zhang <figo1802@gmail.com>
--- 
drivers/net/arm/ks8695net.c |  165 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 165 insertions(+), 0 deletions(-)

diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index 2a7b774..7f9d4bd 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -35,12 +35,16 @@
 
 #include <mach/regs-switch.h>
 #include <mach/regs-misc.h>
+#include <asm/mach/irq.h>
+#include <mach/regs-irq.h>
 
 #include "ks8695net.h"
 
 #define MODULENAME	"ks8695_ether"
 #define MODULEVERSION	"1.01"
 
+#define KS8695NET_NAPI  1
+
 /*
  * Transmit and device reset timeout, default 5 seconds.
  */
@@ -152,6 +156,10 @@ struct ks8695_priv {
 	enum ks8695_dtype dtype;
 	void __iomem *io_regs;
 
+	#ifdef KS8695NET_NAPI
+	struct napi_struct	napi;
+	#endif
+
 	const char *rx_irq_name, *tx_irq_name, *link_irq_name;
 	int rx_irq, tx_irq, link_irq;
 
@@ -172,6 +180,7 @@ struct ks8695_priv {
 	dma_addr_t rx_ring_dma;
 	struct ks8695_skbuff rx_buffers[MAX_RX_DESC];
 	int next_rx_desc_read;
+	spinlock_t rx_lock;
 
 	int msg_enable;
 };
@@ -391,6 +400,155 @@ ks8695_tx_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+#ifdef KS8695NET_NAPI
+static irqreturn_t
+ks8695_rx_irq(int irq, void *dev_id)
+{
+	struct net_device *ndev = (struct net_device *)dev_id;
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	unsigned long status;
+
+	unsigned long mask_bit = 1 << ksp->rx_irq;
+
+	spin_lock(&ksp->rx_lock);
+
+	status = __raw_readl(KS8695_IRQ_VA + KS8695_INTST);
+
+	/*clean rx status bit*/
+	__raw_writel(status | mask_bit , KS8695_IRQ_VA + KS8695_INTST);
+
+	if (status & mask_bit) {
+		if (napi_schedule_prep(&ksp->napi)) {
+			/*disable rx interrupt*/
+			status &= ~mask_bit;
+			__raw_writel(status , KS8695_IRQ_VA + KS8695_INTEN);
+			__napi_schedule(&ksp->napi);
+		}
+	}
+
+	spin_unlock(&ksp->rx_lock);
+	return IRQ_HANDLED;
+}
+
+static int ks8695_rx(struct net_device *ndev, int budget)
+{
+	struct ks8695_priv *ksp = netdev_priv(ndev);
+	struct sk_buff *skb;
+	int buff_n;
+	u32 flags;
+	int pktlen;
+	int last_rx_processed = -1;
+	int received = 0;
+
+	buff_n = ksp->next_rx_desc_read;
+	while (netif_running(ndev) && received < budget
+			&& ksp->rx_buffers[buff_n].skb
+			&& (!(ksp->rx_ring[buff_n].status &
+					cpu_to_le32(RDES_OWN)))) {
+			rmb();
+			flags = le32_to_cpu(ksp->rx_ring[buff_n].status);
+			/* Found an SKB which we own, this means we
+			 * received a packet
+			 */
+			if ((flags & (RDES_FS | RDES_LS)) !=
+			    (RDES_FS | RDES_LS)) {
+				/* This packet is not the first and
+				 * the last segment.  Therefore it is
+				 * a "spanning" packet and we can't
+				 * handle it
+				 */
+				goto rx_failure;
+			}
+
+			if (flags & (RDES_ES | RDES_RE)) {
+				/* It's an error packet */
+				ndev->stats.rx_errors++;
+				if (flags & RDES_TL)
+					ndev->stats.rx_length_errors++;
+				if (flags & RDES_RF)
+					ndev->stats.rx_length_errors++;
+				if (flags & RDES_CE)
+					ndev->stats.rx_crc_errors++;
+				if (flags & RDES_RE)
+					ndev->stats.rx_missed_errors++;
+
+				goto rx_failure;
+			}
+
+			pktlen = flags & RDES_FLEN;
+			pktlen -= 4; /* Drop the CRC */
+
+			/* Retrieve the sk_buff */
+			skb = ksp->rx_buffers[buff_n].skb;
+
+			/* Clear it from the ring */
+			ksp->rx_buffers[buff_n].skb = NULL;
+			ksp->rx_ring[buff_n].data_ptr = 0;
+
+			/* Unmap the SKB */
+			dma_unmap_single(ksp->dev,
+					 ksp->rx_buffers[buff_n].dma_ptr,
+					 ksp->rx_buffers[buff_n].length,
+					 DMA_FROM_DEVICE);
+
+			/* Relinquish the SKB to the network layer */
+			skb_put(skb, pktlen);
+			skb->protocol = eth_type_trans(skb, ndev);
+			netif_receive_skb(skb);
+
+			/* Record stats */
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += pktlen;
+			goto rx_finished;
+
+rx_failure:
+			/* This ring entry is an error, but we can
+			 * re-use the skb
+			 */
+			/* Give the ring entry back to the hardware */
+			ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
+rx_finished:
+			received++;
+			/* And note this as processed so we can start
+			 * from here next time
+			 */
+			last_rx_processed = buff_n;
+			buff_n = (buff_n + 1) & MAX_RX_DESC_MASK;
+			/*And note which RX descriptor we last did */
+			if (likely(last_rx_processed != -1))
+				ksp->next_rx_desc_read =
+					(last_rx_processed + 1) &
+					MAX_RX_DESC_MASK;
+
+			/* And refill the buffers */
+			ks8695_refill_rxbuffers(ksp);
+	}
+	return received;
+}
+
+static int ks8695_poll(struct napi_struct *napi, int budget)
+{
+	struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi);
+	struct net_device *dev = ksp->ndev;
+	unsigned long mask_bit = 1 << ksp->rx_irq;
+	unsigned long isr = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
+
+	unsigned long  work_done = 0;
+
+	work_done = ks8695_rx(dev, budget);
+
+	if (work_done < budget) {
+		unsigned long flags;
+		spin_lock_irqsave(&ksp->rx_lock, flags);
+		/*enable rx interrupt*/
+		__raw_writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN);
+		__napi_complete(napi);
+		spin_unlock_irqrestore(&ksp->rx_lock, flags);
+	}
+	return work_done;
+}
+
+#else
 /**
  *	ks8695_rx_irq - Receive IRQ handler
  *	@irq: The IRQ which went off (ignored)
@@ -503,6 +661,8 @@ rx_finished:
 	return IRQ_HANDLED;
 }
 
+#endif
+
 /**
  *	ks8695_link_irq - Link change IRQ handler
  *	@irq: The IRQ which went off (ignored)
@@ -1472,6 +1632,10 @@ ks8695_probe(struct platform_device *pdev)
 	SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
 	ndev->watchdog_timeo	 = msecs_to_jiffies(watchdog);
 
+#ifdef KS8695NET_NAPI
+	netif_napi_add(ndev, &ksp->napi, ks8695_poll, 64);
+#endif
+
 	/* Retrieve the default MAC addr from the chip. */
 	/* The bootloader should have left it in there for us. */
 
@@ -1505,6 +1669,7 @@ ks8695_probe(struct platform_device *pdev)
 
 	/* And initialise the queue's lock */
 	spin_lock_init(&ksp->txq_lock);
+	spin_lock_init(&ksp->rx_lock);
 
 	/* Specify the RX DMA ring buffer */
 	ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE;



^ permalink raw reply related

* Re: [PATCH next-next-2.6] netdev: better dev_name_hash
From: Octavian Purdila @ 2009-10-26 15:52 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Krishna Kumar2, Hagen Paul Pfeifer, netdev
In-Reply-To: <4AE5B84E.8040505@gmail.com>

On Monday 26 October 2009 16:55:10 you wrote:
> 
> This is because you chose a 65536 slots hash table, to store 16000 elements
> 
> The ideal function should be :
> 
> $ ./dev_name_hash ixunc 16000 5 16
> score 16000
> 
> unsigned int dev_name_hash_new10bis(const char *name)
> {
> 	unsigned hash = 0;
> 	int len = strnlen(name, IFNAMSIZ);
> 	int i;
> 
> 	for (i = 0; i < len; ++i)
> 		hash = 10 * hash + (name[i] - '0');
> 	return hash;
> }
> 

Eric, thanks a lot for your help. This is turning into a very instructive 
thread for me :)

10bis performs better for ixunc but interestingly performs worse for ixint 
now. I also get mixed results for the two when using other names like ppp or 
gtp.

2 - new10, 3 - new10bis

score 49852
$ ./dev_name_hash ixint 32000 3 14
score 53194
$ ./dev_name_hash ixunc 32000 2 14
score 55232
$ ./dev_name_hash ixunc 32000 3 14
score 48168

> But should we really care ?

I'm just testing various common cases we use here ({ixint,ixunc,gtp,ppp,gre} 
{1000,16000,32000,128000} {14,16}). 

Ideally we want a hash function that performs better in all cases  - but I 
understand that it may not be possible.

I will play more with it and see if I can come up with something better, but 
in any case the new{10,10bis,17,31} performs much better than full_name_hash 
and most of the time better that jhash .

^ permalink raw reply

* Re: [PATCH v2 8/8] Document future removal of sysctl_tcp_* options
From: Gilad Ben-Yossef @ 2009-10-26 15:51 UTC (permalink / raw)
  To: Bill Fink; +Cc: Eric Dumazet, William Allen Simpson, netdev, Ilpo Järvinen
In-Reply-To: <20091026110855.98a19f7a.billfink@mindspring.com>

Bill Fink wrote:

>
>> OK. It really sounds like we should go with my first suggestion: global 
>> sysctl based kill switches, just as we have now and in addition, the 
>> ability to kill TCP options per route. The TCP option will be used if 
>> and only if both kill switches (global and per route) are not set.
>>     
>
> This wording is confusing.  The global kill switch not being set
> really means that the sysctl is set.  And this assumes the per-route
> default is not set.  Correct?
>   
Now it is my turn to get confused, because I didn't understand your 
question :-)

What I suggest is to leave the sysctl exactly as they are now:

- You leave them be (value of 1), the respective TCP option is 
supported. This is the default.
- You turn them off (write 0), the respective TCP option is not supported.

What I suggest to *add* is the following ability:

- If you have the TCP option support turned on (default, value of one), 
you can turn support for the option for a specific route using a ip 
route option.

Hope that made it clearer.
>   
>> What we achieve is:
>>
>> 1. Global kill switches work exactly as they do now, whether you use the 
>> new per route options or not, so backwards compatible.
>>
>> 2. In addition, if the global kill switch is not in effect, you can also 
>> kill the options on a per route basis.
>>
>> I'm going to send third version of the patch to this effect, minus the 
>> new remote DoS possibility that Ilpo pointed out and leaving the global 
>> sysctl kill switches be.
>>
>> If you like it, please ACK ;-)
>>     
>
> IIUC this doesn't seem right to me.  I believe the global setting
> should be a default and the route specific an override.  Your scheme
> would mean that if I set a global option to disable timestamps, then
> I couldn't enable timestamps on specific routes using the per route
> setting.
>   
Yes. You understand my intention perfectly.

Let me try to explain why I believe this is the correct behavior to 
implement:

1. This is the closest thing to what we have now. Today you write 0 to 
the sysctl and that TCP option is turned off globally. Period.  My 
suggestion leaves this behavior as is now regardless if you've used per 
route settings. The other way make a very subtle change in the meaning 
of writing 0 to the sysctl.

I believe very subtle changes to meaning of long established interfaces 
is bad way to go. It's better to change interfaces on users, but it is 
even worse to maek something that they have long used do something just 
slightly different.

2. If the per route options needs to be "default, of or off" instead of 
"on or off", we'd need to move from 1 bit to store the option to, well 
2s bit in theory, but probably 32 bits in practice, since we can't use 
RTAX_FEATURES any longer.

Yes, we can invent RTAX_FEATURES_TWO_BITS or some such, but I'd say that 
is ugly :-)

3. I believe that the scenario of needing to set the support of a TCP 
option globally off and just turn it on for a specific route is not very 
likely to be needed and losing it is a small price to pay for 1 + 2.


> And it also doesn't seem to address Eric's scenario.  If I understand
> his concern correctly, what seems to be needed is a third global
> reset value (not calling it a setting since the actual global setting
> wouldn't be changed), which would reset any per-route override settings
> to the global default setting.
>
>   
Well, I do not believe this is what Eric meant (Eric?) but if it is then 
I fail to see why
to require from the per route TCP options switches what is not required 
of any other
route specific option already existing, since AFAIK we don't have a 
"reset to default values" to the other options already supported.


Having said all that, I have no issue with re-spinning the patch with 
your suggestion.
I don't feel all that much which is the correct way- I just want to get 
as much feedback as possible
since I'm suggesting to add a new user interface options and we all know 
it is very hard to back peddle
on those, so I'm trying to make sure to get enough feedback to do it 
right the firs time.

So any feedback from anyone regarding favorite interface? it seems each 
person fancy a different one :-)

Thanks!
Gilad



-- 
Gilad Ben-Yossef
Chief Coffee Drinker & CTO
Codefidence Ltd.

Web:   http://codefidence.com
Cell:  +972-52-8260388
Skype: gilad_codefidence
Tel:   +972-8-9316883 ext. 201
Fax:   +972-8-9316884
Email: gilad@codefidence.com

Check out our Open Source technology and training blog - http://tuxology.net

	"The biggest risk you can take it is to take no risk."
		-- Mark Zuckerberg and probably others


^ permalink raw reply

* [PATCH] can: sja1000: fix bug using library functions for skb allocation
From: Wolfgang Grandegger @ 2009-10-26 15:46 UTC (permalink / raw)
  To: Linux Netdev List; +Cc: Socketcan-core@lists.berlios.de, Kurt Van Dijck

Commit 7b6856a0 "can: provide library functions for skb allocation"
did not properly remove two lines of the SJA1000 driver resulting in
a 'skb_over_panic' when calling skb_put, as reported by Kurt.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck@eia.be>
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
 drivers/net/can/sja1000/sja1000.c |    2 --
 1 file changed, 2 deletions(-)

Index: net-next-2.6/drivers/net/can/sja1000/sja1000.c
===================================================================
--- net-next-2.6.orig/drivers/net/can/sja1000/sja1000.c
+++ net-next-2.6/drivers/net/can/sja1000/sja1000.c
@@ -321,8 +321,6 @@ static void sja1000_rx(struct net_device
 	if (fi & FI_RTR)
 		id |= CAN_RTR_FLAG;

-	cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
-	memset(cf, 0, sizeof(struct can_frame));
 	cf->can_id = id;
 	cf->can_dlc = dlc;
 	for (i = 0; i < dlc; i++)

^ permalink raw reply

* Fw: [Bug 14470] New: freez in TCP stack
From: Stephen Hemminger @ 2009-10-26 15:41 UTC (permalink / raw)
  To: netdev



Begin forwarded message:

Date: Mon, 26 Oct 2009 12:47:22 GMT
From: bugzilla-daemon@bugzilla.kernel.org
To: shemminger@linux-foundation.org
Subject: [Bug 14470] New: freez in TCP stack


http://bugzilla.kernel.org/show_bug.cgi?id=14470

           Summary: freez in TCP stack
           Product: Networking
           Version: 2.5
    Kernel Version: 2.6.31
          Platform: All
        OS/Version: Linux
              Tree: Mainline
            Status: NEW
          Severity: high
          Priority: P1
         Component: IPV4
        AssignedTo: shemminger@linux-foundation.org
        ReportedBy: kolo@albatani.cz
        Regression: No


We are hiting kernel panics on Dell R610 servers with e1000e NICs; it apears
usualy under a high network trafic ( around 100Mbit/s) but it is not a rule it
has happened even on low trafic.

Servers are used as reverse http proxy (varnish).

On 6 equal servers this panic happens aprox 2 times a day depending on network
load. Machine completly freezes till the management watchdog reboots. 


We had to put serial console on these servers to catch the oops. Is there
anything else We can do to debug this?
The RIP is always the same:

RIP: 0010:[<ffffffff814203cc>]  [<ffffffff814203cc>]
tcp_xmit_retransmit_queue+0x8c/0x290

rest of the oops always differs a litle ... here is an example:

RIP: 0010:[<ffffffff814203cc>]  [<ffffffff814203cc>]
tcp_xmit_retransmit_queue+0x8c/0x290
RSP: 0018:ffffc90000003a40  EFLAGS: 00010246
RAX: ffff8807e7420678 RBX: ffff8807e74205c0 RCX: 0000000000000000
RDX: 000000004598a105 RSI: 0000000000000000 RDI: ffff8807e74205c0
RBP: ffffc90000003a80 R08: 0000000000000003 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
R13: ffff8807e74205c0 R14: ffff8807e7420678 R15: 0000000000000000
FS:  0000000000000000(0000) GS:ffffc90000000000(0000) knlGS:0000000000000000
CS:  0010 DS: 0018 ES: 0018 CR0: 000000008005003b
CR2: 0000000000000000 CR3: 0000000001001000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process swapper (pid: 0, threadinfo ffffffff81608000, task ffffffff81631440)
Stack:
 ffffc90000003a60 0000000000000000 4598a105e74205c0 000000004598a101
<0> 000000000000050e ffff8807e74205c0 0000000000000003 0000000000000000
<0> ffffc90000003b40 ffffffff8141ae4a ffff8807e7420678 0000000000000000
Call Trace:
 <IRQ>
 [<ffffffff8141ae4a>] tcp_ack+0x170a/0x1dd0
 [<ffffffff8141c362>] tcp_rcv_state_process+0x122/0xab0
 [<ffffffff81422c6c>] tcp_v4_do_rcv+0xac/0x220
 [<ffffffff813fd02f>] ? nf_iterate+0x5f/0x90
 [<ffffffff81424b26>] tcp_v4_rcv+0x586/0x6b0
 [<ffffffff813fd0c5>] ? nf_hook_slow+0x65/0xf0
 [<ffffffff81406b70>] ? ip_local_deliver_finish+0x0/0x120
 [<ffffffff81406bcf>] ip_local_deliver_finish+0x5f/0x120
 [<ffffffff8140715b>] ip_local_deliver+0x3b/0x90
 [<ffffffff81406971>] ip_rcv_finish+0x141/0x340
 [<ffffffff8140701f>] ip_rcv+0x24f/0x350
 [<ffffffff813e7ced>] netif_receive_skb+0x20d/0x2f0
 [<ffffffff813e7e90>] napi_skb_finish+0x40/0x50
 [<ffffffff813e82f4>] napi_gro_receive+0x34/0x40
 [<ffffffff8133e0c8>] e1000_receive_skb+0x48/0x60
 [<ffffffff81342342>] e1000_clean_rx_irq+0xf2/0x330
 [<ffffffff813410a1>] e1000_clean+0x81/0x2a0
 [<ffffffff81054ce1>] ? ktime_get+0x11/0x50
 [<ffffffff813eaf1c>] net_rx_action+0x9c/0x130
 [<ffffffff81046940>] ? get_next_timer_interrupt+0x1d0/0x210
 [<ffffffff81041bd7>] __do_softirq+0xb7/0x160
 [<ffffffff8100c27c>] call_softirq+0x1c/0x30
 [<ffffffff8100e04d>] do_softirq+0x3d/0x80
 [<ffffffff81041b0b>] irq_exit+0x7b/0x90
 [<ffffffff8100d613>] do_IRQ+0x73/0xe0
 [<ffffffff8100bb13>] ret_from_intr+0x0/0xa
 <EOI>
 [<ffffffff81296e6c>] ? acpi_idle_enter_bm+0x245/0x271
 [<ffffffff81296e62>] ? acpi_idle_enter_bm+0x23b/0x271
 [<ffffffff813c7a08>] ? cpuidle_idle_call+0x98/0xf0
 [<ffffffff8100a104>] ? cpu_idle+0x94/0xd0
 [<ffffffff81468db6>] ? rest_init+0x66/0x70
 [<ffffffff816a082f>] ? start_kernel+0x2ef/0x340
 [<ffffffff8169fd54>] ? x86_64_start_reservations+0x84/0x90
 [<ffffffff8169fe32>] ? x86_64_start_kernel+0xd2/0x100
Code: 00 eb 28 8b 83 d0 03 00 00 41 39 44 24 40 0f 89 00 01 00 00 41 0f b6 cd
41 bd 2f 00 00 00 83 e1 03 0f 84 fc 00 00 00 4d 8b 24 24 <49> 8b 04 24 4d 39 f4
0f 18 08 0f 84 d9 00 00 00 4c 3b a3 b8 01
RIP  [<ffffffff814203cc>] tcp_xmit_retransmit_queue+0x8c/0x290
 RSP <ffffc90000003a40>
CR2: 0000000000000000
---[ end trace d97d99c9ae1d52cc ]---
Kernel panic - not syncing: Fatal exception in interrupt
Pid: 0, comm: swapper Tainted: G      D    2.6.31 #2
Call Trace:
 <IRQ>  [<ffffffff8103cab0>] panic+0xa0/0x170
 [<ffffffff8100bb13>] ? ret_from_intr+0x0/0xa
 [<ffffffff8103c74e>] ? print_oops_end_marker+0x1e/0x20
 [<ffffffff8100f38e>] oops_end+0x9e/0xb0
 [<ffffffff81025b9a>] no_context+0x15a/0x250
 [<ffffffff81025e2b>] __bad_area_nosemaphore+0xdb/0x1c0
 [<ffffffff813e89e9>] ? dev_hard_start_xmit+0x269/0x2f0
 [<ffffffff81025fae>] bad_area_nosemaphore+0xe/0x10
 [<ffffffff8102639f>] do_page_fault+0x17f/0x260
 [<ffffffff8147eadf>] page_fault+0x1f/0x30
 [<ffffffff814203cc>] ? tcp_xmit_retransmit_queue+0x8c/0x290
 [<ffffffff8141ae4a>] tcp_ack+0x170a/0x1dd0
 [<ffffffff8141c362>] tcp_rcv_state_process+0x122/0xab0
 [<ffffffff81422c6c>] tcp_v4_do_rcv+0xac/0x220
 [<ffffffff813fd02f>] ? nf_iterate+0x5f/0x90
 [<ffffffff81424b26>] tcp_v4_rcv+0x586/0x6b0
 [<ffffffff813fd0c5>] ? nf_hook_slow+0x65/0xf0
 [<ffffffff81406b70>] ? ip_local_deliver_finish+0x0/0x120
 [<ffffffff81406bcf>] ip_local_deliver_finish+0x5f/0x120
 [<ffffffff8140715b>] ip_local_deliver+0x3b/0x90
 [<ffffffff81406971>] ip_rcv_finish+0x141/0x340
 [<ffffffff8140701f>] ip_rcv+0x24f/0x350
 [<ffffffff813e7ced>] netif_receive_skb+0x20d/0x2f0
 [<ffffffff813e7e90>] napi_skb_finish+0x40/0x50
 [<ffffffff813e82f4>] napi_gro_receive+0x34/0x40
 [<ffffffff8133e0c8>] e1000_receive_skb+0x48/0x60
 [<ffffffff81342342>] e1000_clean_rx_irq+0xf2/0x330
 [<ffffffff813410a1>] e1000_clean+0x81/0x2a0
 [<ffffffff81054ce1>] ? ktime_get+0x11/0x50
 [<ffffffff813eaf1c>] net_rx_action+0x9c/0x130
 [<ffffffff81046940>] ? get_next_timer_interrupt+0x1d0/0x210
 [<ffffffff81041bd7>] __do_softirq+0xb7/0x160
 [<ffffffff8100c27c>] call_softirq+0x1c/0x30
 [<ffffffff8100e04d>] do_softirq+0x3d/0x80
 [<ffffffff81041b0b>] irq_exit+0x7b/0x90
 [<ffffffff8100d613>] do_IRQ+0x73/0xe0
 [<ffffffff8100bb13>] ret_from_intr+0x0/0xa
 <EOI>  [<ffffffff81296e6c>] ? acpi_idle_enter_bm+0x245/0x271
 [<ffffffff81296e62>] ? acpi_idle_enter_bm+0x23b/0x271
 [<ffffffff813c7a08>] ? cpuidle_idle_call+0x98/0xf0
 [<ffffffff8100a104>] ? cpu_idle+0x94/0xd0
 [<ffffffff81468db6>] ? rest_init+0x66/0x70
 [<ffffffff816a082f>] ? start_kernel+0x2ef/0x340
 [<ffffffff8169fd54>] ? x86_64_start_reservations+0x84/0x90
 [<ffffffff8169fe32>] ? x86_64_start_kernel+0xd2/0x100

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


-- 

^ permalink raw reply

* Re: [RFC] make per interface sysctl entries configurable
From: Denys Fedoryschenko @ 2009-10-26 15:24 UTC (permalink / raw)
  To: Octavian Purdila
  Cc: Eric Dumazet, Benjamin LaHaise, Stephen Hemminger, Cosmin Ratiu,
	netdev
In-Reply-To: <200910251954.49700.opurdila@ixiacom.com>

I test it on pppoe with 1k customers. It works flawlessly.

When there is problem on network and i have massive users disconnect and then 
login, the bottleneck is in lock somewhere in creation of sysctl(according 
perf). PPPoE after 200-300 interfaces will start dying, and connection rate 
will drop to 20-50 customers per minute, load average will jump to 70-100 (i 
guess pppd processes waiting their turn). With this patch i am able to 
sustain 200-300 customers / minute login rate and perftop is "clear" now.

Definitely this option is optional, and doesn't cut any functionality by 
default, just giving more choice. And for PPP (pppoe/pptp) NAS it is very 
useful.

On Sunday 25 October 2009 19:54:49 Octavian Purdila wrote:
> RFC patches are attached.
>
> Another possible approach: add an interface flag and use it to decide
> whether we want per interface sysctl entries or not.
>
> Benchmarks for creating 1000 interface (with the ndst module previously
> posted on the list, ppc750 @800Mhz machine):
>
> - without the patches:
>
> real    4m 38.27s
> user    0m 0.00s
> sys     2m 18.90s
>
> - with the patches:
>
> real    0m 0.10s
> user    0m 0.00s
> sys     0m 0.05s
>
> Thanks,
> tavi



^ permalink raw reply

* Re: Increasing TCP initial cwnd
From: Yair Gottdenker @ 2009-10-26 15:07 UTC (permalink / raw)
  To: Ilpo Järvinen, netdev
In-Reply-To: <alpine.DEB.2.00.0910261629040.19761@wel-95.cs.helsinki.fi>

Thanks,

I already had a look in it. Their changes that are related to changing
the initial cwnd  (snd_cwnd) are in several places in the patch:
1. tcp_ipv4.c in function tcp_init_cwnd. since currently I am working
with no metric this is irrelevant.
2. tcp_ipv4.c: in function tcp_v4_init_sock, which I applied
3. tcp_minisocks.c - which I applied
. They patched kernel 2.6.18.8 which is very old and there were a lot
of changes since that in the kernel tcp layer. I didn't test their
patch but applying the same logic to 2.6.31.3 doesn't seems to change
initial window size.

It is clear that in order to correctly make the change to the initial
cwnd, one should apply changes to many more scenarios like setting the
initial cwnd after idle time and more. I want to proceed step by step,
first the naive changes to make it work.




On Mon, Oct 26, 2009 at 4:38 PM, Ilpo Järvinen
<ilpo.jarvinen@helsinki.fi> wrote:
> On Mon, 26 Oct 2009, Yair Gottdenker wrote:
>
>> Thanks for the response.
>> I disabled metric by: net.ipv4.tcp_no_metrics_save = 1 in sysctl.conf.
>> But just after the call to tcp_init_metrics in tcp_input.c there is
>> also a call to: tcp_init_congestion_control which calls the congestion
>> control algorithm that is in used. I created my own and in the init
>> function I set the snd_cwnd to 10 and still there is no change and
>> only 4 segments are initially sent.
>> You are right tcp_slow_start has nothing to do with the cwnd size, I
>> mistakenly thought that the initial flow enters that function.
>
> Hopefully you don't mess up anything in there.
>
> Please see from http://www.cs.helsinki.fi/research/iwtcp/kernel-patch/
> I haven't had time/interest to bring it up to date but at least there's
> very clearly shown how the initial window can be configured through a
> sysctl (though don't try to patch it to late kernels, it would just be
> a never ending pain for you :-)).
>
>> What do you mean RW? do you mean tcp read/write buffer size?
>
> RW = Restart Window (RFC2681 IIRC, nowadays also in RFC 5681 I think).
> ...It is related to slow-start after idle.
>
> --
>  i.
>

^ permalink raw reply

* Re: [PATCH v2 8/8] Document future removal of sysctl_tcp_* options
From: Bill Fink @ 2009-10-26 15:08 UTC (permalink / raw)
  To: Gilad Ben-Yossef
  Cc: Eric Dumazet, William Allen Simpson, netdev, Ilpo Järvinen
In-Reply-To: <4AE5585E.5010108@codefidence.com>

On Mon, 26 Oct 2009, Gilad Ben-Yossef wrote:

> Eric Dumazet wrote:
> 
> > Bill Fink a écrit :
> >   
> >> On Sun, 25 Oct 2009, Gilad Ben-Yossef wrote:
> >>
> >>     
> >>> Eric Dumazet wrote:
> >>>
> >>>
> >>> I still think having a global kill switch and per route options better 
> >>> (basically use the exiting patch but not retire the global kill 
> >>> switch|), but if you must Hgow about we leave the global sysctl as they 
> >>> are and just have a two bit route option:
> >>>
> >>> 0 Use global default
> >>> 1 Off
> >>> 2 On
> >>>
> >>> It's kind of funny, because this is what the original patch from 
> >>> Comsleep does and I thought it needlessly complicates things.
> >>>
> >>> So, what do you say - which will it be?
> >>>       
> >> I personally feel the 2-bit settings are overkill.  What i think
> >> makes the most sense is for the global options to act as they always
> >> have in the absence of any route specific settings, and for any
> >> route specific settings to override the related global settings.
> >> This is both simple and maintains backward compatibility.
> >>     
> >
> > Backward compatibility is important, very important, if not the most
> > important thing. Then usability comes.
> >   
> I tend to agree.
> > I know some busy servers where adding/changing a single route makes them
> > go crazy (because of ip route flush cache)
> >
> > So if a route is overriding a global conf, and the admin wants to make an
> > emergency change during peak hours, he should do it by a global setting,
> > or he wont use at all this new stuff, and stay conservative.
> >
> > Alternative would be to not trigger the flush of cache when changing
> > features flags.
> >
> >   
> OK. It really sounds like we should go with my first suggestion: global 
> sysctl based kill switches, just as we have now and in addition, the 
> ability to kill TCP options per route. The TCP option will be used if 
> and only if both kill switches (global and per route) are not set.

This wording is confusing.  The global kill switch not being set
really means that the sysctl is set.  And this assumes the per-route
default is not set.  Correct?

> What we achieve is:
> 
> 1. Global kill switches work exactly as they do now, whether you use the 
> new per route options or not, so backwards compatible.
> 
> 2. In addition, if the global kill switch is not in effect, you can also 
> kill the options on a per route basis.
> 
> I'm going to send third version of the patch to this effect, minus the 
> new remote DoS possibility that Ilpo pointed out and leaving the global 
> sysctl kill switches be.
> 
> If you like it, please ACK ;-)

IIUC this doesn't seem right to me.  I believe the global setting
should be a default and the route specific an override.  Your scheme
would mean that if I set a global option to disable timestamps, then
I couldn't enable timestamps on specific routes using the per route
setting.

And it also doesn't seem to address Eric's scenario.  If I understand
his concern correctly, what seems to be needed is a third global
reset value (not calling it a setting since the actual global setting
wouldn't be changed), which would reset any per-route override settings
to the global default setting.

						-Bill

^ permalink raw reply

* [PATCH v1 7/7] gianfar: Basic Support for programming hash rules
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch provides basic hash rules programming via the ethtool
interface.

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/gianfar.c         |   73 +++++++++++++
 drivers/net/gianfar.h         |   93 ++++++++++++++++
 drivers/net/gianfar_ethtool.c |  236 +++++++++++++++++++++++++++++++++++++++++
 include/linux/ethtool.h       |    2 +
 4 files changed, 404 insertions(+), 0 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index a60e05f..c9179d7 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -416,6 +416,9 @@ static const struct net_device_ops gfar_netdev_ops = {
 #endif
 };
 
+unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
+unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
+
 inline void lock_rx_qs(struct gfar_private *priv)
 {
 	int i = 0x0;
@@ -751,6 +754,73 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
 	}
 	return new_bit_map;
 }
+
+u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class)
+{
+	u32 rqfpr = FPR_FILER_MASK;
+	u32 rqfcr = 0x0;
+
+	rqfar--;
+	rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT;
+	ftp_rqfpr[rqfar] = rqfpr;
+	ftp_rqfcr[rqfar] = rqfcr;
+	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+	rqfar--;
+	rqfcr = RQFCR_CMP_NOMATCH;
+	ftp_rqfpr[rqfar] = rqfpr;
+	ftp_rqfcr[rqfar] = rqfcr;
+	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+	rqfar--;
+	rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND;
+	rqfpr = class;
+	ftp_rqfcr[rqfar] = rqfcr;
+	ftp_rqfpr[rqfar] = rqfpr;
+	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+	rqfar--;
+	rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND;
+	rqfpr = class;
+	ftp_rqfcr[rqfar] = rqfcr;
+	ftp_rqfpr[rqfar] = rqfpr;
+	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+	return rqfar;
+}
+
+static void gfar_init_filer_table(struct gfar_private *priv)
+{
+	int i = 0x0;
+	u32 rqfar = MAX_FILER_IDX;
+	u32 rqfcr = 0x0;
+	u32 rqfpr = FPR_FILER_MASK;
+
+	/* Default rule */
+	rqfcr = RQFCR_CMP_MATCH;
+	ftp_rqfcr[rqfar] = rqfcr;
+	ftp_rqfpr[rqfar] = rqfpr;
+	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
+
+	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6);
+	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_UDP);
+	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_TCP);
+	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4);
+	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP);
+	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP);
+
+	/* cur_filer_idx indicated the fisrt non-masked rule */
+	priv->cur_filer_idx = rqfar;
+
+	/* Rest are masked rules */
+	rqfcr = RQFCR_CMP_NOMATCH;
+	for (i = 0; i < rqfar; i++) {
+		ftp_rqfcr[i] = rqfcr;
+		ftp_rqfpr[i] = rqfpr;
+		gfar_write_filer(priv, i, rqfcr, rqfpr);
+	}
+}
+
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
 static int gfar_probe(struct of_device *ofdev,
@@ -990,6 +1060,9 @@ static int gfar_probe(struct of_device *ofdev,
 			priv->gfargrp[i].int_name_tx[len_devname] = '\0';
 	}
 
+	/* Initialize the filer table */
+	gfar_init_filer_table(priv);
+
 	/* Create all the sysfs files */
 	gfar_init_sysfs(dev);
 
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index a43b238..1c9fdea 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -381,6 +381,84 @@ extern const char gfar_driver_version[];
 #define BD_LFLAG(flags) ((flags) << 16)
 #define BD_LENGTH_MASK		0x0000ffff
 
+#define CLASS_CODE_UNRECOG		0x00
+#define CLASS_CODE_DUMMY1		0x01
+#define CLASS_CODE_ETHERTYPE1		0x02
+#define CLASS_CODE_ETHERTYPE2		0x03
+#define CLASS_CODE_USER_PROG1		0x04
+#define CLASS_CODE_USER_PROG2		0x05
+#define CLASS_CODE_USER_PROG3		0x06
+#define CLASS_CODE_USER_PROG4		0x07
+#define CLASS_CODE_TCP_IPV4		0x08
+#define CLASS_CODE_UDP_IPV4		0x09
+#define CLASS_CODE_AH_ESP_IPV4		0x0a
+#define CLASS_CODE_SCTP_IPV4		0x0b
+#define CLASS_CODE_TCP_IPV6		0x0c
+#define CLASS_CODE_UDP_IPV6		0x0d
+#define CLASS_CODE_AH_ESP_IPV6		0x0e
+#define CLASS_CODE_SCTP_IPV6		0x0f
+
+#define FPR_FILER_MASK	0xFFFFFFFF
+#define MAX_FILER_IDX	0xFF
+
+/* RQFCR register bits */
+#define RQFCR_GPI		0x80000000
+#define RQFCR_HASHTBL_Q		0x00000000
+#define RQFCR_HASHTBL_0		0x00020000
+#define RQFCR_HASHTBL_1		0x00040000
+#define RQFCR_HASHTBL_2		0x00060000
+#define RQFCR_HASHTBL_3		0x00080000
+#define RQFCR_HASH		0x00010000
+#define RQFCR_CLE		0x00000200
+#define RQFCR_RJE		0x00000100
+#define RQFCR_AND		0x00000080
+#define RQFCR_CMP_EXACT		0x00000000
+#define RQFCR_CMP_MATCH		0x00000020
+#define RQFCR_CMP_NOEXACT	0x00000040
+#define RQFCR_CMP_NOMATCH	0x00000060
+
+/* RQFCR PID values */
+#define	RQFCR_PID_MASK		0x00000000
+#define	RQFCR_PID_PARSE		0x00000001
+#define	RQFCR_PID_ARB		0x00000002
+#define	RQFCR_PID_DAH		0x00000003
+#define	RQFCR_PID_DAL		0x00000004
+#define	RQFCR_PID_SAH		0x00000005
+#define	RQFCR_PID_SAL		0x00000006
+#define	RQFCR_PID_ETY		0x00000007
+#define	RQFCR_PID_VID		0x00000008
+#define	RQFCR_PID_PRI		0x00000009
+#define	RQFCR_PID_TOS		0x0000000A
+#define	RQFCR_PID_L4P		0x0000000B
+#define	RQFCR_PID_DIA		0x0000000C
+#define	RQFCR_PID_SIA		0x0000000D
+#define	RQFCR_PID_DPT		0x0000000E
+#define	RQFCR_PID_SPT		0x0000000F
+
+/* RQFPR when PID is 0x0001 */
+#define RQFPR_HDR_GE_512	0x00200000
+#define RQFPR_LERR		0x00100000
+#define RQFPR_RAR		0x00080000
+#define RQFPR_RARQ		0x00040000
+#define RQFPR_AR		0x00020000
+#define RQFPR_ARQ		0x00010000
+#define RQFPR_EBC		0x00008000
+#define RQFPR_VLN		0x00004000
+#define RQFPR_CFI		0x00002000
+#define RQFPR_JUM		0x00001000
+#define RQFPR_IPF		0x00000800
+#define RQFPR_FIF		0x00000400
+#define RQFPR_IPV4		0x00000200
+#define RQFPR_IPV6		0x00000100
+#define RQFPR_ICC		0x00000080
+#define RQFPR_ICV		0x00000040
+#define RQFPR_TCP		0x00000020
+#define RQFPR_UDP		0x00000010
+#define RQFPR_TUC		0x00000008
+#define RQFPR_TUV		0x00000004
+#define RQFPR_PER		0x00000002
+#define RQFPR_EER		0x00000001
+
 /* TxBD status field bits */
 #define TXBD_READY		0x8000
 #define TXBD_PADCRC		0x4000
@@ -958,6 +1036,8 @@ struct gfar_private {
 	unsigned int rx_stash_size;
 	unsigned int rx_stash_index;
 
+	u32 cur_filer_idx;
+
 	struct sk_buff_head rx_recycle;
 
 	struct vlan_group *vlgrp;
@@ -1001,6 +1081,9 @@ struct gfar_private {
 	struct gfar_extra_stats extra_stats;
 };
 
+extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
+extern unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
+
 static inline u32 gfar_read(volatile unsigned __iomem *addr)
 {
 	u32 val;
@@ -1013,6 +1096,16 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
 	out_be32(addr, val);
 }
 
+static inline void gfar_write_filer(struct gfar_private *priv,
+		unsigned int far, unsigned int fcr, unsigned int fpr)
+{
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
+
+	gfar_write(&regs->rqfar, far);
+	gfar_write(&regs->rqfcr, fcr);
+	gfar_write(&regs->rqfpr, fpr);
+}
+
 extern inline void lock_rx_qs(struct gfar_private *priv);
 extern inline void lock_tx_qs(struct gfar_private *priv);
 extern inline void unlock_rx_qs(struct gfar_private *priv);
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 562f6c2..1010367 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -645,6 +645,241 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 }
 #endif
 
+static int gfar_ethflow_to_class(int flow_type, u64 *class)
+{
+	switch (flow_type) {
+	case TCP_V4_FLOW:
+		*class = CLASS_CODE_TCP_IPV4;
+		break;
+	case UDP_V4_FLOW:
+		*class = CLASS_CODE_UDP_IPV4;
+		break;
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+		*class = CLASS_CODE_AH_ESP_IPV4;
+		break;
+	case SCTP_V4_FLOW:
+		*class = CLASS_CODE_SCTP_IPV4;
+		break;
+	case TCP_V6_FLOW:
+		*class = CLASS_CODE_TCP_IPV6;
+		break;
+	case UDP_V6_FLOW:
+		*class = CLASS_CODE_UDP_IPV6;
+		break;
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+		*class = CLASS_CODE_AH_ESP_IPV6;
+		break;
+	case SCTP_V6_FLOW:
+		*class = CLASS_CODE_SCTP_IPV6;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
+{
+	u32 fcr = 0x0, fpr = FPR_FILER_MASK;
+
+	if (ethflow & RXH_L2DA) {
+		fcr = RQFCR_PID_DAH |RQFCR_CMP_NOMATCH |
+			RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+
+		fcr = RQFCR_PID_DAL | RQFCR_AND | RQFCR_CMP_NOMATCH |
+				RQFCR_HASH | RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	if (ethflow & RXH_VLAN) {
+		fcr = RQFCR_PID_VID | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+				RQFCR_AND | RQFCR_HASHTBL_0;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	if (ethflow & RXH_IP_SRC) {
+		fcr = RQFCR_PID_SIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+			RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	if (ethflow & (RXH_IP_DST)) {
+		fcr = RQFCR_PID_DIA | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+			RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	if (ethflow & RXH_L3_PROTO) {
+		fcr = RQFCR_PID_L4P | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+			RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	if (ethflow & RXH_L4_B_0_1) {
+		fcr = RQFCR_PID_SPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+			RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	if (ethflow & RXH_L4_B_2_3) {
+		fcr = RQFCR_PID_DPT | RQFCR_CMP_NOMATCH | RQFCR_HASH |
+			RQFCR_AND | RQFCR_HASHTBL_0;
+		ftp_rqfpr[priv->cur_filer_idx] = fpr;
+		ftp_rqfcr[priv->cur_filer_idx] = fcr;
+		gfar_write_filer(priv, priv->cur_filer_idx, fcr, fpr);
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+}
+
+static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u64 class)
+{
+	unsigned int last_rule_idx = priv->cur_filer_idx;
+	unsigned int cmp_rqfpr;
+	unsigned int local_rqfpr[MAX_FILER_IDX + 1];
+	unsigned int local_rqfcr[MAX_FILER_IDX + 1];
+	int i = 0x0, k = 0x0;
+	int j = MAX_FILER_IDX, l = 0x0;
+
+	switch (class) {
+	case TCP_V4_FLOW:
+		cmp_rqfpr = RQFPR_IPV4 |RQFPR_TCP;
+		break;
+	case UDP_V4_FLOW:
+		cmp_rqfpr = RQFPR_IPV4 |RQFPR_UDP;
+		break;
+	case TCP_V6_FLOW:
+		cmp_rqfpr = RQFPR_IPV6 |RQFPR_TCP;
+		break;
+	case UDP_V6_FLOW:
+		cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP;
+		break;
+	case IPV4_FLOW:
+		cmp_rqfpr = RQFPR_IPV4;
+	case IPV6_FLOW:
+		cmp_rqfpr = RQFPR_IPV6;
+		break;
+	default:
+		printk(KERN_ERR "Right now this class is not supported\n");
+		return 0;
+	}
+
+	for (i = 0; i < MAX_FILER_IDX + 1; i++) {
+		local_rqfpr[j] = ftp_rqfpr[i];
+		local_rqfcr[j] = ftp_rqfcr[i];
+		j--;
+		if ((ftp_rqfcr[i] == (RQFCR_PID_PARSE |
+			RQFCR_CLE |RQFCR_AND)) &&
+			(ftp_rqfpr[i] == cmp_rqfpr))
+			break;
+	}
+
+	if (i == MAX_FILER_IDX + 1) {
+		printk(KERN_ERR "No parse rule found, ");
+		printk(KERN_ERR "can't create hash rules\n");
+		return 0;
+	}
+
+	/* If a match was found, then it begins the starting of a cluster rule
+	 * if it was already programmed, we need to overwrite these rules
+	 */
+	for (l = i+1; l < MAX_FILER_IDX; l++) {
+		if ((ftp_rqfcr[l] & RQFCR_CLE) &&
+			!(ftp_rqfcr[l] & RQFCR_AND)) {
+			ftp_rqfcr[l] = RQFCR_CLE | RQFCR_CMP_EXACT |
+				RQFCR_HASHTBL_0 | RQFCR_PID_MASK;
+			ftp_rqfpr[l] = FPR_FILER_MASK;
+			gfar_write_filer(priv, l, ftp_rqfcr[l], ftp_rqfpr[l]);
+			break;
+		}
+
+		if (!(ftp_rqfcr[l] & RQFCR_CLE) && (ftp_rqfcr[l] & RQFCR_AND))
+			continue;
+		else {
+			local_rqfpr[j] = ftp_rqfpr[l];
+			local_rqfcr[j] = ftp_rqfcr[l];
+			j--;
+		}
+	}
+
+	priv->cur_filer_idx = l - 1;
+	last_rule_idx = l;
+
+	/* hash rules */
+	ethflow_to_filer_rules(priv, ethflow);
+
+	/* Write back the popped out rules again */
+	for (k = j+1; k < MAX_FILER_IDX; k++) {
+		ftp_rqfpr[priv->cur_filer_idx] = local_rqfpr[k];
+		ftp_rqfcr[priv->cur_filer_idx] = local_rqfcr[k];
+		gfar_write_filer(priv, priv->cur_filer_idx,
+				local_rqfcr[k], local_rqfpr[k]);
+		if (!priv->cur_filer_idx)
+			break;
+		priv->cur_filer_idx = priv->cur_filer_idx - 1;
+	}
+
+	return 1;
+}
+
+static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
+{
+	u64 class;
+
+	if (!gfar_ethflow_to_class(cmd->flow_type, &class))
+		return -EINVAL;
+
+	if (class < CLASS_CODE_USER_PROG1 ||
+			class > CLASS_CODE_SCTP_IPV6)
+		return -EINVAL;
+
+	/* write the filer rules here */
+	if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type))
+		return -1;
+
+	return 0;
+}
+
+static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	int ret = 0;
+
+	switch(cmd->cmd) {
+	case ETHTOOL_SRXFH:
+		ret = gfar_set_hash_opts(priv, cmd);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 const struct ethtool_ops gfar_ethtool_ops = {
 	.get_settings = gfar_gsettings,
 	.set_settings = gfar_ssettings,
@@ -670,4 +905,5 @@ const struct ethtool_ops gfar_ethtool_ops = {
 	.get_wol = gfar_get_wol,
 	.set_wol = gfar_set_wol,
 #endif
+	.set_rxnfc = gfar_set_nfc,
 };
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index eb1a48d..edd03b7 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -674,6 +674,8 @@ struct ethtool_ops {
 #define	AH_V6_FLOW	0x0b
 #define	ESP_V6_FLOW	0x0c
 #define	IP_USER_FLOW	0x0d
+#define IPV4_FLOW       0x10
+#define IPV6_FLOW       0x11
 
 /* L3-L4 network traffic flow hash options */
 #define	RXH_L2DA	(1 << 1)
-- 
1.5.2.2


^ permalink raw reply related

* [PATCH v1 6/7] gianfar: Add Multiple group Support
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch introduces multiple group support for etsec2.0
devices.

Multiple group support is provided by mapping the set of enabled
queues to different groups and then programming the per group
regsiters imask, ievent, rstat, tstat.

The queues corresponding to a group are indicated by programming
isrg (interrupt steering) registers.

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/gianfar.c         |  532 +++++++++++++++++++++++++++--------------
 drivers/net/gianfar.h         |   29 +++-
 drivers/net/gianfar_ethtool.c |   58 +++--
 drivers/net/gianfar_sysfs.c   |   12 +-
 4 files changed, 422 insertions(+), 209 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 82da5d9..a60e05f 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -241,7 +241,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 	struct device *dev = &priv->ofdev->dev;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 *baddr;
 
 	priv->total_tx_ring_size = 0;
@@ -334,19 +334,13 @@ cleanup:
 static void gfar_init_mac(struct net_device *ndev)
 {
 	struct gfar_private *priv = netdev_priv(ndev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 rctrl = 0;
 	u32 tctrl = 0;
 	u32 attrs = 0;
 
 	/* Configure the coalescing support */
-	gfar_write(&regs->txic, 0);
-	if (priv->tx_queue[0]->txcoalescing)
-		gfar_write(&regs->txic, priv->tx_queue[0]->txic);
-
-	gfar_write(&regs->rxic, 0);
-	if (priv->rx_queue[0]->rxcoalescing)
-		gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
+	gfar_configure_coalescing(priv, 0xFF, 0xFF);
 
 	if (priv->rx_filer_enable)
 		rctrl |= RCTRL_FILREN;
@@ -480,16 +474,91 @@ static void free_rx_pointers(struct gfar_private *priv)
 		kfree(priv->rx_queue[i]);
 }
 
+static void unmap_group_regs(struct gfar_private *priv)
+{
+	int i = 0;
+
+	for (i = 0; i < MAXGROUPS; i++)
+		if (priv->gfargrp[i].regs)
+			iounmap(priv->gfargrp[i].regs);
+}
+
+static void disable_napi(struct gfar_private *priv)
+{
+	int i = 0;
+
+	for (i = 0; i < priv->num_grps; i++)
+		napi_disable(&priv->gfargrp[i].napi);
+}
+
+static void enable_napi(struct gfar_private *priv)
+{
+	int i = 0;
+
+	for (i = 0; i < priv->num_grps; i++)
+		napi_enable(&priv->gfargrp[i].napi);
+}
+
+static int gfar_parse_group(struct device_node *np,
+		struct gfar_private *priv, const char *model)
+{
+	u32 *queue_mask;
+	u64 addr, size;
+
+	addr = of_translate_address(np,
+			of_get_address(np, 0, &size, NULL));
+	priv->gfargrp[priv->num_grps].regs = ioremap(addr, size);
+
+	if (!priv->gfargrp[priv->num_grps].regs)
+		return -ENOMEM;
+
+	priv->gfargrp[priv->num_grps].interruptTransmit =
+			irq_of_parse_and_map(np, 0);
+
+	/* If we aren't the FEC we have multiple interrupts */
+	if (model && strcasecmp(model, "FEC")) {
+		priv->gfargrp[priv->num_grps].interruptReceive =
+			irq_of_parse_and_map(np, 1);
+		priv->gfargrp[priv->num_grps].interruptError =
+			irq_of_parse_and_map(np,2);
+		if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 ||
+			priv->gfargrp[priv->num_grps].interruptReceive < 0 ||
+			priv->gfargrp[priv->num_grps].interruptError < 0) {
+			return -EINVAL;
+		}
+	}
+
+	priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
+	priv->gfargrp[priv->num_grps].priv = priv;
+	spin_lock_init(&priv->gfargrp[priv->num_grps].grplock);
+	if(priv->mode == MQ_MG_MODE) {
+		queue_mask = (u32 *)of_get_property(np,
+					"fsl,rx-bit-map", NULL);
+		priv->gfargrp[priv->num_grps].rx_bit_map =
+			queue_mask ?  *queue_mask :(DEFAULT_MAPPING >> priv->num_grps);
+		queue_mask = (u32 *)of_get_property(np,
+					"fsl,tx-bit-map", NULL);
+		priv->gfargrp[priv->num_grps].tx_bit_map =
+			queue_mask ? *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
+	} else {
+		priv->gfargrp[priv->num_grps].rx_bit_map = 0xFF;
+		priv->gfargrp[priv->num_grps].tx_bit_map = 0xFF;
+	}
+	priv->num_grps++;
+
+	return 0;
+}
+
 static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
 {
 	const char *model;
 	const char *ctype;
 	const void *mac_addr;
-	u64 addr, size;
 	int err = 0, i;
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
 	struct device_node *np = ofdev->node;
+	struct device_node *child = NULL;
 	const u32 *stash;
 	const u32 *stash_len;
 	const u32 *stash_idx;
@@ -533,36 +602,26 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
 	dev->real_num_tx_queues = num_tx_qs;
 	priv->num_tx_queues = num_tx_qs;
 	priv->num_rx_queues = num_rx_qs;
-
-	/* get a pointer to the register memory */
-	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
-	priv->gfargrp.regs = ioremap(addr, size);
-
-	if (priv->gfargrp.regs == NULL) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	priv->gfargrp.priv = priv; /* back pointer from group to priv */
-	priv->gfargrp.rx_bit_map = DEFAULT_MAPPING;
-	priv->gfargrp.tx_bit_map = DEFAULT_MAPPING;
-
-	priv->gfargrp.interruptTransmit = irq_of_parse_and_map(np, 0);
+	priv->num_grps = 0x0;
 
 	model = of_get_property(np, "model", NULL);
 
-	/* If we aren't the FEC we have multiple interrupts */
-	if (model && strcasecmp(model, "FEC")) {
-		priv->gfargrp.interruptReceive = irq_of_parse_and_map(np, 1);
+	for (i = 0; i < MAXGROUPS; i++)
+		priv->gfargrp[i].regs = NULL;
 
-		priv->gfargrp.interruptError = irq_of_parse_and_map(np, 2);
-
-		if (priv->gfargrp.interruptTransmit < 0 ||
-				priv->gfargrp.interruptReceive < 0 ||
-				priv->gfargrp.interruptError < 0) {
-			err = -EINVAL;
-			goto err_out;
+	/* Parse and initialize group specific information */
+	if (of_device_is_compatible(np, "fsl,etsec2")) {
+		priv->mode = MQ_MG_MODE;
+		for_each_child_of_node(np, child) {
+			err = gfar_parse_group(child, priv, model);
+			if (err)
+				goto err_grp_init;
 		}
+	} else {
+		priv->mode = SQ_SG_MODE;
+		err = gfar_parse_group(np, priv, model);
+		if(err)
+			goto err_grp_init;
 	}
 
 	for (i = 0; i < priv->num_tx_queues; i++)
@@ -661,8 +720,8 @@ rx_alloc_failed:
 	free_rx_pointers(priv);
 tx_alloc_failed:
 	free_tx_pointers(priv);
-err_out:
-	iounmap(priv->gfargrp.regs);
+err_grp_init:
+	unmap_group_regs(priv);
 	free_netdev(dev);
 	return err;
 }
@@ -701,9 +760,11 @@ static int gfar_probe(struct of_device *ofdev,
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
 	struct gfar __iomem *regs = NULL;
-	int err = 0, i;
+	int err = 0, i, grp_idx = 0;
 	int len_devname;
 	u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
+	u32 isrg = 0;
+	u32 *baddr;
 
 	err = gfar_of_init(ofdev, &dev);
 
@@ -716,12 +777,11 @@ static int gfar_probe(struct of_device *ofdev,
 	priv->node = ofdev->node;
 	SET_NETDEV_DEV(dev, &ofdev->dev);
 
-	spin_lock_init(&priv->gfargrp.grplock);
 	spin_lock_init(&priv->bflock);
 	INIT_WORK(&priv->reset_task, gfar_reset_task);
 
 	dev_set_drvdata(&ofdev->dev, priv);
-	regs = priv->gfargrp.regs;
+	regs = priv->gfargrp[0].regs;
 
 	/* Stop the DMA engine now, in case it was running before */
 	/* (The firmware could have used it, and left it running). */
@@ -754,7 +814,8 @@ static int gfar_probe(struct of_device *ofdev,
 	dev->ethtool_ops = &gfar_ethtool_ops;
 
 	/* Register for napi ...We are registering NAPI for each grp */
-	netif_napi_add(dev, &priv->gfargrp.napi, gfar_poll, GFAR_DEV_WEIGHT);
+	for (i = 0; i < priv->num_grps; i++)
+		netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT);
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
 		priv->rx_csum_enable = 1;
@@ -810,25 +871,51 @@ static int gfar_probe(struct of_device *ofdev,
 	if (dev->features & NETIF_F_IP_CSUM)
 		dev->hard_header_len += GMAC_FCB_LEN;
 
+	/* Program the isrg regs only if number of grps > 1 */
+	if (priv->num_grps > 1) {
+		baddr = &regs->isrg0;
+		for (i = 0; i < priv->num_grps; i++) {
+			isrg |= (priv->gfargrp[i].rx_bit_map << ISRG_SHIFT_RX);
+			isrg |= (priv->gfargrp[i].tx_bit_map << ISRG_SHIFT_TX);
+			gfar_write(baddr, isrg);
+			baddr++;
+			isrg = 0x0;
+		}
+	}
+
 	/* Need to reverse the bit maps as  bit_map's MSB is q0
 	 * but, for_each_bit parses from right to left, which
 	 * basically reverses the queue numbers */
-	priv->gfargrp.tx_bit_map = reverse_bitmap(priv->gfargrp.tx_bit_map, MAX_TX_QS);
-	priv->gfargrp.rx_bit_map = reverse_bitmap(priv->gfargrp.rx_bit_map, MAX_RX_QS);
-
-	/* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values */
-	for_each_bit(i, &priv->gfargrp.rx_bit_map, priv->num_rx_queues) {
-		priv->gfargrp.num_rx_queues++;
-		rstat = rstat | (RSTAT_CLEAR_RHALT >> i);
-		rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
-	}
-	for_each_bit (i, &priv->gfargrp.tx_bit_map, priv->num_tx_queues) {
-		priv->gfargrp.num_tx_queues++;
-		tstat = tstat | (TSTAT_CLEAR_THALT >> i);
-		tqueue = tqueue | (TQUEUE_EN0 >> i);
+	for (i = 0; i< priv->num_grps; i++) {
+		priv->gfargrp[i].tx_bit_map = reverse_bitmap(
+				priv->gfargrp[i].tx_bit_map, MAX_TX_QS);
+		priv->gfargrp[i].rx_bit_map = reverse_bitmap(
+				priv->gfargrp[i].rx_bit_map, MAX_RX_QS);
+	}
+
+	/* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
+	 * also assign queues to groups */
+	for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
+		priv->gfargrp[grp_idx].num_rx_queues = 0x0;
+		for_each_bit(i, &priv->gfargrp[grp_idx].rx_bit_map,
+				priv->num_rx_queues) {
+			priv->gfargrp[grp_idx].num_rx_queues++;
+			priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx];
+			rstat = rstat | (RSTAT_CLEAR_RHALT >> i);
+			rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
+		}
+		priv->gfargrp[grp_idx].num_tx_queues = 0x0;
+		for_each_bit (i, &priv->gfargrp[grp_idx].tx_bit_map,
+				priv->num_tx_queues) {
+			priv->gfargrp[grp_idx].num_tx_queues++;
+			priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx];
+			tstat = tstat | (TSTAT_CLEAR_THALT >> i);
+			tqueue = tqueue | (TQUEUE_EN0 >> i);
+		}
+		priv->gfargrp[grp_idx].rstat = rstat;
+		priv->gfargrp[grp_idx].tstat = tstat;
+		rstat = tstat =0;
 	}
-	priv->gfargrp.rstat = rstat;
-	priv->gfargrp.tstat = tstat;
 
 	gfar_write(&regs->rqueue, rqueue);
 	gfar_write(&regs->tqueue, tqueue);
@@ -868,20 +955,40 @@ static int gfar_probe(struct of_device *ofdev,
 
 	/* fill out IRQ number and name fields */
 	len_devname = strlen(dev->name);
-	strncpy(&priv->gfargrp.int_name_tx[0], dev->name, len_devname);
-	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		strncpy(&priv->gfargrp.int_name_tx[len_devname],
-			"_tx", sizeof("_tx") + 1);
-
-		strncpy(&priv->gfargrp.int_name_rx[0], dev->name, len_devname);
-		strncpy(&priv->gfargrp.int_name_rx[len_devname],
-			"_rx", sizeof("_rx") + 1);
-
-		strncpy(&priv->gfargrp.int_name_er[0], dev->name, len_devname);
-		strncpy(&priv->gfargrp.int_name_er[len_devname],
-			"_er", sizeof("_er") + 1);
-	} else
-		priv->gfargrp.int_name_tx[len_devname] = '\0';
+	for (i = 0; i < priv->num_grps; i++) {
+		strncpy(&priv->gfargrp[i].int_name_tx[0], dev->name,
+				len_devname);
+		if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+			strncpy(&priv->gfargrp[i].int_name_tx[len_devname],
+				"_g", sizeof("_g"));
+			priv->gfargrp[i].int_name_tx[
+				strlen(priv->gfargrp[i].int_name_tx)] = i+48;
+			strncpy(&priv->gfargrp[i].int_name_tx[strlen(
+				priv->gfargrp[i].int_name_tx)],
+				"_tx", sizeof("_tx") + 1);
+
+			strncpy(&priv->gfargrp[i].int_name_rx[0], dev->name,
+					len_devname);
+			strncpy(&priv->gfargrp[i].int_name_rx[len_devname],
+					"_g", sizeof("_g"));
+			priv->gfargrp[i].int_name_rx[
+				strlen(priv->gfargrp[i].int_name_rx)] = i+48;
+			strncpy(&priv->gfargrp[i].int_name_rx[strlen(
+				priv->gfargrp[i].int_name_rx)],
+				"_rx", sizeof("_rx") + 1);
+
+			strncpy(&priv->gfargrp[i].int_name_er[0], dev->name,
+					len_devname);
+			strncpy(&priv->gfargrp[i].int_name_er[len_devname],
+				"_g", sizeof("_g"));
+			priv->gfargrp[i].int_name_er[strlen(
+					priv->gfargrp[i].int_name_er)] = i+48;
+			strncpy(&priv->gfargrp[i].int_name_er[strlen(\
+				priv->gfargrp[i].int_name_er)],
+				"_er", sizeof("_er") + 1);
+		} else
+			priv->gfargrp[i].int_name_tx[len_devname] = '\0';
+	}
 
 	/* Create all the sysfs files */
 	gfar_init_sysfs(dev);
@@ -902,7 +1009,7 @@ static int gfar_probe(struct of_device *ofdev,
 	return 0;
 
 register_fail:
-	iounmap(priv->gfargrp.regs);
+	unmap_group_regs(priv);
 	free_tx_pointers(priv);
 	free_rx_pointers(priv);
 	if (priv->phy_node)
@@ -925,7 +1032,7 @@ static int gfar_remove(struct of_device *ofdev)
 	dev_set_drvdata(&ofdev->dev, NULL);
 
 	unregister_netdev(priv->ndev);
-	iounmap(priv->gfargrp.regs);
+	unmap_group_regs(priv);
 	free_netdev(priv->ndev);
 
 	return 0;
@@ -937,7 +1044,7 @@ static int gfar_suspend(struct device *dev)
 {
 	struct gfar_private *priv = dev_get_drvdata(dev);
 	struct net_device *ndev = priv->ndev;
-	struct gfar __iomem *regs = NULL;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned long flags;
 	u32 tempval;
 
@@ -945,7 +1052,6 @@ static int gfar_suspend(struct device *dev)
 		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	netif_device_detach(ndev);
-	regs = priv->gfargrp.regs;
 
 	if (netif_running(ndev)) {
 
@@ -969,7 +1075,7 @@ static int gfar_suspend(struct device *dev)
 		unlock_tx_qs(priv);
 		local_irq_restore(flags);
 
-		napi_disable(&priv->gfargrp.napi);
+		disable_napi(priv);
 
 		if (magic_packet) {
 			/* Enable interrupt on Magic Packet */
@@ -991,7 +1097,7 @@ static int gfar_resume(struct device *dev)
 {
 	struct gfar_private *priv = dev_get_drvdata(dev);
 	struct net_device *ndev = priv->ndev;
-	struct gfar __iomem *regs = NULL;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned long flags;
 	u32 tempval;
 	int magic_packet = priv->wol_en &&
@@ -1008,8 +1114,6 @@ static int gfar_resume(struct device *dev)
 	/* Disable Magic Packet mode, in case something
 	 * else woke us up.
 	 */
-	regs = priv->gfargrp.regs;
-
 	local_irq_save(flags);
 	lock_tx_qs(priv);
 	lock_rx_qs(priv);
@@ -1026,7 +1130,7 @@ static int gfar_resume(struct device *dev)
 
 	netif_device_attach(ndev);
 
-	napi_enable(&priv->gfargrp.napi);
+	enable_napi(priv);
 
 	return 0;
 }
@@ -1092,10 +1196,9 @@ static int gfar_legacy_resume(struct of_device *ofdev)
 static phy_interface_t gfar_get_interface(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = NULL;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 ecntrl;
 
-	regs = priv->gfargrp.regs;
 	ecntrl = gfar_read(&regs->ecntrl);
 
 	if (ecntrl & ECNTRL_SGMII_MODE)
@@ -1219,14 +1322,18 @@ static void init_registers(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar __iomem *regs = NULL;
+	int i = 0;
 
-	regs = priv->gfargrp.regs;
-	/* Clear IEVENT */
-	gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
+	for (i = 0; i < priv->num_grps; i++) {
+		regs = priv->gfargrp[i].regs;
+		/* Clear IEVENT */
+		gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
 
-	/* Initialize IMASK */
-	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+		/* Initialize IMASK */
+		gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+	}
 
+	regs = priv->gfargrp[0].regs;
 	/* Init hash registers to zero */
 	gfar_write(&regs->igaddr0, 0);
 	gfar_write(&regs->igaddr1, 0);
@@ -1267,15 +1374,20 @@ static void init_registers(struct net_device *dev)
 static void gfar_halt_nodisable(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = NULL;
 	u32 tempval;
+	int i = 0;
 
-	/* Mask all interrupts */
-	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+	for (i = 0; i < priv->num_grps; i++) {
+		regs = priv->gfargrp[i].regs;
+		/* Mask all interrupts */
+		gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
-	/* Clear all interrupts */
-	gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
+		/* Clear all interrupts */
+		gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
+	}
 
+	regs = priv->gfargrp[0].regs;
 	/* Stop the DMA, and wait for it to stop */
 	tempval = gfar_read(&regs->dmactrl);
 	if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
@@ -1293,7 +1405,7 @@ static void gfar_halt_nodisable(struct net_device *dev)
 void gfar_halt(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 tempval;
 
 	gfar_halt_nodisable(dev);
@@ -1304,10 +1416,18 @@ void gfar_halt(struct net_device *dev)
 	gfar_write(&regs->maccfg1, tempval);
 }
 
+static void free_grp_irqs(struct gfar_priv_grp *grp)
+{
+	free_irq(grp->interruptError, grp);
+	free_irq(grp->interruptTransmit, grp);
+	free_irq(grp->interruptReceive, grp);
+}
+
 void stop_gfar(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	unsigned long flags;
+	int i;
 
 	phy_stop(priv->phydev);
 
@@ -1325,11 +1445,12 @@ void stop_gfar(struct net_device *dev)
 
 	/* Free the IRQs */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		free_irq(priv->gfargrp.interruptError, &priv->gfargrp);
-		free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp);
-		free_irq(priv->gfargrp.interruptReceive, &priv->gfargrp);
+		for (i = 0; i < priv->num_grps; i++)
+			free_grp_irqs(&priv->gfargrp[i]);
 	} else {
-		free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp);
+		for (i = 0; i < priv->num_grps; i++)
+			free_irq(priv->gfargrp[i].interruptTransmit,
+					&priv->gfargrp[i]);
 	}
 
 	free_skb_resources(priv);
@@ -1417,8 +1538,9 @@ static void free_skb_resources(struct gfar_private *priv)
 void gfar_start(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 tempval;
+	int i = 0;
 
 	/* Enable Rx and Tx in MACCFG1 */
 	tempval = gfar_read(&regs->maccfg1);
@@ -1435,92 +1557,149 @@ void gfar_start(struct net_device *dev)
 	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
 	gfar_write(&regs->dmactrl, tempval);
 
-	/* Clear THLT/RHLT, so that the DMA starts polling now */
-	gfar_write(&regs->tstat, priv->gfargrp.tstat);
-	gfar_write(&regs->rstat, priv->gfargrp.rstat);
-
-	/* Unmask the interrupts we look for */
-	gfar_write(&regs->imask, IMASK_DEFAULT);
+	for (i = 0; i < priv->num_grps; i++) {
+		regs = priv->gfargrp[i].regs;
+		/* Clear THLT/RHLT, so that the DMA starts polling now */
+		gfar_write(&regs->tstat, priv->gfargrp[i].tstat);
+		gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
+		/* Unmask the interrupts we look for */
+		gfar_write(&regs->imask, IMASK_DEFAULT);
+	}
 
 	dev->trans_start = jiffies;
 }
 
-/* Bring the controller up and running */
-int startup_gfar(struct net_device *ndev)
+void gfar_configure_coalescing(struct gfar_private *priv,
+	unsigned int tx_mask, unsigned int rx_mask)
 {
-	struct gfar_private *priv = netdev_priv(ndev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
-	int err;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
+	u32 *baddr;
+	int i = 0;
 
-	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+	/* Backward compatible case ---- even if we enable
+	 * multiple queues, there's only single reg to program
+	 */
+	gfar_write(&regs->txic, 0);
+	if(likely(priv->tx_queue[0]->txcoalescing))
+		gfar_write(&regs->txic, priv->tx_queue[0]->txic);
 
-	err = gfar_alloc_skb_resources(ndev);
-	if (err)
-		return err;
+	gfar_write(&regs->rxic, 0);
+	if(unlikely(priv->rx_queue[0]->rxcoalescing))
+		gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
 
-	gfar_init_mac(ndev);
+	if (priv->mode == MQ_MG_MODE) {
+		baddr = &regs->txic0;
+		for_each_bit (i, &tx_mask, priv->num_tx_queues) {
+			if (likely(priv->tx_queue[i]->txcoalescing)) {
+				gfar_write(baddr + i, 0);
+				gfar_write(baddr + i, priv->tx_queue[i]->txic);
+			}
+		}
+
+		baddr = &regs->rxic0;
+		for_each_bit (i, &rx_mask, priv->num_rx_queues) {
+			if (likely(priv->rx_queue[i]->rxcoalescing)) {
+				gfar_write(baddr + i, 0);
+				gfar_write(baddr + i, priv->rx_queue[i]->rxic);
+			}
+		}
+	}
+}
+
+static int register_grp_irqs(struct gfar_priv_grp *grp)
+{
+	struct gfar_private *priv = grp->priv;
+	struct net_device *dev = priv->ndev;
+	int err;
 
 	/* If the device has multiple interrupts, register for
 	 * them.  Otherwise, only register for the one */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
 		/* Install our interrupt handlers for Error,
 		 * Transmit, and Receive */
-		err = request_irq(priv->gfargrp.interruptError, gfar_error, 0,
-				  priv->gfargrp.int_name_er, &priv->gfargrp);
-		if (err) {
+		if ((err = request_irq(grp->interruptError, gfar_error, 0,
+				grp->int_name_er,grp)) < 0) {
 			if (netif_msg_intr(priv))
-				pr_err("%s: Can't get IRQ %d\n", ndev->name,
-				       priv->gfargrp.interruptError);
-			goto err_irq_fail;
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, grp->interruptError);
+
+				goto err_irq_fail;
 		}
 
-		err = request_irq(priv->gfargrp.interruptTransmit,
-					gfar_transmit, 0,
-					priv->gfargrp.int_name_tx,
-					&priv->gfargrp);
-		if (err) {
+		if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
+				0, grp->int_name_tx, grp)) < 0) {
 			if (netif_msg_intr(priv))
-				pr_err("%s: Can't get IRQ %d\n", ndev->name,
-				       priv->gfargrp.interruptTransmit);
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, grp->interruptTransmit);
 			goto tx_irq_fail;
 		}
 
-		err = request_irq(priv->gfargrp.interruptReceive,
-					gfar_receive, 0,
-					priv->gfargrp.int_name_rx,
-					&priv->gfargrp);
-		if (err) {
+		if ((err = request_irq(grp->interruptReceive, gfar_receive, 0,
+				grp->int_name_rx, grp)) < 0) {
 			if (netif_msg_intr(priv))
-				pr_err("%s: Can't get IRQ %d (receive0)\n",
-					ndev->name,
-					priv->gfargrp.interruptReceive);
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, grp->interruptReceive);
 			goto rx_irq_fail;
 		}
 	} else {
-		err = request_irq(priv->gfargrp.interruptTransmit,
-					gfar_interrupt, 0,
-					priv->gfargrp.int_name_tx,
-					&priv->gfargrp);
-		if (err) {
+		if ((err = request_irq(grp->interruptTransmit, gfar_interrupt, 0,
+				grp->int_name_tx, grp)) < 0) {
 			if (netif_msg_intr(priv))
-				pr_err("%s: Can't get IRQ %d\n", ndev->name,
-				       priv->gfargrp.interruptTransmit);
+				printk(KERN_ERR "%s: Can't get IRQ %d\n",
+					dev->name, grp->interruptTransmit);
 			goto err_irq_fail;
 		}
 	}
 
+	return 0;
+
+rx_irq_fail:
+	free_irq(grp->interruptTransmit, grp);
+tx_irq_fail:
+	free_irq(grp->interruptError, grp);
+err_irq_fail:
+	return err;
+
+}
+
+/* Bring the controller up and running */
+int startup_gfar(struct net_device *ndev)
+{
+	struct gfar_private *priv = netdev_priv(ndev);
+	struct gfar __iomem *regs = NULL;
+	int err, i, j;
+
+	for (i = 0; i < priv->num_grps; i++) {
+		regs= priv->gfargrp[i].regs;
+		gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+	}
+
+	regs= priv->gfargrp[0].regs;
+	err = gfar_alloc_skb_resources(ndev);
+	if (err)
+		return err;
+
+	gfar_init_mac(ndev);
+
+	for (i = 0; i < priv->num_grps; i++) {
+		err = register_grp_irqs(&priv->gfargrp[i]);
+		if (err) {
+			for (j = 0; j < i; j++)
+				free_grp_irqs(&priv->gfargrp[j]);
+				goto irq_fail;
+		}
+	}
+
 	/* Start the controller */
 	gfar_start(ndev);
 
 	phy_start(priv->phydev);
 
+	gfar_configure_coalescing(priv, 0xFF, 0xFF);
+
 	return 0;
 
-rx_irq_fail:
-	free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp);
-tx_irq_fail:
-	free_irq(priv->gfargrp.interruptError, &priv->gfargrp);
-err_irq_fail:
+irq_fail:
 	free_skb_resources(priv);
 	return err;
 }
@@ -1532,7 +1711,7 @@ static int gfar_enet_open(struct net_device *dev)
 	struct gfar_private *priv = netdev_priv(dev);
 	int err;
 
-	napi_enable(&priv->gfargrp.napi);
+	enable_napi(priv);
 
 	skb_queue_head_init(&priv->rx_recycle);
 
@@ -1544,13 +1723,13 @@ static int gfar_enet_open(struct net_device *dev)
 	err = init_phy(dev);
 
 	if (err) {
-		napi_disable(&priv->gfargrp.napi);
+		disable_napi(priv);
 		return err;
 	}
 
 	err = startup_gfar(dev);
 	if (err) {
-		napi_disable(&priv->gfargrp.napi);
+		disable_napi(priv);
 		return err;
 	}
 
@@ -1639,7 +1818,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	tx_queue = priv->tx_queue[rq];
 	txq = netdev_get_tx_queue(dev, rq);
 	base = tx_queue->tx_bd_base;
-	regs = priv->gfargrp.regs;
+	regs = tx_queue->grp->regs;
 
 	/* make space for additional header when fcb is needed */
 	if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
@@ -1776,7 +1955,7 @@ static int gfar_close(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	napi_disable(&priv->gfargrp.napi);
+	disable_napi(priv);
 
 	skb_queue_purge(&priv->rx_recycle);
 	cancel_work_sync(&priv->reset_task);
@@ -1809,7 +1988,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
 	unsigned long flags;
 	u32 tempval;
 
-	regs = priv->gfargrp.regs;
+	regs = priv->gfargrp[0].regs;
 	local_irq_save(flags);
 	lock_rx_qs(priv);
 
@@ -1853,7 +2032,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
 	int tempsize, tempval;
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	int oldsize = priv->rx_buffer_size;
 	int frame_size = new_mtu + ETH_HLEN;
 
@@ -2275,7 +2454,7 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 	struct gfar_priv_grp *gfargrp = container_of(napi,
 			struct gfar_priv_grp, napi);
 	struct gfar_private *priv = gfargrp->priv;
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = gfargrp->regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 	int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0;
@@ -2334,14 +2513,8 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 
 		/* If we are coalescing interrupts, update the timer */
 		/* Otherwise, clear it */
-		if (likely(rx_queue->rxcoalescing)) {
-			gfar_write(&regs->rxic, 0);
-			gfar_write(&regs->rxic, rx_queue->rxic);
-		}
-		if (likely(tx_queue->txcoalescing)) {
-			gfar_write(&regs->txic, 0);
-			gfar_write(&regs->txic, tx_queue->txic);
-		}
+		gfar_configure_coalescing(priv,
+				gfargrp->rx_bit_map, gfargrp->tx_bit_map);
 	}
 
 	return rx_cleaned;
@@ -2356,20 +2529,26 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 static void gfar_netpoll(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	int i = 0;
 
 	/* If the device has multiple interrupts, run tx/rx */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		disable_irq(priv->gfargrp.interruptTransmit);
-		disable_irq(priv->gfargrp.interruptReceive);
-		disable_irq(priv->gfargrp.interruptError);
-		gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp);
-		enable_irq(priv->gfargrp.interruptError);
-		enable_irq(priv->gfargrp.interruptReceive);
-		enable_irq(priv->gfargrp.interruptTransmit);
+		for (i = 0; i < priv->num_grps; i++) {
+			disable_irq(priv->gfargrp[i].interruptTransmit);
+			disable_irq(priv->gfargrp[i].interruptReceive);
+			disable_irq(priv->gfargrp[i].interruptError);
+			gfar_interrupt(priv->gfargrp[i].interruptTransmit,
+						&priv->gfargrp[i]);
+			enable_irq(priv->gfargrp[i].interruptError);
+			enable_irq(priv->gfargrp[i].interruptReceive);
+			enable_irq(priv->gfargrp[i].interruptTransmit);
+		}
 	} else {
-		disable_irq(priv->gfargrp.interruptTransmit);
-		gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp);
-		enable_irq(priv->gfargrp.interruptTransmit);
+		for (i = 0; i < priv->num_grps; i++) {
+			disable_irq(priv->gfargrp[i].interruptTransmit);
+			gfar_interrupt(priv->gfargrp[i].interruptTransmit,
+						&priv->gfargrp[i]);
+			enable_irq(priv->gfargrp[i].interruptTransmit);
 	}
 }
 #endif
@@ -2406,7 +2585,7 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id)
 static void adjust_link(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned long flags;
 	struct phy_device *phydev = priv->phydev;
 	int new_state = 0;
@@ -2490,7 +2669,7 @@ static void gfar_set_multi(struct net_device *dev)
 {
 	struct dev_mc_list *mc_ptr;
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u32 tempval;
 
 	if (dev->flags & IFF_PROMISC) {
@@ -2623,7 +2802,7 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	int idx;
 	char tmpbuf[MAC_ADDR_LEN];
 	u32 tempval;
@@ -2727,6 +2906,9 @@ static struct of_device_id gfar_match[] =
 		.type = "network",
 		.compatible = "gianfar",
 	},
+	{
+		.compatible = "fsl,etsec2",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, gfar_match);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 70c25ce..a43b238 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -79,6 +79,9 @@ extern const char gfar_driver_version[];
 #define MAX_TX_QS	0x8
 #define MAX_RX_QS	0x8
 
+/* MAXIMUM NUMBER OF GROUPS SUPPORTED */
+#define MAXGROUPS 0x2
+
 /* These need to be powers of 2 for this driver */
 #define DEFAULT_TX_RING_SIZE	256
 #define DEFAULT_RX_RING_SIZE	256
@@ -795,7 +798,24 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_BD_STASHING		0x00000200
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING	0x00000400
 
+#if (MAXGROUPS == 2)
+#define DEFAULT_MAPPING 	0xAA
+#else
 #define DEFAULT_MAPPING 	0xFF
+#endif
+
+#define ISRG_SHIFT_TX	0x10
+#define ISRG_SHIFT_RX	0x18
+
+/* The same driver can operate in two modes */
+/* SQ_SG_MODE: Single Queue Single Group Mode
+ * 		(Backward compatible mode)
+ * MQ_MG_MODE: Multi Queue Multi Group mode
+ */
+enum {
+	SQ_SG_MODE = 0,
+	MQ_MG_MODE
+};
 
 /**
  *	struct gfar_priv_tx_q - per tx queue structure
@@ -825,6 +845,7 @@ struct gfar_priv_tx_q {
 	struct	txbd8 *cur_tx;
 	struct	txbd8 *dirty_tx;
 	struct	net_device *dev;
+	struct gfar_priv_grp *grp;
 	u16	skb_curtx;
 	u16	skb_dirtytx;
 	u16	qindex;
@@ -857,6 +878,7 @@ struct gfar_priv_rx_q {
 	struct	rxbd8 *rx_bd_base;
 	struct	rxbd8 *cur_rx;
 	struct	net_device *dev;
+	struct gfar_priv_grp *grp;
 	u16	skb_currx;
 	u16	qindex;
 	unsigned int	rx_ring_size;
@@ -884,6 +906,7 @@ struct gfar_priv_grp {
 	struct	napi_struct napi;
 	struct gfar_private *priv;
 	struct gfar __iomem *regs;
+	unsigned int grp_id;
 	unsigned int rx_bit_map;
 	unsigned int tx_bit_map;
 	unsigned int num_tx_queues;
@@ -915,6 +938,8 @@ struct gfar_private {
 	/* Indicates how many tx, rx queues are enabled */
 	unsigned int num_tx_queues;
 	unsigned int num_rx_queues;
+	unsigned int num_grps;
+	unsigned int mode;
 
 	/* The total tx and rx ring size for the enabled queues */
 	unsigned int total_tx_ring_size;
@@ -924,7 +949,7 @@ struct gfar_private {
 	struct net_device *ndev;
 	struct of_device *ofdev;
 
-	struct gfar_priv_grp gfargrp;
+	struct gfar_priv_grp gfargrp[MAXGROUPS];
 	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
 	struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
 
@@ -998,6 +1023,8 @@ extern void stop_gfar(struct net_device *dev);
 extern void gfar_halt(struct net_device *dev);
 extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
 		int enable, u32 regnum, u32 read);
+extern void gfar_configure_coalescing(struct gfar_private *priv,
+		unsigned int tx_mask, unsigned int rx_mask);
 void gfar_init_sysfs(struct net_device *dev);
 
 extern const struct ethtool_ops gfar_ethtool_ops;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index d3d2623..562f6c2 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -137,7 +137,7 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	u64 *extra = (u64 *) & priv->extra_stats;
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
@@ -226,7 +226,7 @@ static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, voi
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
-	u32 __iomem *theregs = (u32 __iomem *) priv->gfargrp.regs;
+	u32 __iomem *theregs = (u32 __iomem *) priv->gfargrp[0].regs;
 	u32 *buf = (u32 *) regbuf;
 
 	for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++)
@@ -352,22 +352,23 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
+	int i = 0;
 
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
 		return -EOPNOTSUPP;
 
-	tx_queue = priv->tx_queue[0];
-	rx_queue = priv->rx_queue[0];
-
 	/* Set up rx coalescing */
+	/* As of now, we will enable/disable coalescing for all
+	 * queues together in case of eTSEC2, this will be modified
+	 * along with the ethtool interface */
 	if ((cvals->rx_coalesce_usecs == 0) ||
-	    (cvals->rx_max_coalesced_frames == 0))
-		rx_queue->rxcoalescing = 0;
-	else
-		rx_queue->rxcoalescing = 1;
+	    (cvals->rx_max_coalesced_frames == 0)) {
+		for (i = 0; i < priv->num_rx_queues; i++)
+			priv->rx_queue[i]->rxcoalescing = 0;
+	} else {
+		for (i = 0; i < priv->num_rx_queues; i++)
+			priv->rx_queue[i]->rxcoalescing = 1;
+	}
 
 	if (NULL == priv->phydev)
 		return -ENODEV;
@@ -385,15 +386,21 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 		return -EINVAL;
 	}
 
-	rx_queue->rxic = mk_ic_value(cvals->rx_max_coalesced_frames,
-		gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs));
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		priv->rx_queue[i]->rxic = mk_ic_value(
+			cvals->rx_max_coalesced_frames,
+			gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs));
+	}
 
 	/* Set up tx coalescing */
 	if ((cvals->tx_coalesce_usecs == 0) ||
-	    (cvals->tx_max_coalesced_frames == 0))
-		tx_queue->txcoalescing = 0;
-	else
-		tx_queue->txcoalescing = 1;
+	    (cvals->tx_max_coalesced_frames == 0)) {
+		for (i = 0; i < priv->num_tx_queues; i++)
+			priv->tx_queue[i]->txcoalescing = 0;
+	} else {
+		for (i = 0; i < priv->num_tx_queues; i++)
+			priv->tx_queue[i]->txcoalescing = 1;
+	}
 
 	/* Check the bounds of the values */
 	if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
@@ -408,16 +415,13 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 		return -EINVAL;
 	}
 
-	tx_queue->txic = mk_ic_value(cvals->tx_max_coalesced_frames,
-		gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
-
-	gfar_write(&regs->rxic, 0);
-	if (rx_queue->rxcoalescing)
-		gfar_write(&regs->rxic, rx_queue->rxic);
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		priv->tx_queue[i]->txic = mk_ic_value(
+			cvals->tx_max_coalesced_frames,
+			gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
+	}
 
-	gfar_write(&regs->txic, 0);
-	if (tx_queue->txcoalescing)
-		gfar_write(&regs->txic, tx_queue->txic);
+	gfar_configure_coalescing(priv, 0xFF, 0xFF);
 
 	return 0;
 }
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index 4b726f6..3724835 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -50,7 +50,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 				 const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	int new_setting = 0;
 	u32 temp;
 	unsigned long flags;
@@ -105,7 +105,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 				      const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -164,7 +164,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 				       const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned short index = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -212,7 +212,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 				       const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -252,7 +252,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 				    const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -293,7 +293,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 					const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-	struct gfar __iomem *regs = priv->gfargrp.regs;
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
-- 
1.5.2.2


^ permalink raw reply related

* [PATCH v1 5/7] gianfar: Add support etsec2.0 registers.
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch adds support for etsec2.0 regsiters

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/gianfar.h |   55 +++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index fc43cfd..70c25ce 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -566,25 +566,32 @@ struct gfar_stats {
 
 struct gfar {
 	u32	tsec_id;	/* 0x.000 - Controller ID register */
-	u8	res1[12];
+	u32	tsec_id2;	/* 0x.004 - Controller ID2 register */
+	u8	res1[8];
 	u32	ievent;		/* 0x.010 - Interrupt Event Register */
 	u32	imask;		/* 0x.014 - Interrupt Mask Register */
 	u32	edis;		/* 0x.018 - Error Disabled Register */
-	u8	res2[4];
+	u32	emapg;		/* 0x.01c - Group Error mapping register */
 	u32	ecntrl;		/* 0x.020 - Ethernet Control Register */
 	u32	minflr;		/* 0x.024 - Minimum Frame Length Register */
 	u32	ptv;		/* 0x.028 - Pause Time Value Register */
 	u32	dmactrl;	/* 0x.02c - DMA Control Register */
 	u32	tbipa;		/* 0x.030 - TBI PHY Address Register */
-	u8	res3[88];
+	u8	res2[28];
+	u32	fifo_rx_pause;	/* 0x.050 - FIFO receive pause start threshold
+					register */
+	u32	fifo_rx_pause_shutoff;	/* x.054 - FIFO receive starve shutoff
+						register */
+	u32	fifo_rx_alarm;	/* 0x.058 - FIFO receive alarm start threshold
+						register */
+	u32	fifo_rx_alarm_shutoff;	/*0x.05c - FIFO receive alarm  starve
+						shutoff register */
+	u8	res3[44];
 	u32	fifo_tx_thr;	/* 0x.08c - FIFO transmit threshold register */
 	u8	res4[8];
 	u32	fifo_tx_starve;	/* 0x.098 - FIFO transmit starve register */
 	u32	fifo_tx_starve_shutoff;	/* 0x.09c - FIFO transmit starve shutoff register */
-	u8	res5[4];
-	u32	fifo_rx_pause;	/* 0x.0a4 - FIFO receive pause threshold register */
-	u32	fifo_rx_alarm;	/* 0x.0a8 - FIFO receive alarm threshold register */
-	u8	res6[84];
+	u8	res5[96];
 	u32	tctrl;		/* 0x.100 - Transmit Control Register */
 	u32	tstat;		/* 0x.104 - Transmit Status Register */
 	u32	dfvlan;		/* 0x.108 - Default VLAN Control word */
@@ -635,7 +642,11 @@ struct gfar {
 	u8	res12[8];
 	u32	rxic;		/* 0x.310 - Receive Interrupt Coalescing Configuration Register */
 	u32	rqueue;		/* 0x.314 - Receive queue control register */
-	u8	res13[24];
+	u32	rir0;		/* 0x.318 - Ring mapping register 0 */
+	u32	rir1;		/* 0x.31c - Ring mapping register 1 */
+	u32	rir2;		/* 0x.320 - Ring mapping register 2 */
+	u32	rir3;		/* 0x.324 - Ring mapping register 3 */
+	u8	res13[8];
 	u32	rbifx;		/* 0x.330 - Receive bit field extract control register */
 	u32	rqfar;		/* 0x.334 - Receive queue filing table address register */
 	u32	rqfcr;		/* 0x.338 - Receive queue filing table control register */
@@ -684,7 +695,7 @@ struct gfar {
 	u32	maxfrm;		/* 0x.510 - Maximum Frame Length Register */
 	u8	res18[12];
 	u8	gfar_mii_regs[24];	/* See gianfar_phy.h */
-	u8	res19[4];
+	u32	ifctrl;		/* 0x.538 - Interface control register */
 	u32	ifstat;		/* 0x.53c - Interface Status Register */
 	u32	macstnaddr1;	/* 0x.540 - Station Address Part 1 Register */
 	u32	macstnaddr2;	/* 0x.544 - Station Address Part 2 Register */
@@ -745,8 +756,30 @@ struct gfar {
 	u8	res23c[248];
 	u32	attr;		/* 0x.bf8 - Attributes Register */
 	u32	attreli;	/* 0x.bfc - Attributes Extract Length and Extract Index Register */
-	u8	res24[1024];
-
+	u8	res24[688];
+	u32	isrg0;		/* 0x.eb0 - Interrupt steering group 0 register */
+	u32	isrg1;		/* 0x.eb4 - Interrupt steering group 1 register */
+	u32	isrg2;		/* 0x.eb8 - Interrupt steering group 2 register */
+	u32	isrg3;		/* 0x.ebc - Interrupt steering group 3 register */
+	u8	res25[16];
+	u32	rxic0;		/* 0x.ed0 - Ring 0 Rx interrupt coalescing */
+	u32	rxic1;		/* 0x.ed4 - Ring 1 Rx interrupt coalescing */
+	u32	rxic2;		/* 0x.ed8 - Ring 2 Rx interrupt coalescing */
+	u32	rxic3;		/* 0x.edc - Ring 3 Rx interrupt coalescing */
+	u32	rxic4;		/* 0x.ee0 - Ring 4 Rx interrupt coalescing */
+	u32	rxic5;		/* 0x.ee4 - Ring 5 Rx interrupt coalescing */
+	u32	rxic6;		/* 0x.ee8 - Ring 6 Rx interrupt coalescing */
+	u32	rxic7;		/* 0x.eec - Ring 7 Rx interrupt coalescing */
+	u8	res26[32];
+	u32	txic0;		/* 0x.f10 - Ring 0 Tx interrupt coalescing */
+	u32	txic1;		/* 0x.f14 - Ring 1 Tx interrupt coalescing */
+	u32	txic2;		/* 0x.f18 - Ring 2 Tx interrupt coalescing */
+	u32	txic3;		/* 0x.f1c - Ring 3 Tx interrupt coalescing */
+	u32	txic4;		/* 0x.f20 - Ring 4 Tx interrupt coalescing */
+	u32	txic5;		/* 0x.f24 - Ring 5 Tx interrupt coalescing */
+	u32	txic6;		/* 0x.f28 - Ring 6 Tx interrupt coalescing */
+	u32	txic7;		/* 0x.f2c - Ring 7 Tx interrupt coalescing */
+	u8	res27[208];
 };
 
 /* Flags related to gianfar device features */
-- 
1.5.2.2


^ permalink raw reply related

* [PATCH v1 4/7] fsl_pq_mdio: Add Suport for etsec2.0 devices.
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch adds mdio support for etsec2.0 devices.

Modified the fsl_pq_mdio structure to include the new mdio
members.

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/fsl_pq_mdio.c |   59 ++++++++++++++++++++++++++++++++++++--------
 drivers/net/fsl_pq_mdio.h |   11 +++++++-
 2 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index 6ac4648..4065b7c 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -3,8 +3,9 @@
  * Provides Bus interface for MIIM regs
  *
  * Author: Andy Fleming <afleming@freescale.com>
+ * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright (c) 2002-2004,2008 Freescale Semiconductor, Inc.
+ * Copyright 2002-2004, 2008-2009 Freescale Semiconductor, Inc.
  *
  * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips)
  *
@@ -189,19 +190,29 @@ static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)
 
 
 #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
-static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs)
+static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np)
 {
 	struct gfar __iomem *enet_regs;
+	u32 __iomem *ioremap_tbipa;
+	u64 addr, size;
 
 	/*
 	 * This is mildly evil, but so is our hardware for doing this.
 	 * Also, we have to cast back to struct gfar because of
 	 * definition weirdness done in gianfar.h.
 	 */
-	enet_regs = (struct gfar __iomem *)
-		((char __iomem *)regs - offsetof(struct gfar, gfar_mii_regs));
-
-	return &enet_regs->tbipa;
+	if(of_device_is_compatible(np, "fsl,gianfar-mdio") ||
+		of_device_is_compatible(np, "fsl,gianfar-tbi") ||
+		of_device_is_compatible(np, "gianfar")) {
+		enet_regs = (struct gfar __iomem *)regs;
+		return &enet_regs->tbipa;
+	} else if (of_device_is_compatible(np, "fsl,etsec2-mdio") ||
+			of_device_is_compatible(np, "fsl,etsec2-tbi")) {
+		addr = of_translate_address(np, of_get_address(np, 1, &size, NULL));
+		ioremap_tbipa = ioremap(addr, size);
+		return ioremap_tbipa;
+	} else
+		return NULL;
 }
 #endif
 
@@ -250,11 +261,11 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
 {
 	struct device_node *np = ofdev->node;
 	struct device_node *tbi;
-	struct fsl_pq_mdio __iomem *regs;
+	struct fsl_pq_mdio __iomem *regs = NULL;
 	u32 __iomem *tbipa;
 	struct mii_bus *new_bus;
 	int tbiaddr = -1;
-	u64 addr, size;
+	u64 addr = 0, size = 0, ioremap_miimcfg = 0;
 	int err = 0;
 
 	new_bus = mdiobus_alloc();
@@ -268,8 +279,22 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
 	fsl_pq_mdio_bus_name(new_bus->id, np);
 
 	/* Set the PHY base address */
-	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
-	regs = ioremap(addr, size);
+	if (of_device_is_compatible(np,"fsl,gianfar-mdio") ||
+		of_device_is_compatible(np, "fsl,gianfar-tbi") ||
+		of_device_is_compatible(np, "fsl,ucc-mdio") ||
+		of_device_is_compatible(np,"ucc_geth_phy" )) {
+		addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
+		ioremap_miimcfg =  container_of(addr, struct fsl_pq_mdio, miimcfg);
+		regs = ioremap(ioremap_miimcfg, size +
+				offsetof(struct fsl_pq_mdio, miimcfg));
+	} else if (of_device_is_compatible(np,"fsl,etsec2-mdio") ||
+			of_device_is_compatible(np, "fsl,etsec2-tbi")) {
+		addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
+		regs = ioremap(addr, size);
+	} else {
+		err = -EINVAL;
+		goto err_free_bus;
+	}
 
 	if (NULL == regs) {
 		err = -ENOMEM;
@@ -290,9 +315,15 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
 
 	if (of_device_is_compatible(np, "fsl,gianfar-mdio") ||
 			of_device_is_compatible(np, "fsl,gianfar-tbi") ||
+			of_device_is_compatible(np, "fsl,etsec2-mdio") ||
+			of_device_is_compatible(np, "fsl,etsec2-tbi") ||
 			of_device_is_compatible(np, "gianfar")) {
 #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
-		tbipa = get_gfar_tbipa(regs);
+		tbipa = get_gfar_tbipa(regs, np);
+		if (!tbipa) {
+			err = -EINVAL;
+			goto err_free_irqs;
+		}
 #else
 		err = -ENODEV;
 		goto err_free_irqs;
@@ -405,6 +436,12 @@ static struct of_device_id fsl_pq_mdio_match[] = {
 	{
 		.compatible = "fsl,gianfar-mdio",
 	},
+	{
+		.compatible = "fsl,etsec2-tbi",
+	},
+	{
+		.compatible = "fsl,etsec2-mdio",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match);
diff --git a/drivers/net/fsl_pq_mdio.h b/drivers/net/fsl_pq_mdio.h
index 36dad52..1f7d865 100644
--- a/drivers/net/fsl_pq_mdio.h
+++ b/drivers/net/fsl_pq_mdio.h
@@ -3,8 +3,9 @@
  * Driver for the MDIO bus controller on Freescale PowerQUICC processors
  *
  * Author: Andy Fleming
+ * Modifier: Sandeep Gopalpet
  *
- * Copyright (c) 2002-2004,2008 Freescale Semiconductor, Inc.
+ * Copyright 2002-2004, 2008-2009 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -23,6 +24,12 @@
 #define MII_READ_COMMAND       0x00000001
 
 struct fsl_pq_mdio {
+	u8 res1[16];
+	u32 ieventm;	/* MDIO Interrupt event register (for etsec2)*/
+	u32 imaskm;	/* MDIO Interrupt mask register (for etsec2)*/
+	u8 res2[4];
+	u32 emapm;	/* MDIO Event mapping register (for etsec2)*/
+	u8 res3[1280];
 	u32 miimcfg;		/* MII management configuration reg */
 	u32 miimcom;		/* MII management command reg */
 	u32 miimadd;		/* MII management address reg */
@@ -31,9 +38,9 @@ struct fsl_pq_mdio {
 	u32 miimind;		/* MII management indication reg */
 	u8 reserved[28];	/* Space holder */
 	u32 utbipar;		/* TBI phy address reg (only on UCC) */
+	u8 res4[2728];
 } __attribute__ ((packed));
 
-
 int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
 int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
 int fsl_pq_local_mdio_write(struct fsl_pq_mdio __iomem *regs, int mii_id,
-- 
1.5.2.2


^ permalink raw reply related

* [PATCH v1 3/7] gianfar: Add Multiple Queue Support
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch introduces multiple Tx and Rx queues.
The incoming packets can be classified into different queues
based on filer rules (out of scope of this patch). The number
of queues enabled will be based on a DTS entries fsl,num_tx_queues
and fsl,num_rx_queues.

Although we are enabling multiple queues, the interrupt coalescing
is on per device level (etsec-1.7 doesn't support multiple rxics
and txics).

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/gianfar.c         |  682 +++++++++++++++++++++++++++--------------
 drivers/net/gianfar.h         |   95 ++++++-
 drivers/net/gianfar_ethtool.c |   70 +++--
 drivers/net/gianfar_sysfs.c   |   50 ++--
 4 files changed, 606 insertions(+), 291 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index fa0188e..82da5d9 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -143,6 +143,7 @@ void gfar_start(struct net_device *dev);
 static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
 static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+u16 gfar_select_queue(struct net_device *dev, struct sk_buff *skb);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
@@ -171,71 +172,91 @@ static int gfar_init_bds(struct net_device *ndev)
 	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct txbd8 *txbdp;
 	struct rxbd8 *rxbdp;
-	int i;
-
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
+	int i, j;
 
-	/* Initialize some variables in our dev structure */
-	tx_queue->num_txbdfree = tx_queue->tx_ring_size;
-	tx_queue->dirty_tx = tx_queue->cur_tx = tx_queue->tx_bd_base;
-	rx_queue->cur_rx = rx_queue->rx_bd_base;
-	tx_queue->skb_curtx = tx_queue->skb_dirtytx = 0;
-	rx_queue->skb_currx = 0;
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		tx_queue = priv->tx_queue[i];
+		/* Initialize some variables in our dev structure */
+		tx_queue->num_txbdfree = tx_queue->tx_ring_size;
+		tx_queue->dirty_tx = tx_queue->tx_bd_base;
+		tx_queue->cur_tx = tx_queue->tx_bd_base;
+		tx_queue->skb_curtx = 0;
+		tx_queue->skb_dirtytx = 0;
+
+		/* Initialize Transmit Descriptor Ring */
+		txbdp = tx_queue->tx_bd_base;
+		for (j = 0; j < tx_queue->tx_ring_size; j++) {
+			txbdp->lstatus = 0;
+			txbdp->bufPtr = 0;
+			txbdp++;
+		}
 
-	/* Initialize Transmit Descriptor Ring */
-	txbdp = tx_queue->tx_bd_base;
-	for (i = 0; i < tx_queue->tx_ring_size; i++) {
-		txbdp->lstatus = 0;
-		txbdp->bufPtr = 0;
-		txbdp++;
+		/* Set the last descriptor in the ring to indicate wrap */
+		txbdp--;
+		txbdp->status |= TXBD_WRAP;
 	}
 
-	/* Set the last descriptor in the ring to indicate wrap */
-	txbdp--;
-	txbdp->status |= TXBD_WRAP;
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		rx_queue = priv->rx_queue[i];
+		rx_queue->cur_rx = rx_queue->rx_bd_base;
+		rx_queue->skb_currx = 0;
+		rxbdp = rx_queue->rx_bd_base;
 
-	rxbdp = rx_queue->rx_bd_base;
-	for (i = 0; i < rx_queue->rx_ring_size; i++) {
-		struct sk_buff *skb = rx_queue->rx_skbuff[i];
+		for (j = 0; j < rx_queue->rx_ring_size; j++) {
+			struct sk_buff *skb = rx_queue->rx_skbuff[j];
 
-		if (skb) {
-			gfar_init_rxbdp(rx_queue, rxbdp, rxbdp->bufPtr);
-		} else {
-			skb = gfar_new_skb(ndev);
-			if (!skb) {
-				pr_err("%s: Can't allocate RX buffers\n",
-				       ndev->name);
-				return -ENOMEM;
+			if (skb) {
+				gfar_init_rxbdp(rx_queue, rxbdp,
+						rxbdp->bufPtr);
+			} else {
+				skb = gfar_new_skb(ndev);
+				if (!skb) {
+					pr_err("%s: Can't allocate RX buffers\n",
+							ndev->name);
+					goto err_rxalloc_fail;
+				}
+				rx_queue->rx_skbuff[j] = skb;
+
+				gfar_new_rxbdp(rx_queue, rxbdp, skb);
 			}
-			rx_queue->rx_skbuff[i] = skb;
 
-			gfar_new_rxbdp(rx_queue, rxbdp, skb);
+			rxbdp++;
 		}
 
-		rxbdp++;
 	}
 
 	return 0;
+
+err_rxalloc_fail:
+	free_skb_resources(priv);
+	return -ENOMEM;
 }
 
 static int gfar_alloc_skb_resources(struct net_device *ndev)
 {
 	void *vaddr;
-	int i;
+	dma_addr_t addr;
+	int i, j, k;
 	struct gfar_private *priv = netdev_priv(ndev);
 	struct device *dev = &priv->ofdev->dev;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
+	u32 *baddr;
+
+	priv->total_tx_ring_size = 0;
+	for (i = 0; i < priv->num_tx_queues; i++)
+		priv->total_tx_ring_size += priv->tx_queue[i]->tx_ring_size;
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
+	priv->total_rx_ring_size = 0;
+	for (i = 0; i < priv->num_rx_queues; i++)
+		priv->total_rx_ring_size += priv->rx_queue[i]->rx_ring_size;
 
 	/* Allocate memory for the buffer descriptors */
 	vaddr = dma_alloc_coherent(dev,
-			sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size +
-			sizeof(*rx_queue->rx_bd_base) * rx_queue->rx_ring_size,
-			&tx_queue->tx_bd_dma_base, GFP_KERNEL);
+			sizeof(struct txbd8) * priv->total_tx_ring_size +
+			sizeof(struct rxbd8) * priv->total_rx_ring_size,
+			&addr, GFP_KERNEL);
 	if (!vaddr) {
 		if (netif_msg_ifup(priv))
 			pr_err("%s: Could not allocate buffer descriptors!\n",
@@ -243,38 +264,62 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 		return -ENOMEM;
 	}
 
-	tx_queue->tx_bd_base = vaddr;
-	tx_queue->dev = ndev;
+	baddr = &regs->tbase0;
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		tx_queue = priv->tx_queue[i];
+		tx_queue->tx_bd_base = (struct txbd8 *) vaddr;
+		tx_queue->tx_bd_dma_base = addr;
+		tx_queue->dev = ndev;
+		/* enet DMA only understands physical addresses */
+		gfar_write(baddr, addr);
+		addr    += sizeof(struct txbd8) *tx_queue->tx_ring_size;
+		vaddr   += sizeof(struct txbd8) *tx_queue->tx_ring_size;
+		baddr   += 2;
+	}
 
+	baddr = &regs->rbase0;
 	/* Start the rx descriptor ring where the tx ring leaves off */
-	vaddr = vaddr + sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size;
-	rx_queue->rx_bd_base = vaddr;
-	rx_queue->dev = ndev;
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		rx_queue = priv->rx_queue[i];
+		rx_queue->rx_bd_base = (struct rxbd8 *) vaddr;
+		rx_queue->dev = ndev;
+		gfar_write(baddr, addr);
+		addr    += sizeof (struct rxbd8) * rx_queue->rx_ring_size;
+		vaddr   += sizeof (struct rxbd8) * rx_queue->rx_ring_size;
+		baddr   += 2;
+	}
 
 	/* Setup the skbuff rings */
-	tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) *
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		tx_queue = priv->tx_queue[i];
+		tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) *
 				  tx_queue->tx_ring_size, GFP_KERNEL);
-	if (!tx_queue->tx_skbuff) {
-		if (netif_msg_ifup(priv))
-			pr_err("%s: Could not allocate tx_skbuff\n",
-			       ndev->name);
-		goto cleanup;
-	}
+		if (!tx_queue->tx_skbuff) {
+			if (netif_msg_ifup(priv))
+				pr_err("%s: Could not allocate tx_skbuff\n",
+						ndev->name);
+			goto cleanup;
+		}
 
-	for (i = 0; i < tx_queue->tx_ring_size; i++)
-		tx_queue->tx_skbuff[i] = NULL;
+		for (k = 0; k < tx_queue->tx_ring_size; k++)
+			tx_queue->tx_skbuff[k] = NULL;
+	}
 
-	rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) *
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		rx_queue = priv->rx_queue[i];
+		rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) *
 				  rx_queue->rx_ring_size, GFP_KERNEL);
-	if (!rx_queue->rx_skbuff) {
-		if (netif_msg_ifup(priv))
-			pr_err("%s: Could not allocate rx_skbuff\n",
-			       ndev->name);
-		goto cleanup;
-	}
 
-	for (i = 0; i < rx_queue->rx_ring_size; i++)
-		rx_queue->rx_skbuff[i] = NULL;
+		if (!rx_queue->rx_skbuff) {
+			if (netif_msg_ifup(priv))
+				pr_err("%s: Could not allocate rx_skbuff\n",
+				       ndev->name);
+			goto cleanup;
+		}
+
+		for (j = 0; j < rx_queue->rx_ring_size; j++)
+			rx_queue->rx_skbuff[j] = NULL;
+	}
 
 	if (gfar_init_bds(ndev))
 		goto cleanup;
@@ -289,30 +334,22 @@ cleanup:
 static void gfar_init_mac(struct net_device *ndev)
 {
 	struct gfar_private *priv = netdev_priv(ndev);
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u32 rctrl = 0;
 	u32 tctrl = 0;
 	u32 attrs = 0;
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
-
-	/* enet DMA only understands physical addresses */
-	gfar_write(&regs->tbase0, tx_queue->tx_bd_dma_base);
-	gfar_write(&regs->rbase0, tx_queue->tx_bd_dma_base +
-				  sizeof(*tx_queue->tx_bd_base) *
-				  tx_queue->tx_ring_size);
-
 	/* Configure the coalescing support */
 	gfar_write(&regs->txic, 0);
-	if (tx_queue->txcoalescing)
-		gfar_write(&regs->txic, tx_queue->txic);
+	if (priv->tx_queue[0]->txcoalescing)
+		gfar_write(&regs->txic, priv->tx_queue[0]->txic);
 
 	gfar_write(&regs->rxic, 0);
-	if (rx_queue->rxcoalescing)
-		gfar_write(&regs->rxic, rx_queue->rxic);
+	if (priv->rx_queue[0]->rxcoalescing)
+		gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
+
+	if (priv->rx_filer_enable)
+		rctrl |= RCTRL_FILREN;
 
 	if (priv->rx_csum_enable)
 		rctrl |= RCTRL_CHECKSUMMING;
@@ -341,6 +378,8 @@ static void gfar_init_mac(struct net_device *ndev)
 	if (ndev->features & NETIF_F_IP_CSUM)
 		tctrl |= TCTRL_INIT_CSUM;
 
+	tctrl |= TCTRL_TXSCHED_PRIO;
+
 	gfar_write(&regs->tctrl, tctrl);
 
 	/* Set the extraction length and index */
@@ -374,6 +413,7 @@ static const struct net_device_ops gfar_netdev_ops = {
 	.ndo_set_multicast_list = gfar_set_multi,
 	.ndo_tx_timeout = gfar_timeout,
 	.ndo_do_ioctl = gfar_ioctl,
+	.ndo_select_queue = gfar_select_queue,
 	.ndo_vlan_rx_register = gfar_vlan_rx_register,
 	.ndo_set_mac_address = eth_mac_addr,
 	.ndo_validate_addr = eth_validate_addr,
@@ -382,36 +422,131 @@ static const struct net_device_ops gfar_netdev_ops = {
 #endif
 };
 
+inline void lock_rx_qs(struct gfar_private *priv)
+{
+	int i = 0x0;
+
+	for (i = 0; i < priv->num_rx_queues; i++)
+		spin_lock(&priv->rx_queue[i]->rxlock);
+}
+
+inline void lock_tx_qs(struct gfar_private *priv)
+{
+	int i = 0x0;
+
+	for (i = 0; i < priv->num_tx_queues; i++)
+		spin_lock(&priv->tx_queue[i]->txlock);
+}
+
+inline void unlock_rx_qs(struct gfar_private *priv)
+{
+	int i = 0x0;
+
+	for (i = 0; i < priv->num_rx_queues; i++)
+		spin_unlock(&priv->rx_queue[i]->rxlock);
+}
+
+inline void unlock_tx_qs(struct gfar_private *priv)
+{
+	int i = 0x0;
+
+	for (i = 0; i < priv->num_tx_queues; i++)
+		spin_unlock(&priv->tx_queue[i]->txlock);
+}
+
 /* Returns 1 if incoming frames use an FCB */
 static inline int gfar_uses_fcb(struct gfar_private *priv)
 {
 	return priv->vlgrp || priv->rx_csum_enable;
 }
 
-static int gfar_of_init(struct net_device *dev)
+u16 gfar_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+	return skb_get_queue_mapping(skb);
+}
+static void free_tx_pointers(struct gfar_private *priv)
+{
+	int i = 0;
+
+	for (i = 0; i < priv->num_tx_queues; i++)
+		kfree(priv->tx_queue[i]);
+}
+
+static void free_rx_pointers(struct gfar_private *priv)
+{
+	int i = 0;
+
+	for (i = 0; i < priv->num_rx_queues; i++)
+		kfree(priv->rx_queue[i]);
+}
+
+static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
 {
 	const char *model;
 	const char *ctype;
 	const void *mac_addr;
 	u64 addr, size;
-	int err = 0;
-	struct gfar_private *priv = netdev_priv(dev);
-	struct device_node *np = priv->node;
+	int err = 0, i;
+	struct net_device *dev = NULL;
+	struct gfar_private *priv = NULL;
+	struct device_node *np = ofdev->node;
 	const u32 *stash;
 	const u32 *stash_len;
 	const u32 *stash_idx;
+	unsigned int num_tx_qs, num_rx_qs;
+	u32 *tx_queues, *rx_queues;
 
 	if (!np || !of_device_is_available(np))
 		return -ENODEV;
 
+	/* parse the num of tx and rx queues */
+	tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL);
+	num_tx_qs = tx_queues ? *tx_queues : 1;
+
+	if (num_tx_qs > MAX_TX_QS) {
+		printk(KERN_ERR "num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n",
+				num_tx_qs, MAX_TX_QS);
+		printk(KERN_ERR "Cannot do alloc_etherdev, aborting\n");
+		return -EINVAL;
+	}
+
+	rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
+	num_rx_qs = rx_queues ? *rx_queues : 1;
+
+	if (num_rx_qs > MAX_RX_QS) {
+		printk(KERN_ERR "num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n",
+				num_tx_qs, MAX_TX_QS);
+		printk(KERN_ERR "Cannot do alloc_etherdev, aborting\n");
+		return -EINVAL;
+	}
+
+	*pdev = alloc_etherdev_mq(sizeof(*priv), num_tx_qs);
+	dev = *pdev;
+	if (NULL == dev)
+		return -ENOMEM;
+
+	priv = netdev_priv(dev);
+	priv->node = ofdev->node;
+	priv->ndev = dev;
+
+	dev->num_tx_queues = num_tx_qs;
+	dev->real_num_tx_queues = num_tx_qs;
+	priv->num_tx_queues = num_tx_qs;
+	priv->num_rx_queues = num_rx_qs;
+
 	/* get a pointer to the register memory */
 	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
 	priv->gfargrp.regs = ioremap(addr, size);
 
-	if (priv->gfargrp.regs == NULL)
-		return -ENOMEM;
+	if (priv->gfargrp.regs == NULL) {
+		err = -ENOMEM;
+		goto err_out;
+	}
 
 	priv->gfargrp.priv = priv; /* back pointer from group to priv */
+	priv->gfargrp.rx_bit_map = DEFAULT_MAPPING;
+	priv->gfargrp.tx_bit_map = DEFAULT_MAPPING;
+
 	priv->gfargrp.interruptTransmit = irq_of_parse_and_map(np, 0);
 
 	model = of_get_property(np, "model", NULL);
@@ -430,6 +565,38 @@ static int gfar_of_init(struct net_device *dev)
 		}
 	}
 
+	for (i = 0; i < priv->num_tx_queues; i++)
+	       priv->tx_queue[i] = NULL;
+	for (i = 0; i < priv->num_rx_queues; i++)
+		priv->rx_queue[i] = NULL;
+
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		priv->tx_queue[i] =  (struct gfar_priv_tx_q *)kmalloc(
+				sizeof (struct gfar_priv_tx_q), GFP_KERNEL);
+		if (!priv->tx_queue[i]) {
+			err = -ENOMEM;
+			goto tx_alloc_failed;
+		}
+		priv->tx_queue[i]->tx_skbuff = NULL;
+		priv->tx_queue[i]->qindex = i;
+		priv->tx_queue[i]->dev = dev;
+		spin_lock_init(&(priv->tx_queue[i]->txlock));
+	}
+
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		priv->rx_queue[i] = (struct gfar_priv_rx_q *)kmalloc(
+					sizeof (struct gfar_priv_rx_q), GFP_KERNEL);
+		if (!priv->rx_queue[i]) {
+			err = -ENOMEM;
+			goto rx_alloc_failed;
+		}
+		priv->rx_queue[i]->rx_skbuff = NULL;
+		priv->rx_queue[i]->qindex = i;
+		priv->rx_queue[i]->dev = dev;
+		spin_lock_init(&(priv->rx_queue[i]->rxlock));
+	}
+
+
 	stash = of_get_property(np, "bd-stash", NULL);
 
 	if (stash) {
@@ -490,8 +657,13 @@ static int gfar_of_init(struct net_device *dev)
 
 	return 0;
 
+rx_alloc_failed:
+	free_rx_pointers(priv);
+tx_alloc_failed:
+	free_tx_pointers(priv);
 err_out:
 	iounmap(priv->gfargrp.regs);
+	free_netdev(dev);
 	return err;
 }
 
@@ -509,6 +681,17 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 	return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
 }
 
+static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
+{
+	unsigned int new_bit_map = 0x0;
+	int mask = 0x1 << (max_qs - 1), i;
+	for (i = 0; i < max_qs; i++) {
+		if (bit_map & mask)
+			new_bit_map = new_bit_map + (1 << i);
+		mask = mask >> 0x1;
+	}
+	return new_bit_map;
+}
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
 static int gfar_probe(struct of_device *ofdev,
@@ -518,14 +701,14 @@ static int gfar_probe(struct of_device *ofdev,
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
 	struct gfar __iomem *regs = NULL;
-	int err = 0;
+	int err = 0, i;
 	int len_devname;
+	u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
 
-	/* Create an ethernet device instance */
-	dev = alloc_etherdev(sizeof (*priv));
+	err = gfar_of_init(ofdev, &dev);
 
-	if (NULL == dev)
-		return -ENOMEM;
+	if (err)
+		return err;
 
 	priv = netdev_priv(dev);
 	priv->ndev = dev;
@@ -533,23 +716,6 @@ static int gfar_probe(struct of_device *ofdev,
 	priv->node = ofdev->node;
 	SET_NETDEV_DEV(dev, &ofdev->dev);
 
-	err = gfar_of_init(dev);
-
-	if (err)
-		goto regs_fail;
-
-	priv->tx_queue = (struct gfar_priv_tx_q *)kmalloc(
-				sizeof (struct gfar_priv_tx_q), GFP_KERNEL);
-	if (!priv->tx_queue)
-		goto regs_fail;
-
-	priv->rx_queue = (struct gfar_priv_rx_q *)kmalloc(
-				sizeof (struct gfar_priv_rx_q), GFP_KERNEL);
-	if (!priv->rx_queue)
-		goto rx_queue_fail;
-
-	spin_lock_init(&priv->tx_queue->txlock);
-	spin_lock_init(&priv->rx_queue->rxlock);
 	spin_lock_init(&priv->gfargrp.grplock);
 	spin_lock_init(&priv->bflock);
 	INIT_WORK(&priv->reset_task, gfar_reset_task);
@@ -587,8 +753,8 @@ static int gfar_probe(struct of_device *ofdev,
 	dev->netdev_ops = &gfar_netdev_ops;
 	dev->ethtool_ops = &gfar_ethtool_ops;
 
-	/* Register for napi ...NAPI is for each rx_queue */
-	netif_napi_add(dev, &priv->rx_queue->napi, gfar_poll, GFAR_DEV_WEIGHT);
+	/* Register for napi ...We are registering NAPI for each grp */
+	netif_napi_add(dev, &priv->gfargrp.napi, gfar_poll, GFAR_DEV_WEIGHT);
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
 		priv->rx_csum_enable = 1;
@@ -644,17 +810,44 @@ static int gfar_probe(struct of_device *ofdev,
 	if (dev->features & NETIF_F_IP_CSUM)
 		dev->hard_header_len += GMAC_FCB_LEN;
 
+	/* Need to reverse the bit maps as  bit_map's MSB is q0
+	 * but, for_each_bit parses from right to left, which
+	 * basically reverses the queue numbers */
+	priv->gfargrp.tx_bit_map = reverse_bitmap(priv->gfargrp.tx_bit_map, MAX_TX_QS);
+	priv->gfargrp.rx_bit_map = reverse_bitmap(priv->gfargrp.rx_bit_map, MAX_RX_QS);
+
+	/* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values */
+	for_each_bit(i, &priv->gfargrp.rx_bit_map, priv->num_rx_queues) {
+		priv->gfargrp.num_rx_queues++;
+		rstat = rstat | (RSTAT_CLEAR_RHALT >> i);
+		rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
+	}
+	for_each_bit (i, &priv->gfargrp.tx_bit_map, priv->num_tx_queues) {
+		priv->gfargrp.num_tx_queues++;
+		tstat = tstat | (TSTAT_CLEAR_THALT >> i);
+		tqueue = tqueue | (TQUEUE_EN0 >> i);
+	}
+	priv->gfargrp.rstat = rstat;
+	priv->gfargrp.tstat = tstat;
+
+	gfar_write(&regs->rqueue, rqueue);
+	gfar_write(&regs->tqueue, tqueue);
+
 	priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
 
 	/* Initializing some of the rx/tx queue level parameters */
-	priv->tx_queue->tx_ring_size = DEFAULT_TX_RING_SIZE;
-	priv->tx_queue->num_txbdfree = DEFAULT_TX_RING_SIZE;
-	priv->tx_queue->txcoalescing = DEFAULT_TX_COALESCE;
-	priv->tx_queue->txic = DEFAULT_TXIC;
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE;
+		priv->tx_queue[i]->num_txbdfree = DEFAULT_TX_RING_SIZE;
+		priv->tx_queue[i]->txcoalescing = DEFAULT_TX_COALESCE;
+		priv->tx_queue[i]->txic = DEFAULT_TXIC;
+	}
 
-	priv->rx_queue->rx_ring_size = DEFAULT_RX_RING_SIZE;
-	priv->rx_queue->rxcoalescing = DEFAULT_RX_COALESCE;
-	priv->rx_queue->rxic = DEFAULT_RXIC;
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		priv->rx_queue[i]->rx_ring_size = DEFAULT_RX_RING_SIZE;
+		priv->rx_queue[i]->rxcoalescing = DEFAULT_RX_COALESCE;
+		priv->rx_queue[i]->rxic = DEFAULT_RXIC;
+	}
 
 	/* Enable most messages by default */
 	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
@@ -699,17 +892,19 @@ static int gfar_probe(struct of_device *ofdev,
 	/* Even more device info helps when determining which kernel */
 	/* provided which set of benchmarks. */
 	printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);
-	printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n",
-	       dev->name, priv->rx_queue->rx_ring_size, priv->tx_queue->tx_ring_size);
+	for (i = 0; i < priv->num_rx_queues; i++)
+		printk(KERN_INFO "%s: :RX BD ring size for Q[%d]: %d\n",
+			dev->name, i, priv->rx_queue[i]->rx_ring_size);
+	for(i = 0; i < priv->num_tx_queues; i++)
+		 printk(KERN_INFO "%s:TX BD ring size for Q[%d]: %d\n",
+			dev->name, i, priv->tx_queue[i]->tx_ring_size);
 
 	return 0;
 
 register_fail:
 	iounmap(priv->gfargrp.regs);
-	kfree(priv->rx_queue);
-rx_queue_fail:
-	kfree(priv->tx_queue);
-regs_fail:
+	free_tx_pointers(priv);
+	free_rx_pointers(priv);
 	if (priv->phy_node)
 		of_node_put(priv->phy_node);
 	if (priv->tbi_node)
@@ -742,8 +937,6 @@ static int gfar_suspend(struct device *dev)
 {
 	struct gfar_private *priv = dev_get_drvdata(dev);
 	struct net_device *ndev = priv->ndev;
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct gfar __iomem *regs = NULL;
 	unsigned long flags;
 	u32 tempval;
@@ -752,13 +945,13 @@ static int gfar_suspend(struct device *dev)
 		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	netif_device_detach(ndev);
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
 	regs = priv->gfargrp.regs;
 
 	if (netif_running(ndev)) {
-		spin_lock_irqsave(&tx_queue->txlock, flags);
-		spin_lock(&rx_queue->rxlock);
+
+		local_irq_save(flags);
+		lock_tx_qs(priv);
+		lock_rx_qs(priv);
 
 		gfar_halt_nodisable(ndev);
 
@@ -772,10 +965,11 @@ static int gfar_suspend(struct device *dev)
 
 		gfar_write(&regs->maccfg1, tempval);
 
-		spin_unlock(&rx_queue->rxlock);
-		spin_unlock_irqrestore(&tx_queue->txlock, flags);
+		unlock_rx_qs(priv);
+		unlock_tx_qs(priv);
+		local_irq_restore(flags);
 
-		napi_disable(&rx_queue->napi);
+		napi_disable(&priv->gfargrp.napi);
 
 		if (magic_packet) {
 			/* Enable interrupt on Magic Packet */
@@ -797,8 +991,6 @@ static int gfar_resume(struct device *dev)
 {
 	struct gfar_private *priv = dev_get_drvdata(dev);
 	struct net_device *ndev = priv->ndev;
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct gfar __iomem *regs = NULL;
 	unsigned long flags;
 	u32 tempval;
@@ -816,12 +1008,11 @@ static int gfar_resume(struct device *dev)
 	/* Disable Magic Packet mode, in case something
 	 * else woke us up.
 	 */
-	rx_queue = priv->rx_queue;
-	tx_queue = priv->tx_queue;
 	regs = priv->gfargrp.regs;
 
-	spin_lock_irqsave(&tx_queue->txlock, flags);
-	spin_lock(&rx_queue->rxlock);
+	local_irq_save(flags);
+	lock_tx_qs(priv);
+	lock_rx_qs(priv);
 
 	tempval = gfar_read(&regs->maccfg2);
 	tempval &= ~MACCFG2_MPEN;
@@ -829,12 +1020,13 @@ static int gfar_resume(struct device *dev)
 
 	gfar_start(ndev);
 
-	spin_unlock(&rx_queue->rxlock);
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
+	unlock_rx_qs(priv);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 
 	netif_device_attach(ndev);
 
-	napi_enable(&rx_queue->napi);
+	napi_enable(&priv->gfargrp.napi);
 
 	return 0;
 }
@@ -861,7 +1053,7 @@ static int gfar_restore(struct device *dev)
 		phy_start(priv->phydev);
 
 	netif_device_attach(ndev);
-	napi_enable(&priv->napi);
+	napi_enable(&priv->gfargrp.napi);
 
 	return 0;
 }
@@ -1115,23 +1307,21 @@ void gfar_halt(struct net_device *dev)
 void stop_gfar(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 
 	phy_stop(priv->phydev);
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
 
 	/* Lock it down */
-	spin_lock_irqsave(&tx_queue->txlock, flags);
-	spin_lock(&rx_queue->rxlock);
+	local_irq_save(flags);
+	lock_tx_qs(priv);
+	lock_rx_qs(priv);
 
 	gfar_halt(dev);
 
-	spin_unlock(&rx_queue->rxlock);
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
+	unlock_rx_qs(priv);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 
 	/* Free the IRQs */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
@@ -1145,24 +1335,14 @@ void stop_gfar(struct net_device *dev)
 	free_skb_resources(priv);
 }
 
-/* If there are any tx skbs or rx skbs still around, free them.
- * Then free tx_skbuff and rx_skbuff */
-static void free_skb_resources(struct gfar_private *priv)
+static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue)
 {
-	struct device *dev = &priv->ofdev->dev;
-	struct rxbd8 *rxbdp;
 	struct txbd8 *txbdp;
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar_private *priv = netdev_priv(tx_queue->dev);
 	int i, j;
 
-	/* Go through all the buffer descriptors and free their data buffers */
-	tx_queue = priv->tx_queue;
 	txbdp = tx_queue->tx_bd_base;
 
-	if (!tx_queue->tx_skbuff)
-		goto skip_tx_skbuff;
-
 	for (i = 0; i < tx_queue->tx_ring_size; i++) {
 		if (!tx_queue->tx_skbuff[i])
 			continue;
@@ -1170,7 +1350,8 @@ static void free_skb_resources(struct gfar_private *priv)
 		dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr,
 				txbdp->length, DMA_TO_DEVICE);
 		txbdp->lstatus = 0;
-		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags; j++) {
+		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags;
+				j++) {
 			txbdp++;
 			dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr,
 					txbdp->length, DMA_TO_DEVICE);
@@ -1179,36 +1360,58 @@ static void free_skb_resources(struct gfar_private *priv)
 		dev_kfree_skb_any(tx_queue->tx_skbuff[i]);
 		tx_queue->tx_skbuff[i] = NULL;
 	}
-
 	kfree(tx_queue->tx_skbuff);
-skip_tx_skbuff:
+}
 
-	rx_queue = priv->rx_queue;
-	rxbdp = rx_queue->rx_bd_base;
+static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
+{
+	struct rxbd8 *rxbdp;
+	struct gfar_private *priv = netdev_priv(rx_queue->dev);
+	int i;
 
-	if (!rx_queue->rx_skbuff)
-		goto skip_rx_skbuff;
+	rxbdp = rx_queue->rx_bd_base;
 
 	for (i = 0; i < rx_queue->rx_ring_size; i++) {
 		if (rx_queue->rx_skbuff[i]) {
-			dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
-					 priv->rx_buffer_size,
+			dma_unmap_single(&priv->ofdev->dev,
+					rxbdp->bufPtr, priv->rx_buffer_size,
 					DMA_FROM_DEVICE);
 			dev_kfree_skb_any(rx_queue->rx_skbuff[i]);
 			rx_queue->rx_skbuff[i] = NULL;
 		}
-
 		rxbdp->lstatus = 0;
 		rxbdp->bufPtr = 0;
 		rxbdp++;
 	}
-
 	kfree(rx_queue->rx_skbuff);
-skip_rx_skbuff:
+}
+
+/* If there are any tx skbs or rx skbs still around, free them.
+ * Then free tx_skbuff and rx_skbuff */
+static void free_skb_resources(struct gfar_private *priv)
+{
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
+	int i;
+
+	/* Go through all the buffer descriptors and free their data buffers */
+	for (i = 0; i < priv->num_tx_queues; i++) {
+		tx_queue = priv->tx_queue[i];
+		if(!tx_queue->tx_skbuff)
+			free_skb_tx_queue(tx_queue);
+	}
 
-	dma_free_coherent(dev, sizeof(*txbdp) * tx_queue->tx_ring_size +
-			       sizeof(*rxbdp) * rx_queue->rx_ring_size,
-			  tx_queue->tx_bd_base, tx_queue->tx_bd_dma_base);
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		rx_queue = priv->rx_queue[i];
+		if(!rx_queue->rx_skbuff)
+			free_skb_rx_queue(rx_queue);
+	}
+
+	dma_free_coherent(&priv->ofdev->dev,
+			sizeof(struct txbd8) * priv->total_tx_ring_size +
+			sizeof(struct rxbd8) * priv->total_rx_ring_size,
+			priv->tx_queue[0]->tx_bd_base,
+			priv->tx_queue[0]->tx_bd_dma_base);
 }
 
 void gfar_start(struct net_device *dev)
@@ -1233,8 +1436,8 @@ void gfar_start(struct net_device *dev)
 	gfar_write(&regs->dmactrl, tempval);
 
 	/* Clear THLT/RHLT, so that the DMA starts polling now */
-	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
-	gfar_write(&regs->rstat, RSTAT_CLEAR_RHALT);
+	gfar_write(&regs->tstat, priv->gfargrp.tstat);
+	gfar_write(&regs->rstat, priv->gfargrp.rstat);
 
 	/* Unmask the interrupts we look for */
 	gfar_write(&regs->imask, IMASK_DEFAULT);
@@ -1329,7 +1532,7 @@ static int gfar_enet_open(struct net_device *dev)
 	struct gfar_private *priv = netdev_priv(dev);
 	int err;
 
-	napi_enable(&priv->rx_queue->napi);
+	napi_enable(&priv->gfargrp.napi);
 
 	skb_queue_head_init(&priv->rx_recycle);
 
@@ -1341,17 +1544,17 @@ static int gfar_enet_open(struct net_device *dev)
 	err = init_phy(dev);
 
 	if (err) {
-		napi_disable(&priv->rx_queue->napi);
+		napi_disable(&priv->gfargrp.napi);
 		return err;
 	}
 
 	err = startup_gfar(dev);
 	if (err) {
-		napi_disable(&priv->rx_queue->napi);
+		napi_disable(&priv->gfargrp.napi);
 		return err;
 	}
 
-	netif_start_queue(dev);
+	netif_tx_start_all_queues(dev);
 
 	device_set_wakeup_enable(&dev->dev, priv->wol_en);
 
@@ -1421,16 +1624,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct netdev_queue *txq;
 	struct gfar __iomem *regs = NULL;
 	struct txfcb *fcb = NULL;
 	struct txbd8 *txbdp, *txbdp_start, *base;
 	u32 lstatus;
-	int i;
+	int i, rq = 0;
 	u32 bufaddr;
 	unsigned long flags;
 	unsigned int nr_frags, length;
 
-	tx_queue = priv->tx_queue;
+
+	rq = skb->queue_mapping;
+	tx_queue = priv->tx_queue[rq];
+	txq = netdev_get_tx_queue(dev, rq);
 	base = tx_queue->tx_bd_base;
 	regs = priv->gfargrp.regs;
 
@@ -1458,7 +1665,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* check if there is space to queue this packet */
 	if ((nr_frags+1) > tx_queue->num_txbdfree) {
 		/* no space, stop the queue */
-		netif_stop_queue(dev);
+		netif_tx_stop_queue(txq);
 		dev->stats.tx_fifo_errors++;
 		spin_unlock_irqrestore(&tx_queue->txlock, flags);
 		return NETDEV_TX_BUSY;
@@ -1550,13 +1757,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* If the next BD still needs to be cleaned up, then the bds
 	   are full.  We need to tell the kernel to stop sending us stuff. */
 	if (!tx_queue->num_txbdfree) {
-		netif_stop_queue(dev);
+		netif_tx_stop_queue(txq);
 
 		dev->stats.tx_fifo_errors++;
 	}
 
 	/* Tell the DMA to go go go */
-	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT >> tx_queue->qindex);
 
 	/* Unlock priv */
 	spin_unlock_irqrestore(&tx_queue->txlock, flags);
@@ -1569,7 +1776,7 @@ static int gfar_close(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	napi_disable(&priv->rx_queue->napi);
+	napi_disable(&priv->gfargrp.napi);
 
 	skb_queue_purge(&priv->rx_recycle);
 	cancel_work_sync(&priv->reset_task);
@@ -1579,7 +1786,7 @@ static int gfar_close(struct net_device *dev)
 	phy_disconnect(priv->phydev);
 	priv->phydev = NULL;
 
-	netif_stop_queue(dev);
+	netif_tx_stop_all_queues(dev);
 
 	return 0;
 }
@@ -1598,14 +1805,13 @@ static void gfar_vlan_rx_register(struct net_device *dev,
 		struct vlan_group *grp)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct gfar __iomem *regs = NULL;
 	unsigned long flags;
 	u32 tempval;
 
-	rx_queue = priv->rx_queue;
 	regs = priv->gfargrp.regs;
-	spin_lock_irqsave(&rx_queue->rxlock, flags);
+	local_irq_save(flags);
+	lock_rx_qs(priv);
 
 	priv->vlgrp = grp;
 
@@ -1639,7 +1845,8 @@ static void gfar_vlan_rx_register(struct net_device *dev,
 
 	gfar_change_mtu(dev, dev->mtu);
 
-	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
+	unlock_rx_qs(priv);
+	local_irq_restore(flags);
 }
 
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
@@ -1711,10 +1918,10 @@ static void gfar_reset_task(struct work_struct *work)
 	struct net_device *dev = priv->ndev;
 
 	if (dev->flags & IFF_UP) {
-		netif_stop_queue(dev);
+		netif_tx_stop_all_queues(dev);
 		stop_gfar(dev);
 		startup_gfar(dev);
-		netif_start_queue(dev);
+		netif_tx_start_all_queues(dev);
 	}
 
 	netif_tx_schedule_all(dev);
@@ -1745,7 +1952,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 	int howmany = 0;
 	u32 lstatus;
 
-	rx_queue = priv->rx_queue;
+	rx_queue = priv->rx_queue[tx_queue->qindex];
 	bdp = tx_queue->dirty_tx;
 	skb_dirtytx = tx_queue->skb_dirtytx;
 
@@ -1798,8 +2005,8 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 	}
 
 	/* If we freed a buffer, we can restart transmission, if necessary */
-	if (netif_queue_stopped(dev) && tx_queue->num_txbdfree)
-		netif_wake_queue(dev);
+	if (__netif_subqueue_stopped(dev, tx_queue->qindex) && tx_queue->num_txbdfree)
+		netif_wake_subqueue(dev, tx_queue->qindex);
 
 	/* Update dirty indicators */
 	tx_queue->skb_dirtytx = skb_dirtytx;
@@ -1812,19 +2019,12 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
 static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
 {
-	struct gfar_private *priv = gfargrp->priv;
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 
-	rx_queue = priv->rx_queue;
-	tx_queue = priv->tx_queue;
-	spin_lock_irqsave(&tx_queue->txlock, flags);
-	spin_lock(&rx_queue->rxlock);
-
-	if (napi_schedule_prep(&rx_queue->napi)) {
+	spin_lock_irqsave(&gfargrp->grplock, flags);
+	if (napi_schedule_prep(&gfargrp->napi)) {
 		gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED);
-		__napi_schedule(&rx_queue->napi);
+		__napi_schedule(&gfargrp->napi);
 	} else {
 		/*
 		 * Clear IEVENT, so interrupts aren't called again
@@ -1832,9 +2032,8 @@ static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
 		 */
 		gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK);
 	}
+	spin_unlock_irqrestore(&gfargrp->grplock, flags);
 
-	spin_unlock(&rx_queue->rxlock);
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 }
 
 /* Interrupt Handler for Transmit complete */
@@ -1952,6 +2151,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 	fcb = (struct rxfcb *)skb->data;
 
 	/* Remove the FCB from the skb */
+	skb_set_queue_mapping(skb, fcb->rq);
 	/* Remove the padded bytes, if there are any */
 	if (amount_pull)
 		skb_pull(skb, amount_pull);
@@ -2072,28 +2272,54 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 
 static int gfar_poll(struct napi_struct *napi, int budget)
 {
-	struct gfar_priv_rx_q *rx_queue = container_of(napi,
-			struct gfar_priv_rx_q, napi);
-	struct net_device *dev = rx_queue->dev;
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_grp *gfargrp = container_of(napi,
+			struct gfar_priv_grp, napi);
+	struct gfar_private *priv = gfargrp->priv;
 	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
-	int tx_cleaned = 0;
-	int rx_cleaned = 0;
+	struct gfar_priv_rx_q *rx_queue = NULL;
+	int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0;
+	int tx_cleaned = 0, i, left_over_budget = budget, serviced_queues = 0;
+	int num_queues = 0;
 	unsigned long flags;
 
+	num_queues = gfargrp->num_rx_queues;
+	budget_per_queue = budget/num_queues;
+
 	/* Clear IEVENT, so interrupts aren't called again
 	 * because of the packets that have already arrived */
 	gfar_write(&regs->ievent, IEVENT_RTX_MASK);
-	tx_queue = priv->tx_queue;
 
-	/* If we fail to get the lock, don't bother with the TX BDs */
-	if (spin_trylock_irqsave(&tx_queue->txlock, flags)) {
-		tx_cleaned = gfar_clean_tx_ring(tx_queue);
-		spin_unlock_irqrestore(&tx_queue->txlock, flags);
-	}
+	while (num_queues && left_over_budget) {
 
-	rx_cleaned = gfar_clean_rx_ring(rx_queue, budget);
+		budget_per_queue = left_over_budget/num_queues;
+		left_over_budget = 0;
+
+		for_each_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
+			if (test_bit(i, &serviced_queues))
+				continue;
+			rx_queue = priv->rx_queue[i];
+			tx_queue = priv->tx_queue[rx_queue->qindex];
+
+			/* If we fail to get the lock,
+			 * don't bother with the TX BDs */
+			if (spin_trylock_irqsave(&tx_queue->txlock, flags)) {
+				tx_cleaned += gfar_clean_tx_ring(tx_queue);
+				spin_unlock_irqrestore(&tx_queue->txlock,
+							flags);
+			}
+
+			rx_cleaned_per_queue = gfar_clean_rx_ring(rx_queue,
+							budget_per_queue);
+			rx_cleaned += rx_cleaned_per_queue;
+			if(rx_cleaned_per_queue < budget_per_queue) {
+				left_over_budget = left_over_budget +
+					(budget_per_queue - rx_cleaned_per_queue);
+				set_bit(i, &serviced_queues);
+				num_queues--;
+			}
+		}
+	}
 
 	if (tx_cleaned)
 		return budget;
@@ -2102,7 +2328,7 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 		napi_complete(napi);
 
 		/* Clear the halt bit in RSTAT */
-		gfar_write(&regs->rstat, RSTAT_CLEAR_RHALT);
+		gfar_write(&regs->rstat, gfargrp->rstat);
 
 		gfar_write(&regs->imask, IMASK_DEFAULT);
 
@@ -2180,14 +2406,14 @@ static irqreturn_t gfar_interrupt(int irq, void *grp_id)
 static void adjust_link(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar __iomem *regs = priv->gfargrp.regs;
 	unsigned long flags;
 	struct phy_device *phydev = priv->phydev;
 	int new_state = 0;
 
-	tx_queue = priv->tx_queue;
-	spin_lock_irqsave(&tx_queue->txlock, flags);
+	local_irq_save(flags);
+	lock_tx_qs(priv);
+
 	if (phydev->link) {
 		u32 tempval = gfar_read(&regs->maccfg2);
 		u32 ecntrl = gfar_read(&regs->ecntrl);
@@ -2252,8 +2478,8 @@ static void adjust_link(struct net_device *dev)
 
 	if (new_state && netif_msg_link(priv))
 		phy_print_status(phydev);
-
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 }
 
 /* Update the hash table based on the current list of multicast
@@ -2457,7 +2683,7 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
 			priv->extra_stats.tx_underrun++;
 
 			/* Reactivate the Tx Queues */
-			gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+			gfar_write(&regs->tstat, gfargrp->tstat);
 		}
 		if (netif_msg_tx_err(priv))
 			printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 79e8471..fc43cfd 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -75,6 +75,10 @@
 extern const char gfar_driver_name[];
 extern const char gfar_driver_version[];
 
+/* MAXIMUM NUMBER OF QUEUES SUPPORTED */
+#define MAX_TX_QS	0x8
+#define MAX_RX_QS	0x8
+
 /* These need to be powers of 2 for this driver */
 #define DEFAULT_TX_RING_SIZE	256
 #define DEFAULT_RX_RING_SIZE	256
@@ -172,12 +176,63 @@ extern const char gfar_driver_version[];
 
 #define MINFLR_INIT_SETTINGS	0x00000040
 
+/* Tqueue control */
+#define TQUEUE_EN0		0x00008000
+#define TQUEUE_EN1		0x00004000
+#define TQUEUE_EN2		0x00002000
+#define TQUEUE_EN3		0x00001000
+#define TQUEUE_EN4		0x00000800
+#define TQUEUE_EN5		0x00000400
+#define TQUEUE_EN6		0x00000200
+#define TQUEUE_EN7		0x00000100
+#define TQUEUE_EN_ALL		0x0000FF00
+
+#define TR03WT_WT0_MASK		0xFF000000
+#define TR03WT_WT1_MASK		0x00FF0000
+#define TR03WT_WT2_MASK		0x0000FF00
+#define TR03WT_WT3_MASK		0x000000FF
+
+#define TR47WT_WT4_MASK		0xFF000000
+#define TR47WT_WT5_MASK		0x00FF0000
+#define TR47WT_WT6_MASK		0x0000FF00
+#define TR47WT_WT7_MASK		0x000000FF
+
+/* Rqueue control */
+#define RQUEUE_EX0		0x00800000
+#define RQUEUE_EX1		0x00400000
+#define RQUEUE_EX2		0x00200000
+#define RQUEUE_EX3		0x00100000
+#define RQUEUE_EX4		0x00080000
+#define RQUEUE_EX5		0x00040000
+#define RQUEUE_EX6		0x00020000
+#define RQUEUE_EX7		0x00010000
+#define RQUEUE_EX_ALL		0x00FF0000
+
+#define RQUEUE_EN0		0x00000080
+#define RQUEUE_EN1		0x00000040
+#define RQUEUE_EN2		0x00000020
+#define RQUEUE_EN3		0x00000010
+#define RQUEUE_EN4		0x00000008
+#define RQUEUE_EN5		0x00000004
+#define RQUEUE_EN6		0x00000002
+#define RQUEUE_EN7		0x00000001
+#define RQUEUE_EN_ALL		0x000000FF
+
 /* Init to do tx snooping for buffers and descriptors */
 #define DMACTRL_INIT_SETTINGS   0x000000c3
 #define DMACTRL_GRS             0x00000010
 #define DMACTRL_GTS             0x00000008
 
-#define TSTAT_CLEAR_THALT       0x80000000
+#define TSTAT_CLEAR_THALT_ALL	0xFF000000
+#define TSTAT_CLEAR_THALT	0x80000000
+#define TSTAT_CLEAR_THALT0	0x80000000
+#define TSTAT_CLEAR_THALT1	0x40000000
+#define TSTAT_CLEAR_THALT2	0x20000000
+#define TSTAT_CLEAR_THALT3	0x10000000
+#define TSTAT_CLEAR_THALT4	0x08000000
+#define TSTAT_CLEAR_THALT5	0x04000000
+#define TSTAT_CLEAR_THALT6	0x02000000
+#define TSTAT_CLEAR_THALT7	0x01000000
 
 /* Interrupt coalescing macros */
 #define IC_ICEN			0x80000000
@@ -228,6 +283,13 @@ extern const char gfar_driver_version[];
 #define TCTRL_IPCSEN		0x00004000
 #define TCTRL_TUCSEN		0x00002000
 #define TCTRL_VLINS		0x00001000
+#define TCTRL_THDF		0x00000800
+#define TCTRL_RFCPAUSE		0x00000010
+#define TCTRL_TFCPAUSE		0x00000008
+#define TCTRL_TXSCHED_MASK	0x00000006
+#define TCTRL_TXSCHED_INIT	0x00000000
+#define TCTRL_TXSCHED_PRIO	0x00000002
+#define TCTRL_TXSCHED_WRRS	0x00000004
 #define TCTRL_INIT_CSUM		(TCTRL_TUCSEN | TCTRL_IPCSEN)
 
 #define IEVENT_INIT_CLEAR	0xffffffff
@@ -700,6 +762,8 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_BD_STASHING		0x00000200
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING	0x00000400
 
+#define DEFAULT_MAPPING 	0xFF
+
 /**
  *	struct gfar_priv_tx_q - per tx queue structure
  *	@txlock: per queue tx spin lock
@@ -743,7 +807,6 @@ struct gfar_priv_tx_q {
 /**
  *	struct gfar_priv_rx_q - per rx queue structure
  *	@rxlock: per queue rx spin lock
- *	@napi: the napi poll function
  *	@rx_skbuff: skb pointers
  *	@skb_currx: currently use skb pointer
  *	@rx_bd_base: First rx buffer descriptor
@@ -757,7 +820,6 @@ struct gfar_priv_tx_q {
 
 struct gfar_priv_rx_q {
 	spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
-	struct	napi_struct napi;
 	struct	sk_buff ** rx_skbuff;
 	struct	rxbd8 *rx_bd_base;
 	struct	rxbd8 *cur_rx;
@@ -772,6 +834,7 @@ struct gfar_priv_rx_q {
 
 /**
  *	struct gfar_priv_grp - per group structure
+ *	@napi: the napi poll function
  *	@priv: back pointer to the priv structure
  *	@regs: the ioremapped register space for this group
  *	@grp_id: group id for this group
@@ -785,8 +848,17 @@ struct gfar_priv_rx_q {
 
 struct gfar_priv_grp {
 	spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES)));
+	struct	napi_struct napi;
 	struct gfar_private *priv;
 	struct gfar __iomem *regs;
+	unsigned int rx_bit_map;
+	unsigned int tx_bit_map;
+	unsigned int num_tx_queues;
+	unsigned int num_rx_queues;
+	unsigned int rstat;
+	unsigned int tstat;
+	unsigned int imask;
+	unsigned int ievent;
 	unsigned int interruptTransmit;
 	unsigned int interruptReceive;
 	unsigned int interruptError;
@@ -807,13 +879,21 @@ struct gfar_priv_grp {
  */
 struct gfar_private {
 
+	/* Indicates how many tx, rx queues are enabled */
+	unsigned int num_tx_queues;
+	unsigned int num_rx_queues;
+
+	/* The total tx and rx ring size for the enabled queues */
+	unsigned int total_tx_ring_size;
+	unsigned int total_rx_ring_size;
+
 	struct device_node *node;
 	struct net_device *ndev;
 	struct of_device *ofdev;
 
 	struct gfar_priv_grp gfargrp;
-	struct gfar_priv_tx_q *tx_queue;
-	struct gfar_priv_rx_q *rx_queue;
+	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
+	struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
 
 	/* RX per device parameters */
 	unsigned int rx_buffer_size;
@@ -844,6 +924,7 @@ struct gfar_private {
 	unsigned char rx_csum_enable:1,
 		extended_hash:1,
 		bd_stash_en:1,
+		rx_filer_enable:1,
 		wol_en:1; /* Wake-on-LAN enabled */
 	unsigned short padding;
 
@@ -874,6 +955,10 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
 	out_be32(addr, val);
 }
 
+extern inline void lock_rx_qs(struct gfar_private *priv);
+extern inline void lock_tx_qs(struct gfar_private *priv);
+extern inline void unlock_rx_qs(struct gfar_private *priv);
+extern inline void unlock_tx_qs(struct gfar_private *priv);
 extern irqreturn_t gfar_receive(int irq, void *dev_id);
 extern int startup_gfar(struct net_device *dev);
 extern void stop_gfar(struct net_device *dev);
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index c681b41..d3d2623 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -204,9 +204,11 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 
 	if (NULL == phydev)
 		return -ENODEV;
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
+	tx_queue = priv->tx_queue[0];
+	rx_queue = priv->rx_queue[0];
 
+	/* etsec-1.7 and older versions have only one txic
+	 * and rxic regs although they support multiple queues */
 	cmd->maxtxpkt = get_icft_value(tx_queue->txic);
 	cmd->maxrxpkt = get_icft_value(rx_queue->rxic);
 
@@ -298,8 +300,8 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 	if (NULL == priv->phydev)
 		return -ENODEV;
 
-	rx_queue = priv->rx_queue;
-	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue[0];
+	tx_queue = priv->tx_queue[0];
 
 	rxtime  = get_ictt_value(rx_queue->rxic);
 	rxcount = get_icft_value(rx_queue->rxic);
@@ -357,8 +359,8 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
 		return -EOPNOTSUPP;
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
+	tx_queue = priv->tx_queue[0];
+	rx_queue = priv->rx_queue[0];
 
 	/* Set up rx coalescing */
 	if ((cvals->rx_coalesce_usecs == 0) ||
@@ -429,8 +431,8 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
+	tx_queue = priv->tx_queue[0];
+	rx_queue = priv->rx_queue[0];
 
 	rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE;
 	rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE;
@@ -453,9 +455,7 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
 static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar_priv_rx_q *rx_queue = NULL;
-	int err = 0;
+	int err = 0, i = 0;
 
 	if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
 		return -EINVAL;
@@ -475,37 +475,41 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 		return -EINVAL;
 	}
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
 
 	if (dev->flags & IFF_UP) {
 		unsigned long flags;
 
 		/* Halt TX and RX, and process the frames which
 		 * have already been received */
-		spin_lock_irqsave(&tx_queue->txlock, flags);
-		spin_lock(&rx_queue->rxlock);
+		local_irq_save(flags);
+		lock_tx_qs(priv);
+		lock_rx_qs(priv);
 
 		gfar_halt(dev);
 
-		spin_unlock(&rx_queue->rxlock);
-		spin_unlock_irqrestore(&tx_queue->txlock, flags);
+		unlock_rx_qs(priv);
+		unlock_tx_qs(priv);
+		local_irq_restore(flags);
 
-		gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size);
+		for (i = 0; i < priv->num_rx_queues; i++)
+			gfar_clean_rx_ring(priv->rx_queue[i],
+					priv->rx_queue[i]->rx_ring_size);
 
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
 	}
 
 	/* Change the size */
-	rx_queue->rx_ring_size = rvals->rx_pending;
-	tx_queue->tx_ring_size = rvals->tx_pending;
-	tx_queue->num_txbdfree = tx_queue->tx_ring_size;
+	for (i = 0; i < priv->num_rx_queues; i++) {
+		priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
+		priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
+		priv->tx_queue[i]->num_txbdfree = priv->tx_queue[i]->tx_ring_size;
+	}
 
 	/* Rebuild the rings with the new size */
 	if (dev->flags & IFF_UP) {
 		err = startup_gfar(dev);
-		netif_wake_queue(dev);
+		netif_tx_wake_all_queues(dev);
 	}
 	return err;
 }
@@ -513,29 +517,29 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_priv_rx_q *rx_queue = NULL;
-	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned long flags;
-	int err = 0;
+	int err = 0, i = 0;
 
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return -EOPNOTSUPP;
 
-	tx_queue = priv->tx_queue;
-	rx_queue = priv->rx_queue;
 
 	if (dev->flags & IFF_UP) {
 		/* Halt TX and RX, and process the frames which
 		 * have already been received */
-		spin_lock_irqsave(&tx_queue->txlock, flags);
-		spin_lock(&rx_queue->rxlock);
+		local_irq_save(flags);
+		lock_tx_qs(priv);
+		lock_rx_qs(priv);
 
 		gfar_halt(dev);
 
-		spin_unlock(&rx_queue->rxlock);
-		spin_unlock_irqrestore(&tx_queue->txlock, flags);
+		unlock_tx_qs(priv);
+		unlock_rx_qs(priv);
+		local_irq_save(flags);
 
-		gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size);
+		for (i = 0; i < priv->num_rx_queues; i++)
+			gfar_clean_rx_ring(priv->rx_queue[i],
+					priv->rx_queue[i]->rx_ring_size);
 
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
@@ -547,7 +551,7 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
 
 	if (dev->flags & IFF_UP) {
 		err = startup_gfar(dev);
-		netif_wake_queue(dev);
+		netif_tx_wake_all_queues(dev);
 	}
 	return err;
 }
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index adea11e..4b726f6 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -51,7 +51,6 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
 	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	int new_setting = 0;
 	u32 temp;
 	unsigned long flags;
@@ -59,7 +58,6 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING))
 		return count;
 
-	rx_queue = priv->rx_queue;
 
 	/* Find out the new setting */
 	if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
@@ -70,7 +68,9 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 	else
 		return count;
 
-	spin_lock_irqsave(&rx_queue->rxlock, flags);
+
+	local_irq_save(flags);
+	lock_rx_qs(priv);
 
 	/* Set the new stashing value */
 	priv->bd_stash_en = new_setting;
@@ -84,7 +84,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 
 	gfar_write(&regs->attr, temp);
 
-	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
+	unlock_rx_qs(priv);
+	local_irq_restore(flags);
 
 	return count;
 }
@@ -105,7 +106,6 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
 	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -113,9 +113,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
 		return count;
 
-	rx_queue = priv->rx_queue;
+	local_irq_save(flags);
+	lock_rx_qs(priv);
 
-	spin_lock_irqsave(&rx_queue->rxlock, flags);
 	if (length > priv->rx_buffer_size)
 		goto out;
 
@@ -140,7 +140,8 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 	gfar_write(&regs->attr, temp);
 
 out:
-	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
+	unlock_rx_qs(priv);
+	local_irq_restore(flags);
 
 	return count;
 }
@@ -164,7 +165,6 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
 	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned short index = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -172,9 +172,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
 		return count;
 
-	rx_queue = priv->rx_queue;
+	local_irq_save(flags);
+	lock_rx_qs(priv);
 
-	spin_lock_irqsave(&rx_queue->rxlock, flags);
 	if (index > priv->rx_stash_size)
 		goto out;
 
@@ -189,7 +189,8 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 	gfar_write(&regs->attreli, flags);
 
 out:
-	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
+	unlock_rx_qs(priv);
+	local_irq_restore(flags);
 
 	return count;
 }
@@ -212,7 +213,6 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
 	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -220,9 +220,8 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 	if (length > GFAR_MAX_FIFO_THRESHOLD)
 		return count;
 
-	tx_queue = priv->tx_queue;
-
-	spin_lock_irqsave(&tx_queue->txlock, flags);
+	local_irq_save(flags);
+	lock_tx_qs(priv);
 
 	priv->fifo_threshold = length;
 
@@ -231,7 +230,8 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 	temp |= length;
 	gfar_write(&regs->fifo_tx_thr, temp);
 
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 
 	return count;
 }
@@ -253,7 +253,6 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
 	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -261,8 +260,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 	if (num > GFAR_MAX_FIFO_STARVE)
 		return count;
 
-	tx_queue = priv->tx_queue;
-	spin_lock_irqsave(&tx_queue->txlock, flags);
+	local_irq_save(flags);
+	lock_tx_qs(priv);
 
 	priv->fifo_starve = num;
 
@@ -271,7 +270,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 	temp |= num;
 	gfar_write(&regs->fifo_tx_starve, temp);
 
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 
 	return count;
 }
@@ -294,7 +294,6 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
 	struct gfar __iomem *regs = priv->gfargrp.regs;
-	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -302,8 +301,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 	if (num > GFAR_MAX_FIFO_STARVE_OFF)
 		return count;
 
-	tx_queue = priv->tx_queue;
-	spin_lock_irqsave(&tx_queue->txlock, flags);
+	local_irq_save(flags);
+	lock_tx_qs(priv);
 
 	priv->fifo_starve_off = num;
 
@@ -312,7 +311,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 	temp |= num;
 	gfar_write(&regs->fifo_tx_starve_shutoff, temp);
 
-	spin_unlock_irqrestore(&tx_queue->txlock, flags);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 
 	return count;
 }
-- 
1.5.2.2


^ permalink raw reply related

* [PATCH v1 2/7] gianfar: Introduce logical group support.
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch introduces the group structure. The elements of this
structure are the interrupt lines, their corresponding names,
the register memory map.
The elements for this group are factored out from the gfar_private
structure. The introduction of group structure will help in
providing support for newer versions of etsec.

Currently, the support is present only for single group and
single tx/rx queues.

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/gianfar.c         |  364 ++++++++++++++++++++++-------------------
 drivers/net/gianfar.h         |   38 +++--
 drivers/net/gianfar_ethtool.c |   14 +-
 drivers/net/gianfar_sysfs.c   |   34 +++--
 4 files changed, 250 insertions(+), 200 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 354b2b5..fa0188e 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -151,7 +151,6 @@ MODULE_LICENSE("GPL");
 static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
 			    dma_addr_t buf)
 {
-	struct net_device *dev = rx_queue->dev;
 	u32 lstatus;
 
 	bdp->bufPtr = buf;
@@ -290,9 +289,9 @@ cleanup:
 static void gfar_init_mac(struct net_device *ndev)
 {
 	struct gfar_private *priv = netdev_priv(ndev);
-	struct gfar __iomem *regs = priv->regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u32 rctrl = 0;
 	u32 tctrl = 0;
 	u32 attrs = 0;
@@ -407,24 +406,25 @@ static int gfar_of_init(struct net_device *dev)
 
 	/* get a pointer to the register memory */
 	addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
-	priv->regs = ioremap(addr, size);
+	priv->gfargrp.regs = ioremap(addr, size);
 
-	if (priv->regs == NULL)
+	if (priv->gfargrp.regs == NULL)
 		return -ENOMEM;
 
-	priv->interruptTransmit = irq_of_parse_and_map(np, 0);
+	priv->gfargrp.priv = priv; /* back pointer from group to priv */
+	priv->gfargrp.interruptTransmit = irq_of_parse_and_map(np, 0);
 
 	model = of_get_property(np, "model", NULL);
 
 	/* If we aren't the FEC we have multiple interrupts */
 	if (model && strcasecmp(model, "FEC")) {
-		priv->interruptReceive = irq_of_parse_and_map(np, 1);
+		priv->gfargrp.interruptReceive = irq_of_parse_and_map(np, 1);
 
-		priv->interruptError = irq_of_parse_and_map(np, 2);
+		priv->gfargrp.interruptError = irq_of_parse_and_map(np, 2);
 
-		if (priv->interruptTransmit < 0 ||
-				priv->interruptReceive < 0 ||
-				priv->interruptError < 0) {
+		if (priv->gfargrp.interruptTransmit < 0 ||
+				priv->gfargrp.interruptReceive < 0 ||
+				priv->gfargrp.interruptError < 0) {
 			err = -EINVAL;
 			goto err_out;
 		}
@@ -491,7 +491,7 @@ static int gfar_of_init(struct net_device *dev)
 	return 0;
 
 err_out:
-	iounmap(priv->regs);
+	iounmap(priv->gfargrp.regs);
 	return err;
 }
 
@@ -517,6 +517,7 @@ static int gfar_probe(struct of_device *ofdev,
 	u32 tempval;
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
+	struct gfar __iomem *regs = NULL;
 	int err = 0;
 	int len_devname;
 
@@ -549,32 +550,34 @@ static int gfar_probe(struct of_device *ofdev,
 
 	spin_lock_init(&priv->tx_queue->txlock);
 	spin_lock_init(&priv->rx_queue->rxlock);
+	spin_lock_init(&priv->gfargrp.grplock);
 	spin_lock_init(&priv->bflock);
 	INIT_WORK(&priv->reset_task, gfar_reset_task);
 
 	dev_set_drvdata(&ofdev->dev, priv);
+	regs = priv->gfargrp.regs;
 
 	/* Stop the DMA engine now, in case it was running before */
 	/* (The firmware could have used it, and left it running). */
 	gfar_halt(dev);
 
 	/* Reset MAC layer */
-	gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+	gfar_write(&regs->maccfg1, MACCFG1_SOFT_RESET);
 
 	/* We need to delay at least 3 TX clocks */
 	udelay(2);
 
 	tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
-	gfar_write(&priv->regs->maccfg1, tempval);
+	gfar_write(&regs->maccfg1, tempval);
 
 	/* Initialize MACCFG2. */
-	gfar_write(&priv->regs->maccfg2, MACCFG2_INIT_SETTINGS);
+	gfar_write(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
 
 	/* Initialize ECNTRL */
-	gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS);
+	gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
 
 	/* Set the dev->base_addr to the gfar reg region */
-	dev->base_addr = (unsigned long) (priv->regs);
+	dev->base_addr = (unsigned long) regs;
 
 	SET_NETDEV_DEV(dev, &ofdev->dev);
 
@@ -602,35 +605,35 @@ static int gfar_probe(struct of_device *ofdev,
 		priv->extended_hash = 1;
 		priv->hash_width = 9;
 
-		priv->hash_regs[0] = &priv->regs->igaddr0;
-		priv->hash_regs[1] = &priv->regs->igaddr1;
-		priv->hash_regs[2] = &priv->regs->igaddr2;
-		priv->hash_regs[3] = &priv->regs->igaddr3;
-		priv->hash_regs[4] = &priv->regs->igaddr4;
-		priv->hash_regs[5] = &priv->regs->igaddr5;
-		priv->hash_regs[6] = &priv->regs->igaddr6;
-		priv->hash_regs[7] = &priv->regs->igaddr7;
-		priv->hash_regs[8] = &priv->regs->gaddr0;
-		priv->hash_regs[9] = &priv->regs->gaddr1;
-		priv->hash_regs[10] = &priv->regs->gaddr2;
-		priv->hash_regs[11] = &priv->regs->gaddr3;
-		priv->hash_regs[12] = &priv->regs->gaddr4;
-		priv->hash_regs[13] = &priv->regs->gaddr5;
-		priv->hash_regs[14] = &priv->regs->gaddr6;
-		priv->hash_regs[15] = &priv->regs->gaddr7;
+		priv->hash_regs[0] = &regs->igaddr0;
+		priv->hash_regs[1] = &regs->igaddr1;
+		priv->hash_regs[2] = &regs->igaddr2;
+		priv->hash_regs[3] = &regs->igaddr3;
+		priv->hash_regs[4] = &regs->igaddr4;
+		priv->hash_regs[5] = &regs->igaddr5;
+		priv->hash_regs[6] = &regs->igaddr6;
+		priv->hash_regs[7] = &regs->igaddr7;
+		priv->hash_regs[8] = &regs->gaddr0;
+		priv->hash_regs[9] = &regs->gaddr1;
+		priv->hash_regs[10] = &regs->gaddr2;
+		priv->hash_regs[11] = &regs->gaddr3;
+		priv->hash_regs[12] = &regs->gaddr4;
+		priv->hash_regs[13] = &regs->gaddr5;
+		priv->hash_regs[14] = &regs->gaddr6;
+		priv->hash_regs[15] = &regs->gaddr7;
 
 	} else {
 		priv->extended_hash = 0;
 		priv->hash_width = 8;
 
-		priv->hash_regs[0] = &priv->regs->gaddr0;
-		priv->hash_regs[1] = &priv->regs->gaddr1;
-		priv->hash_regs[2] = &priv->regs->gaddr2;
-		priv->hash_regs[3] = &priv->regs->gaddr3;
-		priv->hash_regs[4] = &priv->regs->gaddr4;
-		priv->hash_regs[5] = &priv->regs->gaddr5;
-		priv->hash_regs[6] = &priv->regs->gaddr6;
-		priv->hash_regs[7] = &priv->regs->gaddr7;
+		priv->hash_regs[0] = &regs->gaddr0;
+		priv->hash_regs[1] = &regs->gaddr1;
+		priv->hash_regs[2] = &regs->gaddr2;
+		priv->hash_regs[3] = &regs->gaddr3;
+		priv->hash_regs[4] = &regs->gaddr4;
+		priv->hash_regs[5] = &regs->gaddr5;
+		priv->hash_regs[6] = &regs->gaddr6;
+		priv->hash_regs[7] = &regs->gaddr7;
 	}
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
@@ -672,20 +675,20 @@ static int gfar_probe(struct of_device *ofdev,
 
 	/* fill out IRQ number and name fields */
 	len_devname = strlen(dev->name);
-	strncpy(&priv->int_name_tx[0], dev->name, len_devname);
+	strncpy(&priv->gfargrp.int_name_tx[0], dev->name, len_devname);
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		strncpy(&priv->int_name_tx[len_devname],
+		strncpy(&priv->gfargrp.int_name_tx[len_devname],
 			"_tx", sizeof("_tx") + 1);
 
-		strncpy(&priv->int_name_rx[0], dev->name, len_devname);
-		strncpy(&priv->int_name_rx[len_devname],
+		strncpy(&priv->gfargrp.int_name_rx[0], dev->name, len_devname);
+		strncpy(&priv->gfargrp.int_name_rx[len_devname],
 			"_rx", sizeof("_rx") + 1);
 
-		strncpy(&priv->int_name_er[0], dev->name, len_devname);
-		strncpy(&priv->int_name_er[len_devname],
+		strncpy(&priv->gfargrp.int_name_er[0], dev->name, len_devname);
+		strncpy(&priv->gfargrp.int_name_er[len_devname],
 			"_er", sizeof("_er") + 1);
 	} else
-		priv->int_name_tx[len_devname] = '\0';
+		priv->gfargrp.int_name_tx[len_devname] = '\0';
 
 	/* Create all the sysfs files */
 	gfar_init_sysfs(dev);
@@ -702,7 +705,7 @@ static int gfar_probe(struct of_device *ofdev,
 	return 0;
 
 register_fail:
-	iounmap(priv->regs);
+	iounmap(priv->gfargrp.regs);
 	kfree(priv->rx_queue);
 rx_queue_fail:
 	kfree(priv->tx_queue);
@@ -727,7 +730,7 @@ static int gfar_remove(struct of_device *ofdev)
 	dev_set_drvdata(&ofdev->dev, NULL);
 
 	unregister_netdev(priv->ndev);
-	iounmap(priv->regs);
+	iounmap(priv->gfargrp.regs);
 	free_netdev(priv->ndev);
 
 	return 0;
@@ -741,6 +744,7 @@ static int gfar_suspend(struct device *dev)
 	struct net_device *ndev = priv->ndev;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar __iomem *regs = NULL;
 	unsigned long flags;
 	u32 tempval;
 
@@ -750,6 +754,7 @@ static int gfar_suspend(struct device *dev)
 	netif_device_detach(ndev);
 	tx_queue = priv->tx_queue;
 	rx_queue = priv->rx_queue;
+	regs = priv->gfargrp.regs;
 
 	if (netif_running(ndev)) {
 		spin_lock_irqsave(&tx_queue->txlock, flags);
@@ -758,14 +763,14 @@ static int gfar_suspend(struct device *dev)
 		gfar_halt_nodisable(ndev);
 
 		/* Disable Tx, and Rx if wake-on-LAN is disabled. */
-		tempval = gfar_read(&priv->regs->maccfg1);
+		tempval = gfar_read(&regs->maccfg1);
 
 		tempval &= ~MACCFG1_TX_EN;
 
 		if (!magic_packet)
 			tempval &= ~MACCFG1_RX_EN;
 
-		gfar_write(&priv->regs->maccfg1, tempval);
+		gfar_write(&regs->maccfg1, tempval);
 
 		spin_unlock(&rx_queue->rxlock);
 		spin_unlock_irqrestore(&tx_queue->txlock, flags);
@@ -774,12 +779,12 @@ static int gfar_suspend(struct device *dev)
 
 		if (magic_packet) {
 			/* Enable interrupt on Magic Packet */
-			gfar_write(&priv->regs->imask, IMASK_MAG);
+			gfar_write(&regs->imask, IMASK_MAG);
 
 			/* Enable Magic Packet mode */
-			tempval = gfar_read(&priv->regs->maccfg2);
+			tempval = gfar_read(&regs->maccfg2);
 			tempval |= MACCFG2_MPEN;
-			gfar_write(&priv->regs->maccfg2, tempval);
+			gfar_write(&regs->maccfg2, tempval);
 		} else {
 			phy_stop(priv->phydev);
 		}
@@ -794,6 +799,7 @@ static int gfar_resume(struct device *dev)
 	struct net_device *ndev = priv->ndev;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar __iomem *regs = NULL;
 	unsigned long flags;
 	u32 tempval;
 	int magic_packet = priv->wol_en &&
@@ -812,13 +818,14 @@ static int gfar_resume(struct device *dev)
 	 */
 	rx_queue = priv->rx_queue;
 	tx_queue = priv->tx_queue;
+	regs = priv->gfargrp.regs;
 
 	spin_lock_irqsave(&tx_queue->txlock, flags);
 	spin_lock(&rx_queue->rxlock);
 
-	tempval = gfar_read(&priv->regs->maccfg2);
+	tempval = gfar_read(&regs->maccfg2);
 	tempval &= ~MACCFG2_MPEN;
-	gfar_write(&priv->regs->maccfg2, tempval);
+	gfar_write(&regs->maccfg2, tempval);
 
 	gfar_start(ndev);
 
@@ -893,7 +900,11 @@ static int gfar_legacy_resume(struct of_device *ofdev)
 static phy_interface_t gfar_get_interface(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	u32 ecntrl = gfar_read(&priv->regs->ecntrl);
+	struct gfar __iomem *regs = NULL;
+	u32 ecntrl;
+
+	regs = priv->gfargrp.regs;
+	ecntrl = gfar_read(&regs->ecntrl);
 
 	if (ecntrl & ECNTRL_SGMII_MODE)
 		return PHY_INTERFACE_MODE_SGMII;
@@ -1015,46 +1026,48 @@ static void gfar_configure_serdes(struct net_device *dev)
 static void init_registers(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = NULL;
 
+	regs = priv->gfargrp.regs;
 	/* Clear IEVENT */
-	gfar_write(&priv->regs->ievent, IEVENT_INIT_CLEAR);
+	gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
 
 	/* Initialize IMASK */
-	gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
+	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
 	/* Init hash registers to zero */
-	gfar_write(&priv->regs->igaddr0, 0);
-	gfar_write(&priv->regs->igaddr1, 0);
-	gfar_write(&priv->regs->igaddr2, 0);
-	gfar_write(&priv->regs->igaddr3, 0);
-	gfar_write(&priv->regs->igaddr4, 0);
-	gfar_write(&priv->regs->igaddr5, 0);
-	gfar_write(&priv->regs->igaddr6, 0);
-	gfar_write(&priv->regs->igaddr7, 0);
-
-	gfar_write(&priv->regs->gaddr0, 0);
-	gfar_write(&priv->regs->gaddr1, 0);
-	gfar_write(&priv->regs->gaddr2, 0);
-	gfar_write(&priv->regs->gaddr3, 0);
-	gfar_write(&priv->regs->gaddr4, 0);
-	gfar_write(&priv->regs->gaddr5, 0);
-	gfar_write(&priv->regs->gaddr6, 0);
-	gfar_write(&priv->regs->gaddr7, 0);
+	gfar_write(&regs->igaddr0, 0);
+	gfar_write(&regs->igaddr1, 0);
+	gfar_write(&regs->igaddr2, 0);
+	gfar_write(&regs->igaddr3, 0);
+	gfar_write(&regs->igaddr4, 0);
+	gfar_write(&regs->igaddr5, 0);
+	gfar_write(&regs->igaddr6, 0);
+	gfar_write(&regs->igaddr7, 0);
+
+	gfar_write(&regs->gaddr0, 0);
+	gfar_write(&regs->gaddr1, 0);
+	gfar_write(&regs->gaddr2, 0);
+	gfar_write(&regs->gaddr3, 0);
+	gfar_write(&regs->gaddr4, 0);
+	gfar_write(&regs->gaddr5, 0);
+	gfar_write(&regs->gaddr6, 0);
+	gfar_write(&regs->gaddr7, 0);
 
 	/* Zero out the rmon mib registers if it has them */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
-		memset_io(&(priv->regs->rmon), 0, sizeof (struct rmon_mib));
+		memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib));
 
 		/* Mask off the CAM interrupts */
-		gfar_write(&priv->regs->rmon.cam1, 0xffffffff);
-		gfar_write(&priv->regs->rmon.cam2, 0xffffffff);
+		gfar_write(&regs->rmon.cam1, 0xffffffff);
+		gfar_write(&regs->rmon.cam2, 0xffffffff);
 	}
 
 	/* Initialize the max receive buffer length */
-	gfar_write(&priv->regs->mrblr, priv->rx_buffer_size);
+	gfar_write(&regs->mrblr, priv->rx_buffer_size);
 
 	/* Initialize the Minimum Frame Length Register */
-	gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
+	gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
 }
 
 
@@ -1062,7 +1075,7 @@ static void init_registers(struct net_device *dev)
 static void gfar_halt_nodisable(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->regs;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u32 tempval;
 
 	/* Mask all interrupts */
@@ -1072,13 +1085,13 @@ static void gfar_halt_nodisable(struct net_device *dev)
 	gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
 
 	/* Stop the DMA, and wait for it to stop */
-	tempval = gfar_read(&priv->regs->dmactrl);
+	tempval = gfar_read(&regs->dmactrl);
 	if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
 	    != (DMACTRL_GRS | DMACTRL_GTS)) {
 		tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-		gfar_write(&priv->regs->dmactrl, tempval);
+		gfar_write(&regs->dmactrl, tempval);
 
-		while (!(gfar_read(&priv->regs->ievent) &
+		while (!(gfar_read(&regs->ievent) &
 			 (IEVENT_GRSC | IEVENT_GTSC)))
 			cpu_relax();
 	}
@@ -1088,7 +1101,7 @@ static void gfar_halt_nodisable(struct net_device *dev)
 void gfar_halt(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->regs;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u32 tempval;
 
 	gfar_halt_nodisable(dev);
@@ -1122,11 +1135,11 @@ void stop_gfar(struct net_device *dev)
 
 	/* Free the IRQs */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		free_irq(priv->interruptError, dev);
-		free_irq(priv->interruptTransmit, dev);
-		free_irq(priv->interruptReceive, dev);
+		free_irq(priv->gfargrp.interruptError, &priv->gfargrp);
+		free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp);
+		free_irq(priv->gfargrp.interruptReceive, &priv->gfargrp);
 	} else {
-		free_irq(priv->interruptTransmit, dev);
+		free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp);
 	}
 
 	free_skb_resources(priv);
@@ -1201,9 +1214,7 @@ skip_rx_skbuff:
 void gfar_start(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar_priv_tx_q *tx_queue;
-	struct gfar_priv_rx_q *rx_queue;
-	struct gfar __iomem *regs = priv->regs;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u32 tempval;
 
 	/* Enable Rx and Tx in MACCFG1 */
@@ -1212,14 +1223,14 @@ void gfar_start(struct net_device *dev)
 	gfar_write(&regs->maccfg1, tempval);
 
 	/* Initialize DMACTRL to have WWR and WOP */
-	tempval = gfar_read(&priv->regs->dmactrl);
+	tempval = gfar_read(&regs->dmactrl);
 	tempval |= DMACTRL_INIT_SETTINGS;
-	gfar_write(&priv->regs->dmactrl, tempval);
+	gfar_write(&regs->dmactrl, tempval);
 
 	/* Make sure we aren't stopped */
-	tempval = gfar_read(&priv->regs->dmactrl);
+	tempval = gfar_read(&regs->dmactrl);
 	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-	gfar_write(&priv->regs->dmactrl, tempval);
+	gfar_write(&regs->dmactrl, tempval);
 
 	/* Clear THLT/RHLT, so that the DMA starts polling now */
 	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
@@ -1235,7 +1246,7 @@ void gfar_start(struct net_device *dev)
 int startup_gfar(struct net_device *ndev)
 {
 	struct gfar_private *priv = netdev_priv(ndev);
-	struct gfar __iomem *regs = priv->regs;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	int err;
 
 	gfar_write(&regs->imask, IMASK_INIT_CLEAR);
@@ -1251,39 +1262,46 @@ int startup_gfar(struct net_device *ndev)
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
 		/* Install our interrupt handlers for Error,
 		 * Transmit, and Receive */
-		err = request_irq(priv->interruptError, gfar_error, 0,
-				  priv->int_name_er, ndev);
+		err = request_irq(priv->gfargrp.interruptError, gfar_error, 0,
+				  priv->gfargrp.int_name_er, &priv->gfargrp);
 		if (err) {
 			if (netif_msg_intr(priv))
 				pr_err("%s: Can't get IRQ %d\n", ndev->name,
-				       priv->interruptError);
+				       priv->gfargrp.interruptError);
 			goto err_irq_fail;
 		}
 
-		err = request_irq(priv->interruptTransmit, gfar_transmit, 0,
-				  priv->int_name_tx, ndev);
+		err = request_irq(priv->gfargrp.interruptTransmit,
+					gfar_transmit, 0,
+					priv->gfargrp.int_name_tx,
+					&priv->gfargrp);
 		if (err) {
 			if (netif_msg_intr(priv))
 				pr_err("%s: Can't get IRQ %d\n", ndev->name,
-				       priv->interruptTransmit);
+				       priv->gfargrp.interruptTransmit);
 			goto tx_irq_fail;
 		}
 
-		err = request_irq(priv->interruptReceive, gfar_receive, 0,
-				  priv->int_name_rx, ndev);
+		err = request_irq(priv->gfargrp.interruptReceive,
+					gfar_receive, 0,
+					priv->gfargrp.int_name_rx,
+					&priv->gfargrp);
 		if (err) {
 			if (netif_msg_intr(priv))
 				pr_err("%s: Can't get IRQ %d (receive0)\n",
-				       ndev->name, priv->interruptReceive);
+					ndev->name,
+					priv->gfargrp.interruptReceive);
 			goto rx_irq_fail;
 		}
 	} else {
-		err = request_irq(priv->interruptTransmit, gfar_interrupt,
-				0, priv->int_name_tx, ndev);
+		err = request_irq(priv->gfargrp.interruptTransmit,
+					gfar_interrupt, 0,
+					priv->gfargrp.int_name_tx,
+					&priv->gfargrp);
 		if (err) {
 			if (netif_msg_intr(priv))
 				pr_err("%s: Can't get IRQ %d\n", ndev->name,
-				       priv->interruptTransmit);
+				       priv->gfargrp.interruptTransmit);
 			goto err_irq_fail;
 		}
 	}
@@ -1296,9 +1314,9 @@ int startup_gfar(struct net_device *ndev)
 	return 0;
 
 rx_irq_fail:
-	free_irq(priv->interruptTransmit, ndev);
+	free_irq(priv->gfargrp.interruptTransmit, &priv->gfargrp);
 tx_irq_fail:
-	free_irq(priv->interruptError, ndev);
+	free_irq(priv->gfargrp.interruptError, &priv->gfargrp);
 err_irq_fail:
 	free_skb_resources(priv);
 	return err;
@@ -1403,6 +1421,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar __iomem *regs = NULL;
 	struct txfcb *fcb = NULL;
 	struct txbd8 *txbdp, *txbdp_start, *base;
 	u32 lstatus;
@@ -1413,6 +1432,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	tx_queue = priv->tx_queue;
 	base = tx_queue->tx_bd_base;
+	regs = priv->gfargrp.regs;
 
 	/* make space for additional header when fcb is needed */
 	if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
@@ -1536,7 +1556,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	/* Tell the DMA to go go go */
-	gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
+	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
 
 	/* Unlock priv */
 	spin_unlock_irqrestore(&tx_queue->txlock, flags);
@@ -1579,40 +1599,42 @@ static void gfar_vlan_rx_register(struct net_device *dev,
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar __iomem *regs = NULL;
 	unsigned long flags;
 	u32 tempval;
 
 	rx_queue = priv->rx_queue;
+	regs = priv->gfargrp.regs;
 	spin_lock_irqsave(&rx_queue->rxlock, flags);
 
 	priv->vlgrp = grp;
 
 	if (grp) {
 		/* Enable VLAN tag insertion */
-		tempval = gfar_read(&priv->regs->tctrl);
+		tempval = gfar_read(&regs->tctrl);
 		tempval |= TCTRL_VLINS;
 
-		gfar_write(&priv->regs->tctrl, tempval);
+		gfar_write(&regs->tctrl, tempval);
 
 		/* Enable VLAN tag extraction */
-		tempval = gfar_read(&priv->regs->rctrl);
+		tempval = gfar_read(&regs->rctrl);
 		tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
-		gfar_write(&priv->regs->rctrl, tempval);
+		gfar_write(&regs->rctrl, tempval);
 	} else {
 		/* Disable VLAN tag insertion */
-		tempval = gfar_read(&priv->regs->tctrl);
+		tempval = gfar_read(&regs->tctrl);
 		tempval &= ~TCTRL_VLINS;
-		gfar_write(&priv->regs->tctrl, tempval);
+		gfar_write(&regs->tctrl, tempval);
 
 		/* Disable VLAN tag extraction */
-		tempval = gfar_read(&priv->regs->rctrl);
+		tempval = gfar_read(&regs->rctrl);
 		tempval &= ~RCTRL_VLEX;
 		/* If parse is no longer required, then disable parser */
 		if (tempval & RCTRL_REQ_PARSER)
 			tempval |= RCTRL_PRSDEP_INIT;
 		else
 			tempval &= ~RCTRL_PRSDEP_INIT;
-		gfar_write(&priv->regs->rctrl, tempval);
+		gfar_write(&regs->rctrl, tempval);
 	}
 
 	gfar_change_mtu(dev, dev->mtu);
@@ -1624,6 +1646,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
 	int tempsize, tempval;
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	int oldsize = priv->rx_buffer_size;
 	int frame_size = new_mtu + ETH_HLEN;
 
@@ -1655,20 +1678,20 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 
 	dev->mtu = new_mtu;
 
-	gfar_write(&priv->regs->mrblr, priv->rx_buffer_size);
-	gfar_write(&priv->regs->maxfrm, priv->rx_buffer_size);
+	gfar_write(&regs->mrblr, priv->rx_buffer_size);
+	gfar_write(&regs->maxfrm, priv->rx_buffer_size);
 
 	/* If the mtu is larger than the max size for standard
 	 * ethernet frames (ie, a jumbo frame), then set maccfg2
 	 * to allow huge frames, and to check the length */
-	tempval = gfar_read(&priv->regs->maccfg2);
+	tempval = gfar_read(&regs->maccfg2);
 
 	if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE)
 		tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
 	else
 		tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
 
-	gfar_write(&priv->regs->maccfg2, tempval);
+	gfar_write(&regs->maccfg2, tempval);
 
 	if ((oldsize != tempsize) && (dev->flags & IFF_UP))
 		startup_gfar(dev);
@@ -1787,9 +1810,9 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 	return howmany;
 }
 
-static void gfar_schedule_cleanup(struct net_device *dev)
+static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
 {
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_private *priv = gfargrp->priv;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
@@ -1800,14 +1823,14 @@ static void gfar_schedule_cleanup(struct net_device *dev)
 	spin_lock(&rx_queue->rxlock);
 
 	if (napi_schedule_prep(&rx_queue->napi)) {
-		gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED);
+		gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED);
 		__napi_schedule(&rx_queue->napi);
 	} else {
 		/*
 		 * Clear IEVENT, so interrupts aren't called again
 		 * because of the packets that have already arrived.
 		 */
-		gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
+		gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK);
 	}
 
 	spin_unlock(&rx_queue->rxlock);
@@ -1815,9 +1838,9 @@ static void gfar_schedule_cleanup(struct net_device *dev)
 }
 
 /* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *dev_id)
+static irqreturn_t gfar_transmit(int irq, void *grp_id)
 {
-	gfar_schedule_cleanup((struct net_device *)dev_id);
+	gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
 	return IRQ_HANDLED;
 }
 
@@ -1897,9 +1920,9 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
 	}
 }
 
-irqreturn_t gfar_receive(int irq, void *dev_id)
+irqreturn_t gfar_receive(int irq, void *grp_id)
 {
-	gfar_schedule_cleanup((struct net_device *)dev_id);
+	gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
 	return IRQ_HANDLED;
 }
 
@@ -2053,6 +2076,7 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 			struct gfar_priv_rx_q, napi);
 	struct net_device *dev = rx_queue->dev;
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	int tx_cleaned = 0;
 	int rx_cleaned = 0;
@@ -2060,7 +2084,7 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 
 	/* Clear IEVENT, so interrupts aren't called again
 	 * because of the packets that have already arrived */
-	gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
+	gfar_write(&regs->ievent, IEVENT_RTX_MASK);
 	tx_queue = priv->tx_queue;
 
 	/* If we fail to get the lock, don't bother with the TX BDs */
@@ -2078,19 +2102,19 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 		napi_complete(napi);
 
 		/* Clear the halt bit in RSTAT */
-		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
+		gfar_write(&regs->rstat, RSTAT_CLEAR_RHALT);
 
-		gfar_write(&priv->regs->imask, IMASK_DEFAULT);
+		gfar_write(&regs->imask, IMASK_DEFAULT);
 
 		/* If we are coalescing interrupts, update the timer */
 		/* Otherwise, clear it */
 		if (likely(rx_queue->rxcoalescing)) {
-			gfar_write(&priv->regs->rxic, 0);
-			gfar_write(&priv->regs->rxic, rx_queue->rxic);
+			gfar_write(&regs->rxic, 0);
+			gfar_write(&regs->rxic, rx_queue->rxic);
 		}
 		if (likely(tx_queue->txcoalescing)) {
-			gfar_write(&priv->regs->txic, 0);
-			gfar_write(&priv->regs->txic, tx_queue->txic);
+			gfar_write(&regs->txic, 0);
+			gfar_write(&regs->txic, tx_queue->txic);
 		}
 	}
 
@@ -2109,41 +2133,40 @@ static void gfar_netpoll(struct net_device *dev)
 
 	/* If the device has multiple interrupts, run tx/rx */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-		disable_irq(priv->interruptTransmit);
-		disable_irq(priv->interruptReceive);
-		disable_irq(priv->interruptError);
-		gfar_interrupt(priv->interruptTransmit, dev);
-		enable_irq(priv->interruptError);
-		enable_irq(priv->interruptReceive);
-		enable_irq(priv->interruptTransmit);
+		disable_irq(priv->gfargrp.interruptTransmit);
+		disable_irq(priv->gfargrp.interruptReceive);
+		disable_irq(priv->gfargrp.interruptError);
+		gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp);
+		enable_irq(priv->gfargrp.interruptError);
+		enable_irq(priv->gfargrp.interruptReceive);
+		enable_irq(priv->gfargrp.interruptTransmit);
 	} else {
-		disable_irq(priv->interruptTransmit);
-		gfar_interrupt(priv->interruptTransmit, dev);
-		enable_irq(priv->interruptTransmit);
+		disable_irq(priv->gfargrp.interruptTransmit);
+		gfar_interrupt(priv->gfargrp.interruptTransmit, &priv->gfargrp);
+		enable_irq(priv->gfargrp.interruptTransmit);
 	}
 }
 #endif
 
 /* The interrupt handler for devices with one interrupt */
-static irqreturn_t gfar_interrupt(int irq, void *dev_id)
+static irqreturn_t gfar_interrupt(int irq, void *grp_id)
 {
-	struct net_device *dev = dev_id;
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_grp *gfargrp = grp_id;
 
 	/* Save ievent for future reference */
-	u32 events = gfar_read(&priv->regs->ievent);
+	u32 events = gfar_read(&gfargrp->regs->ievent);
 
 	/* Check for reception */
 	if (events & IEVENT_RX_MASK)
-		gfar_receive(irq, dev_id);
+		gfar_receive(irq, grp_id);
 
 	/* Check for transmit completion */
 	if (events & IEVENT_TX_MASK)
-		gfar_transmit(irq, dev_id);
+		gfar_transmit(irq, grp_id);
 
 	/* Check for errors */
 	if (events & IEVENT_ERR_MASK)
-		gfar_error(irq, dev_id);
+		gfar_error(irq, grp_id);
 
 	return IRQ_HANDLED;
 }
@@ -2158,7 +2181,7 @@ static void adjust_link(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar_priv_tx_q *tx_queue = NULL;
-	struct gfar __iomem *regs = priv->regs;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	unsigned long flags;
 	struct phy_device *phydev = priv->phydev;
 	int new_state = 0;
@@ -2241,7 +2264,7 @@ static void gfar_set_multi(struct net_device *dev)
 {
 	struct dev_mc_list *mc_ptr;
 	struct gfar_private *priv = netdev_priv(dev);
-	struct gfar __iomem *regs = priv->regs;
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u32 tempval;
 
 	if (dev->flags & IFF_PROMISC) {
@@ -2374,10 +2397,11 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	int idx;
 	char tmpbuf[MAC_ADDR_LEN];
 	u32 tempval;
-	u32 __iomem *macptr = &priv->regs->macstnaddr1;
+	u32 __iomem *macptr = &regs->macstnaddr1;
 
 	macptr += num*2;
 
@@ -2394,16 +2418,18 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
 }
 
 /* GFAR error interrupt handler */
-static irqreturn_t gfar_error(int irq, void *dev_id)
+static irqreturn_t gfar_error(int irq, void *grp_id)
 {
-	struct net_device *dev = dev_id;
-	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_grp *gfargrp = grp_id;
+	struct gfar __iomem *regs = gfargrp->regs;
+	struct gfar_private *priv= gfargrp->priv;
+	struct net_device *dev = priv->ndev;
 
 	/* Save ievent for future reference */
-	u32 events = gfar_read(&priv->regs->ievent);
+	u32 events = gfar_read(&regs->ievent);
 
 	/* Clear IEVENT */
-	gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK);
+	gfar_write(&regs->ievent, events & IEVENT_ERR_MASK);
 
 	/* Magic Packet is not an error. */
 	if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
@@ -2413,7 +2439,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
 	/* Hmm... */
 	if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
 		printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
-		       dev->name, events, gfar_read(&priv->regs->imask));
+		       dev->name, events, gfar_read(&regs->imask));
 
 	/* Update the error counters */
 	if (events & IEVENT_TXE) {
@@ -2431,7 +2457,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
 			priv->extra_stats.tx_underrun++;
 
 			/* Reactivate the Tx Queues */
-			gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
+			gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
 		}
 		if (netif_msg_tx_err(priv))
 			printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
@@ -2440,11 +2466,11 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
 		dev->stats.rx_errors++;
 		priv->extra_stats.rx_bsy++;
 
-		gfar_receive(irq, dev_id);
+		gfar_receive(irq, grp_id);
 
 		if (netif_msg_rx_err(priv))
 			printk(KERN_DEBUG "%s: busy error (rstat: %x)\n",
-			       dev->name, gfar_read(&priv->regs->rstat));
+			       dev->name, gfar_read(&regs->rstat));
 	}
 	if (events & IEVENT_BABR) {
 		dev->stats.rx_errors++;
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index a60f93f..79e8471 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -770,6 +770,32 @@ struct gfar_priv_rx_q {
 	unsigned long rxic;
 };
 
+/**
+ *	struct gfar_priv_grp - per group structure
+ *	@priv: back pointer to the priv structure
+ *	@regs: the ioremapped register space for this group
+ *	@grp_id: group id for this group
+ *	@interruptTransmit: The TX interrupt number for this group
+ *	@interruptReceive: The RX interrupt number for this group
+ *	@interruptError: The ERROR interrupt number for this group
+ *	@int_name_tx: tx interrupt name for this group
+ *	@int_name_rx: rx interrupt name for this group
+ *	@int_name_er: er interrupt name for this group
+ */
+
+struct gfar_priv_grp {
+	spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES)));
+	struct gfar_private *priv;
+	struct gfar __iomem *regs;
+	unsigned int interruptTransmit;
+	unsigned int interruptReceive;
+	unsigned int interruptError;
+
+	char int_name_tx[GFAR_INT_NAME_MAX];
+	char int_name_rx[GFAR_INT_NAME_MAX];
+	char int_name_er[GFAR_INT_NAME_MAX];
+};
+
 /* Struct stolen almost completely (and shamelessly) from the FCC enet source
  * (Ok, that's not so true anymore, but there is a family resemblence)
  * The GFAR buffer descriptors track the ring buffers.  The rx_bd_base
@@ -785,6 +811,7 @@ struct gfar_private {
 	struct net_device *ndev;
 	struct of_device *ofdev;
 
+	struct gfar_priv_grp gfargrp;
 	struct gfar_priv_tx_q *tx_queue;
 	struct gfar_priv_rx_q *rx_queue;
 
@@ -797,9 +824,6 @@ struct gfar_private {
 
 	struct vlan_group *vlgrp;
 
-	/* Unprotected fields */
-	/* Pointer to the GFAR memory mapped Registers */
-	struct gfar __iomem *regs;
 
 	/* Hash registers and their width */
 	u32 __iomem *hash_regs[16];
@@ -823,10 +847,6 @@ struct gfar_private {
 		wol_en:1; /* Wake-on-LAN enabled */
 	unsigned short padding;
 
-	unsigned int interruptTransmit;
-	unsigned int interruptReceive;
-	unsigned int interruptError;
-
 	/* PHY stuff */
 	struct phy_device *phydev;
 	struct mii_bus *mii_bus;
@@ -838,10 +858,6 @@ struct gfar_private {
 
 	struct work_struct reset_task;
 
-	char int_name_tx[GFAR_INT_NAME_MAX];
-	char int_name_rx[GFAR_INT_NAME_MAX];
-	char int_name_er[GFAR_INT_NAME_MAX];
-
 	/* Network Statistics */
 	struct gfar_extra_stats extra_stats;
 };
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6d0d171..c681b41 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -137,10 +137,11 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	u64 *extra = (u64 *) & priv->extra_stats;
 
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
-		u32 __iomem *rmon = (u32 __iomem *) & priv->regs->rmon;
+		u32 __iomem *rmon = (u32 __iomem *) &regs->rmon;
 		struct gfar_stats *stats = (struct gfar_stats *) buf;
 
 		for (i = 0; i < GFAR_RMON_LEN; i++)
@@ -223,7 +224,7 @@ static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, voi
 {
 	int i;
 	struct gfar_private *priv = netdev_priv(dev);
-	u32 __iomem *theregs = (u32 __iomem *) priv->regs;
+	u32 __iomem *theregs = (u32 __iomem *) priv->gfargrp.regs;
 	u32 *buf = (u32 *) regbuf;
 
 	for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++)
@@ -349,6 +350,7 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 
@@ -407,13 +409,13 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 	tx_queue->txic = mk_ic_value(cvals->tx_max_coalesced_frames,
 		gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
 
-	gfar_write(&priv->regs->rxic, 0);
+	gfar_write(&regs->rxic, 0);
 	if (rx_queue->rxcoalescing)
-		gfar_write(&priv->regs->rxic, rx_queue->rxic);
+		gfar_write(&regs->rxic, rx_queue->rxic);
 
-	gfar_write(&priv->regs->txic, 0);
+	gfar_write(&regs->txic, 0);
 	if (tx_queue->txcoalescing)
-		gfar_write(&priv->regs->txic, tx_queue->txic);
+		gfar_write(&regs->txic, tx_queue->txic);
 
 	return 0;
 }
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index 9c664f8..adea11e 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -50,6 +50,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 				 const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 	int new_setting = 0;
 	u32 temp;
@@ -74,14 +75,14 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 	/* Set the new stashing value */
 	priv->bd_stash_en = new_setting;
 
-	temp = gfar_read(&priv->regs->attr);
+	temp = gfar_read(&regs->attr);
 
 	if (new_setting)
 		temp |= ATTR_BDSTASH;
 	else
 		temp &= ~(ATTR_BDSTASH);
 
-	gfar_write(&priv->regs->attr, temp);
+	gfar_write(&regs->attr, temp);
 
 	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
 
@@ -103,6 +104,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 				      const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
@@ -122,20 +124,20 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 
 	priv->rx_stash_size = length;
 
-	temp = gfar_read(&priv->regs->attreli);
+	temp = gfar_read(&regs->attreli);
 	temp &= ~ATTRELI_EL_MASK;
 	temp |= ATTRELI_EL(length);
-	gfar_write(&priv->regs->attreli, temp);
+	gfar_write(&regs->attreli, temp);
 
 	/* Turn stashing on/off as appropriate */
-	temp = gfar_read(&priv->regs->attr);
+	temp = gfar_read(&regs->attr);
 
 	if (length)
 		temp |= ATTR_BUFSTASH;
 	else
 		temp &= ~(ATTR_BUFSTASH);
 
-	gfar_write(&priv->regs->attr, temp);
+	gfar_write(&regs->attr, temp);
 
 out:
 	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
@@ -161,6 +163,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 				       const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned short index = simple_strtoul(buf, NULL, 0);
 	u32 temp;
@@ -180,10 +183,10 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 
 	priv->rx_stash_index = index;
 
-	temp = gfar_read(&priv->regs->attreli);
+	temp = gfar_read(&regs->attreli);
 	temp &= ~ATTRELI_EI_MASK;
 	temp |= ATTRELI_EI(index);
-	gfar_write(&priv->regs->attreli, flags);
+	gfar_write(&regs->attreli, flags);
 
 out:
 	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
@@ -208,6 +211,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 				       const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
@@ -222,10 +226,10 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 
 	priv->fifo_threshold = length;
 
-	temp = gfar_read(&priv->regs->fifo_tx_thr);
+	temp = gfar_read(&regs->fifo_tx_thr);
 	temp &= ~FIFO_TX_THR_MASK;
 	temp |= length;
-	gfar_write(&priv->regs->fifo_tx_thr, temp);
+	gfar_write(&regs->fifo_tx_thr, temp);
 
 	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
@@ -248,6 +252,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 				    const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
@@ -261,10 +266,10 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 
 	priv->fifo_starve = num;
 
-	temp = gfar_read(&priv->regs->fifo_tx_starve);
+	temp = gfar_read(&regs->fifo_tx_starve);
 	temp &= ~FIFO_TX_STARVE_MASK;
 	temp |= num;
-	gfar_write(&priv->regs->fifo_tx_starve, temp);
+	gfar_write(&regs->fifo_tx_starve, temp);
 
 	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
@@ -288,6 +293,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 					const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar __iomem *regs = priv->gfargrp.regs;
 	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
@@ -301,10 +307,10 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 
 	priv->fifo_starve_off = num;
 
-	temp = gfar_read(&priv->regs->fifo_tx_starve_shutoff);
+	temp = gfar_read(&regs->fifo_tx_starve_shutoff);
 	temp &= ~FIFO_TX_STARVE_OFF_MASK;
 	temp |= num;
-	gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp);
+	gfar_write(&regs->fifo_tx_starve_shutoff, temp);
 
 	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
-- 
1.5.2.2


^ permalink raw reply related

* [PATCH v1 1/7] gianfar: Add per queue structure support
From: Sandeep Gopalpet @ 2009-10-26 16:27 UTC (permalink / raw)
  To: netdev; +Cc: Sandeep Gopalpet

This patch introduces per tx and per rx queue structures.
Earlier the members of these structures were inside the
gfar_private structure.

Moving forward if we want to support multiple queues, we need
to refactor the gfar_private structure so that introduction of
multiple queues is easier.

Signed-off-by: Sandeep Gopalpet <sandeep.kumar@freescale.com>
---
 drivers/net/gianfar.c         |  384 ++++++++++++++++++++++++-----------------
 drivers/net/gianfar.h         |  116 ++++++++-----
 drivers/net/gianfar_ethtool.c |  100 +++++++----
 drivers/net/gianfar_sysfs.c   |   43 ++++--
 4 files changed, 398 insertions(+), 245 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index f714186..354b2b5 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -8,9 +8,10 @@
  *
  * Author: Andy Fleming
  * Maintainer: Kumar Gala
+ * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
- * Copyright (c) 2007 MontaVista Software, Inc.
+ * Copyright 2002-2009 Freescale Semiconductor, Inc.
+ * Copyright 2007 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -109,7 +110,7 @@ static void gfar_reset_task(struct work_struct *work);
 static void gfar_timeout(struct net_device *dev);
 static int gfar_close(struct net_device *dev);
 struct sk_buff *gfar_new_skb(struct net_device *dev);
-static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
 		struct sk_buff *skb);
 static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
@@ -130,8 +131,8 @@ static int gfar_poll(struct napi_struct *napi, int budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void gfar_netpoll(struct net_device *dev);
 #endif
-int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
-static int gfar_clean_tx_ring(struct net_device *dev);
+int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
+static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
 			      int amount_pull);
 static void gfar_vlan_rx_register(struct net_device *netdev,
@@ -147,16 +148,16 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
 MODULE_LICENSE("GPL");
 
-static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
 			    dma_addr_t buf)
 {
-	struct gfar_private *priv = netdev_priv(dev);
+	struct net_device *dev = rx_queue->dev;
 	u32 lstatus;
 
 	bdp->bufPtr = buf;
 
 	lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
-	if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
+	if (bdp == rx_queue->rx_bd_base + rx_queue->rx_ring_size - 1)
 		lstatus |= BD_LFLAG(RXBD_WRAP);
 
 	eieio();
@@ -167,20 +168,25 @@ static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
 static int gfar_init_bds(struct net_device *ndev)
 {
 	struct gfar_private *priv = netdev_priv(ndev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct txbd8 *txbdp;
 	struct rxbd8 *rxbdp;
 	int i;
 
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
+
 	/* Initialize some variables in our dev structure */
-	priv->num_txbdfree = priv->tx_ring_size;
-	priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
-	priv->cur_rx = priv->rx_bd_base;
-	priv->skb_curtx = priv->skb_dirtytx = 0;
-	priv->skb_currx = 0;
+	tx_queue->num_txbdfree = tx_queue->tx_ring_size;
+	tx_queue->dirty_tx = tx_queue->cur_tx = tx_queue->tx_bd_base;
+	rx_queue->cur_rx = rx_queue->rx_bd_base;
+	tx_queue->skb_curtx = tx_queue->skb_dirtytx = 0;
+	rx_queue->skb_currx = 0;
 
 	/* Initialize Transmit Descriptor Ring */
-	txbdp = priv->tx_bd_base;
-	for (i = 0; i < priv->tx_ring_size; i++) {
+	txbdp = tx_queue->tx_bd_base;
+	for (i = 0; i < tx_queue->tx_ring_size; i++) {
 		txbdp->lstatus = 0;
 		txbdp->bufPtr = 0;
 		txbdp++;
@@ -190,12 +196,12 @@ static int gfar_init_bds(struct net_device *ndev)
 	txbdp--;
 	txbdp->status |= TXBD_WRAP;
 
-	rxbdp = priv->rx_bd_base;
-	for (i = 0; i < priv->rx_ring_size; i++) {
-		struct sk_buff *skb = priv->rx_skbuff[i];
+	rxbdp = rx_queue->rx_bd_base;
+	for (i = 0; i < rx_queue->rx_ring_size; i++) {
+		struct sk_buff *skb = rx_queue->rx_skbuff[i];
 
 		if (skb) {
-			gfar_init_rxbdp(ndev, rxbdp, rxbdp->bufPtr);
+			gfar_init_rxbdp(rx_queue, rxbdp, rxbdp->bufPtr);
 		} else {
 			skb = gfar_new_skb(ndev);
 			if (!skb) {
@@ -203,9 +209,9 @@ static int gfar_init_bds(struct net_device *ndev)
 				       ndev->name);
 				return -ENOMEM;
 			}
-			priv->rx_skbuff[i] = skb;
+			rx_queue->rx_skbuff[i] = skb;
 
-			gfar_new_rxbdp(ndev, rxbdp, skb);
+			gfar_new_rxbdp(rx_queue, rxbdp, skb);
 		}
 
 		rxbdp++;
@@ -220,12 +226,17 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 	int i;
 	struct gfar_private *priv = netdev_priv(ndev);
 	struct device *dev = &priv->ofdev->dev;
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
+
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
 
 	/* Allocate memory for the buffer descriptors */
 	vaddr = dma_alloc_coherent(dev,
-			sizeof(*priv->tx_bd_base) * priv->tx_ring_size +
-			sizeof(*priv->rx_bd_base) * priv->rx_ring_size,
-			&priv->tx_bd_dma_base, GFP_KERNEL);
+			sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size +
+			sizeof(*rx_queue->rx_bd_base) * rx_queue->rx_ring_size,
+			&tx_queue->tx_bd_dma_base, GFP_KERNEL);
 	if (!vaddr) {
 		if (netif_msg_ifup(priv))
 			pr_err("%s: Could not allocate buffer descriptors!\n",
@@ -233,36 +244,38 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
 		return -ENOMEM;
 	}
 
-	priv->tx_bd_base = vaddr;
+	tx_queue->tx_bd_base = vaddr;
+	tx_queue->dev = ndev;
 
 	/* Start the rx descriptor ring where the tx ring leaves off */
-	vaddr = vaddr + sizeof(*priv->tx_bd_base) * priv->tx_ring_size;
-	priv->rx_bd_base = vaddr;
+	vaddr = vaddr + sizeof(*tx_queue->tx_bd_base) * tx_queue->tx_ring_size;
+	rx_queue->rx_bd_base = vaddr;
+	rx_queue->dev = ndev;
 
 	/* Setup the skbuff rings */
-	priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) *
-				  priv->tx_ring_size, GFP_KERNEL);
-	if (!priv->tx_skbuff) {
+	tx_queue->tx_skbuff = kmalloc(sizeof(*tx_queue->tx_skbuff) *
+				  tx_queue->tx_ring_size, GFP_KERNEL);
+	if (!tx_queue->tx_skbuff) {
 		if (netif_msg_ifup(priv))
 			pr_err("%s: Could not allocate tx_skbuff\n",
 			       ndev->name);
 		goto cleanup;
 	}
 
-	for (i = 0; i < priv->tx_ring_size; i++)
-		priv->tx_skbuff[i] = NULL;
+	for (i = 0; i < tx_queue->tx_ring_size; i++)
+		tx_queue->tx_skbuff[i] = NULL;
 
-	priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) *
-				  priv->rx_ring_size, GFP_KERNEL);
-	if (!priv->rx_skbuff) {
+	rx_queue->rx_skbuff = kmalloc(sizeof(*rx_queue->rx_skbuff) *
+				  rx_queue->rx_ring_size, GFP_KERNEL);
+	if (!rx_queue->rx_skbuff) {
 		if (netif_msg_ifup(priv))
 			pr_err("%s: Could not allocate rx_skbuff\n",
 			       ndev->name);
 		goto cleanup;
 	}
 
-	for (i = 0; i < priv->rx_ring_size; i++)
-		priv->rx_skbuff[i] = NULL;
+	for (i = 0; i < rx_queue->rx_ring_size; i++)
+		rx_queue->rx_skbuff[i] = NULL;
 
 	if (gfar_init_bds(ndev))
 		goto cleanup;
@@ -278,24 +291,29 @@ static void gfar_init_mac(struct net_device *ndev)
 {
 	struct gfar_private *priv = netdev_priv(ndev);
 	struct gfar __iomem *regs = priv->regs;
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	u32 rctrl = 0;
 	u32 tctrl = 0;
 	u32 attrs = 0;
 
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
+
 	/* enet DMA only understands physical addresses */
-	gfar_write(&regs->tbase0, priv->tx_bd_dma_base);
-	gfar_write(&regs->rbase0, priv->tx_bd_dma_base +
-				  sizeof(*priv->tx_bd_base) *
-				  priv->tx_ring_size);
+	gfar_write(&regs->tbase0, tx_queue->tx_bd_dma_base);
+	gfar_write(&regs->rbase0, tx_queue->tx_bd_dma_base +
+				  sizeof(*tx_queue->tx_bd_base) *
+				  tx_queue->tx_ring_size);
 
 	/* Configure the coalescing support */
 	gfar_write(&regs->txic, 0);
-	if (priv->txcoalescing)
-		gfar_write(&regs->txic, priv->txic);
+	if (tx_queue->txcoalescing)
+		gfar_write(&regs->txic, tx_queue->txic);
 
 	gfar_write(&regs->rxic, 0);
-	if (priv->rxcoalescing)
-		gfar_write(&regs->rxic, priv->rxic);
+	if (rx_queue->rxcoalescing)
+		gfar_write(&regs->rxic, rx_queue->rxic);
 
 	if (priv->rx_csum_enable)
 		rctrl |= RCTRL_CHECKSUMMING;
@@ -414,7 +432,7 @@ static int gfar_of_init(struct net_device *dev)
 
 	stash = of_get_property(np, "bd-stash", NULL);
 
-	if(stash) {
+	if (stash) {
 		priv->device_flags |= FSL_GIANFAR_DEV_HAS_BD_STASHING;
 		priv->bd_stash_en = 1;
 	}
@@ -519,8 +537,18 @@ static int gfar_probe(struct of_device *ofdev,
 	if (err)
 		goto regs_fail;
 
-	spin_lock_init(&priv->txlock);
-	spin_lock_init(&priv->rxlock);
+	priv->tx_queue = (struct gfar_priv_tx_q *)kmalloc(
+				sizeof (struct gfar_priv_tx_q), GFP_KERNEL);
+	if (!priv->tx_queue)
+		goto regs_fail;
+
+	priv->rx_queue = (struct gfar_priv_rx_q *)kmalloc(
+				sizeof (struct gfar_priv_rx_q), GFP_KERNEL);
+	if (!priv->rx_queue)
+		goto rx_queue_fail;
+
+	spin_lock_init(&priv->tx_queue->txlock);
+	spin_lock_init(&priv->rx_queue->rxlock);
 	spin_lock_init(&priv->bflock);
 	INIT_WORK(&priv->reset_task, gfar_reset_task);
 
@@ -552,12 +580,13 @@ static int gfar_probe(struct of_device *ofdev,
 
 	/* Fill in the dev structure */
 	dev->watchdog_timeo = TX_TIMEOUT;
-	netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
 	dev->mtu = 1500;
-
 	dev->netdev_ops = &gfar_netdev_ops;
 	dev->ethtool_ops = &gfar_ethtool_ops;
 
+	/* Register for napi ...NAPI is for each rx_queue */
+	netif_napi_add(dev, &priv->rx_queue->napi, gfar_poll, GFAR_DEV_WEIGHT);
+
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
 		priv->rx_csum_enable = 1;
 		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
@@ -613,14 +642,16 @@ static int gfar_probe(struct of_device *ofdev,
 		dev->hard_header_len += GMAC_FCB_LEN;
 
 	priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
-	priv->tx_ring_size = DEFAULT_TX_RING_SIZE;
-	priv->rx_ring_size = DEFAULT_RX_RING_SIZE;
-	priv->num_txbdfree = DEFAULT_TX_RING_SIZE;
 
-	priv->txcoalescing = DEFAULT_TX_COALESCE;
-	priv->txic = DEFAULT_TXIC;
-	priv->rxcoalescing = DEFAULT_RX_COALESCE;
-	priv->rxic = DEFAULT_RXIC;
+	/* Initializing some of the rx/tx queue level parameters */
+	priv->tx_queue->tx_ring_size = DEFAULT_TX_RING_SIZE;
+	priv->tx_queue->num_txbdfree = DEFAULT_TX_RING_SIZE;
+	priv->tx_queue->txcoalescing = DEFAULT_TX_COALESCE;
+	priv->tx_queue->txic = DEFAULT_TXIC;
+
+	priv->rx_queue->rx_ring_size = DEFAULT_RX_RING_SIZE;
+	priv->rx_queue->rxcoalescing = DEFAULT_RX_COALESCE;
+	priv->rx_queue->rxic = DEFAULT_RXIC;
 
 	/* Enable most messages by default */
 	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
@@ -666,12 +697,15 @@ static int gfar_probe(struct of_device *ofdev,
 	/* provided which set of benchmarks. */
 	printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name);
 	printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n",
-	       dev->name, priv->rx_ring_size, priv->tx_ring_size);
+	       dev->name, priv->rx_queue->rx_ring_size, priv->tx_queue->tx_ring_size);
 
 	return 0;
 
 register_fail:
 	iounmap(priv->regs);
+	kfree(priv->rx_queue);
+rx_queue_fail:
+	kfree(priv->tx_queue);
 regs_fail:
 	if (priv->phy_node)
 		of_node_put(priv->phy_node);
@@ -705,6 +739,8 @@ static int gfar_suspend(struct device *dev)
 {
 	struct gfar_private *priv = dev_get_drvdata(dev);
 	struct net_device *ndev = priv->ndev;
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 	u32 tempval;
 
@@ -712,10 +748,12 @@ static int gfar_suspend(struct device *dev)
 		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
 	netif_device_detach(ndev);
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
 
 	if (netif_running(ndev)) {
-		spin_lock_irqsave(&priv->txlock, flags);
-		spin_lock(&priv->rxlock);
+		spin_lock_irqsave(&tx_queue->txlock, flags);
+		spin_lock(&rx_queue->rxlock);
 
 		gfar_halt_nodisable(ndev);
 
@@ -729,10 +767,10 @@ static int gfar_suspend(struct device *dev)
 
 		gfar_write(&priv->regs->maccfg1, tempval);
 
-		spin_unlock(&priv->rxlock);
-		spin_unlock_irqrestore(&priv->txlock, flags);
+		spin_unlock(&rx_queue->rxlock);
+		spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
-		napi_disable(&priv->napi);
+		napi_disable(&rx_queue->napi);
 
 		if (magic_packet) {
 			/* Enable interrupt on Magic Packet */
@@ -754,6 +792,8 @@ static int gfar_resume(struct device *dev)
 {
 	struct gfar_private *priv = dev_get_drvdata(dev);
 	struct net_device *ndev = priv->ndev;
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 	u32 tempval;
 	int magic_packet = priv->wol_en &&
@@ -770,9 +810,11 @@ static int gfar_resume(struct device *dev)
 	/* Disable Magic Packet mode, in case something
 	 * else woke us up.
 	 */
+	rx_queue = priv->rx_queue;
+	tx_queue = priv->tx_queue;
 
-	spin_lock_irqsave(&priv->txlock, flags);
-	spin_lock(&priv->rxlock);
+	spin_lock_irqsave(&tx_queue->txlock, flags);
+	spin_lock(&rx_queue->rxlock);
 
 	tempval = gfar_read(&priv->regs->maccfg2);
 	tempval &= ~MACCFG2_MPEN;
@@ -780,12 +822,12 @@ static int gfar_resume(struct device *dev)
 
 	gfar_start(ndev);
 
-	spin_unlock(&priv->rxlock);
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock(&rx_queue->rxlock);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
 	netif_device_attach(ndev);
 
-	napi_enable(&priv->napi);
+	napi_enable(&rx_queue->napi);
 
 	return 0;
 }
@@ -1060,18 +1102,23 @@ void gfar_halt(struct net_device *dev)
 void stop_gfar(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 
 	phy_stop(priv->phydev);
 
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
+
 	/* Lock it down */
-	spin_lock_irqsave(&priv->txlock, flags);
-	spin_lock(&priv->rxlock);
+	spin_lock_irqsave(&tx_queue->txlock, flags);
+	spin_lock(&rx_queue->rxlock);
 
 	gfar_halt(dev);
 
-	spin_unlock(&priv->rxlock);
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock(&rx_queue->rxlock);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
 	/* Free the IRQs */
 	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
@@ -1092,46 +1139,50 @@ static void free_skb_resources(struct gfar_private *priv)
 	struct device *dev = &priv->ofdev->dev;
 	struct rxbd8 *rxbdp;
 	struct txbd8 *txbdp;
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	int i, j;
 
 	/* Go through all the buffer descriptors and free their data buffers */
-	txbdp = priv->tx_bd_base;
+	tx_queue = priv->tx_queue;
+	txbdp = tx_queue->tx_bd_base;
 
-	if (!priv->tx_skbuff)
+	if (!tx_queue->tx_skbuff)
 		goto skip_tx_skbuff;
 
-	for (i = 0; i < priv->tx_ring_size; i++) {
-		if (!priv->tx_skbuff[i])
+	for (i = 0; i < tx_queue->tx_ring_size; i++) {
+		if (!tx_queue->tx_skbuff[i])
 			continue;
 
 		dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr,
 				txbdp->length, DMA_TO_DEVICE);
 		txbdp->lstatus = 0;
-		for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) {
+		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags; j++) {
 			txbdp++;
 			dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr,
 					txbdp->length, DMA_TO_DEVICE);
 		}
 		txbdp++;
-		dev_kfree_skb_any(priv->tx_skbuff[i]);
-		priv->tx_skbuff[i] = NULL;
+		dev_kfree_skb_any(tx_queue->tx_skbuff[i]);
+		tx_queue->tx_skbuff[i] = NULL;
 	}
 
-	kfree(priv->tx_skbuff);
+	kfree(tx_queue->tx_skbuff);
 skip_tx_skbuff:
 
-	rxbdp = priv->rx_bd_base;
+	rx_queue = priv->rx_queue;
+	rxbdp = rx_queue->rx_bd_base;
 
-	if (!priv->rx_skbuff)
+	if (!rx_queue->rx_skbuff)
 		goto skip_rx_skbuff;
 
-	for (i = 0; i < priv->rx_ring_size; i++) {
-		if (priv->rx_skbuff[i]) {
+	for (i = 0; i < rx_queue->rx_ring_size; i++) {
+		if (rx_queue->rx_skbuff[i]) {
 			dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
 					 priv->rx_buffer_size,
 					DMA_FROM_DEVICE);
-			dev_kfree_skb_any(priv->rx_skbuff[i]);
-			priv->rx_skbuff[i] = NULL;
+			dev_kfree_skb_any(rx_queue->rx_skbuff[i]);
+			rx_queue->rx_skbuff[i] = NULL;
 		}
 
 		rxbdp->lstatus = 0;
@@ -1139,17 +1190,19 @@ skip_tx_skbuff:
 		rxbdp++;
 	}
 
-	kfree(priv->rx_skbuff);
+	kfree(rx_queue->rx_skbuff);
 skip_rx_skbuff:
 
-	dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
-			       sizeof(*rxbdp) * priv->rx_ring_size,
-			  priv->tx_bd_base, priv->tx_bd_dma_base);
+	dma_free_coherent(dev, sizeof(*txbdp) * tx_queue->tx_ring_size +
+			       sizeof(*rxbdp) * rx_queue->rx_ring_size,
+			  tx_queue->tx_bd_base, tx_queue->tx_bd_dma_base);
 }
 
 void gfar_start(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue;
+	struct gfar_priv_rx_q *rx_queue;
 	struct gfar __iomem *regs = priv->regs;
 	u32 tempval;
 
@@ -1258,7 +1311,7 @@ static int gfar_enet_open(struct net_device *dev)
 	struct gfar_private *priv = netdev_priv(dev);
 	int err;
 
-	napi_enable(&priv->napi);
+	napi_enable(&priv->rx_queue->napi);
 
 	skb_queue_head_init(&priv->rx_recycle);
 
@@ -1269,14 +1322,14 @@ static int gfar_enet_open(struct net_device *dev)
 
 	err = init_phy(dev);
 
-	if(err) {
-		napi_disable(&priv->napi);
+	if (err) {
+		napi_disable(&priv->rx_queue->napi);
 		return err;
 	}
 
 	err = startup_gfar(dev);
 	if (err) {
-		napi_disable(&priv->napi);
+		napi_disable(&priv->rx_queue->napi);
 		return err;
 	}
 
@@ -1349,6 +1402,7 @@ static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base,
 static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct txfcb *fcb = NULL;
 	struct txbd8 *txbdp, *txbdp_start, *base;
 	u32 lstatus;
@@ -1357,7 +1411,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	unsigned long flags;
 	unsigned int nr_frags, length;
 
-	base = priv->tx_bd_base;
+	tx_queue = priv->tx_queue;
+	base = tx_queue->tx_bd_base;
 
 	/* make space for additional header when fcb is needed */
 	if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
@@ -1378,21 +1433,21 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* total number of fragments in the SKB */
 	nr_frags = skb_shinfo(skb)->nr_frags;
 
-	spin_lock_irqsave(&priv->txlock, flags);
+	spin_lock_irqsave(&tx_queue->txlock, flags);
 
 	/* check if there is space to queue this packet */
-	if ((nr_frags+1) > priv->num_txbdfree) {
+	if ((nr_frags+1) > tx_queue->num_txbdfree) {
 		/* no space, stop the queue */
 		netif_stop_queue(dev);
 		dev->stats.tx_fifo_errors++;
-		spin_unlock_irqrestore(&priv->txlock, flags);
+		spin_unlock_irqrestore(&tx_queue->txlock, flags);
 		return NETDEV_TX_BUSY;
 	}
 
 	/* Update transmit stats */
 	dev->stats.tx_bytes += skb->len;
 
-	txbdp = txbdp_start = priv->cur_tx;
+	txbdp = txbdp_start = tx_queue->cur_tx;
 
 	if (nr_frags == 0) {
 		lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
@@ -1400,7 +1455,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		/* Place the fragment addresses and lengths into the TxBDs */
 		for (i = 0; i < nr_frags; i++) {
 			/* Point at the next BD, wrapping as needed */
-			txbdp = next_txbd(txbdp, base, priv->tx_ring_size);
+			txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
 
 			length = skb_shinfo(skb)->frags[i].size;
 
@@ -1442,7 +1497,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	/* setup the TxBD length and buffer pointer for the first BD */
-	priv->tx_skbuff[priv->skb_curtx] = skb;
+	tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb;
 	txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
 			skb_headlen(skb), DMA_TO_DEVICE);
 
@@ -1462,19 +1517,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	/* Update the current skb pointer to the next entry we will use
 	 * (wrapping if necessary) */
-	priv->skb_curtx = (priv->skb_curtx + 1) &
-		TX_RING_MOD_MASK(priv->tx_ring_size);
+	tx_queue->skb_curtx = (tx_queue->skb_curtx + 1) &
+		TX_RING_MOD_MASK(tx_queue->tx_ring_size);
 
-	priv->cur_tx = next_txbd(txbdp, base, priv->tx_ring_size);
+	tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size);
 
 	/* reduce TxBD free count */
-	priv->num_txbdfree -= (nr_frags + 1);
+	tx_queue->num_txbdfree -= (nr_frags + 1);
 
 	dev->trans_start = jiffies;
 
 	/* If the next BD still needs to be cleaned up, then the bds
 	   are full.  We need to tell the kernel to stop sending us stuff. */
-	if (!priv->num_txbdfree) {
+	if (!tx_queue->num_txbdfree) {
 		netif_stop_queue(dev);
 
 		dev->stats.tx_fifo_errors++;
@@ -1484,7 +1539,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
 
 	/* Unlock priv */
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
 	return NETDEV_TX_OK;
 }
@@ -1494,7 +1549,7 @@ static int gfar_close(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	napi_disable(&priv->napi);
+	napi_disable(&priv->rx_queue->napi);
 
 	skb_queue_purge(&priv->rx_recycle);
 	cancel_work_sync(&priv->reset_task);
@@ -1523,10 +1578,12 @@ static void gfar_vlan_rx_register(struct net_device *dev,
 		struct vlan_group *grp)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 	u32 tempval;
 
-	spin_lock_irqsave(&priv->rxlock, flags);
+	rx_queue = priv->rx_queue;
+	spin_lock_irqsave(&rx_queue->rxlock, flags);
 
 	priv->vlgrp = grp;
 
@@ -1560,7 +1617,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
 
 	gfar_change_mtu(dev, dev->mtu);
 
-	spin_unlock_irqrestore(&priv->rxlock, flags);
+	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
 }
 
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
@@ -1649,24 +1706,27 @@ static void gfar_timeout(struct net_device *dev)
 }
 
 /* Interrupt Handler for Transmit complete */
-static int gfar_clean_tx_ring(struct net_device *dev)
+static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 {
+	struct net_device *dev = tx_queue->dev;
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	struct txbd8 *bdp;
 	struct txbd8 *lbdp = NULL;
-	struct txbd8 *base = priv->tx_bd_base;
+	struct txbd8 *base = tx_queue->tx_bd_base;
 	struct sk_buff *skb;
 	int skb_dirtytx;
-	int tx_ring_size = priv->tx_ring_size;
+	int tx_ring_size = tx_queue->tx_ring_size;
 	int frags = 0;
 	int i;
 	int howmany = 0;
 	u32 lstatus;
 
-	bdp = priv->dirty_tx;
-	skb_dirtytx = priv->skb_dirtytx;
+	rx_queue = priv->rx_queue;
+	bdp = tx_queue->dirty_tx;
+	skb_dirtytx = tx_queue->skb_dirtytx;
 
-	while ((skb = priv->tx_skbuff[skb_dirtytx])) {
+	while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
 		frags = skb_shinfo(skb)->nr_frags;
 		lbdp = skip_txbd(bdp, frags, base, tx_ring_size);
 
@@ -1698,29 +1758,29 @@ static int gfar_clean_tx_ring(struct net_device *dev)
 		 * If there's room in the queue (limit it to rx_buffer_size)
 		 * we add this skb back into the pool, if it's the right size
 		 */
-		if (skb_queue_len(&priv->rx_recycle) < priv->rx_ring_size &&
+		if (skb_queue_len(&priv->rx_recycle) < rx_queue->rx_ring_size &&
 				skb_recycle_check(skb, priv->rx_buffer_size +
 					RXBUF_ALIGNMENT))
 			__skb_queue_head(&priv->rx_recycle, skb);
 		else
 			dev_kfree_skb_any(skb);
 
-		priv->tx_skbuff[skb_dirtytx] = NULL;
+		tx_queue->tx_skbuff[skb_dirtytx] = NULL;
 
 		skb_dirtytx = (skb_dirtytx + 1) &
 			TX_RING_MOD_MASK(tx_ring_size);
 
 		howmany++;
-		priv->num_txbdfree += frags + 1;
+		tx_queue->num_txbdfree += frags + 1;
 	}
 
 	/* If we freed a buffer, we can restart transmission, if necessary */
-	if (netif_queue_stopped(dev) && priv->num_txbdfree)
+	if (netif_queue_stopped(dev) && tx_queue->num_txbdfree)
 		netif_wake_queue(dev);
 
 	/* Update dirty indicators */
-	priv->skb_dirtytx = skb_dirtytx;
-	priv->dirty_tx = bdp;
+	tx_queue->skb_dirtytx = skb_dirtytx;
+	tx_queue->dirty_tx = bdp;
 
 	dev->stats.tx_packets += howmany;
 
@@ -1730,14 +1790,18 @@ static int gfar_clean_tx_ring(struct net_device *dev)
 static void gfar_schedule_cleanup(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned long flags;
 
-	spin_lock_irqsave(&priv->txlock, flags);
-	spin_lock(&priv->rxlock);
+	rx_queue = priv->rx_queue;
+	tx_queue = priv->tx_queue;
+	spin_lock_irqsave(&tx_queue->txlock, flags);
+	spin_lock(&rx_queue->rxlock);
 
-	if (napi_schedule_prep(&priv->napi)) {
+	if (napi_schedule_prep(&rx_queue->napi)) {
 		gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED);
-		__napi_schedule(&priv->napi);
+		__napi_schedule(&rx_queue->napi);
 	} else {
 		/*
 		 * Clear IEVENT, so interrupts aren't called again
@@ -1746,8 +1810,8 @@ static void gfar_schedule_cleanup(struct net_device *dev)
 		gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
 	}
 
-	spin_unlock(&priv->rxlock);
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock(&rx_queue->rxlock);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 }
 
 /* Interrupt Handler for Transmit complete */
@@ -1757,15 +1821,16 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
 		struct sk_buff *skb)
 {
+	struct net_device *dev = rx_queue->dev;
 	struct gfar_private *priv = netdev_priv(dev);
 	dma_addr_t buf;
 
 	buf = dma_map_single(&priv->ofdev->dev, skb->data,
 			     priv->rx_buffer_size, DMA_FROM_DEVICE);
-	gfar_init_rxbdp(dev, bdp, buf);
+	gfar_init_rxbdp(rx_queue, bdp, buf);
 }
 
 
@@ -1890,8 +1955,9 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
  *   until the budget/quota has been reached. Returns the number
  *   of frames handled
  */
-int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
 {
+	struct net_device *dev = rx_queue->dev;
 	struct rxbd8 *bdp, *base;
 	struct sk_buff *skb;
 	int pkt_len;
@@ -1900,8 +1966,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 	struct gfar_private *priv = netdev_priv(dev);
 
 	/* Get the first full descriptor */
-	bdp = priv->cur_rx;
-	base = priv->rx_bd_base;
+	bdp = rx_queue->cur_rx;
+	base = rx_queue->rx_bd_base;
 
 	amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
 		priv->padding;
@@ -1913,7 +1979,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 		/* Add another skb for the future */
 		newskb = gfar_new_skb(dev);
 
-		skb = priv->rx_skbuff[priv->skb_currx];
+		skb = rx_queue->rx_skbuff[rx_queue->skb_currx];
 
 		dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
 				priv->rx_buffer_size, DMA_FROM_DEVICE);
@@ -1961,30 +2027,33 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 
 		}
 
-		priv->rx_skbuff[priv->skb_currx] = newskb;
+		rx_queue->rx_skbuff[rx_queue->skb_currx] = newskb;
 
 		/* Setup the new bdp */
-		gfar_new_rxbdp(dev, bdp, newskb);
+		gfar_new_rxbdp(rx_queue, bdp, newskb);
 
 		/* Update to the next pointer */
-		bdp = next_bd(bdp, base, priv->rx_ring_size);
+		bdp = next_bd(bdp, base, rx_queue->rx_ring_size);
 
 		/* update to point at the next skb */
-		priv->skb_currx =
-		    (priv->skb_currx + 1) &
-		    RX_RING_MOD_MASK(priv->rx_ring_size);
+		rx_queue->skb_currx =
+		    (rx_queue->skb_currx + 1) &
+		    RX_RING_MOD_MASK(rx_queue->rx_ring_size);
 	}
 
 	/* Update the current rxbd pointer to be the next one */
-	priv->cur_rx = bdp;
+	rx_queue->cur_rx = bdp;
 
 	return howmany;
 }
 
 static int gfar_poll(struct napi_struct *napi, int budget)
 {
-	struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
-	struct net_device *dev = priv->ndev;
+	struct gfar_priv_rx_q *rx_queue = container_of(napi,
+			struct gfar_priv_rx_q, napi);
+	struct net_device *dev = rx_queue->dev;
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	int tx_cleaned = 0;
 	int rx_cleaned = 0;
 	unsigned long flags;
@@ -1992,14 +2061,15 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 	/* Clear IEVENT, so interrupts aren't called again
 	 * because of the packets that have already arrived */
 	gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
+	tx_queue = priv->tx_queue;
 
 	/* If we fail to get the lock, don't bother with the TX BDs */
-	if (spin_trylock_irqsave(&priv->txlock, flags)) {
-		tx_cleaned = gfar_clean_tx_ring(dev);
-		spin_unlock_irqrestore(&priv->txlock, flags);
+	if (spin_trylock_irqsave(&tx_queue->txlock, flags)) {
+		tx_cleaned = gfar_clean_tx_ring(tx_queue);
+		spin_unlock_irqrestore(&tx_queue->txlock, flags);
 	}
 
-	rx_cleaned = gfar_clean_rx_ring(dev, budget);
+	rx_cleaned = gfar_clean_rx_ring(rx_queue, budget);
 
 	if (tx_cleaned)
 		return budget;
@@ -2014,13 +2084,13 @@ static int gfar_poll(struct napi_struct *napi, int budget)
 
 		/* If we are coalescing interrupts, update the timer */
 		/* Otherwise, clear it */
-		if (likely(priv->rxcoalescing)) {
+		if (likely(rx_queue->rxcoalescing)) {
 			gfar_write(&priv->regs->rxic, 0);
-			gfar_write(&priv->regs->rxic, priv->rxic);
+			gfar_write(&priv->regs->rxic, rx_queue->rxic);
 		}
-		if (likely(priv->txcoalescing)) {
+		if (likely(tx_queue->txcoalescing)) {
 			gfar_write(&priv->regs->txic, 0);
-			gfar_write(&priv->regs->txic, priv->txic);
+			gfar_write(&priv->regs->txic, tx_queue->txic);
 		}
 	}
 
@@ -2087,12 +2157,14 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id)
 static void adjust_link(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	struct gfar __iomem *regs = priv->regs;
 	unsigned long flags;
 	struct phy_device *phydev = priv->phydev;
 	int new_state = 0;
 
-	spin_lock_irqsave(&priv->txlock, flags);
+	tx_queue = priv->tx_queue;
+	spin_lock_irqsave(&tx_queue->txlock, flags);
 	if (phydev->link) {
 		u32 tempval = gfar_read(&regs->maccfg2);
 		u32 ecntrl = gfar_read(&regs->ecntrl);
@@ -2158,7 +2230,7 @@ static void adjust_link(struct net_device *dev)
 	if (new_state && netif_msg_link(priv))
 		phy_print_status(phydev);
 
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 }
 
 /* Update the hash table based on the current list of multicast
@@ -2172,7 +2244,7 @@ static void gfar_set_multi(struct net_device *dev)
 	struct gfar __iomem *regs = priv->regs;
 	u32 tempval;
 
-	if(dev->flags & IFF_PROMISC) {
+	if (dev->flags & IFF_PROMISC) {
 		/* Set RCTRL to PROM */
 		tempval = gfar_read(&regs->rctrl);
 		tempval |= RCTRL_PROM;
@@ -2184,7 +2256,7 @@ static void gfar_set_multi(struct net_device *dev)
 		gfar_write(&regs->rctrl, tempval);
 	}
 
-	if(dev->flags & IFF_ALLMULTI) {
+	if (dev->flags & IFF_ALLMULTI) {
 		/* Set the hash to rx all multicast frames */
 		gfar_write(&regs->igaddr0, 0xffffffff);
 		gfar_write(&regs->igaddr1, 0xffffffff);
@@ -2236,7 +2308,7 @@ static void gfar_set_multi(struct net_device *dev)
 			em_num = 0;
 		}
 
-		if(dev->mc_count == 0)
+		if (dev->mc_count == 0)
 			return;
 
 		/* Parse the list, and set the appropriate bits */
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 05732fa..a60f93f 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -7,8 +7,9 @@
  *
  * Author: Andy Fleming
  * Maintainer: Kumar Gala
+ * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -699,6 +700,76 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_BD_STASHING		0x00000200
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING	0x00000400
 
+/**
+ *	struct gfar_priv_tx_q - per tx queue structure
+ *	@txlock: per queue tx spin lock
+ *	@tx_skbuff:skb pointers
+ *	@skb_curtx: to be used skb pointer
+ *	@skb_dirtytx:the last used skb pointer
+ *	@qindex: index of this queue
+ *	@dev: back pointer to the dev structure
+ *	@grp: back pointer to the group to which this queue belongs
+ *	@tx_bd_base: First tx buffer descriptor
+ *	@cur_tx: Next free ring entry
+ *	@dirty_tx: First buffer in line to be transmitted
+ *	@tx_ring_size: Tx ring size
+ *	@num_txbdfree: number of free TxBds
+ *	@txcoalescing: enable/disable tx coalescing
+ *	@txic: transmit interrupt coalescing value
+ *	@txcount: coalescing value if based on tx frame count
+ *	@txtime: coalescing value if based on time
+ */
+struct gfar_priv_tx_q {
+	spinlock_t txlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
+	struct sk_buff ** tx_skbuff;
+	/* Buffer descriptor pointers */
+	dma_addr_t tx_bd_dma_base;
+	struct	txbd8 *tx_bd_base;
+	struct	txbd8 *cur_tx;
+	struct	txbd8 *dirty_tx;
+	struct	net_device *dev;
+	u16	skb_curtx;
+	u16	skb_dirtytx;
+	u16	qindex;
+	unsigned int tx_ring_size;
+	unsigned int num_txbdfree;
+	/* Configuration info for the coalescing features */
+	unsigned char txcoalescing;
+	unsigned long txic;
+	unsigned short txcount;
+	unsigned short txtime;
+};
+
+/**
+ *	struct gfar_priv_rx_q - per rx queue structure
+ *	@rxlock: per queue rx spin lock
+ *	@napi: the napi poll function
+ *	@rx_skbuff: skb pointers
+ *	@skb_currx: currently use skb pointer
+ *	@rx_bd_base: First rx buffer descriptor
+ *	@cur_rx: Next free rx ring entry
+ *	@qindex: index of this queue
+ *	@dev: back pointer to the dev structure
+ *	@rx_ring_size: Rx ring size
+ *	@rxcoalescing: enable/disable rx-coalescing
+ *	@rxic: receive interrupt coalescing vlaue
+ */
+
+struct gfar_priv_rx_q {
+	spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
+	struct	napi_struct napi;
+	struct	sk_buff ** rx_skbuff;
+	struct	rxbd8 *rx_bd_base;
+	struct	rxbd8 *cur_rx;
+	struct	net_device *dev;
+	u16	skb_currx;
+	u16	qindex;
+	unsigned int	rx_ring_size;
+	/* RX Coalescing values */
+	unsigned char rxcoalescing;
+	unsigned long rxic;
+};
+
 /* Struct stolen almost completely (and shamelessly) from the FCC enet source
  * (Ok, that's not so true anymore, but there is a family resemblence)
  * The GFAR buffer descriptors track the ring buffers.  The rx_bd_base
@@ -709,52 +780,15 @@ struct gfar {
  * the buffer descriptor determines the actual condition.
  */
 struct gfar_private {
-	/* Fields controlled by TX lock */
-	spinlock_t txlock;
-
-	/* Pointer to the array of skbuffs */
-	struct sk_buff ** tx_skbuff;
-
-	/* next free skb in the array */
-	u16 skb_curtx;
-
-	/* First skb in line to be transmitted */
-	u16 skb_dirtytx;
-
-	/* Configuration info for the coalescing features */
-	unsigned char txcoalescing;
-	unsigned long txic;
-
-	/* Buffer descriptor pointers */
-	dma_addr_t tx_bd_dma_base;
-	struct txbd8 *tx_bd_base;	/* First tx buffer descriptor */
-	struct txbd8 *cur_tx;	        /* Next free ring entry */
-	struct txbd8 *dirty_tx;		/* First buffer in line
-					   to be transmitted */
-	unsigned int tx_ring_size;
-	unsigned int num_txbdfree;	/* number of TxBDs free */
-
-	/* RX Locked fields */
-	spinlock_t rxlock;
 
 	struct device_node *node;
 	struct net_device *ndev;
 	struct of_device *ofdev;
-	struct napi_struct napi;
-
-	/* skb array and index */
-	struct sk_buff ** rx_skbuff;
-	u16 skb_currx;
-
-	/* RX Coalescing values */
-	unsigned char rxcoalescing;
-	unsigned long rxic;
 
-	struct rxbd8 *rx_bd_base;	/* First Rx buffers */
-	struct rxbd8 *cur_rx;           /* Next free rx ring entry */
+	struct gfar_priv_tx_q *tx_queue;
+	struct gfar_priv_rx_q *rx_queue;
 
-	/* RX parameters */
-	unsigned int rx_ring_size;
+	/* RX per device parameters */
 	unsigned int rx_buffer_size;
 	unsigned int rx_stash_size;
 	unsigned int rx_stash_index;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6c144b5..6d0d171 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -7,8 +7,9 @@
  *
  *  Author: Andy Fleming
  *  Maintainer: Kumar Gala
+ *  Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- *  Copyright (c) 2003,2004 Freescale Semiconductor, Inc.
+ *  Copyright 2003-2006, 2008-2009 Freescale Semiconductor, Inc.
  *
  *  This software may be used and distributed according to
  *  the terms of the GNU Public License, Version 2, incorporated herein
@@ -41,7 +42,7 @@
 #include "gianfar.h"
 
 extern void gfar_start(struct net_device *dev);
-extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
 
 #define GFAR_MAX_COAL_USECS 0xffff
 #define GFAR_MAX_COAL_FRAMES 0xff
@@ -197,12 +198,16 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct phy_device *phydev = priv->phydev;
+	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar_priv_tx_q *tx_queue = NULL;
 
 	if (NULL == phydev)
 		return -ENODEV;
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
 
-	cmd->maxtxpkt = get_icft_value(priv->txic);
-	cmd->maxrxpkt = get_icft_value(priv->rxic);
+	cmd->maxtxpkt = get_icft_value(tx_queue->txic);
+	cmd->maxrxpkt = get_icft_value(rx_queue->rxic);
 
 	return phy_ethtool_gset(phydev, cmd);
 }
@@ -279,6 +284,8 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
 static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned long rxtime;
 	unsigned long rxcount;
 	unsigned long txtime;
@@ -290,10 +297,13 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 	if (NULL == priv->phydev)
 		return -ENODEV;
 
-	rxtime  = get_ictt_value(priv->rxic);
-	rxcount = get_icft_value(priv->rxic);
-	txtime  = get_ictt_value(priv->txic);
-	txcount = get_icft_value(priv->txic);
+	rx_queue = priv->rx_queue;
+	tx_queue = priv->tx_queue;
+
+	rxtime  = get_ictt_value(rx_queue->rxic);
+	rxcount = get_icft_value(rx_queue->rxic);
+	txtime  = get_ictt_value(tx_queue->txic);
+	txcount = get_icft_value(tx_queue->txic);
 	cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, rxtime);
 	cvals->rx_max_coalesced_frames = rxcount;
 
@@ -339,16 +349,21 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
 		return -EOPNOTSUPP;
 
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
+
 	/* Set up rx coalescing */
 	if ((cvals->rx_coalesce_usecs == 0) ||
 	    (cvals->rx_max_coalesced_frames == 0))
-		priv->rxcoalescing = 0;
+		rx_queue->rxcoalescing = 0;
 	else
-		priv->rxcoalescing = 1;
+		rx_queue->rxcoalescing = 1;
 
 	if (NULL == priv->phydev)
 		return -ENODEV;
@@ -366,15 +381,15 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 		return -EINVAL;
 	}
 
-	priv->rxic = mk_ic_value(cvals->rx_max_coalesced_frames,
+	rx_queue->rxic = mk_ic_value(cvals->rx_max_coalesced_frames,
 		gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs));
 
 	/* Set up tx coalescing */
 	if ((cvals->tx_coalesce_usecs == 0) ||
 	    (cvals->tx_max_coalesced_frames == 0))
-		priv->txcoalescing = 0;
+		tx_queue->txcoalescing = 0;
 	else
-		priv->txcoalescing = 1;
+		tx_queue->txcoalescing = 1;
 
 	/* Check the bounds of the values */
 	if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
@@ -389,16 +404,16 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 		return -EINVAL;
 	}
 
-	priv->txic = mk_ic_value(cvals->tx_max_coalesced_frames,
+	tx_queue->txic = mk_ic_value(cvals->tx_max_coalesced_frames,
 		gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
 
 	gfar_write(&priv->regs->rxic, 0);
-	if (priv->rxcoalescing)
-		gfar_write(&priv->regs->rxic, priv->rxic);
+	if (rx_queue->rxcoalescing)
+		gfar_write(&priv->regs->rxic, rx_queue->rxic);
 
 	gfar_write(&priv->regs->txic, 0);
-	if (priv->txcoalescing)
-		gfar_write(&priv->regs->txic, priv->txic);
+	if (tx_queue->txcoalescing)
+		gfar_write(&priv->regs->txic, tx_queue->txic);
 
 	return 0;
 }
@@ -409,6 +424,11 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
 static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
+
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
 
 	rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE;
 	rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE;
@@ -418,10 +438,10 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
 	/* Values changeable by the user.  The valid values are
 	 * in the range 1 to the "*_max_pending" counterpart above.
 	 */
-	rvals->rx_pending = priv->rx_ring_size;
-	rvals->rx_mini_pending = priv->rx_ring_size;
-	rvals->rx_jumbo_pending = priv->rx_ring_size;
-	rvals->tx_pending = priv->tx_ring_size;
+	rvals->rx_pending = rx_queue->rx_ring_size;
+	rvals->rx_mini_pending = rx_queue->rx_ring_size;
+	rvals->rx_jumbo_pending = rx_queue->rx_ring_size;
+	rvals->tx_pending = tx_queue->tx_ring_size;
 }
 
 /* Change the current ring parameters, stopping the controller if
@@ -431,6 +451,8 @@ static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rv
 static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_tx_q *tx_queue = NULL;
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	int err = 0;
 
 	if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
@@ -451,29 +473,32 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 		return -EINVAL;
 	}
 
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
+
 	if (dev->flags & IFF_UP) {
 		unsigned long flags;
 
 		/* Halt TX and RX, and process the frames which
 		 * have already been received */
-		spin_lock_irqsave(&priv->txlock, flags);
-		spin_lock(&priv->rxlock);
+		spin_lock_irqsave(&tx_queue->txlock, flags);
+		spin_lock(&rx_queue->rxlock);
 
 		gfar_halt(dev);
 
-		spin_unlock(&priv->rxlock);
-		spin_unlock_irqrestore(&priv->txlock, flags);
+		spin_unlock(&rx_queue->rxlock);
+		spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
-		gfar_clean_rx_ring(dev, priv->rx_ring_size);
+		gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size);
 
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
 	}
 
 	/* Change the size */
-	priv->rx_ring_size = rvals->rx_pending;
-	priv->tx_ring_size = rvals->tx_pending;
-	priv->num_txbdfree = priv->tx_ring_size;
+	rx_queue->rx_ring_size = rvals->rx_pending;
+	tx_queue->tx_ring_size = rvals->tx_pending;
+	tx_queue->num_txbdfree = tx_queue->tx_ring_size;
 
 	/* Rebuild the rings with the new size */
 	if (dev->flags & IFF_UP) {
@@ -486,24 +511,29 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar_priv_rx_q *rx_queue = NULL;
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned long flags;
 	int err = 0;
 
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return -EOPNOTSUPP;
 
+	tx_queue = priv->tx_queue;
+	rx_queue = priv->rx_queue;
+
 	if (dev->flags & IFF_UP) {
 		/* Halt TX and RX, and process the frames which
 		 * have already been received */
-		spin_lock_irqsave(&priv->txlock, flags);
-		spin_lock(&priv->rxlock);
+		spin_lock_irqsave(&tx_queue->txlock, flags);
+		spin_lock(&rx_queue->rxlock);
 
 		gfar_halt(dev);
 
-		spin_unlock(&priv->rxlock);
-		spin_unlock_irqrestore(&priv->txlock, flags);
+		spin_unlock(&rx_queue->rxlock);
+		spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
-		gfar_clean_rx_ring(dev, priv->rx_ring_size);
+		gfar_clean_rx_ring(rx_queue, rx_queue->rx_ring_size);
 
 		/* Now we take down the rings to rebuild them */
 		stop_gfar(dev);
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index dd26da7..9c664f8 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -8,8 +8,9 @@
  *
  * Author: Andy Fleming
  * Maintainer: Kumar Gala (galak@kernel.crashing.org)
+ * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright (c) 2002-2005 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -49,6 +50,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 				 const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	int new_setting = 0;
 	u32 temp;
 	unsigned long flags;
@@ -56,6 +58,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING))
 		return count;
 
+	rx_queue = priv->rx_queue;
+
 	/* Find out the new setting */
 	if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
 		new_setting = 1;
@@ -65,7 +69,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 	else
 		return count;
 
-	spin_lock_irqsave(&priv->rxlock, flags);
+	spin_lock_irqsave(&rx_queue->rxlock, flags);
 
 	/* Set the new stashing value */
 	priv->bd_stash_en = new_setting;
@@ -79,7 +83,7 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 
 	gfar_write(&priv->regs->attr, temp);
 
-	spin_unlock_irqrestore(&priv->rxlock, flags);
+	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
 
 	return count;
 }
@@ -99,6 +103,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 				      const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -106,7 +111,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
 		return count;
 
-	spin_lock_irqsave(&priv->rxlock, flags);
+	rx_queue = priv->rx_queue;
+
+	spin_lock_irqsave(&rx_queue->rxlock, flags);
 	if (length > priv->rx_buffer_size)
 		goto out;
 
@@ -131,7 +138,7 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 	gfar_write(&priv->regs->attr, temp);
 
 out:
-	spin_unlock_irqrestore(&priv->rxlock, flags);
+	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
 
 	return count;
 }
@@ -154,6 +161,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 				       const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar_priv_rx_q *rx_queue = NULL;
 	unsigned short index = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -161,7 +169,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
 		return count;
 
-	spin_lock_irqsave(&priv->rxlock, flags);
+	rx_queue = priv->rx_queue;
+
+	spin_lock_irqsave(&rx_queue->rxlock, flags);
 	if (index > priv->rx_stash_size)
 		goto out;
 
@@ -176,7 +186,7 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 	gfar_write(&priv->regs->attreli, flags);
 
 out:
-	spin_unlock_irqrestore(&priv->rxlock, flags);
+	spin_unlock_irqrestore(&rx_queue->rxlock, flags);
 
 	return count;
 }
@@ -198,6 +208,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 				       const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int length = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -205,7 +216,9 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 	if (length > GFAR_MAX_FIFO_THRESHOLD)
 		return count;
 
-	spin_lock_irqsave(&priv->txlock, flags);
+	tx_queue = priv->tx_queue;
+
+	spin_lock_irqsave(&tx_queue->txlock, flags);
 
 	priv->fifo_threshold = length;
 
@@ -214,7 +227,7 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 	temp |= length;
 	gfar_write(&priv->regs->fifo_tx_thr, temp);
 
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
 	return count;
 }
@@ -235,6 +248,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 				    const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -242,7 +256,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 	if (num > GFAR_MAX_FIFO_STARVE)
 		return count;
 
-	spin_lock_irqsave(&priv->txlock, flags);
+	tx_queue = priv->tx_queue;
+	spin_lock_irqsave(&tx_queue->txlock, flags);
 
 	priv->fifo_starve = num;
 
@@ -251,7 +266,7 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 	temp |= num;
 	gfar_write(&priv->regs->fifo_tx_starve, temp);
 
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
 	return count;
 }
@@ -273,6 +288,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 					const char *buf, size_t count)
 {
 	struct gfar_private *priv = netdev_priv(to_net_dev(dev));
+	struct gfar_priv_tx_q *tx_queue = NULL;
 	unsigned int num = simple_strtoul(buf, NULL, 0);
 	u32 temp;
 	unsigned long flags;
@@ -280,7 +296,8 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 	if (num > GFAR_MAX_FIFO_STARVE_OFF)
 		return count;
 
-	spin_lock_irqsave(&priv->txlock, flags);
+	tx_queue = priv->tx_queue;
+	spin_lock_irqsave(&tx_queue->txlock, flags);
 
 	priv->fifo_starve_off = num;
 
@@ -289,7 +306,7 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 	temp |= num;
 	gfar_write(&priv->regs->fifo_tx_starve_shutoff, temp);
 
-	spin_unlock_irqrestore(&priv->txlock, flags);
+	spin_unlock_irqrestore(&tx_queue->txlock, flags);
 
 	return count;
 }
-- 
1.5.2.2


^ permalink raw reply related

* Re: [PATCH next-next-2.6] netdev: better dev_name_hash
From: Eric Dumazet @ 2009-10-26 14:55 UTC (permalink / raw)
  To: Octavian Purdila; +Cc: Krishna Kumar2, Hagen Paul Pfeifer, netdev
In-Reply-To: <200910261631.44666.opurdila@ixiacom.com>

Octavian Purdila a écrit :
> On Monday 26 October 2009 15:07:31 you wrote:
>> Eric Dumazet wrote on 10/26/2009 10:58:34 AM:
>>> In fact, new10 should be the 'perfect' hash for the "eth%d"
>>> netdev use, not jhash (way more expensive in cpu cycles BTW)
>>>
>>> Most linux machines in the world have less than 10 interfaces, jhash
>>> would be really overkill.
>>>
>>>
>>> Thanks
>>>
>>>
>>> [PATCH net-next-2.6] netdev: better dev_name_hash
>> Changing Eric's test program to pass a multiplier to string_hash()
>> and calling string_hash with multipler=<2 - 63> confirms that 10
>> is almost always the best number for varying netdev names. I print
>> the number of times perfect 64 was scored, and for most passed
>> device names, the best is for n=10, followed by n=5 and others.
>> Almost the worst was n=31, slightly better was n=17.
>>
>> But other variables matter too, like fewer entries (4K or 1K) but
>> above values for are still better compared to n=31.
>>
> 
> Hmm, I've found out that it very much depends on the name as well:
> 
> 0 - orig, 1 - jhash, 2 - new10, 3 - new17, 4 - new31
> 
> $ ./dev_name_hash ixint 16000 0 16
> score 24741
> $ ./dev_name_hash ixint 16000 1 16
> score 17949
> $ ./dev_name_hash ixint 16000 2 16
> score 16000
> $ ./dev_name_hash ixint 16000 3 16
> score 16715
> $ ./dev_name_hash ixint 16000 4 16
> score 18125
> 
> 
> $ ./dev_name_hash ixunc 16000 0 16
> score 24741
> $ ./dev_name_hash ixunc 16000 1 16
> score 17904
> $ ./dev_name_hash ixunc 16000 2 16
> score 22180
> $ ./dev_name_hash ixunc 16000 3 16
> score 17065

> $ ./dev_name_hash ixunc 16000 4 16
> score 18038

This is because you chose a 65536 slots hash table, to store 16000 elements

The ideal function should be :

$ ./dev_name_hash ixunc 16000 5 16
score 16000

unsigned int dev_name_hash_new10bis(const char *name)
{
	unsigned hash = 0;
	int len = strnlen(name, IFNAMSIZ);
	int i;

	for (i = 0; i < len; ++i)
		hash = 10 * hash + (name[i] - '0');
	return hash;
}

But should we really care ?



^ permalink raw reply

* RE: [PATCH net-next] bnx2x: Do Tx handling in a separate tasklet.
From: Vladislav Zolotarov @ 2009-10-26 14:42 UTC (permalink / raw)
  To: David Miller; +Cc: Eilon Greenstein, netdev@vger.kernel.org
In-Reply-To: <20091025.142059.175260055.davem@davemloft.net>

The separation of Tx and Rx interrupt handling gives us the possibility to properly affinitize the Rx (heavy CPU consuming task) and Tx (low CPU consuming task) and to ensure that Tx work is done not long after the Tx interrupt without interference of Rx work thus letting the user benefit from Tx coalescing configuration in order to achieve the best performance in each specific scenario. This is most important in heavy load scenarios with mixed traffic (UDP + TCP for instance). If we didn't separate Tx and Rx interrupt handling Tx coalescing configuration was not worth much.

The mentioned above lead us to conclusion that it's more efficient not to use NAPI for freeing Tx buffers but to use a separate tasklet instead.

Best regards,
vlad

-----Original Message-----
From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org] On Behalf Of David Miller
Sent: Sunday, October 25, 2009 11:21 PM
To: Vladislav Zolotarov
Cc: Eilon Greenstein; netdev@vger.kernel.org
Subject: Re: [PATCH net-next] bnx2x: Do Tx handling in a separate tasklet.

From: "Vladislav Zolotarov" <vladz@broadcom.com>
Date: Sun, 25 Oct 2009 14:19:42 +0200

> This patch moves the 'Tx interrupt work' of each Tx queue from the hardIRQ
> context to the separate low-latency tasklet. Otherwise there is a possibility
> of a software lockup situation in a Tx softIRQ as it handles freeing all skb's
> 'freed' in (hard)IRQ context.
> 
> Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com>
> Signed-off-by: Eilon Greenstein <eilong@broadcom.com>

Use NAPI, please...
--
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

* Re: [PATCH next-next-2.6] netdev: better dev_name_hash
From: Octavian Purdila @ 2009-10-26 14:31 UTC (permalink / raw)
  To: Krishna Kumar2; +Cc: Eric Dumazet, Hagen Paul Pfeifer, netdev
In-Reply-To: <OF703F980D.0971407E-ON6525765B.00458CCA-6525765B.00481976@in.ibm.com>

On Monday 26 October 2009 15:07:31 you wrote:
> Eric Dumazet wrote on 10/26/2009 10:58:34 AM:
> > In fact, new10 should be the 'perfect' hash for the "eth%d"
> > netdev use, not jhash (way more expensive in cpu cycles BTW)
> >
> > Most linux machines in the world have less than 10 interfaces, jhash
> > would be really overkill.
> >
> >
> > Thanks
> >
> >
> > [PATCH net-next-2.6] netdev: better dev_name_hash
> 
> Changing Eric's test program to pass a multiplier to string_hash()
> and calling string_hash with multipler=<2 - 63> confirms that 10
> is almost always the best number for varying netdev names. I print
> the number of times perfect 64 was scored, and for most passed
> device names, the best is for n=10, followed by n=5 and others.
> Almost the worst was n=31, slightly better was n=17.
> 
> But other variables matter too, like fewer entries (4K or 1K) but
> above values for are still better compared to n=31.
> 

Hmm, I've found out that it very much depends on the name as well:

0 - orig, 1 - jhash, 2 - new10, 3 - new17, 4 - new31

$ ./dev_name_hash ixint 16000 0 16
score 24741
$ ./dev_name_hash ixint 16000 1 16
score 17949
$ ./dev_name_hash ixint 16000 2 16
score 16000
$ ./dev_name_hash ixint 16000 3 16
score 16715
$ ./dev_name_hash ixint 16000 4 16
score 18125


$ ./dev_name_hash ixunc 16000 0 16
score 24741
$ ./dev_name_hash ixunc 16000 1 16
score 17904
$ ./dev_name_hash ixunc 16000 2 16
score 22180
$ ./dev_name_hash ixunc 16000 3 16
score 17065
$ ./dev_name_hash ixunc 16000 4 16
score 18038

^ permalink raw reply

* Re: Increasing TCP initial cwnd
From: Ilpo Järvinen @ 2009-10-26 13:57 UTC (permalink / raw)
  To: Yair Gottdenker; +Cc: Netdev
In-Reply-To: <alpine.DEB.2.00.0910261553180.19761@wel-95.cs.helsinki.fi>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1127 bytes --]

On Mon, 26 Oct 2009, Ilpo Järvinen wrote:

> On Mon, 26 Oct 2009, Yair Gottdenker wrote:
> 
> > I am working on research project to control the sender initial
> > congestion window size. I am trying to allow user space to set the
> > initial congestion window size but with no luck. The sender always
> > sends just 4 packets disregarding from the snd_cwnd.
> > 
> > I am working on kernel version 2.6.31.3.
> > 
> > I made the following changes:
> > 1. tcp_ipv4.c -> in function tcp_v4_init_sock, changed from
> > tp->snd_cwnd = 2 to tp->snd_cwnd = user_space_initial_cwnd.
> > 2. tcp_output.c -> tcp_init_cwnd - to always return user_space_initial_cwnd.
> > 3. tcp_cong.c -> tcp_slow_start- to always return user_space_initial_cwnd.
> > 
> > Any help will be more than welcome.
> 
> How about trying tcp_init_metrics in tcp_input.c?

Also, now that I looked. I don't understand what interesting you find in 
tcp_slow_start to modify? That certainly has nothing to do with initial 
window. ....Then you also might want to play with RW but that 
is out-of-scope of your question, just mentioning it for completeleness.

-- 
 i.

^ permalink raw reply

* Re: Increasing TCP initial cwnd
From: Ilpo Järvinen @ 2009-10-26 13:54 UTC (permalink / raw)
  To: Yair Gottdenker; +Cc: Netdev
In-Reply-To: <fa3cddca0910260640s22d0396ey5fc51c51047bc2c@mail.gmail.com>

On Mon, 26 Oct 2009, Yair Gottdenker wrote:

> I am working on research project to control the sender initial
> congestion window size. I am trying to allow user space to set the
> initial congestion window size but with no luck. The sender always
> sends just 4 packets disregarding from the snd_cwnd.
> 
> I am working on kernel version 2.6.31.3.
> 
> I made the following changes:
> 1. tcp_ipv4.c -> in function tcp_v4_init_sock, changed from
> tp->snd_cwnd = 2 to tp->snd_cwnd = user_space_initial_cwnd.
> 2. tcp_output.c -> tcp_init_cwnd - to always return user_space_initial_cwnd.
> 3. tcp_cong.c -> tcp_slow_start- to always return user_space_initial_cwnd.
> 
> Any help will be more than welcome.

How about trying tcp_init_metrics in tcp_input.c?

-- 
 i.

^ 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