Commit b7766206 authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller

net: stmmac: Implement UDP Segmentation Offload

Implement the UDP Segmentation Offload feature in stmmac. This is only
available in GMAC4+ cores.
Signed-off-by: default avatarJose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 88ebe2cf
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/phylink.h> #include <linux/phylink.h>
#include <linux/udp.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include "stmmac_ptp.h" #include "stmmac_ptp.h"
#include "stmmac.h" #include "stmmac.h"
...@@ -2916,9 +2917,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2916,9 +2917,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
u32 queue = skb_get_queue_mapping(skb); u32 queue = skb_get_queue_mapping(skb);
struct stmmac_tx_queue *tx_q; struct stmmac_tx_queue *tx_q;
unsigned int first_entry; unsigned int first_entry;
u8 proto_hdr_len, hdr;
int tmp_pay_len = 0; int tmp_pay_len = 0;
u32 pay_len, mss; u32 pay_len, mss;
u8 proto_hdr_len;
dma_addr_t des; dma_addr_t des;
bool has_vlan; bool has_vlan;
int i; int i;
...@@ -2926,7 +2927,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2926,7 +2927,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
tx_q = &priv->tx_queue[queue]; tx_q = &priv->tx_queue[queue];
/* Compute header lengths */ /* Compute header lengths */
proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
proto_hdr_len = skb_transport_offset(skb) + sizeof(struct udphdr);
hdr = sizeof(struct udphdr);
} else {
proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
hdr = tcp_hdrlen(skb);
}
/* Desc availability based on threshold should be enough safe */ /* Desc availability based on threshold should be enough safe */
if (unlikely(stmmac_tx_avail(priv, queue) < if (unlikely(stmmac_tx_avail(priv, queue) <
...@@ -2956,8 +2963,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2956,8 +2963,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
} }
if (netif_msg_tx_queued(priv)) { if (netif_msg_tx_queued(priv)) {
pr_info("%s: tcphdrlen %d, hdr_len %d, pay_len %d, mss %d\n", pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n",
__func__, tcp_hdrlen(skb), proto_hdr_len, pay_len, mss); __func__, hdr, proto_hdr_len, pay_len, mss);
pr_info("\tskb->len %d, skb->data_len %d\n", skb->len, pr_info("\tskb->len %d, skb->data_len %d\n", skb->len,
skb->data_len); skb->data_len);
} }
...@@ -3071,7 +3078,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3071,7 +3078,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
proto_hdr_len, proto_hdr_len,
pay_len, pay_len,
1, tx_q->tx_skbuff_dma[first_entry].last_segment, 1, tx_q->tx_skbuff_dma[first_entry].last_segment,
tcp_hdrlen(skb) / 4, (skb->len - proto_hdr_len)); hdr / 4, (skb->len - proto_hdr_len));
/* If context desc is used to change MSS */ /* If context desc is used to change MSS */
if (mss_desc) { if (mss_desc) {
...@@ -3130,6 +3137,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3130,6 +3137,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
int i, csum_insertion = 0, is_jumbo = 0; int i, csum_insertion = 0, is_jumbo = 0;
u32 queue = skb_get_queue_mapping(skb); u32 queue = skb_get_queue_mapping(skb);
int nfrags = skb_shinfo(skb)->nr_frags; int nfrags = skb_shinfo(skb)->nr_frags;
int gso = skb_shinfo(skb)->gso_type;
struct dma_desc *desc, *first; struct dma_desc *desc, *first;
struct stmmac_tx_queue *tx_q; struct stmmac_tx_queue *tx_q;
unsigned int first_entry; unsigned int first_entry;
...@@ -3145,7 +3153,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3145,7 +3153,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
/* Manage oversized TCP frames for GMAC4 device */ /* Manage oversized TCP frames for GMAC4 device */
if (skb_is_gso(skb) && priv->tso) { if (skb_is_gso(skb) && priv->tso) {
if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))
return stmmac_tso_xmit(skb, dev);
if (priv->plat->has_gmac4 && (gso & SKB_GSO_UDP_L4))
return stmmac_tso_xmit(skb, dev); return stmmac_tso_xmit(skb, dev);
} }
...@@ -4036,11 +4046,13 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type, ...@@ -4036,11 +4046,13 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb, static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev) struct net_device *sb_dev)
{ {
if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { int gso = skb_shinfo(skb)->gso_type;
if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6 | SKB_GSO_UDP_L4)) {
/* /*
* There is no way to determine the number of TSO * There is no way to determine the number of TSO/USO
* capable Queues. Let's use always the Queue 0 * capable Queues. Let's use always the Queue 0
* because if TSO is supported then at least this * because if TSO/USO is supported then at least this
* one will be capable. * one will be capable.
*/ */
return 0; return 0;
...@@ -4555,6 +4567,8 @@ int stmmac_dvr_probe(struct device *device, ...@@ -4555,6 +4567,8 @@ int stmmac_dvr_probe(struct device *device,
if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
if (priv->plat->has_gmac4)
ndev->hw_features |= NETIF_F_GSO_UDP_L4;
priv->tso = true; priv->tso = true;
dev_info(priv->device, "TSO feature enabled\n"); dev_info(priv->device, "TSO feature enabled\n");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment