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>
This commit is contained in:
committed by
David S. Miller
parent
88ebe2cf7f
commit
b776620651
@@ -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)
|
|||||||
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)
|
|||||||
tx_q = &priv->tx_queue[queue];
|
tx_q = &priv->tx_queue[queue];
|
||||||
|
|
||||||
/* Compute header lengths */
|
/* Compute header lengths */
|
||||||
|
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);
|
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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,
|
|||||||
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user