ramips: ethernet: ralink: fix offload with diff dsa tag
DSA copies the driver features to slave device, including offload capabilites. Once a packet is sent though a DSA slave interface, according to its features, the kernel does not calculate checksums, expecting that the HW will fill the gaps. DSA adds the defined DSA tag and sends the tagged packet through the master device. Ethertype DSA tags expect the driver to calculate checksum based on the csum_start/csum_offset. However, mtk_eth_soc does not use that info. mtk_eth_soc checks the network header and decides if the HW can manage that packet, unaware that mac layer now contains an extra DSA tag. When that tag is the Mediatek CPU tag, offload will work as expected. When it is an incompatible DSA tag (all but Mediatek) or if DSA is stacking two incompatible DSA tags, the driver will still count on the HW offload. In this case, packets go to the network with an incorrect checksum. This patch adds an extra check and disables offloading when DSA tag is in use and it is not Mediatek. Offloading is also disabled even when DSA tag is Mediatek but there is something else increasing the mac layer region (possibly another stacked tag). Mediatek tag can encode 802.1Q info and using vlan tags will still use offloading. Other mac layer protocols that are not supported by Mediatek will disable HW offloading. PPPoE was not tested but it is expected that it will disable offloading. This code is heuristically trying to keep HW offload enable with DSA tags. Anyway, in the worse case, offloading is disabled and there is an increase in overhead, which is better than packet with wrong checksum. Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com> Link: https://github.com/openwrt/openwrt/pull/23933 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
committed by
Robert Marko
parent
84aafc08d7
commit
3c0a73b4d2
@@ -41,6 +41,10 @@
|
||||
#include "mdio.h"
|
||||
#include "ethtool.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
#include <net/dsa.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_MT7620)
|
||||
#define DMA_FWD_REG MT7620A_GDMA1_FWD_CFG
|
||||
#define MAX_RX_LENGTH 2048
|
||||
@@ -786,6 +790,41 @@ err_out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
#define MTK_HDR_LEN 4
|
||||
|
||||
static netdev_features_t fe_features_check(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
/* No point in doing any of this if neither checksum nor GSO are
|
||||
* being requested for this frame. We can rule out both by just
|
||||
* checking for CHECKSUM_PARTIAL
|
||||
*/
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
return features;
|
||||
|
||||
/* DSA tag might break existing offload checks as offload feature flags
|
||||
* are copied to slave ports and this driver does not use csum_start. */
|
||||
if (netdev_uses_dsa(dev)) {
|
||||
const struct dsa_device_ops *tag_ops = dev->dsa_ptr->tag_ops;
|
||||
|
||||
/* If tag is Mediatek, checksum should work */
|
||||
if (tag_ops->proto == DSA_TAG_PROTO_MTK)
|
||||
/* However, make sure that it is not stacking another
|
||||
* L2 protocol, possibly a second incompatible DSA tag
|
||||
* 802.1Q does not increase the mac header size because
|
||||
* it is embedded inside mediatek tag */
|
||||
if (skb_mac_header_len(skb) <= ETH_HLEN + MTK_HDR_LEN)
|
||||
return features;
|
||||
|
||||
features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int fe_skb_padto(struct sk_buff *skb, struct fe_priv *priv)
|
||||
{
|
||||
unsigned int len;
|
||||
@@ -1491,6 +1530,9 @@ static const struct net_device_ops fe_netdev_ops = {
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = fe_poll_controller,
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
.ndo_features_check = fe_features_check,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void fe_reset_pending(struct fe_priv *priv)
|
||||
|
||||
Reference in New Issue
Block a user