All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 20:38 ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li

These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature. 

Frank Li (3):
  net:fec: add enet-avb IP support
  ARM: Documentation: Update fec dts binding doc
  ARM: dts: imx6sx: add multi-queue support enet

Fugang Duan (8):
  net:fec: add enet refrence clock for i.MX 6SX chip
  net:fec: add enet AVB feature macro define for imx6sx
  net:fec: use multiqueue interface to allocate Ethernet device
  net:fec: add multiqueue support
  net:fec: Disable enet-avb MAC instead of reset MAC
  net:fec: Add fsl,imx6sx-fec  compatible strings
  net:fec: change FEC alignment to 64 bytes for ARM platform
  net:fec: remove unnessary memory copy for address alignment in .xmit()

 Documentation/devicetree/bindings/net/fsl-fec.txt |   6 +
 arch/arm/boot/dts/imx6sx.dtsi                     |   2 +
 drivers/net/ethernet/freescale/fec.h              | 151 +++-
 drivers/net/ethernet/freescale/fec_main.c         | 877 +++++++++++++++-------
 4 files changed, 750 insertions(+), 286 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 20:38 ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li

These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature. 

Frank Li (3):
  net:fec: add enet-avb IP support
  ARM: Documentation: Update fec dts binding doc
  ARM: dts: imx6sx: add multi-queue support enet

Fugang Duan (8):
  net:fec: add enet refrence clock for i.MX 6SX chip
  net:fec: add enet AVB feature macro define for imx6sx
  net:fec: use multiqueue interface to allocate Ethernet device
  net:fec: add multiqueue support
  net:fec: Disable enet-avb MAC instead of reset MAC
  net:fec: Add fsl,imx6sx-fec  compatible strings
  net:fec: change FEC alignment to 64 bytes for ARM platform
  net:fec: remove unnessary memory copy for address alignment in .xmit()

 Documentation/devicetree/bindings/net/fsl-fec.txt |   6 +
 arch/arm/boot/dts/imx6sx.dtsi                     |   2 +
 drivers/net/ethernet/freescale/fec.h              | 151 +++-
 drivers/net/ethernet/freescale/fec_main.c         | 877 +++++++++++++++-------
 4 files changed, 750 insertions(+), 286 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 01/11] net:fec: add enet refrence clock for i.MX 6SX chip
       [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2014-09-03 20:38     ` Frank Li
  2014-09-03 20:38     ` Frank Li
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

i.MX6sx enet has below clocks for user config:
clk_ipg: ipg_clk_s, ipg_clk_mac0_s, 66Mhz
clk_ahb: enet system clock, it is enet AXI clock for imx6sx.
	 For imx6sx, it alos is the clock source of interrupt coalescing.
	 The clock range: 200Mhz ~ 266Mhz.
clk_ref: refrence clock for tx and rx. For imx6sx enet RGMII mode,
	 the refrence clock is 125Mhz coming from internal PLL or external.
	 In i.MX6sx-arm2 board, the clock is from internal PLL.
	 clk_ref is optional, depends on board.
clk_enet_out: The clock can be output from internal PLL. It can supply 50Mhz
	 clock for phy. clk_enet_out is optional, depends on chip and board.
clk_ptp: 1588 ts clock. It is optional, depends on chip.

The patch add clk_ref to distiguish the different clocks.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec.h      |  1 +
 drivers/net/ethernet/freescale/fec_main.c | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ee41d98..635772b 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -272,6 +272,7 @@ struct fec_enet_private {
 
 	struct clk *clk_ipg;
 	struct clk *clk_ahb;
+	struct clk *clk_ref;
 	struct clk *clk_enet_out;
 	struct clk *clk_ptp;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 89355a7..c21ecff1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1621,6 +1621,11 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 			}
 			mutex_unlock(&fep->ptp_clk_mutex);
 		}
+		if (fep->clk_ref) {
+			ret = clk_prepare_enable(fep->clk_ref);
+			if (ret)
+				goto failed_clk_ref;
+		}
 	} else {
 		clk_disable_unprepare(fep->clk_ahb);
 		clk_disable_unprepare(fep->clk_ipg);
@@ -1632,9 +1637,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 			fep->ptp_clk_on = false;
 			mutex_unlock(&fep->ptp_clk_mutex);
 		}
+		if (fep->clk_ref)
+			clk_disable_unprepare(fep->clk_ref);
 	}
 
 	return 0;
+
+failed_clk_ref:
+	if (fep->clk_ref)
+		clk_disable_unprepare(fep->clk_ref);
 failed_clk_ptp:
 	if (fep->clk_enet_out)
 		clk_disable_unprepare(fep->clk_enet_out);
@@ -2637,6 +2648,12 @@ fec_probe(struct platform_device *pdev)
 
 	fep->ptp_clk_on = false;
 	mutex_init(&fep->ptp_clk_mutex);
+
+	/* clk_ref is optional, depends on board */
+	fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
+	if (IS_ERR(fep->clk_ref))
+		fep->clk_ref = NULL;
+
 	fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
 	fep->bufdesc_ex =
 		pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 01/11] net:fec: add enet refrence clock for i.MX 6SX chip
@ 2014-09-03 20:38     ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

i.MX6sx enet has below clocks for user config:
clk_ipg: ipg_clk_s, ipg_clk_mac0_s, 66Mhz
clk_ahb: enet system clock, it is enet AXI clock for imx6sx.
	 For imx6sx, it alos is the clock source of interrupt coalescing.
	 The clock range: 200Mhz ~ 266Mhz.
clk_ref: refrence clock for tx and rx. For imx6sx enet RGMII mode,
	 the refrence clock is 125Mhz coming from internal PLL or external.
	 In i.MX6sx-arm2 board, the clock is from internal PLL.
	 clk_ref is optional, depends on board.
clk_enet_out: The clock can be output from internal PLL. It can supply 50Mhz
	 clock for phy. clk_enet_out is optional, depends on chip and board.
clk_ptp: 1588 ts clock. It is optional, depends on chip.

The patch add clk_ref to distiguish the different clocks.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec.h      |  1 +
 drivers/net/ethernet/freescale/fec_main.c | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ee41d98..635772b 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -272,6 +272,7 @@ struct fec_enet_private {
 
 	struct clk *clk_ipg;
 	struct clk *clk_ahb;
+	struct clk *clk_ref;
 	struct clk *clk_enet_out;
 	struct clk *clk_ptp;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 89355a7..c21ecff1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1621,6 +1621,11 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 			}
 			mutex_unlock(&fep->ptp_clk_mutex);
 		}
+		if (fep->clk_ref) {
+			ret = clk_prepare_enable(fep->clk_ref);
+			if (ret)
+				goto failed_clk_ref;
+		}
 	} else {
 		clk_disable_unprepare(fep->clk_ahb);
 		clk_disable_unprepare(fep->clk_ipg);
@@ -1632,9 +1637,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 			fep->ptp_clk_on = false;
 			mutex_unlock(&fep->ptp_clk_mutex);
 		}
+		if (fep->clk_ref)
+			clk_disable_unprepare(fep->clk_ref);
 	}
 
 	return 0;
+
+failed_clk_ref:
+	if (fep->clk_ref)
+		clk_disable_unprepare(fep->clk_ref);
 failed_clk_ptp:
 	if (fep->clk_enet_out)
 		clk_disable_unprepare(fep->clk_enet_out);
@@ -2637,6 +2648,12 @@ fec_probe(struct platform_device *pdev)
 
 	fep->ptp_clk_on = false;
 	mutex_init(&fep->ptp_clk_mutex);
+
+	/* clk_ref is optional, depends on board */
+	fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
+	if (IS_ERR(fep->clk_ref))
+		fep->clk_ref = NULL;
+
 	fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
 	fep->bufdesc_ex =
 		pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 02/11] net:fec: add enet AVB feature macro define for imx6sx
       [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2014-09-03 20:38     ` Frank Li
  2014-09-03 20:38     ` Frank Li
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

Add enet AVB feature macro define for imx6sx.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c21ecff1..ee9f04f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -104,6 +104,16 @@ static void set_multicast_list(struct net_device *ndev);
  * ENET_TDAR[TDAR].
  */
 #define FEC_QUIRK_ERR006358            (1 << 7)
+/* ENET IP hw AVB
+ *
+ * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support.
+ * - Two class indicators on receive with configurable priority
+ * - Two class indicators and line speed timer on transmit allowing
+ *   implementation class credit based shapers externally
+ * - Additional DMA registers provisioned to allow managing up to 3
+ *   independent rings
+ */
+#define FEC_QUIRK_HAS_AVB		(1 << 8)
 
 static struct platform_device_id fec_devtype[] = {
 	{
@@ -128,6 +138,12 @@ static struct platform_device_id fec_devtype[] = {
 		.name = "mvf600-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC,
 	}, {
+		.name = "imx6sx-fec",
+		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
+				FEC_QUIRK_HAS_AVB,
+	}, {
 		/* sentinel */
 	}
 };
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 02/11] net:fec: add enet AVB feature macro define for imx6sx
@ 2014-09-03 20:38     ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

Add enet AVB feature macro define for imx6sx.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c21ecff1..ee9f04f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -104,6 +104,16 @@ static void set_multicast_list(struct net_device *ndev);
  * ENET_TDAR[TDAR].
  */
 #define FEC_QUIRK_ERR006358            (1 << 7)
+/* ENET IP hw AVB
+ *
+ * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support.
+ * - Two class indicators on receive with configurable priority
+ * - Two class indicators and line speed timer on transmit allowing
+ *   implementation class credit based shapers externally
+ * - Additional DMA registers provisioned to allow managing up to 3
+ *   independent rings
+ */
+#define FEC_QUIRK_HAS_AVB		(1 << 8)
 
 static struct platform_device_id fec_devtype[] = {
 	{
@@ -128,6 +138,12 @@ static struct platform_device_id fec_devtype[] = {
 		.name = "mvf600-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC,
 	}, {
+		.name = "imx6sx-fec",
+		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
+				FEC_QUIRK_HAS_AVB,
+	}, {
 		/* sentinel */
 	}
 };
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 03/11] net:fec: use multiqueue interface to allocate Ethernet device
  2014-09-03 20:38 ` Frank Li
@ 2014-09-03 20:38   ` Frank Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

Since i.MX6SX enet-AVB IP support multi queues, so use multi queues
interface to allocate and set up an Ethernet device.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec.h      |  9 ++++++
 drivers/net/ethernet/freescale/fec_main.c | 49 ++++++++++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 635772b..f77ed6f 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -233,6 +233,13 @@ struct bufdesc_ex {
 /* This device has up to three irqs on some platforms */
 #define FEC_IRQ_NUM		3
 
+/* Maximum number of queues supported
+ * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
+ * User can point the queue number that is less than or equal to 3.
+ */
+#define FEC_ENET_MAX_TX_QS	3
+#define FEC_ENET_MAX_RX_QS	3
+
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it it best
  * to keep them that size.
@@ -278,6 +285,8 @@ struct fec_enet_private {
 
 	bool ptp_clk_on;
 	struct mutex ptp_clk_mutex;
+	int num_tx_queues;
+	int num_rx_queues;
 
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	unsigned char *tx_bounce[TX_RING_SIZE];
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index ee9f04f..00fcadd 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2573,6 +2573,39 @@ static void fec_reset_phy(struct platform_device *pdev)
 #endif /* CONFIG_OF */
 
 static int
+fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int err;
+
+	if (!np || !of_device_is_available(np))
+		return -ENODEV;
+
+	/* parse the num of tx and rx queues */
+	err = of_property_read_u32(np, "fsl,num_tx_queues", num_tx);
+	err |= of_property_read_u32(np, "fsl,num_rx_queues", num_rx);
+	if (err) {
+		*num_tx = 1;
+		*num_rx = 1;
+		return 0;
+	}
+
+	if (*num_tx < 1 || *num_tx > FEC_ENET_MAX_TX_QS) {
+		dev_err(&pdev->dev, "num_tx(=%d) greater than MAX_TX_QS(=%d)\n",
+			*num_tx, FEC_ENET_MAX_TX_QS);
+		return -EINVAL;
+	}
+
+	if (*num_rx < 1 || *num_rx > FEC_ENET_MAX_RX_QS) {
+		dev_err(&pdev->dev, "num_rx(=%d) greater than MAX_RX_QS(=%d)\n",
+			*num_rx, FEC_ENET_MAX_RX_QS);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 fec_probe(struct platform_device *pdev)
 {
 	struct fec_enet_private *fep;
@@ -2583,13 +2616,23 @@ fec_probe(struct platform_device *pdev)
 	const struct of_device_id *of_id;
 	static int dev_id;
 	struct device_node *np = pdev->dev.of_node, *phy_node;
+	int num_tx_qs = 1;
+	int num_rx_qs = 1;
 
 	of_id = of_match_device(fec_dt_ids, &pdev->dev);
 	if (of_id)
 		pdev->id_entry = of_id->data;
 
+	if (pdev->id_entry &&
+	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_AVB)) {
+		ret = fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
+		if (ret)
+			return ret;
+	}
+
 	/* Init network device */
-	ndev = alloc_etherdev(sizeof(struct fec_enet_private));
+	ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
+				  num_tx_qs, num_rx_qs);
 	if (!ndev)
 		return -ENOMEM;
 
@@ -2598,6 +2641,10 @@ fec_probe(struct platform_device *pdev)
 	/* setup board info structure */
 	fep = netdev_priv(ndev);
 
+	fep->num_rx_queues = num_rx_qs;
+	fep->num_tx_queues = num_tx_qs;
+	netif_set_real_num_rx_queues(ndev, num_rx_qs);
+
 #if !defined(CONFIG_M5272)
 	/* default enable pause frame auto negotiation */
 	if (pdev->id_entry &&
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 03/11] net:fec: use multiqueue interface to allocate Ethernet device
@ 2014-09-03 20:38   ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

Since i.MX6SX enet-AVB IP support multi queues, so use multi queues
interface to allocate and set up an Ethernet device.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec.h      |  9 ++++++
 drivers/net/ethernet/freescale/fec_main.c | 49 ++++++++++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 635772b..f77ed6f 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -233,6 +233,13 @@ struct bufdesc_ex {
 /* This device has up to three irqs on some platforms */
 #define FEC_IRQ_NUM		3
 
+/* Maximum number of queues supported
+ * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
+ * User can point the queue number that is less than or equal to 3.
+ */
+#define FEC_ENET_MAX_TX_QS	3
+#define FEC_ENET_MAX_RX_QS	3
+
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it it best
  * to keep them that size.
@@ -278,6 +285,8 @@ struct fec_enet_private {
 
 	bool ptp_clk_on;
 	struct mutex ptp_clk_mutex;
+	int num_tx_queues;
+	int num_rx_queues;
 
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	unsigned char *tx_bounce[TX_RING_SIZE];
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index ee9f04f..00fcadd 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2573,6 +2573,39 @@ static void fec_reset_phy(struct platform_device *pdev)
 #endif /* CONFIG_OF */
 
 static int
+fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int err;
+
+	if (!np || !of_device_is_available(np))
+		return -ENODEV;
+
+	/* parse the num of tx and rx queues */
+	err = of_property_read_u32(np, "fsl,num_tx_queues", num_tx);
+	err |= of_property_read_u32(np, "fsl,num_rx_queues", num_rx);
+	if (err) {
+		*num_tx = 1;
+		*num_rx = 1;
+		return 0;
+	}
+
+	if (*num_tx < 1 || *num_tx > FEC_ENET_MAX_TX_QS) {
+		dev_err(&pdev->dev, "num_tx(=%d) greater than MAX_TX_QS(=%d)\n",
+			*num_tx, FEC_ENET_MAX_TX_QS);
+		return -EINVAL;
+	}
+
+	if (*num_rx < 1 || *num_rx > FEC_ENET_MAX_RX_QS) {
+		dev_err(&pdev->dev, "num_rx(=%d) greater than MAX_RX_QS(=%d)\n",
+			*num_rx, FEC_ENET_MAX_RX_QS);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 fec_probe(struct platform_device *pdev)
 {
 	struct fec_enet_private *fep;
@@ -2583,13 +2616,23 @@ fec_probe(struct platform_device *pdev)
 	const struct of_device_id *of_id;
 	static int dev_id;
 	struct device_node *np = pdev->dev.of_node, *phy_node;
+	int num_tx_qs = 1;
+	int num_rx_qs = 1;
 
 	of_id = of_match_device(fec_dt_ids, &pdev->dev);
 	if (of_id)
 		pdev->id_entry = of_id->data;
 
+	if (pdev->id_entry &&
+	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_AVB)) {
+		ret = fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
+		if (ret)
+			return ret;
+	}
+
 	/* Init network device */
-	ndev = alloc_etherdev(sizeof(struct fec_enet_private));
+	ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
+				  num_tx_qs, num_rx_qs);
 	if (!ndev)
 		return -ENOMEM;
 
@@ -2598,6 +2641,10 @@ fec_probe(struct platform_device *pdev)
 	/* setup board info structure */
 	fep = netdev_priv(ndev);
 
+	fep->num_rx_queues = num_rx_qs;
+	fep->num_tx_queues = num_tx_qs;
+	netif_set_real_num_rx_queues(ndev, num_rx_qs);
+
 #if !defined(CONFIG_M5272)
 	/* default enable pause frame auto negotiation */
 	if (pdev->id_entry &&
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 04/11] net:fec: add multiqueue support
       [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2014-09-03 20:38     ` Frank Li
  2014-09-03 20:38     ` Frank Li
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

Add multiqueue support, which is compatible with previous single queue
driver for FEC/ENET IPs.

By default, the tx/rx queue number is 1, user can config the queue number
at DTS file like this:
	fsl,num_tx_queues=<3>;
	fsl,num_rx_queues=<3>;

Ethernet multiqueue mechanism can improve performance in SMP system.
For single hw queue, multiqueue can balance cpu loading.
For multi hw queues, multiple cores can process network packets in parallel,
and refer the article for the detail advantage for multiqueue:
http://vger.kernel.org/~davem/davem_nyc09.pdf

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <frank.li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec.h      | 108 ++++-
 drivers/net/ethernet/freescale/fec_main.c | 730 ++++++++++++++++++++----------
 2 files changed, 577 insertions(+), 261 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index f77ed6f..984eaf2 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -27,8 +27,8 @@
  */
 #define FEC_IEVENT		0x004 /* Interrupt event reg */
 #define FEC_IMASK		0x008 /* Interrupt mask reg */
-#define FEC_R_DES_ACTIVE	0x010 /* Receive descriptor reg */
-#define FEC_X_DES_ACTIVE	0x014 /* Transmit descriptor reg */
+#define FEC_R_DES_ACTIVE_0	0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE_0	0x014 /* Transmit descriptor reg */
 #define FEC_ECNTRL		0x024 /* Ethernet control reg */
 #define FEC_MII_DATA		0x040 /* MII manage frame reg */
 #define FEC_MII_SPEED		0x044 /* MII speed control reg */
@@ -45,14 +45,26 @@
 #define FEC_X_WMRK		0x144 /* FIFO transmit water mark */
 #define FEC_R_BOUND		0x14c /* FIFO receive bound reg */
 #define FEC_R_FSTART		0x150 /* FIFO receive start reg */
-#define FEC_R_DES_START		0x180 /* Receive descriptor ring */
-#define FEC_X_DES_START		0x184 /* Transmit descriptor ring */
+#define FEC_R_DES_START_1	0x160 /* Receive descriptor ring 1 */
+#define FEC_X_DES_START_1	0x164 /* Transmit descriptor ring 1 */
+#define FEC_R_DES_START_2	0x16c /* Receive descriptor ring 2 */
+#define FEC_X_DES_START_2	0x170 /* Transmit descriptor ring 2 */
+#define FEC_R_DES_START_0	0x180 /* Receive descriptor ring */
+#define FEC_X_DES_START_0	0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */
 #define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */
 #define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */
 #define FEC_R_FIFO_RAEM		0x198 /* Receive FIFO almost empty threshold */
 #define FEC_R_FIFO_RAFL		0x19c /* Receive FIFO almost full threshold */
 #define FEC_RACC		0x1C4 /* Receive Accelerator function */
+#define FEC_RCMR_1		0x1c8 /* Receive classification match ring 1 */
+#define FEC_RCMR_2		0x1cc /* Receive classification match ring 2 */
+#define FEC_DMA_CFG_1		0x1d8 /* DMA class configuration for ring 1 */
+#define FEC_DMA_CFG_2		0x1dc /* DMA class Configuration for ring 2 */
+#define FEC_R_DES_ACTIVE_1	0x1e0 /* Rx descriptor active for ring 1 */
+#define FEC_X_DES_ACTIVE_1	0x1e4 /* Tx descriptor active for ring 1 */
+#define FEC_R_DES_ACTIVE_2	0x1e8 /* Rx descriptor active for ring 2 */
+#define FEC_X_DES_ACTIVE_2	0x1ec /* Tx descriptor active for ring 2 */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -240,6 +252,36 @@ struct bufdesc_ex {
 #define FEC_ENET_MAX_TX_QS	3
 #define FEC_ENET_MAX_RX_QS	3
 
+#define FEC_R_DES_START(X)	((X == 1) ? FEC_R_DES_START_1 : \
+				((X == 2) ? \
+					FEC_R_DES_START_2 : FEC_R_DES_START_0))
+#define FEC_X_DES_START(X)	((X == 1) ? FEC_X_DES_START_1 : \
+				((X == 2) ? \
+					FEC_X_DES_START_2 : FEC_X_DES_START_0))
+#define FEC_R_DES_ACTIVE(X)	((X == 1) ? FEC_R_DES_ACTIVE_1 : \
+				((X == 2) ? \
+				   FEC_R_DES_ACTIVE_2 : FEC_R_DES_ACTIVE_0))
+#define FEC_X_DES_ACTIVE(X)	((X == 1) ? FEC_X_DES_ACTIVE_1 : \
+				((X == 2) ? \
+				   FEC_X_DES_ACTIVE_2 : FEC_X_DES_ACTIVE_0))
+
+#define FEC_DMA_CFG(X)		((X == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
+
+#define DMA_CLASS_EN		(1 << 16)
+#define FEC_RCMR(X)		((X == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
+#define IDLE_SLOPE_MASK		0xFFFF
+#define IDLE_SLOPE_1		0x200 /* BW fraction: 0.5 */
+#define IDLE_SLOPE_2		0x200 /* BW fraction: 0.5 */
+#define IDLE_SLOPE(X)		((X == 1) ? (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
+				(IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
+#define RCMR_MATCHEN            (0x1 << 16)
+#define RCMR_CMP_CFG(v, n)	((v & 0x7) <<  (n << 2))
+#define RCMR_CMP_1		(RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
+				RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
+#define RCMR_CMP_2		(RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
+				RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
+#define RCMR_CMP(X)		((X == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
+
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it it best
  * to keep them that size.
@@ -263,6 +305,35 @@ struct bufdesc_ex {
 #define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
+struct fec_enet_priv_tx_q {
+	int index;
+	unsigned char *tx_bounce[TX_RING_SIZE];
+	struct  sk_buff *tx_skbuff[TX_RING_SIZE];
+
+	dma_addr_t	bd_dma;
+	struct bufdesc	*tx_bd_base;
+	uint tx_ring_size;
+
+	unsigned short tx_stop_threshold;
+	unsigned short tx_wake_threshold;
+
+	struct bufdesc	*cur_tx;
+	struct bufdesc	*dirty_tx;
+	char *tso_hdrs;
+	dma_addr_t tso_hdrs_dma;
+};
+
+struct fec_enet_priv_rx_q {
+	int index;
+	struct  sk_buff *rx_skbuff[RX_RING_SIZE];
+
+	dma_addr_t	bd_dma;
+	struct bufdesc	*rx_bd_base;
+	uint rx_ring_size;
+
+	struct bufdesc	*cur_rx;
+};
+
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -289,29 +360,18 @@ struct fec_enet_private {
 	int num_rx_queues;
 
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	unsigned char *tx_bounce[TX_RING_SIZE];
-	struct	sk_buff *tx_skbuff[TX_RING_SIZE];
-	struct	sk_buff *rx_skbuff[RX_RING_SIZE];
+	struct fec_enet_priv_tx_q *tx_queue[FEC_ENET_MAX_TX_QS];
+	struct fec_enet_priv_rx_q *rx_queue[FEC_ENET_MAX_RX_QS];
 
-	/* CPM dual port RAM relative addresses */
-	dma_addr_t	bd_dma;
-	/* Address of Rx and Tx buffers */
-	struct bufdesc	*rx_bd_base;
-	struct bufdesc	*tx_bd_base;
-	/* The next free ring entry */
-	struct bufdesc	*cur_rx, *cur_tx;
-	/* The ring entries to be free()ed */
-	struct bufdesc	*dirty_tx;
+	unsigned int total_tx_ring_size;
+	unsigned int total_rx_ring_size;
 
-	unsigned short bufdesc_size;
-	unsigned short tx_ring_size;
-	unsigned short rx_ring_size;
-	unsigned short tx_stop_threshold;
-	unsigned short tx_wake_threshold;
+	unsigned long work_tx;
+	unsigned long work_rx;
+	unsigned long work_ts;
+	unsigned long work_mdio;
 
-	/* Software TSO */
-	char *tso_hdrs;
-	dma_addr_t tso_hdrs_dma;
+	unsigned short bufdesc_size;
 
 	struct	platform_device *pdev;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 00fcadd..f973a92 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -72,6 +72,8 @@ static void set_multicast_list(struct net_device *ndev);
 
 #define DRIVER_NAME	"fec"
 
+#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+
 /* Pause frame feild and FIFO threshold */
 #define FEC_ENET_FCE	(1 << 5)
 #define FEC_ENET_RSEM_V	0x84
@@ -258,22 +260,26 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 static int mii_cnt;
 
 static inline
-struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
+				      struct fec_enet_private *fep,
+				      int queue_id)
 {
 	struct bufdesc *new_bd = bdp + 1;
 	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1;
+	struct fec_enet_priv_tx_q *tx_queue = fep->tx_queue[queue_id];
+	struct fec_enet_priv_rx_q *rx_queue = fep->rx_queue[queue_id];
 	struct bufdesc_ex *ex_base;
 	struct bufdesc *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+	if (bdp >= tx_queue->tx_bd_base) {
+		base = tx_queue->tx_bd_base;
+		ring_size = tx_queue->tx_ring_size;
+		ex_base = (struct bufdesc_ex *)tx_queue->tx_bd_base;
 	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+		base = rx_queue->rx_bd_base;
+		ring_size = rx_queue->rx_ring_size;
+		ex_base = (struct bufdesc_ex *)rx_queue->rx_bd_base;
 	}
 
 	if (fep->bufdesc_ex)
@@ -285,22 +291,26 @@ struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_priva
 }
 
 static inline
-struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
+				      struct fec_enet_private *fep,
+				      int queue_id)
 {
 	struct bufdesc *new_bd = bdp - 1;
 	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1;
+	struct fec_enet_priv_tx_q *tx_queue = fep->tx_queue[queue_id];
+	struct fec_enet_priv_rx_q *rx_queue = fep->rx_queue[queue_id];
 	struct bufdesc_ex *ex_base;
 	struct bufdesc *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+	if (bdp >= tx_queue->tx_bd_base) {
+		base = tx_queue->tx_bd_base;
+		ring_size = tx_queue->tx_ring_size;
+		ex_base = (struct bufdesc_ex *)tx_queue->tx_bd_base;
 	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+		base = rx_queue->rx_bd_base;
+		ring_size = rx_queue->rx_ring_size;
+		ex_base = (struct bufdesc_ex *)rx_queue->rx_bd_base;
 	}
 
 	if (fep->bufdesc_ex)
@@ -316,14 +326,15 @@ static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp,
 	return ((const char *)bdp - (const char *)base) / fep->bufdesc_size;
 }
 
-static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep)
+static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep,
+					struct fec_enet_priv_tx_q *txq)
 {
 	int entries;
 
-	entries = ((const char *)fep->dirty_tx -
-			(const char *)fep->cur_tx) / fep->bufdesc_size - 1;
+	entries = ((const char *)txq->dirty_tx -
+			(const char *)txq->cur_tx) / fep->bufdesc_size - 1;
 
-	return entries > 0 ? entries : entries + fep->tx_ring_size;
+	return entries > 0 ? entries : entries + txq->tx_ring_size;
 }
 
 static void *swap_buffer(void *bufaddr, int len)
@@ -340,22 +351,30 @@ static void *swap_buffer(void *bufaddr, int len)
 static void fec_dump(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct bufdesc *bdp = fep->tx_bd_base;
-	unsigned int index = 0;
+	struct bufdesc *bdp;
+	struct fec_enet_priv_tx_q *txq;
+	int index = 0;
+	int i;
 
 	netdev_info(ndev, "TX ring dump\n");
 	pr_info("Nr     SC     addr       len  SKB\n");
 
-	do {
-		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
-			index,
-			bdp == fep->cur_tx ? 'S' : ' ',
-			bdp == fep->dirty_tx ? 'H' : ' ',
-			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
-			fep->tx_skbuff[index]);
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-		index++;
-	} while (bdp != fep->tx_bd_base);
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		txq = fep->tx_queue[i];
+		bdp = txq->tx_bd_base;
+		pr_info("Tx Queue %d\n", i);
+
+		do {
+			pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+				index,
+				bdp == txq->cur_tx ? 'S' : ' ',
+				bdp == txq->dirty_tx ? 'H' : ' ',
+				bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
+				txq->tx_skbuff[index]);
+			bdp = fec_enet_get_nextdesc(bdp, fep, i);
+			index++;
+		} while (bdp != txq->tx_bd_base);
+	}
 }
 
 static inline bool is_ipv4_pkt(struct sk_buff *skb)
@@ -381,14 +400,17 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 }
 
 static int
-fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
+fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
+			     struct sk_buff *skb,
+			     struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *bdp = fep->cur_tx;
+	struct bufdesc *bdp = txq->cur_tx;
 	struct bufdesc_ex *ebdp;
 	int nr_frags = skb_shinfo(skb)->nr_frags;
+	unsigned short queue = skb_get_queue_mapping(skb);
 	int frag, frag_len;
 	unsigned short status;
 	unsigned int estatus = 0;
@@ -400,7 +422,7 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 
 	for (frag = 0; frag < nr_frags; frag++) {
 		this_frag = &skb_shinfo(skb)->frags[frag];
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 		ebdp = (struct bufdesc_ex *)bdp;
 
 		status = bdp->cbd_sc;
@@ -428,11 +450,11 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 
 		bufaddr = page_address(this_frag->page.p) + this_frag->page_offset;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 		if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 			id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-			memcpy(fep->tx_bounce[index], bufaddr, frag_len);
-			bufaddr = fep->tx_bounce[index];
+			memcpy(txq->tx_bounce[index], bufaddr, frag_len);
+			bufaddr = txq->tx_bounce[index];
 
 			if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 				swap_buffer(bufaddr, frag_len);
@@ -452,21 +474,22 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 		bdp->cbd_sc = status;
 	}
 
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	return 0;
 
 dma_mapping_error:
-	bdp = fep->cur_tx;
+	bdp = txq->cur_tx;
 	for (i = 0; i < frag; i++) {
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 				bdp->cbd_datlen, DMA_TO_DEVICE);
 	}
 	return NETDEV_TX_OK;
 }
 
-static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
+				   struct sk_buff *skb, struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -477,12 +500,13 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	dma_addr_t addr;
 	unsigned short status;
 	unsigned short buflen;
+	unsigned short queue;
 	unsigned int estatus = 0;
 	unsigned int index;
 	int entries_free;
 	int ret;
 
-	entries_free = fec_enet_get_free_txdesc_num(fep);
+	entries_free = fec_enet_get_free_txdesc_num(fep, txq);
 	if (entries_free < MAX_SKB_FRAGS + 1) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
@@ -497,7 +521,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	/* Fill in a Tx ring entry */
-	bdp = fep->cur_tx;
+	bdp = txq->cur_tx;
 	status = bdp->cbd_sc;
 	status &= ~BD_ENET_TX_STATS;
 
@@ -505,11 +529,12 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	bufaddr = skb->data;
 	buflen = skb_headlen(skb);
 
-	index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+	queue = skb_get_queue_mapping(skb);
+	index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], skb->data, buflen);
-		bufaddr = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], skb->data, buflen);
+		bufaddr = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(bufaddr, buflen);
@@ -525,7 +550,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	if (nr_frags) {
-		ret = fec_enet_txq_submit_frag_skb(skb, ndev);
+		ret = fec_enet_txq_submit_frag_skb(txq, skb, ndev);
 		if (ret)
 			return ret;
 	} else {
@@ -553,10 +578,10 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 		ebdp->cbd_esc = estatus;
 	}
 
-	last_bdp = fep->cur_tx;
-	index = fec_enet_get_bd_index(fep->tx_bd_base, last_bdp, fep);
+	last_bdp = txq->cur_tx;
+	index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep);
 	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	txq->tx_skbuff[index] = skb;
 
 	bdp->cbd_datlen = buflen;
 	bdp->cbd_bufaddr = addr;
@@ -568,22 +593,23 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	bdp->cbd_sc = status;
 
 	/* If this was the last BD in the ring, start at the beginning again. */
-	bdp = fec_enet_get_nextdesc(last_bdp, fep);
+	bdp = fec_enet_get_nextdesc(last_bdp, fep, queue);
 
 	skb_tx_timestamp(skb);
 
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
 
 	return 0;
 }
 
 static int
-fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
-			struct bufdesc *bdp, int index, char *data,
-			int size, bool last_tcp, bool is_last)
+fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
+			  struct net_device *ndev,
+			  struct bufdesc *bdp, int index, char *data,
+			  int size, bool last_tcp, bool is_last)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -600,8 +626,8 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
 
 	if (((unsigned long) data) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], data, size);
-		data = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], data, size);
+		data = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(data, size);
@@ -640,8 +666,9 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
 }
 
 static int
-fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
-			struct bufdesc *bdp, int index)
+fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
+			 struct sk_buff *skb, struct net_device *ndev,
+			 struct bufdesc *bdp, int index)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -657,12 +684,12 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
 	status &= ~BD_ENET_TX_STATS;
 	status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
 
-	bufaddr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
-	dmabuf = fep->tso_hdrs_dma + index * TSO_HEADER_SIZE;
+	bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
+	dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], skb->data, hdr_len);
-		bufaddr = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], skb->data, hdr_len);
+		bufaddr = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(bufaddr, hdr_len);
@@ -692,17 +719,20 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
 	return 0;
 }
 
-static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
+				   struct sk_buff *skb,
+				   struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 	int total_len, data_left;
-	struct bufdesc *bdp = fep->cur_tx;
+	struct bufdesc *bdp = txq->cur_tx;
+	unsigned short queue = skb_get_queue_mapping(skb);
 	struct tso_t tso;
 	unsigned int index = 0;
 	int ret;
 
-	if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep)) {
+	if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
 			netdev_err(ndev, "NOT enough BD for TSO!\n");
@@ -722,14 +752,14 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 	while (total_len > 0) {
 		char *hdr;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 		data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
 		total_len -= data_left;
 
 		/* prepare packet headers: MAC + IP + TCP */
-		hdr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
+		hdr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
 		tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
-		ret = fec_enet_txq_put_hdr_tso(skb, ndev, bdp, index);
+		ret = fec_enet_txq_put_hdr_tso(txq, skb, ndev, bdp, index);
 		if (ret)
 			goto err_release;
 
@@ -737,10 +767,13 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 			int size;
 
 			size = min_t(int, tso.size, data_left);
-			bdp = fec_enet_get_nextdesc(bdp, fep);
-			index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
-			ret = fec_enet_txq_put_data_tso(skb, ndev, bdp, index, tso.data,
-							size, size == data_left,
+			bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+			index = fec_enet_get_bd_index(txq->tx_bd_base,
+						      bdp, fep);
+			ret = fec_enet_txq_put_data_tso(txq, skb, ndev,
+							bdp, index,
+							tso.data, size,
+							size == data_left,
 							total_len == 0);
 			if (ret)
 				goto err_release;
@@ -749,17 +782,17 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 			tso_build_data(skb, &tso, size);
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 	}
 
 	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	txq->tx_skbuff[index] = skb;
 
 	skb_tx_timestamp(skb);
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
 
 	return 0;
 
@@ -773,18 +806,25 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int entries_free;
+	unsigned short queue;
+	struct fec_enet_priv_tx_q *txq;
+	struct netdev_queue *nq;
 	int ret;
 
+	queue = skb_get_queue_mapping(skb);
+	txq = fep->tx_queue[queue];
+	nq = netdev_get_tx_queue(ndev, queue);
+
 	if (skb_is_gso(skb))
-		ret = fec_enet_txq_submit_tso(skb, ndev);
+		ret = fec_enet_txq_submit_tso(txq, skb, ndev);
 	else
-		ret = fec_enet_txq_submit_skb(skb, ndev);
+		ret = fec_enet_txq_submit_skb(txq, skb, ndev);
 	if (ret)
 		return ret;
 
-	entries_free = fec_enet_get_free_txdesc_num(fep);
-	if (entries_free <= fep->tx_stop_threshold)
-		netif_stop_queue(ndev);
+	entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+	if (entries_free <= txq->tx_stop_threshold)
+		netif_tx_stop_queue(nq);
 
 	return NETDEV_TX_OK;
 }
@@ -794,46 +834,101 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 static void fec_enet_bd_init(struct net_device *dev)
 {
 	struct fec_enet_private *fep = netdev_priv(dev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
 	struct bufdesc *bdp;
-	unsigned int i;
+	unsigned int i, j;
 
 	/* Initialize the receive buffer descriptors. */
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		rx_queue = fep->rx_queue[i];
+		bdp = rx_queue->rx_bd_base;
 
-		/* Initialize the BD for every fragment in the page. */
-		if (bdp->cbd_bufaddr)
-			bdp->cbd_sc = BD_ENET_RX_EMPTY;
-		else
-			bdp->cbd_sc = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-	}
+		for (j = 0; j < rx_queue->rx_ring_size; j++) {
 
-	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+			/* Initialize the BD for every fragment in the page. */
+			if (bdp->cbd_bufaddr)
+				bdp->cbd_sc = BD_ENET_RX_EMPTY;
+			else
+				bdp->cbd_sc = 0;
+			bdp = fec_enet_get_nextdesc(bdp, fep, i);
+		}
 
-	fep->cur_rx = fep->rx_bd_base;
+		/* Set the last buffer to wrap */
+		bdp = fec_enet_get_prevdesc(bdp, fep, i);
+		bdp->cbd_sc |= BD_SC_WRAP;
+
+		rx_queue->cur_rx = rx_queue->rx_bd_base;
+	}
 
 	/* ...and the same for transmit */
-	bdp = fep->tx_bd_base;
-	fep->cur_tx = bdp;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-
-		/* Initialize the BD for every fragment in the page. */
-		bdp->cbd_sc = 0;
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+		bdp = tx_queue->tx_bd_base;
+		tx_queue->cur_tx = bdp;
+
+		for (j = 0; j < tx_queue->tx_ring_size; j++) {
+			/* Initialize the BD for every fragment in the page. */
+			bdp->cbd_sc = 0;
+			if (tx_queue->tx_skbuff[j]) {
+				dev_kfree_skb_any(tx_queue->tx_skbuff[j]);
+				tx_queue->tx_skbuff[j] = NULL;
+			}
+			bdp->cbd_bufaddr = 0;
+			bdp = fec_enet_get_nextdesc(bdp, fep, i);
 		}
-		bdp->cbd_bufaddr = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+
+		/* Set the last buffer to wrap */
+		bdp = fec_enet_get_prevdesc(bdp, fep, i);
+		bdp->cbd_sc |= BD_SC_WRAP;
+		tx_queue->dirty_tx = bdp;
+	}
+}
+
+static inline void fec_enet_enable_ring(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
+	int i;
+
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		rx_queue = fep->rx_queue[i];
+		writel(rx_queue->bd_dma, fep->hwp + FEC_R_DES_START(i));
+
+		/* enable DMA1/2 */
+		if (i)
+			writel(RCMR_MATCHEN | RCMR_CMP(i),
+			       fep->hwp + FEC_RCMR(i));
 	}
 
-	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
-	fep->dirty_tx = bdp;
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+		writel(tx_queue->bd_dma, fep->hwp + FEC_X_DES_START(i));
+
+		/* enable DMA1/2 */
+		if (i)
+			writel(DMA_CLASS_EN | IDLE_SLOPE(i),
+			       fep->hwp + FEC_DMA_CFG(i));
+	}
+}
+
+static void fec_enet_reset_skb(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	int i, j;
+
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+
+		for (j = 0; j < tx_queue->tx_ring_size; j++) {
+			if (tx_queue->tx_skbuff[j]) {
+				dev_kfree_skb_any(tx_queue->tx_skbuff[j]);
+				tx_queue->tx_skbuff[j] = NULL;
+			}
+		}
+	}
 }
 
 /*
@@ -847,11 +942,11 @@ fec_restart(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	int i;
 	u32 val;
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
+	int i;
 
 	/* Whack a reset.  We should wait for this. */
 	writel(1, fep->hwp + FEC_ECNTRL);
@@ -876,21 +971,10 @@ fec_restart(struct net_device *ndev)
 	fec_enet_bd_init(ndev);
 
 	/* Set receive and transmit descriptor base. */
-	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
-	if (fep->bufdesc_ex)
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
-			* fep->rx_ring_size, fep->hwp + FEC_X_DES_START);
-	else
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
-			* fep->rx_ring_size,	fep->hwp + FEC_X_DES_START);
-
+	fec_enet_enable_ring(ndev);
 
-	for (i = 0; i <= TX_RING_MOD_MASK; i++) {
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
-		}
-	}
+	/* Reset tx SKB buffers. */
+	fec_enet_reset_skb(ndev);
 
 	/* Enable MII mode */
 	if (fep->full_duplex == DUPLEX_FULL) {
@@ -1012,7 +1096,8 @@ fec_restart(struct net_device *ndev)
 
 	/* And last, enable the transmit and receive processing */
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
-	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+	for (i = 0; i < fep->num_rx_queues; i++)
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
 
 	if (fep->bufdesc_ex)
 		fec_ptp_start_cyclecounter(ndev);
@@ -1097,37 +1182,45 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
 }
 
 static void
-fec_enet_tx(struct net_device *ndev)
+fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
 {
 	struct	fec_enet_private *fep;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
+	struct fec_enet_priv_tx_q *txq;
+	struct netdev_queue *nq;
 	int	index = 0;
 	int	entries_free;
 
 	fep = netdev_priv(ndev);
-	bdp = fep->dirty_tx;
 
+	queue_id = FEC_ENET_GET_QUQUE(queue_id);
+
+	txq = fep->tx_queue[queue_id];
 	/* get next bdp of dirty_tx */
-	bdp = fec_enet_get_nextdesc(bdp, fep);
+	nq = netdev_get_tx_queue(ndev, queue_id);
+	bdp = txq->dirty_tx;
+
+	/* get next bdp of dirty_tx */
+	bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
 
 		/* current queue is empty */
-		if (bdp == fep->cur_tx)
+		if (bdp == txq->cur_tx)
 			break;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 
-		skb = fep->tx_skbuff[index];
-		fep->tx_skbuff[index] = NULL;
-		if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
+		skb = txq->tx_skbuff[index];
+		txq->tx_skbuff[index] = NULL;
+		if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
 			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 					bdp->cbd_datlen, DMA_TO_DEVICE);
 		bdp->cbd_bufaddr = 0;
 		if (!skb) {
-			bdp = fec_enet_get_nextdesc(bdp, fep);
+			bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 			continue;
 		}
 
@@ -1169,23 +1262,37 @@ fec_enet_tx(struct net_device *ndev)
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
 
-		fep->dirty_tx = bdp;
+		txq->dirty_tx = bdp;
 
 		/* Update pointer to next buffer descriptor to be transmitted */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 		/* Since we have freed up a buffer, the ring is no longer full
 		 */
 		if (netif_queue_stopped(ndev)) {
-			entries_free = fec_enet_get_free_txdesc_num(fep);
-			if (entries_free >= fep->tx_wake_threshold)
-				netif_wake_queue(ndev);
+			entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+			if (entries_free >= txq->tx_wake_threshold)
+				netif_tx_wake_queue(nq);
 		}
 	}
 
 	/* ERR006538: Keep the transmitter going */
-	if (bdp != fep->cur_tx && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
-		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	if (bdp != txq->cur_tx &&
+	    readl(fep->hwp + FEC_X_DES_ACTIVE(queue_id)) == 0)
+		writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue_id));
+}
+
+static void
+fec_enet_tx(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	u16 queue_id;
+	/* First process class A queue, then Class B and Best Effort queue */
+	for_each_set_bit(queue_id, &fep->work_tx, FEC_ENET_MAX_TX_QS) {
+		clear_bit(queue_id, &fep->work_tx);
+		fec_enet_tx_queue(ndev, queue_id);
+	}
+	return;
 }
 
 /* During a receive, the cur_rx points to the current incoming buffer.
@@ -1194,11 +1301,12 @@ fec_enet_tx(struct net_device *ndev)
  * effectively tossing the packet.
  */
 static int
-fec_enet_rx(struct net_device *ndev, int budget)
+fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
+	struct fec_enet_priv_rx_q *rxq;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
@@ -1213,11 +1321,13 @@ fec_enet_rx(struct net_device *ndev, int budget)
 #ifdef CONFIG_M532x
 	flush_cache_all();
 #endif
+	queue_id = FEC_ENET_GET_QUQUE(queue_id);
+	rxq = fep->rx_queue[queue_id];
 
 	/* First, grab all of the stats for the incoming packet.
 	 * These get messed up if we get called due to a busy condition.
 	 */
-	bdp = fep->cur_rx;
+	bdp = rxq->cur_rx;
 
 	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
@@ -1231,7 +1341,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		if ((status & BD_ENET_RX_LAST) == 0)
 			netdev_err(ndev, "rcv is not +last\n");
 
-		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
 
 		/* Check for errors. */
 		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
@@ -1264,8 +1373,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		pkt_len = bdp->cbd_datlen;
 		ndev->stats.rx_bytes += pkt_len;
 
-		index = fec_enet_get_bd_index(fep->rx_bd_base, bdp, fep);
-		data = fep->rx_skbuff[index]->data;
+		index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep);
+		data = rxq->rx_skbuff[index]->data;
 		dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 
@@ -1280,7 +1389,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
 		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-		    fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
+			fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1308,7 +1417,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN));
 			if (vlan_packet_rcvd)
 				payload_offset = (2 * ETH_ALEN) + VLAN_HLEN;
-			skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
+				skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
 						       data + payload_offset,
 						       pkt_len - 4 - (2 * ETH_ALEN));
 
@@ -1357,19 +1466,48 @@ rx_processing_done:
 		}
 
 		/* Update BD pointer to next entry */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 		/* Doing this here will keep the FEC running while we process
 		 * incoming frames.  On a heavily loaded network, we should be
 		 * able to keep up at the expense of system resources.
 		 */
-		writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(queue_id));
 	}
-	fep->cur_rx = bdp;
+	rxq->cur_rx = bdp;
+	return pkt_received;
+}
 
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
+{
+	int     pkt_received = 0;
+	u16	queue_id;
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) {
+		clear_bit(queue_id, &fep->work_rx);
+		pkt_received += fec_enet_rx_queue(ndev,
+					budget - pkt_received, queue_id);
+	}
 	return pkt_received;
 }
 
+static bool
+fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
+{
+	if (int_events == 0)
+		return false;
+
+	if (int_events & FEC_ENET_RXF)
+		fep->work_rx |= (1 << 2);
+
+	if (int_events & FEC_ENET_TXF)
+		fep->work_tx |= (1 << 2);
+
+	return true;
+}
+
 static irqreturn_t
 fec_enet_interrupt(int irq, void *dev_id)
 {
@@ -1381,6 +1519,7 @@ fec_enet_interrupt(int irq, void *dev_id)
 
 	int_events = readl(fep->hwp + FEC_IEVENT);
 	writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT);
+	fec_enet_collect_events(fep, int_events);
 
 	if (int_events & napi_mask) {
 		ret = IRQ_HANDLED;
@@ -2129,93 +2268,117 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 static void fec_enet_free_buffers(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	unsigned int i;
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
+	unsigned int i, j;
 	struct sk_buff *skb;
 	struct bufdesc	*bdp;
 
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
-		skb = fep->rx_skbuff[i];
-		fep->rx_skbuff[i] = NULL;
-		if (skb) {
-			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
-					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
-			dev_kfree_skb(skb);
+	for (j = 0; j < fep->num_rx_queues; j++) {
+		rx_queue = fep->rx_queue[j];
+		bdp = rx_queue->rx_bd_base;
+		for (i = 0; i < rx_queue->rx_ring_size; i++) {
+			skb = rx_queue->rx_skbuff[i];
+			rx_queue->rx_skbuff[i] = NULL;
+			if (skb) {
+				dma_unmap_single(&fep->pdev->dev,
+						 bdp->cbd_bufaddr,
+						 FEC_ENET_RX_FRSIZE,
+						 DMA_FROM_DEVICE);
+				dev_kfree_skb(skb);
+			}
+			bdp = fec_enet_get_nextdesc(bdp, fep, j);
 		}
-		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
-	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-		kfree(fep->tx_bounce[i]);
-		fep->tx_bounce[i] = NULL;
-		skb = fep->tx_skbuff[i];
-		fep->tx_skbuff[i] = NULL;
-		dev_kfree_skb(skb);
+	for (j = 0; j < fep->num_tx_queues; j++) {
+		tx_queue = fep->tx_queue[j];
+		bdp = tx_queue->tx_bd_base;
+		for (i = 0; i < tx_queue->tx_ring_size; i++) {
+			kfree(tx_queue->tx_bounce[i]);
+			tx_queue->tx_bounce[i] = NULL;
+			skb = tx_queue->tx_skbuff[i];
+			tx_queue->tx_skbuff[i] = NULL;
+			dev_kfree_skb(skb);
+		}
 	}
 }
 
 static int fec_enet_alloc_buffers(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	unsigned int i;
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
+	unsigned int i, j;
 	struct sk_buff *skb;
 	struct bufdesc	*bdp;
 
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
-		dma_addr_t addr;
+	for (j = 0; j < fep->num_rx_queues; j++) {
+		rx_queue = fep->rx_queue[j];
+		bdp = rx_queue->rx_bd_base;
+		for (i = 0; i < rx_queue->rx_ring_size; i++) {
+			dma_addr_t addr;
+
+			skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
+			if (!skb)
+				goto err_alloc;
+
+			addr = dma_map_single(&fep->pdev->dev, skb->data,
+					      FEC_ENET_RX_FRSIZE,
+					      DMA_FROM_DEVICE);
+			if (dma_mapping_error(&fep->pdev->dev, addr)) {
+				dev_kfree_skb(skb);
+				if (net_ratelimit())
+					netdev_err(ndev, "Rx DMA memory map failed\n");
+				goto err_alloc;
+			}
 
-		skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
-		if (!skb)
-			goto err_alloc;
+			rx_queue->rx_skbuff[i] = skb;
+			bdp->cbd_bufaddr = addr;
+			bdp->cbd_sc = BD_ENET_RX_EMPTY;
 
-		addr = dma_map_single(&fep->pdev->dev, skb->data,
-				FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
-		if (dma_mapping_error(&fep->pdev->dev, addr)) {
-			dev_kfree_skb(skb);
-			if (net_ratelimit())
-				netdev_err(ndev, "Rx DMA memory map failed\n");
-			goto err_alloc;
-		}
+			if (fep->bufdesc_ex) {
+				struct bufdesc_ex *ebdp;
 
-		fep->rx_skbuff[i] = skb;
-		bdp->cbd_bufaddr = addr;
-		bdp->cbd_sc = BD_ENET_RX_EMPTY;
+				ebdp = (struct bufdesc_ex *)bdp;
+				ebdp->cbd_esc = BD_ENET_RX_INT;
+			}
 
-		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-			ebdp->cbd_esc = BD_ENET_RX_INT;
+			bdp = fec_enet_get_nextdesc(bdp, fep, j);
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		/* Set the last buffer to wrap. */
+		bdp = fec_enet_get_prevdesc(bdp, fep, j);
+		bdp->cbd_sc |= BD_SC_WRAP;
 	}
 
-	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+	for (j = 0; j < fep->num_tx_queues; j++) {
+		tx_queue = fep->tx_queue[j];
+		bdp = tx_queue->tx_bd_base;
 
-	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-		fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
-		if (!fep->tx_bounce[i])
-			goto err_alloc;
+		for (i = 0; i < tx_queue->tx_ring_size; i++) {
+			tx_queue->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE,
+							 GFP_KERNEL);
+			if (!tx_queue->tx_bounce[i])
+				goto err_alloc;
 
-		bdp->cbd_sc = 0;
-		bdp->cbd_bufaddr = 0;
+			bdp->cbd_sc = 0;
+			bdp->cbd_bufaddr = 0;
 
-		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-			ebdp->cbd_esc = BD_ENET_TX_INT;
-		}
+			if (fep->bufdesc_ex) {
+				struct bufdesc_ex *ebdp;
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-	}
+				ebdp = (struct bufdesc_ex *)bdp;
+				ebdp->cbd_esc = BD_ENET_TX_INT;
+			}
 
-	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+			bdp = fec_enet_get_nextdesc(bdp, fep, j);
+		}
 
+		/* Set the last buffer to wrap. */
+		bdp = fec_enet_get_prevdesc(bdp, fep, j);
+		bdp->cbd_sc |= BD_SC_WRAP;
+	}
 	return 0;
 
  err_alloc:
@@ -2252,7 +2415,8 @@ fec_enet_open(struct net_device *ndev)
 	fec_restart(ndev);
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
-	netif_start_queue(ndev);
+	netif_tx_start_all_queues(ndev);
+
 	return 0;
 }
 
@@ -2426,7 +2590,7 @@ static int fec_set_features(struct net_device *netdev,
 	/* Resume the device after updates */
 	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
 		fec_restart(netdev);
-		netif_wake_queue(netdev);
+		netif_tx_wake_all_queues(netdev);
 		netif_tx_unlock_bh(netdev);
 		napi_enable(&fep->napi);
 	}
@@ -2434,10 +2598,17 @@ static int fec_set_features(struct net_device *netdev,
 	return 0;
 }
 
+u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+			  void *accel_priv, select_queue_fallback_t fallback)
+{
+	return skb_tx_hash(ndev, skb);
+}
+
 static const struct net_device_ops fec_netdev_ops = {
 	.ndo_open		= fec_enet_open,
 	.ndo_stop		= fec_enet_close,
 	.ndo_start_xmit		= fec_enet_start_xmit,
+	.ndo_select_queue       = fec_enet_select_queue,
 	.ndo_set_rx_mode	= set_multicast_list,
 	.ndo_change_mtu		= eth_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -2450,6 +2621,76 @@ static const struct net_device_ops fec_netdev_ops = {
 	.ndo_set_features	= fec_set_features,
 };
 
+static void fec_enet_free_queue(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < fep->num_tx_queues; i++)
+		if (fep->tx_queue[i] && fep->tx_queue[i]->tso_hdrs)
+			dma_free_coherent(NULL,
+				fep->tx_queue[i]->tx_ring_size * TSO_HEADER_SIZE,
+				fep->tx_queue[i]->tso_hdrs,
+				fep->tx_queue[i]->tso_hdrs_dma);
+
+	for (i = 0; i < fep->num_rx_queues; i++)
+		if (fep->rx_queue[i])
+			kfree(fep->rx_queue[i]);
+
+	for (i = 0; i < fep->num_tx_queues; i++)
+		if (fep->tx_queue[i])
+			kfree(fep->tx_queue[i]);
+}
+
+static int fec_enet_alloc_queue(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i;
+	int ret = 0;
+	struct fec_enet_priv_tx_q *txq;
+
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+		if (!txq) {
+			ret = -ENOMEM;
+			goto alloc_failed;
+		}
+
+		fep->tx_queue[i] = txq;
+		txq->tx_ring_size = TX_RING_SIZE;
+		fep->total_tx_ring_size += fep->tx_queue[i]->tx_ring_size;
+
+		txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
+		txq->tx_wake_threshold =
+			(txq->tx_ring_size - txq->tx_stop_threshold) / 2;
+
+		txq->tso_hdrs = dma_alloc_coherent(NULL,
+					txq->tx_ring_size * TSO_HEADER_SIZE,
+					&txq->tso_hdrs_dma,
+					GFP_KERNEL);
+		if (!txq->tso_hdrs) {
+			ret = -ENOMEM;
+			goto alloc_failed;
+		}
+	}
+
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		fep->rx_queue[i] = kzalloc(sizeof(*fep->rx_queue[i]),
+				GFP_KERNEL);
+		if (!fep->rx_queue[i]) {
+			ret = -ENOMEM;
+			goto alloc_failed;
+		}
+
+		fep->rx_queue[i]->rx_ring_size = RX_RING_SIZE;
+		fep->total_rx_ring_size += fep->rx_queue[i]->rx_ring_size;
+	}
+	return ret;
+
+alloc_failed:
+	fec_enet_free_queue(ndev);
+	return ret;
+}
  /*
   * XXX:  We need to clean up on failure exits here.
   *
@@ -2459,37 +2700,60 @@ static int fec_enet_init(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
 	struct bufdesc *cbd_base;
+	dma_addr_t bd_dma;
 	int bd_size;
+	int i;
 
-	/* init the tx & rx ring size */
-	fep->tx_ring_size = TX_RING_SIZE;
-	fep->rx_ring_size = RX_RING_SIZE;
-
-	fep->tx_stop_threshold = FEC_MAX_SKB_DESCS;
-	fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2;
+	fec_enet_alloc_queue(ndev);
 
 	if (fep->bufdesc_ex)
 		fep->bufdesc_size = sizeof(struct bufdesc_ex);
 	else
 		fep->bufdesc_size = sizeof(struct bufdesc);
-	bd_size = (fep->tx_ring_size + fep->rx_ring_size) *
+	bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *
 			fep->bufdesc_size;
 
 	/* Allocate memory for buffer descriptors. */
-	cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma,
+	cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
 				      GFP_KERNEL);
 	if (!cbd_base)
 		return -ENOMEM;
 
-	fep->tso_hdrs = dma_alloc_coherent(NULL, fep->tx_ring_size * TSO_HEADER_SIZE,
-						&fep->tso_hdrs_dma, GFP_KERNEL);
-	if (!fep->tso_hdrs) {
-		dma_free_coherent(NULL, bd_size, cbd_base, fep->bd_dma);
-		return -ENOMEM;
+	memset(cbd_base, 0, bd_size);
+
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		rx_queue = fep->rx_queue[i];
+		rx_queue->index = i;
+		rx_queue->rx_bd_base = (struct bufdesc *)cbd_base;
+		rx_queue->bd_dma = bd_dma;
+		if (fep->bufdesc_ex) {
+			bd_dma += sizeof(struct bufdesc_ex) * rx_queue->rx_ring_size;
+			cbd_base = (struct bufdesc *)
+				(((struct bufdesc_ex *)cbd_base) + rx_queue->rx_ring_size);
+		} else {
+			bd_dma += sizeof(struct bufdesc) * rx_queue->rx_ring_size;
+			cbd_base += rx_queue->rx_ring_size;
+		}
+	}
+
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+		tx_queue->index = i;
+		tx_queue->tx_bd_base = (struct bufdesc *)cbd_base;
+		tx_queue->bd_dma = bd_dma;
+		if (fep->bufdesc_ex) {
+			bd_dma += sizeof(struct bufdesc_ex) * tx_queue->tx_ring_size;
+			cbd_base = (struct bufdesc *)
+			(((struct bufdesc_ex *)cbd_base) + tx_queue->tx_ring_size);
+		} else {
+			bd_dma += sizeof(struct bufdesc) * tx_queue->tx_ring_size;
+			cbd_base += tx_queue->tx_ring_size;
+		}
 	}
 
-	memset(cbd_base, 0, PAGE_SIZE);
 
 	fep->netdev = ndev;
 
@@ -2498,14 +2762,6 @@ static int fec_enet_init(struct net_device *ndev)
 	/* make sure MAC we just acquired is programmed into the hw */
 	fec_set_mac_address(ndev, NULL);
 
-	/* Set receive and transmit descriptor base. */
-	fep->rx_bd_base = cbd_base;
-	if (fep->bufdesc_ex)
-		fep->tx_bd_base = (struct bufdesc *)
-			(((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size);
-	else
-		fep->tx_bd_base = cbd_base + fep->rx_ring_size;
-
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
 	ndev->netdev_ops = &fec_netdev_ops;
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 04/11] net:fec: add multiqueue support
@ 2014-09-03 20:38     ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

Add multiqueue support, which is compatible with previous single queue
driver for FEC/ENET IPs.

By default, the tx/rx queue number is 1, user can config the queue number
at DTS file like this:
	fsl,num_tx_queues=<3>;
	fsl,num_rx_queues=<3>;

Ethernet multiqueue mechanism can improve performance in SMP system.
For single hw queue, multiqueue can balance cpu loading.
For multi hw queues, multiple cores can process network packets in parallel,
and refer the article for the detail advantage for multiqueue:
http://vger.kernel.org/~davem/davem_nyc09.pdf

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <frank.li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec.h      | 108 ++++-
 drivers/net/ethernet/freescale/fec_main.c | 730 ++++++++++++++++++++----------
 2 files changed, 577 insertions(+), 261 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index f77ed6f..984eaf2 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -27,8 +27,8 @@
  */
 #define FEC_IEVENT		0x004 /* Interrupt event reg */
 #define FEC_IMASK		0x008 /* Interrupt mask reg */
-#define FEC_R_DES_ACTIVE	0x010 /* Receive descriptor reg */
-#define FEC_X_DES_ACTIVE	0x014 /* Transmit descriptor reg */
+#define FEC_R_DES_ACTIVE_0	0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE_0	0x014 /* Transmit descriptor reg */
 #define FEC_ECNTRL		0x024 /* Ethernet control reg */
 #define FEC_MII_DATA		0x040 /* MII manage frame reg */
 #define FEC_MII_SPEED		0x044 /* MII speed control reg */
@@ -45,14 +45,26 @@
 #define FEC_X_WMRK		0x144 /* FIFO transmit water mark */
 #define FEC_R_BOUND		0x14c /* FIFO receive bound reg */
 #define FEC_R_FSTART		0x150 /* FIFO receive start reg */
-#define FEC_R_DES_START		0x180 /* Receive descriptor ring */
-#define FEC_X_DES_START		0x184 /* Transmit descriptor ring */
+#define FEC_R_DES_START_1	0x160 /* Receive descriptor ring 1 */
+#define FEC_X_DES_START_1	0x164 /* Transmit descriptor ring 1 */
+#define FEC_R_DES_START_2	0x16c /* Receive descriptor ring 2 */
+#define FEC_X_DES_START_2	0x170 /* Transmit descriptor ring 2 */
+#define FEC_R_DES_START_0	0x180 /* Receive descriptor ring */
+#define FEC_X_DES_START_0	0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */
 #define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */
 #define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */
 #define FEC_R_FIFO_RAEM		0x198 /* Receive FIFO almost empty threshold */
 #define FEC_R_FIFO_RAFL		0x19c /* Receive FIFO almost full threshold */
 #define FEC_RACC		0x1C4 /* Receive Accelerator function */
+#define FEC_RCMR_1		0x1c8 /* Receive classification match ring 1 */
+#define FEC_RCMR_2		0x1cc /* Receive classification match ring 2 */
+#define FEC_DMA_CFG_1		0x1d8 /* DMA class configuration for ring 1 */
+#define FEC_DMA_CFG_2		0x1dc /* DMA class Configuration for ring 2 */
+#define FEC_R_DES_ACTIVE_1	0x1e0 /* Rx descriptor active for ring 1 */
+#define FEC_X_DES_ACTIVE_1	0x1e4 /* Tx descriptor active for ring 1 */
+#define FEC_R_DES_ACTIVE_2	0x1e8 /* Rx descriptor active for ring 2 */
+#define FEC_X_DES_ACTIVE_2	0x1ec /* Tx descriptor active for ring 2 */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -240,6 +252,36 @@ struct bufdesc_ex {
 #define FEC_ENET_MAX_TX_QS	3
 #define FEC_ENET_MAX_RX_QS	3
 
+#define FEC_R_DES_START(X)	((X == 1) ? FEC_R_DES_START_1 : \
+				((X == 2) ? \
+					FEC_R_DES_START_2 : FEC_R_DES_START_0))
+#define FEC_X_DES_START(X)	((X == 1) ? FEC_X_DES_START_1 : \
+				((X == 2) ? \
+					FEC_X_DES_START_2 : FEC_X_DES_START_0))
+#define FEC_R_DES_ACTIVE(X)	((X == 1) ? FEC_R_DES_ACTIVE_1 : \
+				((X == 2) ? \
+				   FEC_R_DES_ACTIVE_2 : FEC_R_DES_ACTIVE_0))
+#define FEC_X_DES_ACTIVE(X)	((X == 1) ? FEC_X_DES_ACTIVE_1 : \
+				((X == 2) ? \
+				   FEC_X_DES_ACTIVE_2 : FEC_X_DES_ACTIVE_0))
+
+#define FEC_DMA_CFG(X)		((X == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
+
+#define DMA_CLASS_EN		(1 << 16)
+#define FEC_RCMR(X)		((X == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
+#define IDLE_SLOPE_MASK		0xFFFF
+#define IDLE_SLOPE_1		0x200 /* BW fraction: 0.5 */
+#define IDLE_SLOPE_2		0x200 /* BW fraction: 0.5 */
+#define IDLE_SLOPE(X)		((X == 1) ? (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
+				(IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
+#define RCMR_MATCHEN            (0x1 << 16)
+#define RCMR_CMP_CFG(v, n)	((v & 0x7) <<  (n << 2))
+#define RCMR_CMP_1		(RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
+				RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
+#define RCMR_CMP_2		(RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
+				RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
+#define RCMR_CMP(X)		((X == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
+
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it it best
  * to keep them that size.
@@ -263,6 +305,35 @@ struct bufdesc_ex {
 #define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
+struct fec_enet_priv_tx_q {
+	int index;
+	unsigned char *tx_bounce[TX_RING_SIZE];
+	struct  sk_buff *tx_skbuff[TX_RING_SIZE];
+
+	dma_addr_t	bd_dma;
+	struct bufdesc	*tx_bd_base;
+	uint tx_ring_size;
+
+	unsigned short tx_stop_threshold;
+	unsigned short tx_wake_threshold;
+
+	struct bufdesc	*cur_tx;
+	struct bufdesc	*dirty_tx;
+	char *tso_hdrs;
+	dma_addr_t tso_hdrs_dma;
+};
+
+struct fec_enet_priv_rx_q {
+	int index;
+	struct  sk_buff *rx_skbuff[RX_RING_SIZE];
+
+	dma_addr_t	bd_dma;
+	struct bufdesc	*rx_bd_base;
+	uint rx_ring_size;
+
+	struct bufdesc	*cur_rx;
+};
+
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -289,29 +360,18 @@ struct fec_enet_private {
 	int num_rx_queues;
 
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	unsigned char *tx_bounce[TX_RING_SIZE];
-	struct	sk_buff *tx_skbuff[TX_RING_SIZE];
-	struct	sk_buff *rx_skbuff[RX_RING_SIZE];
+	struct fec_enet_priv_tx_q *tx_queue[FEC_ENET_MAX_TX_QS];
+	struct fec_enet_priv_rx_q *rx_queue[FEC_ENET_MAX_RX_QS];
 
-	/* CPM dual port RAM relative addresses */
-	dma_addr_t	bd_dma;
-	/* Address of Rx and Tx buffers */
-	struct bufdesc	*rx_bd_base;
-	struct bufdesc	*tx_bd_base;
-	/* The next free ring entry */
-	struct bufdesc	*cur_rx, *cur_tx;
-	/* The ring entries to be free()ed */
-	struct bufdesc	*dirty_tx;
+	unsigned int total_tx_ring_size;
+	unsigned int total_rx_ring_size;
 
-	unsigned short bufdesc_size;
-	unsigned short tx_ring_size;
-	unsigned short rx_ring_size;
-	unsigned short tx_stop_threshold;
-	unsigned short tx_wake_threshold;
+	unsigned long work_tx;
+	unsigned long work_rx;
+	unsigned long work_ts;
+	unsigned long work_mdio;
 
-	/* Software TSO */
-	char *tso_hdrs;
-	dma_addr_t tso_hdrs_dma;
+	unsigned short bufdesc_size;
 
 	struct	platform_device *pdev;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 00fcadd..f973a92 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -72,6 +72,8 @@ static void set_multicast_list(struct net_device *ndev);
 
 #define DRIVER_NAME	"fec"
 
+#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+
 /* Pause frame feild and FIFO threshold */
 #define FEC_ENET_FCE	(1 << 5)
 #define FEC_ENET_RSEM_V	0x84
@@ -258,22 +260,26 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 static int mii_cnt;
 
 static inline
-struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
+				      struct fec_enet_private *fep,
+				      int queue_id)
 {
 	struct bufdesc *new_bd = bdp + 1;
 	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1;
+	struct fec_enet_priv_tx_q *tx_queue = fep->tx_queue[queue_id];
+	struct fec_enet_priv_rx_q *rx_queue = fep->rx_queue[queue_id];
 	struct bufdesc_ex *ex_base;
 	struct bufdesc *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+	if (bdp >= tx_queue->tx_bd_base) {
+		base = tx_queue->tx_bd_base;
+		ring_size = tx_queue->tx_ring_size;
+		ex_base = (struct bufdesc_ex *)tx_queue->tx_bd_base;
 	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+		base = rx_queue->rx_bd_base;
+		ring_size = rx_queue->rx_ring_size;
+		ex_base = (struct bufdesc_ex *)rx_queue->rx_bd_base;
 	}
 
 	if (fep->bufdesc_ex)
@@ -285,22 +291,26 @@ struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_priva
 }
 
 static inline
-struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
+				      struct fec_enet_private *fep,
+				      int queue_id)
 {
 	struct bufdesc *new_bd = bdp - 1;
 	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1;
+	struct fec_enet_priv_tx_q *tx_queue = fep->tx_queue[queue_id];
+	struct fec_enet_priv_rx_q *rx_queue = fep->rx_queue[queue_id];
 	struct bufdesc_ex *ex_base;
 	struct bufdesc *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+	if (bdp >= tx_queue->tx_bd_base) {
+		base = tx_queue->tx_bd_base;
+		ring_size = tx_queue->tx_ring_size;
+		ex_base = (struct bufdesc_ex *)tx_queue->tx_bd_base;
 	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+		base = rx_queue->rx_bd_base;
+		ring_size = rx_queue->rx_ring_size;
+		ex_base = (struct bufdesc_ex *)rx_queue->rx_bd_base;
 	}
 
 	if (fep->bufdesc_ex)
@@ -316,14 +326,15 @@ static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp,
 	return ((const char *)bdp - (const char *)base) / fep->bufdesc_size;
 }
 
-static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep)
+static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep,
+					struct fec_enet_priv_tx_q *txq)
 {
 	int entries;
 
-	entries = ((const char *)fep->dirty_tx -
-			(const char *)fep->cur_tx) / fep->bufdesc_size - 1;
+	entries = ((const char *)txq->dirty_tx -
+			(const char *)txq->cur_tx) / fep->bufdesc_size - 1;
 
-	return entries > 0 ? entries : entries + fep->tx_ring_size;
+	return entries > 0 ? entries : entries + txq->tx_ring_size;
 }
 
 static void *swap_buffer(void *bufaddr, int len)
@@ -340,22 +351,30 @@ static void *swap_buffer(void *bufaddr, int len)
 static void fec_dump(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct bufdesc *bdp = fep->tx_bd_base;
-	unsigned int index = 0;
+	struct bufdesc *bdp;
+	struct fec_enet_priv_tx_q *txq;
+	int index = 0;
+	int i;
 
 	netdev_info(ndev, "TX ring dump\n");
 	pr_info("Nr     SC     addr       len  SKB\n");
 
-	do {
-		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
-			index,
-			bdp == fep->cur_tx ? 'S' : ' ',
-			bdp == fep->dirty_tx ? 'H' : ' ',
-			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
-			fep->tx_skbuff[index]);
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-		index++;
-	} while (bdp != fep->tx_bd_base);
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		txq = fep->tx_queue[i];
+		bdp = txq->tx_bd_base;
+		pr_info("Tx Queue %d\n", i);
+
+		do {
+			pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+				index,
+				bdp == txq->cur_tx ? 'S' : ' ',
+				bdp == txq->dirty_tx ? 'H' : ' ',
+				bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
+				txq->tx_skbuff[index]);
+			bdp = fec_enet_get_nextdesc(bdp, fep, i);
+			index++;
+		} while (bdp != txq->tx_bd_base);
+	}
 }
 
 static inline bool is_ipv4_pkt(struct sk_buff *skb)
@@ -381,14 +400,17 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 }
 
 static int
-fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
+fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
+			     struct sk_buff *skb,
+			     struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *bdp = fep->cur_tx;
+	struct bufdesc *bdp = txq->cur_tx;
 	struct bufdesc_ex *ebdp;
 	int nr_frags = skb_shinfo(skb)->nr_frags;
+	unsigned short queue = skb_get_queue_mapping(skb);
 	int frag, frag_len;
 	unsigned short status;
 	unsigned int estatus = 0;
@@ -400,7 +422,7 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 
 	for (frag = 0; frag < nr_frags; frag++) {
 		this_frag = &skb_shinfo(skb)->frags[frag];
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 		ebdp = (struct bufdesc_ex *)bdp;
 
 		status = bdp->cbd_sc;
@@ -428,11 +450,11 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 
 		bufaddr = page_address(this_frag->page.p) + this_frag->page_offset;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 		if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 			id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-			memcpy(fep->tx_bounce[index], bufaddr, frag_len);
-			bufaddr = fep->tx_bounce[index];
+			memcpy(txq->tx_bounce[index], bufaddr, frag_len);
+			bufaddr = txq->tx_bounce[index];
 
 			if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 				swap_buffer(bufaddr, frag_len);
@@ -452,21 +474,22 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 		bdp->cbd_sc = status;
 	}
 
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	return 0;
 
 dma_mapping_error:
-	bdp = fep->cur_tx;
+	bdp = txq->cur_tx;
 	for (i = 0; i < frag; i++) {
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 				bdp->cbd_datlen, DMA_TO_DEVICE);
 	}
 	return NETDEV_TX_OK;
 }
 
-static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
+				   struct sk_buff *skb, struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -477,12 +500,13 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	dma_addr_t addr;
 	unsigned short status;
 	unsigned short buflen;
+	unsigned short queue;
 	unsigned int estatus = 0;
 	unsigned int index;
 	int entries_free;
 	int ret;
 
-	entries_free = fec_enet_get_free_txdesc_num(fep);
+	entries_free = fec_enet_get_free_txdesc_num(fep, txq);
 	if (entries_free < MAX_SKB_FRAGS + 1) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
@@ -497,7 +521,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	/* Fill in a Tx ring entry */
-	bdp = fep->cur_tx;
+	bdp = txq->cur_tx;
 	status = bdp->cbd_sc;
 	status &= ~BD_ENET_TX_STATS;
 
@@ -505,11 +529,12 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	bufaddr = skb->data;
 	buflen = skb_headlen(skb);
 
-	index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+	queue = skb_get_queue_mapping(skb);
+	index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], skb->data, buflen);
-		bufaddr = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], skb->data, buflen);
+		bufaddr = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(bufaddr, buflen);
@@ -525,7 +550,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	if (nr_frags) {
-		ret = fec_enet_txq_submit_frag_skb(skb, ndev);
+		ret = fec_enet_txq_submit_frag_skb(txq, skb, ndev);
 		if (ret)
 			return ret;
 	} else {
@@ -553,10 +578,10 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 		ebdp->cbd_esc = estatus;
 	}
 
-	last_bdp = fep->cur_tx;
-	index = fec_enet_get_bd_index(fep->tx_bd_base, last_bdp, fep);
+	last_bdp = txq->cur_tx;
+	index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep);
 	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	txq->tx_skbuff[index] = skb;
 
 	bdp->cbd_datlen = buflen;
 	bdp->cbd_bufaddr = addr;
@@ -568,22 +593,23 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	bdp->cbd_sc = status;
 
 	/* If this was the last BD in the ring, start at the beginning again. */
-	bdp = fec_enet_get_nextdesc(last_bdp, fep);
+	bdp = fec_enet_get_nextdesc(last_bdp, fep, queue);
 
 	skb_tx_timestamp(skb);
 
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
 
 	return 0;
 }
 
 static int
-fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
-			struct bufdesc *bdp, int index, char *data,
-			int size, bool last_tcp, bool is_last)
+fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
+			  struct net_device *ndev,
+			  struct bufdesc *bdp, int index, char *data,
+			  int size, bool last_tcp, bool is_last)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -600,8 +626,8 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
 
 	if (((unsigned long) data) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], data, size);
-		data = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], data, size);
+		data = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(data, size);
@@ -640,8 +666,9 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
 }
 
 static int
-fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
-			struct bufdesc *bdp, int index)
+fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
+			 struct sk_buff *skb, struct net_device *ndev,
+			 struct bufdesc *bdp, int index)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -657,12 +684,12 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
 	status &= ~BD_ENET_TX_STATS;
 	status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
 
-	bufaddr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
-	dmabuf = fep->tso_hdrs_dma + index * TSO_HEADER_SIZE;
+	bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
+	dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], skb->data, hdr_len);
-		bufaddr = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], skb->data, hdr_len);
+		bufaddr = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(bufaddr, hdr_len);
@@ -692,17 +719,20 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
 	return 0;
 }
 
-static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
+				   struct sk_buff *skb,
+				   struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 	int total_len, data_left;
-	struct bufdesc *bdp = fep->cur_tx;
+	struct bufdesc *bdp = txq->cur_tx;
+	unsigned short queue = skb_get_queue_mapping(skb);
 	struct tso_t tso;
 	unsigned int index = 0;
 	int ret;
 
-	if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep)) {
+	if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
 			netdev_err(ndev, "NOT enough BD for TSO!\n");
@@ -722,14 +752,14 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 	while (total_len > 0) {
 		char *hdr;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 		data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
 		total_len -= data_left;
 
 		/* prepare packet headers: MAC + IP + TCP */
-		hdr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
+		hdr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
 		tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
-		ret = fec_enet_txq_put_hdr_tso(skb, ndev, bdp, index);
+		ret = fec_enet_txq_put_hdr_tso(txq, skb, ndev, bdp, index);
 		if (ret)
 			goto err_release;
 
@@ -737,10 +767,13 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 			int size;
 
 			size = min_t(int, tso.size, data_left);
-			bdp = fec_enet_get_nextdesc(bdp, fep);
-			index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
-			ret = fec_enet_txq_put_data_tso(skb, ndev, bdp, index, tso.data,
-							size, size == data_left,
+			bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+			index = fec_enet_get_bd_index(txq->tx_bd_base,
+						      bdp, fep);
+			ret = fec_enet_txq_put_data_tso(txq, skb, ndev,
+							bdp, index,
+							tso.data, size,
+							size == data_left,
 							total_len == 0);
 			if (ret)
 				goto err_release;
@@ -749,17 +782,17 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 			tso_build_data(skb, &tso, size);
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 	}
 
 	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	txq->tx_skbuff[index] = skb;
 
 	skb_tx_timestamp(skb);
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
 
 	return 0;
 
@@ -773,18 +806,25 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int entries_free;
+	unsigned short queue;
+	struct fec_enet_priv_tx_q *txq;
+	struct netdev_queue *nq;
 	int ret;
 
+	queue = skb_get_queue_mapping(skb);
+	txq = fep->tx_queue[queue];
+	nq = netdev_get_tx_queue(ndev, queue);
+
 	if (skb_is_gso(skb))
-		ret = fec_enet_txq_submit_tso(skb, ndev);
+		ret = fec_enet_txq_submit_tso(txq, skb, ndev);
 	else
-		ret = fec_enet_txq_submit_skb(skb, ndev);
+		ret = fec_enet_txq_submit_skb(txq, skb, ndev);
 	if (ret)
 		return ret;
 
-	entries_free = fec_enet_get_free_txdesc_num(fep);
-	if (entries_free <= fep->tx_stop_threshold)
-		netif_stop_queue(ndev);
+	entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+	if (entries_free <= txq->tx_stop_threshold)
+		netif_tx_stop_queue(nq);
 
 	return NETDEV_TX_OK;
 }
@@ -794,46 +834,101 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 static void fec_enet_bd_init(struct net_device *dev)
 {
 	struct fec_enet_private *fep = netdev_priv(dev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
 	struct bufdesc *bdp;
-	unsigned int i;
+	unsigned int i, j;
 
 	/* Initialize the receive buffer descriptors. */
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		rx_queue = fep->rx_queue[i];
+		bdp = rx_queue->rx_bd_base;
 
-		/* Initialize the BD for every fragment in the page. */
-		if (bdp->cbd_bufaddr)
-			bdp->cbd_sc = BD_ENET_RX_EMPTY;
-		else
-			bdp->cbd_sc = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-	}
+		for (j = 0; j < rx_queue->rx_ring_size; j++) {
 
-	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+			/* Initialize the BD for every fragment in the page. */
+			if (bdp->cbd_bufaddr)
+				bdp->cbd_sc = BD_ENET_RX_EMPTY;
+			else
+				bdp->cbd_sc = 0;
+			bdp = fec_enet_get_nextdesc(bdp, fep, i);
+		}
 
-	fep->cur_rx = fep->rx_bd_base;
+		/* Set the last buffer to wrap */
+		bdp = fec_enet_get_prevdesc(bdp, fep, i);
+		bdp->cbd_sc |= BD_SC_WRAP;
+
+		rx_queue->cur_rx = rx_queue->rx_bd_base;
+	}
 
 	/* ...and the same for transmit */
-	bdp = fep->tx_bd_base;
-	fep->cur_tx = bdp;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-
-		/* Initialize the BD for every fragment in the page. */
-		bdp->cbd_sc = 0;
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+		bdp = tx_queue->tx_bd_base;
+		tx_queue->cur_tx = bdp;
+
+		for (j = 0; j < tx_queue->tx_ring_size; j++) {
+			/* Initialize the BD for every fragment in the page. */
+			bdp->cbd_sc = 0;
+			if (tx_queue->tx_skbuff[j]) {
+				dev_kfree_skb_any(tx_queue->tx_skbuff[j]);
+				tx_queue->tx_skbuff[j] = NULL;
+			}
+			bdp->cbd_bufaddr = 0;
+			bdp = fec_enet_get_nextdesc(bdp, fep, i);
 		}
-		bdp->cbd_bufaddr = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+
+		/* Set the last buffer to wrap */
+		bdp = fec_enet_get_prevdesc(bdp, fep, i);
+		bdp->cbd_sc |= BD_SC_WRAP;
+		tx_queue->dirty_tx = bdp;
+	}
+}
+
+static inline void fec_enet_enable_ring(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
+	int i;
+
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		rx_queue = fep->rx_queue[i];
+		writel(rx_queue->bd_dma, fep->hwp + FEC_R_DES_START(i));
+
+		/* enable DMA1/2 */
+		if (i)
+			writel(RCMR_MATCHEN | RCMR_CMP(i),
+			       fep->hwp + FEC_RCMR(i));
 	}
 
-	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
-	fep->dirty_tx = bdp;
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+		writel(tx_queue->bd_dma, fep->hwp + FEC_X_DES_START(i));
+
+		/* enable DMA1/2 */
+		if (i)
+			writel(DMA_CLASS_EN | IDLE_SLOPE(i),
+			       fep->hwp + FEC_DMA_CFG(i));
+	}
+}
+
+static void fec_enet_reset_skb(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	int i, j;
+
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+
+		for (j = 0; j < tx_queue->tx_ring_size; j++) {
+			if (tx_queue->tx_skbuff[j]) {
+				dev_kfree_skb_any(tx_queue->tx_skbuff[j]);
+				tx_queue->tx_skbuff[j] = NULL;
+			}
+		}
+	}
 }
 
 /*
@@ -847,11 +942,11 @@ fec_restart(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	int i;
 	u32 val;
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
+	int i;
 
 	/* Whack a reset.  We should wait for this. */
 	writel(1, fep->hwp + FEC_ECNTRL);
@@ -876,21 +971,10 @@ fec_restart(struct net_device *ndev)
 	fec_enet_bd_init(ndev);
 
 	/* Set receive and transmit descriptor base. */
-	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
-	if (fep->bufdesc_ex)
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
-			* fep->rx_ring_size, fep->hwp + FEC_X_DES_START);
-	else
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
-			* fep->rx_ring_size,	fep->hwp + FEC_X_DES_START);
-
+	fec_enet_enable_ring(ndev);
 
-	for (i = 0; i <= TX_RING_MOD_MASK; i++) {
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
-		}
-	}
+	/* Reset tx SKB buffers. */
+	fec_enet_reset_skb(ndev);
 
 	/* Enable MII mode */
 	if (fep->full_duplex == DUPLEX_FULL) {
@@ -1012,7 +1096,8 @@ fec_restart(struct net_device *ndev)
 
 	/* And last, enable the transmit and receive processing */
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
-	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+	for (i = 0; i < fep->num_rx_queues; i++)
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
 
 	if (fep->bufdesc_ex)
 		fec_ptp_start_cyclecounter(ndev);
@@ -1097,37 +1182,45 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
 }
 
 static void
-fec_enet_tx(struct net_device *ndev)
+fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
 {
 	struct	fec_enet_private *fep;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
+	struct fec_enet_priv_tx_q *txq;
+	struct netdev_queue *nq;
 	int	index = 0;
 	int	entries_free;
 
 	fep = netdev_priv(ndev);
-	bdp = fep->dirty_tx;
 
+	queue_id = FEC_ENET_GET_QUQUE(queue_id);
+
+	txq = fep->tx_queue[queue_id];
 	/* get next bdp of dirty_tx */
-	bdp = fec_enet_get_nextdesc(bdp, fep);
+	nq = netdev_get_tx_queue(ndev, queue_id);
+	bdp = txq->dirty_tx;
+
+	/* get next bdp of dirty_tx */
+	bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
 
 		/* current queue is empty */
-		if (bdp == fep->cur_tx)
+		if (bdp == txq->cur_tx)
 			break;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 
-		skb = fep->tx_skbuff[index];
-		fep->tx_skbuff[index] = NULL;
-		if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
+		skb = txq->tx_skbuff[index];
+		txq->tx_skbuff[index] = NULL;
+		if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
 			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 					bdp->cbd_datlen, DMA_TO_DEVICE);
 		bdp->cbd_bufaddr = 0;
 		if (!skb) {
-			bdp = fec_enet_get_nextdesc(bdp, fep);
+			bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 			continue;
 		}
 
@@ -1169,23 +1262,37 @@ fec_enet_tx(struct net_device *ndev)
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
 
-		fep->dirty_tx = bdp;
+		txq->dirty_tx = bdp;
 
 		/* Update pointer to next buffer descriptor to be transmitted */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 		/* Since we have freed up a buffer, the ring is no longer full
 		 */
 		if (netif_queue_stopped(ndev)) {
-			entries_free = fec_enet_get_free_txdesc_num(fep);
-			if (entries_free >= fep->tx_wake_threshold)
-				netif_wake_queue(ndev);
+			entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+			if (entries_free >= txq->tx_wake_threshold)
+				netif_tx_wake_queue(nq);
 		}
 	}
 
 	/* ERR006538: Keep the transmitter going */
-	if (bdp != fep->cur_tx && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
-		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	if (bdp != txq->cur_tx &&
+	    readl(fep->hwp + FEC_X_DES_ACTIVE(queue_id)) == 0)
+		writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue_id));
+}
+
+static void
+fec_enet_tx(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	u16 queue_id;
+	/* First process class A queue, then Class B and Best Effort queue */
+	for_each_set_bit(queue_id, &fep->work_tx, FEC_ENET_MAX_TX_QS) {
+		clear_bit(queue_id, &fep->work_tx);
+		fec_enet_tx_queue(ndev, queue_id);
+	}
+	return;
 }
 
 /* During a receive, the cur_rx points to the current incoming buffer.
@@ -1194,11 +1301,12 @@ fec_enet_tx(struct net_device *ndev)
  * effectively tossing the packet.
  */
 static int
-fec_enet_rx(struct net_device *ndev, int budget)
+fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
+	struct fec_enet_priv_rx_q *rxq;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
@@ -1213,11 +1321,13 @@ fec_enet_rx(struct net_device *ndev, int budget)
 #ifdef CONFIG_M532x
 	flush_cache_all();
 #endif
+	queue_id = FEC_ENET_GET_QUQUE(queue_id);
+	rxq = fep->rx_queue[queue_id];
 
 	/* First, grab all of the stats for the incoming packet.
 	 * These get messed up if we get called due to a busy condition.
 	 */
-	bdp = fep->cur_rx;
+	bdp = rxq->cur_rx;
 
 	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
@@ -1231,7 +1341,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		if ((status & BD_ENET_RX_LAST) == 0)
 			netdev_err(ndev, "rcv is not +last\n");
 
-		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
 
 		/* Check for errors. */
 		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
@@ -1264,8 +1373,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		pkt_len = bdp->cbd_datlen;
 		ndev->stats.rx_bytes += pkt_len;
 
-		index = fec_enet_get_bd_index(fep->rx_bd_base, bdp, fep);
-		data = fep->rx_skbuff[index]->data;
+		index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep);
+		data = rxq->rx_skbuff[index]->data;
 		dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 
@@ -1280,7 +1389,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
 		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-		    fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
+			fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1308,7 +1417,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN));
 			if (vlan_packet_rcvd)
 				payload_offset = (2 * ETH_ALEN) + VLAN_HLEN;
-			skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
+				skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
 						       data + payload_offset,
 						       pkt_len - 4 - (2 * ETH_ALEN));
 
@@ -1357,19 +1466,48 @@ rx_processing_done:
 		}
 
 		/* Update BD pointer to next entry */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 		/* Doing this here will keep the FEC running while we process
 		 * incoming frames.  On a heavily loaded network, we should be
 		 * able to keep up at the expense of system resources.
 		 */
-		writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(queue_id));
 	}
-	fep->cur_rx = bdp;
+	rxq->cur_rx = bdp;
+	return pkt_received;
+}
 
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
+{
+	int     pkt_received = 0;
+	u16	queue_id;
+	struct fec_enet_private *fep = netdev_priv(ndev);
+
+	for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) {
+		clear_bit(queue_id, &fep->work_rx);
+		pkt_received += fec_enet_rx_queue(ndev,
+					budget - pkt_received, queue_id);
+	}
 	return pkt_received;
 }
 
+static bool
+fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
+{
+	if (int_events == 0)
+		return false;
+
+	if (int_events & FEC_ENET_RXF)
+		fep->work_rx |= (1 << 2);
+
+	if (int_events & FEC_ENET_TXF)
+		fep->work_tx |= (1 << 2);
+
+	return true;
+}
+
 static irqreturn_t
 fec_enet_interrupt(int irq, void *dev_id)
 {
@@ -1381,6 +1519,7 @@ fec_enet_interrupt(int irq, void *dev_id)
 
 	int_events = readl(fep->hwp + FEC_IEVENT);
 	writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT);
+	fec_enet_collect_events(fep, int_events);
 
 	if (int_events & napi_mask) {
 		ret = IRQ_HANDLED;
@@ -2129,93 +2268,117 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 static void fec_enet_free_buffers(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	unsigned int i;
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
+	unsigned int i, j;
 	struct sk_buff *skb;
 	struct bufdesc	*bdp;
 
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
-		skb = fep->rx_skbuff[i];
-		fep->rx_skbuff[i] = NULL;
-		if (skb) {
-			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
-					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
-			dev_kfree_skb(skb);
+	for (j = 0; j < fep->num_rx_queues; j++) {
+		rx_queue = fep->rx_queue[j];
+		bdp = rx_queue->rx_bd_base;
+		for (i = 0; i < rx_queue->rx_ring_size; i++) {
+			skb = rx_queue->rx_skbuff[i];
+			rx_queue->rx_skbuff[i] = NULL;
+			if (skb) {
+				dma_unmap_single(&fep->pdev->dev,
+						 bdp->cbd_bufaddr,
+						 FEC_ENET_RX_FRSIZE,
+						 DMA_FROM_DEVICE);
+				dev_kfree_skb(skb);
+			}
+			bdp = fec_enet_get_nextdesc(bdp, fep, j);
 		}
-		bdp = fec_enet_get_nextdesc(bdp, fep);
 	}
 
-	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-		kfree(fep->tx_bounce[i]);
-		fep->tx_bounce[i] = NULL;
-		skb = fep->tx_skbuff[i];
-		fep->tx_skbuff[i] = NULL;
-		dev_kfree_skb(skb);
+	for (j = 0; j < fep->num_tx_queues; j++) {
+		tx_queue = fep->tx_queue[j];
+		bdp = tx_queue->tx_bd_base;
+		for (i = 0; i < tx_queue->tx_ring_size; i++) {
+			kfree(tx_queue->tx_bounce[i]);
+			tx_queue->tx_bounce[i] = NULL;
+			skb = tx_queue->tx_skbuff[i];
+			tx_queue->tx_skbuff[i] = NULL;
+			dev_kfree_skb(skb);
+		}
 	}
 }
 
 static int fec_enet_alloc_buffers(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	unsigned int i;
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
+	unsigned int i, j;
 	struct sk_buff *skb;
 	struct bufdesc	*bdp;
 
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
-		dma_addr_t addr;
+	for (j = 0; j < fep->num_rx_queues; j++) {
+		rx_queue = fep->rx_queue[j];
+		bdp = rx_queue->rx_bd_base;
+		for (i = 0; i < rx_queue->rx_ring_size; i++) {
+			dma_addr_t addr;
+
+			skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
+			if (!skb)
+				goto err_alloc;
+
+			addr = dma_map_single(&fep->pdev->dev, skb->data,
+					      FEC_ENET_RX_FRSIZE,
+					      DMA_FROM_DEVICE);
+			if (dma_mapping_error(&fep->pdev->dev, addr)) {
+				dev_kfree_skb(skb);
+				if (net_ratelimit())
+					netdev_err(ndev, "Rx DMA memory map failed\n");
+				goto err_alloc;
+			}
 
-		skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
-		if (!skb)
-			goto err_alloc;
+			rx_queue->rx_skbuff[i] = skb;
+			bdp->cbd_bufaddr = addr;
+			bdp->cbd_sc = BD_ENET_RX_EMPTY;
 
-		addr = dma_map_single(&fep->pdev->dev, skb->data,
-				FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
-		if (dma_mapping_error(&fep->pdev->dev, addr)) {
-			dev_kfree_skb(skb);
-			if (net_ratelimit())
-				netdev_err(ndev, "Rx DMA memory map failed\n");
-			goto err_alloc;
-		}
+			if (fep->bufdesc_ex) {
+				struct bufdesc_ex *ebdp;
 
-		fep->rx_skbuff[i] = skb;
-		bdp->cbd_bufaddr = addr;
-		bdp->cbd_sc = BD_ENET_RX_EMPTY;
+				ebdp = (struct bufdesc_ex *)bdp;
+				ebdp->cbd_esc = BD_ENET_RX_INT;
+			}
 
-		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-			ebdp->cbd_esc = BD_ENET_RX_INT;
+			bdp = fec_enet_get_nextdesc(bdp, fep, j);
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		/* Set the last buffer to wrap. */
+		bdp = fec_enet_get_prevdesc(bdp, fep, j);
+		bdp->cbd_sc |= BD_SC_WRAP;
 	}
 
-	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+	for (j = 0; j < fep->num_tx_queues; j++) {
+		tx_queue = fep->tx_queue[j];
+		bdp = tx_queue->tx_bd_base;
 
-	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-		fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
-		if (!fep->tx_bounce[i])
-			goto err_alloc;
+		for (i = 0; i < tx_queue->tx_ring_size; i++) {
+			tx_queue->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE,
+							 GFP_KERNEL);
+			if (!tx_queue->tx_bounce[i])
+				goto err_alloc;
 
-		bdp->cbd_sc = 0;
-		bdp->cbd_bufaddr = 0;
+			bdp->cbd_sc = 0;
+			bdp->cbd_bufaddr = 0;
 
-		if (fep->bufdesc_ex) {
-			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
-			ebdp->cbd_esc = BD_ENET_TX_INT;
-		}
+			if (fep->bufdesc_ex) {
+				struct bufdesc_ex *ebdp;
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
-	}
+				ebdp = (struct bufdesc_ex *)bdp;
+				ebdp->cbd_esc = BD_ENET_TX_INT;
+			}
 
-	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
-	bdp->cbd_sc |= BD_SC_WRAP;
+			bdp = fec_enet_get_nextdesc(bdp, fep, j);
+		}
 
+		/* Set the last buffer to wrap. */
+		bdp = fec_enet_get_prevdesc(bdp, fep, j);
+		bdp->cbd_sc |= BD_SC_WRAP;
+	}
 	return 0;
 
  err_alloc:
@@ -2252,7 +2415,8 @@ fec_enet_open(struct net_device *ndev)
 	fec_restart(ndev);
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
-	netif_start_queue(ndev);
+	netif_tx_start_all_queues(ndev);
+
 	return 0;
 }
 
@@ -2426,7 +2590,7 @@ static int fec_set_features(struct net_device *netdev,
 	/* Resume the device after updates */
 	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
 		fec_restart(netdev);
-		netif_wake_queue(netdev);
+		netif_tx_wake_all_queues(netdev);
 		netif_tx_unlock_bh(netdev);
 		napi_enable(&fep->napi);
 	}
@@ -2434,10 +2598,17 @@ static int fec_set_features(struct net_device *netdev,
 	return 0;
 }
 
+u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+			  void *accel_priv, select_queue_fallback_t fallback)
+{
+	return skb_tx_hash(ndev, skb);
+}
+
 static const struct net_device_ops fec_netdev_ops = {
 	.ndo_open		= fec_enet_open,
 	.ndo_stop		= fec_enet_close,
 	.ndo_start_xmit		= fec_enet_start_xmit,
+	.ndo_select_queue       = fec_enet_select_queue,
 	.ndo_set_rx_mode	= set_multicast_list,
 	.ndo_change_mtu		= eth_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -2450,6 +2621,76 @@ static const struct net_device_ops fec_netdev_ops = {
 	.ndo_set_features	= fec_set_features,
 };
 
+static void fec_enet_free_queue(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < fep->num_tx_queues; i++)
+		if (fep->tx_queue[i] && fep->tx_queue[i]->tso_hdrs)
+			dma_free_coherent(NULL,
+				fep->tx_queue[i]->tx_ring_size * TSO_HEADER_SIZE,
+				fep->tx_queue[i]->tso_hdrs,
+				fep->tx_queue[i]->tso_hdrs_dma);
+
+	for (i = 0; i < fep->num_rx_queues; i++)
+		if (fep->rx_queue[i])
+			kfree(fep->rx_queue[i]);
+
+	for (i = 0; i < fep->num_tx_queues; i++)
+		if (fep->tx_queue[i])
+			kfree(fep->tx_queue[i]);
+}
+
+static int fec_enet_alloc_queue(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i;
+	int ret = 0;
+	struct fec_enet_priv_tx_q *txq;
+
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+		if (!txq) {
+			ret = -ENOMEM;
+			goto alloc_failed;
+		}
+
+		fep->tx_queue[i] = txq;
+		txq->tx_ring_size = TX_RING_SIZE;
+		fep->total_tx_ring_size += fep->tx_queue[i]->tx_ring_size;
+
+		txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
+		txq->tx_wake_threshold =
+			(txq->tx_ring_size - txq->tx_stop_threshold) / 2;
+
+		txq->tso_hdrs = dma_alloc_coherent(NULL,
+					txq->tx_ring_size * TSO_HEADER_SIZE,
+					&txq->tso_hdrs_dma,
+					GFP_KERNEL);
+		if (!txq->tso_hdrs) {
+			ret = -ENOMEM;
+			goto alloc_failed;
+		}
+	}
+
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		fep->rx_queue[i] = kzalloc(sizeof(*fep->rx_queue[i]),
+				GFP_KERNEL);
+		if (!fep->rx_queue[i]) {
+			ret = -ENOMEM;
+			goto alloc_failed;
+		}
+
+		fep->rx_queue[i]->rx_ring_size = RX_RING_SIZE;
+		fep->total_rx_ring_size += fep->rx_queue[i]->rx_ring_size;
+	}
+	return ret;
+
+alloc_failed:
+	fec_enet_free_queue(ndev);
+	return ret;
+}
  /*
   * XXX:  We need to clean up on failure exits here.
   *
@@ -2459,37 +2700,60 @@ static int fec_enet_init(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
+	struct fec_enet_priv_tx_q *tx_queue;
+	struct fec_enet_priv_rx_q *rx_queue;
 	struct bufdesc *cbd_base;
+	dma_addr_t bd_dma;
 	int bd_size;
+	int i;
 
-	/* init the tx & rx ring size */
-	fep->tx_ring_size = TX_RING_SIZE;
-	fep->rx_ring_size = RX_RING_SIZE;
-
-	fep->tx_stop_threshold = FEC_MAX_SKB_DESCS;
-	fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2;
+	fec_enet_alloc_queue(ndev);
 
 	if (fep->bufdesc_ex)
 		fep->bufdesc_size = sizeof(struct bufdesc_ex);
 	else
 		fep->bufdesc_size = sizeof(struct bufdesc);
-	bd_size = (fep->tx_ring_size + fep->rx_ring_size) *
+	bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *
 			fep->bufdesc_size;
 
 	/* Allocate memory for buffer descriptors. */
-	cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma,
+	cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
 				      GFP_KERNEL);
 	if (!cbd_base)
 		return -ENOMEM;
 
-	fep->tso_hdrs = dma_alloc_coherent(NULL, fep->tx_ring_size * TSO_HEADER_SIZE,
-						&fep->tso_hdrs_dma, GFP_KERNEL);
-	if (!fep->tso_hdrs) {
-		dma_free_coherent(NULL, bd_size, cbd_base, fep->bd_dma);
-		return -ENOMEM;
+	memset(cbd_base, 0, bd_size);
+
+	for (i = 0; i < fep->num_rx_queues; i++) {
+		rx_queue = fep->rx_queue[i];
+		rx_queue->index = i;
+		rx_queue->rx_bd_base = (struct bufdesc *)cbd_base;
+		rx_queue->bd_dma = bd_dma;
+		if (fep->bufdesc_ex) {
+			bd_dma += sizeof(struct bufdesc_ex) * rx_queue->rx_ring_size;
+			cbd_base = (struct bufdesc *)
+				(((struct bufdesc_ex *)cbd_base) + rx_queue->rx_ring_size);
+		} else {
+			bd_dma += sizeof(struct bufdesc) * rx_queue->rx_ring_size;
+			cbd_base += rx_queue->rx_ring_size;
+		}
+	}
+
+	for (i = 0; i < fep->num_tx_queues; i++) {
+		tx_queue = fep->tx_queue[i];
+		tx_queue->index = i;
+		tx_queue->tx_bd_base = (struct bufdesc *)cbd_base;
+		tx_queue->bd_dma = bd_dma;
+		if (fep->bufdesc_ex) {
+			bd_dma += sizeof(struct bufdesc_ex) * tx_queue->tx_ring_size;
+			cbd_base = (struct bufdesc *)
+			(((struct bufdesc_ex *)cbd_base) + tx_queue->tx_ring_size);
+		} else {
+			bd_dma += sizeof(struct bufdesc) * tx_queue->tx_ring_size;
+			cbd_base += tx_queue->tx_ring_size;
+		}
 	}
 
-	memset(cbd_base, 0, PAGE_SIZE);
 
 	fep->netdev = ndev;
 
@@ -2498,14 +2762,6 @@ static int fec_enet_init(struct net_device *ndev)
 	/* make sure MAC we just acquired is programmed into the hw */
 	fec_set_mac_address(ndev, NULL);
 
-	/* Set receive and transmit descriptor base. */
-	fep->rx_bd_base = cbd_base;
-	if (fep->bufdesc_ex)
-		fep->tx_bd_base = (struct bufdesc *)
-			(((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size);
-	else
-		fep->tx_bd_base = cbd_base + fep->rx_ring_size;
-
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
 	ndev->netdev_ops = &fec_netdev_ops;
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 05/11] net:fec: Disable enet-avb MAC instead of reset MAC
  2014-09-03 20:38 ` Frank Li
@ 2014-09-03 20:38   ` Frank Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

For i.MX6SX enet use AXI bus, reset MAC will make system bus dead
if ENET-AXI bus has pending access (AHB bus should not have such issue).
So, disable enet with AVB MAC instead of reset MAC itself.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec_main.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f973a92..5dab6a6 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -948,9 +948,16 @@ fec_restart(struct net_device *ndev)
 	u32 ecntl = 0x2; /* ETHEREN */
 	int i;
 
-	/* Whack a reset.  We should wait for this. */
-	writel(1, fep->hwp + FEC_ECNTRL);
-	udelay(10);
+	/* Whack a reset.  We should wait for this.
+	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
+	 * instead of reset MAC itself.
+	 */
+	if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+		writel(0, fep->hwp + FEC_ECNTRL);
+	} else {
+		writel(1, fep->hwp + FEC_ECNTRL);
+		udelay(10);
+	}
 
 	/*
 	 * enet-mac reset will reset mac address registers too,
@@ -1122,9 +1129,16 @@ fec_stop(struct net_device *ndev)
 			netdev_err(ndev, "Graceful transmit stop did not complete!\n");
 	}
 
-	/* Whack a reset.  We should wait for this. */
-	writel(1, fep->hwp + FEC_ECNTRL);
-	udelay(10);
+	/* Whack a reset.  We should wait for this.
+	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
+	 * instead of reset MAC itself.
+	 */
+	if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+		writel(0, fep->hwp + FEC_ECNTRL);
+	} else {
+		writel(1, fep->hwp + FEC_ECNTRL);
+		udelay(10);
+	}
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 05/11] net:fec: Disable enet-avb MAC instead of reset MAC
@ 2014-09-03 20:38   ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

For i.MX6SX enet use AXI bus, reset MAC will make system bus dead
if ENET-AXI bus has pending access (AHB bus should not have such issue).
So, disable enet with AVB MAC instead of reset MAC itself.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec_main.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f973a92..5dab6a6 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -948,9 +948,16 @@ fec_restart(struct net_device *ndev)
 	u32 ecntl = 0x2; /* ETHEREN */
 	int i;
 
-	/* Whack a reset.  We should wait for this. */
-	writel(1, fep->hwp + FEC_ECNTRL);
-	udelay(10);
+	/* Whack a reset.  We should wait for this.
+	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
+	 * instead of reset MAC itself.
+	 */
+	if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+		writel(0, fep->hwp + FEC_ECNTRL);
+	} else {
+		writel(1, fep->hwp + FEC_ECNTRL);
+		udelay(10);
+	}
 
 	/*
 	 * enet-mac reset will reset mac address registers too,
@@ -1122,9 +1129,16 @@ fec_stop(struct net_device *ndev)
 			netdev_err(ndev, "Graceful transmit stop did not complete!\n");
 	}
 
-	/* Whack a reset.  We should wait for this. */
-	writel(1, fep->hwp + FEC_ECNTRL);
-	udelay(10);
+	/* Whack a reset.  We should wait for this.
+	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
+	 * instead of reset MAC itself.
+	 */
+	if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+		writel(0, fep->hwp + FEC_ECNTRL);
+	} else {
+		writel(1, fep->hwp + FEC_ECNTRL);
+		udelay(10);
+	}
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 06/11] net:fec: add enet-avb IP support
  2014-09-03 20:38 ` Frank Li
@ 2014-09-03 20:38   ` Frank Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li, Fugang Duan

i.MX6SX Enet-AVB support 3 tx queues, 3 rx queues.
For tx queues: ring 0 -> best effort
	       ring 1 -> Class A
	       ring 2 -> Class B
For rx queues:
	       ring 0 -> best effort
	       ring 1 -> receive VLAN packet with classification match
	       ring 2 -> receive VLAN packet with classification match

Add enet-avb IP multiqueue support for the driver.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec.h      | 33 +++++++++++++++++++++++++++
 drivers/net/ethernet/freescale/fec_main.c | 38 +++++++++++++++----------------
 2 files changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 984eaf2..16989bc 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -38,6 +38,12 @@
 #define FEC_ADDR_LOW		0x0e4 /* Low 32bits MAC address */
 #define FEC_ADDR_HIGH		0x0e8 /* High 16bits MAC address */
 #define FEC_OPD			0x0ec /* Opcode + Pause duration */
+#define FEC_TXIC0		0xF0  /* Tx Interrupt Coalescing for ring 0 */
+#define FEC_TXIC1		0xF4  /* Tx Interrupt Coalescing for ring 1 */
+#define FEC_TXIC2		0xF8  /* Tx Interrupt Coalescing for ring 2 */
+#define FEC_RXIC0		0x100 /* Rx Interrupt Coalescing for ring 0 */
+#define FEC_RXIC1		0x104 /* Rx Interrupt Coalescing for ring 1 */
+#define FEC_RXIC2		0x108 /* Rx Interrupt Coalescing for ring 2 */
 #define FEC_HASH_TABLE_HIGH	0x118 /* High 32bits hash table */
 #define FEC_HASH_TABLE_LOW	0x11c /* Low 32bits hash table */
 #define FEC_GRP_HASH_TABLE_HIGH	0x120 /* High 32bits hash table */
@@ -65,6 +71,7 @@
 #define FEC_X_DES_ACTIVE_1	0x1e4 /* Tx descriptor active for ring 1 */
 #define FEC_R_DES_ACTIVE_2	0x1e8 /* Rx descriptor active for ring 2 */
 #define FEC_X_DES_ACTIVE_2	0x1ec /* Tx descriptor active for ring 2 */
+#define FEC_QOS_SCHEME		0x1f0 /* Set multi queues Qos scheme */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -305,6 +312,32 @@ struct bufdesc_ex {
 #define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
+/* Interrupt events/masks. */
+#define FEC_ENET_HBERR  ((uint)0x80000000)      /* Heartbeat error */
+#define FEC_ENET_BABR   ((uint)0x40000000)      /* Babbling receiver */
+#define FEC_ENET_BABT   ((uint)0x20000000)      /* Babbling transmitter */
+#define FEC_ENET_GRA    ((uint)0x10000000)      /* Graceful stop complete */
+#define FEC_ENET_TXF_0	((uint)0x08000000)	/* Full frame transmitted */
+#define FEC_ENET_TXF_1	((uint)0x00000008)	/* Full frame transmitted */
+#define FEC_ENET_TXF_2	((uint)0x00000080)	/* Full frame transmitted */
+#define FEC_ENET_TXB    ((uint)0x04000000)      /* A buffer was transmitted */
+#define FEC_ENET_RXF_0	((uint)0x02000000)	/* Full frame received */
+#define FEC_ENET_RXF_1	((uint)0x00000002)	/* Full frame received */
+#define FEC_ENET_RXF_2	((uint)0x00000020)	/* Full frame received */
+#define FEC_ENET_RXB    ((uint)0x01000000)      /* A buffer was received */
+#define FEC_ENET_MII    ((uint)0x00800000)      /* MII interrupt */
+#define FEC_ENET_EBERR  ((uint)0x00400000)      /* SDMA bus error */
+#define FEC_ENET_TXF	(FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
+#define FEC_ENET_RXF	(FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
+#define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
+#define FEC_ENET_TS_TIMER       ((uint)0x00008000)
+
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_TS_TIMER)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
+
+#define FEC_VLAN_TAG_LEN       0x04
+#define FEC_ETHTYPE_LEN                0x02
+
 struct fec_enet_priv_tx_q {
 	int index;
 	unsigned char *tx_bounce[TX_RING_SIZE];
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 5dab6a6..6aab64b 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -193,21 +193,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #endif
 #endif /* CONFIG_M5272 */
 
-/* Interrupt events/masks. */
-#define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
-#define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
-#define FEC_ENET_BABT	((uint)0x20000000)	/* Babbling transmitter */
-#define FEC_ENET_GRA	((uint)0x10000000)	/* Graceful stop complete */
-#define FEC_ENET_TXF	((uint)0x08000000)	/* Full frame transmitted */
-#define FEC_ENET_TXB	((uint)0x04000000)	/* A buffer was transmitted */
-#define FEC_ENET_RXF	((uint)0x02000000)	/* Full frame received */
-#define FEC_ENET_RXB	((uint)0x01000000)	/* A buffer was received */
-#define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
-#define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
-
-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
-#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
-
 /* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE		1522
@@ -885,7 +870,16 @@ static void fec_enet_bd_init(struct net_device *dev)
 	}
 }
 
-static inline void fec_enet_enable_ring(struct net_device *ndev)
+static void fec_enet_active_rxring(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < fep->num_rx_queues; i++)
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+}
+
+static void fec_enet_enable_ring(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct fec_enet_priv_tx_q *tx_queue;
@@ -946,7 +940,6 @@ fec_restart(struct net_device *ndev)
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
-	int i;
 
 	/* Whack a reset.  We should wait for this.
 	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -1103,8 +1096,7 @@ fec_restart(struct net_device *ndev)
 
 	/* And last, enable the transmit and receive processing */
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
-	for (i = 0; i < fep->num_rx_queues; i++)
-		writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+	fec_enet_active_rxring(ndev);
 
 	if (fep->bufdesc_ex)
 		fec_ptp_start_cyclecounter(ndev);
@@ -1515,9 +1507,17 @@ fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
 
 	if (int_events & FEC_ENET_RXF)
 		fep->work_rx |= (1 << 2);
+	if (int_events & FEC_ENET_RXF_1)
+		fep->work_rx |= (1 << 0);
+	if (int_events & FEC_ENET_RXF_2)
+		fep->work_rx |= (1 << 1);
 
 	if (int_events & FEC_ENET_TXF)
 		fep->work_tx |= (1 << 2);
+	if (int_events & FEC_ENET_TXF_1)
+		fep->work_tx |= (1 << 0);
+	if (int_events & FEC_ENET_TXF_2)
+		fep->work_tx |= (1 << 1);
 
 	return true;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 06/11] net:fec: add enet-avb IP support
@ 2014-09-03 20:38   ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li, Fugang Duan

i.MX6SX Enet-AVB support 3 tx queues, 3 rx queues.
For tx queues: ring 0 -> best effort
	       ring 1 -> Class A
	       ring 2 -> Class B
For rx queues:
	       ring 0 -> best effort
	       ring 1 -> receive VLAN packet with classification match
	       ring 2 -> receive VLAN packet with classification match

Add enet-avb IP multiqueue support for the driver.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec.h      | 33 +++++++++++++++++++++++++++
 drivers/net/ethernet/freescale/fec_main.c | 38 +++++++++++++++----------------
 2 files changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 984eaf2..16989bc 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -38,6 +38,12 @@
 #define FEC_ADDR_LOW		0x0e4 /* Low 32bits MAC address */
 #define FEC_ADDR_HIGH		0x0e8 /* High 16bits MAC address */
 #define FEC_OPD			0x0ec /* Opcode + Pause duration */
+#define FEC_TXIC0		0xF0  /* Tx Interrupt Coalescing for ring 0 */
+#define FEC_TXIC1		0xF4  /* Tx Interrupt Coalescing for ring 1 */
+#define FEC_TXIC2		0xF8  /* Tx Interrupt Coalescing for ring 2 */
+#define FEC_RXIC0		0x100 /* Rx Interrupt Coalescing for ring 0 */
+#define FEC_RXIC1		0x104 /* Rx Interrupt Coalescing for ring 1 */
+#define FEC_RXIC2		0x108 /* Rx Interrupt Coalescing for ring 2 */
 #define FEC_HASH_TABLE_HIGH	0x118 /* High 32bits hash table */
 #define FEC_HASH_TABLE_LOW	0x11c /* Low 32bits hash table */
 #define FEC_GRP_HASH_TABLE_HIGH	0x120 /* High 32bits hash table */
@@ -65,6 +71,7 @@
 #define FEC_X_DES_ACTIVE_1	0x1e4 /* Tx descriptor active for ring 1 */
 #define FEC_R_DES_ACTIVE_2	0x1e8 /* Rx descriptor active for ring 2 */
 #define FEC_X_DES_ACTIVE_2	0x1ec /* Tx descriptor active for ring 2 */
+#define FEC_QOS_SCHEME		0x1f0 /* Set multi queues Qos scheme */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -305,6 +312,32 @@ struct bufdesc_ex {
 #define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
+/* Interrupt events/masks. */
+#define FEC_ENET_HBERR  ((uint)0x80000000)      /* Heartbeat error */
+#define FEC_ENET_BABR   ((uint)0x40000000)      /* Babbling receiver */
+#define FEC_ENET_BABT   ((uint)0x20000000)      /* Babbling transmitter */
+#define FEC_ENET_GRA    ((uint)0x10000000)      /* Graceful stop complete */
+#define FEC_ENET_TXF_0	((uint)0x08000000)	/* Full frame transmitted */
+#define FEC_ENET_TXF_1	((uint)0x00000008)	/* Full frame transmitted */
+#define FEC_ENET_TXF_2	((uint)0x00000080)	/* Full frame transmitted */
+#define FEC_ENET_TXB    ((uint)0x04000000)      /* A buffer was transmitted */
+#define FEC_ENET_RXF_0	((uint)0x02000000)	/* Full frame received */
+#define FEC_ENET_RXF_1	((uint)0x00000002)	/* Full frame received */
+#define FEC_ENET_RXF_2	((uint)0x00000020)	/* Full frame received */
+#define FEC_ENET_RXB    ((uint)0x01000000)      /* A buffer was received */
+#define FEC_ENET_MII    ((uint)0x00800000)      /* MII interrupt */
+#define FEC_ENET_EBERR  ((uint)0x00400000)      /* SDMA bus error */
+#define FEC_ENET_TXF	(FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
+#define FEC_ENET_RXF	(FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
+#define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
+#define FEC_ENET_TS_TIMER       ((uint)0x00008000)
+
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_TS_TIMER)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
+
+#define FEC_VLAN_TAG_LEN       0x04
+#define FEC_ETHTYPE_LEN                0x02
+
 struct fec_enet_priv_tx_q {
 	int index;
 	unsigned char *tx_bounce[TX_RING_SIZE];
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 5dab6a6..6aab64b 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -193,21 +193,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #endif
 #endif /* CONFIG_M5272 */
 
-/* Interrupt events/masks. */
-#define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
-#define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
-#define FEC_ENET_BABT	((uint)0x20000000)	/* Babbling transmitter */
-#define FEC_ENET_GRA	((uint)0x10000000)	/* Graceful stop complete */
-#define FEC_ENET_TXF	((uint)0x08000000)	/* Full frame transmitted */
-#define FEC_ENET_TXB	((uint)0x04000000)	/* A buffer was transmitted */
-#define FEC_ENET_RXF	((uint)0x02000000)	/* Full frame received */
-#define FEC_ENET_RXB	((uint)0x01000000)	/* A buffer was received */
-#define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
-#define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
-
-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
-#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
-
 /* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE		1522
@@ -885,7 +870,16 @@ static void fec_enet_bd_init(struct net_device *dev)
 	}
 }
 
-static inline void fec_enet_enable_ring(struct net_device *ndev)
+static void fec_enet_active_rxring(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	int i;
+
+	for (i = 0; i < fep->num_rx_queues; i++)
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+}
+
+static void fec_enet_enable_ring(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct fec_enet_priv_tx_q *tx_queue;
@@ -946,7 +940,6 @@ fec_restart(struct net_device *ndev)
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
-	int i;
 
 	/* Whack a reset.  We should wait for this.
 	 * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -1103,8 +1096,7 @@ fec_restart(struct net_device *ndev)
 
 	/* And last, enable the transmit and receive processing */
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
-	for (i = 0; i < fep->num_rx_queues; i++)
-		writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+	fec_enet_active_rxring(ndev);
 
 	if (fep->bufdesc_ex)
 		fec_ptp_start_cyclecounter(ndev);
@@ -1515,9 +1507,17 @@ fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
 
 	if (int_events & FEC_ENET_RXF)
 		fep->work_rx |= (1 << 2);
+	if (int_events & FEC_ENET_RXF_1)
+		fep->work_rx |= (1 << 0);
+	if (int_events & FEC_ENET_RXF_2)
+		fep->work_rx |= (1 << 1);
 
 	if (int_events & FEC_ENET_TXF)
 		fep->work_tx |= (1 << 2);
+	if (int_events & FEC_ENET_TXF_1)
+		fep->work_tx |= (1 << 0);
+	if (int_events & FEC_ENET_TXF_2)
+		fep->work_tx |= (1 << 1);
 
 	return true;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 07/11] net:fec: Add fsl,imx6sx-fec  compatible strings
  2014-09-03 20:38 ` Frank Li
@ 2014-09-03 20:38   ` Frank Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

Add compatible string "fsl,imx6sx-fec" for i.MX6SX.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 6aab64b..a232245 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -157,6 +157,7 @@ enum imx_fec_type {
 	IMX28_FEC,
 	IMX6Q_FEC,
 	MVF600_FEC,
+	IMX6SX_FEC,
 };
 
 static const struct of_device_id fec_dt_ids[] = {
@@ -165,6 +166,7 @@ static const struct of_device_id fec_dt_ids[] = {
 	{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
 	{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
 	{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
+	{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fec_dt_ids);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 07/11] net:fec: Add fsl,imx6sx-fec  compatible strings
@ 2014-09-03 20:38   ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

Add compatible string "fsl,imx6sx-fec" for i.MX6SX.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 6aab64b..a232245 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -157,6 +157,7 @@ enum imx_fec_type {
 	IMX28_FEC,
 	IMX6Q_FEC,
 	MVF600_FEC,
+	IMX6SX_FEC,
 };
 
 static const struct of_device_id fec_dt_ids[] = {
@@ -165,6 +166,7 @@ static const struct of_device_id fec_dt_ids[] = {
 	{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
 	{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
 	{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
+	{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fec_dt_ids);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
       [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2014-09-03 20:38     ` Frank Li
  2014-09-03 20:38     ` Frank Li
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
The previous enet IP for ARM platform has 16 bytes alignment for tx
DMA transfer. 64 is the an integral number of 16, so change alignment
to 64 bytes for all ARM platform, which don't impact the performance
of previous platform.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index a232245..b388e29f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -65,7 +65,7 @@
 static void set_multicast_list(struct net_device *ndev);
 
 #if defined(CONFIG_ARM)
-#define FEC_ALIGNMENT	0xf
+#define FEC_ALIGNMENT	0x3f
 #else
 #define FEC_ALIGNMENT	0x3
 #endif
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
@ 2014-09-03 20:38     ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
The previous enet IP for ARM platform has 16 bytes alignment for tx
DMA transfer. 64 is the an integral number of 16, so change alignment
to 64 bytes for all ARM platform, which don't impact the performance
of previous platform.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index a232245..b388e29f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -65,7 +65,7 @@
 static void set_multicast_list(struct net_device *ndev);
 
 #if defined(CONFIG_ARM)
-#define FEC_ALIGNMENT	0xf
+#define FEC_ALIGNMENT	0x3f
 #else
 #define FEC_ALIGNMENT	0x3
 #endif
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 09/11] net:fec: remove unnessary memory copy for address alignment in .xmit()
       [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2014-09-03 20:38     ` Frank Li
  2014-09-03 20:38     ` Frank Li
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

i.MX6SX enet-avb IP support buffer address byte alignment for tx DMA
transfer, so remove the unnessary memory copy for the enet avb IP.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b388e29f..d09fe16 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -518,8 +518,9 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
 
 	queue = skb_get_queue_mapping(skb);
 	index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
-	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
-		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+	if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB) &&
+	    ((((unsigned long)bufaddr) & FEC_ALIGNMENT ||
+		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME))) {
 		memcpy(txq->tx_bounce[index], skb->data, buflen);
 		bufaddr = txq->tx_bounce[index];
 
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 09/11] net:fec: remove unnessary memory copy for address alignment in .xmit()
@ 2014-09-03 20:38     ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li

From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

i.MX6SX enet-avb IP support buffer address byte alignment for tx DMA
transfer, so remove the unnessary memory copy for the enet avb IP.

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b388e29f..d09fe16 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -518,8 +518,9 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
 
 	queue = skb_get_queue_mapping(skb);
 	index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
-	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
-		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+	if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB) &&
+	    ((((unsigned long)bufaddr) & FEC_ALIGNMENT ||
+		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME))) {
 		memcpy(txq->tx_bounce[index], skb->data, buflen);
 		bufaddr = txq->tx_bounce[index];
 
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 10/11] ARM: Documentation: Update fec dts binding doc
       [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
@ 2014-09-03 20:38     ` Frank Li
  2014-09-03 20:38     ` Frank Li
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Frank Li, Fugang Duan

    This patch update fec devicetree binding doc that add Optional
    properties "fsl,num_tx_queues" and "fsl,num_rx_queues".

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 Documentation/devicetree/bindings/net/fsl-fec.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
index 8a2c7b5..4da148d 100644
--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -16,6 +16,12 @@ Optional properties:
 - phy-handle : phandle to the PHY device connected to this device.
 - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
   Use instead of phy-handle.
+- fsl,num_tx_queues : The property is valid for enet-avb IP, which supports
+  hw multi queues. Should specify the tx queue number, otherwise set tx queue
+  number to 1.
+- fsl,num_rx_queues : The property is valid for enet-avb IP, which supports
+  hw multi queues. Should specify the rx queue number, otherwise set rx queue
+  number to 1.
 
 Optional subnodes:
 - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 10/11] ARM: Documentation: Update fec dts binding doc
@ 2014-09-03 20:38     ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Frank Li, Fugang Duan

    This patch update fec devicetree binding doc that add Optional
    properties "fsl,num_tx_queues" and "fsl,num_rx_queues".

Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 Documentation/devicetree/bindings/net/fsl-fec.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
index 8a2c7b5..4da148d 100644
--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -16,6 +16,12 @@ Optional properties:
 - phy-handle : phandle to the PHY device connected to this device.
 - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
   Use instead of phy-handle.
+- fsl,num_tx_queues : The property is valid for enet-avb IP, which supports
+  hw multi queues. Should specify the tx queue number, otherwise set tx queue
+  number to 1.
+- fsl,num_rx_queues : The property is valid for enet-avb IP, which supports
+  hw multi queues. Should specify the rx queue number, otherwise set rx queue
+  number to 1.
 
 Optional subnodes:
 - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
-- 
1.9.1

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

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 11/11] ARM: dts: imx6sx: add multi-queue support enet
  2014-09-03 20:38 ` Frank Li
@ 2014-09-03 20:38   ` Frank Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li

Enable 3 queues suppport for ethernet

Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 arch/arm/boot/dts/imx6sx.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index f4b9da6..1722748 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -776,6 +776,8 @@
 					 <&clks IMX6SX_CLK_ENET_PTP>;
 				clock-names = "ipg", "ahb", "ptp",
 					      "enet_clk_ref", "enet_out";
+				fsl,num_tx_queues=<3>;
+				fsl,num_rx_queues=<3>;
 				status = "disabled";
                         };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [Patch net-next 11/11] ARM: dts: imx6sx: add multi-queue support enet
@ 2014-09-03 20:38   ` Frank Li
  0 siblings, 0 replies; 46+ messages in thread
From: Frank Li @ 2014-09-03 20:38 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li

Enable 3 queues suppport for ethernet

Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 arch/arm/boot/dts/imx6sx.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index f4b9da6..1722748 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -776,6 +776,8 @@
 					 <&clks IMX6SX_CLK_ENET_PTP>;
 				clock-names = "ipg", "ahb", "ptp",
 					      "enet_clk_ref", "enet_out";
+				fsl,num_tx_queues=<3>;
+				fsl,num_rx_queues=<3>;
 				status = "disabled";
                         };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 03/11] net:fec: use multiqueue interface to allocate Ethernet device
  2014-09-03 20:38   ` Frank Li
@ 2014-09-03 21:20     ` Florian Fainelli
  -1 siblings, 0 replies; 46+ messages in thread
From: Florian Fainelli @ 2014-09-03 21:20 UTC (permalink / raw)
  To: Frank Li, b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree

On 09/03/2014 01:38 PM, Frank Li wrote:
> From: Fugang Duan <B38611@freescale.com>
> 
> Since i.MX6SX enet-AVB IP support multi queues, so use multi queues
> interface to allocate and set up an Ethernet device.
> 
> Signed-off-by: Fugang Duan <B38611@freescale.com>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
> ---
>  drivers/net/ethernet/freescale/fec.h      |  9 ++++++
>  drivers/net/ethernet/freescale/fec_main.c | 49 ++++++++++++++++++++++++++++++-
>  2 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
> index 635772b..f77ed6f 100644
> --- a/drivers/net/ethernet/freescale/fec.h
> +++ b/drivers/net/ethernet/freescale/fec.h
> @@ -233,6 +233,13 @@ struct bufdesc_ex {
>  /* This device has up to three irqs on some platforms */
>  #define FEC_IRQ_NUM		3
>  
> +/* Maximum number of queues supported
> + * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
> + * User can point the queue number that is less than or equal to 3.
> + */
> +#define FEC_ENET_MAX_TX_QS	3
> +#define FEC_ENET_MAX_RX_QS	3
> +
>  /* The number of Tx and Rx buffers.  These are allocated from the page
>   * pool.  The code may assume these are power of two, so it it best
>   * to keep them that size.
> @@ -278,6 +285,8 @@ struct fec_enet_private {
>  
>  	bool ptp_clk_on;
>  	struct mutex ptp_clk_mutex;
> +	int num_tx_queues;
> +	int num_rx_queues;

unsigned int.

>  
>  	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
>  	unsigned char *tx_bounce[TX_RING_SIZE];
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index ee9f04f..00fcadd 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -2573,6 +2573,39 @@ static void fec_reset_phy(struct platform_device *pdev)
>  #endif /* CONFIG_OF */
>  
>  static int
> +fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int err;
> +
> +	if (!np || !of_device_is_available(np))
> +		return -ENODEV;

This effectively breaks non-DT platform probing, is that intentional?
How about assining *num_tx and *num_rx to 1, and if you find the
property, use it?

> +
> +	/* parse the num of tx and rx queues */
> +	err = of_property_read_u32(np, "fsl,num_tx_queues", num_tx);
> +	err |= of_property_read_u32(np, "fsl,num_rx_queues", num_rx);
> +	if (err) {
> +		*num_tx = 1;
> +		*num_rx = 1;
> +		return 0;
> +	}
> +
> +	if (*num_tx < 1 || *num_tx > FEC_ENET_MAX_TX_QS) {
> +		dev_err(&pdev->dev, "num_tx(=%d) greater than MAX_TX_QS(=%d)\n",
> +			*num_tx, FEC_ENET_MAX_TX_QS);
> +		return -EINVAL;
> +	}

You are dealing with two error conditions here, *num_tx == 0 and *num_tx
> FEC_ENET_MAX_TX_QS, so the message should not be "greater than"

> +
> +	if (*num_rx < 1 || *num_rx > FEC_ENET_MAX_RX_QS) {
> +		dev_err(&pdev->dev, "num_rx(=%d) greater than MAX_RX_QS(=%d)\n",
> +			*num_rx, FEC_ENET_MAX_RX_QS);
> +		return -EINVAL;
> +	}

Same here.

> +
> +	return 0;
> +}
> +
> +static int
>  fec_probe(struct platform_device *pdev)
>  {
>  	struct fec_enet_private *fep;
> @@ -2583,13 +2616,23 @@ fec_probe(struct platform_device *pdev)
>  	const struct of_device_id *of_id;
>  	static int dev_id;
>  	struct device_node *np = pdev->dev.of_node, *phy_node;
> +	int num_tx_qs = 1;
> +	int num_rx_qs = 1;
>  
>  	of_id = of_match_device(fec_dt_ids, &pdev->dev);
>  	if (of_id)
>  		pdev->id_entry = of_id->data;
>  
> +	if (pdev->id_entry &&
> +	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_AVB)) {
> +		ret = fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
> +		if (ret)
> +			return ret;
> +	}

This should be made a void function in order no to break non-DT probing
as mentioned before.

> +
>  	/* Init network device */
> -	ndev = alloc_etherdev(sizeof(struct fec_enet_private));
> +	ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
> +				  num_tx_qs, num_rx_qs);
>  	if (!ndev)
>  		return -ENOMEM;
>  
> @@ -2598,6 +2641,10 @@ fec_probe(struct platform_device *pdev)
>  	/* setup board info structure */
>  	fep = netdev_priv(ndev);
>  
> +	fep->num_rx_queues = num_rx_qs;
> +	fep->num_tx_queues = num_tx_qs;
> +	netif_set_real_num_rx_queues(ndev, num_rx_qs);

How about netif_set_real_num_tx_queues? This is probably useless anyway
because you already allocated this network device with the correct
(supposedly) number of TX and RX queues coming from the platform
configuration data.

> +
>  #if !defined(CONFIG_M5272)
>  	/* default enable pause frame auto negotiation */
>  	if (pdev->id_entry &&
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 03/11] net:fec: use multiqueue interface to allocate Ethernet device
@ 2014-09-03 21:20     ` Florian Fainelli
  0 siblings, 0 replies; 46+ messages in thread
From: Florian Fainelli @ 2014-09-03 21:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/03/2014 01:38 PM, Frank Li wrote:
> From: Fugang Duan <B38611@freescale.com>
> 
> Since i.MX6SX enet-AVB IP support multi queues, so use multi queues
> interface to allocate and set up an Ethernet device.
> 
> Signed-off-by: Fugang Duan <B38611@freescale.com>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
> ---
>  drivers/net/ethernet/freescale/fec.h      |  9 ++++++
>  drivers/net/ethernet/freescale/fec_main.c | 49 ++++++++++++++++++++++++++++++-
>  2 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
> index 635772b..f77ed6f 100644
> --- a/drivers/net/ethernet/freescale/fec.h
> +++ b/drivers/net/ethernet/freescale/fec.h
> @@ -233,6 +233,13 @@ struct bufdesc_ex {
>  /* This device has up to three irqs on some platforms */
>  #define FEC_IRQ_NUM		3
>  
> +/* Maximum number of queues supported
> + * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
> + * User can point the queue number that is less than or equal to 3.
> + */
> +#define FEC_ENET_MAX_TX_QS	3
> +#define FEC_ENET_MAX_RX_QS	3
> +
>  /* The number of Tx and Rx buffers.  These are allocated from the page
>   * pool.  The code may assume these are power of two, so it it best
>   * to keep them that size.
> @@ -278,6 +285,8 @@ struct fec_enet_private {
>  
>  	bool ptp_clk_on;
>  	struct mutex ptp_clk_mutex;
> +	int num_tx_queues;
> +	int num_rx_queues;

unsigned int.

>  
>  	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
>  	unsigned char *tx_bounce[TX_RING_SIZE];
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index ee9f04f..00fcadd 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -2573,6 +2573,39 @@ static void fec_reset_phy(struct platform_device *pdev)
>  #endif /* CONFIG_OF */
>  
>  static int
> +fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	int err;
> +
> +	if (!np || !of_device_is_available(np))
> +		return -ENODEV;

This effectively breaks non-DT platform probing, is that intentional?
How about assining *num_tx and *num_rx to 1, and if you find the
property, use it?

> +
> +	/* parse the num of tx and rx queues */
> +	err = of_property_read_u32(np, "fsl,num_tx_queues", num_tx);
> +	err |= of_property_read_u32(np, "fsl,num_rx_queues", num_rx);
> +	if (err) {
> +		*num_tx = 1;
> +		*num_rx = 1;
> +		return 0;
> +	}
> +
> +	if (*num_tx < 1 || *num_tx > FEC_ENET_MAX_TX_QS) {
> +		dev_err(&pdev->dev, "num_tx(=%d) greater than MAX_TX_QS(=%d)\n",
> +			*num_tx, FEC_ENET_MAX_TX_QS);
> +		return -EINVAL;
> +	}

You are dealing with two error conditions here, *num_tx == 0 and *num_tx
> FEC_ENET_MAX_TX_QS, so the message should not be "greater than"

> +
> +	if (*num_rx < 1 || *num_rx > FEC_ENET_MAX_RX_QS) {
> +		dev_err(&pdev->dev, "num_rx(=%d) greater than MAX_RX_QS(=%d)\n",
> +			*num_rx, FEC_ENET_MAX_RX_QS);
> +		return -EINVAL;
> +	}

Same here.

> +
> +	return 0;
> +}
> +
> +static int
>  fec_probe(struct platform_device *pdev)
>  {
>  	struct fec_enet_private *fep;
> @@ -2583,13 +2616,23 @@ fec_probe(struct platform_device *pdev)
>  	const struct of_device_id *of_id;
>  	static int dev_id;
>  	struct device_node *np = pdev->dev.of_node, *phy_node;
> +	int num_tx_qs = 1;
> +	int num_rx_qs = 1;
>  
>  	of_id = of_match_device(fec_dt_ids, &pdev->dev);
>  	if (of_id)
>  		pdev->id_entry = of_id->data;
>  
> +	if (pdev->id_entry &&
> +	    (pdev->id_entry->driver_data & FEC_QUIRK_HAS_AVB)) {
> +		ret = fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
> +		if (ret)
> +			return ret;
> +	}

This should be made a void function in order no to break non-DT probing
as mentioned before.

> +
>  	/* Init network device */
> -	ndev = alloc_etherdev(sizeof(struct fec_enet_private));
> +	ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
> +				  num_tx_qs, num_rx_qs);
>  	if (!ndev)
>  		return -ENOMEM;
>  
> @@ -2598,6 +2641,10 @@ fec_probe(struct platform_device *pdev)
>  	/* setup board info structure */
>  	fep = netdev_priv(ndev);
>  
> +	fep->num_rx_queues = num_rx_qs;
> +	fep->num_tx_queues = num_tx_qs;
> +	netif_set_real_num_rx_queues(ndev, num_rx_qs);

How about netif_set_real_num_tx_queues? This is probably useless anyway
because you already allocated this network device with the correct
(supposedly) number of TX and RX queues coming from the platform
configuration data.

> +
>  #if !defined(CONFIG_M5272)
>  	/* default enable pause frame auto negotiation */
>  	if (pdev->id_entry &&
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 04/11] net:fec: add multiqueue support
  2014-09-03 20:38     ` Frank Li
@ 2014-09-03 21:27       ` Florian Fainelli
  -1 siblings, 0 replies; 46+ messages in thread
From: Florian Fainelli @ 2014-09-03 21:27 UTC (permalink / raw)
  To: Frank Li, b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree

On 09/03/2014 01:38 PM, Frank Li wrote:
> From: Fugang Duan <B38611@freescale.com>
> 
> Add multiqueue support, which is compatible with previous single queue
> driver for FEC/ENET IPs.
> 
> By default, the tx/rx queue number is 1, user can config the queue number
> at DTS file like this:
> 	fsl,num_tx_queues=<3>;
> 	fsl,num_rx_queues=<3>;
> 
> Ethernet multiqueue mechanism can improve performance in SMP system.
> For single hw queue, multiqueue can balance cpu loading.
> For multi hw queues, multiple cores can process network packets in parallel,
> and refer the article for the detail advantage for multiqueue:
> http://vger.kernel.org/~davem/davem_nyc09.pdf

You should probably split that patch in a minimum of two, or more
different parts.

Two parts:

- add TX multiqueue support
- add RX multiqueue support

More parts:

- prepare for TX multiqueue (introduce queue structure, definitions)
- transition TX path to use queue 0
- add support for the two other TX queues
- prepare for RX multiqueue (introduce queue structure, definitions)
- prepare for multiqueue, hardcode RX path to use queue 0
- add support for the two other RX queues

The number of changes are extremely hard to review...
--
Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 04/11] net:fec: add multiqueue support
@ 2014-09-03 21:27       ` Florian Fainelli
  0 siblings, 0 replies; 46+ messages in thread
From: Florian Fainelli @ 2014-09-03 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/03/2014 01:38 PM, Frank Li wrote:
> From: Fugang Duan <B38611@freescale.com>
> 
> Add multiqueue support, which is compatible with previous single queue
> driver for FEC/ENET IPs.
> 
> By default, the tx/rx queue number is 1, user can config the queue number
> at DTS file like this:
> 	fsl,num_tx_queues=<3>;
> 	fsl,num_rx_queues=<3>;
> 
> Ethernet multiqueue mechanism can improve performance in SMP system.
> For single hw queue, multiqueue can balance cpu loading.
> For multi hw queues, multiple cores can process network packets in parallel,
> and refer the article for the detail advantage for multiqueue:
> http://vger.kernel.org/~davem/davem_nyc09.pdf

You should probably split that patch in a minimum of two, or more
different parts.

Two parts:

- add TX multiqueue support
- add RX multiqueue support

More parts:

- prepare for TX multiqueue (introduce queue structure, definitions)
- transition TX path to use queue 0
- add support for the two other TX queues
- prepare for RX multiqueue (introduce queue structure, definitions)
- prepare for multiqueue, hardcode RX path to use queue 0
- add support for the two other RX queues

The number of changes are extremely hard to review...
--
Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 04/11] net:fec: add multiqueue support
  2014-09-03 21:27       ` Florian Fainelli
@ 2014-09-04  3:41           ` Zhi Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-04  3:41 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Frank Li, Duan Fugang-B38611, David Miller,
	netdev-u79uwXL29TY76Z2rM5mHXA, Shawn Guo,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Wed, Sep 3, 2014 at 4:27 PM, Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 09/03/2014 01:38 PM, Frank Li wrote:
>> From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
>>
>> Add multiqueue support, which is compatible with previous single queue
>> driver for FEC/ENET IPs.
>>
>> By default, the tx/rx queue number is 1, user can config the queue number
>> at DTS file like this:
>>       fsl,num_tx_queues=<3>;
>>       fsl,num_rx_queues=<3>;
>>
>> Ethernet multiqueue mechanism can improve performance in SMP system.
>> For single hw queue, multiqueue can balance cpu loading.
>> For multi hw queues, multiple cores can process network packets in parallel,
>> and refer the article for the detail advantage for multiqueue:
>> http://vger.kernel.org/~davem/davem_nyc09.pdf
>
> You should probably split that patch in a minimum of two, or more
> different parts.
>
> Two parts:
>
> - add TX multiqueue support
> - add RX multiqueue support
>

I understood your concern.
We also need consider logical integration.

Separate this patch just reduce changed lines in a patch.
Most of this patch change is from fep-> to txq-> or rxq->

best regards
Frank Li

> More parts:
>
> - prepare for TX multiqueue (introduce queue structure, definitions)
> - transition TX path to use queue 0
> - add support for the two other TX queues
> - prepare for RX multiqueue (introduce queue structure, definitions)
> - prepare for multiqueue, hardcode RX path to use queue 0
> - add support for the two other RX queues
>
> The number of changes are extremely hard to review...
> --
> Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 04/11] net:fec: add multiqueue support
@ 2014-09-04  3:41           ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-04  3:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 3, 2014 at 4:27 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 09/03/2014 01:38 PM, Frank Li wrote:
>> From: Fugang Duan <B38611@freescale.com>
>>
>> Add multiqueue support, which is compatible with previous single queue
>> driver for FEC/ENET IPs.
>>
>> By default, the tx/rx queue number is 1, user can config the queue number
>> at DTS file like this:
>>       fsl,num_tx_queues=<3>;
>>       fsl,num_rx_queues=<3>;
>>
>> Ethernet multiqueue mechanism can improve performance in SMP system.
>> For single hw queue, multiqueue can balance cpu loading.
>> For multi hw queues, multiple cores can process network packets in parallel,
>> and refer the article for the detail advantage for multiqueue:
>> http://vger.kernel.org/~davem/davem_nyc09.pdf
>
> You should probably split that patch in a minimum of two, or more
> different parts.
>
> Two parts:
>
> - add TX multiqueue support
> - add RX multiqueue support
>

I understood your concern.
We also need consider logical integration.

Separate this patch just reduce changed lines in a patch.
Most of this patch change is from fep-> to txq-> or rxq->

best regards
Frank Li

> More parts:
>
> - prepare for TX multiqueue (introduce queue structure, definitions)
> - transition TX path to use queue 0
> - add support for the two other TX queues
> - prepare for RX multiqueue (introduce queue structure, definitions)
> - prepare for multiqueue, hardcode RX path to use queue 0
> - add support for the two other RX queues
>
> The number of changes are extremely hard to review...
> --
> Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 04/11] net:fec: add multiqueue support
  2014-09-04  3:41           ` Zhi Li
@ 2014-09-04  4:09             ` Florian Fainelli
  -1 siblings, 0 replies; 46+ messages in thread
From: Florian Fainelli @ 2014-09-04  4:09 UTC (permalink / raw)
  To: Zhi Li
  Cc: Frank Li, Duan Fugang-B38611, David Miller, netdev, Shawn Guo,
	linux-arm-kernel, devicetree

2014-09-03 20:41 GMT-07:00 Zhi Li <lznuaa@gmail.com>:
> On Wed, Sep 3, 2014 at 4:27 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 09/03/2014 01:38 PM, Frank Li wrote:
>>> From: Fugang Duan <B38611@freescale.com>
>>>
>>> Add multiqueue support, which is compatible with previous single queue
>>> driver for FEC/ENET IPs.
>>>
>>> By default, the tx/rx queue number is 1, user can config the queue number
>>> at DTS file like this:
>>>       fsl,num_tx_queues=<3>;
>>>       fsl,num_rx_queues=<3>;
>>>
>>> Ethernet multiqueue mechanism can improve performance in SMP system.
>>> For single hw queue, multiqueue can balance cpu loading.
>>> For multi hw queues, multiple cores can process network packets in parallel,
>>> and refer the article for the detail advantage for multiqueue:
>>> http://vger.kernel.org/~davem/davem_nyc09.pdf
>>
>> You should probably split that patch in a minimum of two, or more
>> different parts.
>>
>> Two parts:
>>
>> - add TX multiqueue support
>> - add RX multiqueue support
>>
>
> I understood your concern.
> We also need consider logical integration.

Sure, hence the reason why I suggest you make it happen in different
parts, what you can do is make sure that you parse "fsl,num_tx_queues"
and "fsl,num_rx_queues" as one of the last patches in this patch
series. That way, we achieve a logical breakdown of the changes and
only support and enable multiqueue when the driver is ready.

>
> Separate this patch just reduce changed lines in a patch.

That is exactly my point, right now there is too much churn to make a
reviewer able to spot potential problems.

> Most of this patch change is from fep-> to txq-> or rxq->
>
> best regards
> Frank Li
>
>> More parts:
>>
>> - prepare for TX multiqueue (introduce queue structure, definitions)
>> - transition TX path to use queue 0
>> - add support for the two other TX queues
>> - prepare for RX multiqueue (introduce queue structure, definitions)
>> - prepare for multiqueue, hardcode RX path to use queue 0
>> - add support for the two other RX queues
>>
>> The number of changes are extremely hard to review...
>> --
>> Florian



-- 
Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 04/11] net:fec: add multiqueue support
@ 2014-09-04  4:09             ` Florian Fainelli
  0 siblings, 0 replies; 46+ messages in thread
From: Florian Fainelli @ 2014-09-04  4:09 UTC (permalink / raw)
  To: linux-arm-kernel

2014-09-03 20:41 GMT-07:00 Zhi Li <lznuaa@gmail.com>:
> On Wed, Sep 3, 2014 at 4:27 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 09/03/2014 01:38 PM, Frank Li wrote:
>>> From: Fugang Duan <B38611@freescale.com>
>>>
>>> Add multiqueue support, which is compatible with previous single queue
>>> driver for FEC/ENET IPs.
>>>
>>> By default, the tx/rx queue number is 1, user can config the queue number
>>> at DTS file like this:
>>>       fsl,num_tx_queues=<3>;
>>>       fsl,num_rx_queues=<3>;
>>>
>>> Ethernet multiqueue mechanism can improve performance in SMP system.
>>> For single hw queue, multiqueue can balance cpu loading.
>>> For multi hw queues, multiple cores can process network packets in parallel,
>>> and refer the article for the detail advantage for multiqueue:
>>> http://vger.kernel.org/~davem/davem_nyc09.pdf
>>
>> You should probably split that patch in a minimum of two, or more
>> different parts.
>>
>> Two parts:
>>
>> - add TX multiqueue support
>> - add RX multiqueue support
>>
>
> I understood your concern.
> We also need consider logical integration.

Sure, hence the reason why I suggest you make it happen in different
parts, what you can do is make sure that you parse "fsl,num_tx_queues"
and "fsl,num_rx_queues" as one of the last patches in this patch
series. That way, we achieve a logical breakdown of the changes and
only support and enable multiqueue when the driver is ready.

>
> Separate this patch just reduce changed lines in a patch.

That is exactly my point, right now there is too much churn to make a
reviewer able to spot potential problems.

> Most of this patch change is from fep-> to txq-> or rxq->
>
> best regards
> Frank Li
>
>> More parts:
>>
>> - prepare for TX multiqueue (introduce queue structure, definitions)
>> - transition TX path to use queue 0
>> - add support for the two other TX queues
>> - prepare for RX multiqueue (introduce queue structure, definitions)
>> - prepare for multiqueue, hardcode RX path to use queue 0
>> - add support for the two other RX queues
>>
>> The number of changes are extremely hard to review...
>> --
>> Florian



-- 
Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
  2014-09-03 20:38     ` Frank Li
  (?)
@ 2014-09-04  8:50     ` David Laight
  2014-09-04  9:11       ` fugang.duan at freescale.com
  -1 siblings, 1 reply; 46+ messages in thread
From: David Laight @ 2014-09-04  8:50 UTC (permalink / raw)
  To: linux-arm-kernel

From: Frank Li
> From: Fugang Duan <B38611@freescale.com>
> 
> Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
> The previous enet IP for ARM platform has 16 bytes alignment for tx
> DMA transfer.

Do you mean rx or tx here? or both??

And can we beat up the hardware designers to stop these restrictions
on rx (in particular) ethernet buffer alignments?
A device isn't suitable for ethernet unless is can write the destination
mac address to a 4n+2 boundary.

	David

> 64 is the an integral number of 16, so change alignment
> to 64 bytes for all ARM platform, which don't impact the performance
> of previous platform.
> 
> Signed-off-by: Fugang Duan <B38611@freescale.com>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
> ---
>  drivers/net/ethernet/freescale/fec_main.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index a232245..b388e29f 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -65,7 +65,7 @@
>  static void set_multicast_list(struct net_device *ndev);
> 
>  #if defined(CONFIG_ARM)
> -#define FEC_ALIGNMENT	0xf
> +#define FEC_ALIGNMENT	0x3f
>  #else
>  #define FEC_ALIGNMENT	0x3
>  #endif
> --
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
  2014-09-04  8:50     ` David Laight
@ 2014-09-04  9:11       ` fugang.duan at freescale.com
  2014-09-04  9:18         ` David Laight
  0 siblings, 1 reply; 46+ messages in thread
From: fugang.duan at freescale.com @ 2014-09-04  9:11 UTC (permalink / raw)
  To: linux-arm-kernel

From: David Laight <David.Laight@ACULAB.COM> Sent: Thursday, September 04, 2014 4:51 PM
>To: Li Frank-B20596; Duan Fugang-B38611; davem at davemloft.net;
>netdev at vger.kernel.org; lznuaa at gmail.com
>Cc: shawn.guo at linaro.org; linux-arm-kernel at lists.infradead.org;
>devicetree at vger.kernel.org; Duan Fugang-B38611
>Subject: RE: [Patch net-next 08/11] net:fec: change FEC alignment to 64
>bytes for ARM platform
>
>From: Frank Li
>> From: Fugang Duan <B38611@freescale.com>
>>
>> Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
>> The previous enet IP for ARM platform has 16 bytes alignment for tx
>> DMA transfer.
>
>Do you mean rx or tx here? or both??
>
>And can we beat up the hardware designers to stop these restrictions on rx
>(in particular) ethernet buffer alignments?
>A device isn't suitable for ethernet unless is can write the destination
>mac address to a 4n+2 boundary.
>
>	David
>
Hi, David,

For previous enet IP there has 16 bytes data buffer alignment limitation for tx & rx DMA transfer.
For imx6sx enet-avb IP, there has 64 bytes data buffer alignment limitation for rx DMA transfer, byte alignment for tx data
Buffer for DMA transfer.

I think rx data buffer alignment limitation don't introduce performance drop, is not complex for sw implemention. Anyway,
We can request IC designer to remove the limitation for future chips.

Thanks,
Andy

>> 64 is the an integral number of 16, so change alignment to 64 bytes
>> for all ARM platform, which don't impact the performance of previous
>> platform.
>>
>> Signed-off-by: Fugang Duan <B38611@freescale.com>
>> Signed-off-by: Frank Li <Frank.Li@freescale.com>
>> ---
>>  drivers/net/ethernet/freescale/fec_main.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/freescale/fec_main.c
>> b/drivers/net/ethernet/freescale/fec_main.c
>> index a232245..b388e29f 100644
>> --- a/drivers/net/ethernet/freescale/fec_main.c
>> +++ b/drivers/net/ethernet/freescale/fec_main.c
>> @@ -65,7 +65,7 @@
>>  static void set_multicast_list(struct net_device *ndev);
>>
>>  #if defined(CONFIG_ARM)
>> -#define FEC_ALIGNMENT	0xf
>> +#define FEC_ALIGNMENT	0x3f
>>  #else
>>  #define FEC_ALIGNMENT	0x3
>>  #endif
>> --
>> 1.9.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo at vger.kernel.org More majordomo info
>> at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
  2014-09-04  9:11       ` fugang.duan at freescale.com
@ 2014-09-04  9:18         ` David Laight
  2014-09-04 14:17             ` Zhi Li
  0 siblings, 1 reply; 46+ messages in thread
From: David Laight @ 2014-09-04  9:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: fugang.duan@freescale.com
> >From: Frank Li
> >> From: Fugang Duan <B38611@freescale.com>
> >>
> >> Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
> >> The previous enet IP for ARM platform has 16 bytes alignment for tx
> >> DMA transfer.
> >
> >Do you mean rx or tx here? or both??
> >
> >And can we beat up the hardware designers to stop these restrictions on rx
> >(in particular) ethernet buffer alignments?
> >A device isn't suitable for ethernet unless is can write the destination
> >mac address to a 4n+2 boundary.
> >
> >	David
> >
> Hi, David,
> 
> For previous enet IP there has 16 bytes data buffer alignment limitation for tx & rx DMA transfer.
> For imx6sx enet-avb IP, there has 64 bytes data buffer alignment limitation for rx DMA transfer, byte
> alignment for tx data
> Buffer for DMA transfer.
> 
> I think rx data buffer alignment limitation don't introduce performance drop, is not complex for sw
> implemention. Anyway,
> We can request IC designer to remove the limitation for future chips.

The 'problem' is that you need the IP header to be 32bit aligned.
If the dma buffer has to be aligned then the code either has to do an expensive
misaligned copy of the entire frame (at some point the entire frame is almost
certainly all copied into an aligned buffer), or take the hit of misaligned
memory accesses (which might have to be emulated with byte transfers).

The rx buffer can be aligned provided the hardware skips (or writes junk to)
the first two bytes.

	David

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 04/11] net:fec: add multiqueue support
  2014-09-04  4:09             ` Florian Fainelli
@ 2014-09-04 14:02               ` Zhi Li
  -1 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-04 14:02 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Frank Li, Duan Fugang-B38611, David Miller, netdev, Shawn Guo,
	linux-arm-kernel, devicetree

On Wed, Sep 3, 2014 at 11:09 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> 2014-09-03 20:41 GMT-07:00 Zhi Li <lznuaa@gmail.com>:
>> On Wed, Sep 3, 2014 at 4:27 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>>> On 09/03/2014 01:38 PM, Frank Li wrote:
>>>> From: Fugang Duan <B38611@freescale.com>
>>>>
>>>> Add multiqueue support, which is compatible with previous single queue
>>>> driver for FEC/ENET IPs.
>>>>
>>>> By default, the tx/rx queue number is 1, user can config the queue number
>>>> at DTS file like this:
>>>>       fsl,num_tx_queues=<3>;
>>>>       fsl,num_rx_queues=<3>;
>>>>
>>>> Ethernet multiqueue mechanism can improve performance in SMP system.
>>>> For single hw queue, multiqueue can balance cpu loading.
>>>> For multi hw queues, multiple cores can process network packets in parallel,
>>>> and refer the article for the detail advantage for multiqueue:
>>>> http://vger.kernel.org/~davem/davem_nyc09.pdf
>>>
>>> You should probably split that patch in a minimum of two, or more
>>> different parts.
>>>
>>> Two parts:
>>>
>>> - add TX multiqueue support
>>> - add RX multiqueue support
>>>
>>
>> I understood your concern.
>> We also need consider logical integration.
>
> Sure, hence the reason why I suggest you make it happen in different
> parts, what you can do is make sure that you parse "fsl,num_tx_queues"
> and "fsl,num_rx_queues" as one of the last patches in this patch
> series. That way, we achieve a logical breakdown of the changes and
> only support and enable multiqueue when the driver is ready.

I can remove this part to "net:fec: add enet-avb IP support", last
patch just change DT file,
which come into difference maintainer.

But RX and TX is difficult to separate because RX and TX share some
function, such as
fec_enet_get_nextdesc

If I change TX part,  fec_enet_get_nextdesc will add a parameter. If
that, all RX part need be
changed.

>
>>
>> Separate this patch just reduce changed lines in a patch.
>
> That is exactly my point, right now there is too much churn to make a
> reviewer able to spot potential problems.
>
>> Most of this patch change is from fep-> to txq-> or rxq->
>>
>> best regards
>> Frank Li
>>
>>> More parts:
>>>
>>> - prepare for TX multiqueue (introduce queue structure, definitions)
>>> - transition TX path to use queue 0
>>> - add support for the two other TX queues
>>> - prepare for RX multiqueue (introduce queue structure, definitions)
>>> - prepare for multiqueue, hardcode RX path to use queue 0
>>> - add support for the two other RX queues
>>>
>>> The number of changes are extremely hard to review...
>>> --
>>> Florian
>
>
>
> --
> Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 04/11] net:fec: add multiqueue support
@ 2014-09-04 14:02               ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-04 14:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 3, 2014 at 11:09 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> 2014-09-03 20:41 GMT-07:00 Zhi Li <lznuaa@gmail.com>:
>> On Wed, Sep 3, 2014 at 4:27 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>>> On 09/03/2014 01:38 PM, Frank Li wrote:
>>>> From: Fugang Duan <B38611@freescale.com>
>>>>
>>>> Add multiqueue support, which is compatible with previous single queue
>>>> driver for FEC/ENET IPs.
>>>>
>>>> By default, the tx/rx queue number is 1, user can config the queue number
>>>> at DTS file like this:
>>>>       fsl,num_tx_queues=<3>;
>>>>       fsl,num_rx_queues=<3>;
>>>>
>>>> Ethernet multiqueue mechanism can improve performance in SMP system.
>>>> For single hw queue, multiqueue can balance cpu loading.
>>>> For multi hw queues, multiple cores can process network packets in parallel,
>>>> and refer the article for the detail advantage for multiqueue:
>>>> http://vger.kernel.org/~davem/davem_nyc09.pdf
>>>
>>> You should probably split that patch in a minimum of two, or more
>>> different parts.
>>>
>>> Two parts:
>>>
>>> - add TX multiqueue support
>>> - add RX multiqueue support
>>>
>>
>> I understood your concern.
>> We also need consider logical integration.
>
> Sure, hence the reason why I suggest you make it happen in different
> parts, what you can do is make sure that you parse "fsl,num_tx_queues"
> and "fsl,num_rx_queues" as one of the last patches in this patch
> series. That way, we achieve a logical breakdown of the changes and
> only support and enable multiqueue when the driver is ready.

I can remove this part to "net:fec: add enet-avb IP support", last
patch just change DT file,
which come into difference maintainer.

But RX and TX is difficult to separate because RX and TX share some
function, such as
fec_enet_get_nextdesc

If I change TX part,  fec_enet_get_nextdesc will add a parameter. If
that, all RX part need be
changed.

>
>>
>> Separate this patch just reduce changed lines in a patch.
>
> That is exactly my point, right now there is too much churn to make a
> reviewer able to spot potential problems.
>
>> Most of this patch change is from fep-> to txq-> or rxq->
>>
>> best regards
>> Frank Li
>>
>>> More parts:
>>>
>>> - prepare for TX multiqueue (introduce queue structure, definitions)
>>> - transition TX path to use queue 0
>>> - add support for the two other TX queues
>>> - prepare for RX multiqueue (introduce queue structure, definitions)
>>> - prepare for multiqueue, hardcode RX path to use queue 0
>>> - add support for the two other RX queues
>>>
>>> The number of changes are extremely hard to review...
>>> --
>>> Florian
>
>
>
> --
> Florian

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
  2014-09-04  9:18         ` David Laight
@ 2014-09-04 14:17             ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-04 14:17 UTC (permalink / raw)
  To: David Laight
  Cc: fugang.duan, Frank.Li, davem, netdev, shawn.guo,
	linux-arm-kernel, devicetree

On Thu, Sep 4, 2014 at 4:18 AM, David Laight <David.Laight@aculab.com> wrote:
> From: fugang.duan@freescale.com
>> >From: Frank Li
>> >> From: Fugang Duan <B38611@freescale.com>
>> >>
>> >> Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
>> >> The previous enet IP for ARM platform has 16 bytes alignment for tx
>> >> DMA transfer.
>> >
>> >Do you mean rx or tx here? or both??
>> >
>> >And can we beat up the hardware designers to stop these restrictions on rx
>> >(in particular) ethernet buffer alignments?
>> >A device isn't suitable for ethernet unless is can write the destination
>> >mac address to a 4n+2 boundary.
>> >
>> >     David
>> >
>> Hi, David,
>>
>> For previous enet IP there has 16 bytes data buffer alignment limitation for tx & rx DMA transfer.
>> For imx6sx enet-avb IP, there has 64 bytes data buffer alignment limitation for rx DMA transfer, byte
>> alignment for tx data
>> Buffer for DMA transfer.
>>
>> I think rx data buffer alignment limitation don't introduce performance drop, is not complex for sw
>> implemention. Anyway,
>> We can request IC designer to remove the limitation for future chips.
>
> The 'problem' is that you need the IP header to be 32bit aligned.
> If the dma buffer has to be aligned then the code either has to do an expensive
> misaligned copy of the entire frame (at some point the entire frame is almost
> certainly all copied into an aligned buffer), or take the hit of misaligned
> memory accesses (which might have to be emulated with byte transfers).
>
> The rx buffer can be aligned provided the hardware skips (or writes junk to)
> the first two bytes.

ENET IP have feature to add additional 2 byte when save data to memory.

RX FIFO Shift-16
When this field is set, the actual frame data starts at bit 16 of the
first word read from the RX FIFO aligning
the Ethernet payload on a 32-bit boundary.
NOTE: This function only affects the FIFO storage and has no influence
on the statistics, which use the
actual length of the frame received.
0 Disabled.
1 Instructs the MAC to write two additional bytes in front of each
frame received into the RX FIFO.

i.MX6SX,
          Remove TX alignment requirement.
          But RX and DMA BD address is 64byte aligment.


best regards
Frank Li



>
>         David
>
>
>

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
@ 2014-09-04 14:17             ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-04 14:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Sep 4, 2014 at 4:18 AM, David Laight <David.Laight@aculab.com> wrote:
> From: fugang.duan at freescale.com
>> >From: Frank Li
>> >> From: Fugang Duan <B38611@freescale.com>
>> >>
>> >> Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
>> >> The previous enet IP for ARM platform has 16 bytes alignment for tx
>> >> DMA transfer.
>> >
>> >Do you mean rx or tx here? or both??
>> >
>> >And can we beat up the hardware designers to stop these restrictions on rx
>> >(in particular) ethernet buffer alignments?
>> >A device isn't suitable for ethernet unless is can write the destination
>> >mac address to a 4n+2 boundary.
>> >
>> >     David
>> >
>> Hi, David,
>>
>> For previous enet IP there has 16 bytes data buffer alignment limitation for tx & rx DMA transfer.
>> For imx6sx enet-avb IP, there has 64 bytes data buffer alignment limitation for rx DMA transfer, byte
>> alignment for tx data
>> Buffer for DMA transfer.
>>
>> I think rx data buffer alignment limitation don't introduce performance drop, is not complex for sw
>> implemention. Anyway,
>> We can request IC designer to remove the limitation for future chips.
>
> The 'problem' is that you need the IP header to be 32bit aligned.
> If the dma buffer has to be aligned then the code either has to do an expensive
> misaligned copy of the entire frame (at some point the entire frame is almost
> certainly all copied into an aligned buffer), or take the hit of misaligned
> memory accesses (which might have to be emulated with byte transfers).
>
> The rx buffer can be aligned provided the hardware skips (or writes junk to)
> the first two bytes.

ENET IP have feature to add additional 2 byte when save data to memory.

RX FIFO Shift-16
When this field is set, the actual frame data starts at bit 16 of the
first word read from the RX FIFO aligning
the Ethernet payload on a 32-bit boundary.
NOTE: This function only affects the FIFO storage and has no influence
on the statistics, which use the
actual length of the frame received.
0 Disabled.
1 Instructs the MAC to write two additional bytes in front of each
frame received into the RX FIFO.

i.MX6SX,
          Remove TX alignment requirement.
          But RX and DMA BD address is 64byte aligment.


best regards
Frank Li



>
>         David
>
>
>

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 00/11] net: fec: imx6sx multiqueue support
       [not found] <5407807e.c26c460a.65d3.71b9SMTPIN_ADDED_BROKEN@mx.google.com>
  2014-09-03 21:02   ` Zhi Li
@ 2014-09-03 21:02   ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-03 21:02 UTC (permalink / raw)
  Cc: Duan Fugang-B38611, David Miller, netdev, Shawn Guo,
	linux-arm-kernel, devicetree, Frank Li

On Wed, Sep 3, 2014 at 3:34 PM,  <y@shlinux1.ap.freescale.net> wrote:
>
>
Sorry! Sent out with wrong sender email address.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 21:02   ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-03 21:02 UTC (permalink / raw)
  Cc: Duan Fugang-B38611, David Miller, netdev, Shawn Guo,
	linux-arm-kernel, devicetree, Frank Li

On Wed, Sep 3, 2014 at 3:34 PM,  <y@shlinux1.ap.freescale.net> wrote:
>
>
Sorry! Sent out with wrong sender email address.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 21:02   ` Zhi Li
  0 siblings, 0 replies; 46+ messages in thread
From: Zhi Li @ 2014-09-03 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 3, 2014 at 3:34 PM,  <y@shlinux1.ap.freescale.net> wrote:
>
>
Sorry! Sent out with wrong sender email address.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 20:34 ` y
  0 siblings, 0 replies; 46+ messages in thread
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li

From: Frank Li <Frank.Li@freescale.com>

These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature. 

Frank Li (3):
  net:fec: add enet-avb IP support
  ARM: Documentation: Update fec dts binding doc
  ARM: dts: imx6sx: add multi-queue support enet

Fugang Duan (8):
  net:fec: add enet refrence clock for i.MX 6SX chip
  net:fec: add enet AVB feature macro define for imx6sx
  net:fec: use multiqueue interface to allocate Ethernet device
  net:fec: add multiqueue support
  net:fec: Disable enet-avb MAC instead of reset MAC
  net:fec: Add fsl,imx6sx-fec  compatible strings
  net:fec: change FEC alignment to 64 bytes for ARM platform
  net:fec: remove unnessary memory copy for address alignment in .xmit()

 Documentation/devicetree/bindings/net/fsl-fec.txt |   6 +
 arch/arm/boot/dts/imx6sx.dtsi                     |   2 +
 drivers/net/ethernet/freescale/fec.h              | 151 +++-
 drivers/net/ethernet/freescale/fec_main.c         | 877 +++++++++++++++-------
 4 files changed, 750 insertions(+), 286 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 20:34 ` y
  0 siblings, 0 replies; 46+ messages in thread
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Frank Li

From: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature. 

Frank Li (3):
  net:fec: add enet-avb IP support
  ARM: Documentation: Update fec dts binding doc
  ARM: dts: imx6sx: add multi-queue support enet

Fugang Duan (8):
  net:fec: add enet refrence clock for i.MX 6SX chip
  net:fec: add enet AVB feature macro define for imx6sx
  net:fec: use multiqueue interface to allocate Ethernet device
  net:fec: add multiqueue support
  net:fec: Disable enet-avb MAC instead of reset MAC
  net:fec: Add fsl,imx6sx-fec  compatible strings
  net:fec: change FEC alignment to 64 bytes for ARM platform
  net:fec: remove unnessary memory copy for address alignment in .xmit()

 Documentation/devicetree/bindings/net/fsl-fec.txt |   6 +
 arch/arm/boot/dts/imx6sx.dtsi                     |   2 +
 drivers/net/ethernet/freescale/fec.h              | 151 +++-
 drivers/net/ethernet/freescale/fec_main.c         | 877 +++++++++++++++-------
 4 files changed, 750 insertions(+), 286 deletions(-)

-- 
1.9.1

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

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 20:34 ` y
  0 siblings, 0 replies; 46+ messages in thread
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
  To: b38611, davem, netdev, lznuaa
  Cc: shawn.guo, linux-arm-kernel, devicetree, Frank Li

From: Frank Li <Frank.Li@freescale.com>

These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature. 

Frank Li (3):
  net:fec: add enet-avb IP support
  ARM: Documentation: Update fec dts binding doc
  ARM: dts: imx6sx: add multi-queue support enet

Fugang Duan (8):
  net:fec: add enet refrence clock for i.MX 6SX chip
  net:fec: add enet AVB feature macro define for imx6sx
  net:fec: use multiqueue interface to allocate Ethernet device
  net:fec: add multiqueue support
  net:fec: Disable enet-avb MAC instead of reset MAC
  net:fec: Add fsl,imx6sx-fec  compatible strings
  net:fec: change FEC alignment to 64 bytes for ARM platform
  net:fec: remove unnessary memory copy for address alignment in .xmit()

 Documentation/devicetree/bindings/net/fsl-fec.txt |   6 +
 arch/arm/boot/dts/imx6sx.dtsi                     |   2 +
 drivers/net/ethernet/freescale/fec.h              | 151 +++-
 drivers/net/ethernet/freescale/fec_main.c         | 877 +++++++++++++++-------
 4 files changed, 750 insertions(+), 286 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
@ 2014-09-03 20:34 ` y
  0 siblings, 0 replies; 46+ messages in thread
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
  To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
  Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Frank Li

From: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>

These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature. 

Frank Li (3):
  net:fec: add enet-avb IP support
  ARM: Documentation: Update fec dts binding doc
  ARM: dts: imx6sx: add multi-queue support enet

Fugang Duan (8):
  net:fec: add enet refrence clock for i.MX 6SX chip
  net:fec: add enet AVB feature macro define for imx6sx
  net:fec: use multiqueue interface to allocate Ethernet device
  net:fec: add multiqueue support
  net:fec: Disable enet-avb MAC instead of reset MAC
  net:fec: Add fsl,imx6sx-fec  compatible strings
  net:fec: change FEC alignment to 64 bytes for ARM platform
  net:fec: remove unnessary memory copy for address alignment in .xmit()

 Documentation/devicetree/bindings/net/fsl-fec.txt |   6 +
 arch/arm/boot/dts/imx6sx.dtsi                     |   2 +
 drivers/net/ethernet/freescale/fec.h              | 151 +++-
 drivers/net/ethernet/freescale/fec_main.c         | 877 +++++++++++++++-------
 4 files changed, 750 insertions(+), 286 deletions(-)

-- 
1.9.1

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

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2014-09-04 14:17 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-03 20:38 [Patch net-next 00/11] net: fec: imx6sx multiqueue support Frank Li
2014-09-03 20:38 ` Frank Li
2014-09-03 20:38 ` [Patch net-next 03/11] net:fec: use multiqueue interface to allocate Ethernet device Frank Li
2014-09-03 20:38   ` Frank Li
2014-09-03 21:20   ` Florian Fainelli
2014-09-03 21:20     ` Florian Fainelli
     [not found] ` <1409776697-1536-1-git-send-email-Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2014-09-03 20:38   ` [Patch net-next 01/11] net:fec: add enet refrence clock for i.MX 6SX chip Frank Li
2014-09-03 20:38     ` Frank Li
2014-09-03 20:38   ` [Patch net-next 02/11] net:fec: add enet AVB feature macro define for imx6sx Frank Li
2014-09-03 20:38     ` Frank Li
2014-09-03 20:38   ` [Patch net-next 04/11] net:fec: add multiqueue support Frank Li
2014-09-03 20:38     ` Frank Li
2014-09-03 21:27     ` Florian Fainelli
2014-09-03 21:27       ` Florian Fainelli
     [not found]       ` <540787B9.8090504-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2014-09-04  3:41         ` Zhi Li
2014-09-04  3:41           ` Zhi Li
2014-09-04  4:09           ` Florian Fainelli
2014-09-04  4:09             ` Florian Fainelli
2014-09-04 14:02             ` Zhi Li
2014-09-04 14:02               ` Zhi Li
2014-09-03 20:38   ` [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform Frank Li
2014-09-03 20:38     ` Frank Li
2014-09-04  8:50     ` David Laight
2014-09-04  9:11       ` fugang.duan at freescale.com
2014-09-04  9:18         ` David Laight
2014-09-04 14:17           ` Zhi Li
2014-09-04 14:17             ` Zhi Li
2014-09-03 20:38   ` [Patch net-next 09/11] net:fec: remove unnessary memory copy for address alignment in .xmit() Frank Li
2014-09-03 20:38     ` Frank Li
2014-09-03 20:38   ` [Patch net-next 10/11] ARM: Documentation: Update fec dts binding doc Frank Li
2014-09-03 20:38     ` Frank Li
2014-09-03 20:38 ` [Patch net-next 05/11] net:fec: Disable enet-avb MAC instead of reset MAC Frank Li
2014-09-03 20:38   ` Frank Li
2014-09-03 20:38 ` [Patch net-next 06/11] net:fec: add enet-avb IP support Frank Li
2014-09-03 20:38   ` Frank Li
2014-09-03 20:38 ` [Patch net-next 07/11] net:fec: Add fsl,imx6sx-fec compatible strings Frank Li
2014-09-03 20:38   ` Frank Li
2014-09-03 20:38 ` [Patch net-next 11/11] ARM: dts: imx6sx: add multi-queue support enet Frank Li
2014-09-03 20:38   ` Frank Li
     [not found] <5407807e.c26c460a.65d3.71b9SMTPIN_ADDED_BROKEN@mx.google.com>
2014-09-03 21:02 ` [Patch net-next 00/11] net: fec: imx6sx multiqueue support Zhi Li
2014-09-03 21:02   ` Zhi Li
2014-09-03 21:02   ` Zhi Li
  -- strict thread matches above, loose matches on Subject: below --
2014-09-03 20:34 y
2014-09-03 20:34 ` y
2014-09-03 20:34 y
2014-09-03 20:34 ` y

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.