diff options
author | Jose Abreu <Jose.Abreu@synopsys.com> | 2019-11-11 15:42:39 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-11-11 23:13:19 -0800 |
commit | b776620651a1182976b51643bb2c5b08d535fb2e (patch) | |
tree | d90d51d74d0a88de47ed1875be9bdc70abc200d8 /drivers/net/ethernet/stmicro | |
parent | 88ebe2cf7f3fc9da95e0f06483fd58da3e67e675 (diff) | |
download | linux-b776620651a1182976b51643bb2c5b08d535fb2e.tar.bz2 |
net: stmmac: Implement UDP Segmentation Offload
Implement the UDP Segmentation Offload feature in stmmac. This is only
available in GMAC4+ cores.
Signed-off-by: Jose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a2fac7772666..39b4efd521f9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -36,6 +36,7 @@ #endif /* CONFIG_DEBUG_FS */ #include <linux/net_tstamp.h> #include <linux/phylink.h> +#include <linux/udp.h> #include <net/pkt_cls.h> #include "stmmac_ptp.h" #include "stmmac.h" @@ -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); struct stmmac_tx_queue *tx_q; unsigned int first_entry; + u8 proto_hdr_len, hdr; int tmp_pay_len = 0; u32 pay_len, mss; - u8 proto_hdr_len; dma_addr_t des; bool has_vlan; int i; @@ -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]; /* 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 */ 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) } if (netif_msg_tx_queued(priv)) { - pr_info("%s: tcphdrlen %d, hdr_len %d, pay_len %d, mss %d\n", - __func__, tcp_hdrlen(skb), proto_hdr_len, pay_len, mss); + pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n", + __func__, hdr, proto_hdr_len, pay_len, mss); pr_info("\tskb->len %d, skb->data_len %d\n", skb->len, skb->data_len); } @@ -3071,7 +3078,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) proto_hdr_len, pay_len, 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 (mss_desc) { @@ -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; u32 queue = skb_get_queue_mapping(skb); int nfrags = skb_shinfo(skb)->nr_frags; + int gso = skb_shinfo(skb)->gso_type; struct dma_desc *desc, *first; struct stmmac_tx_queue *tx_q; unsigned int first_entry; @@ -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 */ 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); } @@ -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, 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 - * because if TSO is supported then at least this + * because if TSO/USO is supported then at least this * one will be capable. */ return 0; @@ -4555,6 +4567,8 @@ int stmmac_dvr_probe(struct device *device, if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { 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; dev_info(priv->device, "TSO feature enabled\n"); } |