All of lore.kernel.org
 help / color / mirror / Atom feed
* [net-next 0/8] stmmac: update to Oct 2011 version (v4)
@ 2011-10-18 10:01 Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 1/8] stmmac: Stop advertising 1000Base capabilties for non GMII iface (V4) Giuseppe CAVALLARO
                   ` (8 more replies)
  0 siblings, 9 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro

This patches update the driver adding the chained
descriptor mode and some new useful fixes.

I've reviewed some patches after the V1/2/3 and added new ones:

 stmmac: allow mtu bigger than 1500 in case of normal desc (V4)
   |-> removed the useless max_mtu init: Thx Eric's feedback

 stmmac: add CHAINED descriptor mode support (V4)
   |-> removed ifdef in the C and added small routines
	specialised for chained/ring modes. See comment
	within the patch itself. Thx David's feedback.

 stmmac: allow mmc usage only if feature actually available (V4)
   |-> added a check if interface is NULL

 stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb.
  |-> another enhancements proposed by Eric (built on top of the
      V3 patches sent today).

 stmmac: use predefined macros for HW cap register fields (V4)
 stmmac: allow mmc usage only if feature actually available (V4)

Let me know if all is ok.

Regards
Peppe

Giuseppe Cavallaro (6):
  stmmac: protect tx process with lock (V4)
  stmmac: update the driver version and doc (V4)
  stmmac: allow mtu bigger than 1500 in case of normal desc (V4)
  stmmac: allow mmc usage only if feature actually available (V4)
  stmmac: add CHAINED descriptor mode support (V4)
  stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb.

Rayagond Kokatanur (1):
  stmmac: use predefined macros for HW cap register fields (V4)

Srinivas Kandagatla (1):
  stmmac: Stop advertising 1000Base capabilties for non GMII iface
    (V4).

 Documentation/networking/stmmac.txt                |   11 +-
 drivers/net/ethernet/stmicro/stmmac/Kconfig        |   18 ++
 drivers/net/ethernet/stmicro/stmmac/Makefile       |    2 +
 drivers/net/ethernet/stmicro/stmmac/chain_mode.c   |  137 ++++++++++++
 drivers/net/ethernet/stmicro/stmmac/common.h       |   43 ++++
 drivers/net/ethernet/stmicro/stmmac/descs_com.h    |  126 +++++++++++
 drivers/net/ethernet/stmicro/stmmac/enh_desc.c     |   22 +--
 drivers/net/ethernet/stmicro/stmmac/norm_desc.c    |   14 +-
 drivers/net/ethernet/stmicro/stmmac/ring_mode.c    |  126 +++++++++++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h       |    5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |   24 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |  223 ++++++++++----------
 12 files changed, 610 insertions(+), 141 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/chain_mode.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/descs_com.h
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode.c

-- 
1.7.4.4

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

* [net-next 1/8] stmmac: Stop advertising 1000Base capabilties for non GMII iface (V4).
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 2/8] stmmac: protect tx process with lock (V4) Giuseppe CAVALLARO
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Srinivas Kandagatla, Giuseppe Cavallaro

From: Srinivas Kandagatla <srinivas.kandagatla@st.com>

This patch stops advertising 1000Base capablities if GMAC is either
configured for MII or RMII mode and on board there is a GPHY plugged on.
Without this patch if an GBit switch is connected on MII interface,
Ethernet stops working at all.

Discovered as part of
https://bugzilla.stlinux.com/show_bug.cgi?id=14148 triage

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index c0ee6b6..229fe44 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -304,7 +304,7 @@ static int stmmac_init_phy(struct net_device *dev)
 	struct phy_device *phydev;
 	char phy_id[MII_BUS_ID_SIZE + 3];
 	char bus_id[MII_BUS_ID_SIZE];
-
+	int interface = priv->plat->interface;
 	priv->oldlink = 0;
 	priv->speed = 0;
 	priv->oldduplex = -1;
@@ -314,14 +314,21 @@ static int stmmac_init_phy(struct net_device *dev)
 		 priv->plat->phy_addr);
 	pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id);
 
-	phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
-			     priv->plat->interface);
+	phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0, interface);
 
 	if (IS_ERR(phydev)) {
 		pr_err("%s: Could not attach to PHY\n", dev->name);
 		return PTR_ERR(phydev);
 	}
 
+	/* Stop Advertising 1000BASE Capability if interface is not GMII */
+	if ((interface) && ((interface == PHY_INTERFACE_MODE_MII) ||
+	    (interface == PHY_INTERFACE_MODE_RMII))) {
+		phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+				      SUPPORTED_Asym_Pause);
+		priv->phydev->advertising = priv->phydev->supported;
+	}
+
 	/*
 	 * Broken HW is sometimes missing the pull-up resistor on the
 	 * MDIO line, which results in reads to non-existent devices returning
-- 
1.7.4.4

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

* [net-next 2/8] stmmac: protect tx process with lock (V4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 1/8] stmmac: Stop advertising 1000Base capabilties for non GMII iface (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 3/8] stmmac: update the driver version and doc (V4) Giuseppe CAVALLARO
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro

This patch fixes a problem raised on Orly ARM SMP platform
where, in case of fragmented frames, the descriptors
in the TX ring resulted broken. This was due to a missing lock
protection in the tx process.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Tested-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h      |    1 +
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |    8 ++++++++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 1434bdb..50e95d8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -70,6 +70,7 @@ struct stmmac_priv {
 
 	u32 msg_enable;
 	spinlock_t lock;
+	spinlock_t tx_lock;
 	int wolopts;
 	int wolenabled;
 	int wol_irq;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 229fe44..d0af002 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -588,6 +588,8 @@ static void stmmac_tx(struct stmmac_priv *priv)
 {
 	unsigned int txsize = priv->dma_tx_size;
 
+	spin_lock(&priv->tx_lock);
+
 	while (priv->dirty_tx != priv->cur_tx) {
 		int last;
 		unsigned int entry = priv->dirty_tx % txsize;
@@ -651,6 +653,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
 		}
 		netif_tx_unlock(priv->dev);
 	}
+	spin_unlock(&priv->tx_lock);
 }
 
 static inline void stmmac_enable_irq(struct stmmac_priv *priv)
@@ -1078,6 +1081,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		return NETDEV_TX_BUSY;
 	}
 
+	spin_lock(&priv->tx_lock);
+
 	entry = priv->cur_tx % txsize;
 
 #ifdef STMMAC_XMIT_DEBUG
@@ -1166,6 +1171,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	priv->hw->dma->enable_dma_transmission(priv->ioaddr);
 
+	spin_unlock(&priv->tx_lock);
+
 	return NETDEV_TX_OK;
 }
 
@@ -1731,6 +1738,7 @@ static int stmmac_probe(struct net_device *dev)
 			"please, use ifconfig or nwhwconfig!\n");
 
 	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->tx_lock);
 
 	ret = register_netdev(dev);
 	if (ret) {
-- 
1.7.4.4

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

* [net-next 3/8] stmmac: update the driver version and doc (V4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 1/8] stmmac: Stop advertising 1000Base capabilties for non GMII iface (V4) Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 2/8] stmmac: protect tx process with lock (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 4/8] stmmac: allow mtu bigger than 1500 in case of normal desc (V4) Giuseppe CAVALLARO
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 Documentation/networking/stmmac.txt          |   11 ++++++++++-
 drivers/net/ethernet/stmicro/stmmac/stmmac.h |    2 +-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt
index 40ec92c..8d67980 100644
--- a/Documentation/networking/stmmac.txt
+++ b/Documentation/networking/stmmac.txt
@@ -76,7 +76,16 @@ core.
 
 4.5) DMA descriptors
 Driver handles both normal and enhanced descriptors. The latter has been only
-tested on DWC Ether MAC 10/100/1000 Universal version 3.41a.
+tested on DWC Ether MAC 10/100/1000 Universal version 3.41a and later.
+
+STMMAC supports DMA descriptor to operate both in dual buffer (RING)
+and linked-list(CHAINED) mode. In RING each descriptor points to two
+data buffer pointers whereas in CHAINED mode they point to only one data
+buffer pointer. RING mode is the default.
+
+In CHAINED mode each descriptor will have pointer to next descriptor in
+the list, hence creating the explicit chaining in the descriptor itself,
+whereas such explicit chaining is not possible in RING mode.
 
 4.6) Ethtool support
 Ethtool is supported. Driver statistics and internal errors can be taken using:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 50e95d8..49a4af3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -20,7 +20,7 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#define DRV_MODULE_VERSION	"Aug_2011"
+#define DRV_MODULE_VERSION	"Oct_2011"
 #include <linux/stmmac.h>
 
 #include "common.h"
-- 
1.7.4.4

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

* [net-next 4/8] stmmac: allow mtu bigger than 1500 in case of normal desc (V4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
                   ` (2 preceding siblings ...)
  2011-10-18 10:01 ` [net-next 3/8] stmmac: update the driver version and doc (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 5/8] stmmac: use predefined macros for HW cap register fields (V4) Giuseppe CAVALLARO
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro, Deepak SIKRI

This patch allows to set the mtu bigger than 1500
in case of normal descriptors.
This is helping some SPEAr customers.

Signed-off-by: Deepak SIKRI <deepak.sikri@st.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/norm_desc.c   |    8 +++++++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |    4 ++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 029c2a2..e13226b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -126,6 +126,7 @@ static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
 	for (i = 0; i < ring_size; i++) {
 		p->des01.rx.own = 1;
 		p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
+		p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
 		if (i == ring_size - 1)
 			p->des01.rx.end_ring = 1;
 		if (disable_rx_ic)
@@ -183,7 +184,12 @@ static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 				  int csum_flag)
 {
 	p->des01.tx.first_segment = is_fs;
-	p->des01.tx.buffer1_size = len;
+
+	if (unlikely(len > BUF_SIZE_2KiB)) {
+		p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
+		p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
+	} else
+		p->des01.tx.buffer1_size = len;
 }
 
 static void ndesc_clear_tx_ic(struct dma_desc *p)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d0af002..622b7ac 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1412,10 +1412,10 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
 		return -EBUSY;
 	}
 
-	if (priv->plat->has_gmac)
+	if (priv->plat->enh_desc)
 		max_mtu = JUMBO_LEN;
 	else
-		max_mtu = ETH_DATA_LEN;
+		max_mtu = BUF_SIZE_4KiB;
 
 	if ((new_mtu < 46) || (new_mtu > max_mtu)) {
 		pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
-- 
1.7.4.4

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

* [net-next 5/8] stmmac: use predefined macros for HW cap register fields (V4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
                   ` (3 preceding siblings ...)
  2011-10-18 10:01 ` [net-next 4/8] stmmac: allow mtu bigger than 1500 in case of normal desc (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 6/8] stmmac: allow mmc usage only if feature actually available (V4) Giuseppe CAVALLARO
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Rayagond Kokatanur, Giuseppe Cavallaro

From: Rayagond Kokatanur <rayagond@vayavyalabs.com>

Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h      |   30 +++++++++++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   54 +++++++++++++--------
 2 files changed, 63 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 22c61b2..ffba014 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -103,6 +103,36 @@ struct stmmac_extra_stats {
 
 #define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
 
+/* DAM HW feature register fields */
+#define DMA_HW_FEAT_MIISEL	0x00000001 /* 10/100 Mbps Support */
+#define DMA_HW_FEAT_GMIISEL	0x00000002 /* 1000 Mbps Support */
+#define DMA_HW_FEAT_HDSEL	0x00000004 /* Half-Duplex Support */
+#define DMA_HW_FEAT_EXTHASHEN	0x00000008 /* Expanded DA Hash Filter */
+#define DMA_HW_FEAT_HASHSEL	0x00000010 /* HASH Filter */
+#define DMA_HW_FEAT_ADDMACADRSEL	0x00000020 /* Multiple MAC Addr Reg */
+#define DMA_HW_FEAT_PCSSEL	0x00000040 /* PCS registers */
+#define DMA_HW_FEAT_L3L4FLTREN	0x00000080 /* Layer 3 & Layer 4 Feature */
+#define DMA_HW_FEAT_SMASEL	0x00000100 /* SMA(MDIO) Interface */
+#define DMA_HW_FEAT_RWKSEL	0x00000200 /* PMT Remote Wakeup */
+#define DMA_HW_FEAT_MGKSEL	0x00000400 /* PMT Magic Packet */
+#define DMA_HW_FEAT_MMCSEL	0x00000800 /* RMON Module */
+#define DMA_HW_FEAT_TSVER1SEL	0x00001000 /* Only IEEE 1588-2002 Timestamp */
+#define DMA_HW_FEAT_TSVER2SEL	0x00002000 /* IEEE 1588-2008 Adv Timestamp */
+#define DMA_HW_FEAT_EEESEL	0x00004000 /* Energy Efficient Ethernet */
+#define DMA_HW_FEAT_AVSEL	0x00008000 /* AV Feature */
+#define DMA_HW_FEAT_TXCOESEL	0x00010000 /* Checksum Offload in Tx */
+#define DMA_HW_FEAT_RXTYP1COE	0x00020000 /* IP csum Offload(Type 1) in Rx */
+#define DMA_HW_FEAT_RXTYP2COE	0x00040000 /* IP csum Offload(Type 2) in Rx */
+#define DMA_HW_FEAT_RXFIFOSIZE	0x00080000 /* Rx FIFO > 2048 Bytes */
+#define DMA_HW_FEAT_RXCHCNT	0x00300000 /* No. of additional Rx Channels */
+#define DMA_HW_FEAT_TXCHCNT	0x00c00000 /* No. of additional Tx Channels */
+#define DMA_HW_FEAT_ENHDESSEL	0x01000000 /* Alternate (Enhanced Descriptor) */
+#define DMA_HW_FEAT_INTTSEN	0x02000000 /* Timestamping with Internal
+					      System Time */
+#define DMA_HW_FEAT_FLEXIPPSEN	0x04000000 /* Flexible PPS Output */
+#define DMA_HW_FEAT_SAVLANINS	0x08000000 /* Source Addr or VLAN Insertion */
+#define DMA_HW_FEAT_ACTPHYIF	0x70000000 /* Active/selected PHY interface */
+
 enum rx_frame_status { /* IPC status */
 	good_frame = 0,
 	discard_frame = 1,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 622b7ac..125a177 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -799,33 +799,45 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv)
 	u32 hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr);
 
 	if (likely(hw_cap)) {
-		priv->dma_cap.mbps_10_100 = (hw_cap & 0x1);
-		priv->dma_cap.mbps_1000 = (hw_cap & 0x2) >> 1;
-		priv->dma_cap.half_duplex = (hw_cap & 0x4) >> 2;
-		priv->dma_cap.hash_filter = (hw_cap & 0x10) >> 4;
-		priv->dma_cap.multi_addr = (hw_cap & 0x20) >> 5;
-		priv->dma_cap.pcs = (hw_cap & 0x40) >> 6;
-		priv->dma_cap.sma_mdio = (hw_cap & 0x100) >> 8;
-		priv->dma_cap.pmt_remote_wake_up = (hw_cap & 0x200) >> 9;
-		priv->dma_cap.pmt_magic_frame = (hw_cap & 0x400) >> 10;
-		priv->dma_cap.rmon = (hw_cap & 0x800) >> 11; /* MMC */
+		priv->dma_cap.mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
+		priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
+		priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
+		priv->dma_cap.hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
+		priv->dma_cap.multi_addr =
+			(hw_cap & DMA_HW_FEAT_ADDMACADRSEL) >> 5;
+		priv->dma_cap.pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
+		priv->dma_cap.sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
+		priv->dma_cap.pmt_remote_wake_up =
+			(hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
+		priv->dma_cap.pmt_magic_frame =
+			(hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
+		/*MMC*/
+		priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
 		/* IEEE 1588-2002*/
-		priv->dma_cap.time_stamp = (hw_cap & 0x1000) >> 12;
+		priv->dma_cap.time_stamp =
+			(hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
 		/* IEEE 1588-2008*/
-		priv->dma_cap.atime_stamp = (hw_cap & 0x2000) >> 13;
+		priv->dma_cap.atime_stamp =
+			(hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
 		/* 802.3az - Energy-Efficient Ethernet (EEE) */
-		priv->dma_cap.eee = (hw_cap & 0x4000) >> 14;
-		priv->dma_cap.av = (hw_cap & 0x8000) >> 15;
+		priv->dma_cap.eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
+		priv->dma_cap.av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
 		/* TX and RX csum */
-		priv->dma_cap.tx_coe = (hw_cap & 0x10000) >> 16;
-		priv->dma_cap.rx_coe_type1 = (hw_cap & 0x20000) >> 17;
-		priv->dma_cap.rx_coe_type2 = (hw_cap & 0x40000) >> 18;
-		priv->dma_cap.rxfifo_over_2048 = (hw_cap & 0x80000) >> 19;
+		priv->dma_cap.tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
+		priv->dma_cap.rx_coe_type1 =
+			(hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
+		priv->dma_cap.rx_coe_type2 =
+			(hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
+		priv->dma_cap.rxfifo_over_2048 =
+			(hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
 		/* TX and RX number of channels */
-		priv->dma_cap.number_rx_channel = (hw_cap & 0x300000) >> 20;
-		priv->dma_cap.number_tx_channel = (hw_cap & 0xc00000) >> 22;
+		priv->dma_cap.number_rx_channel =
+			(hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
+		priv->dma_cap.number_tx_channel =
+			(hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
 		/* Alternate (enhanced) DESC mode*/
-		priv->dma_cap.enh_desc = (hw_cap & 0x1000000) >> 24;
+		priv->dma_cap.enh_desc =
+			(hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
 
 	} else
 		pr_debug("\tNo HW DMA feature register supported");
-- 
1.7.4.4

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

* [net-next 6/8] stmmac: allow mmc usage only if feature actually available (V4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
                   ` (4 preceding siblings ...)
  2011-10-18 10:01 ` [net-next 5/8] stmmac: use predefined macros for HW cap register fields (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 7/8] stmmac: add CHAINED descriptor mode support (V4) Giuseppe CAVALLARO
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro, Rayagond Kokatanur

Enable the MMC support if it is actually available from the
HW capability register.

Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |   24 +++++++++++--------
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |    3 +-
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index aedff9a..406404f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -96,7 +96,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
 	{ #m, FIELD_SIZEOF(struct stmmac_counters, m),	\
 	offsetof(struct stmmac_priv, mmc.m)}
 
-static const struct stmmac_stats stmmac_gstr_mmc[] = {
+static const struct stmmac_stats stmmac_mmc[] = {
 	STMMAC_MMC_STAT(mmc_tx_octetcount_gb),
 	STMMAC_MMC_STAT(mmc_tx_framecount_gb),
 	STMMAC_MMC_STAT(mmc_tx_broadcastframe_g),
@@ -177,7 +177,7 @@ static const struct stmmac_stats stmmac_gstr_mmc[] = {
 	STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets),
 	STMMAC_MMC_STAT(mmc_rx_icmp_err_octets),
 };
-#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_gstr_mmc)
+#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc)
 
 static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
 				      struct ethtool_drvinfo *info)
@@ -348,13 +348,17 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
 						 priv->ioaddr);
 	else {
 		/* If supported, for new GMAC chips expose the MMC counters */
-		dwmac_mmc_read(priv->ioaddr, &priv->mmc);
+		if (priv->dma_cap.rmon) {
+			dwmac_mmc_read(priv->ioaddr, &priv->mmc);
 
-		for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
-			char *p = (char *)priv + stmmac_gstr_mmc[i].stat_offset;
+			for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
+				char *p;
+				p = (char *)priv + stmmac_mmc[i].stat_offset;
 
-			data[j++] = (stmmac_gstr_mmc[i].sizeof_stat ==
-				     sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
+				data[j++] = (stmmac_mmc[i].sizeof_stat ==
+					     sizeof(u64)) ? (*(u64 *)p) :
+					     (*(u32 *)p);
+			}
 		}
 	}
 	for (i = 0; i < STMMAC_STATS_LEN; i++) {
@@ -373,7 +377,7 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset)
 	case ETH_SS_STATS:
 		len = STMMAC_STATS_LEN;
 
-		if (priv->plat->has_gmac)
+		if (priv->dma_cap.rmon)
 			len += STMMAC_MMC_STATS_LEN;
 
 		return len;
@@ -390,9 +394,9 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
 
 	switch (stringset) {
 	case ETH_SS_STATS:
-		if (priv->plat->has_gmac)
+		if (priv->dma_cap.rmon)
 			for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
-				memcpy(p, stmmac_gstr_mmc[i].stat_string,
+				memcpy(p, stmmac_mmc[i].stat_string,
 				       ETH_GSTRING_LEN);
 				p += ETH_GSTRING_LEN;
 			}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 125a177..7325256 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -946,7 +946,8 @@ static int stmmac_open(struct net_device *dev)
 	memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
 	priv->xstats.threshold = tc;
 
-	stmmac_mmc_setup(priv);
+	if (priv->dma_cap.rmon)
+		stmmac_mmc_setup(priv);
 
 	/* Start the ball rolling... */
 	DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
-- 
1.7.4.4

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

* [net-next 7/8] stmmac: add CHAINED descriptor mode support (V4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
                   ` (5 preceding siblings ...)
  2011-10-18 10:01 ` [net-next 6/8] stmmac: allow mmc usage only if feature actually available (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:01 ` [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb Giuseppe CAVALLARO
  2011-10-19 22:53 ` [net-next 0/8] stmmac: update to Oct 2011 version (v4) David Miller
  8 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro, Rayagond Kokatanur

This patch enhances the STMMAC driver to support CHAINED mode of
descriptor.

STMMAC supports DMA descriptor to operate both in dual buffer(RING)
and linked-list(CHAINED) mode. In RING mode (default) each descriptor
points to two data buffer pointers whereas in CHAINED mode they point
to only one data buffer pointer.

In CHAINED mode each descriptor will have pointer to next descriptor in
the list, hence creating the explicit chaining in the descriptor itself,
whereas such explicit chaining is not possible in RING mode.

First version of this work has been done by Rayagond.
Then the patch has been reworked avoiding ifdef inside the C code.
A new header file has been added to define all the functions needed for
managing enhanced and normal descriptors.
In fact, these have to be specialized according to the ring/chain usage.
Two new C files have been also added to implement the helper routines
needed to manage: jumbo frames, chain and ring setup (i.e. desc3).

Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/Kconfig       |   18 +++
 drivers/net/ethernet/stmicro/stmmac/Makefile      |    2 +
 drivers/net/ethernet/stmicro/stmmac/chain_mode.c  |  137 +++++++++++++++++++++
 drivers/net/ethernet/stmicro/stmmac/common.h      |   13 ++
 drivers/net/ethernet/stmicro/stmmac/descs_com.h   |  126 +++++++++++++++++++
 drivers/net/ethernet/stmicro/stmmac/enh_desc.c    |   22 ++--
 drivers/net/ethernet/stmicro/stmmac/norm_desc.c   |   20 +--
 drivers/net/ethernet/stmicro/stmmac/ring_mode.c   |  126 +++++++++++++++++++
 drivers/net/ethernet/stmicro/stmmac/stmmac.h      |    2 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |  130 ++++++++------------
 10 files changed, 491 insertions(+), 105 deletions(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/chain_mode.c
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/descs_com.h
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode.c

diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 8cd9dde..ac6f190 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -63,4 +63,22 @@ config STMMAC_RTC_TIMER
 
 endchoice
 
+choice
+	prompt "Select the DMA TX/RX descriptor operating modes"
+	depends on STMMAC_ETH
+	---help---
+	  This driver supports DMA descriptor to operate both in dual buffer
+	  (RING) and linked-list(CHAINED) mode. In RING mode each descriptor
+	  points to two data buffer pointers whereas in CHAINED mode they
+	  points to only one data buffer pointer.
+
+config STMMAC_RING
+	bool "Enable Descriptor Ring Mode"
+
+config STMMAC_CHAINED
+	bool "Enable Descriptor Chained Mode"
+
+endchoice
+
+
 endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 0f23d95..d7c4516 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,5 +1,7 @@
 obj-$(CONFIG_STMMAC_ETH) += stmmac.o
 stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
+stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
+stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
 stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o	\
 	      dwmac_lib.o dwmac1000_core.o  dwmac1000_dma.o	\
 	      dwmac100_core.o dwmac100_dma.o enh_desc.o  norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
new file mode 100644
index 0000000..0668659
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -0,0 +1,137 @@
+/*******************************************************************************
+  Specialised functions for managing Chained mode
+
+  Copyright(C) 2011  STMicroelectronics Ltd
+
+  It defines all the functions used to handle the normal/enhanced
+  descriptors in case of the DMA is configured to work in chained or
+  in ring mode.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include "stmmac.h"
+
+unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+{
+	struct stmmac_priv *priv = (struct stmmac_priv *) p;
+	unsigned int txsize = priv->dma_tx_size;
+	unsigned int entry = priv->cur_tx % txsize;
+	struct dma_desc *desc = priv->dma_tx + entry;
+	unsigned int nopaged_len = skb_headlen(skb);
+	unsigned int bmax;
+	unsigned int i = 1, len;
+
+	if (priv->plat->enh_desc)
+		bmax = BUF_SIZE_8KiB;
+	else
+		bmax = BUF_SIZE_2KiB;
+
+	len = nopaged_len - bmax;
+
+	desc->des2 = dma_map_single(priv->device, skb->data,
+				    bmax, DMA_TO_DEVICE);
+	priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
+
+	while (len != 0) {
+		entry = (++priv->cur_tx) % txsize;
+		desc = priv->dma_tx + entry;
+
+		if (len > bmax) {
+			desc->des2 = dma_map_single(priv->device,
+						    (skb->data + bmax * i),
+						    bmax, DMA_TO_DEVICE);
+			priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
+							csum);
+			priv->hw->desc->set_tx_owner(desc);
+			priv->tx_skbuff[entry] = NULL;
+			len -= bmax;
+			i++;
+		} else {
+			desc->des2 = dma_map_single(priv->device,
+						    (skb->data + bmax * i), len,
+						    DMA_TO_DEVICE);
+			priv->hw->desc->prepare_tx_desc(desc, 0, len,
+							csum);
+			priv->hw->desc->set_tx_owner(desc);
+			priv->tx_skbuff[entry] = NULL;
+			len = 0;
+		}
+	}
+	return entry;
+}
+
+static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
+{
+	unsigned int ret = 0;
+
+	if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
+	    (!enh_desc && (len > BUF_SIZE_2KiB))) {
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+{
+}
+
+static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
+{
+}
+
+static void stmmac_clean_desc3(struct dma_desc *p)
+{
+}
+
+static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
+				  unsigned int size)
+{
+	/*
+	 * In chained mode the des3 points to the next element in the ring.
+	 * The latest element has to point to the head.
+	 */
+	int i;
+	struct dma_desc *p = des;
+	dma_addr_t dma_phy = phy_addr;
+
+	for (i = 0; i < (size - 1); i++) {
+		dma_phy += sizeof(struct dma_desc);
+		p->des3 = (unsigned int)dma_phy;
+		p++;
+	}
+	p->des3 = (unsigned int)phy_addr;
+}
+
+static int stmmac_set_16kib_bfsize(int mtu)
+{
+	/* Not supported */
+	return 0;
+}
+
+const struct stmmac_ring_mode_ops ring_mode_ops = {
+	.is_jumbo_frm = stmmac_is_jumbo_frm,
+	.jumbo_frm = stmmac_jumbo_frm,
+	.refill_desc3 = stmmac_refill_desc3,
+	.init_desc3 = stmmac_init_desc3,
+	.init_dma_chain = stmmac_init_dma_chain,
+	.clean_desc3 = stmmac_clean_desc3,
+	.set_16kib_bfsize = stmmac_set_16kib_bfsize,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index ffba014..9100c10 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -287,10 +287,22 @@ struct mii_regs {
 	unsigned int data;	/* MII Data */
 };
 
+struct stmmac_ring_mode_ops {
+	unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
+	unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+	void (*refill_desc3) (int bfsize, struct dma_desc *p);
+	void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
+	void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
+				unsigned int size);
+	void (*clean_desc3) (struct dma_desc *p);
+	int (*set_16kib_bfsize) (int mtu);
+};
+
 struct mac_device_info {
 	const struct stmmac_ops		*mac;
 	const struct stmmac_desc_ops	*desc;
 	const struct stmmac_dma_ops	*dma;
+	const struct stmmac_ring_mode_ops	*ring;
 	struct mii_regs mii;	/* MII register Addresses */
 	struct mac_link link;
 	unsigned int synopsys_uid;
@@ -304,3 +316,4 @@ extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
 extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
 				unsigned int high, unsigned int low);
 extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
+extern const struct stmmac_ring_mode_ops ring_mode_ops;
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
new file mode 100644
index 0000000..dd8d6e1
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -0,0 +1,126 @@
+/*******************************************************************************
+  Header File to describe Normal/enhanced descriptor functions used for RING
+  and CHAINED modes.
+
+  Copyright(C) 2011  STMicroelectronics Ltd
+
+  It defines all the functions used to handle the normal/enhanced
+  descriptors in case of the DMA is configured to work in chained or
+  in ring mode.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#if defined(CONFIG_STMMAC_RING)
+static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
+	if (end)
+		p->des01.erx.end_ring = 1;
+}
+
+static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	if (end)
+		p->des01.etx.end_ring = 1;
+}
+
+static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
+{
+	p->des01.etx.end_ring = ter;
+}
+
+static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
+{
+	if (unlikely(len > BUF_SIZE_4KiB)) {
+		p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
+		p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
+	} else
+		p->des01.etx.buffer1_size = len;
+}
+
+static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
+	if (end)
+		p->des01.rx.end_ring = 1;
+}
+
+static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	if (end)
+		p->des01.tx.end_ring = 1;
+}
+
+static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
+{
+	p->des01.tx.end_ring = ter;
+}
+
+static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
+{
+	if (unlikely(len > BUF_SIZE_2KiB)) {
+		p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
+		p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
+	} else
+		p->des01.tx.buffer1_size = len;
+}
+
+#else
+
+static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	p->des01.erx.second_address_chained = 1;
+}
+
+static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	p->des01.etx.second_address_chained = 1;
+}
+
+static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
+{
+	p->des01.etx.second_address_chained = 1;
+}
+
+static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
+{
+	p->des01.etx.buffer1_size = len;
+}
+
+static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+{
+	p->des01.rx.second_address_chained = 1;
+}
+
+static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size)
+{
+	p->des01.tx.second_address_chained = 1;
+}
+
+static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
+{
+	p->des01.tx.second_address_chained = 1;
+}
+
+static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
+{
+	p->des01.tx.buffer1_size = len;
+}
+#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index e5dfb6a..d879763 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -23,6 +23,7 @@
 *******************************************************************************/
 
 #include "common.h"
+#include "descs_com.h"
 
 static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
 				  struct dma_desc *p, void __iomem *ioaddr)
@@ -233,10 +234,9 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
 	for (i = 0; i < ring_size; i++) {
 		p->des01.erx.own = 1;
 		p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
-		/* To support jumbo frames */
-		p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
-		if (i == ring_size - 1)
-			p->des01.erx.end_ring = 1;
+
+		ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1));
+
 		if (disable_rx_ic)
 			p->des01.erx.disable_ic = 1;
 		p++;
@@ -249,8 +249,7 @@ static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
 
 	for (i = 0; i < ring_size; i++) {
 		p->des01.etx.own = 0;
-		if (i == ring_size - 1)
-			p->des01.etx.end_ring = 1;
+		ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1));
 		p++;
 	}
 }
@@ -285,19 +284,16 @@ static void enh_desc_release_tx_desc(struct dma_desc *p)
 	int ter = p->des01.etx.end_ring;
 
 	memset(p, 0, offsetof(struct dma_desc, des2));
-	p->des01.etx.end_ring = ter;
+	enh_desc_end_tx_desc(p, ter);
 }
 
 static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 				     int csum_flag)
 {
 	p->des01.etx.first_segment = is_fs;
-	if (unlikely(len > BUF_SIZE_4KiB)) {
-		p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
-		p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
-	} else {
-		p->des01.etx.buffer1_size = len;
-	}
+
+	enh_set_tx_desc_len(p, len);
+
 	if (likely(csum_flag))
 		p->des01.etx.checksum_insertion = cic_full;
 }
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index e13226b..f7e8ba7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -23,6 +23,7 @@
 *******************************************************************************/
 
 #include "common.h"
+#include "descs_com.h"
 
 static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
 			       struct dma_desc *p, void __iomem *ioaddr)
@@ -126,9 +127,9 @@ static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
 	for (i = 0; i < ring_size; i++) {
 		p->des01.rx.own = 1;
 		p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
-		p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
-		if (i == ring_size - 1)
-			p->des01.rx.end_ring = 1;
+
+		ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1));
+
 		if (disable_rx_ic)
 			p->des01.rx.disable_ic = 1;
 		p++;
@@ -140,8 +141,7 @@ static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
 	int i;
 	for (i = 0; i < ring_size; i++) {
 		p->des01.tx.own = 0;
-		if (i == ring_size - 1)
-			p->des01.tx.end_ring = 1;
+		ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1)));
 		p++;
 	}
 }
@@ -176,20 +176,14 @@ static void ndesc_release_tx_desc(struct dma_desc *p)
 	int ter = p->des01.tx.end_ring;
 
 	memset(p, 0, offsetof(struct dma_desc, des2));
-	/* set termination field */
-	p->des01.tx.end_ring = ter;
+	ndesc_end_tx_desc(p, ter);
 }
 
 static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 				  int csum_flag)
 {
 	p->des01.tx.first_segment = is_fs;
-
-	if (unlikely(len > BUF_SIZE_2KiB)) {
-		p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
-		p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
-	} else
-		p->des01.tx.buffer1_size = len;
+	norm_set_tx_desc_len(p, len);
 }
 
 static void ndesc_clear_tx_ic(struct dma_desc *p)
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
new file mode 100644
index 0000000..fb8377d
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -0,0 +1,126 @@
+/*******************************************************************************
+  Specialised functions for managing Ring mode
+
+  Copyright(C) 2011  STMicroelectronics Ltd
+
+  It defines all the functions used to handle the normal/enhanced
+  descriptors in case of the DMA is configured to work in chained or
+  in ring mode.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include "stmmac.h"
+
+static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+{
+	struct stmmac_priv *priv = (struct stmmac_priv *) p;
+	unsigned int txsize = priv->dma_tx_size;
+	unsigned int entry = priv->cur_tx % txsize;
+	struct dma_desc *desc = priv->dma_tx + entry;
+	unsigned int nopaged_len = skb_headlen(skb);
+	unsigned int bmax, len;
+
+	if (priv->plat->enh_desc)
+		bmax = BUF_SIZE_8KiB;
+	else
+		bmax = BUF_SIZE_2KiB;
+
+	len = nopaged_len - bmax;
+
+	if (nopaged_len > BUF_SIZE_8KiB) {
+
+		desc->des2 = dma_map_single(priv->device, skb->data,
+					    bmax, DMA_TO_DEVICE);
+		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+		priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
+						csum);
+
+		entry = (++priv->cur_tx) % txsize;
+		desc = priv->dma_tx + entry;
+
+		desc->des2 = dma_map_single(priv->device, skb->data + bmax,
+					    len, DMA_TO_DEVICE);
+		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
+		priv->hw->desc->set_tx_owner(desc);
+		priv->tx_skbuff[entry] = NULL;
+	} else {
+		desc->des2 = dma_map_single(priv->device, skb->data,
+					    nopaged_len, DMA_TO_DEVICE);
+		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
+	}
+
+	return entry;
+}
+
+static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
+{
+	unsigned int ret = 0;
+
+	if (len >= BUF_SIZE_4KiB)
+		ret = 1;
+
+	return ret;
+}
+
+static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+{
+	/* Fill DES3 in case of RING mode */
+	if (bfsize >= BUF_SIZE_8KiB)
+		p->des3 = p->des2 + BUF_SIZE_8KiB;
+}
+
+/* In ring mode we need to fill the desc3 because it is used
+ * as buffer */
+static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
+{
+	if (unlikely(des3_as_data_buf))
+		p->des3 = p->des2 + BUF_SIZE_8KiB;
+}
+
+static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
+				  unsigned int size)
+{
+}
+
+static void stmmac_clean_desc3(struct dma_desc *p)
+{
+	if (unlikely(p->des3))
+		p->des3 = 0;
+}
+
+static int stmmac_set_16kib_bfsize(int mtu)
+{
+	int ret = 0;
+	if (unlikely(mtu >= BUF_SIZE_8KiB))
+		ret = BUF_SIZE_16KiB;
+	return ret;
+}
+
+const struct stmmac_ring_mode_ops ring_mode_ops = {
+	.is_jumbo_frm = stmmac_is_jumbo_frm,
+	.jumbo_frm = stmmac_jumbo_frm,
+	.refill_desc3 = stmmac_refill_desc3,
+	.init_desc3 = stmmac_init_desc3,
+	.init_dma_chain = stmmac_init_dma_chain,
+	.clean_desc3 = stmmac_clean_desc3,
+	.set_16kib_bfsize = stmmac_set_16kib_bfsize,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 49a4af3..9bafa6c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -22,7 +22,7 @@
 
 #define DRV_MODULE_VERSION	"Oct_2011"
 #include <linux/stmmac.h>
-
+#include <linux/phy.h>
 #include "common.h"
 #ifdef CONFIG_STMMAC_TIMER
 #include "stmmac_timer.h"
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7325256..1848a16 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2,7 +2,7 @@
   This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
   ST Ethernet IPs are built around a Synopsys IP Core.
 
-  Copyright (C) 2007-2009  STMicroelectronics Ltd
+	Copyright(C) 2007-2011 STMicroelectronics Ltd
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -41,17 +41,16 @@
 #include <linux/if_ether.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
-#include <linux/phy.h>
 #include <linux/if.h>
 #include <linux/if_vlan.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/prefetch.h>
-#include "stmmac.h"
 #ifdef CONFIG_STMMAC_DEBUG_FS
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #endif
+#include "stmmac.h"
 
 #define STMMAC_RESOURCE_NAME	"stmmaceth"
 
@@ -388,11 +387,28 @@ static void display_ring(struct dma_desc *p, int size)
 	}
 }
 
+static int stmmac_set_bfsize(int mtu, int bufsize)
+{
+	int ret = bufsize;
+
+	if (mtu >= BUF_SIZE_4KiB)
+		ret = BUF_SIZE_8KiB;
+	else if (mtu >= BUF_SIZE_2KiB)
+		ret = BUF_SIZE_4KiB;
+	else if (mtu >= DMA_BUFFER_SIZE)
+		ret = BUF_SIZE_2KiB;
+	else
+		ret = DMA_BUFFER_SIZE;
+
+	return ret;
+}
+
 /**
  * init_dma_desc_rings - init the RX/TX descriptor rings
  * @dev: net device structure
  * Description:  this function initializes the DMA RX/TX descriptors
- * and allocates the socket buffers.
+ * and allocates the socket buffers. It suppors the chained and ring
+ * modes.
  */
 static void init_dma_desc_rings(struct net_device *dev)
 {
@@ -401,31 +417,24 @@ static void init_dma_desc_rings(struct net_device *dev)
 	struct sk_buff *skb;
 	unsigned int txsize = priv->dma_tx_size;
 	unsigned int rxsize = priv->dma_rx_size;
-	unsigned int bfsize = priv->dma_buf_sz;
-	int buff2_needed = 0, dis_ic = 0;
+	unsigned int bfsize;
+	int dis_ic = 0;
+	int des3_as_data_buf = 0;
 
-	/* Set the Buffer size according to the MTU;
-	 * indeed, in case of jumbo we need to bump-up the buffer sizes.
-	 */
-	if (unlikely(dev->mtu >= BUF_SIZE_8KiB))
-		bfsize = BUF_SIZE_16KiB;
-	else if (unlikely(dev->mtu >= BUF_SIZE_4KiB))
-		bfsize = BUF_SIZE_8KiB;
-	else if (unlikely(dev->mtu >= BUF_SIZE_2KiB))
-		bfsize = BUF_SIZE_4KiB;
-	else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE))
-		bfsize = BUF_SIZE_2KiB;
+	/* Set the max buffer size according to the DESC mode
+	 * and the MTU. Note that RING mode allows 16KiB bsize. */
+	bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+
+	if (bfsize == BUF_SIZE_16KiB)
+		des3_as_data_buf = 1;
 	else
-		bfsize = DMA_BUFFER_SIZE;
+		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
 
 #ifdef CONFIG_STMMAC_TIMER
 	/* Disable interrupts on completion for the reception if timer is on */
 	if (likely(priv->tm->enable))
 		dis_ic = 1;
 #endif
-	/* If the MTU exceeds 8k so use the second buffer in the chain */
-	if (bfsize >= BUF_SIZE_8KiB)
-		buff2_needed = 1;
 
 	DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
 	    txsize, rxsize, bfsize);
@@ -453,7 +462,7 @@ static void init_dma_desc_rings(struct net_device *dev)
 		return;
 	}
 
-	DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, "
+	DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
 	    "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
 	    dev->name, priv->dma_rx, priv->dma_tx,
 	    (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy);
@@ -475,8 +484,9 @@ static void init_dma_desc_rings(struct net_device *dev)
 						bfsize, DMA_FROM_DEVICE);
 
 		p->des2 = priv->rx_skbuff_dma[i];
-		if (unlikely(buff2_needed))
-			p->des3 = p->des2 + BUF_SIZE_8KiB;
+
+		priv->hw->ring->init_desc3(des3_as_data_buf, p);
+
 		DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
 			priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
 	}
@@ -490,6 +500,12 @@ static void init_dma_desc_rings(struct net_device *dev)
 		priv->tx_skbuff[i] = NULL;
 		priv->dma_tx[i].des2 = 0;
 	}
+
+	/* In case of Chained mode this sets the des3 to the next
+	 * element in the chain */
+	priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize);
+	priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize);
+
 	priv->dirty_tx = 0;
 	priv->cur_tx = 0;
 
@@ -620,8 +636,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
 			dma_unmap_single(priv->device, p->des2,
 					 priv->hw->desc->get_tx_len(p),
 					 DMA_TO_DEVICE);
-		if (unlikely(p->des3))
-			p->des3 = 0;
+		priv->hw->ring->clean_desc3(p);
 
 		if (likely(skb != NULL)) {
 			/*
@@ -728,7 +743,6 @@ static void stmmac_no_timer_stopped(void)
  */
 static void stmmac_tx_err(struct stmmac_priv *priv)
 {
-
 	netif_stop_queue(priv->dev);
 
 	priv->hw->dma->stop_tx(priv->ioaddr);
@@ -1028,47 +1042,6 @@ static int stmmac_release(struct net_device *dev)
 	return 0;
 }
 
-static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
-					       struct net_device *dev,
-					       int csum_insertion)
-{
-	struct stmmac_priv *priv = netdev_priv(dev);
-	unsigned int nopaged_len = skb_headlen(skb);
-	unsigned int txsize = priv->dma_tx_size;
-	unsigned int entry = priv->cur_tx % txsize;
-	struct dma_desc *desc = priv->dma_tx + entry;
-
-	if (nopaged_len > BUF_SIZE_8KiB) {
-
-		int buf2_size = nopaged_len - BUF_SIZE_8KiB;
-
-		desc->des2 = dma_map_single(priv->device, skb->data,
-					    BUF_SIZE_8KiB, DMA_TO_DEVICE);
-		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-		priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
-						csum_insertion);
-
-		entry = (++priv->cur_tx) % txsize;
-		desc = priv->dma_tx + entry;
-
-		desc->des2 = dma_map_single(priv->device,
-					skb->data + BUF_SIZE_8KiB,
-					buf2_size, DMA_TO_DEVICE);
-		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-		priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size,
-						csum_insertion);
-		priv->hw->desc->set_tx_owner(desc);
-		priv->tx_skbuff[entry] = NULL;
-	} else {
-		desc->des2 = dma_map_single(priv->device, skb->data,
-					nopaged_len, DMA_TO_DEVICE);
-		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
-						csum_insertion);
-	}
-	return entry;
-}
-
 /**
  *  stmmac_xmit:
  *  @skb : the socket buffer
@@ -1083,6 +1056,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	int i, csum_insertion = 0;
 	int nfrags = skb_shinfo(skb)->nr_frags;
 	struct dma_desc *desc, *first;
+	unsigned int nopaged_len = skb_headlen(skb);
 
 	if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
 		if (!netif_queue_stopped(dev)) {
@@ -1103,7 +1077,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		pr_info("stmmac xmit:\n"
 		       "\tskb addr %p - len: %d - nopaged_len: %d\n"
 		       "\tn_frags: %d - ip_summed: %d - %s gso\n",
-		       skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed,
+		       skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
 		       !skb_is_gso(skb) ? "isn't" : "is");
 #endif
 
@@ -1116,14 +1090,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
 		pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
 		       "\t\tn_frags: %d, ip_summed: %d\n",
-		       skb->len, skb_headlen(skb), nfrags, skb->ip_summed);
+		       skb->len, nopaged_len, nfrags, skb->ip_summed);
 #endif
 	priv->tx_skbuff[entry] = skb;
-	if (unlikely(skb->len >= BUF_SIZE_4KiB)) {
-		entry = stmmac_handle_jumbo_frames(skb, dev, csum_insertion);
+
+	if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) {
+		entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion);
 		desc = priv->dma_tx + entry;
 	} else {
-		unsigned int nopaged_len = skb_headlen(skb);
 		desc->des2 = dma_map_single(priv->device, skb->data,
 					nopaged_len, DMA_TO_DEVICE);
 		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
@@ -1214,11 +1188,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 					   DMA_FROM_DEVICE);
 
 			(p + entry)->des2 = priv->rx_skbuff_dma[entry];
-			if (unlikely(priv->plat->has_gmac)) {
-				if (bfsize >= BUF_SIZE_8KiB)
-					(p + entry)->des3 =
-					    (p + entry)->des2 + BUF_SIZE_8KiB;
-			}
+
+			if (unlikely(priv->plat->has_gmac))
+				priv->hw->ring->refill_desc3(bfsize, p + entry);
+
 			RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
 		}
 		wmb();
@@ -1795,6 +1768,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
 		device->desc = &ndesc_ops;
 
 	priv->hw = device;
+	priv->hw->ring = &ring_mode_ops;
 
 	if (device_can_wakeup(priv->device)) {
 		priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
-- 
1.7.4.4

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

* [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb.
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
                   ` (6 preceding siblings ...)
  2011-10-18 10:01 ` [net-next 7/8] stmmac: add CHAINED descriptor mode support (V4) Giuseppe CAVALLARO
@ 2011-10-18 10:01 ` Giuseppe CAVALLARO
  2011-10-18 10:18   ` Eric Dumazet
  2011-10-18 11:39   ` [net-next] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2) Giuseppe CAVALLARO
  2011-10-19 22:53 ` [net-next 0/8] stmmac: update to Oct 2011 version (v4) David Miller
  8 siblings, 2 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 10:01 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro

Problem using big mtu around 4096 bytes is you end allocating (4096
+NET_SKB_PAD + NET_IP_ALIGN + sizeof(struct skb_shared_info) bytes ->
8192 bytes : order-1 pages

It's better to limit the mtu to SKB_MAX_HEAD(NET_SKB_PAD),
to have no more than one page per skb.

Also the patch changes the netdev_alloc_skb_ip_align() done in
init_dma_desc_rings() and uses a variant allowing GFP_KERNEL allocations
allowing the driver to load even in case of memory pressure.

Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 1848a16..f5ca3be 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -474,11 +474,13 @@ static void init_dma_desc_rings(struct net_device *dev)
 	for (i = 0; i < rxsize; i++) {
 		struct dma_desc *p = priv->dma_rx + i;
 
-		skb = netdev_alloc_skb_ip_align(dev, bfsize);
+		skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
+					 GFP_KERNEL);
 		if (unlikely(skb == NULL)) {
 			pr_err("%s: Rx init fails; skb is NULL\n", __func__);
 			break;
 		}
+		skb_reserve(skb, NET_IP_ALIGN);
 		priv->rx_skbuff[i] = skb;
 		priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
 						bfsize, DMA_FROM_DEVICE);
@@ -1176,12 +1178,15 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 
 			skb = __skb_dequeue(&priv->rx_recycle);
 			if (skb == NULL)
-				skb = netdev_alloc_skb_ip_align(priv->dev,
-								bfsize);
+				skb = __netdev_alloc_skb(priv->dev, bfsize +
+							 NET_IP_ALIGN,
+							 GFP_KERNEL);
 
 			if (unlikely(skb == NULL))
 				break;
 
+			skb_reserve(skb, NET_IP_ALIGN);
+
 			priv->rx_skbuff[entry] = skb;
 			priv->rx_skbuff_dma[entry] =
 			    dma_map_single(priv->device, skb->data, bfsize,
@@ -1401,7 +1406,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
 	if (priv->plat->enh_desc)
 		max_mtu = JUMBO_LEN;
 	else
-		max_mtu = BUF_SIZE_4KiB;
+		max_mtu = SKB_MAX_HEAD(NET_SKB_PAD);
 
 	if ((new_mtu < 46) || (new_mtu > max_mtu)) {
 		pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
-- 
1.7.4.4

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

* Re: [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb.
  2011-10-18 10:01 ` [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb Giuseppe CAVALLARO
@ 2011-10-18 10:18   ` Eric Dumazet
  2011-10-18 11:33     ` Giuseppe CAVALLARO
  2011-10-18 11:39   ` [net-next] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2) Giuseppe CAVALLARO
  1 sibling, 1 reply; 14+ messages in thread
From: Eric Dumazet @ 2011-10-18 10:18 UTC (permalink / raw)
  To: Giuseppe CAVALLARO; +Cc: netdev, davem

Le mardi 18 octobre 2011 à 12:01 +0200, Giuseppe CAVALLARO a écrit :
> Problem using big mtu around 4096 bytes is you end allocating (4096
> +NET_SKB_PAD + NET_IP_ALIGN + sizeof(struct skb_shared_info) bytes ->
> 8192 bytes : order-1 pages
> 
> It's better to limit the mtu to SKB_MAX_HEAD(NET_SKB_PAD),
> to have no more than one page per skb.
> 
> Also the patch changes the netdev_alloc_skb_ip_align() done in
> init_dma_desc_rings() and uses a variant allowing GFP_KERNEL allocations
> allowing the driver to load even in case of memory pressure.
> 
> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   13 +++++++++----
>  1 files changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 1848a16..f5ca3be 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -474,11 +474,13 @@ static void init_dma_desc_rings(struct net_device *dev)
>  	for (i = 0; i < rxsize; i++) {
>  		struct dma_desc *p = priv->dma_rx + i;
>  
> -		skb = netdev_alloc_skb_ip_align(dev, bfsize);
> +		skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
> +					 GFP_KERNEL);
>  		if (unlikely(skb == NULL)) {
>  			pr_err("%s: Rx init fails; skb is NULL\n", __func__);
>  			break;
>  		}
> +		skb_reserve(skb, NET_IP_ALIGN);
>  		priv->rx_skbuff[i] = skb;
>  		priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
>  						bfsize, DMA_FROM_DEVICE);
> @@ -1176,12 +1178,15 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
>  
>  			skb = __skb_dequeue(&priv->rx_recycle);
>  			if (skb == NULL)
> -				skb = netdev_alloc_skb_ip_align(priv->dev,
> -								bfsize);
> +				skb = __netdev_alloc_skb(priv->dev, bfsize +
> +							 NET_IP_ALIGN,
> +							 GFP_KERNEL);
>  

No, you cant do that in softirq context. We cant sleep here and must use
GFP_ATOMIC

Only the init_dma_desc_rings() part is OK, we run in process context and
are allowed to sleep in memory allocations (GFP_KERNEL)


>  			if (unlikely(skb == NULL))
>  				break;
>  
> +			skb_reserve(skb, NET_IP_ALIGN);
> +
>  			priv->rx_skbuff[entry] = skb;
>  			priv->rx_skbuff_dma[entry] =
>  			    dma_map_single(priv->device, skb->data, bfsize,
> @@ -1401,7 +1406,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
>  	if (priv->plat->enh_desc)
>  		max_mtu = JUMBO_LEN;
>  	else
> -		max_mtu = BUF_SIZE_4KiB;
> +		max_mtu = SKB_MAX_HEAD(NET_SKB_PAD);
>  

minor nit (since NET_IP_ALIGN is 0 anyway on modern x86)
max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);


>  	if ((new_mtu < 46) || (new_mtu > max_mtu)) {
>  		pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);

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

* Re: [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb.
  2011-10-18 10:18   ` Eric Dumazet
@ 2011-10-18 11:33     ` Giuseppe CAVALLARO
  0 siblings, 0 replies; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 11:33 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, davem

On 10/18/2011 12:18 PM, Eric Dumazet wrote:
> Le mardi 18 octobre 2011 à 12:01 +0200, Giuseppe CAVALLARO a écrit :
>> Problem using big mtu around 4096 bytes is you end allocating (4096
>> +NET_SKB_PAD + NET_IP_ALIGN + sizeof(struct skb_shared_info) bytes ->
>> 8192 bytes : order-1 pages
>>
>> It's better to limit the mtu to SKB_MAX_HEAD(NET_SKB_PAD),
>> to have no more than one page per skb.
>>
>> Also the patch changes the netdev_alloc_skb_ip_align() done in
>> init_dma_desc_rings() and uses a variant allowing GFP_KERNEL allocations
>> allowing the driver to load even in case of memory pressure.
>>
>> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
>> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
>> ---
>>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   13 +++++++++----
>>  1 files changed, 9 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> index 1848a16..f5ca3be 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> @@ -474,11 +474,13 @@ static void init_dma_desc_rings(struct net_device *dev)
>>  	for (i = 0; i < rxsize; i++) {
>>  		struct dma_desc *p = priv->dma_rx + i;
>>  
>> -		skb = netdev_alloc_skb_ip_align(dev, bfsize);
>> +		skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
>> +					 GFP_KERNEL);
>>  		if (unlikely(skb == NULL)) {
>>  			pr_err("%s: Rx init fails; skb is NULL\n", __func__);
>>  			break;
>>  		}
>> +		skb_reserve(skb, NET_IP_ALIGN);
>>  		priv->rx_skbuff[i] = skb;
>>  		priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
>>  						bfsize, DMA_FROM_DEVICE);
>> @@ -1176,12 +1178,15 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
>>  
>>  			skb = __skb_dequeue(&priv->rx_recycle);
>>  			if (skb == NULL)
>> -				skb = netdev_alloc_skb_ip_align(priv->dev,
>> -								bfsize);
>> +				skb = __netdev_alloc_skb(priv->dev, bfsize +
>> +							 NET_IP_ALIGN,
>> +							 GFP_KERNEL);
>>  
> 
> No, you cant do that in softirq context. We cant sleep here and must use
> GFP_ATOMIC
> Only the init_dma_desc_rings() part is OK, we run in process context and
> are allowed to sleep in memory allocations (GFP_KERNEL)
> 
> 
>>  			if (unlikely(skb == NULL))
>>  				break;
>>  
>> +			skb_reserve(skb, NET_IP_ALIGN);
>> +
>>  			priv->rx_skbuff[entry] = skb;
>>  			priv->rx_skbuff_dma[entry] =
>>  			    dma_map_single(priv->device, skb->data, bfsize,
>> @@ -1401,7 +1406,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
>>  	if (priv->plat->enh_desc)
>>  		max_mtu = JUMBO_LEN;
>>  	else
>> -		max_mtu = BUF_SIZE_4KiB;
>> +		max_mtu = SKB_MAX_HEAD(NET_SKB_PAD);
>>  
> 
> minor nit (since NET_IP_ALIGN is 0 anyway on modern x86)
> max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
> 
> 
>>  	if ((new_mtu < 46) || (new_mtu > max_mtu)) {
>>  		pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
> 
> 
> 

Ok! I'm reworking and sending it again.

Thx
Peppe

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

* [net-next] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2)
  2011-10-18 10:01 ` [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb Giuseppe CAVALLARO
  2011-10-18 10:18   ` Eric Dumazet
@ 2011-10-18 11:39   ` Giuseppe CAVALLARO
  2011-10-18 12:26     ` Eric Dumazet
  1 sibling, 1 reply; 14+ messages in thread
From: Giuseppe CAVALLARO @ 2011-10-18 11:39 UTC (permalink / raw)
  To: netdev; +Cc: davem, eric.dumazet, Giuseppe Cavallaro

Problem using big mtu around 4096 bytes is you end allocating (4096
+NET_SKB_PAD + NET_IP_ALIGN + sizeof(struct skb_shared_info) bytes ->
8192 bytes : order-1 pages

It's better to limit the mtu to SKB_MAX_HEAD(NET_SKB_PAD),
to have no more than one page per skb.

Also the patch changes the netdev_alloc_skb_ip_align() done in
init_dma_desc_rings() and uses a variant allowing GFP_KERNEL allocations
allowing the driver to load even in case of memory pressure.

Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 1848a16..6b8f455 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -474,11 +474,13 @@ static void init_dma_desc_rings(struct net_device *dev)
 	for (i = 0; i < rxsize; i++) {
 		struct dma_desc *p = priv->dma_rx + i;
 
-		skb = netdev_alloc_skb_ip_align(dev, bfsize);
+		skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
+					 GFP_KERNEL);
 		if (unlikely(skb == NULL)) {
 			pr_err("%s: Rx init fails; skb is NULL\n", __func__);
 			break;
 		}
+		skb_reserve(skb, NET_IP_ALIGN);
 		priv->rx_skbuff[i] = skb;
 		priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
 						bfsize, DMA_FROM_DEVICE);
@@ -1401,7 +1403,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
 	if (priv->plat->enh_desc)
 		max_mtu = JUMBO_LEN;
 	else
-		max_mtu = BUF_SIZE_4KiB;
+		max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
 
 	if ((new_mtu < 46) || (new_mtu > max_mtu)) {
 		pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
-- 
1.7.4.4

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

* Re: [net-next] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2)
  2011-10-18 11:39   ` [net-next] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2) Giuseppe CAVALLARO
@ 2011-10-18 12:26     ` Eric Dumazet
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Dumazet @ 2011-10-18 12:26 UTC (permalink / raw)
  To: Giuseppe CAVALLARO; +Cc: netdev, davem

Le mardi 18 octobre 2011 à 13:39 +0200, Giuseppe CAVALLARO a écrit :
> Problem using big mtu around 4096 bytes is you end allocating (4096
> +NET_SKB_PAD + NET_IP_ALIGN + sizeof(struct skb_shared_info) bytes ->
> 8192 bytes : order-1 pages
> 
> It's better to limit the mtu to SKB_MAX_HEAD(NET_SKB_PAD),
> to have no more than one page per skb.
> 
> Also the patch changes the netdev_alloc_skb_ip_align() done in
> init_dma_desc_rings() and uses a variant allowing GFP_KERNEL allocations
> allowing the driver to load even in case of memory pressure.
> 
> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 

Seems good, thanks :)

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

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

* Re: [net-next 0/8] stmmac: update to Oct 2011 version (v4)
  2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
                   ` (7 preceding siblings ...)
  2011-10-18 10:01 ` [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb Giuseppe CAVALLARO
@ 2011-10-19 22:53 ` David Miller
  8 siblings, 0 replies; 14+ messages in thread
From: David Miller @ 2011-10-19 22:53 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, eric.dumazet

From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
Date: Tue, 18 Oct 2011 12:01:17 +0200

> This patches update the driver adding the chained
> descriptor mode and some new useful fixes.
> 
> I've reviewed some patches after the V1/2/3 and added new ones:

All applied, with the updated version of patch #8.

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

end of thread, other threads:[~2011-10-19 22:53 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-18 10:01 [net-next 0/8] stmmac: update to Oct 2011 version (v4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 1/8] stmmac: Stop advertising 1000Base capabilties for non GMII iface (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 2/8] stmmac: protect tx process with lock (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 3/8] stmmac: update the driver version and doc (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 4/8] stmmac: allow mtu bigger than 1500 in case of normal desc (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 5/8] stmmac: use predefined macros for HW cap register fields (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 6/8] stmmac: allow mmc usage only if feature actually available (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 7/8] stmmac: add CHAINED descriptor mode support (V4) Giuseppe CAVALLARO
2011-10-18 10:01 ` [net-next 8/8] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb Giuseppe CAVALLARO
2011-10-18 10:18   ` Eric Dumazet
2011-10-18 11:33     ` Giuseppe CAVALLARO
2011-10-18 11:39   ` [net-next] stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2) Giuseppe CAVALLARO
2011-10-18 12:26     ` Eric Dumazet
2011-10-19 22:53 ` [net-next 0/8] stmmac: update to Oct 2011 version (v4) David Miller

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.