From 7b3e018f3eefc6144638800d9f92b3a5e120c537 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:23 +0800 Subject: [PATCH 01/16] net: vxlan: make vxlan_remcsum() return drop reasons Make vxlan_remcsum() support skb drop reasons by changing the return value type of it from bool to enum skb_drop_reason. The only drop reason in vxlan_remcsum() comes from pskb_may_pull_reason(), so we just return it. Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Reviewed-by: Kalesh AP Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 40111d05d18e..e3ac46d6e148 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1551,9 +1551,11 @@ static void vxlan_sock_release(struct vxlan_dev *vxlan) #endif } -static bool vxlan_remcsum(struct vxlanhdr *unparsed, - struct sk_buff *skb, u32 vxflags) +static enum skb_drop_reason vxlan_remcsum(struct vxlanhdr *unparsed, + struct sk_buff *skb, + u32 vxflags) { + enum skb_drop_reason reason; size_t start, offset; if (!(unparsed->vx_flags & VXLAN_HF_RCO) || skb->remcsum_offload) @@ -1562,15 +1564,17 @@ static bool vxlan_remcsum(struct vxlanhdr *unparsed, start = vxlan_rco_start(unparsed->vx_vni); offset = start + vxlan_rco_offset(unparsed->vx_vni); - if (!pskb_may_pull(skb, offset + sizeof(u16))) - return false; + reason = pskb_may_pull_reason(skb, offset + sizeof(u16)); + if (reason) + return reason; skb_remcsum_process(skb, (void *)(vxlan_hdr(skb) + 1), start, offset, !!(vxflags & VXLAN_F_REMCSUM_NOPARTIAL)); out: unparsed->vx_flags &= ~VXLAN_HF_RCO; unparsed->vx_vni &= VXLAN_VNI_MASK; - return true; + + return SKB_NOT_DROPPED_YET; } static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed, @@ -1723,9 +1727,11 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) goto drop; } - if (vs->flags & VXLAN_F_REMCSUM_RX) - if (unlikely(!vxlan_remcsum(&unparsed, skb, vs->flags))) + if (vs->flags & VXLAN_F_REMCSUM_RX) { + reason = vxlan_remcsum(&unparsed, skb, vs->flags); + if (unlikely(reason)) goto drop; + } if (vxlan_collect_metadata(vs)) { IP_TUNNEL_DECLARE_FLAGS(flags) = { }; -- 2.51.0 From 289fd4e75219a96f77c5d679166035cd5118d139 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:24 +0800 Subject: [PATCH 02/16] net: vxlan: make vxlan_snoop() return drop reasons Change the return type of vxlan_snoop() from bool to enum skb_drop_reason. In this commit, two drop reasons are introduced: SKB_DROP_REASON_MAC_INVALID_SOURCE SKB_DROP_REASON_VXLAN_ENTRY_EXISTS Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 17 +++++++++-------- include/net/dropreason-core.h | 9 +++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index e3ac46d6e148..947c29d6605c 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1437,9 +1437,10 @@ errout: * and Tunnel endpoint. * Return true if packet is bogus and should be dropped. */ -static bool vxlan_snoop(struct net_device *dev, - union vxlan_addr *src_ip, const u8 *src_mac, - u32 src_ifindex, __be32 vni) +static enum skb_drop_reason vxlan_snoop(struct net_device *dev, + union vxlan_addr *src_ip, + const u8 *src_mac, u32 src_ifindex, + __be32 vni) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_fdb *f; @@ -1447,7 +1448,7 @@ static bool vxlan_snoop(struct net_device *dev, /* Ignore packets from invalid src-address */ if (!is_valid_ether_addr(src_mac)) - return true; + return SKB_DROP_REASON_MAC_INVALID_SOURCE; #if IS_ENABLED(CONFIG_IPV6) if (src_ip->sa.sa_family == AF_INET6 && @@ -1461,15 +1462,15 @@ static bool vxlan_snoop(struct net_device *dev, if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) && rdst->remote_ifindex == ifindex)) - return false; + return SKB_NOT_DROPPED_YET; /* Don't migrate static entries, drop packets */ if (f->state & (NUD_PERMANENT | NUD_NOARP)) - return true; + return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; /* Don't override an fdb with nexthop with a learnt entry */ if (rcu_access_pointer(f->nh)) - return true; + return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; if (net_ratelimit()) netdev_info(dev, @@ -1497,7 +1498,7 @@ static bool vxlan_snoop(struct net_device *dev, spin_unlock(&vxlan->hash_lock[hash_index]); } - return false; + return SKB_NOT_DROPPED_YET; } static bool __vxlan_sock_release_prep(struct vxlan_sock *vs) diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index 98259d2b3e92..1cb8d7c953be 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -94,6 +94,8 @@ FN(TC_RECLASSIFY_LOOP) \ FN(VXLAN_INVALID_HDR) \ FN(VXLAN_VNI_NOT_FOUND) \ + FN(MAC_INVALID_SOURCE) \ + FN(VXLAN_ENTRY_EXISTS) \ FN(IP_TUNNEL_ECN) \ FNe(MAX) @@ -429,6 +431,13 @@ enum skb_drop_reason { SKB_DROP_REASON_VXLAN_INVALID_HDR, /** @SKB_DROP_REASON_VXLAN_VNI_NOT_FOUND: no VXLAN device found for VNI */ SKB_DROP_REASON_VXLAN_VNI_NOT_FOUND, + /** @SKB_DROP_REASON_MAC_INVALID_SOURCE: source mac is invalid */ + SKB_DROP_REASON_MAC_INVALID_SOURCE, + /** + * @SKB_DROP_REASON_VXLAN_ENTRY_EXISTS: trying to migrate a static + * entry or an entry pointing to a nexthop. + */ + SKB_DROP_REASON_VXLAN_ENTRY_EXISTS, /** * @SKB_DROP_REASON_IP_TUNNEL_ECN: skb is dropped according to * RFC 6040 4.2, see __INET_ECN_decapsulate() for detail. -- 2.51.0 From d209706f562ee4fa81bdf24cf6b679c3222aa06c Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:25 +0800 Subject: [PATCH 03/16] net: vxlan: make vxlan_set_mac() return drop reasons Change the return type of vxlan_set_mac() from bool to enum skb_drop_reason. In this commit, the drop reason "SKB_DROP_REASON_LOCAL_MAC" is introduced for the case that the source mac of the packet is a local mac. Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 19 ++++++++++--------- include/net/dropreason-core.h | 6 ++++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 947c29d6605c..b4f9f23797de 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1609,9 +1609,9 @@ out: unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS; } -static bool vxlan_set_mac(struct vxlan_dev *vxlan, - struct vxlan_sock *vs, - struct sk_buff *skb, __be32 vni) +static enum skb_drop_reason vxlan_set_mac(struct vxlan_dev *vxlan, + struct vxlan_sock *vs, + struct sk_buff *skb, __be32 vni) { union vxlan_addr saddr; u32 ifindex = skb->dev->ifindex; @@ -1622,7 +1622,7 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, /* Ignore packet loops (and multicast echo) */ if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) - return false; + return SKB_DROP_REASON_LOCAL_MAC; /* Get address from the outer IP header */ if (vxlan_get_sk_family(vs) == AF_INET) { @@ -1635,11 +1635,11 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, #endif } - if ((vxlan->cfg.flags & VXLAN_F_LEARN) && - vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni)) - return false; + if (!(vxlan->cfg.flags & VXLAN_F_LEARN)) + return SKB_NOT_DROPPED_YET; - return true; + return vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, + ifindex, vni); } static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph, @@ -1774,7 +1774,8 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) } if (!raw_proto) { - if (!vxlan_set_mac(vxlan, vs, skb, vni)) + reason = vxlan_set_mac(vxlan, vs, skb, vni); + if (reason) goto drop; } else { skb_reset_mac_header(skb); diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index 1cb8d7c953be..fbf92d442c1b 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -97,6 +97,7 @@ FN(MAC_INVALID_SOURCE) \ FN(VXLAN_ENTRY_EXISTS) \ FN(IP_TUNNEL_ECN) \ + FN(LOCAL_MAC) \ FNe(MAX) /** @@ -443,6 +444,11 @@ enum skb_drop_reason { * RFC 6040 4.2, see __INET_ECN_decapsulate() for detail. */ SKB_DROP_REASON_IP_TUNNEL_ECN, + /** + * @SKB_DROP_REASON_LOCAL_MAC: the source MAC address is equal to + * the MAC address of the local netdev. + */ + SKB_DROP_REASON_LOCAL_MAC, /** * @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which * shouldn't be used as a real 'reason' - only for tracing code gen -- 2.51.0 From b71a576e452b800efeac49ecca116d954601d911 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:26 +0800 Subject: [PATCH 04/16] net: vxlan: use kfree_skb_reason() in vxlan_xmit() Replace kfree_skb() with kfree_skb_reason() in vxlan_xmit(). Following new skb drop reasons are introduced for vxlan: /* no remote found for xmit */ SKB_DROP_REASON_VXLAN_NO_REMOTE /* packet without necessary metadata reached a device which is * in "external" mode */ SKB_DROP_REASON_TUNNEL_TXINFO Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 6 +++--- include/net/dropreason-core.h | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index b4f9f23797de..649b4ea5c362 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2730,7 +2730,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (info && info->mode & IP_TUNNEL_INFO_TX) vxlan_xmit_one(skb, dev, vni, NULL, false); else - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_TUNNEL_TXINFO); return NETDEV_TX_OK; } } @@ -2793,7 +2793,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) dev_core_stats_tx_dropped_inc(dev); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE); return NETDEV_TX_OK; } } @@ -2816,7 +2816,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (fdst) vxlan_xmit_one(skb, dev, vni, fdst, did_rsc); else - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE); } return NETDEV_TX_OK; diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h index fbf92d442c1b..d59bb96c5a02 100644 --- a/include/net/dropreason-core.h +++ b/include/net/dropreason-core.h @@ -96,7 +96,9 @@ FN(VXLAN_VNI_NOT_FOUND) \ FN(MAC_INVALID_SOURCE) \ FN(VXLAN_ENTRY_EXISTS) \ + FN(VXLAN_NO_REMOTE) \ FN(IP_TUNNEL_ECN) \ + FN(TUNNEL_TXINFO) \ FN(LOCAL_MAC) \ FNe(MAX) @@ -439,11 +441,18 @@ enum skb_drop_reason { * entry or an entry pointing to a nexthop. */ SKB_DROP_REASON_VXLAN_ENTRY_EXISTS, + /** @SKB_DROP_REASON_VXLAN_NO_REMOTE: no remote found for xmit */ + SKB_DROP_REASON_VXLAN_NO_REMOTE, /** * @SKB_DROP_REASON_IP_TUNNEL_ECN: skb is dropped according to * RFC 6040 4.2, see __INET_ECN_decapsulate() for detail. */ SKB_DROP_REASON_IP_TUNNEL_ECN, + /** + * @SKB_DROP_REASON_TUNNEL_TXINFO: packet without necessary metadata + * reached a device which is in "external" mode. + */ + SKB_DROP_REASON_TUNNEL_TXINFO, /** * @SKB_DROP_REASON_LOCAL_MAC: the source MAC address is equal to * the MAC address of the local netdev. -- 2.51.0 From e7c700aaa67a59c28da07072fbaae207b5f27519 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:27 +0800 Subject: [PATCH 05/16] net: vxlan: add drop reasons support to vxlan_xmit_one() Replace kfree_skb/dev_kfree_skb with kfree_skb_reason in vxlan_xmit_one. No drop reasons are introduced in this commit. The only concern of mine is replacing dev_kfree_skb with kfree_skb_reason. The dev_kfree_skb is equal to consume_skb, and I'm not sure if we can change it to kfree_skb here. In my option, the skb is "dropped" here, isn't it? Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 649b4ea5c362..e82f2e30bd39 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2374,13 +2374,16 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, bool use_cache; bool udp_sum = false; bool xnet = !net_eq(vxlan->net, dev_net(vxlan->dev)); + enum skb_drop_reason reason; bool no_eth_encap; __be32 vni = 0; no_eth_encap = flags & VXLAN_F_GPE && skb->protocol != htons(ETH_P_TEB); - if (skb_vlan_inet_prepare(skb, no_eth_encap)) + reason = skb_vlan_inet_prepare(skb, no_eth_encap); + if (reason) goto drop; + reason = SKB_DROP_REASON_NOT_SPECIFIED; old_iph = ip_hdr(skb); info = skb_tunnel_info(skb); @@ -2484,6 +2487,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos, use_cache ? dst_cache : NULL); if (IS_ERR(rt)) { err = PTR_ERR(rt); + reason = SKB_DROP_REASON_IP_OUTNOROUTES; goto tx_error; } @@ -2535,8 +2539,10 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), vni, md, flags, udp_sum); - if (err < 0) + if (err < 0) { + reason = SKB_DROP_REASON_NOMEM; goto tx_error; + } udp_tunnel_xmit_skb(rt, sock4->sock->sk, skb, saddr, pkey->u.ipv4.dst, tos, ttl, df, @@ -2556,6 +2562,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (IS_ERR(ndst)) { err = PTR_ERR(ndst); ndst = NULL; + reason = SKB_DROP_REASON_IP_OUTNOROUTES; goto tx_error; } @@ -2596,8 +2603,10 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, skb_scrub_packet(skb, xnet); err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), vni, md, flags, udp_sum); - if (err < 0) + if (err < 0) { + reason = SKB_DROP_REASON_NOMEM; goto tx_error; + } udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev, &saddr, &pkey->u.ipv6.dst, tos, ttl, @@ -2612,7 +2621,7 @@ out_unlock: drop: dev_core_stats_tx_dropped_inc(dev); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); - dev_kfree_skb(skb); + kfree_skb_reason(skb, reason); return; tx_error: @@ -2624,7 +2633,7 @@ tx_error: dst_release(ndst); DEV_STATS_INC(dev, tx_errors); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); - kfree_skb(skb); + kfree_skb_reason(skb, reason); } static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev, -- 2.51.0 From 03483dbde80d102146a61ec09b9e90cfc4bb8be0 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:28 +0800 Subject: [PATCH 06/16] net: vxlan: use kfree_skb_reason() in vxlan_mdb_xmit() Replace kfree_skb() with kfree_skb_reason() in vxlan_mdb_xmit. No drop reasons are introduced in this commit. Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_mdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c index ebed05a2804c..8735891ee128 100644 --- a/drivers/net/vxlan/vxlan_mdb.c +++ b/drivers/net/vxlan/vxlan_mdb.c @@ -1712,7 +1712,7 @@ netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan, vxlan_xmit_one(skb, vxlan->dev, src_vni, rcu_dereference(fremote->rd), false); else - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE); return NETDEV_TX_OK; } -- 2.51.0 From c106479b612d34739c9337a18ce5332ca613f993 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:29 +0800 Subject: [PATCH 07/16] net: vxlan: use kfree_skb_reason() in vxlan_encap_bypass() Replace kfree_skb with kfree_skb_reason in vxlan_encap_bypass, and no new skb drop reason is added in this commit. Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index e82f2e30bd39..2b0f00f92eae 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2290,7 +2290,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, rcu_read_lock(); dev = skb->dev; if (unlikely(!(dev->flags & IFF_UP))) { - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY); goto drop; } -- 2.51.0 From 790961d88b0e63d993e112b747746dfd94a7c823 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Wed, 9 Oct 2024 10:28:30 +0800 Subject: [PATCH 08/16] net: vxlan: use kfree_skb_reason() in encap_bypass_if_local() Replace kfree_skb() with kfree_skb_reason() in encap_bypass_if_local, and no new skb drop reason is added in this commit. Signed-off-by: Menglong Dong Reviewed-by: Simon Horman Reviewed-by: Kalesh AP Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 2b0f00f92eae..d507155e62ce 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2341,7 +2341,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, DEV_STATS_INC(dev, tx_errors); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_INVALID_HDR); return -ENOENT; } -- 2.51.0 From edc344568922eb9588e77ba49de1ef0cb9a2ff1c Mon Sep 17 00:00:00 2001 From: Danielle Ratson Date: Wed, 9 Oct 2024 13:53:46 +0300 Subject: [PATCH 09/16] net: ethtool: Add new parameters and a function to support EPL In the CMIS specification for pluggable modules, LPL (Local Payload) and EPL (Extended Payload) are two types of data payloads used for managing various functions and features of the module. EPL payloads are used for more complex and extensive management functions that require a larger amount of data, so writing firmware blocks using EPL is much more efficient. Currently, only LPL payload is supported for writing firmware blocks to the module. Add EPL related parameters to the function ethtool_cmis_cdb_compose_args() and add a specific function for calculating the maximum allowable length extension for EPL. Both will be used in the next patch to add support for writing firmware blocks using EPL. Signed-off-by: Danielle Ratson Reviewed-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ethtool/cmis.h | 12 +++++++----- net/ethtool/cmis_cdb.c | 32 +++++++++++++++++++++----------- net/ethtool/cmis_fw_update.c | 17 ++++++++++------- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h index 3e7c293af78c..73a5060d0f4c 100644 --- a/net/ethtool/cmis.h +++ b/net/ethtool/cmis.h @@ -96,13 +96,15 @@ struct ethtool_cmis_cdb_rpl { u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH]; }; -u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs); +u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs); +u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs); void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args, - enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl, - u8 lpl_len, u16 max_duration, - u8 read_write_len_ext, u16 msleep_pre_rpl, - u8 rpl_exp_len, u8 flags); + enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl, + u8 lpl_len, u8 *epl, u16 epl_len, + u16 max_duration, u8 read_write_len_ext, + u16 msleep_pre_rpl, u8 rpl_exp_len, + u8 flags); void ethtool_cmis_cdb_check_completion_flag(u8 cmis_rev, u8 *flags); diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c index 4d5581147952..80bb475fd52a 100644 --- a/net/ethtool/cmis_cdb.c +++ b/net/ethtool/cmis_cdb.c @@ -11,25 +11,34 @@ * min(i, 15) byte octets where i specifies the allowable additional number of * byte octets in a READ or a WRITE. */ -u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs) +u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs) { return 8 * (1 + min_t(u8, num_of_byte_octs, 15)); } +/* For accessing the EPL field on page 9Fh, the allowable length extension is + * min(i, 255) byte octets where i specifies the allowable additional number of + * byte octets in a READ or a WRITE. + */ +u32 ethtool_cmis_get_max_epl_size(u8 num_of_byte_octs) +{ + return 8 * (1 + min_t(u8, num_of_byte_octs, 255)); +} + void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args, - enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl, - u8 lpl_len, u16 max_duration, - u8 read_write_len_ext, u16 msleep_pre_rpl, - u8 rpl_exp_len, u8 flags) + enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl, + u8 lpl_len, u8 *epl, u16 epl_len, + u16 max_duration, u8 read_write_len_ext, + u16 msleep_pre_rpl, u8 rpl_exp_len, u8 flags) { args->req.id = cpu_to_be16(cmd); args->req.lpl_len = lpl_len; - if (pl) - memcpy(args->req.payload, pl, args->req.lpl_len); + if (lpl) + memcpy(args->req.payload, lpl, args->req.lpl_len); args->max_duration = max_duration; args->read_write_len_ext = - ethtool_cmis_get_max_payload_size(read_write_len_ext); + ethtool_cmis_get_max_lpl_size(read_write_len_ext); args->msleep_pre_rpl = msleep_pre_rpl; args->rpl_exp_len = rpl_exp_len; args->flags = flags; @@ -183,7 +192,7 @@ cmis_cdb_validate_password(struct ethtool_cmis_cdb *cdb, } ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_QUERY_STATUS, - (u8 *)&qs_pl, sizeof(qs_pl), 0, + (u8 *)&qs_pl, sizeof(qs_pl), NULL, 0, 0, cdb->read_write_len_ext, 1000, sizeof(*rpl), CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -245,8 +254,9 @@ static int cmis_cdb_module_features_get(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags); ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_MODULE_FEATURES, - NULL, 0, 0, cdb->read_write_len_ext, - 1000, sizeof(*rpl), flags); + NULL, 0, NULL, 0, 0, + cdb->read_write_len_ext, 1000, + sizeof(*rpl), flags); err = ethtool_cmis_cdb_execute_cmd(dev, &args); if (err < 0) { diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c index 655ff5224ffa..a514127985d4 100644 --- a/net/ethtool/cmis_fw_update.c +++ b/net/ethtool/cmis_fw_update.c @@ -54,7 +54,8 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags); ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES, - NULL, 0, cdb->max_completion_time, + NULL, 0, NULL, 0, + cdb->max_completion_time, cdb->read_write_len_ext, 1000, sizeof(*rpl), flags); @@ -122,7 +123,7 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD, - (u8 *)&pl, lpl_len, + (u8 *)&pl, lpl_len, NULL, 0, fw_mng->max_duration_start, cdb->read_write_len_ext, 1000, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -158,7 +159,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, int err; max_lpl_len = min_t(u32, - ethtool_cmis_get_max_payload_size(cdb->read_write_len_ext), + ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext), ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH); max_block_size = max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl, @@ -183,7 +184,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL, - (u8 *)&pl, lpl_len, + (u8 *)&pl, lpl_len, NULL, 0, fw_mng->max_duration_write, cdb->read_write_len_ext, 1, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -212,7 +213,8 @@ cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD, - NULL, 0, fw_mng->max_duration_complete, + NULL, 0, NULL, 0, + fw_mng->max_duration_complete, cdb->read_write_len_ext, 1000, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); @@ -294,7 +296,7 @@ cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev, int err; ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE, - (u8 *)&pl, sizeof(pl), + (u8 *)&pl, sizeof(pl), NULL, 0, cdb->max_completion_time, cdb->read_write_len_ext, 1000, 0, CDB_F_MODULE_STATE_VALID); @@ -326,7 +328,8 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb, ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE, - NULL, 0, cdb->max_completion_time, + NULL, 0, NULL, 0, + cdb->max_completion_time, cdb->read_write_len_ext, 1000, 0, CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); -- 2.51.0 From 9a3b0d078bd825613c0821bf7bf5a2e1d8d60057 Mon Sep 17 00:00:00 2001 From: Danielle Ratson Date: Wed, 9 Oct 2024 13:53:47 +0300 Subject: [PATCH 10/16] net: ethtool: Add support for writing firmware blocks using EPL payload In the CMIS specification for pluggable modules, LPL (Local Payload) and EPL (Extended Payload) are two types of data payloads used for managing various functions and features of the module. EPL payloads are used for more complex and extensive management functions that require a larger amount of data, so writing firmware blocks using EPL is much more efficient. Currently, only LPL payload is supported for writing firmware blocks to the module. Add support for writing firmware block using EPL payload, both to support modules that supports only EPL write mechanism, and to optimize the flashing process of modules that support LPL and EPL. Signed-off-by: Danielle Ratson Reviewed-by: Petr Machata Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ethtool/cmis.h | 4 ++ net/ethtool/cmis_cdb.c | 66 ++++++++++++++++++++++++-- net/ethtool/cmis_fw_update.c | 91 ++++++++++++++++++++++++++++++++---- 3 files changed, 148 insertions(+), 13 deletions(-) diff --git a/net/ethtool/cmis.h b/net/ethtool/cmis.h index 73a5060d0f4c..1e790413db0e 100644 --- a/net/ethtool/cmis.h +++ b/net/ethtool/cmis.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #define ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH 120 +#define ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH 2048 #define ETHTOOL_CMIS_CDB_CMD_PAGE 0x9F #define ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR 0x50 @@ -23,6 +24,7 @@ enum ethtool_cmis_cdb_cmd_id { ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES = 0x0041, ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD = 0x0101, ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL = 0x0103, + ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL = 0x0104, ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD = 0x0107, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE = 0x0109, ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE = 0x010A, @@ -38,6 +40,7 @@ enum ethtool_cmis_cdb_cmd_id { * @resv1: Added to match the CMIS standard request continuity. * @resv2: Added to match the CMIS standard request continuity. * @payload: Payload for the CDB commands. + * @epl: Extended payload for the CDB commands. */ struct ethtool_cmis_cdb_request { __be16 id; @@ -49,6 +52,7 @@ struct ethtool_cmis_cdb_request { u8 resv2; u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH]; ); + u8 *epl; /* Everything above this field checksummed. */ }; #define CDB_F_COMPLETION_VALID BIT(0) diff --git a/net/ethtool/cmis_cdb.c b/net/ethtool/cmis_cdb.c index 80bb475fd52a..d159dc121bde 100644 --- a/net/ethtool/cmis_cdb.c +++ b/net/ethtool/cmis_cdb.c @@ -33,12 +33,19 @@ void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args, { args->req.id = cpu_to_be16(cmd); args->req.lpl_len = lpl_len; - if (lpl) + if (lpl) { memcpy(args->req.payload, lpl, args->req.lpl_len); + args->read_write_len_ext = + ethtool_cmis_get_max_lpl_size(read_write_len_ext); + } + if (epl) { + args->req.epl_len = cpu_to_be16(epl_len); + args->req.epl = epl; + args->read_write_len_ext = + ethtool_cmis_get_max_epl_size(read_write_len_ext); + } args->max_duration = max_duration; - args->read_write_len_ext = - ethtool_cmis_get_max_lpl_size(read_write_len_ext); args->msleep_pre_rpl = msleep_pre_rpl; args->rpl_exp_len = rpl_exp_len; args->flags = flags; @@ -556,6 +563,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev, return err; } +#define CMIS_CDB_EPL_PAGE_START 0xA0 +#define CMIS_CDB_EPL_PAGE_END 0xAF +#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START 128 +#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END 255 + +static int +ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev, + struct ethtool_cmis_cdb_cmd_args *args, + struct ethtool_module_eeprom *page_data) +{ + u16 epl_len = be16_to_cpu(args->req.epl_len); + u32 bytes_written = 0; + u8 page; + int err; + + for (page = CMIS_CDB_EPL_PAGE_START; + page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) { + u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START; + + while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END && + bytes_written < epl_len) { + u32 bytes_left = epl_len - bytes_written; + u16 space_left, bytes_to_write; + + space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1; + bytes_to_write = min_t(u16, bytes_left, + min_t(u16, space_left, + args->read_write_len_ext)); + + err = __ethtool_cmis_cdb_execute_cmd(dev, page_data, + page, offset, + bytes_to_write, + args->req.epl + bytes_written); + if (err < 0) + return err; + + offset += bytes_to_write; + bytes_written += bytes_to_write; + } + } + return 0; +} + static u8 cmis_cdb_calc_checksum(const void *data, size_t size) { const u8 *bytes = (const u8 *)data; @@ -577,7 +627,9 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev, int err; args->req.chk_code = - cmis_cdb_calc_checksum(&args->req, sizeof(args->req)); + cmis_cdb_calc_checksum(&args->req, + offsetof(struct ethtool_cmis_cdb_request, + epl)); if (args->req.lpl_len > args->read_write_len_ext) { args->err_msg = "LPL length is longer than CDB read write length extension allows"; @@ -599,6 +651,12 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev, if (err < 0) return err; + if (args->req.epl_len) { + err = ethtool_cmis_cdb_execute_epl_cmd(dev, args, &page_data); + if (err < 0) + return err; + } + offset = CMIS_CDB_CMD_ID_OFFSET + offsetof(struct ethtool_cmis_cdb_request, id); err = __ethtool_cmis_cdb_execute_cmd(dev, &page_data, diff --git a/net/ethtool/cmis_fw_update.c b/net/ethtool/cmis_fw_update.c index a514127985d4..48aef6220f00 100644 --- a/net/ethtool/cmis_fw_update.c +++ b/net/ethtool/cmis_fw_update.c @@ -9,6 +9,7 @@ struct cmis_fw_update_fw_mng_features { u8 start_cmd_payload_size; + u8 write_mechanism; u16 max_duration_start; u16 max_duration_write; u16 max_duration_complete; @@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl { }; enum cmis_cdb_fw_write_mechanism { + CMIS_CDB_FW_WRITE_MECHANISM_NONE = 0x00, CMIS_CDB_FW_WRITE_MECHANISM_LPL = 0x01, + CMIS_CDB_FW_WRITE_MECHANISM_EPL = 0x10, CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11, }; @@ -68,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, } rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload; - if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL || - rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) { + if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) { ethnl_module_fw_flash_ntf_err(dev, ntf_params, - "Write LPL is not supported", + "CDB write mechanism is not supported", NULL); return -EOPNOTSUPP; } @@ -83,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb, */ cdb->read_write_len_ext = rpl->read_write_len_ext; fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size; + fw_mng->write_mechanism = + rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ? + CMIS_CDB_FW_WRITE_MECHANISM_LPL : + CMIS_CDB_FW_WRITE_MECHANISM_EPL; fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start); fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write); fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete); @@ -149,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl { }; static int -cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, - struct ethtool_cmis_fw_update_params *fw_update, - struct cmis_fw_update_fw_mng_features *fw_mng) +cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb, + struct ethtool_cmis_fw_update_params *fw_update, + struct cmis_fw_update_fw_mng_features *fw_mng) { u8 start = fw_mng->start_cmd_payload_size; u32 offset, max_block_size, max_lpl_len; @@ -202,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb, return 0; } +struct cmis_cdb_write_fw_block_epl_pl { + u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH]; +}; + +static int +cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb, + struct ethtool_cmis_fw_update_params *fw_update, + struct cmis_fw_update_fw_mng_features *fw_mng) +{ + u8 start = fw_mng->start_cmd_payload_size; + u32 image_size = fw_update->fw->size; + u32 offset, lpl_len; + int err; + + lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl, + block_address); + + for (offset = start; offset < image_size; + offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) { + struct cmis_cdb_write_fw_block_lpl_pl lpl = { + .block_address = cpu_to_be32(offset - start), + }; + struct cmis_cdb_write_fw_block_epl_pl *epl; + struct ethtool_cmis_cdb_cmd_args args = {}; + u32 epl_len; + + ethnl_module_fw_flash_ntf_in_progress(fw_update->dev, + &fw_update->ntf_params, + offset - start, + image_size); + + epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH, + image_size - offset); + epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL); + if (!epl) + return -ENOMEM; + + memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len); + + ethtool_cmis_cdb_compose_args(&args, + ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL, + (u8 *)&lpl, lpl_len, (u8 *)epl, + epl_len, + fw_mng->max_duration_write, + cdb->read_write_len_ext, 1, 0, + CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID); + + err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args); + kfree(epl); + if (err < 0) { + ethnl_module_fw_flash_ntf_err(fw_update->dev, + &fw_update->ntf_params, + "Write FW block EPL command failed", + args.err_msg); + return err; + } + } + + return 0; +} + static int cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb, struct net_device *dev, @@ -238,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb, if (err < 0) return err; - err = cmis_fw_update_write_image(cdb, fw_update, fw_mng); - if (err < 0) - return err; + if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) { + err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng); + if (err < 0) + return err; + } else { + err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng); + if (err < 0) + return err; + } err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng, &fw_update->ntf_params); -- 2.51.0 From e4c416533f0633c96eba849832a9212ace3c3ec4 Mon Sep 17 00:00:00 2001 From: Yu Liao Date: Thu, 10 Oct 2024 17:27:44 +0800 Subject: [PATCH 11/16] net: hsr: convert to use new timer APIs del_timer() and del_timer_sync() have been renamed to timer_delete() and timer_delete_sync(). Inconsistent API usage makes the code a bit confusing, so replace with the new APIs. No functional changes intended. Signed-off-by: Yu Liao Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/hsr/hsr_netlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index f6ff0b61e08a..6f09b9512484 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -128,9 +128,9 @@ static void hsr_dellink(struct net_device *dev, struct list_head *head) { struct hsr_priv *hsr = netdev_priv(dev); - del_timer_sync(&hsr->prune_timer); - del_timer_sync(&hsr->prune_proxy_timer); - del_timer_sync(&hsr->announce_timer); + timer_delete_sync(&hsr->prune_timer); + timer_delete_sync(&hsr->prune_proxy_timer); + timer_delete_sync(&hsr->announce_timer); timer_delete_sync(&hsr->announce_proxy_timer); hsr_debugfs_term(hsr); -- 2.51.0 From b8bf38440ba94e8ed8e2ae55c5dfb0276d30e843 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 10 Oct 2024 12:58:02 +0200 Subject: [PATCH 12/16] r8169: enable SG/TSO on selected chip versions per default Due to problem reports in the past SG and TSO/TSO6 are disabled per default. It's not fully clear which chip versions are affected, so we may impact also users of unaffected chip versions, unless they know how to use ethtool for enabling SG/TSO/TSO6. Vendor drivers r8168/r8125 enable SG/TSO/TSO6 for selected chip versions per default, I'd interpret this as confirmation that these chip versions are unaffected. So let's do the same here. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 7287e841bbf1..30de74565228 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5525,11 +5525,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features |= dev->hw_features; - /* There has been a number of reports that using SG/TSO results in - * tx timeouts. However for a lot of people SG/TSO works fine. - * Therefore disable both features by default, but allow users to - * enable them. Use at own risk! - */ if (rtl_chip_supports_csum_v2(tp)) { dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2); @@ -5540,6 +5535,17 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1); } + /* There has been a number of reports that using SG/TSO results in + * tx timeouts. However for a lot of people SG/TSO works fine. + * It's not fully clear which chip versions are affected. Vendor + * drivers enable SG/TSO for certain chip versions per default, + * let's mimic this here. On other chip versions users can + * use ethtool to enable SG/TSO, use at own risk! + */ + if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && + tp->mac_version != RTL_GIGA_MAC_VER_61) + dev->features |= dev->hw_features; + dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; -- 2.51.0 From 5c16e118b796e95d6e5c80c5d8af2591262431c9 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 10 Oct 2024 12:04:10 +0100 Subject: [PATCH 13/16] net: ethernet: ti: am65-cpsw: Use __be64 type for id_temp The id_temp local variable in am65_cpsw_nuss_probe() is used to hold a 64-bit big-endian value as it is assigned using cpu_to_be64(). It is read using memcpy(), where it is written as an identifier into a byte-array. So this can also be treated as big endian. As it's type is currently host byte order (u64), sparse flags an endian mismatch when compiling for little-endian systems: .../am65-cpsw-nuss.c:3454:17: warning: incorrect type in assignment (different base types) .../am65-cpsw-nuss.c:3454:17: expected unsigned long long [usertype] id_temp .../am65-cpsw-nuss.c:3454:17: got restricted __be64 [usertype] Address this by using __be64 as the type of id_temp. No functional change intended. Compile tested only. Reviewed-by: Kalesh AP Reviewed-by: Roger Quadros Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index aee98ffcf093..bb3e636b6eae 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -3500,7 +3500,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) struct resource *res; struct clk *clk; int ale_entries; - u64 id_temp; + __be64 id_temp; int ret, i; common = devm_kzalloc(dev, sizeof(struct am65_cpsw_common), GFP_KERNEL); -- 2.51.0 From 4a7b2ba94a59d188e0ab1e5b0ea5a71a23b787fa Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 10 Oct 2024 12:04:11 +0100 Subject: [PATCH 14/16] net: ethernet: ti: am65-cpsw: Use tstats instead of open coded version Make use of struct pcpu_sw_netstats and related helpers to handle existing per-cpu stats for this driver - the exact same counters are maintained. A side effect of this change is to address __percpu warnings flagged by Sparse: .../am65-cpsw-nuss.c:2658:55: warning: incorrect type in initializer (different address spaces) .../am65-cpsw-nuss.c:2658:55: expected struct am65_cpsw_ndev_stats [noderef] __percpu *stats .../am65-cpsw-nuss.c:2658:55: got void *data .../am65-cpsw-nuss.c:2781:15: warning: incorrect type in argument 3 (different address spaces) .../am65-cpsw-nuss.c:2781:15: expected void *data .../am65-cpsw-nuss.c:2781:15: got struct am65_cpsw_ndev_stats [noderef] __percpu *stats Compile tested only. No functional change intended. Suggested-by: Jakub Kicinski Link: https://lore.kernel.org/all/20240911170643.7ecb1bbb@kernel.org/ Signed-off-by: Simon Horman Reviewed-by: Roger Quadros Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 92 +++--------------------- drivers/net/ethernet/ti/am65-cpsw-nuss.h | 9 --- 2 files changed, 8 insertions(+), 93 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index bb3e636b6eae..cda7ddfe6845 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -1031,9 +1031,7 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow, int desc_idx, int cpu, int *len) { struct am65_cpsw_common *common = flow->common; - struct am65_cpsw_ndev_priv *ndev_priv; struct net_device *ndev = port->ndev; - struct am65_cpsw_ndev_stats *stats; int ret = AM65_CPSW_XDP_CONSUMED; struct am65_cpsw_tx_chn *tx_chn; struct netdev_queue *netif_txq; @@ -1051,9 +1049,6 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow, /* XDP prog might have changed packet data and boundaries */ *len = xdp->data_end - xdp->data; - ndev_priv = netdev_priv(ndev); - stats = this_cpu_ptr(ndev_priv->stats); - switch (act) { case XDP_PASS: ret = AM65_CPSW_XDP_PASS; @@ -1073,20 +1068,14 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow, if (err) goto drop; - u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += *len; - stats->rx_packets++; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_tx_add(ndev, 1, *len); ret = AM65_CPSW_XDP_CONSUMED; goto out; case XDP_REDIRECT: if (unlikely(xdp_do_redirect(ndev, xdp, prog))) goto drop; - u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += *len; - stats->rx_packets++; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_rx_add(ndev, *len); ret = AM65_CPSW_XDP_REDIRECT; goto out; default: @@ -1147,7 +1136,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow, u32 buf_dma_len, pkt_len, port_id = 0, csum_info; struct am65_cpsw_common *common = flow->common; struct am65_cpsw_ndev_priv *ndev_priv; - struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_rx; struct device *dev = common->dev; struct page *page, *new_page; @@ -1233,12 +1221,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow, am65_cpsw_nuss_rx_csum(skb, csum_info); napi_gro_receive(&flow->napi_rx, skb); - stats = this_cpu_ptr(ndev_priv->stats); - - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += pkt_len; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_rx_add(ndev, pkt_len); allocate: new_page = page_pool_dev_alloc_pages(flow->page_pool); @@ -1321,10 +1304,7 @@ static struct sk_buff * am65_cpsw_nuss_tx_compl_packet_skb(struct am65_cpsw_tx_chn *tx_chn, dma_addr_t desc_dma) { - struct am65_cpsw_ndev_priv *ndev_priv; - struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_tx; - struct net_device *ndev; struct sk_buff *skb; void **swdata; @@ -1334,16 +1314,9 @@ am65_cpsw_nuss_tx_compl_packet_skb(struct am65_cpsw_tx_chn *tx_chn, skb = *(swdata); am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); - ndev = skb->dev; - am65_cpts_tx_timestamp(tx_chn->common->cpts, skb); - ndev_priv = netdev_priv(ndev); - stats = this_cpu_ptr(ndev_priv->stats); - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_tx_add(skb->dev, 1, skb->len); return skb; } @@ -1354,8 +1327,6 @@ am65_cpsw_nuss_tx_compl_packet_xdp(struct am65_cpsw_common *common, dma_addr_t desc_dma, struct net_device **ndev) { - struct am65_cpsw_ndev_priv *ndev_priv; - struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_tx; struct am65_cpsw_port *port; struct xdp_frame *xdpf; @@ -1369,14 +1340,7 @@ am65_cpsw_nuss_tx_compl_packet_xdp(struct am65_cpsw_common *common, am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); port = am65_common_get_port(common, port_id); - *ndev = port->ndev; - - ndev_priv = netdev_priv(*ndev); - stats = this_cpu_ptr(ndev_priv->stats); - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += xdpf->len; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_tx_add(port->ndev, 1, xdpf->len); return xdpf; } @@ -1899,31 +1863,7 @@ static int am65_cpsw_nuss_ndo_slave_ioctl(struct net_device *ndev, static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) { - struct am65_cpsw_ndev_priv *ndev_priv = netdev_priv(dev); - unsigned int start; - int cpu; - - for_each_possible_cpu(cpu) { - struct am65_cpsw_ndev_stats *cpu_stats; - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - - cpu_stats = per_cpu_ptr(ndev_priv->stats, cpu); - do { - start = u64_stats_fetch_begin(&cpu_stats->syncp); - rx_packets = cpu_stats->rx_packets; - rx_bytes = cpu_stats->rx_bytes; - tx_packets = cpu_stats->tx_packets; - tx_bytes = cpu_stats->tx_bytes; - } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; - stats->tx_packets += tx_packets; - stats->tx_bytes += tx_bytes; - } + dev_fetch_sw_netstats(stats, dev->tstats); stats->rx_errors = dev->stats.rx_errors; stats->rx_dropped = dev->stats.rx_dropped; @@ -2710,13 +2650,6 @@ of_node_put: return ret; } -static void am65_cpsw_pcpu_stats_free(void *data) -{ - struct am65_cpsw_ndev_stats __percpu *stats = data; - - free_percpu(stats); -} - static void am65_cpsw_nuss_phylink_cleanup(struct am65_cpsw_common *common) { struct am65_cpsw_port *port; @@ -2736,7 +2669,6 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) struct device *dev = common->dev; struct am65_cpsw_port *port; struct phylink *phylink; - int ret; port = &common->ports[port_idx]; @@ -2829,21 +2761,13 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) if (common->pdata.quirks & AM65_CPSW_QUIRK_I2027_NO_TX_CSUM) port->ndev->features &= ~NETIF_F_HW_CSUM; - ndev_priv->stats = netdev_alloc_pcpu_stats(struct am65_cpsw_ndev_stats); - if (!ndev_priv->stats) - return -ENOMEM; - - ret = devm_add_action_or_reset(dev, am65_cpsw_pcpu_stats_free, - ndev_priv->stats); - if (ret) - dev_err(dev, "failed to add percpu stat free action %d\n", ret); - + port->ndev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; port->xdp_prog = NULL; if (!common->dma_ndev) common->dma_ndev = port->ndev; - return ret; + return 0; } static int am65_cpsw_nuss_init_ndevs(struct am65_cpsw_common *common) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h index dc8d544230dc..3f3e353dfe88 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h @@ -180,18 +180,9 @@ struct am65_cpsw_common { u32 *ale_context; }; -struct am65_cpsw_ndev_stats { - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets; - u64 rx_bytes; - struct u64_stats_sync syncp; -}; - struct am65_cpsw_ndev_priv { u32 msg_enable; struct am65_cpsw_port *port; - struct am65_cpsw_ndev_stats __percpu *stats; bool offload_fwd_mark; /* Serialize access to MAC Merge state between ethtool requests * and link state updates -- 2.51.0 From 2c9eacbb56de00591e2e4f9484e286c86c3c10b4 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 10 Oct 2024 12:04:12 +0100 Subject: [PATCH 15/16] net: ethernet: ti: cpsw_ale: Remove unused accessor functions W=1 builds flag that some accessor functions for ALE fields are unused. Address this by splitting up the macros used to define these accessors to allow only those that are used to be declared. The warnings are verbose, but for example, the mcast_state case is flagged by clang-18 as: .../cpsw_ale.c:220:1: warning: unused function 'cpsw_ale_get_mcast_state' [-Wunused-function] 220 | DEFINE_ALE_FIELD(mcast_state, 62, 2) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .../cpsw_ale.c:145:19: note: expanded from macro 'DEFINE_ALE_FIELD' 145 | static inline int cpsw_ale_get_##name(u32 *ale_entry) \ | ^~~~~~~~~~~~~~~~~~~ :196:1: note: expanded from here 196 | cpsw_ale_get_mcast_state | ^~~~~~~~~~~~~~~~~~~~~~~~ Compile tested only. No functional change intended. Signed-off-by: Simon Horman Reviewed-by: Roger Quadros Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw_ale.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 8d02d2b21429..d361caa80d05 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -162,27 +162,39 @@ static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits, ale_entry[idx] |= (value << start); } -#define DEFINE_ALE_FIELD(name, start, bits) \ +#define DEFINE_ALE_FIELD_GET(name, start, bits) \ static inline int cpsw_ale_get_##name(u32 *ale_entry) \ { \ return cpsw_ale_get_field(ale_entry, start, bits); \ -} \ +} + +#define DEFINE_ALE_FIELD_SET(name, start, bits) \ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ { \ cpsw_ale_set_field(ale_entry, start, bits, value); \ } -#define DEFINE_ALE_FIELD1(name, start) \ +#define DEFINE_ALE_FIELD(name, start, bits) \ +DEFINE_ALE_FIELD_GET(name, start, bits) \ +DEFINE_ALE_FIELD_SET(name, start, bits) + +#define DEFINE_ALE_FIELD1_GET(name, start) \ static inline int cpsw_ale_get_##name(u32 *ale_entry, u32 bits) \ { \ return cpsw_ale_get_field(ale_entry, start, bits); \ -} \ +} + +#define DEFINE_ALE_FIELD1_SET(name, start) \ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value, \ u32 bits) \ { \ cpsw_ale_set_field(ale_entry, start, bits, value); \ } +#define DEFINE_ALE_FIELD1(name, start) \ +DEFINE_ALE_FIELD1_GET(name, start) \ +DEFINE_ALE_FIELD1_SET(name, start) + enum { ALE_ENT_VID_MEMBER_LIST = 0, ALE_ENT_VID_UNREG_MCAST_MSK, @@ -238,14 +250,14 @@ static const struct ale_entry_fld vlan_entry_k3_cpswxg[] = { DEFINE_ALE_FIELD(entry_type, 60, 2) DEFINE_ALE_FIELD(vlan_id, 48, 12) -DEFINE_ALE_FIELD(mcast_state, 62, 2) +DEFINE_ALE_FIELD_SET(mcast_state, 62, 2) DEFINE_ALE_FIELD1(port_mask, 66) DEFINE_ALE_FIELD(super, 65, 1) DEFINE_ALE_FIELD(ucast_type, 62, 2) -DEFINE_ALE_FIELD1(port_num, 66) -DEFINE_ALE_FIELD(blocked, 65, 1) -DEFINE_ALE_FIELD(secure, 64, 1) -DEFINE_ALE_FIELD(mcast, 40, 1) +DEFINE_ALE_FIELD1_SET(port_num, 66) +DEFINE_ALE_FIELD_SET(blocked, 65, 1) +DEFINE_ALE_FIELD_SET(secure, 64, 1) +DEFINE_ALE_FIELD_GET(mcast, 40, 1) #define NU_VLAN_UNREG_MCAST_IDX 1 -- 2.51.0 From 76d37e4fd638a582cf13bec243ebab0af3658d07 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 9 Oct 2024 10:40:10 +0100 Subject: [PATCH 16/16] tg3: Address byte-order miss-matches Address byte-order miss-matches flagged by Sparse. In tg3_load_firmware_cpu() and tg3_get_device_address() this is done using appropriate types to store big endian values. In the cases of tg3_test_nvram(), where buf is an array which contains values of several different types, cast to __le32 before converting values to host byte order. Reported by Sparse as: .../tg3.c:3745:34: warning: cast to restricted __be32 .../tg3.c:13096:21: warning: cast to restricted __le32 .../tg3.c:13096:21: warning: cast from restricted __be32 .../tg3.c:13101:21: warning: cast to restricted __le32 .../tg3.c:13101:21: warning: cast from restricted __be32 .../tg3.c:17070:63: warning: incorrect type in argument 3 (different base types) .../tg3.c:17070:63: expected restricted __be32 [usertype] *val .../tg3.c:17070:63: got unsigned int * dr.../tg3.c:17071:63: warning: incorrect type in argument 3 (different base types) .../tg3.c:17071:63: expected restricted __be32 [usertype] *val .../tg3.c:17071:63: got unsigned int * Also, address white-space issues on lines modified for the above. And, for consistency, lines adjacent to them. Compile tested only. No functional change intended. Signed-off-by: Simon Horman Link: https://patch.msgid.link/20241009-tg3-sparse-v1-1-6af38a7bf4ff@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/tg3.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index c4bce6493afa..d5916bbc1b3a 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -3737,7 +3737,7 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, } do { - u32 *fw_data = (u32 *)(fw_hdr + 1); + __be32 *fw_data = (__be32 *)(fw_hdr + 1); for (i = 0; i < tg3_fw_data_len(tp, fw_hdr); i++) write_op(tp, cpu_scratch_base + (be32_to_cpu(fw_hdr->base_addr) & 0xffff) + @@ -13126,12 +13126,16 @@ static int tg3_test_nvram(struct tg3 *tp) /* Bootstrap checksum at offset 0x10 */ csum = calc_crc((unsigned char *) buf, 0x10); - if (csum != le32_to_cpu(buf[0x10/4])) + + /* The type of buf is __be32 *, but this value is __le32 */ + if (csum != le32_to_cpu((__force __le32)buf[0x10 / 4])) goto out; /* Manufacturing block starts at offset 0x74, checksum at 0xfc */ - csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88); - if (csum != le32_to_cpu(buf[0xfc/4])) + csum = calc_crc((unsigned char *)&buf[0x74 / 4], 0x88); + + /* The type of buf is __be32 *, but this value is __le32 */ + if (csum != le32_to_cpu((__force __le32)buf[0xfc / 4])) goto out; kfree(buf); @@ -17098,12 +17102,14 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr) addr_ok = is_valid_ether_addr(addr); } if (!addr_ok) { + __be32 be_hi, be_lo; + /* Next, try NVRAM. */ if (!tg3_flag(tp, NO_NVRAM) && - !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && - !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { - memcpy(&addr[0], ((char *)&hi) + 2, 2); - memcpy(&addr[2], (char *)&lo, sizeof(lo)); + !tg3_nvram_read_be32(tp, mac_offset + 0, &be_hi) && + !tg3_nvram_read_be32(tp, mac_offset + 4, &be_lo)) { + memcpy(&addr[0], ((char *)&be_hi) + 2, 2); + memcpy(&addr[2], (char *)&be_lo, sizeof(be_lo)); } /* Finally just fetch it out of the MAC control regs. */ else { -- 2.51.0