All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support
@ 2018-10-17 19:53 Christian Lamparter
  2018-10-17 19:53 ` [PATCH 2/2] net: emac: implement TCP TSO Christian Lamparter
  2018-10-17 20:08 ` [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Florian Fainelli
  0 siblings, 2 replies; 7+ messages in thread
From: Christian Lamparter @ 2018-10-17 19:53 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller

As per' APM82181 Embedded Processor User Manual 26.1 EMAC Features:
VLAN:
 - Support for VLAN tag ID in compliance with IEEE 802.3ac.
 - VLAN tag insertion or replacement for transmit packets

This patch completes the missing code for the VLAN tx tagging
support, as the the EMAC_MR1_VLE was already enabled.

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
 drivers/net/ethernet/ibm/emac/core.c | 32 ++++++++++++++++++++++++----
 drivers/net/ethernet/ibm/emac/core.h |  6 +++++-
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 760b2ad8e295..be560f9031f4 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -37,6 +37,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/bitops.h>
+#include <linux/if_vlan.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -674,7 +675,7 @@ static int emac_configure(struct emac_instance *dev)
 		 ndev->dev_addr[5]);
 
 	/* VLAN Tag Protocol ID */
-	out_be32(&p->vtpid, 0x8100);
+	out_be32(&p->vtpid, ETH_P_8021Q);
 
 	/* Receive mode register */
 	r = emac_iff2rmr(ndev);
@@ -1435,6 +1436,22 @@ static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len)
 	return NETDEV_TX_OK;
 }
 
+static inline u16 emac_tx_vlan(struct emac_instance *dev, struct sk_buff *skb)
+{
+	/* Handle VLAN TPID and TCI insert if this is a VLAN skb */
+	if (emac_has_feature(dev, EMAC_FTR_HAS_VLAN_CTAG_TX) &&
+	    skb_vlan_tag_present(skb)) {
+		struct emac_regs __iomem *p = dev->emacp;
+
+		/* update the VLAN TCI */
+		out_be32(&p->vtci, (u32)skb_vlan_tag_get(skb));
+
+		/* Insert VLAN tag */
+		return EMAC_TX_CTRL_IVT;
+	}
+	return 0;
+}
+
 /* Tx lock BH */
 static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
@@ -1443,7 +1460,7 @@ static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	int slot;
 
 	u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
-	    MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb);
+	    MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb) | emac_tx_vlan(dev, skb);
 
 	slot = dev->tx_slot++;
 	if (dev->tx_slot == NUM_TX_BUFF) {
@@ -1518,7 +1535,7 @@ emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
 		goto stop_queue;
 
 	ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
-	    emac_tx_csum(dev, skb);
+	    emac_tx_csum(dev, skb) | emac_tx_vlan(dev, skb);
 	slot = dev->tx_slot;
 
 	/* skb data */
@@ -2891,7 +2908,8 @@ static int emac_init_config(struct emac_instance *dev)
 		if (of_device_is_compatible(np, "ibm,emac-apm821xx")) {
 			dev->features |= (EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
 					  EMAC_FTR_APM821XX_NO_HALF_DUPLEX |
-					  EMAC_FTR_460EX_PHY_CLK_FIX);
+					  EMAC_FTR_460EX_PHY_CLK_FIX |
+					  EMAC_FTR_HAS_VLAN_CTAG_TX);
 		}
 	} else if (of_device_is_compatible(np, "ibm,emac4")) {
 		dev->features |= EMAC_FTR_EMAC4;
@@ -3148,6 +3166,12 @@ static int emac_probe(struct platform_device *ofdev)
 
 	if (dev->tah_dev) {
 		ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG;
+
+		if (emac_has_feature(dev, EMAC_FTR_HAS_VLAN_CTAG_TX)) {
+			ndev->vlan_features |= ndev->hw_features;
+			ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
+		}
+
 		ndev->features |= ndev->hw_features | NETIF_F_RXCSUM;
 	}
 	ndev->watchdog_timeo = 5 * HZ;
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 84caa4a3fc52..8d84d439168c 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -334,6 +334,8 @@ struct emac_instance {
  * APM821xx does not support Half Duplex mode
  */
 #define EMAC_FTR_APM821XX_NO_HALF_DUPLEX	0x00001000
+/* EMAC can insert 802.1Q tag */
+#define EMAC_FTR_HAS_VLAN_CTAG_TX		0x00002000
 
 /* Right now, we don't quite handle the always/possible masks on the
  * most optimal way as we don't have a way to say something like
@@ -363,7 +365,9 @@ enum {
 	EMAC_FTR_460EX_PHY_CLK_FIX |
 	EMAC_FTR_440EP_PHY_CLK_FIX |
 	EMAC_APM821XX_REQ_JUMBO_FRAME_SIZE |
-	EMAC_FTR_APM821XX_NO_HALF_DUPLEX,
+	EMAC_FTR_APM821XX_NO_HALF_DUPLEX |
+	EMAC_FTR_HAS_VLAN_CTAG_TX |
+	0,
 };
 
 static inline int emac_has_feature(struct emac_instance *dev,
-- 
2.19.1

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

* [PATCH 2/2] net: emac: implement TCP TSO
  2018-10-17 19:53 [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Christian Lamparter
@ 2018-10-17 19:53 ` Christian Lamparter
  2018-10-17 20:09   ` Florian Fainelli
  2018-10-17 20:08 ` [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Florian Fainelli
  1 sibling, 1 reply; 7+ messages in thread
From: Christian Lamparter @ 2018-10-17 19:53 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller

This patch enables TSO(v4) hw feature for emac driver.
As atleast the APM82181's TCP/IP acceleration hardware
controller (TAH) provides TCP segmentation support in
the transmit path.

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
 drivers/net/ethernet/ibm/emac/core.c | 101 ++++++++++++++++++++++++++-
 drivers/net/ethernet/ibm/emac/core.h |   4 ++
 drivers/net/ethernet/ibm/emac/emac.h |   7 ++
 drivers/net/ethernet/ibm/emac/tah.c  |  20 ++++++
 drivers/net/ethernet/ibm/emac/tah.h  |   2 +
 5 files changed, 133 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index be560f9031f4..49ffbd6e1707 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -38,6 +38,9 @@
 #include <linux/mii.h>
 #include <linux/bitops.h>
 #include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -1410,6 +1413,52 @@ static inline u16 emac_tx_csum(struct emac_instance *dev,
 	return 0;
 }
 
+const u32 tah_ss[TAH_NO_SSR] = { 9000, 4500, 1500, 1300, 576, 176 };
+
+static int emac_tx_tso(struct emac_instance *dev, struct sk_buff *skb,
+		       u16 *ctrl)
+{
+	if (emac_has_feature(dev, EMAC_FTR_TAH_HAS_TSO) &&
+	    skb_is_gso(skb) && !!(skb_shinfo(skb)->gso_type &
+				(SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
+		u32 seg_size = 0, i;
+
+		/* Get the MTU */
+		seg_size = skb_shinfo(skb)->gso_size + tcp_hdrlen(skb)
+			+ skb_network_header_len(skb);
+
+		/* Restriction applied for the segmentation size
+		 * to use HW segmentation offload feature: the size
+		 * of the segment must not be less than 168 bytes for
+		 * DIX formatted segments, or 176 bytes for
+		 * IEEE formatted segments.
+		 *
+		 * I use value 176 to check for the segment size here
+		 * as it can cover both 2 conditions above.
+		 */
+		if (seg_size < 176)
+			return -ENODEV;
+
+		/* Get the best suitable MTU */
+		for (i = 0; i < ARRAY_SIZE(tah_ss); i++) {
+			u32 curr_seg = tah_ss[i];
+
+			if (curr_seg > dev->ndev->mtu ||
+			    curr_seg > seg_size)
+				continue;
+
+			*ctrl &= ~EMAC_TX_CTRL_TAH_CSUM;
+			*ctrl |= EMAC_TX_CTRL_TAH_SSR(i);
+			return 0;
+		}
+
+		/* none found fall back to software */
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len)
 {
 	struct emac_regs __iomem *p = dev->emacp;
@@ -1452,8 +1501,46 @@ static inline u16 emac_tx_vlan(struct emac_instance *dev, struct sk_buff *skb)
 	return 0;
 }
 
+static netdev_tx_t
+emac_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+
+static netdev_tx_t emac_sw_tso(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	struct sk_buff *segs, *curr;
+
+	segs = skb_gso_segment(skb, ndev->features &
+					~(NETIF_F_TSO | NETIF_F_TSO6));
+	if (IS_ERR_OR_NULL(segs)) {
+		goto drop;
+	} else {
+		while (segs) {
+			/* check for overflow */
+			if (dev->tx_cnt >= NUM_TX_BUFF) {
+				dev_kfree_skb_any(segs);
+				goto drop;
+			}
+
+			curr = segs;
+			segs = curr->next;
+			curr->next = NULL;
+
+			emac_start_xmit(curr, ndev);
+		}
+		dev_consume_skb_any(skb);
+	}
+
+	return NETDEV_TX_OK;
+
+drop:
+	++dev->estats.tx_dropped;
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
+
 /* Tx lock BH */
-static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static netdev_tx_t
+emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct emac_instance *dev = netdev_priv(ndev);
 	unsigned int len = skb->len;
@@ -1462,6 +1549,9 @@ static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
 	    MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb) | emac_tx_vlan(dev, skb);
 
+	if (emac_tx_tso(dev, skb, &ctrl))
+		return emac_sw_tso(skb, ndev);
+
 	slot = dev->tx_slot++;
 	if (dev->tx_slot == NUM_TX_BUFF) {
 		dev->tx_slot = 0;
@@ -1536,6 +1626,9 @@ emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
 
 	ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
 	    emac_tx_csum(dev, skb) | emac_tx_vlan(dev, skb);
+	if (emac_tx_tso(dev, skb, &ctrl))
+		return emac_sw_tso(skb, ndev);
+
 	slot = dev->tx_slot;
 
 	/* skb data */
@@ -2946,6 +3039,9 @@ static int emac_init_config(struct emac_instance *dev)
 	if (dev->tah_ph != 0) {
 #ifdef CONFIG_IBM_EMAC_TAH
 		dev->features |= EMAC_FTR_HAS_TAH;
+
+		if (of_device_is_compatible(np, "ibm,emac-apm821xx"))
+			dev->features |= EMAC_FTR_TAH_HAS_TSO;
 #else
 		printk(KERN_ERR "%pOF: TAH support not enabled !\n", np);
 		return -ENXIO;
@@ -3167,6 +3263,9 @@ static int emac_probe(struct platform_device *ofdev)
 	if (dev->tah_dev) {
 		ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG;
 
+		if (emac_has_feature(dev, EMAC_FTR_TAH_HAS_TSO))
+			ndev->hw_features |= NETIF_F_TSO;
+
 		if (emac_has_feature(dev, EMAC_FTR_HAS_VLAN_CTAG_TX)) {
 			ndev->vlan_features |= ndev->hw_features;
 			ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 8d84d439168c..e40ccee58775 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -336,6 +336,8 @@ struct emac_instance {
 #define EMAC_FTR_APM821XX_NO_HALF_DUPLEX	0x00001000
 /* EMAC can insert 802.1Q tag */
 #define EMAC_FTR_HAS_VLAN_CTAG_TX		0x00002000
+/* TAH can do TCP segmentation offload */
+#define EMAC_FTR_TAH_HAS_TSO			0x00004000
 
 /* Right now, we don't quite handle the always/possible masks on the
  * most optimal way as we don't have a way to say something like
@@ -352,6 +354,8 @@ enum {
 #endif
 #ifdef CONFIG_IBM_EMAC_TAH
 	    EMAC_FTR_HAS_TAH	|
+	    EMAC_FTR_TAH_HAS_TSO	|
+
 #endif
 #ifdef CONFIG_IBM_EMAC_ZMII
 	    EMAC_FTR_HAS_ZMII	|
diff --git a/drivers/net/ethernet/ibm/emac/emac.h b/drivers/net/ethernet/ibm/emac/emac.h
index e2f80cca9bed..833967aceb2f 100644
--- a/drivers/net/ethernet/ibm/emac/emac.h
+++ b/drivers/net/ethernet/ibm/emac/emac.h
@@ -266,6 +266,13 @@ struct emac_regs {
 #define EMAC_TX_CTRL_IVT		0x0020
 #define EMAC_TX_CTRL_RVT		0x0010
 #define EMAC_TX_CTRL_TAH_CSUM		0x000e
+#define EMAC_TX_CTRL_TAH_SSR(idx)	(((idx) + 1) << 1)
+#define EMAC_TX_CTRL_TAH_SSR5		0x000c
+#define EMAC_TX_CTRL_TAH_SSR4		0x000a
+#define EMAC_TX_CTRL_TAH_SSR3		0x0008
+#define EMAC_TX_CTRL_TAH_SSR2		0x0006
+#define EMAC_TX_CTRL_TAH_SSR1		0x0004
+#define EMAC_TX_CTRL_TAH_SSR0		0x0002
 
 /* EMAC specific TX descriptor status fields (read access) */
 #define EMAC_TX_ST_BFCS			0x0200
diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c
index 9912456dca48..a0236eb305ae 100644
--- a/drivers/net/ethernet/ibm/emac/tah.c
+++ b/drivers/net/ethernet/ibm/emac/tah.c
@@ -45,6 +45,24 @@ void tah_detach(struct platform_device *ofdev, int channel)
 	mutex_unlock(&dev->lock);
 }
 
+static void tah_set_ssr(struct platform_device *ofdev)
+{
+	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct tah_regs __iomem *p = dev->base;
+	int i;
+
+	mutex_lock(&dev->lock);
+
+	for (i = 0; i < ARRAY_SIZE(tah_ss); i++) {
+		/* Segment size can be up to 16K, but needs
+		 * to be a multiple of 2 bytes
+		 */
+		out_be32(&p->ssr0 + i, (tah_ss[i] & 0x3ffe) << 16);
+	}
+
+	mutex_unlock(&dev->lock);
+}
+
 void tah_reset(struct platform_device *ofdev)
 {
 	struct tah_instance *dev = platform_get_drvdata(ofdev);
@@ -64,6 +82,8 @@ void tah_reset(struct platform_device *ofdev)
 	out_be32(&p->mr,
 		 TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |
 		 TAH_MR_DIG);
+
+	tah_set_ssr(ofdev);
 }
 
 int tah_get_regs_len(struct platform_device *ofdev)
diff --git a/drivers/net/ethernet/ibm/emac/tah.h b/drivers/net/ethernet/ibm/emac/tah.h
index 4d5f336f07b3..2cb0629f30e2 100644
--- a/drivers/net/ethernet/ibm/emac/tah.h
+++ b/drivers/net/ethernet/ibm/emac/tah.h
@@ -36,6 +36,8 @@ struct tah_regs {
 	u32 tsr;
 };
 
+#define TAH_NO_SSR	6
+extern const u32 tah_ss[TAH_NO_SSR];
 
 /* TAH device */
 struct tah_instance {
-- 
2.19.1

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

* Re: [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support
  2018-10-17 19:53 [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Christian Lamparter
  2018-10-17 19:53 ` [PATCH 2/2] net: emac: implement TCP TSO Christian Lamparter
@ 2018-10-17 20:08 ` Florian Fainelli
  2018-10-17 20:09   ` Florian Fainelli
  1 sibling, 1 reply; 7+ messages in thread
From: Florian Fainelli @ 2018-10-17 20:08 UTC (permalink / raw)
  To: Christian Lamparter, netdev; +Cc: David S . Miller

On 10/17/2018 12:53 PM, Christian Lamparter wrote:
> As per' APM82181 Embedded Processor User Manual 26.1 EMAC Features:
> VLAN:
>  - Support for VLAN tag ID in compliance with IEEE 802.3ac.
>  - VLAN tag insertion or replacement for transmit packets
> 
> This patch completes the missing code for the VLAN tx tagging
> support, as the the EMAC_MR1_VLE was already enabled.
> 
> Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
> ---
>  drivers/net/ethernet/ibm/emac/core.c | 32 ++++++++++++++++++++++++----
>  drivers/net/ethernet/ibm/emac/core.h |  6 +++++-
>  2 files changed, 33 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
> index 760b2ad8e295..be560f9031f4 100644
> --- a/drivers/net/ethernet/ibm/emac/core.c
> +++ b/drivers/net/ethernet/ibm/emac/core.c
> @@ -37,6 +37,7 @@
>  #include <linux/ethtool.h>
>  #include <linux/mii.h>
>  #include <linux/bitops.h>
> +#include <linux/if_vlan.h>
>  #include <linux/workqueue.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> @@ -674,7 +675,7 @@ static int emac_configure(struct emac_instance *dev)
>  		 ndev->dev_addr[5]);
>  
>  	/* VLAN Tag Protocol ID */
> -	out_be32(&p->vtpid, 0x8100);
> +	out_be32(&p->vtpid, ETH_P_8021Q);
>  
>  	/* Receive mode register */
>  	r = emac_iff2rmr(ndev);
> @@ -1435,6 +1436,22 @@ static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len)
>  	return NETDEV_TX_OK;
>  }
>  
> +static inline u16 emac_tx_vlan(struct emac_instance *dev, struct sk_buff *skb)
> +{
> +	/* Handle VLAN TPID and TCI insert if this is a VLAN skb */
> +	if (emac_has_feature(dev, EMAC_FTR_HAS_VLAN_CTAG_TX) &&
> +	    skb_vlan_tag_present(skb)) {
> +		struct emac_regs __iomem *p = dev->emacp;
> +
> +		/* update the VLAN TCI */
> +		out_be32(&p->vtci, (u32)skb_vlan_tag_get(skb));

The only case where this is likely not going to be 0x8100/ETH_P_8021Q is
if you do 802.1ad (QinQ) and you decided to somehow offload the S-Tag
instead of the C-Tag.

It would be a shame to slow down your TX path with an expensive register
write, when maybe inserting the VLAN in software amounts to the same
performance result ;)
-- 
Florian

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

* Re: [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support
  2018-10-17 20:08 ` [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Florian Fainelli
@ 2018-10-17 20:09   ` Florian Fainelli
  2018-10-19 15:56     ` Christian Lamparter
  0 siblings, 1 reply; 7+ messages in thread
From: Florian Fainelli @ 2018-10-17 20:09 UTC (permalink / raw)
  To: Christian Lamparter, netdev; +Cc: David S . Miller

On 10/17/2018 01:08 PM, Florian Fainelli wrote:
> On 10/17/2018 12:53 PM, Christian Lamparter wrote:
>> As per' APM82181 Embedded Processor User Manual 26.1 EMAC Features:
>> VLAN:
>>  - Support for VLAN tag ID in compliance with IEEE 802.3ac.
>>  - VLAN tag insertion or replacement for transmit packets
>>
>> This patch completes the missing code for the VLAN tx tagging
>> support, as the the EMAC_MR1_VLE was already enabled.
>>
>> Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
>> ---
>>  drivers/net/ethernet/ibm/emac/core.c | 32 ++++++++++++++++++++++++----
>>  drivers/net/ethernet/ibm/emac/core.h |  6 +++++-
>>  2 files changed, 33 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
>> index 760b2ad8e295..be560f9031f4 100644
>> --- a/drivers/net/ethernet/ibm/emac/core.c
>> +++ b/drivers/net/ethernet/ibm/emac/core.c
>> @@ -37,6 +37,7 @@
>>  #include <linux/ethtool.h>
>>  #include <linux/mii.h>
>>  #include <linux/bitops.h>
>> +#include <linux/if_vlan.h>
>>  #include <linux/workqueue.h>
>>  #include <linux/of.h>
>>  #include <linux/of_address.h>
>> @@ -674,7 +675,7 @@ static int emac_configure(struct emac_instance *dev)
>>  		 ndev->dev_addr[5]);
>>  
>>  	/* VLAN Tag Protocol ID */
>> -	out_be32(&p->vtpid, 0x8100);
>> +	out_be32(&p->vtpid, ETH_P_8021Q);
>>  
>>  	/* Receive mode register */
>>  	r = emac_iff2rmr(ndev);
>> @@ -1435,6 +1436,22 @@ static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len)
>>  	return NETDEV_TX_OK;
>>  }
>>  
>> +static inline u16 emac_tx_vlan(struct emac_instance *dev, struct sk_buff *skb)
>> +{
>> +	/* Handle VLAN TPID and TCI insert if this is a VLAN skb */
>> +	if (emac_has_feature(dev, EMAC_FTR_HAS_VLAN_CTAG_TX) &&
>> +	    skb_vlan_tag_present(skb)) {
>> +		struct emac_regs __iomem *p = dev->emacp;
>> +
>> +		/* update the VLAN TCI */
>> +		out_be32(&p->vtci, (u32)skb_vlan_tag_get(skb));
> 
> The only case where this is likely not going to be 0x8100/ETH_P_8021Q is
> if you do 802.1ad (QinQ) and you decided to somehow offload the S-Tag
> instead of the C-Tag.

Sorry, looks like I mixed up TCI and TPID here, this looks obviously
correct ;)
-- 
Florian

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

* Re: [PATCH 2/2] net: emac: implement TCP TSO
  2018-10-17 19:53 ` [PATCH 2/2] net: emac: implement TCP TSO Christian Lamparter
@ 2018-10-17 20:09   ` Florian Fainelli
  2018-10-19 15:39     ` Christian Lamparter
  0 siblings, 1 reply; 7+ messages in thread
From: Florian Fainelli @ 2018-10-17 20:09 UTC (permalink / raw)
  To: Christian Lamparter, netdev; +Cc: David S . Miller

On 10/17/2018 12:53 PM, Christian Lamparter wrote:
> This patch enables TSO(v4) hw feature for emac driver.
> As atleast the APM82181's TCP/IP acceleration hardware
> controller (TAH) provides TCP segmentation support in
> the transmit path.
> 
> Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
> ---
>  drivers/net/ethernet/ibm/emac/core.c | 101 ++++++++++++++++++++++++++-
>  drivers/net/ethernet/ibm/emac/core.h |   4 ++
>  drivers/net/ethernet/ibm/emac/emac.h |   7 ++
>  drivers/net/ethernet/ibm/emac/tah.c  |  20 ++++++
>  drivers/net/ethernet/ibm/emac/tah.h  |   2 +
>  5 files changed, 133 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
> index be560f9031f4..49ffbd6e1707 100644
> --- a/drivers/net/ethernet/ibm/emac/core.c
> +++ b/drivers/net/ethernet/ibm/emac/core.c
> @@ -38,6 +38,9 @@
>  #include <linux/mii.h>
>  #include <linux/bitops.h>
>  #include <linux/if_vlan.h>
> +#include <linux/ip.h>
> +#include <linux/ipv6.h>
> +#include <linux/tcp.h>
>  #include <linux/workqueue.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> @@ -1410,6 +1413,52 @@ static inline u16 emac_tx_csum(struct emac_instance *dev,
>  	return 0;
>  }
>  
> +const u32 tah_ss[TAH_NO_SSR] = { 9000, 4500, 1500, 1300, 576, 176 };
> +
> +static int emac_tx_tso(struct emac_instance *dev, struct sk_buff *skb,
> +		       u16 *ctrl)
> +{
> +	if (emac_has_feature(dev, EMAC_FTR_TAH_HAS_TSO) &&
> +	    skb_is_gso(skb) && !!(skb_shinfo(skb)->gso_type &
> +				(SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
> +		u32 seg_size = 0, i;
> +
> +		/* Get the MTU */
> +		seg_size = skb_shinfo(skb)->gso_size + tcp_hdrlen(skb)
> +			+ skb_network_header_len(skb);
> +
> +		/* Restriction applied for the segmentation size
> +		 * to use HW segmentation offload feature: the size
> +		 * of the segment must not be less than 168 bytes for
> +		 * DIX formatted segments, or 176 bytes for
> +		 * IEEE formatted segments.
> +		 *
> +		 * I use value 176 to check for the segment size here
> +		 * as it can cover both 2 conditions above.
> +		 */
> +		if (seg_size < 176)
> +			return -ENODEV;
> +
> +		/* Get the best suitable MTU */
> +		for (i = 0; i < ARRAY_SIZE(tah_ss); i++) {
> +			u32 curr_seg = tah_ss[i];
> +
> +			if (curr_seg > dev->ndev->mtu ||
> +			    curr_seg > seg_size)
> +				continue;
> +
> +			*ctrl &= ~EMAC_TX_CTRL_TAH_CSUM;
> +			*ctrl |= EMAC_TX_CTRL_TAH_SSR(i);
> +			return 0;

This is something that you can possibly take out of your hot path and
recalculate when the MTU actually changes?

[snip]

> +static netdev_tx_t emac_sw_tso(struct sk_buff *skb, struct net_device *ndev)
> +{
> +	struct emac_instance *dev = netdev_priv(ndev);
> +	struct sk_buff *segs, *curr;
> +
> +	segs = skb_gso_segment(skb, ndev->features &
> +					~(NETIF_F_TSO | NETIF_F_TSO6));
> +	if (IS_ERR_OR_NULL(segs)) {
> +		goto drop;
> +	} else {
> +		while (segs) {
> +			/* check for overflow */
> +			if (dev->tx_cnt >= NUM_TX_BUFF) {
> +				dev_kfree_skb_any(segs);
> +				goto drop;
> +			}

Would setting dev->max_gso_segs somehow help make sure the stack does
not feed you oversized GSO'd skbs?
-- 
Florian

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

* Re: [PATCH 2/2] net: emac: implement TCP TSO
  2018-10-17 20:09   ` Florian Fainelli
@ 2018-10-19 15:39     ` Christian Lamparter
  0 siblings, 0 replies; 7+ messages in thread
From: Christian Lamparter @ 2018-10-19 15:39 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: netdev, David S . Miller

Hello,

On Wednesday, October 17, 2018 10:09:44 PM CEST Florian Fainelli wrote:
> On 10/17/2018 12:53 PM, Christian Lamparter wrote:
> > This patch enables TSO(v4) hw feature for emac driver.
> > As atleast the APM82181's TCP/IP acceleration hardware
> > controller (TAH) provides TCP segmentation support in
> > the transmit path.
> > 
> > Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
> > ---
> > diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
> > index be560f9031f4..49ffbd6e1707 100644
> > --- a/drivers/net/ethernet/ibm/emac/core.c
> > +++ b/drivers/net/ethernet/ibm/emac/core.c
> > @@ -1410,6 +1413,52 @@ static inline u16 emac_tx_csum(struct emac_instance *dev,
> >  	return 0;
> >  }
> >  
> > +const u32 tah_ss[TAH_NO_SSR] = { 9000, 4500, 1500, 1300, 576, 176 };
> > +
> > +static int emac_tx_tso(struct emac_instance *dev, struct sk_buff *skb,
> > +		       u16 *ctrl)
> > +{
> > +	if (emac_has_feature(dev, EMAC_FTR_TAH_HAS_TSO) &&
> > +	    skb_is_gso(skb) && !!(skb_shinfo(skb)->gso_type &
> > +				(SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
> > +		u32 seg_size = 0, i;
> > +
> > +		/* Get the MTU */
> > +		seg_size = skb_shinfo(skb)->gso_size + tcp_hdrlen(skb)
> > +			+ skb_network_header_len(skb);
> > +
> > +		/* Restriction applied for the segmentation size
> > +		 * to use HW segmentation offload feature: the size
> > +		 * of the segment must not be less than 168 bytes for
> > +		 * DIX formatted segments, or 176 bytes for
> > +		 * IEEE formatted segments.
> > +		 *
> > +		 * I use value 176 to check for the segment size here
> > +		 * as it can cover both 2 conditions above.
> > +		 */
> > +		if (seg_size < 176)
> > +			return -ENODEV;
> > +
> > +		/* Get the best suitable MTU */
> > +		for (i = 0; i < ARRAY_SIZE(tah_ss); i++) {
> > +			u32 curr_seg = tah_ss[i];
> > +
> > +			if (curr_seg > dev->ndev->mtu ||
> > +			    curr_seg > seg_size)
> > +				continue;
> > +
> > +			*ctrl &= ~EMAC_TX_CTRL_TAH_CSUM;
> > +			*ctrl |= EMAC_TX_CTRL_TAH_SSR(i);
> > +			return 0;
> 
> This is something that you can possibly take out of your hot path and
> recalculate when the MTU actually changes?

Do you mean the curr_seg > dev->ndev->mtu check? Because from what I
know, the MSS can be manually set by a socket option (TCP_MAXSEG) on a
"per-socket" base.

(Altough, iperf warns that "Setting MSS is very buggy"... Which it is
as I see more way retries with a iperf run with a MSS less than
768-ish. Ideally, the change_mtu could update the TAH_SS register )

> [snip]
> 
> > +static netdev_tx_t emac_sw_tso(struct sk_buff *skb, struct net_device *ndev)
> > +{
> > +	struct emac_instance *dev = netdev_priv(ndev);
> > +	struct sk_buff *segs, *curr;
> > +
> > +	segs = skb_gso_segment(skb, ndev->features &
> > +					~(NETIF_F_TSO | NETIF_F_TSO6));
> > +	if (IS_ERR_OR_NULL(segs)) {
> > +		goto drop;
> > +	} else {
> > +		while (segs) {
> > +			/* check for overflow */
> > +			if (dev->tx_cnt >= NUM_TX_BUFF) {
> > +				dev_kfree_skb_any(segs);
> > +				goto drop;
> > +			}
> 
> Would setting dev->max_gso_segs somehow help make sure the stack does
> not feed you oversized GSO'd skbs?
Ok, thanks's for that pointer. I'll look at dev->gso_max_segs and
dev->gso_max_size. The hardware documentation doesn't mention any
hard upper limit for how many segments it can do. What it does tell
is that it just needs an extra 512Bytes in the TX FIFO as a buffer
to store the header template and the calculated checksums and what
not.
 
But this should be no problem because that TX FIFO is 10 KiB. so even
the 9000 Jumbo frames should have plenty of "free real estate".

As for the "overflow" case:

There's a check in emac_start_xmit_sg() before emac_tx_tso() call that
does an *estimation* check and goes to "stop_queue" if it doesn't fit:

|        /* Note, this is only an *estimation*, we can still run out of empty
|         * slots because of the additional fragmentation into
|         * MAL_MAX_TX_SIZE-sized chunks
|         */
|        if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF))
|                goto stop_queue;
|        [...]
|
|        if (emac_tx_tso(dev, skb, &ctrl))
|               return emac_sw_tso(skb, ndev);
|        [....]
|
|		stop_queue:
|		 netif_stop_queue(ndev);
|		 DBG2(dev, "stopped TX queue" NL);
|		 return NETDEV_TX_BUSY;

emac_start_xmit_sg() can also drop the whole skb later if it turns
out that it doesn't fit. (see the "undo_frame" goto label in emac's
core.c file (not included in the extract above, but it is there).

That said, I could do a better job at making sure that no incomplete
skb gets sent to the network though. 
@Dave: Please ignore this version of the TSO patch for now.

Regards,
Christian

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

* Re: [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support
  2018-10-17 20:09   ` Florian Fainelli
@ 2018-10-19 15:56     ` Christian Lamparter
  0 siblings, 0 replies; 7+ messages in thread
From: Christian Lamparter @ 2018-10-19 15:56 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: netdev, David S . Miller

On Wednesday, October 17, 2018 10:09:10 PM CEST Florian Fainelli wrote:
> On 10/17/2018 01:08 PM, Florian Fainelli wrote:
> > On 10/17/2018 12:53 PM, Christian Lamparter wrote:
> >> As per' APM82181 Embedded Processor User Manual 26.1 EMAC Features:
> >> VLAN:
> >>  - Support for VLAN tag ID in compliance with IEEE 802.3ac.
> >>  - VLAN tag insertion or replacement for transmit packets
> >>
> >> This patch completes the missing code for the VLAN tx tagging
> >> support, as the the EMAC_MR1_VLE was already enabled.
> >>
> >> Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
> >> ---
> >>  drivers/net/ethernet/ibm/emac/core.c | 32 ++++++++++++++++++++++++----
> >>  drivers/net/ethernet/ibm/emac/core.h |  6 +++++-
> >>  2 files changed, 33 insertions(+), 5 deletions(-)
> >>
> >> diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
> >> index 760b2ad8e295..be560f9031f4 100644
> >> --- a/drivers/net/ethernet/ibm/emac/core.c
> >> +++ b/drivers/net/ethernet/ibm/emac/core.c
> >> @@ -37,6 +37,7 @@
> >>  #include <linux/ethtool.h>
> >>  #include <linux/mii.h>
> >>  #include <linux/bitops.h>
> >> +#include <linux/if_vlan.h>
> >>  #include <linux/workqueue.h>
> >>  #include <linux/of.h>
> >>  #include <linux/of_address.h>
> >> @@ -674,7 +675,7 @@ static int emac_configure(struct emac_instance *dev)
> >>  		 ndev->dev_addr[5]);
> >>  
> >>  	/* VLAN Tag Protocol ID */
> >> -	out_be32(&p->vtpid, 0x8100);
> >> +	out_be32(&p->vtpid, ETH_P_8021Q);
> >>  
> >>  	/* Receive mode register */
> >>  	r = emac_iff2rmr(ndev);
> >> @@ -1435,6 +1436,22 @@ static inline netdev_tx_t emac_xmit_finish(struct emac_instance *dev, int len)
> >>  	return NETDEV_TX_OK;
> >>  }
> >>  
> >> +static inline u16 emac_tx_vlan(struct emac_instance *dev, struct sk_buff *skb)
> >> +{
> >> +	/* Handle VLAN TPID and TCI insert if this is a VLAN skb */
> >> +	if (emac_has_feature(dev, EMAC_FTR_HAS_VLAN_CTAG_TX) &&
> >> +	    skb_vlan_tag_present(skb)) {
> >> +		struct emac_regs __iomem *p = dev->emacp;
> >> +
> >> +		/* update the VLAN TCI */
> >> +		out_be32(&p->vtci, (u32)skb_vlan_tag_get(skb));
> > 
> > The only case where this is likely not going to be 0x8100/ETH_P_8021Q is
> > if you do 802.1ad (QinQ) and you decided to somehow offload the S-Tag
> > instead of the C-Tag.
> 
> Sorry, looks like I mixed up TCI and TPID here, this looks obviously
> correct ;)

Ok, I wasn't really sure what to write anyway ;).

The hardware documentation mentions that:
"Support for VLAN tag ID in compliance with IEEE Draft 802.3ac/D1.0 standard".
It's too old for offloading any fancy QinQ stuff :(.

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

end of thread, other threads:[~2018-10-20  0:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-17 19:53 [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Christian Lamparter
2018-10-17 19:53 ` [PATCH 2/2] net: emac: implement TCP TSO Christian Lamparter
2018-10-17 20:09   ` Florian Fainelli
2018-10-19 15:39     ` Christian Lamparter
2018-10-17 20:08 ` [PATCH 1/2] net: emac: implement 802.1Q VLAN TX tagging support Florian Fainelli
2018-10-17 20:09   ` Florian Fainelli
2018-10-19 15:56     ` Christian Lamparter

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.