From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com [IPv6:2a00:1450:4864:20::22c]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.bufferbloat.net (Postfix) with ESMTPS id C0EBC3B29E for ; Sun, 11 Jul 2021 19:33:52 -0400 (EDT) Received: by mail-lj1-x22c.google.com with SMTP id h9so5336492ljm.5 for ; Sun, 11 Jul 2021 16:33:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jackrabbitwireless.com; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=Lu9M/MsD05iS0M0qSzD+5CvkLDMoh001cdPu3OrEsHY=; b=11G4bAHLnvUmnY8F8W2B3iuvZu7SX28mRFbAiV8uMlpTjrkMbdmW4nzrpbkLZZiA8L HNLtrau05hPZZfiRVI6hei38R9umolwtpwCgJYTBQMKNqqjgmHYjHY+ZFD/nM9jsAbFM zh9aXHT5Dm+BPEzQodjjgsdMY1SRAGgRDnDKA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=Lu9M/MsD05iS0M0qSzD+5CvkLDMoh001cdPu3OrEsHY=; b=P1cM+YEXVFZEOkqIwfm0XAFWHU12ifzuaFc3/ncvLyRiOkIbBsOO2qLPrY2NNHTk4Y jUUsrjEVVOILNvlhdsBWYSXsq3mhl99B74AdcRLqgwBSgaXuE7XXvc1APVVL0YObVQE9 3p6jndvuo3utYLkbvjWb/hZ9deJ2ugSuuSJjPcFH4Y4rDlYch2zajdFjDyKp7Ka2vIN/ Uo6rlKWhLBOvV4I4Ka4+bMDw5BHTxwCmHN2iVo6FwjHY9E+NMlly0Ry1fE/QuAbfS8AN GXTqJykwfX9u6QI4BbluT5zMgbedLn8lohLz+7sBn3swQfIcO2sDdOUO2oYmtN8fJt7b wR2A== X-Gm-Message-State: AOAM532w8DE5AGnWSzbnM9CL2NcvTIWezOF3jmJBZqsD/nr0HVGuxPFJ pFPunww/mZ7snTkgx9tKWhYWW0yPSxr0JGRXftpbJQ== X-Google-Smtp-Source: ABdhPJwX9z9vpQwXSllTpV+ZXUFHJM9UQSLQodlIgzX+TP2b4ckJdaQRXQUmAS11AGd7qlglthR6LV/IlVoXmwXPvF0= X-Received: by 2002:a2e:97d1:: with SMTP id m17mr26207687ljj.168.1626046431163; Sun, 11 Jul 2021 16:33:51 -0700 (PDT) MIME-Version: 1.0 References: <1625910047-56840-1-git-send-email-shenjian15@huawei.com> In-Reply-To: From: =?UTF-8?Q?Robert_Chac=C3=B3n?= Date: Sun, 11 Jul 2021 17:33:38 -0600 Message-ID: To: Dave Taht Cc: Cake List , cerowrt-devel Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Mailman-Approved-At: Tue, 13 Jul 2021 06:06:12 -0400 Subject: Re: [Cerowrt-devel] [Cake] Fwd: [RFC net-next] net: extend netdev features X-BeenThere: cerowrt-devel@lists.bufferbloat.net X-Mailman-Version: 2.1.20 Precedence: list List-Id: Development issues regarding the cerowrt test router project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 11 Jul 2021 23:33:53 -0000 Hey Dave, I am completely open to using cake's integral shaper, but from what I understand, it is not possible to create child leaf classes of cake qdiscs because cake is classless, right? For now I tried htb + cake diffserv4 ack-filter and it seemed to cause an increase in CPU usage (30%) with 8ms higher latency. However when I tried "cake diffserv4 no-ack-filter" it worked very well. CPU use was only 3% higher than fq_codel. I will test "cake diffserv4 no-ack-filter" on my production network to see how it does with live video over fixed wireless. If it works well I will make it the new default for LibreQoS. Thank you for the recommendation, I appreciate it! On Sat, Jul 10, 2021 at 1:43 PM Dave Taht wrote: > > can I encourage you to try cake with it's integral shaper instead of htb? > > or htb + cake diffserv4 ack-filter? (I've settled on that to optimize > even better for marked videoconferencing traffic. > facetime, in particular, does not handle loss well) > > > On Sat, Jul 10, 2021 at 10:00 AM Robert Chac=C3=B3n > wrote: > > > > I have a question regarding this, and the current maximum number of htb= leaf classes and/or qdiscs per interface. > > I recently integrated Jesper's xdp-cpumap-tc code into LibreQoS, which = increased throughput to 10Gbps on tests. > > I suspect somewhere between 10Gbps and 40Gbps throughput is now possibl= e if you throw enough cores at it. Asking our local university to help us t= est this. > > Xdp-cpumap-tc uses xdp's cpumap-redirect feature to filter packets into= the appropriate CPU / queue using eBPF hash maps, rather than linux tc fil= ters / u32. > > > > Question) Since LibreQoS would not depend on tc filters, would the curr= ent 32-bit or 64-bit feature limit impose a practical client limit on Libre= QoS? > > The average user's throughput is around 3.5Mbps at peak hours, so I'm t= hinking ~5800 qdiscs and ~5800 htb leaf classes would be required for each = interface at 20Gbps throughput for example. > > There may be some more immediate limitations I'm not understanding. Jus= t curious about the practical limitations there. > > > > Thanks! > > Robert > > > > On Sat, Jul 10, 2021 at 9:33 AM Dave Taht wrote: > > > > > > One thing somewhat related to this was finally expanding the space > > > available for the tc and iptables functionality for > > > things like hashing and actions etc from 16 bits to 32. That is > > > something of a fork lift upgrade, but... 64k queues is not > > > enough in some cases, nor is 64k possible users in libreqos. thoughts > > > > > > ---------- Forwarded message --------- > > > From: Jian Shen > > > Date: Sat, Jul 10, 2021 at 2:47 AM > > > Subject: [RFC net-next] net: extend netdev features > > > To: , > > > Cc: , > > > > > > > > > For the prototype of netdev_features_t is u64, and the number > > > of netdevice feature bits is 64 now. So there is no space to > > > introduce new feature bit. > > > > > > I did a small change for this. Keep the prototype of > > > netdev_feature_t, and extend the feature members in struct > > > net_device to an array of netdev_features_t. So more features > > > bits can be used. > > > > > > As this change, some functions which use netdev_features_t as > > > parameter or returen value will be affected. > > > I did below changes: > > > a. parameter: "netdev_features_t" to "netdev_features_t *" > > > b. return value: "netdev_feature_t" to "void", and add > > > "netdev_feature_t *" as output parameter. > > > > > > I kept some functions no change, which are surely useing the > > > first 64 bit of net device features now, such as function > > > nedev_add_tso_features(). In order to minimize to changes. > > > > > > For the features are array now, so it's unable to do logical > > > operation directly. I introduce a inline function set for > > > them, including "netdev_features_and/andnot/or/xor/equal/empty". > > > > > > For NETDEV_FEATURE_COUNT may be more than 64, so the shift > > > operation for NETDEV_FEATURE_COUNT is illegal. I changed some > > > macroes and functions, which does shift opertion with it. > > > > > > I haven't finished all the changes, for it affected all the > > > drivers which use the feature, need more time and test. I > > > sent this RFC patch, want to know whether this change is > > > acceptable, and how to improve it. > > > > > > Any comments will be helpful. > > > > > > Signed-off-by: Jian Shen > > > --- > > > drivers/net/ethernet/hisilicon/hns/hns_enet.c | 34 +-- > > > drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 97 ++++----- > > > drivers/net/ethernet/huawei/hinic/hinic_main.c | 71 +++--- > > > drivers/net/ethernet/huawei/hinic/hinic_rx.c | 4 +- > > > include/linux/if_vlan.h | 2 +- > > > include/linux/netdev_features.h | 105 ++++++++- > > > include/linux/netdevice.h | 31 +-- > > > net/8021q/vlan.c | 4 +- > > > net/8021q/vlan.h | 2 +- > > > net/8021q/vlan_dev.c | 49 +++-- > > > net/core/dev.c | 276 ++++++++++++--= ---------- > > > net/core/netpoll.c | 6 +- > > > net/ethtool/features.c | 56 +++-- > > > net/ethtool/ioctl.c | 93 +++++--- > > > 14 files changed, 493 insertions(+), 337 deletions(-) > > > > > > diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > b/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > index ad534f9..4f245cf 100644 > > > --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > @@ -479,7 +479,7 @@ static void hns_nic_rx_checksum(struct > > > hns_nic_ring_data *ring_data, > > > u32 l4id; > > > > > > /* check if RX checksum offload is enabled */ > > > - if (unlikely(!(netdev->features & NETIF_F_RXCSUM))) > > > + if (unlikely(!(netdev->features[0] & NETIF_F_RXCSUM))) > > > return; > > > > > > /* In hardware, we only support checksum for the following pr= otocols: > > > @@ -1768,17 +1768,17 @@ static int hns_nic_change_mtu(struct > > > net_device *ndev, int new_mtu) > > > } > > > > > > static int hns_nic_set_features(struct net_device *netdev, > > > - netdev_features_t features) > > > + netdev_features_t *features) > > > { > > > struct hns_nic_priv *priv =3D netdev_priv(netdev); > > > > > > switch (priv->enet_ver) { > > > case AE_VERSION_1: > > > - if (features & (NETIF_F_TSO | NETIF_F_TSO6)) > > > + if (features[0] & (NETIF_F_TSO | NETIF_F_TSO6)) > > > netdev_info(netdev, "enet v1 do not support t= so!\n"); > > > break; > > > default: > > > - if (features & (NETIF_F_TSO | NETIF_F_TSO6)) { > > > + if (features[0] & (NETIF_F_TSO | NETIF_F_TSO6)) { > > > priv->ops.fill_desc =3D fill_tso_desc; > > > priv->ops.maybe_stop_tx =3D hns_nic_maybe_sto= p_tso; > > > /* The chip only support 7*4096 */ > > > @@ -1789,24 +1789,23 @@ static int hns_nic_set_features(struct > > > net_device *netdev, > > > } > > > break; > > > } > > > - netdev->features =3D features; > > > + netdev->features[0] =3D features[0]; > > > return 0; > > > } > > > > > > -static netdev_features_t hns_nic_fix_features( > > > - struct net_device *netdev, netdev_features_t features= ) > > > +static void hns_nic_fix_features(struct net_device *netdev, > > > + netdev_features_t *features) > > > { > > > struct hns_nic_priv *priv =3D netdev_priv(netdev); > > > > > > switch (priv->enet_ver) { > > > case AE_VERSION_1: > > > - features &=3D ~(NETIF_F_TSO | NETIF_F_TSO6 | > > > + features[0] &=3D ~(NETIF_F_TSO | NETIF_F_TSO6 | > > > NETIF_F_HW_VLAN_CTAG_FILTER); > > > break; > > > default: > > > break; > > > } > > > - return features; > > > } > > > > > > static int hns_nic_uc_sync(struct net_device *netdev, const unsigned > > > char *addr) > > > @@ -2163,8 +2162,8 @@ static void hns_nic_set_priv_ops(struct > > > net_device *netdev) > > > priv->ops.maybe_stop_tx =3D hns_nic_maybe_stop_tx; > > > } else { > > > priv->ops.get_rxd_bnum =3D get_v2rx_desc_bnum; > > > - if ((netdev->features & NETIF_F_TSO) || > > > - (netdev->features & NETIF_F_TSO6)) { > > > + if ((netdev->features[0] & NETIF_F_TSO) || > > > + (netdev->features[0] & NETIF_F_TSO6)) { > > > priv->ops.fill_desc =3D fill_tso_desc; > > > priv->ops.maybe_stop_tx =3D hns_nic_maybe_sto= p_tso; > > > /* This chip only support 7*4096 */ > > > @@ -2325,22 +2324,23 @@ static int hns_nic_dev_probe(struct > > > platform_device *pdev) > > > ndev->netdev_ops =3D &hns_nic_netdev_ops; > > > hns_ethtool_set_ops(ndev); > > > > > > - ndev->features |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | > > > + ndev->features[0] |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO; > > > - ndev->vlan_features |=3D > > > + ndev->vlan_features[0] |=3D > > > NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; > > > - ndev->vlan_features |=3D NETIF_F_SG | NETIF_F_GSO | NETIF_F_G= RO; > > > + ndev->vlan_features[0] |=3D NETIF_F_SG | NETIF_F_GSO | NETIF_= F_GRO; > > > > > > /* MTU range: 68 - 9578 (v1) or 9706 (v2) */ > > > ndev->min_mtu =3D MAC_MIN_MTU; > > > switch (priv->enet_ver) { > > > case AE_VERSION_2: > > > - ndev->features |=3D NETIF_F_TSO | NETIF_F_TSO6 | NETI= F_F_NTUPLE; > > > - ndev->hw_features |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6= _CSUM | > > > + ndev->features[0] |=3D > > > + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_= NTUPLE; > > > + ndev->hw_features[0] |=3D NETIF_F_IP_CSUM | NETIF_F_I= PV6_CSUM | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6; > > > - ndev->vlan_features |=3D NETIF_F_TSO | NETIF_F_TSO6; > > > + ndev->vlan_features[0] |=3D NETIF_F_TSO | NETIF_F_TSO= 6; > > > ndev->max_mtu =3D MAC_MAX_MTU_V2 - > > > (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); > > > break; > > > diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > index cdb5f14..ba56907 100644 > > > --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > @@ -1481,7 +1481,7 @@ static int hns3_handle_vtags(struct > > > hns3_enet_ring *tx_ring, > > > return -EINVAL; > > > > > > if (skb->protocol =3D=3D htons(ETH_P_8021Q) && > > > - !(handle->kinfo.netdev->features & NETIF_F_HW_VLAN_CTAG_T= X)) { > > > + !(handle->kinfo.netdev->features[0] & NETIF_F_HW_VLAN_CTA= G_TX)) { > > > /* When HW VLAN acceleration is turned off, and the s= tack > > > * sets the protocol to 802.1q, the driver just need = to > > > * set the protocol to the encapsulated ethertype. > > > @@ -2300,56 +2300,57 @@ static int hns3_nic_do_ioctl(struct net_devic= e *netdev, > > > } > > > > > > static int hns3_nic_set_features(struct net_device *netdev, > > > - netdev_features_t features) > > > + netdev_features_t *features) > > > { > > > - netdev_features_t changed =3D netdev->features ^ features; > > > + netdev_features_t changed[NETDEV_FEATURE_DWORDS]; > > > struct hns3_nic_priv *priv =3D netdev_priv(netdev); > > > struct hnae3_handle *h =3D priv->ae_handle; > > > bool enable; > > > int ret; > > > > > > - if (changed & (NETIF_F_GRO_HW) && h->ae_algo->ops->set_gro_en= ) { > > > - enable =3D !!(features & NETIF_F_GRO_HW); > > > + netdev_features_xor(changed, netdev->features, features); > > > + if (changed[0] & (NETIF_F_GRO_HW) && h->ae_algo->ops->set_gro= _en) { > > > + enable =3D !!(features[0] & NETIF_F_GRO_HW); > > > ret =3D h->ae_algo->ops->set_gro_en(h, enable); > > > if (ret) > > > return ret; > > > } > > > > > > - if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && > > > + if ((changed[0] & NETIF_F_HW_VLAN_CTAG_RX) && > > > h->ae_algo->ops->enable_hw_strip_rxvtag) { > > > - enable =3D !!(features & NETIF_F_HW_VLAN_CTAG_RX); > > > + enable =3D !!(features[0] & NETIF_F_HW_VLAN_CTAG_RX); > > > ret =3D h->ae_algo->ops->enable_hw_strip_rxvtag(h, en= able); > > > if (ret) > > > return ret; > > > } > > > > > > - if ((changed & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_fd)= { > > > - enable =3D !!(features & NETIF_F_NTUPLE); > > > + if ((changed[0] & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_= fd) { > > > + enable =3D !!(features[0] & NETIF_F_NTUPLE); > > > h->ae_algo->ops->enable_fd(h, enable); > > > } > > > > > > - if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_= HW_TC) && > > > + if ((netdev->features[0] & NETIF_F_HW_TC) > > > > + (features[0] & NETIF_F_HW_TC) && > > > h->ae_algo->ops->cls_flower_active(h)) { > > > netdev_err(netdev, > > > "there are offloaded TC filters active, > > > cannot disable HW TC offload"); > > > return -EINVAL; > > > } > > > > > > - if ((changed & NETIF_F_HW_VLAN_CTAG_FILTER) && > > > + if ((changed[0] & NETIF_F_HW_VLAN_CTAG_FILTER) && > > > h->ae_algo->ops->enable_vlan_filter) { > > > - enable =3D !!(features & NETIF_F_HW_VLAN_CTAG_FILTER)= ; > > > + enable =3D !!(features[0] & NETIF_F_HW_VLAN_CTAG_FILT= ER); > > > ret =3D h->ae_algo->ops->enable_vlan_filter(h, enable= ); > > > if (ret) > > > return ret; > > > } > > > > > > - netdev->features =3D features; > > > + netdev_features_copy(netdev->features, features); > > > return 0; > > > } > > > > > > -static netdev_features_t hns3_features_check(struct sk_buff *skb, > > > - struct net_device *dev, > > > - netdev_features_t featur= es) > > > +static void hns3_features_check(struct sk_buff *skb, struct net_devi= ce *dev, > > > + netdev_features_t *features) > > > { > > > #define HNS3_MAX_HDR_LEN 480U > > > #define HNS3_MAX_L4_HDR_LEN 60U > > > @@ -2373,9 +2374,7 @@ static netdev_features_t > > > hns3_features_check(struct sk_buff *skb, > > > * len of 480 bytes. > > > */ > > > if (len > HNS3_MAX_HDR_LEN) > > > - features &=3D ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK)= ; > > > - > > > - return features; > > > + features[0] &=3D ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MA= SK); > > > } > > > > > > static void hns3_nic_get_stats64(struct net_device *netdev, > > > @@ -3127,27 +3126,28 @@ static void hns3_set_default_feature(struct > > > net_device *netdev) > > > > > > netdev->priv_flags |=3D IFF_UNICAST_FLT; > > > > > > - netdev->hw_enc_features |=3D NETIF_F_RXCSUM | NETIF_F_SG | NE= TIF_F_GSO | > > > + netdev->hw_enc_features[0] |=3D > > > + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GS= O_GRE | > > > NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_SCTP_CRC | NETIF_F_TSO_MANGLEID | NETIF_F_FRA= GLIST; > > > > > > netdev->gso_partial_features |=3D NETIF_F_GSO_GRE_CSUM; > > > > > > - netdev->features |=3D NETIF_F_HW_VLAN_CTAG_FILTER | > > > + netdev->features[0] |=3D NETIF_F_HW_VLAN_CTAG_FILTER | > > > NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GS= O_GRE | > > > NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_SCTP_CRC | NETIF_F_FRAGLIST; > > > > > > - netdev->vlan_features |=3D NETIF_F_RXCSUM | > > > + netdev->vlan_features[0] |=3D NETIF_F_RXCSUM | > > > NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | > > > NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | > > > NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_SCTP_CRC | NETIF_F_FRAGLIST; > > > > > > - netdev->hw_features |=3D NETIF_F_HW_VLAN_CTAG_TX | > > > + netdev->hw_features[0] |=3D NETIF_F_HW_VLAN_CTAG_TX | > > > NETIF_F_HW_VLAN_CTAG_RX | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GS= O_GRE | > > > @@ -3155,48 +3155,49 @@ static void hns3_set_default_feature(struct > > > net_device *netdev) > > > NETIF_F_SCTP_CRC | NETIF_F_FRAGLIST; > > > > > > if (ae_dev->dev_version >=3D HNAE3_DEVICE_VERSION_V2) { > > > - netdev->hw_features |=3D NETIF_F_GRO_HW; > > > - netdev->features |=3D NETIF_F_GRO_HW; > > > + netdev->hw_features[0] |=3D NETIF_F_GRO_HW; > > > + netdev->features[0] |=3D NETIF_F_GRO_HW; > > > > > > if (!(h->flags & HNAE3_SUPPORT_VF)) { > > > - netdev->hw_features |=3D NETIF_F_NTUPLE; > > > - netdev->features |=3D NETIF_F_NTUPLE; > > > + netdev->hw_features[0] |=3D NETIF_F_NTUPLE; > > > + netdev->features[0] |=3D NETIF_F_NTUPLE; > > > } > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_UDP_GSO_B, ae_dev->caps)) { > > > - netdev->hw_features |=3D NETIF_F_GSO_UDP_L4; > > > - netdev->features |=3D NETIF_F_GSO_UDP_L4; > > > - netdev->vlan_features |=3D NETIF_F_GSO_UDP_L4; > > > - netdev->hw_enc_features |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->hw_features[0] |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->features[0] |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->vlan_features[0] |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->hw_enc_features[0] |=3D NETIF_F_GSO_UDP_L4; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps)) { > > > - netdev->hw_features |=3D NETIF_F_HW_CSUM; > > > - netdev->features |=3D NETIF_F_HW_CSUM; > > > - netdev->vlan_features |=3D NETIF_F_HW_CSUM; > > > - netdev->hw_enc_features |=3D NETIF_F_HW_CSUM; > > > + netdev->hw_features[0] |=3D NETIF_F_HW_CSUM; > > > + netdev->features[0] |=3D NETIF_F_HW_CSUM; > > > + netdev->vlan_features[0] |=3D NETIF_F_HW_CSUM; > > > + netdev->hw_enc_features[0] |=3D NETIF_F_HW_CSUM; > > > } else { > > > - netdev->hw_features |=3D NETIF_F_IP_CSUM | NETIF_F_IP= V6_CSUM; > > > - netdev->features |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6_= CSUM; > > > - netdev->vlan_features |=3D NETIF_F_IP_CSUM | NETIF_F_= IPV6_CSUM; > > > - netdev->hw_enc_features |=3D NETIF_F_IP_CSUM | NETIF_= F_IPV6_CSUM; > > > + netdev->hw_features[0] |=3D NETIF_F_IP_CSUM | NETIF_F= _IPV6_CSUM; > > > + netdev->features[0] |=3D NETIF_F_IP_CSUM | NETIF_F_IP= V6_CSUM; > > > + netdev->vlan_features[0] |=3D NETIF_F_IP_CSUM | NETIF= _F_IPV6_CSUM; > > > + netdev->hw_enc_features[0] |=3D > > > + NETIF_F_IP_CSUM | NETIF_F_IPV= 6_CSUM; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, ae_dev->cap= s)) { > > > - netdev->hw_features |=3D NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > - netdev->features |=3D NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > - netdev->vlan_features |=3D NETIF_F_GSO_UDP_TUNNEL_CSU= M; > > > - netdev->hw_enc_features |=3D NETIF_F_GSO_UDP_TUNNEL_C= SUM; > > > + netdev->hw_features[0] |=3D NETIF_F_GSO_UDP_TUNNEL_CS= UM; > > > + netdev->features[0] |=3D NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > + netdev->vlan_features[0] |=3D NETIF_F_GSO_UDP_TUNNEL_= CSUM; > > > + netdev->hw_enc_features[0] |=3D NETIF_F_GSO_UDP_TUNNE= L_CSUM; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B, ae_dev->caps)= ) { > > > - netdev->hw_features |=3D NETIF_F_HW_TC; > > > - netdev->features |=3D NETIF_F_HW_TC; > > > + netdev->hw_features[0] |=3D NETIF_F_HW_TC; > > > + netdev->features[0] |=3D NETIF_F_HW_TC; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps)= ) > > > - netdev->hw_features |=3D NETIF_F_HW_VLAN_CTAG_FILTER; > > > + netdev->hw_features[0] |=3D NETIF_F_HW_VLAN_CTAG_FILT= ER; > > > } > > > > > > static int hns3_alloc_buffer(struct hns3_enet_ring *ring, > > > @@ -3727,7 +3728,7 @@ static void hns3_rx_checksum(struct > > > hns3_enet_ring *ring, struct sk_buff *skb, > > > > > > skb_checksum_none_assert(skb); > > > > > > - if (!(netdev->features & NETIF_F_RXCSUM)) > > > + if (!(netdev->features[0] & NETIF_F_RXCSUM)) > > > return; > > > > > > if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->sta= te)) > > > @@ -4024,7 +4025,7 @@ static int hns3_handle_bdinfo(struct > > > hns3_enet_ring *ring, struct sk_buff *skb) > > > * ot_vlan_tag in two layer tag case, and stored at vlan_tag > > > * in one layer tag case. > > > */ > > > - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { > > > + if (netdev->features[0] & NETIF_F_HW_VLAN_CTAG_RX) { > > > u16 vlan_tag; > > > > > > if (hns3_parse_vlan_tag(ring, desc, l234info, &vlan_t= ag)) > > > diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > b/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > index 405ee4d..b193ee4 100644 > > > --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > @@ -79,8 +79,8 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for > > > NAPI budget (default=3D64)"); > > > static int change_mac_addr(struct net_device *netdev, const u8 *addr= ); > > > > > > static int set_features(struct hinic_dev *nic_dev, > > > - netdev_features_t pre_features, > > > - netdev_features_t features, bool force_change= ); > > > + netdev_features_t *pre_features, > > > + netdev_features_t *features, bool force_chang= e); > > > > > > static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_= rxq *rxq) > > > { > > > @@ -880,7 +880,7 @@ static void hinic_get_stats64(struct net_device *= netdev, > > > } > > > > > > static int hinic_set_features(struct net_device *netdev, > > > - netdev_features_t features) > > > + netdev_features_t *features) > > > { > > > struct hinic_dev *nic_dev =3D netdev_priv(netdev); > > > > > > @@ -888,18 +888,16 @@ static int hinic_set_features(struct net_device= *netdev, > > > features, false); > > > } > > > > > > -static netdev_features_t hinic_fix_features(struct net_device *netde= v, > > > - netdev_features_t feature= s) > > > +static void hinic_fix_features(struct net_device *netdev, > > > + netdev_features_t features) > > > { > > > struct hinic_dev *nic_dev =3D netdev_priv(netdev); > > > > > > /* If Rx checksum is disabled, then LRO should also be disabl= ed */ > > > - if (!(features & NETIF_F_RXCSUM)) { > > > + if (!(features[0] & NETIF_F_RXCSUM)) { > > > netif_info(nic_dev, drv, netdev, "disabling LRO as > > > RXCSUM is off\n"); > > > - features &=3D ~NETIF_F_LRO; > > > + features[0] &=3D ~NETIF_F_LRO; > > > } > > > - > > > - return features; > > > } > > > > > > static const struct net_device_ops hinic_netdev_ops =3D { > > > @@ -943,19 +941,22 @@ static const struct net_device_ops hinicvf_netd= ev_ops =3D { > > > > > > static void netdev_features_init(struct net_device *netdev) > > > { > > > - netdev->hw_features =3D NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_= F_IP_CSUM | > > > - NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF= _F_TSO6 | > > > - NETIF_F_RXCSUM | NETIF_F_LRO | > > > - NETIF_F_HW_VLAN_CTAG_TX | > > > NETIF_F_HW_VLAN_CTAG_RX | > > > - NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > - > > > - netdev->vlan_features =3D netdev->hw_features; > > > - > > > - netdev->features =3D netdev->hw_features | NETIF_F_HW_VLAN_CT= AG_FILTER; > > > - > > > - netdev->hw_enc_features =3D NETIF_F_IP_CSUM | NETIF_F_IPV6_CS= UM > > > | NETIF_F_SCTP_CRC | > > > - NETIF_F_SG | NETIF_F_TSO | > > > NETIF_F_TSO6 | NETIF_F_TSO_ECN | > > > - NETIF_F_GSO_UDP_TUNNEL_CSUM | > > > NETIF_F_GSO_UDP_TUNNEL; > > > + netdev->hw_features[0] =3D > > > + NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSU= M | > > > + NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO= 6 | > > > + NETIF_F_RXCSUM | NETIF_F_LRO | > > > + NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTA= G_RX | > > > + NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNN= EL_CSUM; > > > + > > > + netdev_features_copy(netdev->vlan_features, netdev->hw_featur= es); > > > + > > > + netdev->features[0] =3D > > > + netdev->hw_features[0] | NETIF_F_HW_VLAN_CTAG= _FILTER; > > > + > > > + netdev->hw_enc_features[0] =3D > > > + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SCTP_CR= C | > > > + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO= _ECN | > > > + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_UDP_TUNNEL; > > > } > > > > > > static void hinic_refresh_nic_cfg(struct hinic_dev *nic_dev) > > > @@ -1072,21 +1073,22 @@ static void link_err_event(void *handle, > > > } > > > > > > static int set_features(struct hinic_dev *nic_dev, > > > - netdev_features_t pre_features, > > > - netdev_features_t features, bool force_change= ) > > > + netdev_features_t *pre_features, > > > + netdev_features_t *features, bool force_chang= e) > > > { > > > - netdev_features_t changed =3D force_change ? ~0 : pre_feature= s ^ features; > > > + netdev_features_t failed_features[NETDEV_FEATURE_DWORDS] =3D = {0}; > > > u32 csum_en =3D HINIC_RX_CSUM_OFFLOAD_EN; > > > - netdev_features_t failed_features =3D 0; > > > + netdev_features_t changed; > > > int ret =3D 0; > > > int err =3D 0; > > > > > > + changed =3D force_change ? ~0 : pre_features[0] ^ features[0]= ; > > > if (changed & NETIF_F_TSO) { > > > - ret =3D hinic_port_set_tso(nic_dev, (features & NETIF= _F_TSO) ? > > > + ret =3D hinic_port_set_tso(nic_dev, (features[0] & NE= TIF_F_TSO) ? > > > HINIC_TSO_ENABLE : HINIC_TSO= _DISABLE); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_TSO; > > > + failed_features[0] |=3D NETIF_F_TSO; > > > } > > > } > > > > > > @@ -1094,33 +1096,34 @@ static int set_features(struct hinic_dev *nic= _dev, > > > ret =3D hinic_set_rx_csum_offload(nic_dev, csum_en); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_RXCSUM; > > > + failed_features[0] |=3D NETIF_F_RXCSUM; > > > } > > > } > > > > > > if (changed & NETIF_F_LRO) { > > > ret =3D hinic_set_rx_lro_state(nic_dev, > > > - !!(features & NETIF_F_LR= O), > > > + !!(features[0] & NETIF_F= _LRO), > > > HINIC_LRO_RX_TIMER_DEFAU= LT, > > > HINIC_LRO_MAX_WQE_NUM_DE= FAULT); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_LRO; > > > + failed_features[0] |=3D NETIF_F_LRO; > > > } > > > } > > > > > > if (changed & NETIF_F_HW_VLAN_CTAG_RX) { > > > ret =3D hinic_set_rx_vlan_offload(nic_dev, > > > - !!(features & > > > + !!(features[0] & > > > NETIF_F_HW_VLAN_CT= AG_RX)); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_HW_VLAN_CTAG_RX; > > > + failed_features[0] |=3D NETIF_F_HW_VLAN_CTAG_= RX; > > > } > > > } > > > > > > if (err) { > > > - nic_dev->netdev->features =3D features ^ failed_featu= res; > > > + netdev_features_xor(nic_dev->netdev->features, featur= es, > > > + failed_features) > > > return -EIO; > > > } > > > > > > diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > b/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > index fed3b6b..452a91b 100644 > > > --- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > +++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > @@ -106,7 +106,7 @@ static void rx_csum(struct hinic_rxq *rxq, u32 st= atus, > > > > > > csum_err =3D HINIC_RQ_CQE_STATUS_GET(status, CSUM_ERR); > > > > > > - if (!(netdev->features & NETIF_F_RXCSUM)) > > > + if (!(netdev->features[0] & NETIF_F_RXCSUM)) > > > return; > > > > > > if (!csum_err) { > > > @@ -411,7 +411,7 @@ static int rxq_recv(struct hinic_rxq *rxq, int bu= dget) > > > > > > offload_type =3D be32_to_cpu(cqe->offload_type); > > > vlan_len =3D be32_to_cpu(cqe->len); > > > - if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && > > > + if ((netdev->features[0] & NETIF_F_HW_VLAN_CTAG_RX) &= & > > > HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type)) { > > > vid =3D HINIC_GET_RX_VLAN_TAG(vlan_len); > > > __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q= ), vid); > > > diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h > > > index 41a5183..4173464 100644 > > > --- a/include/linux/if_vlan.h > > > +++ b/include/linux/if_vlan.h > > > @@ -563,7 +563,7 @@ static inline int __vlan_hwaccel_get_tag(const > > > struct sk_buff *skb, > > > */ > > > static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_= tci) > > > { > > > - if (skb->dev->features & NETIF_F_HW_VLAN_CTAG_TX) { > > > + if (skb->dev->features[0] & NETIF_F_HW_VLAN_CTAG_TX) { > > > return __vlan_hwaccel_get_tag(skb, vlan_tci); > > > } else { > > > return __vlan_get_tag(skb, vlan_tci); > > > diff --git a/include/linux/netdev_features.h b/include/linux/netdev_f= eatures.h > > > index 2c6b9e4..9184963 100644 > > > --- a/include/linux/netdev_features.h > > > +++ b/include/linux/netdev_features.h > > > @@ -102,7 +102,8 @@ enum { > > > }; > > > > > > /* copy'n'paste compression ;) */ > > > -#define __NETIF_F_BIT(bit) ((netdev_features_t)1 << (bit)) > > > +#define __NETIF_F_BIT(bit) ((netdev_features_t)1 << (bit & 0x3F)= ) > > > + > > > #define __NETIF_F(name) __NETIF_F_BIT(NETIF_F_##name#= #_BIT) > > > > > > #define NETIF_F_FCOE_CRC __NETIF_F(FCOE_CRC) > > > @@ -169,6 +170,8 @@ enum { > > > #define NETIF_F_HW_HSR_FWD __NETIF_F(HW_HSR_FWD) > > > #define NETIF_F_HW_HSR_DUP __NETIF_F(HW_HSR_DUP) > > > > > > +#define NETDEV_FEATURE_DWORDS DIV_ROUND_UP(NETDEV_FEATURE_COUNT, 64= ) > > > + > > > /* Finds the next feature with the highest number of the range of st= art till 0. > > > */ > > > static inline int find_next_netdev_feature(u64 feature, unsigned lon= g start) > > > @@ -185,8 +188,7 @@ static inline int find_next_netdev_feature(u64 > > > feature, unsigned long start) > > > * mask_addr should be a u64 and bit an int > > > */ > > > #define for_each_netdev_feature(mask_addr, bit) > > > \ > > > - for ((bit) =3D find_next_netdev_feature((mask_addr), = \ > > > - NETDEV_FEATURE_COUNT); = \ > > > + for ((bit) =3D find_next_netdev_feature((mask_addr), 64); = \ > > > (bit) >=3D 0; = \ > > > (bit) =3D find_next_netdev_feature((mask_addr), (bit) - = 1)) > > > > > > @@ -195,11 +197,6 @@ static inline int find_next_netdev_feature(u64 > > > feature, unsigned long start) > > > #define NETIF_F_NEVER_CHANGE (NETIF_F_VLAN_CHALLENGED | \ > > > NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) > > > > > > -/* remember that ((t)1 << t_BITS) is undefined in C99 */ > > > -#define NETIF_F_ETHTOOL_BITS ((__NETIF_F_BIT(NETDEV_FEATURE_COUNT = - 1) | \ > > > - (__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) - 1)) & \ > > > - ~NETIF_F_NEVER_CHANGE) > > > - > > > /* Segmentation offload feature mask */ > > > #define NETIF_F_GSO_MASK (__NETIF_F_BIT(NETIF_F_GSO_LAST + 1) = - \ > > > __NETIF_F_BIT(NETIF_F_GSO_SHIFT)) > > > @@ -261,4 +258,96 @@ static inline int find_next_netdev_feature(u64 > > > feature, unsigned long start) > > > NETIF_F_GSO_UDP_TUNNEL | = \ > > > NETIF_F_GSO_UDP_TUNNEL_CSUM) > > > > > > +static inline void netdev_features_copy(netdev_features_t *dst, > > > + const netdev_features_t *src) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D src[i]; > > > +} > > > + > > > +static inline void netdev_features_and(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] & b[i]; > > > +} > > > + > > > +static inline void netdev_features_andnot(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] & ~b[i]; > > > +} > > > + > > > +static inline void netdev_features_or(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] | b[i]; > > > +} > > > + > > > +static inline void netdev_features_xor(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] ^ b[i]; > > > +} > > > + > > > +static inline void netdev_features_set(netdev_features_t *dst, > > > + unsigned int bit) > > > +{ > > > + dst[bit / 64] |=3D __NETIF_F_BIT(bit); > > > +} > > > + > > > +static inline bool netdev_features_equal(const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + if (a[i] !=3D b[i]) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static inline void netdev_features_empty(netdev_features_t *src) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + if (src[i]) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static inline void netdev_features_ethtool_bits(netdev_features_t *d= st) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + if (NETDEV_FEATURE_COUNT >=3D (i + 1) * 64) > > > + dst[i] =3D GENMASK_ULL(63, 0); > > > + else > > > + dst[i] =3D GENMASK_ULL(NETDEV_FEATURE_COUNT -= i * 64, > > > + 0); > > > + } > > > + dst[0] &=3D ~NETIF_F_NEVER_CHANGE; > > > +} > > > + > > > #endif /* _LINUX_NETDEV_FEATURES_H */ > > > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h > > > index eaf5bb0..4a29487 100644 > > > --- a/include/linux/netdevice.h > > > +++ b/include/linux/netdevice.h > > > @@ -1347,9 +1347,9 @@ struct net_device_ops { > > > int (*ndo_stop)(struct net_device *dev); > > > netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb= , > > > struct net_device *= dev); > > > - netdev_features_t (*ndo_features_check)(struct sk_buff = *skb, > > > + void (*ndo_features_check)(struct sk_buff = *skb, > > > struct net_devi= ce *dev, > > > - > > > netdev_features_t features); > > > + > > > netdev_features_t *features); > > > u16 (*ndo_select_queue)(struct net_device= *dev, > > > struct sk_buff *s= kb, > > > struct net_device= *sb_dev); > > > @@ -1467,10 +1467,10 @@ struct net_device_ops { > > > bool all_slaves= ); > > > struct net_device* (*ndo_sk_get_lower_dev)(struct net_de= vice *dev, > > > struct sock *= sk); > > > - netdev_features_t (*ndo_fix_features)(struct net_device= *dev, > > > - netdev_features_t= features); > > > + void (*ndo_fix_features)(struct net_device= *dev, > > > + netdev_features_t > > > *features); > > > int (*ndo_set_features)(struct net_device= *dev, > > > - netdev_features_t= features); > > > + netdev_features_t > > > *features); > > > int (*ndo_neigh_construct)(struct net_dev= ice *dev, > > > struct neighbo= ur *n); > > > void (*ndo_neigh_destroy)(struct net_devic= e *dev, > > > @@ -1978,12 +1978,12 @@ struct net_device { > > > unsigned short needed_headroom; > > > unsigned short needed_tailroom; > > > > > > - netdev_features_t features; > > > - netdev_features_t hw_features; > > > - netdev_features_t wanted_features; > > > - netdev_features_t vlan_features; > > > - netdev_features_t hw_enc_features; > > > - netdev_features_t mpls_features; > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t hw_features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t wanted_features[NETDEV_FEATURE_DWORDS= ]; > > > + netdev_features_t vlan_features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t hw_enc_features[NETDEV_FEATURE_DWORDS= ]; > > > + netdev_features_t mpls_features[NETDEV_FEATURE_DWORDS]; > > > netdev_features_t gso_partial_features; > > > > > > unsigned int min_mtu; > > > @@ -4986,10 +4986,11 @@ static inline netdev_features_t > > > netdev_intersect_features(netdev_features_t f1, > > > return f1 & f2; > > > } > > > > > > -static inline netdev_features_t netdev_get_wanted_features( > > > - struct net_device *dev) > > > +static inline void netdev_get_wanted_features(struct net_device *dev= , > > > + netdev_features_t *want= ed) > > > { > > > - return (dev->features & ~dev->hw_features) | dev->wanted_feat= ures; > > > + netdev_features_andnot(wanted, dev->features, dev->hw_feature= s); > > > + netdev_features_or(wanted, wanted, dev->wanted_features); > > > } > > > netdev_features_t netdev_increment_features(netdev_features_t all, > > > netdev_features_t one, netdev_features_t mask); > > > @@ -5014,7 +5015,7 @@ void netif_stacked_transfer_operstate(const > > > struct net_device *rootdev, > > > netdev_features_t passthru_features_check(struct sk_buff *skb, > > > struct net_device *dev, > > > netdev_features_t features)= ; > > > -netdev_features_t netif_skb_features(struct sk_buff *skb); > > > +void netif_skb_features(struct sk_buff *skb, netdev_features_t *feat= ures); > > > > > > static inline bool net_gso_ok(netdev_features_t features, int gso_ty= pe) > > > { > > > diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c > > > index 4cdf841..7d77692 100644 > > > --- a/net/8021q/vlan.c > > > +++ b/net/8021q/vlan.c > > > @@ -328,7 +328,7 @@ static void vlan_transfer_features(struct net_dev= ice *dev, > > > vlandev->gso_max_size =3D dev->gso_max_size; > > > vlandev->gso_max_segs =3D dev->gso_max_segs; > > > > > > - if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto)) > > > + if (vlan_hw_offload_capable(dev->features[0], vlan->vlan_prot= o)) > > > vlandev->hard_header_len =3D dev->hard_header_len; > > > else > > > vlandev->hard_header_len =3D dev->hard_header_len + V= LAN_HLEN; > > > @@ -339,7 +339,7 @@ static void vlan_transfer_features(struct net_dev= ice *dev, > > > > > > vlandev->priv_flags &=3D ~IFF_XMIT_DST_RELEASE; > > > vlandev->priv_flags |=3D (vlan->real_dev->priv_flags & > > > IFF_XMIT_DST_RELEASE); > > > - vlandev->hw_enc_features =3D vlan_tnl_features(vlan->real_dev= ); > > > + vlandev->hw_enc_features[0] =3D vlan_tnl_features(vlan->real_= dev); > > > > > > netdev_update_features(vlandev); > > > } > > > diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h > > > index 1a705a4..4e784a1 100644 > > > --- a/net/8021q/vlan.h > > > +++ b/net/8021q/vlan.h > > > @@ -107,7 +107,7 @@ static inline netdev_features_t > > > vlan_tnl_features(struct net_device *real_dev) > > > { > > > netdev_features_t ret; > > > > > > - ret =3D real_dev->hw_enc_features & > > > + ret =3D real_dev->hw_enc_features[0] & > > > (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE | > > > NETIF_F_GSO_ENCAP_ALL); > > > > > > diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c > > > index a0367b3..6d49761 100644 > > > --- a/net/8021q/vlan_dev.c > > > +++ b/net/8021q/vlan_dev.c > > > @@ -566,21 +566,21 @@ static int vlan_dev_init(struct net_device *dev= ) > > > if (vlan->flags & VLAN_FLAG_BRIDGE_BINDING) > > > dev->state |=3D (1 << __LINK_STATE_NOCARRIER); > > > > > > - dev->hw_features =3D NETIF_F_HW_CSUM | NETIF_F_SG | > > > - NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | > > > - NETIF_F_GSO_ENCAP_ALL | > > > - NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | > > > - NETIF_F_ALL_FCOE; > > > + dev->hw_features[0] =3D NETIF_F_HW_CSUM | NETIF_F_SG | > > > + NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE= | > > > + NETIF_F_GSO_ENCAP_ALL | > > > + NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | > > > + NETIF_F_ALL_FCOE; > > > > > > - dev->features |=3D dev->hw_features | NETIF_F_LLTX; > > > + dev->features[0] |=3D dev->hw_features[0] | NETIF_F_LLTX; > > > dev->gso_max_size =3D real_dev->gso_max_size; > > > dev->gso_max_segs =3D real_dev->gso_max_segs; > > > - if (dev->features & NETIF_F_VLAN_FEATURES) > > > + if (dev->features[0] & NETIF_F_VLAN_FEATURES) > > > netdev_warn(real_dev, "VLAN features are set > > > incorrectly. Q-in-Q configurations may not work correctly.\n"); > > > > > > - dev->vlan_features =3D real_dev->vlan_features & ~NETIF_F_ALL= _FCOE; > > > - dev->hw_enc_features =3D vlan_tnl_features(real_dev); > > > - dev->mpls_features =3D real_dev->mpls_features; > > > + dev->vlan_features[0] =3D real_dev->vlan_features[0] & ~NETIF= _F_ALL_FCOE; > > > + dev->hw_enc_features[0] =3D vlan_tnl_features(real_dev); > > > + netdev_features_copy(dev->mpls_features, real_dev->mpls_featu= res); > > > > > > /* ipv6 shared card related stuff */ > > > dev->dev_id =3D real_dev->dev_id; > > > @@ -633,27 +633,30 @@ void vlan_dev_uninit(struct net_device *dev) > > > } > > > } > > > > > > -static netdev_features_t vlan_dev_fix_features(struct net_device *de= v, > > > - netdev_features_t features) > > > +static void vlan_dev_fix_features(struct net_device *dev, > > > + netdev_features_t *features) > > > { > > > struct net_device *real_dev =3D vlan_dev_priv(dev)->real_dev; > > > - netdev_features_t old_features =3D features; > > > - netdev_features_t lower_features; > > > + netdev_features_t lower_features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t old_features[NETDEV_FEATURE_DWORDS]; > > > > > > - lower_features =3D netdev_intersect_features((real_dev->vlan_= features | > > > - NETIF_F_RXCSUM), > > > - real_dev->features= ); > > > + netdev_features_copy(lower_features, features); > > > + > > > + lower_features[0] =3D > > > + netdev_intersect_features((real_dev->vlan_features[0]= | > > > + NETIF_F_RXCSUM), > > > + real_dev->features[0]); > > > > > > /* Add HW_CSUM setting to preserve user ability to control > > > * checksum offload on the vlan device. > > > */ > > > - if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) > > > - lower_features |=3D NETIF_F_HW_CSUM; > > > - features =3D netdev_intersect_features(features, lower_featur= es); > > > - features |=3D old_features & (NETIF_F_SOFT_FEATURES | > > > NETIF_F_GSO_SOFTWARE); > > > - features |=3D NETIF_F_LLTX; > > > + if (lower_features[0] & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)= ) > > > + lower_features[0] |=3D NETIF_F_HW_CSUM; > > > > > > - return features; > > > + features[0] =3D netdev_intersect_features(features[0], lower_= features[0]); > > > + features[0] |=3D old_features[0] & > > > + (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE= ); > > > + features[0] |=3D NETIF_F_LLTX; > > > } > > > > > > static int vlan_ethtool_get_link_ksettings(struct net_device *dev, > > > diff --git a/net/core/dev.c b/net/core/dev.c > > > index c253c2a..7066bf3 100644 > > > --- a/net/core/dev.c > > > +++ b/net/core/dev.c > > > @@ -1765,7 +1765,7 @@ void dev_disable_lro(struct net_device *dev) > > > dev->wanted_features &=3D ~NETIF_F_LRO; > > > netdev_update_features(dev); > > > > > > - if (unlikely(dev->features & NETIF_F_LRO)) > > > + if (unlikely(dev->features[0] & NETIF_F_LRO)) > > > netdev_WARN(dev, "failed to disable LRO!\n"); > > > > > > netdev_for_each_lower_dev(dev, lower_dev, iter) > > > @@ -1786,7 +1786,7 @@ static void dev_disable_gro_hw(struct net_devic= e *dev) > > > dev->wanted_features &=3D ~NETIF_F_GRO_HW; > > > netdev_update_features(dev); > > > > > > - if (unlikely(dev->features & NETIF_F_GRO_HW)) > > > + if (unlikely(dev->features[0] & NETIF_F_GRO_HW)) > > > netdev_WARN(dev, "failed to disable GRO_HW!\n"); > > > } > > > > > > @@ -3276,7 +3276,7 @@ static void skb_warn_bad_offload(const struct > > > sk_buff *skb) > > > } > > > skb_dump(KERN_WARNING, skb, false); > > > WARN(1, "%s: caps=3D(%pNF, %pNF)\n", > > > - name, dev ? &dev->features : &null_features, > > > + name, dev ? &dev->features[0] : &null_features, > > > skb->sk ? &skb->sk->sk_route_caps : &null_features); > > > } > > > > > > @@ -3463,7 +3463,8 @@ struct sk_buff *__skb_gso_segment(struct sk_buf= f *skb, > > > netdev_features_t partial_features =3D NETIF_F_GSO_RO= BUST; > > > struct net_device *dev =3D skb->dev; > > > > > > - partial_features |=3D dev->features & dev->gso_partia= l_features; > > > + partial_features |=3D > > > + dev->features[0] & dev->gso_partial_f= eatures; > > > if (!skb_gso_ok(skb, features | partial_features)) > > > features &=3D ~NETIF_F_GSO_PARTIAL; > > > } > > > @@ -3508,7 +3509,7 @@ static int illegal_highdma(struct net_device > > > *dev, struct sk_buff *skb) > > > #ifdef CONFIG_HIGHMEM > > > int i; > > > > > > - if (!(dev->features & NETIF_F_HIGHDMA)) { > > > + if (!(dev->features[0] & NETIF_F_HIGHDMA)) { > > > for (i =3D 0; i < skb_shinfo(skb)->nr_frags; i++) { > > > skb_frag_t *frag =3D &skb_shinfo(skb)->frags[= i]; > > > > > > @@ -3612,34 +3613,33 @@ static netdev_features_t > > > gso_features_check(const struct sk_buff *skb, > > > return features; > > > } > > > > > > -netdev_features_t netif_skb_features(struct sk_buff *skb) > > > +void netif_skb_features(struct sk_buff *skb, netdev_features_t *feat= ures) > > > { > > > struct net_device *dev =3D skb->dev; > > > - netdev_features_t features =3D dev->features; > > > > > > + netdev_features_copy(features, dev->features); > > > if (skb_is_gso(skb)) > > > - features =3D gso_features_check(skb, dev, features); > > > + features[0] =3D gso_features_check(skb, dev, features= [0]); > > > > > > /* If encapsulation offload request, verify we are testing > > > * hardware encapsulation features instead of standard > > > * features for the netdev > > > */ > > > if (skb->encapsulation) > > > - features &=3D dev->hw_enc_features; > > > + netdev_features_and(features, dev->hw_enc_features); > > > > > > if (skb_vlan_tagged(skb)) > > > - features =3D netdev_intersect_features(features, > > > - dev->vlan_featur= es | > > > - NETIF_F_HW_VLAN_= CTAG_TX | > > > - NETIF_F_HW_VLAN_= STAG_TX); > > > + features[0] =3D netdev_intersect_features(features[0]= , > > > + dev->vlan_fea= tures[0] | > > > + > > > NETIF_F_HW_VLAN_CTAG_TX | > > > + > > > NETIF_F_HW_VLAN_STAG_TX); > > > > > > if (dev->netdev_ops->ndo_features_check) > > > - features &=3D dev->netdev_ops->ndo_features_check(skb= , dev, > > > - featu= res); > > > + dev->netdev_ops->ndo_features_check(skb, dev, feature= s); > > > else > > > - features &=3D dflt_features_check(skb, dev, features)= ; > > > + features[0] &=3D dflt_features_check(skb, dev, featur= es[0]); > > > > > > - return harmonize_features(skb, features); > > > + features[0] =3D harmonize_features(skb, features[0]); > > > } > > > EXPORT_SYMBOL(netif_skb_features); > > > > > > @@ -3722,10 +3722,10 @@ EXPORT_SYMBOL(skb_csum_hwoffload_help); > > > > > > static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct > > > net_device *dev, bool *again) > > > { > > > - netdev_features_t features; > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > > > > - features =3D netif_skb_features(skb); > > > - skb =3D validate_xmit_vlan(skb, features); > > > + netif_skb_features(skb, features); > > > + skb =3D validate_xmit_vlan(skb, features[0]); > > > if (unlikely(!skb)) > > > goto out_null; > > > > > > @@ -3733,10 +3733,10 @@ static struct sk_buff > > > *validate_xmit_skb(struct sk_buff *skb, struct net_device > > > if (unlikely(!skb)) > > > goto out_null; > > > > > > - if (netif_needs_gso(skb, features)) { > > > + if (netif_needs_gso(skb, features[0])) { > > > struct sk_buff *segs; > > > > > > - segs =3D skb_gso_segment(skb, features); > > > + segs =3D skb_gso_segment(skb, features[0]); > > > if (IS_ERR(segs)) { > > > goto out_kfree_skb; > > > } else if (segs) { > > > @@ -3744,7 +3744,7 @@ static struct sk_buff *validate_xmit_skb(struct > > > sk_buff *skb, struct net_device > > > skb =3D segs; > > > } > > > } else { > > > - if (skb_needs_linearize(skb, features) && > > > + if (skb_needs_linearize(skb, features[0]) && > > > __skb_linearize(skb)) > > > goto out_kfree_skb; > > > > > > @@ -3759,12 +3759,12 @@ static struct sk_buff > > > *validate_xmit_skb(struct sk_buff *skb, struct net_device > > > else > > > skb_set_transport_header(skb, > > > > > > skb_checksum_start_offset(skb)); > > > - if (skb_csum_hwoffload_help(skb, features)) > > > + if (skb_csum_hwoffload_help(skb, features[0])= ) > > > goto out_kfree_skb; > > > } > > > } > > > > > > - skb =3D validate_xmit_xfrm(skb, features, again); > > > + skb =3D validate_xmit_xfrm(skb, features[0], again); > > > > > > return skb; > > > > > > @@ -4429,7 +4429,7 @@ set_rps_cpu(struct net_device *dev, struct sk_b= uff *skb, > > > > > > /* Should we steer this flow to a different hardware = queue? */ > > > if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap = || > > > - !(dev->features & NETIF_F_NTUPLE)) > > > + !(dev->features[0] & NETIF_F_NTUPLE)) > > > goto out; > > > rxq_index =3D cpu_rmap_lookup_index(dev->rx_cpu_rmap,= next_cpu); > > > if (rxq_index =3D=3D skb_get_rx_queue(skb)) > > > @@ -9799,171 +9799,179 @@ static void net_set_todo(struct net_device = *dev) > > > dev_net(dev)->dev_unreg_count++; > > > } > > > > > > -static netdev_features_t netdev_sync_upper_features(struct net_devic= e *lower, > > > - struct net_device *upper, netdev_features_t features) > > > +static void netdev_sync_upper_features(struct net_device *lower, > > > + struct net_device *upper, > > > + netdev_features_t *features) > > > { > > > netdev_features_t upper_disables =3D NETIF_F_UPPER_DISABLES; > > > netdev_features_t feature; > > > int feature_bit; > > > + unsigned int i; > > > > > > - for_each_netdev_feature(upper_disables, feature_bit) { > > > - feature =3D __NETIF_F_BIT(feature_bit); > > > - if (!(upper->wanted_features & feature) > > > - && (features & feature)) { > > > - netdev_dbg(lower, "Dropping feature %pNF, > > > upper dev %s has it off.\n", > > > - &feature, upper->name); > > > - features &=3D ~feature; > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + for_each_netdev_feature(upper_disables, feature_bit) = { > > > + feature =3D __NETIF_F_BIT(feature_bit); > > > + if (!(upper->wanted_features[i] & feature) && > > > + (features[i] & feature)) { > > > + netdev_dbg(lower, "Dropping > > > feature[%u] %pNF, upper dev %s has it off.\n", > > > + i, &feature, upper->name); > > > + features[i] &=3D ~feature; > > > + } > > > } > > > } > > > - > > > - return features; > > > } > > > > > > static void netdev_sync_lower_features(struct net_device *upper, > > > - struct net_device *lower, netdev_features_t features) > > > + struct net_device *lower, netdev_features_t *features) > > > { > > > netdev_features_t upper_disables =3D NETIF_F_UPPER_DISABLES; > > > netdev_features_t feature; > > > int feature_bit; > > > + unsigned int i; > > > > > > - for_each_netdev_feature(upper_disables, feature_bit) { > > > - feature =3D __NETIF_F_BIT(feature_bit); > > > - if (!(features & feature) && (lower->features & featu= re)) { > > > - netdev_dbg(upper, "Disabling feature %pNF on > > > lower dev %s.\n", > > > - &feature, lower->name); > > > - lower->wanted_features &=3D ~feature; > > > - __netdev_update_features(lower); > > > - > > > - if (unlikely(lower->features & feature)) > > > - netdev_WARN(upper, "failed to disable > > > %pNF on %s!\n", > > > - &feature, lower->name); > > > - else > > > - netdev_features_change(lower); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + for_each_netdev_feature(upper_disables, feature_bit) = { > > > + feature =3D __NETIF_F_BIT(feature_bit); > > > + if (!(features[i] & feature) && > > > + (lower->features[i] & feature)) { > > > + netdev_dbg(upper, "Disabling > > > feature[%u] %pNF on lower dev %s.\n", > > > + i, &feature, lower->name); > > > + lower->wanted_features[i] &=3D ~featu= re[i]; > > > + __netdev_update_features(lower); > > > + > > > + if (unlikely(lower->features[i] & fea= ture)) > > > + netdev_WARN(upper, "failed to > > > disable feature[%u] %pNF on %s!\n", > > > + i, &feature, lowe= r->name); > > > + else > > > + netdev_features_change(lower)= ; > > > + } > > > } > > > } > > > } > > > > > > -static netdev_features_t netdev_fix_features(struct net_device *dev, > > > - netdev_features_t features) > > > +static void netdev_fix_features(struct net_device *dev, > > > + netdev_features_t *features) > > > { > > > /* Fix illegal checksum combinations */ > > > - if ((features & NETIF_F_HW_CSUM) && > > > - (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { > > > + if ((features[0] & NETIF_F_HW_CSUM) && > > > + (features[0] & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) { > > > netdev_warn(dev, "mixed HW and IP checksum settings.\= n"); > > > - features &=3D ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); > > > + features[0] &=3D ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSU= M); > > > } > > > > > > /* TSO requires that SG is present as well. */ > > > - if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG))= { > > > + if ((features[0] & NETIF_F_ALL_TSO) && !(features[0] & NETIF_= F_SG)) { > > > netdev_dbg(dev, "Dropping TSO features since no SG fe= ature.\n"); > > > - features &=3D ~NETIF_F_ALL_TSO; > > > + features[0] &=3D ~NETIF_F_ALL_TSO; > > > } > > > > > > - if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM)= && > > > - !(features & NETIF_F_IP_CSUM)= ) { > > > + if ((features[0] & NETIF_F_TSO) && !(features[0] & NETIF_F_HW= _CSUM) && > > > + !(features[0] & NETIF_F_IP_CSUM)) { > > > netdev_dbg(dev, "Dropping TSO features since no CSUM > > > feature.\n"); > > > - features &=3D ~NETIF_F_TSO; > > > - features &=3D ~NETIF_F_TSO_ECN; > > > + features[0] &=3D ~NETIF_F_TSO; > > > + features[0] &=3D ~NETIF_F_TSO_ECN; > > > } > > > > > > - if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM= ) && > > > - !(features & NETIF_F_IPV6_CS= UM)) { > > > + if ((features[0] & NETIF_F_TSO6) && !(features[0] & NETIF_F_H= W_CSUM) && > > > + !(features[0] & NETIF_F_IPV6_CSUM)) { > > > netdev_dbg(dev, "Dropping TSO6 features since no CSUM > > > feature.\n"); > > > - features &=3D ~NETIF_F_TSO6; > > > + features[0] &=3D ~NETIF_F_TSO6; > > > } > > > > > > /* TSO with IPv4 ID mangling requires IPv4 TSO be enabled */ > > > - if ((features & NETIF_F_TSO_MANGLEID) && !(features & NETIF_F= _TSO)) > > > - features &=3D ~NETIF_F_TSO_MANGLEID; > > > + if ((features[0] & NETIF_F_TSO_MANGLEID) && > > > + !(features[0] & NETIF_F_TSO)) > > > + features[0] &=3D ~NETIF_F_TSO_MANGLEID; > > > > > > /* TSO ECN requires that TSO is present as well. */ > > > - if ((features & NETIF_F_ALL_TSO) =3D=3D NETIF_F_TSO_ECN) > > > - features &=3D ~NETIF_F_TSO_ECN; > > > + if ((features[0] & NETIF_F_ALL_TSO) =3D=3D NETIF_F_TSO_ECN) > > > + features[0] &=3D ~NETIF_F_TSO_ECN; > > > > > > /* Software GSO depends on SG. */ > > > - if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) { > > > + if ((features[0] & NETIF_F_GSO) && !(features[0] & NETIF_F_SG= )) { > > > netdev_dbg(dev, "Dropping NETIF_F_GSO since no SG fea= ture.\n"); > > > - features &=3D ~NETIF_F_GSO; > > > + features[0] &=3D ~NETIF_F_GSO; > > > } > > > > > > /* GSO partial features require GSO partial be set */ > > > - if ((features & dev->gso_partial_features) && > > > - !(features & NETIF_F_GSO_PARTIAL)) { > > > + if ((features[0] & dev->gso_partial_features) && > > > + !(features[0] & NETIF_F_GSO_PARTIAL)) { > > > netdev_dbg(dev, > > > "Dropping partially supported GSO features > > > since no GSO partial.\n"); > > > - features &=3D ~dev->gso_partial_features; > > > + features[0] &=3D ~dev->gso_partial_features; > > > } > > > > > > - if (!(features & NETIF_F_RXCSUM)) { > > > + if (!(features[0] & NETIF_F_RXCSUM)) { > > > /* NETIF_F_GRO_HW implies doing RXCSUM since every pa= cket > > > * successfully merged by hardware must also have the > > > * checksum verified by hardware. If the user does n= ot > > > * want to enable RXCSUM, logically, we should disabl= e GRO_HW. > > > */ > > > - if (features & NETIF_F_GRO_HW) { > > > + if (features[0] & NETIF_F_GRO_HW) { > > > netdev_dbg(dev, "Dropping NETIF_F_GRO_HW sinc= e > > > no RXCSUM feature.\n"); > > > - features &=3D ~NETIF_F_GRO_HW; > > > + features[0] &=3D ~NETIF_F_GRO_HW; > > > } > > > } > > > > > > /* LRO/HW-GRO features cannot be combined with RX-FCS */ > > > - if (features & NETIF_F_RXFCS) { > > > - if (features & NETIF_F_LRO) { > > > + if (features[0] & NETIF_F_RXFCS) { > > > + if (features[0] & NETIF_F_LRO) { > > > netdev_dbg(dev, "Dropping LRO feature since > > > RX-FCS is requested.\n"); > > > - features &=3D ~NETIF_F_LRO; > > > + features[0] &=3D ~NETIF_F_LRO; > > > } > > > > > > - if (features & NETIF_F_GRO_HW) { > > > + if (features[0] & NETIF_F_GRO_HW) { > > > netdev_dbg(dev, "Dropping HW-GRO feature sinc= e > > > RX-FCS is requested.\n"); > > > - features &=3D ~NETIF_F_GRO_HW; > > > + features[0] &=3D ~NETIF_F_GRO_HW; > > > } > > > } > > > > > > - if (features & NETIF_F_HW_TLS_TX) { > > > - bool ip_csum =3D (features & (NETIF_F_IP_CSUM | > > > NETIF_F_IPV6_CSUM)) =3D=3D > > > + if (features[0] & NETIF_F_HW_TLS_TX) { > > > + bool ip_csum =3D (features[0] & (NETIF_F_IP_CSUM | > > > NETIF_F_IPV6_CSUM)) =3D=3D > > > (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); > > > - bool hw_csum =3D features & NETIF_F_HW_CSUM; > > > + bool hw_csum =3D features[0] & NETIF_F_HW_CSUM; > > > > > > if (!ip_csum && !hw_csum) { > > > netdev_dbg(dev, "Dropping TLS TX HW offload > > > feature since no CSUM feature.\n"); > > > - features &=3D ~NETIF_F_HW_TLS_TX; > > > + features[0] &=3D ~NETIF_F_HW_TLS_TX; > > > } > > > } > > > > > > - if ((features & NETIF_F_HW_TLS_RX) && !(features & NETIF_F_RX= CSUM)) { > > > + if ((features[0] & NETIF_F_HW_TLS_RX) && > > > + !(features[0] & NETIF_F_RXCSUM)) { > > > netdev_dbg(dev, "Dropping TLS RX HW offload feature > > > since no RXCSUM feature.\n"); > > > - features &=3D ~NETIF_F_HW_TLS_RX; > > > + features[0] &=3D ~NETIF_F_HW_TLS_RX; > > > } > > > - > > > - return features; > > > } > > > > > > int __netdev_update_features(struct net_device *dev) > > > { > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > struct net_device *upper, *lower; > > > - netdev_features_t features; > > > struct list_head *iter; > > > + unsigned int i; > > > int err =3D -1; > > > > > > ASSERT_RTNL(); > > > > > > - features =3D netdev_get_wanted_features(dev); > > > + netdev_get_wanted_features(dev, features); > > > > > > if (dev->netdev_ops->ndo_fix_features) > > > - features =3D dev->netdev_ops->ndo_fix_features(dev, f= eatures); > > > + dev->netdev_ops->ndo_fix_features(dev, features); > > > > > > /* driver might be less strict about feature dependencies */ > > > - features =3D netdev_fix_features(dev, features); > > > + netdev_fix_features(dev, features); > > > > > > /* some features can't be enabled if they're off on an upper = device */ > > > netdev_for_each_upper_dev_rcu(dev, upper, iter) > > > - features =3D netdev_sync_upper_features(dev, upper, f= eatures); > > > + netdev_sync_upper_features(dev, upper, features); > > > > > > - if (dev->features =3D=3D features) > > > + if (netdev_features_equal(dev->features, features)) > > > goto sync_lower; > > > > > > - netdev_dbg(dev, "Features changed: %pNF -> %pNF\n", > > > - &dev->features, &features); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + netdev_dbg(dev, "Features[%u] changed: %pNF -> %pNF\n= ", > > > + i, &dev->features[i], &features[i]); > > > > > > if (dev->netdev_ops->ndo_set_features) > > > err =3D dev->netdev_ops->ndo_set_features(dev, featur= es); > > > @@ -9971,9 +9979,10 @@ int __netdev_update_features(struct net_device= *dev) > > > err =3D 0; > > > > > > if (unlikely(err < 0)) { > > > - netdev_err(dev, > > > - "set_features() failed (%d); wanted %pNF, lef= t %pNF\n", > > > - err, &features, &dev->features); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + netdev_err(dev, > > > + "set_features() failed (%d); > > > wanted[%u] %pNF, left[%u] %pNF\n", > > > + err, i, &features[i], i, &dev->fea= tures[i]); > > > /* return non-0 since some features might have change= d and > > > * it's better to fire a spurious notification than m= iss it > > > */ > > > @@ -9988,9 +9997,10 @@ int __netdev_update_features(struct net_device= *dev) > > > netdev_sync_lower_features(dev, lower, features); > > > > > > if (!err) { > > > - netdev_features_t diff =3D features ^ dev->features; > > > + netdev_features_t diff[NETDEV_FEATURE_DWORDS]; > > > > > > - if (diff & NETIF_F_RX_UDP_TUNNEL_PORT) { > > > + netdev_features_xor(diff, features, dev->features); > > > + if (diff[0] & NETIF_F_RX_UDP_TUNNEL_PORT) { > > > /* udp_tunnel_{get,drop}_rx_info both need > > > * NETIF_F_RX_UDP_TUNNEL_PORT enabled on the > > > * device, or they won't do anything. > > > @@ -9998,33 +10008,33 @@ int __netdev_update_features(struct net_devi= ce *dev) > > > * *before* calling udp_tunnel_get_rx_info, > > > * but *after* calling udp_tunnel_drop_rx_inf= o. > > > */ > > > - if (features & NETIF_F_RX_UDP_TUNNEL_PORT) { > > > - dev->features =3D features; > > > + if (features[0] & NETIF_F_RX_UDP_TUNNEL_PORT)= { > > > + dev->features[0] =3D features[0]; > > > udp_tunnel_get_rx_info(dev); > > > } else { > > > udp_tunnel_drop_rx_info(dev); > > > } > > > } > > > > > > - if (diff & NETIF_F_HW_VLAN_CTAG_FILTER) { > > > - if (features & NETIF_F_HW_VLAN_CTAG_FILTER) { > > > - dev->features =3D features; > > > + if (diff[0] & NETIF_F_HW_VLAN_CTAG_FILTER) { > > > + if (features[0] & NETIF_F_HW_VLAN_CTAG_FILTER= ) { > > > + dev->features[0] =3D features[0]; > > > err |=3D vlan_get_rx_ctag_filter_info= (dev); > > > } else { > > > vlan_drop_rx_ctag_filter_info(dev); > > > } > > > } > > > > > > - if (diff & NETIF_F_HW_VLAN_STAG_FILTER) { > > > + if (diff[0] & NETIF_F_HW_VLAN_STAG_FILTER) { > > > if (features & NETIF_F_HW_VLAN_STAG_FILTER) { > > > - dev->features =3D features; > > > + dev->features[0] =3D features[0]; > > > err |=3D vlan_get_rx_stag_filter_info= (dev); > > > } else { > > > vlan_drop_rx_stag_filter_info(dev); > > > } > > > } > > > > > > - dev->features =3D features; > > > + netdev_features_copy(dev->features, features); > > > } > > > > > > return err < 0 ? 0 : 1; > > > @@ -10213,7 +10223,7 @@ int register_netdevice(struct net_device *dev= ) > > > int ret; > > > struct net *net =3D dev_net(dev); > > > > > > - BUILD_BUG_ON(sizeof(netdev_features_t) * BITS_PER_BYTE < > > > + BUILD_BUG_ON(sizeof(dev->features) * BITS_PER_BYTE < > > > NETDEV_FEATURE_COUNT); > > > BUG_ON(dev_boot_phase); > > > ASSERT_RTNL(); > > > @@ -10250,7 +10260,7 @@ int register_netdevice(struct net_device *dev= ) > > > } > > > } > > > > > > - if (((dev->hw_features | dev->features) & > > > + if (((dev->hw_features[0] | dev->features[0]) & > > > NETIF_F_HW_VLAN_CTAG_FILTER) && > > > (!dev->netdev_ops->ndo_vlan_rx_add_vid || > > > !dev->netdev_ops->ndo_vlan_rx_kill_vid)) { > > > @@ -10268,44 +10278,46 @@ int register_netdevice(struct net_device *d= ev) > > > /* Transfer changeable features to wanted_features and enable > > > * software offloads (GSO and GRO). > > > */ > > > - dev->hw_features |=3D (NETIF_F_SOFT_FEATURES | NETIF_F_SOFT_F= EATURES_OFF); > > > - dev->features |=3D NETIF_F_SOFT_FEATURES; > > > + dev->hw_features[0] |=3D > > > + (NETIF_F_SOFT_FEATURES | NETIF_F_SOFT_FEATURE= S_OFF); > > > + dev->features[0] |=3D NETIF_F_SOFT_FEATURES; > > > > > > if (dev->udp_tunnel_nic_info) { > > > - dev->features |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > - dev->hw_features |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > + dev->features[0] |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > + dev->hw_features[0] |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > } > > > > > > - dev->wanted_features =3D dev->features & dev->hw_features; > > > + netdev_features_and(dev->wanted_features, dev->features, > > > + dev->hw_features); > > > > > > if (!(dev->flags & IFF_LOOPBACK)) > > > - dev->hw_features |=3D NETIF_F_NOCACHE_COPY; > > > + dev->hw_features[0] |=3D NETIF_F_NOCACHE_COPY; > > > > > > /* If IPv4 TCP segmentation offload is supported we should al= so > > > * allow the device to enable segmenting the frame with the o= ption > > > * of ignoring a static IP ID value. This doesn't enable the > > > * feature itself but allows the user to enable it later. > > > */ > > > - if (dev->hw_features & NETIF_F_TSO) > > > - dev->hw_features |=3D NETIF_F_TSO_MANGLEID; > > > - if (dev->vlan_features & NETIF_F_TSO) > > > - dev->vlan_features |=3D NETIF_F_TSO_MANGLEID; > > > - if (dev->mpls_features & NETIF_F_TSO) > > > - dev->mpls_features |=3D NETIF_F_TSO_MANGLEID; > > > - if (dev->hw_enc_features & NETIF_F_TSO) > > > - dev->hw_enc_features |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->hw_features[0] & NETIF_F_TSO) > > > + dev->hw_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->vlan_features[0] & NETIF_F_TSO) > > > + dev->vlan_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->mpls_features[0] & NETIF_F_TSO) > > > + dev->mpls_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->hw_enc_features[0] & NETIF_F_TSO) > > > + dev->hw_enc_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > > > > /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. > > > */ > > > - dev->vlan_features |=3D NETIF_F_HIGHDMA; > > > + dev->vlan_features[0] |=3D NETIF_F_HIGHDMA; > > > > > > /* Make NETIF_F_SG inheritable to tunnel devices. > > > */ > > > - dev->hw_enc_features |=3D NETIF_F_SG | NETIF_F_GSO_PARTIAL; > > > + dev->hw_enc_features[0] |=3D NETIF_F_SG | NETIF_F_GSO_PARTIAL= ; > > > > > > /* Make NETIF_F_SG inheritable to MPLS. > > > */ > > > - dev->mpls_features |=3D NETIF_F_SG; > > > + dev->mpls_features[0] |=3D NETIF_F_SG; > > > > > > ret =3D call_netdevice_notifiers(NETDEV_POST_INIT, dev); > > > ret =3D notifier_to_errno(ret); > > > @@ -11146,7 +11158,7 @@ int __dev_change_net_namespace(struct > > > net_device *dev, struct net *net, > > > > > > /* Don't allow namespace local devices to be moved. */ > > > err =3D -EINVAL; > > > - if (dev->features & NETIF_F_NETNS_LOCAL) > > > + if (dev->features[0] & NETIF_F_NETNS_LOCAL) > > > goto out; > > > > > > /* Ensure the device has been registrered */ > > > @@ -11506,7 +11518,7 @@ static void __net_exit > > > default_device_exit(struct net *net) > > > char fb_name[IFNAMSIZ]; > > > > > > /* Ignore unmoveable devices (i.e. loopback) */ > > > - if (dev->features & NETIF_F_NETNS_LOCAL) > > > + if (dev->features[0] & NETIF_F_NETNS_LOCAL) > > > continue; > > > > > > /* Leave virtual devices for the generic cleanup */ > > > diff --git a/net/core/netpoll.c b/net/core/netpoll.c > > > index 0a6b047..2c0adf4 100644 > > > --- a/net/core/netpoll.c > > > +++ b/net/core/netpoll.c > > > @@ -74,13 +74,13 @@ static netdev_tx_t netpoll_start_xmit(struct sk_b= uff *skb, > > > struct net_device *dev, > > > struct netdev_queue *txq) > > > { > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > netdev_tx_t status =3D NETDEV_TX_OK; > > > - netdev_features_t features; > > > > > > - features =3D netif_skb_features(skb); > > > + netif_skb_features(skb, features); > > > > > > if (skb_vlan_tag_present(skb) && > > > - !vlan_hw_offload_capable(features, skb->vlan_proto)) { > > > + !vlan_hw_offload_capable(features[0], skb->vlan_proto)) { > > > skb =3D __vlan_hwaccel_push_inside(skb); > > > if (unlikely(!skb)) { > > > /* This is actually a packet drop, but we > > > diff --git a/net/ethtool/features.c b/net/ethtool/features.c > > > index 1c9f4df..0eedb17 100644 > > > --- a/net/ethtool/features.c > > > +++ b/net/ethtool/features.c > > > @@ -25,12 +25,13 @@ const struct nla_policy ethnl_features_get_policy= [] =3D { > > > NLA_POLICY_NESTED(ethnl_header_policy), > > > }; > > > > > > -static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t = src) > > > +static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t = *src) > > > { > > > + u32 *__src =3D (u32 *)src; > > > unsigned int i; > > > > > > for (i =3D 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++) > > > - dest[i] =3D src >> (32 * i); > > > + dest[i] =3D __src[i]; > > > } > > > > > > static int features_prepare_data(const struct ethnl_req_info *req_ba= se, > > > @@ -38,15 +39,23 @@ static int features_prepare_data(const struct > > > ethnl_req_info *req_base, > > > struct genl_info *info) > > > { > > > struct features_reply_data *data =3D FEATURES_REPDATA(reply_b= ase); > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS] =3D {0}; > > > struct net_device *dev =3D reply_base->dev; > > > - netdev_features_t all_features; > > > + unsigned int i; > > > > > > ethnl_features_to_bitmap32(data->hw, dev->hw_features); > > > ethnl_features_to_bitmap32(data->wanted, dev->wanted_features= ); > > > ethnl_features_to_bitmap32(data->active, dev->features); > > > - ethnl_features_to_bitmap32(data->nochange, NETIF_F_NEVER_CHAN= GE); > > > - all_features =3D GENMASK_ULL(NETDEV_FEATURE_COUNT - 1, 0); > > > - ethnl_features_to_bitmap32(data->all, all_features); > > > + features[0] =3D NETIF_F_NEVER_CHANGE; > > > + ethnl_features_to_bitmap32(data->nochange, features); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + if (NETDEV_FEATURE_COUNT >=3D (i + 1) * 64) > > > + features[i] =3D GENMASK_ULL(63, 0); > > > + else > > > + features[i] =3D GENMASK_ULL(NETDEV_FEATURE_CO= UNT - i * 64, > > > + 0); > > > + } > > > + ethnl_features_to_bitmap32(data->all, features); > > > > > > return 0; > > > } > > > @@ -131,27 +140,29 @@ const struct nla_policy ethnl_features_set_poli= cy[] =3D { > > > [ETHTOOL_A_FEATURES_WANTED] =3D { .type =3D NLA_NESTED }, > > > }; > > > > > > -static void ethnl_features_to_bitmap(unsigned long *dest, > > > netdev_features_t val) > > > +static void ethnl_features_to_bitmap(unsigned long *dest, > > > + netdev_features_t *val) > > > { > > > const unsigned int words =3D BITS_TO_LONGS(NETDEV_FEATURE_COU= NT); > > > unsigned int i; > > > > > > bitmap_zero(dest, NETDEV_FEATURE_COUNT); > > > for (i =3D 0; i < words; i++) > > > - dest[i] =3D (unsigned long)(val >> (i * BITS_PER_LONG= )); > > > + dest[i] =3D > > > + (unsigned long)(val[i / 2] >> (i % 2 * BITS_P= ER_LONG)); > > > } > > > > > > -static netdev_features_t ethnl_bitmap_to_features(unsigned long *src= ) > > > +static void ethnl_bitmap_to_features(netdev_features_t *val, unsigne= d > > > long *src) > > > { > > > - const unsigned int nft_bits =3D sizeof(netdev_features_t) * B= ITS_PER_BYTE; > > > const unsigned int words =3D BITS_TO_LONGS(NETDEV_FEATURE_COU= NT); > > > - netdev_features_t ret =3D 0; > > > unsigned int i; > > > > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + val[i] =3D 0; > > > + > > > for (i =3D 0; i < words; i++) > > > - ret |=3D (netdev_features_t)(src[i]) << (i * BITS_PER= _LONG); > > > - ret &=3D ~(netdev_features_t)0 >> (nft_bits - NETDEV_FEATURE_= COUNT); > > > - return ret; > > > + val[i / 2] |=3D > > > + (netdev_features_t)(src[i]) << (i % 2 * BITS_= PER_LONG); > > > } > > > > > > static int features_send_reply(struct net_device *dev, struct genl_i= nfo *info, > > > @@ -212,12 +223,14 @@ int ethnl_set_features(struct sk_buff *skb, > > > struct genl_info *info) > > > { > > > DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT); > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(old_wanted, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT); > > > + netdev_features_t tmp[NETDEV_FEATURE_DWORDS]; > > > struct ethnl_req_info req_info =3D {}; > > > struct nlattr **tb =3D info->attrs; > > > struct net_device *dev; > > > @@ -242,7 +255,11 @@ int ethnl_set_features(struct sk_buff *skb, > > > struct genl_info *info) > > > netdev_features_strings, info->extac= k); > > > if (ret < 0) > > > goto out_rtnl; > > > - if (ethnl_bitmap_to_features(req_mask) & ~NETIF_F_ETHTOOL_BIT= S) { > > > + > > > + ethnl_bitmap_to_features(features, req_mask); > > > + netdev_features_ethtool_bits(tmp); > > > + netdev_features_andnot(features, features, tmp); > > > + if (!netdev_features_empty(features)) { > > > GENL_SET_ERR_MSG(info, "attempt to change non-ethtool > > > features"); > > > ret =3D -EINVAL; > > > goto out_rtnl; > > > @@ -253,8 +270,13 @@ int ethnl_set_features(struct sk_buff *skb, > > > struct genl_info *info) > > > bitmap_andnot(new_wanted, old_wanted, req_mask, NETDEV_FEATUR= E_COUNT); > > > bitmap_or(req_wanted, new_wanted, req_wanted, NETDEV_FEATURE_= COUNT); > > > if (!bitmap_equal(req_wanted, old_wanted, NETDEV_FEATURE_COUN= T)) { > > > - dev->wanted_features &=3D ~dev->hw_features; > > > - dev->wanted_features |=3D > > > ethnl_bitmap_to_features(req_wanted) & dev->hw_features; > > > + netdev_features_andnot(dev->wanted_features, > > > + dev->wanted_features, > > > + dev->hw_features); > > > + ethnl_bitmap_to_features(features, req_wanted); > > > + netdev_features_and(features, features, dev->hw_featu= res); > > > + netdev_features_or(dev->wanted_features, dev->wanted_= features, > > > + features); > > > __netdev_update_features(dev); > > > } > > > ethnl_features_to_bitmap(new_active, dev->features); > > > diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c > > > index baa5d10..f213ec9 100644 > > > --- a/net/ethtool/ioctl.c > > > +++ b/net/ethtool/ioctl.c > > > @@ -67,12 +67,15 @@ static int ethtool_get_features(struct net_device > > > *dev, void __user *useraddr) > > > int i; > > > > > > /* in case feature bits run out again */ > > > - BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > > > > sizeof(netdev_features_t)); > > > + BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > > > > sizeof(dev->features)); > > > > > > for (i =3D 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) { > > > - features[i].available =3D (u32)(dev->hw_features >> (= 32 * i)); > > > - features[i].requested =3D (u32)(dev->wanted_features = >> (32 * i)); > > > - features[i].active =3D (u32)(dev->features >> (32 * i= )); > > > + features[i].available =3D > > > + (u32)(dev->hw_features[i / 2] >> (i % 2 * 32)= ); > > > + features[i].requested =3D > > > + (u32)(dev->wanted_features[i / 2] >> (i % 2 *= 32)); > > > + features[i].active =3D > > > + (u32)(dev->features[i / 2] >> (i % 2 * 32)); > > > features[i].never_changed =3D > > > (u32)(NETIF_F_NEVER_CHANGE >> (32 * i)); > > > } > > > @@ -97,7 +100,9 @@ static int ethtool_set_features(struct net_device > > > *dev, void __user *useraddr) > > > { > > > struct ethtool_sfeatures cmd; > > > struct ethtool_set_features_block features[ETHTOOL_DEV_FEATUR= E_WORDS]; > > > - netdev_features_t wanted =3D 0, valid =3D 0; > > > + netdev_features_t wanted[NETDEV_FEATURE_DWORDS] =3D {0}; > > > + netdev_features_t valid[NETDEV_FEATURE_DWORDS] =3D {0}; > > > + netdev_features_t tmp[NETDEV_FEATURE_DWORDS]; > > > int i, ret =3D 0; > > > > > > if (copy_from_user(&cmd, useraddr, sizeof(cmd))) > > > @@ -111,23 +116,33 @@ static int ethtool_set_features(struct > > > net_device *dev, void __user *useraddr) > > > return -EFAULT; > > > > > > for (i =3D 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) { > > > - valid |=3D (netdev_features_t)features[i].valid << (3= 2 * i); > > > - wanted |=3D (netdev_features_t)features[i].requested = << (32 * i); > > > + valid[i / 2] |=3D > > > + (netdev_features_t)features[i].valid << (32 *= i); > > > + wanted[i / 2] |=3D > > > + (netdev_features_t)features[i].requested << (= 32 * i); > > > } > > > > > > - if (valid & ~NETIF_F_ETHTOOL_BITS) > > > + netdev_features_ethtool_bits(tmp); > > > + netdev_features_andnot(tmp, features, tmp); > > > + if (!netdev_features_empty(tmp)) > > > return -EINVAL; > > > > > > - if (valid & ~dev->hw_features) { > > > - valid &=3D dev->hw_features; > > > + netdev_features_andnot(tmp, valid, dev->hw_features); > > > + > > > + if (!netdev_features_empty(tmp)) { > > > + netdev_features_and(valid, valid, dev->hw_features); > > > ret |=3D ETHTOOL_F_UNSUPPORTED; > > > } > > > > > > - dev->wanted_features &=3D ~valid; > > > - dev->wanted_features |=3D wanted & valid; > > > + netdev_features_andnot(dev->wanted_features, dev->wanted_feat= ures, > > > + valid); > > > + netdev_features_and(wanted, wanted, valid); > > > + netdev_features_or(dev->wanted_features, dev->wanted_features= , wanted); > > > __netdev_update_features(dev); > > > > > > - if ((dev->wanted_features ^ dev->features) & valid) > > > + netdev_features_xor(tmp, dev->wanted_features, dev->features)= ; > > > + netdev_features_and(tmp, tmp, valid); > > > + if (!netdev_features_empty(tmp)) > > > ret |=3D ETHTOOL_F_WISH; > > > > > > return ret; > > > @@ -227,7 +242,7 @@ static int ethtool_get_one_feature(struct net_dev= ice *dev, > > > netdev_features_t mask =3D ethtool_get_feature_mask(ethcmd); > > > struct ethtool_value edata =3D { > > > .cmd =3D ethcmd, > > > - .data =3D !!(dev->features & mask), > > > + .data =3D !!(dev->features[0] & mask), > > > }; > > > > > > if (copy_to_user(useraddr, &edata, sizeof(edata))) > > > @@ -238,21 +253,23 @@ static int ethtool_get_one_feature(struct net_d= evice *dev, > > > static int ethtool_set_one_feature(struct net_device *dev, > > > void __user *useraddr, u32 ethcmd) > > > { > > > + netdev_features_t mask[NETDEV_FEATURE_DWORDS] =3D {0}; > > > struct ethtool_value edata; > > > - netdev_features_t mask; > > > > > > if (copy_from_user(&edata, useraddr, sizeof(edata))) > > > return -EFAULT; > > > > > > - mask =3D ethtool_get_feature_mask(ethcmd); > > > - mask &=3D dev->hw_features; > > > - if (!mask) > > > + mask[0] =3D ethtool_get_feature_mask(ethcmd); > > > + netdev_features_and(mask, mask, dev->hw_features); > > > + if (netdev_features_empty(mask)) > > > return -EOPNOTSUPP; > > > > > > if (edata.data) > > > - dev->wanted_features |=3D mask; > > > + netdev_features_or(dev->wanted_features, dev->wanted_= features, > > > + mask) > > > else > > > - dev->wanted_features &=3D ~mask; > > > + netdev_features_andnot(dev->wanted_features, > > > + dev->wanted_features, mask); > > > > > > __netdev_update_features(dev); > > > > > > @@ -285,29 +302,37 @@ static u32 __ethtool_get_flags(struct net_devic= e *dev) > > > > > > static int __ethtool_set_flags(struct net_device *dev, u32 data) > > > { > > > - netdev_features_t features =3D 0, changed; > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS] =3D {0}; > > > + netdev_features_t changed[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t tmp[NETDEV_FEATURE_DWORDS]; > > > > > > if (data & ~ETH_ALL_FLAGS) > > > return -EINVAL; > > > > > > if (data & ETH_FLAG_LRO) > > > - features |=3D NETIF_F_LRO; > > > + features[0] |=3D NETIF_F_LRO; > > > if (data & ETH_FLAG_RXVLAN) > > > - features |=3D NETIF_F_HW_VLAN_CTAG_RX; > > > + features[0] |=3D NETIF_F_HW_VLAN_CTAG_RX; > > > if (data & ETH_FLAG_TXVLAN) > > > - features |=3D NETIF_F_HW_VLAN_CTAG_TX; > > > + features[0] |=3D NETIF_F_HW_VLAN_CTAG_TX; > > > if (data & ETH_FLAG_NTUPLE) > > > - features |=3D NETIF_F_NTUPLE; > > > + features[0] |=3D NETIF_F_NTUPLE; > > > if (data & ETH_FLAG_RXHASH) > > > - features |=3D NETIF_F_RXHASH; > > > + features[0] |=3D NETIF_F_RXHASH; > > > > > > /* allow changing only bits set in hw_features */ > > > - changed =3D (features ^ dev->features) & ETH_ALL_FEATURES; > > > - if (changed & ~dev->hw_features) > > > - return (changed & dev->hw_features) ? -EINVAL : -EOPN= OTSUPP; > > > + netdev_features_xor(changed, features, dev->features); > > > + changed[0] &=3D ETH_ALL_FEATURES; > > > + > > > + netdev_features_andnot(tmp, changed, dev->hw_features); > > > + if (!netdev_features_empty(tmp)) { > > > + netdev_features_and(tmp, changed, dev->hw_features); > > > + return (!netdev_features_empty(tmp)) ? -EINVAL : -EOP= NOTSUPP; > > > + } > > > > > > - dev->wanted_features =3D > > > - (dev->wanted_features & ~changed) | (features & chang= ed); > > > + netdev_features_andnot(tmp, dev->wanted_features, changed); > > > + netdev_features_and(features, features, changed); > > > + netdev_features_or(dev->wanted_features, tmp, features); > > > > > > __netdev_update_features(dev); > > > > > > @@ -2587,7 +2612,7 @@ int dev_ethtool(struct net *net, struct ifreq *= ifr) > > > void __user *useraddr =3D ifr->ifr_data; > > > u32 ethcmd, sub_cmd; > > > int rc; > > > - netdev_features_t old_features; > > > + netdev_features_t old_features[NETDEV_FEATURE_DWORDS]; > > > > > > if (!dev || !netif_device_present(dev)) > > > return -ENODEV; > > > @@ -2650,7 +2675,7 @@ int dev_ethtool(struct net *net, struct ifreq *= ifr) > > > if (rc < 0) > > > return rc; > > > } > > > - old_features =3D dev->features; > > > + netdev_features_copy(old_features, dev->features); > > > > > > switch (ethcmd) { > > > case ETHTOOL_GSET: > > > @@ -2865,7 +2890,7 @@ int dev_ethtool(struct net *net, struct ifreq *= ifr) > > > if (dev->ethtool_ops->complete) > > > dev->ethtool_ops->complete(dev); > > > > > > - if (old_features !=3D dev->features) > > > + if (!netdev_features_equal(old_features, dev->features)) > > > netdev_features_change(dev); > > > > > > return rc; > > > -- > > > 2.8.1 > > > > > > > > > > > > -- > > > Latest Podcast: > > > https://www.linkedin.com/feed/update/urn:li:activity:6791014284936785= 920/ > > > > > > Dave T=C3=A4ht CTO, TekLibre, LLC > > > _______________________________________________ > > > Cake mailing list > > > Cake@lists.bufferbloat.net > > > https://lists.bufferbloat.net/listinfo/cake > > > > > > > > -- > > Robert Chac=C3=B3n > > robert.chacon@jackrabbitwireless.com > > > > -- > Latest Podcast: > https://www.linkedin.com/feed/update/urn:li:activity:6791014284936785920/ > > Dave T=C3=A4ht CTO, TekLibre, LLC On Sat, Jul 10, 2021 at 1:43 PM Dave Taht wrote: > > can I encourage you to try cake with it's integral shaper instead of htb? > > or htb + cake diffserv4 ack-filter? (I've settled on that to optimize > even better for marked videoconferencing traffic. > facetime, in particular, does not handle loss well) > > > On Sat, Jul 10, 2021 at 10:00 AM Robert Chac=C3=B3n > wrote: > > > > I have a question regarding this, and the current maximum number of htb= leaf classes and/or qdiscs per interface. > > I recently integrated Jesper's xdp-cpumap-tc code into LibreQoS, which = increased throughput to 10Gbps on tests. > > I suspect somewhere between 10Gbps and 40Gbps throughput is now possibl= e if you throw enough cores at it. Asking our local university to help us t= est this. > > Xdp-cpumap-tc uses xdp's cpumap-redirect feature to filter packets into= the appropriate CPU / queue using eBPF hash maps, rather than linux tc fil= ters / u32. > > > > Question) Since LibreQoS would not depend on tc filters, would the curr= ent 32-bit or 64-bit feature limit impose a practical client limit on Libre= QoS? > > The average user's throughput is around 3.5Mbps at peak hours, so I'm t= hinking ~5800 qdiscs and ~5800 htb leaf classes would be required for each = interface at 20Gbps throughput for example. > > There may be some more immediate limitations I'm not understanding. Jus= t curious about the practical limitations there. > > > > Thanks! > > Robert > > > > On Sat, Jul 10, 2021 at 9:33 AM Dave Taht wrote: > > > > > > One thing somewhat related to this was finally expanding the space > > > available for the tc and iptables functionality for > > > things like hashing and actions etc from 16 bits to 32. That is > > > something of a fork lift upgrade, but... 64k queues is not > > > enough in some cases, nor is 64k possible users in libreqos. thoughts > > > > > > ---------- Forwarded message --------- > > > From: Jian Shen > > > Date: Sat, Jul 10, 2021 at 2:47 AM > > > Subject: [RFC net-next] net: extend netdev features > > > To: , > > > Cc: , > > > > > > > > > For the prototype of netdev_features_t is u64, and the number > > > of netdevice feature bits is 64 now. So there is no space to > > > introduce new feature bit. > > > > > > I did a small change for this. Keep the prototype of > > > netdev_feature_t, and extend the feature members in struct > > > net_device to an array of netdev_features_t. So more features > > > bits can be used. > > > > > > As this change, some functions which use netdev_features_t as > > > parameter or returen value will be affected. > > > I did below changes: > > > a. parameter: "netdev_features_t" to "netdev_features_t *" > > > b. return value: "netdev_feature_t" to "void", and add > > > "netdev_feature_t *" as output parameter. > > > > > > I kept some functions no change, which are surely useing the > > > first 64 bit of net device features now, such as function > > > nedev_add_tso_features(). In order to minimize to changes. > > > > > > For the features are array now, so it's unable to do logical > > > operation directly. I introduce a inline function set for > > > them, including "netdev_features_and/andnot/or/xor/equal/empty". > > > > > > For NETDEV_FEATURE_COUNT may be more than 64, so the shift > > > operation for NETDEV_FEATURE_COUNT is illegal. I changed some > > > macroes and functions, which does shift opertion with it. > > > > > > I haven't finished all the changes, for it affected all the > > > drivers which use the feature, need more time and test. I > > > sent this RFC patch, want to know whether this change is > > > acceptable, and how to improve it. > > > > > > Any comments will be helpful. > > > > > > Signed-off-by: Jian Shen > > > --- > > > drivers/net/ethernet/hisilicon/hns/hns_enet.c | 34 +-- > > > drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 97 ++++----- > > > drivers/net/ethernet/huawei/hinic/hinic_main.c | 71 +++--- > > > drivers/net/ethernet/huawei/hinic/hinic_rx.c | 4 +- > > > include/linux/if_vlan.h | 2 +- > > > include/linux/netdev_features.h | 105 ++++++++- > > > include/linux/netdevice.h | 31 +-- > > > net/8021q/vlan.c | 4 +- > > > net/8021q/vlan.h | 2 +- > > > net/8021q/vlan_dev.c | 49 +++-- > > > net/core/dev.c | 276 ++++++++++++--= ---------- > > > net/core/netpoll.c | 6 +- > > > net/ethtool/features.c | 56 +++-- > > > net/ethtool/ioctl.c | 93 +++++--- > > > 14 files changed, 493 insertions(+), 337 deletions(-) > > > > > > diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > b/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > index ad534f9..4f245cf 100644 > > > --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c > > > @@ -479,7 +479,7 @@ static void hns_nic_rx_checksum(struct > > > hns_nic_ring_data *ring_data, > > > u32 l4id; > > > > > > /* check if RX checksum offload is enabled */ > > > - if (unlikely(!(netdev->features & NETIF_F_RXCSUM))) > > > + if (unlikely(!(netdev->features[0] & NETIF_F_RXCSUM))) > > > return; > > > > > > /* In hardware, we only support checksum for the following pr= otocols: > > > @@ -1768,17 +1768,17 @@ static int hns_nic_change_mtu(struct > > > net_device *ndev, int new_mtu) > > > } > > > > > > static int hns_nic_set_features(struct net_device *netdev, > > > - netdev_features_t features) > > > + netdev_features_t *features) > > > { > > > struct hns_nic_priv *priv =3D netdev_priv(netdev); > > > > > > switch (priv->enet_ver) { > > > case AE_VERSION_1: > > > - if (features & (NETIF_F_TSO | NETIF_F_TSO6)) > > > + if (features[0] & (NETIF_F_TSO | NETIF_F_TSO6)) > > > netdev_info(netdev, "enet v1 do not support t= so!\n"); > > > break; > > > default: > > > - if (features & (NETIF_F_TSO | NETIF_F_TSO6)) { > > > + if (features[0] & (NETIF_F_TSO | NETIF_F_TSO6)) { > > > priv->ops.fill_desc =3D fill_tso_desc; > > > priv->ops.maybe_stop_tx =3D hns_nic_maybe_sto= p_tso; > > > /* The chip only support 7*4096 */ > > > @@ -1789,24 +1789,23 @@ static int hns_nic_set_features(struct > > > net_device *netdev, > > > } > > > break; > > > } > > > - netdev->features =3D features; > > > + netdev->features[0] =3D features[0]; > > > return 0; > > > } > > > > > > -static netdev_features_t hns_nic_fix_features( > > > - struct net_device *netdev, netdev_features_t features= ) > > > +static void hns_nic_fix_features(struct net_device *netdev, > > > + netdev_features_t *features) > > > { > > > struct hns_nic_priv *priv =3D netdev_priv(netdev); > > > > > > switch (priv->enet_ver) { > > > case AE_VERSION_1: > > > - features &=3D ~(NETIF_F_TSO | NETIF_F_TSO6 | > > > + features[0] &=3D ~(NETIF_F_TSO | NETIF_F_TSO6 | > > > NETIF_F_HW_VLAN_CTAG_FILTER); > > > break; > > > default: > > > break; > > > } > > > - return features; > > > } > > > > > > static int hns_nic_uc_sync(struct net_device *netdev, const unsigned > > > char *addr) > > > @@ -2163,8 +2162,8 @@ static void hns_nic_set_priv_ops(struct > > > net_device *netdev) > > > priv->ops.maybe_stop_tx =3D hns_nic_maybe_stop_tx; > > > } else { > > > priv->ops.get_rxd_bnum =3D get_v2rx_desc_bnum; > > > - if ((netdev->features & NETIF_F_TSO) || > > > - (netdev->features & NETIF_F_TSO6)) { > > > + if ((netdev->features[0] & NETIF_F_TSO) || > > > + (netdev->features[0] & NETIF_F_TSO6)) { > > > priv->ops.fill_desc =3D fill_tso_desc; > > > priv->ops.maybe_stop_tx =3D hns_nic_maybe_sto= p_tso; > > > /* This chip only support 7*4096 */ > > > @@ -2325,22 +2324,23 @@ static int hns_nic_dev_probe(struct > > > platform_device *pdev) > > > ndev->netdev_ops =3D &hns_nic_netdev_ops; > > > hns_ethtool_set_ops(ndev); > > > > > > - ndev->features |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | > > > + ndev->features[0] |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO; > > > - ndev->vlan_features |=3D > > > + ndev->vlan_features[0] |=3D > > > NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; > > > - ndev->vlan_features |=3D NETIF_F_SG | NETIF_F_GSO | NETIF_F_G= RO; > > > + ndev->vlan_features[0] |=3D NETIF_F_SG | NETIF_F_GSO | NETIF_= F_GRO; > > > > > > /* MTU range: 68 - 9578 (v1) or 9706 (v2) */ > > > ndev->min_mtu =3D MAC_MIN_MTU; > > > switch (priv->enet_ver) { > > > case AE_VERSION_2: > > > - ndev->features |=3D NETIF_F_TSO | NETIF_F_TSO6 | NETI= F_F_NTUPLE; > > > - ndev->hw_features |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6= _CSUM | > > > + ndev->features[0] |=3D > > > + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_= NTUPLE; > > > + ndev->hw_features[0] |=3D NETIF_F_IP_CSUM | NETIF_F_I= PV6_CSUM | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6; > > > - ndev->vlan_features |=3D NETIF_F_TSO | NETIF_F_TSO6; > > > + ndev->vlan_features[0] |=3D NETIF_F_TSO | NETIF_F_TSO= 6; > > > ndev->max_mtu =3D MAC_MAX_MTU_V2 - > > > (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); > > > break; > > > diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > index cdb5f14..ba56907 100644 > > > --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c > > > @@ -1481,7 +1481,7 @@ static int hns3_handle_vtags(struct > > > hns3_enet_ring *tx_ring, > > > return -EINVAL; > > > > > > if (skb->protocol =3D=3D htons(ETH_P_8021Q) && > > > - !(handle->kinfo.netdev->features & NETIF_F_HW_VLAN_CTAG_T= X)) { > > > + !(handle->kinfo.netdev->features[0] & NETIF_F_HW_VLAN_CTA= G_TX)) { > > > /* When HW VLAN acceleration is turned off, and the s= tack > > > * sets the protocol to 802.1q, the driver just need = to > > > * set the protocol to the encapsulated ethertype. > > > @@ -2300,56 +2300,57 @@ static int hns3_nic_do_ioctl(struct net_devic= e *netdev, > > > } > > > > > > static int hns3_nic_set_features(struct net_device *netdev, > > > - netdev_features_t features) > > > + netdev_features_t *features) > > > { > > > - netdev_features_t changed =3D netdev->features ^ features; > > > + netdev_features_t changed[NETDEV_FEATURE_DWORDS]; > > > struct hns3_nic_priv *priv =3D netdev_priv(netdev); > > > struct hnae3_handle *h =3D priv->ae_handle; > > > bool enable; > > > int ret; > > > > > > - if (changed & (NETIF_F_GRO_HW) && h->ae_algo->ops->set_gro_en= ) { > > > - enable =3D !!(features & NETIF_F_GRO_HW); > > > + netdev_features_xor(changed, netdev->features, features); > > > + if (changed[0] & (NETIF_F_GRO_HW) && h->ae_algo->ops->set_gro= _en) { > > > + enable =3D !!(features[0] & NETIF_F_GRO_HW); > > > ret =3D h->ae_algo->ops->set_gro_en(h, enable); > > > if (ret) > > > return ret; > > > } > > > > > > - if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && > > > + if ((changed[0] & NETIF_F_HW_VLAN_CTAG_RX) && > > > h->ae_algo->ops->enable_hw_strip_rxvtag) { > > > - enable =3D !!(features & NETIF_F_HW_VLAN_CTAG_RX); > > > + enable =3D !!(features[0] & NETIF_F_HW_VLAN_CTAG_RX); > > > ret =3D h->ae_algo->ops->enable_hw_strip_rxvtag(h, en= able); > > > if (ret) > > > return ret; > > > } > > > > > > - if ((changed & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_fd)= { > > > - enable =3D !!(features & NETIF_F_NTUPLE); > > > + if ((changed[0] & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_= fd) { > > > + enable =3D !!(features[0] & NETIF_F_NTUPLE); > > > h->ae_algo->ops->enable_fd(h, enable); > > > } > > > > > > - if ((netdev->features & NETIF_F_HW_TC) > (features & NETIF_F_= HW_TC) && > > > + if ((netdev->features[0] & NETIF_F_HW_TC) > > > > + (features[0] & NETIF_F_HW_TC) && > > > h->ae_algo->ops->cls_flower_active(h)) { > > > netdev_err(netdev, > > > "there are offloaded TC filters active, > > > cannot disable HW TC offload"); > > > return -EINVAL; > > > } > > > > > > - if ((changed & NETIF_F_HW_VLAN_CTAG_FILTER) && > > > + if ((changed[0] & NETIF_F_HW_VLAN_CTAG_FILTER) && > > > h->ae_algo->ops->enable_vlan_filter) { > > > - enable =3D !!(features & NETIF_F_HW_VLAN_CTAG_FILTER)= ; > > > + enable =3D !!(features[0] & NETIF_F_HW_VLAN_CTAG_FILT= ER); > > > ret =3D h->ae_algo->ops->enable_vlan_filter(h, enable= ); > > > if (ret) > > > return ret; > > > } > > > > > > - netdev->features =3D features; > > > + netdev_features_copy(netdev->features, features); > > > return 0; > > > } > > > > > > -static netdev_features_t hns3_features_check(struct sk_buff *skb, > > > - struct net_device *dev, > > > - netdev_features_t featur= es) > > > +static void hns3_features_check(struct sk_buff *skb, struct net_devi= ce *dev, > > > + netdev_features_t *features) > > > { > > > #define HNS3_MAX_HDR_LEN 480U > > > #define HNS3_MAX_L4_HDR_LEN 60U > > > @@ -2373,9 +2374,7 @@ static netdev_features_t > > > hns3_features_check(struct sk_buff *skb, > > > * len of 480 bytes. > > > */ > > > if (len > HNS3_MAX_HDR_LEN) > > > - features &=3D ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK)= ; > > > - > > > - return features; > > > + features[0] &=3D ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MA= SK); > > > } > > > > > > static void hns3_nic_get_stats64(struct net_device *netdev, > > > @@ -3127,27 +3126,28 @@ static void hns3_set_default_feature(struct > > > net_device *netdev) > > > > > > netdev->priv_flags |=3D IFF_UNICAST_FLT; > > > > > > - netdev->hw_enc_features |=3D NETIF_F_RXCSUM | NETIF_F_SG | NE= TIF_F_GSO | > > > + netdev->hw_enc_features[0] |=3D > > > + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GS= O_GRE | > > > NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_SCTP_CRC | NETIF_F_TSO_MANGLEID | NETIF_F_FRA= GLIST; > > > > > > netdev->gso_partial_features |=3D NETIF_F_GSO_GRE_CSUM; > > > > > > - netdev->features |=3D NETIF_F_HW_VLAN_CTAG_FILTER | > > > + netdev->features[0] |=3D NETIF_F_HW_VLAN_CTAG_FILTER | > > > NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GS= O_GRE | > > > NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_SCTP_CRC | NETIF_F_FRAGLIST; > > > > > > - netdev->vlan_features |=3D NETIF_F_RXCSUM | > > > + netdev->vlan_features[0] |=3D NETIF_F_RXCSUM | > > > NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | > > > NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | > > > NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_SCTP_CRC | NETIF_F_FRAGLIST; > > > > > > - netdev->hw_features |=3D NETIF_F_HW_VLAN_CTAG_TX | > > > + netdev->hw_features[0] |=3D NETIF_F_HW_VLAN_CTAG_TX | > > > NETIF_F_HW_VLAN_CTAG_RX | > > > NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | > > > NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GS= O_GRE | > > > @@ -3155,48 +3155,49 @@ static void hns3_set_default_feature(struct > > > net_device *netdev) > > > NETIF_F_SCTP_CRC | NETIF_F_FRAGLIST; > > > > > > if (ae_dev->dev_version >=3D HNAE3_DEVICE_VERSION_V2) { > > > - netdev->hw_features |=3D NETIF_F_GRO_HW; > > > - netdev->features |=3D NETIF_F_GRO_HW; > > > + netdev->hw_features[0] |=3D NETIF_F_GRO_HW; > > > + netdev->features[0] |=3D NETIF_F_GRO_HW; > > > > > > if (!(h->flags & HNAE3_SUPPORT_VF)) { > > > - netdev->hw_features |=3D NETIF_F_NTUPLE; > > > - netdev->features |=3D NETIF_F_NTUPLE; > > > + netdev->hw_features[0] |=3D NETIF_F_NTUPLE; > > > + netdev->features[0] |=3D NETIF_F_NTUPLE; > > > } > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_UDP_GSO_B, ae_dev->caps)) { > > > - netdev->hw_features |=3D NETIF_F_GSO_UDP_L4; > > > - netdev->features |=3D NETIF_F_GSO_UDP_L4; > > > - netdev->vlan_features |=3D NETIF_F_GSO_UDP_L4; > > > - netdev->hw_enc_features |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->hw_features[0] |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->features[0] |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->vlan_features[0] |=3D NETIF_F_GSO_UDP_L4; > > > + netdev->hw_enc_features[0] |=3D NETIF_F_GSO_UDP_L4; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_HW_TX_CSUM_B, ae_dev->caps)) { > > > - netdev->hw_features |=3D NETIF_F_HW_CSUM; > > > - netdev->features |=3D NETIF_F_HW_CSUM; > > > - netdev->vlan_features |=3D NETIF_F_HW_CSUM; > > > - netdev->hw_enc_features |=3D NETIF_F_HW_CSUM; > > > + netdev->hw_features[0] |=3D NETIF_F_HW_CSUM; > > > + netdev->features[0] |=3D NETIF_F_HW_CSUM; > > > + netdev->vlan_features[0] |=3D NETIF_F_HW_CSUM; > > > + netdev->hw_enc_features[0] |=3D NETIF_F_HW_CSUM; > > > } else { > > > - netdev->hw_features |=3D NETIF_F_IP_CSUM | NETIF_F_IP= V6_CSUM; > > > - netdev->features |=3D NETIF_F_IP_CSUM | NETIF_F_IPV6_= CSUM; > > > - netdev->vlan_features |=3D NETIF_F_IP_CSUM | NETIF_F_= IPV6_CSUM; > > > - netdev->hw_enc_features |=3D NETIF_F_IP_CSUM | NETIF_= F_IPV6_CSUM; > > > + netdev->hw_features[0] |=3D NETIF_F_IP_CSUM | NETIF_F= _IPV6_CSUM; > > > + netdev->features[0] |=3D NETIF_F_IP_CSUM | NETIF_F_IP= V6_CSUM; > > > + netdev->vlan_features[0] |=3D NETIF_F_IP_CSUM | NETIF= _F_IPV6_CSUM; > > > + netdev->hw_enc_features[0] |=3D > > > + NETIF_F_IP_CSUM | NETIF_F_IPV= 6_CSUM; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B, ae_dev->cap= s)) { > > > - netdev->hw_features |=3D NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > - netdev->features |=3D NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > - netdev->vlan_features |=3D NETIF_F_GSO_UDP_TUNNEL_CSU= M; > > > - netdev->hw_enc_features |=3D NETIF_F_GSO_UDP_TUNNEL_C= SUM; > > > + netdev->hw_features[0] |=3D NETIF_F_GSO_UDP_TUNNEL_CS= UM; > > > + netdev->features[0] |=3D NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > + netdev->vlan_features[0] |=3D NETIF_F_GSO_UDP_TUNNEL_= CSUM; > > > + netdev->hw_enc_features[0] |=3D NETIF_F_GSO_UDP_TUNNE= L_CSUM; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B, ae_dev->caps)= ) { > > > - netdev->hw_features |=3D NETIF_F_HW_TC; > > > - netdev->features |=3D NETIF_F_HW_TC; > > > + netdev->hw_features[0] |=3D NETIF_F_HW_TC; > > > + netdev->features[0] |=3D NETIF_F_HW_TC; > > > } > > > > > > if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps)= ) > > > - netdev->hw_features |=3D NETIF_F_HW_VLAN_CTAG_FILTER; > > > + netdev->hw_features[0] |=3D NETIF_F_HW_VLAN_CTAG_FILT= ER; > > > } > > > > > > static int hns3_alloc_buffer(struct hns3_enet_ring *ring, > > > @@ -3727,7 +3728,7 @@ static void hns3_rx_checksum(struct > > > hns3_enet_ring *ring, struct sk_buff *skb, > > > > > > skb_checksum_none_assert(skb); > > > > > > - if (!(netdev->features & NETIF_F_RXCSUM)) > > > + if (!(netdev->features[0] & NETIF_F_RXCSUM)) > > > return; > > > > > > if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->sta= te)) > > > @@ -4024,7 +4025,7 @@ static int hns3_handle_bdinfo(struct > > > hns3_enet_ring *ring, struct sk_buff *skb) > > > * ot_vlan_tag in two layer tag case, and stored at vlan_tag > > > * in one layer tag case. > > > */ > > > - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { > > > + if (netdev->features[0] & NETIF_F_HW_VLAN_CTAG_RX) { > > > u16 vlan_tag; > > > > > > if (hns3_parse_vlan_tag(ring, desc, l234info, &vlan_t= ag)) > > > diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > b/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > index 405ee4d..b193ee4 100644 > > > --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c > > > @@ -79,8 +79,8 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for > > > NAPI budget (default=3D64)"); > > > static int change_mac_addr(struct net_device *netdev, const u8 *addr= ); > > > > > > static int set_features(struct hinic_dev *nic_dev, > > > - netdev_features_t pre_features, > > > - netdev_features_t features, bool force_change= ); > > > + netdev_features_t *pre_features, > > > + netdev_features_t *features, bool force_chang= e); > > > > > > static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_= rxq *rxq) > > > { > > > @@ -880,7 +880,7 @@ static void hinic_get_stats64(struct net_device *= netdev, > > > } > > > > > > static int hinic_set_features(struct net_device *netdev, > > > - netdev_features_t features) > > > + netdev_features_t *features) > > > { > > > struct hinic_dev *nic_dev =3D netdev_priv(netdev); > > > > > > @@ -888,18 +888,16 @@ static int hinic_set_features(struct net_device= *netdev, > > > features, false); > > > } > > > > > > -static netdev_features_t hinic_fix_features(struct net_device *netde= v, > > > - netdev_features_t feature= s) > > > +static void hinic_fix_features(struct net_device *netdev, > > > + netdev_features_t features) > > > { > > > struct hinic_dev *nic_dev =3D netdev_priv(netdev); > > > > > > /* If Rx checksum is disabled, then LRO should also be disabl= ed */ > > > - if (!(features & NETIF_F_RXCSUM)) { > > > + if (!(features[0] & NETIF_F_RXCSUM)) { > > > netif_info(nic_dev, drv, netdev, "disabling LRO as > > > RXCSUM is off\n"); > > > - features &=3D ~NETIF_F_LRO; > > > + features[0] &=3D ~NETIF_F_LRO; > > > } > > > - > > > - return features; > > > } > > > > > > static const struct net_device_ops hinic_netdev_ops =3D { > > > @@ -943,19 +941,22 @@ static const struct net_device_ops hinicvf_netd= ev_ops =3D { > > > > > > static void netdev_features_init(struct net_device *netdev) > > > { > > > - netdev->hw_features =3D NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_= F_IP_CSUM | > > > - NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF= _F_TSO6 | > > > - NETIF_F_RXCSUM | NETIF_F_LRO | > > > - NETIF_F_HW_VLAN_CTAG_TX | > > > NETIF_F_HW_VLAN_CTAG_RX | > > > - NETIF_F_GSO_UDP_TUNNEL | > > > NETIF_F_GSO_UDP_TUNNEL_CSUM; > > > - > > > - netdev->vlan_features =3D netdev->hw_features; > > > - > > > - netdev->features =3D netdev->hw_features | NETIF_F_HW_VLAN_CT= AG_FILTER; > > > - > > > - netdev->hw_enc_features =3D NETIF_F_IP_CSUM | NETIF_F_IPV6_CS= UM > > > | NETIF_F_SCTP_CRC | > > > - NETIF_F_SG | NETIF_F_TSO | > > > NETIF_F_TSO6 | NETIF_F_TSO_ECN | > > > - NETIF_F_GSO_UDP_TUNNEL_CSUM | > > > NETIF_F_GSO_UDP_TUNNEL; > > > + netdev->hw_features[0] =3D > > > + NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSU= M | > > > + NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO= 6 | > > > + NETIF_F_RXCSUM | NETIF_F_LRO | > > > + NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTA= G_RX | > > > + NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNN= EL_CSUM; > > > + > > > + netdev_features_copy(netdev->vlan_features, netdev->hw_featur= es); > > > + > > > + netdev->features[0] =3D > > > + netdev->hw_features[0] | NETIF_F_HW_VLAN_CTAG= _FILTER; > > > + > > > + netdev->hw_enc_features[0] =3D > > > + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SCTP_CR= C | > > > + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO= _ECN | > > > + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_UDP_TUNNEL; > > > } > > > > > > static void hinic_refresh_nic_cfg(struct hinic_dev *nic_dev) > > > @@ -1072,21 +1073,22 @@ static void link_err_event(void *handle, > > > } > > > > > > static int set_features(struct hinic_dev *nic_dev, > > > - netdev_features_t pre_features, > > > - netdev_features_t features, bool force_change= ) > > > + netdev_features_t *pre_features, > > > + netdev_features_t *features, bool force_chang= e) > > > { > > > - netdev_features_t changed =3D force_change ? ~0 : pre_feature= s ^ features; > > > + netdev_features_t failed_features[NETDEV_FEATURE_DWORDS] =3D = {0}; > > > u32 csum_en =3D HINIC_RX_CSUM_OFFLOAD_EN; > > > - netdev_features_t failed_features =3D 0; > > > + netdev_features_t changed; > > > int ret =3D 0; > > > int err =3D 0; > > > > > > + changed =3D force_change ? ~0 : pre_features[0] ^ features[0]= ; > > > if (changed & NETIF_F_TSO) { > > > - ret =3D hinic_port_set_tso(nic_dev, (features & NETIF= _F_TSO) ? > > > + ret =3D hinic_port_set_tso(nic_dev, (features[0] & NE= TIF_F_TSO) ? > > > HINIC_TSO_ENABLE : HINIC_TSO= _DISABLE); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_TSO; > > > + failed_features[0] |=3D NETIF_F_TSO; > > > } > > > } > > > > > > @@ -1094,33 +1096,34 @@ static int set_features(struct hinic_dev *nic= _dev, > > > ret =3D hinic_set_rx_csum_offload(nic_dev, csum_en); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_RXCSUM; > > > + failed_features[0] |=3D NETIF_F_RXCSUM; > > > } > > > } > > > > > > if (changed & NETIF_F_LRO) { > > > ret =3D hinic_set_rx_lro_state(nic_dev, > > > - !!(features & NETIF_F_LR= O), > > > + !!(features[0] & NETIF_F= _LRO), > > > HINIC_LRO_RX_TIMER_DEFAU= LT, > > > HINIC_LRO_MAX_WQE_NUM_DE= FAULT); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_LRO; > > > + failed_features[0] |=3D NETIF_F_LRO; > > > } > > > } > > > > > > if (changed & NETIF_F_HW_VLAN_CTAG_RX) { > > > ret =3D hinic_set_rx_vlan_offload(nic_dev, > > > - !!(features & > > > + !!(features[0] & > > > NETIF_F_HW_VLAN_CT= AG_RX)); > > > if (ret) { > > > err =3D ret; > > > - failed_features |=3D NETIF_F_HW_VLAN_CTAG_RX; > > > + failed_features[0] |=3D NETIF_F_HW_VLAN_CTAG_= RX; > > > } > > > } > > > > > > if (err) { > > > - nic_dev->netdev->features =3D features ^ failed_featu= res; > > > + netdev_features_xor(nic_dev->netdev->features, featur= es, > > > + failed_features) > > > return -EIO; > > > } > > > > > > diff --git a/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > b/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > index fed3b6b..452a91b 100644 > > > --- a/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > +++ b/drivers/net/ethernet/huawei/hinic/hinic_rx.c > > > @@ -106,7 +106,7 @@ static void rx_csum(struct hinic_rxq *rxq, u32 st= atus, > > > > > > csum_err =3D HINIC_RQ_CQE_STATUS_GET(status, CSUM_ERR); > > > > > > - if (!(netdev->features & NETIF_F_RXCSUM)) > > > + if (!(netdev->features[0] & NETIF_F_RXCSUM)) > > > return; > > > > > > if (!csum_err) { > > > @@ -411,7 +411,7 @@ static int rxq_recv(struct hinic_rxq *rxq, int bu= dget) > > > > > > offload_type =3D be32_to_cpu(cqe->offload_type); > > > vlan_len =3D be32_to_cpu(cqe->len); > > > - if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && > > > + if ((netdev->features[0] & NETIF_F_HW_VLAN_CTAG_RX) &= & > > > HINIC_GET_RX_VLAN_OFFLOAD_EN(offload_type)) { > > > vid =3D HINIC_GET_RX_VLAN_TAG(vlan_len); > > > __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q= ), vid); > > > diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h > > > index 41a5183..4173464 100644 > > > --- a/include/linux/if_vlan.h > > > +++ b/include/linux/if_vlan.h > > > @@ -563,7 +563,7 @@ static inline int __vlan_hwaccel_get_tag(const > > > struct sk_buff *skb, > > > */ > > > static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_= tci) > > > { > > > - if (skb->dev->features & NETIF_F_HW_VLAN_CTAG_TX) { > > > + if (skb->dev->features[0] & NETIF_F_HW_VLAN_CTAG_TX) { > > > return __vlan_hwaccel_get_tag(skb, vlan_tci); > > > } else { > > > return __vlan_get_tag(skb, vlan_tci); > > > diff --git a/include/linux/netdev_features.h b/include/linux/netdev_f= eatures.h > > > index 2c6b9e4..9184963 100644 > > > --- a/include/linux/netdev_features.h > > > +++ b/include/linux/netdev_features.h > > > @@ -102,7 +102,8 @@ enum { > > > }; > > > > > > /* copy'n'paste compression ;) */ > > > -#define __NETIF_F_BIT(bit) ((netdev_features_t)1 << (bit)) > > > +#define __NETIF_F_BIT(bit) ((netdev_features_t)1 << (bit & 0x3F)= ) > > > + > > > #define __NETIF_F(name) __NETIF_F_BIT(NETIF_F_##name#= #_BIT) > > > > > > #define NETIF_F_FCOE_CRC __NETIF_F(FCOE_CRC) > > > @@ -169,6 +170,8 @@ enum { > > > #define NETIF_F_HW_HSR_FWD __NETIF_F(HW_HSR_FWD) > > > #define NETIF_F_HW_HSR_DUP __NETIF_F(HW_HSR_DUP) > > > > > > +#define NETDEV_FEATURE_DWORDS DIV_ROUND_UP(NETDEV_FEATURE_COUNT, 64= ) > > > + > > > /* Finds the next feature with the highest number of the range of st= art till 0. > > > */ > > > static inline int find_next_netdev_feature(u64 feature, unsigned lon= g start) > > > @@ -185,8 +188,7 @@ static inline int find_next_netdev_feature(u64 > > > feature, unsigned long start) > > > * mask_addr should be a u64 and bit an int > > > */ > > > #define for_each_netdev_feature(mask_addr, bit) > > > \ > > > - for ((bit) =3D find_next_netdev_feature((mask_addr), = \ > > > - NETDEV_FEATURE_COUNT); = \ > > > + for ((bit) =3D find_next_netdev_feature((mask_addr), 64); = \ > > > (bit) >=3D 0; = \ > > > (bit) =3D find_next_netdev_feature((mask_addr), (bit) - = 1)) > > > > > > @@ -195,11 +197,6 @@ static inline int find_next_netdev_feature(u64 > > > feature, unsigned long start) > > > #define NETIF_F_NEVER_CHANGE (NETIF_F_VLAN_CHALLENGED | \ > > > NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) > > > > > > -/* remember that ((t)1 << t_BITS) is undefined in C99 */ > > > -#define NETIF_F_ETHTOOL_BITS ((__NETIF_F_BIT(NETDEV_FEATURE_COUNT = - 1) | \ > > > - (__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) - 1)) & \ > > > - ~NETIF_F_NEVER_CHANGE) > > > - > > > /* Segmentation offload feature mask */ > > > #define NETIF_F_GSO_MASK (__NETIF_F_BIT(NETIF_F_GSO_LAST + 1) = - \ > > > __NETIF_F_BIT(NETIF_F_GSO_SHIFT)) > > > @@ -261,4 +258,96 @@ static inline int find_next_netdev_feature(u64 > > > feature, unsigned long start) > > > NETIF_F_GSO_UDP_TUNNEL | = \ > > > NETIF_F_GSO_UDP_TUNNEL_CSUM) > > > > > > +static inline void netdev_features_copy(netdev_features_t *dst, > > > + const netdev_features_t *src) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D src[i]; > > > +} > > > + > > > +static inline void netdev_features_and(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] & b[i]; > > > +} > > > + > > > +static inline void netdev_features_andnot(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] & ~b[i]; > > > +} > > > + > > > +static inline void netdev_features_or(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] | b[i]; > > > +} > > > + > > > +static inline void netdev_features_xor(netdev_features_t *dst, > > > + const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + dst[i] =3D a[i] ^ b[i]; > > > +} > > > + > > > +static inline void netdev_features_set(netdev_features_t *dst, > > > + unsigned int bit) > > > +{ > > > + dst[bit / 64] |=3D __NETIF_F_BIT(bit); > > > +} > > > + > > > +static inline bool netdev_features_equal(const netdev_features_t *a, > > > + const netdev_features_t *b) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + if (a[i] !=3D b[i]) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static inline void netdev_features_empty(netdev_features_t *src) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + if (src[i]) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static inline void netdev_features_ethtool_bits(netdev_features_t *d= st) > > > +{ > > > + unsigned int i; > > > + > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + if (NETDEV_FEATURE_COUNT >=3D (i + 1) * 64) > > > + dst[i] =3D GENMASK_ULL(63, 0); > > > + else > > > + dst[i] =3D GENMASK_ULL(NETDEV_FEATURE_COUNT -= i * 64, > > > + 0); > > > + } > > > + dst[0] &=3D ~NETIF_F_NEVER_CHANGE; > > > +} > > > + > > > #endif /* _LINUX_NETDEV_FEATURES_H */ > > > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h > > > index eaf5bb0..4a29487 100644 > > > --- a/include/linux/netdevice.h > > > +++ b/include/linux/netdevice.h > > > @@ -1347,9 +1347,9 @@ struct net_device_ops { > > > int (*ndo_stop)(struct net_device *dev); > > > netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb= , > > > struct net_device *= dev); > > > - netdev_features_t (*ndo_features_check)(struct sk_buff = *skb, > > > + void (*ndo_features_check)(struct sk_buff = *skb, > > > struct net_devi= ce *dev, > > > - > > > netdev_features_t features); > > > + > > > netdev_features_t *features); > > > u16 (*ndo_select_queue)(struct net_device= *dev, > > > struct sk_buff *s= kb, > > > struct net_device= *sb_dev); > > > @@ -1467,10 +1467,10 @@ struct net_device_ops { > > > bool all_slaves= ); > > > struct net_device* (*ndo_sk_get_lower_dev)(struct net_de= vice *dev, > > > struct sock *= sk); > > > - netdev_features_t (*ndo_fix_features)(struct net_device= *dev, > > > - netdev_features_t= features); > > > + void (*ndo_fix_features)(struct net_device= *dev, > > > + netdev_features_t > > > *features); > > > int (*ndo_set_features)(struct net_device= *dev, > > > - netdev_features_t= features); > > > + netdev_features_t > > > *features); > > > int (*ndo_neigh_construct)(struct net_dev= ice *dev, > > > struct neighbo= ur *n); > > > void (*ndo_neigh_destroy)(struct net_devic= e *dev, > > > @@ -1978,12 +1978,12 @@ struct net_device { > > > unsigned short needed_headroom; > > > unsigned short needed_tailroom; > > > > > > - netdev_features_t features; > > > - netdev_features_t hw_features; > > > - netdev_features_t wanted_features; > > > - netdev_features_t vlan_features; > > > - netdev_features_t hw_enc_features; > > > - netdev_features_t mpls_features; > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t hw_features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t wanted_features[NETDEV_FEATURE_DWORDS= ]; > > > + netdev_features_t vlan_features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t hw_enc_features[NETDEV_FEATURE_DWORDS= ]; > > > + netdev_features_t mpls_features[NETDEV_FEATURE_DWORDS]; > > > netdev_features_t gso_partial_features; > > > > > > unsigned int min_mtu; > > > @@ -4986,10 +4986,11 @@ static inline netdev_features_t > > > netdev_intersect_features(netdev_features_t f1, > > > return f1 & f2; > > > } > > > > > > -static inline netdev_features_t netdev_get_wanted_features( > > > - struct net_device *dev) > > > +static inline void netdev_get_wanted_features(struct net_device *dev= , > > > + netdev_features_t *want= ed) > > > { > > > - return (dev->features & ~dev->hw_features) | dev->wanted_feat= ures; > > > + netdev_features_andnot(wanted, dev->features, dev->hw_feature= s); > > > + netdev_features_or(wanted, wanted, dev->wanted_features); > > > } > > > netdev_features_t netdev_increment_features(netdev_features_t all, > > > netdev_features_t one, netdev_features_t mask); > > > @@ -5014,7 +5015,7 @@ void netif_stacked_transfer_operstate(const > > > struct net_device *rootdev, > > > netdev_features_t passthru_features_check(struct sk_buff *skb, > > > struct net_device *dev, > > > netdev_features_t features)= ; > > > -netdev_features_t netif_skb_features(struct sk_buff *skb); > > > +void netif_skb_features(struct sk_buff *skb, netdev_features_t *feat= ures); > > > > > > static inline bool net_gso_ok(netdev_features_t features, int gso_ty= pe) > > > { > > > diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c > > > index 4cdf841..7d77692 100644 > > > --- a/net/8021q/vlan.c > > > +++ b/net/8021q/vlan.c > > > @@ -328,7 +328,7 @@ static void vlan_transfer_features(struct net_dev= ice *dev, > > > vlandev->gso_max_size =3D dev->gso_max_size; > > > vlandev->gso_max_segs =3D dev->gso_max_segs; > > > > > > - if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto)) > > > + if (vlan_hw_offload_capable(dev->features[0], vlan->vlan_prot= o)) > > > vlandev->hard_header_len =3D dev->hard_header_len; > > > else > > > vlandev->hard_header_len =3D dev->hard_header_len + V= LAN_HLEN; > > > @@ -339,7 +339,7 @@ static void vlan_transfer_features(struct net_dev= ice *dev, > > > > > > vlandev->priv_flags &=3D ~IFF_XMIT_DST_RELEASE; > > > vlandev->priv_flags |=3D (vlan->real_dev->priv_flags & > > > IFF_XMIT_DST_RELEASE); > > > - vlandev->hw_enc_features =3D vlan_tnl_features(vlan->real_dev= ); > > > + vlandev->hw_enc_features[0] =3D vlan_tnl_features(vlan->real_= dev); > > > > > > netdev_update_features(vlandev); > > > } > > > diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h > > > index 1a705a4..4e784a1 100644 > > > --- a/net/8021q/vlan.h > > > +++ b/net/8021q/vlan.h > > > @@ -107,7 +107,7 @@ static inline netdev_features_t > > > vlan_tnl_features(struct net_device *real_dev) > > > { > > > netdev_features_t ret; > > > > > > - ret =3D real_dev->hw_enc_features & > > > + ret =3D real_dev->hw_enc_features[0] & > > > (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE | > > > NETIF_F_GSO_ENCAP_ALL); > > > > > > diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c > > > index a0367b3..6d49761 100644 > > > --- a/net/8021q/vlan_dev.c > > > +++ b/net/8021q/vlan_dev.c > > > @@ -566,21 +566,21 @@ static int vlan_dev_init(struct net_device *dev= ) > > > if (vlan->flags & VLAN_FLAG_BRIDGE_BINDING) > > > dev->state |=3D (1 << __LINK_STATE_NOCARRIER); > > > > > > - dev->hw_features =3D NETIF_F_HW_CSUM | NETIF_F_SG | > > > - NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | > > > - NETIF_F_GSO_ENCAP_ALL | > > > - NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | > > > - NETIF_F_ALL_FCOE; > > > + dev->hw_features[0] =3D NETIF_F_HW_CSUM | NETIF_F_SG | > > > + NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE= | > > > + NETIF_F_GSO_ENCAP_ALL | > > > + NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | > > > + NETIF_F_ALL_FCOE; > > > > > > - dev->features |=3D dev->hw_features | NETIF_F_LLTX; > > > + dev->features[0] |=3D dev->hw_features[0] | NETIF_F_LLTX; > > > dev->gso_max_size =3D real_dev->gso_max_size; > > > dev->gso_max_segs =3D real_dev->gso_max_segs; > > > - if (dev->features & NETIF_F_VLAN_FEATURES) > > > + if (dev->features[0] & NETIF_F_VLAN_FEATURES) > > > netdev_warn(real_dev, "VLAN features are set > > > incorrectly. Q-in-Q configurations may not work correctly.\n"); > > > > > > - dev->vlan_features =3D real_dev->vlan_features & ~NETIF_F_ALL= _FCOE; > > > - dev->hw_enc_features =3D vlan_tnl_features(real_dev); > > > - dev->mpls_features =3D real_dev->mpls_features; > > > + dev->vlan_features[0] =3D real_dev->vlan_features[0] & ~NETIF= _F_ALL_FCOE; > > > + dev->hw_enc_features[0] =3D vlan_tnl_features(real_dev); > > > + netdev_features_copy(dev->mpls_features, real_dev->mpls_featu= res); > > > > > > /* ipv6 shared card related stuff */ > > > dev->dev_id =3D real_dev->dev_id; > > > @@ -633,27 +633,30 @@ void vlan_dev_uninit(struct net_device *dev) > > > } > > > } > > > > > > -static netdev_features_t vlan_dev_fix_features(struct net_device *de= v, > > > - netdev_features_t features) > > > +static void vlan_dev_fix_features(struct net_device *dev, > > > + netdev_features_t *features) > > > { > > > struct net_device *real_dev =3D vlan_dev_priv(dev)->real_dev; > > > - netdev_features_t old_features =3D features; > > > - netdev_features_t lower_features; > > > + netdev_features_t lower_features[NETDEV_FEATURE_DWORDS]; > > > + netdev_features_t old_features[NETDEV_FEATURE_DWORDS]; > > > > > > - lower_features =3D netdev_intersect_features((real_dev->vlan_= features | > > > - NETIF_F_RXCSUM), > > > - real_dev->features= ); > > > + netdev_features_copy(lower_features, features); > > > + > > > + lower_features[0] =3D > > > + netdev_intersect_features((real_dev->vlan_features[0]= | > > > + NETIF_F_RXCSUM), > > > + real_dev->features[0]); > > > > > > /* Add HW_CSUM setting to preserve user ability to control > > > * checksum offload on the vlan device. > > > */ > > > - if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) > > > - lower_features |=3D NETIF_F_HW_CSUM; > > > - features =3D netdev_intersect_features(features, lower_featur= es); > > > - features |=3D old_features & (NETIF_F_SOFT_FEATURES | > > > NETIF_F_GSO_SOFTWARE); > > > - features |=3D NETIF_F_LLTX; > > > + if (lower_features[0] & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)= ) > > > + lower_features[0] |=3D NETIF_F_HW_CSUM; > > > > > > - return features; > > > + features[0] =3D netdev_intersect_features(features[0], lower_= features[0]); > > > + features[0] |=3D old_features[0] & > > > + (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE= ); > > > + features[0] |=3D NETIF_F_LLTX; > > > } > > > > > > static int vlan_ethtool_get_link_ksettings(struct net_device *dev, > > > diff --git a/net/core/dev.c b/net/core/dev.c > > > index c253c2a..7066bf3 100644 > > > --- a/net/core/dev.c > > > +++ b/net/core/dev.c > > > @@ -1765,7 +1765,7 @@ void dev_disable_lro(struct net_device *dev) > > > dev->wanted_features &=3D ~NETIF_F_LRO; > > > netdev_update_features(dev); > > > > > > - if (unlikely(dev->features & NETIF_F_LRO)) > > > + if (unlikely(dev->features[0] & NETIF_F_LRO)) > > > netdev_WARN(dev, "failed to disable LRO!\n"); > > > > > > netdev_for_each_lower_dev(dev, lower_dev, iter) > > > @@ -1786,7 +1786,7 @@ static void dev_disable_gro_hw(struct net_devic= e *dev) > > > dev->wanted_features &=3D ~NETIF_F_GRO_HW; > > > netdev_update_features(dev); > > > > > > - if (unlikely(dev->features & NETIF_F_GRO_HW)) > > > + if (unlikely(dev->features[0] & NETIF_F_GRO_HW)) > > > netdev_WARN(dev, "failed to disable GRO_HW!\n"); > > > } > > > > > > @@ -3276,7 +3276,7 @@ static void skb_warn_bad_offload(const struct > > > sk_buff *skb) > > > } > > > skb_dump(KERN_WARNING, skb, false); > > > WARN(1, "%s: caps=3D(%pNF, %pNF)\n", > > > - name, dev ? &dev->features : &null_features, > > > + name, dev ? &dev->features[0] : &null_features, > > > skb->sk ? &skb->sk->sk_route_caps : &null_features); > > > } > > > > > > @@ -3463,7 +3463,8 @@ struct sk_buff *__skb_gso_segment(struct sk_buf= f *skb, > > > netdev_features_t partial_features =3D NETIF_F_GSO_RO= BUST; > > > struct net_device *dev =3D skb->dev; > > > > > > - partial_features |=3D dev->features & dev->gso_partia= l_features; > > > + partial_features |=3D > > > + dev->features[0] & dev->gso_partial_f= eatures; > > > if (!skb_gso_ok(skb, features | partial_features)) > > > features &=3D ~NETIF_F_GSO_PARTIAL; > > > } > > > @@ -3508,7 +3509,7 @@ static int illegal_highdma(struct net_device > > > *dev, struct sk_buff *skb) > > > #ifdef CONFIG_HIGHMEM > > > int i; > > > > > > - if (!(dev->features & NETIF_F_HIGHDMA)) { > > > + if (!(dev->features[0] & NETIF_F_HIGHDMA)) { > > > for (i =3D 0; i < skb_shinfo(skb)->nr_frags; i++) { > > > skb_frag_t *frag =3D &skb_shinfo(skb)->frags[= i]; > > > > > > @@ -3612,34 +3613,33 @@ static netdev_features_t > > > gso_features_check(const struct sk_buff *skb, > > > return features; > > > } > > > > > > -netdev_features_t netif_skb_features(struct sk_buff *skb) > > > +void netif_skb_features(struct sk_buff *skb, netdev_features_t *feat= ures) > > > { > > > struct net_device *dev =3D skb->dev; > > > - netdev_features_t features =3D dev->features; > > > > > > + netdev_features_copy(features, dev->features); > > > if (skb_is_gso(skb)) > > > - features =3D gso_features_check(skb, dev, features); > > > + features[0] =3D gso_features_check(skb, dev, features= [0]); > > > > > > /* If encapsulation offload request, verify we are testing > > > * hardware encapsulation features instead of standard > > > * features for the netdev > > > */ > > > if (skb->encapsulation) > > > - features &=3D dev->hw_enc_features; > > > + netdev_features_and(features, dev->hw_enc_features); > > > > > > if (skb_vlan_tagged(skb)) > > > - features =3D netdev_intersect_features(features, > > > - dev->vlan_featur= es | > > > - NETIF_F_HW_VLAN_= CTAG_TX | > > > - NETIF_F_HW_VLAN_= STAG_TX); > > > + features[0] =3D netdev_intersect_features(features[0]= , > > > + dev->vlan_fea= tures[0] | > > > + > > > NETIF_F_HW_VLAN_CTAG_TX | > > > + > > > NETIF_F_HW_VLAN_STAG_TX); > > > > > > if (dev->netdev_ops->ndo_features_check) > > > - features &=3D dev->netdev_ops->ndo_features_check(skb= , dev, > > > - featu= res); > > > + dev->netdev_ops->ndo_features_check(skb, dev, feature= s); > > > else > > > - features &=3D dflt_features_check(skb, dev, features)= ; > > > + features[0] &=3D dflt_features_check(skb, dev, featur= es[0]); > > > > > > - return harmonize_features(skb, features); > > > + features[0] =3D harmonize_features(skb, features[0]); > > > } > > > EXPORT_SYMBOL(netif_skb_features); > > > > > > @@ -3722,10 +3722,10 @@ EXPORT_SYMBOL(skb_csum_hwoffload_help); > > > > > > static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct > > > net_device *dev, bool *again) > > > { > > > - netdev_features_t features; > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > > > > - features =3D netif_skb_features(skb); > > > - skb =3D validate_xmit_vlan(skb, features); > > > + netif_skb_features(skb, features); > > > + skb =3D validate_xmit_vlan(skb, features[0]); > > > if (unlikely(!skb)) > > > goto out_null; > > > > > > @@ -3733,10 +3733,10 @@ static struct sk_buff > > > *validate_xmit_skb(struct sk_buff *skb, struct net_device > > > if (unlikely(!skb)) > > > goto out_null; > > > > > > - if (netif_needs_gso(skb, features)) { > > > + if (netif_needs_gso(skb, features[0])) { > > > struct sk_buff *segs; > > > > > > - segs =3D skb_gso_segment(skb, features); > > > + segs =3D skb_gso_segment(skb, features[0]); > > > if (IS_ERR(segs)) { > > > goto out_kfree_skb; > > > } else if (segs) { > > > @@ -3744,7 +3744,7 @@ static struct sk_buff *validate_xmit_skb(struct > > > sk_buff *skb, struct net_device > > > skb =3D segs; > > > } > > > } else { > > > - if (skb_needs_linearize(skb, features) && > > > + if (skb_needs_linearize(skb, features[0]) && > > > __skb_linearize(skb)) > > > goto out_kfree_skb; > > > > > > @@ -3759,12 +3759,12 @@ static struct sk_buff > > > *validate_xmit_skb(struct sk_buff *skb, struct net_device > > > else > > > skb_set_transport_header(skb, > > > > > > skb_checksum_start_offset(skb)); > > > - if (skb_csum_hwoffload_help(skb, features)) > > > + if (skb_csum_hwoffload_help(skb, features[0])= ) > > > goto out_kfree_skb; > > > } > > > } > > > > > > - skb =3D validate_xmit_xfrm(skb, features, again); > > > + skb =3D validate_xmit_xfrm(skb, features[0], again); > > > > > > return skb; > > > > > > @@ -4429,7 +4429,7 @@ set_rps_cpu(struct net_device *dev, struct sk_b= uff *skb, > > > > > > /* Should we steer this flow to a different hardware = queue? */ > > > if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap = || > > > - !(dev->features & NETIF_F_NTUPLE)) > > > + !(dev->features[0] & NETIF_F_NTUPLE)) > > > goto out; > > > rxq_index =3D cpu_rmap_lookup_index(dev->rx_cpu_rmap,= next_cpu); > > > if (rxq_index =3D=3D skb_get_rx_queue(skb)) > > > @@ -9799,171 +9799,179 @@ static void net_set_todo(struct net_device = *dev) > > > dev_net(dev)->dev_unreg_count++; > > > } > > > > > > -static netdev_features_t netdev_sync_upper_features(struct net_devic= e *lower, > > > - struct net_device *upper, netdev_features_t features) > > > +static void netdev_sync_upper_features(struct net_device *lower, > > > + struct net_device *upper, > > > + netdev_features_t *features) > > > { > > > netdev_features_t upper_disables =3D NETIF_F_UPPER_DISABLES; > > > netdev_features_t feature; > > > int feature_bit; > > > + unsigned int i; > > > > > > - for_each_netdev_feature(upper_disables, feature_bit) { > > > - feature =3D __NETIF_F_BIT(feature_bit); > > > - if (!(upper->wanted_features & feature) > > > - && (features & feature)) { > > > - netdev_dbg(lower, "Dropping feature %pNF, > > > upper dev %s has it off.\n", > > > - &feature, upper->name); > > > - features &=3D ~feature; > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + for_each_netdev_feature(upper_disables, feature_bit) = { > > > + feature =3D __NETIF_F_BIT(feature_bit); > > > + if (!(upper->wanted_features[i] & feature) && > > > + (features[i] & feature)) { > > > + netdev_dbg(lower, "Dropping > > > feature[%u] %pNF, upper dev %s has it off.\n", > > > + i, &feature, upper->name); > > > + features[i] &=3D ~feature; > > > + } > > > } > > > } > > > - > > > - return features; > > > } > > > > > > static void netdev_sync_lower_features(struct net_device *upper, > > > - struct net_device *lower, netdev_features_t features) > > > + struct net_device *lower, netdev_features_t *features) > > > { > > > netdev_features_t upper_disables =3D NETIF_F_UPPER_DISABLES; > > > netdev_features_t feature; > > > int feature_bit; > > > + unsigned int i; > > > > > > - for_each_netdev_feature(upper_disables, feature_bit) { > > > - feature =3D __NETIF_F_BIT(feature_bit); > > > - if (!(features & feature) && (lower->features & featu= re)) { > > > - netdev_dbg(upper, "Disabling feature %pNF on > > > lower dev %s.\n", > > > - &feature, lower->name); > > > - lower->wanted_features &=3D ~feature; > > > - __netdev_update_features(lower); > > > - > > > - if (unlikely(lower->features & feature)) > > > - netdev_WARN(upper, "failed to disable > > > %pNF on %s!\n", > > > - &feature, lower->name); > > > - else > > > - netdev_features_change(lower); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + for_each_netdev_feature(upper_disables, feature_bit) = { > > > + feature =3D __NETIF_F_BIT(feature_bit); > > > + if (!(features[i] & feature) && > > > + (lower->features[i] & feature)) { > > > + netdev_dbg(upper, "Disabling > > > feature[%u] %pNF on lower dev %s.\n", > > > + i, &feature, lower->name); > > > + lower->wanted_features[i] &=3D ~featu= re[i]; > > > + __netdev_update_features(lower); > > > + > > > + if (unlikely(lower->features[i] & fea= ture)) > > > + netdev_WARN(upper, "failed to > > > disable feature[%u] %pNF on %s!\n", > > > + i, &feature, lowe= r->name); > > > + else > > > + netdev_features_change(lower)= ; > > > + } > > > } > > > } > > > } > > > > > > -static netdev_features_t netdev_fix_features(struct net_device *dev, > > > - netdev_features_t features) > > > +static void netdev_fix_features(struct net_device *dev, > > > + netdev_features_t *features) > > > { > > > /* Fix illegal checksum combinations */ > > > - if ((features & NETIF_F_HW_CSUM) && > > > - (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { > > > + if ((features[0] & NETIF_F_HW_CSUM) && > > > + (features[0] & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) { > > > netdev_warn(dev, "mixed HW and IP checksum settings.\= n"); > > > - features &=3D ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); > > > + features[0] &=3D ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSU= M); > > > } > > > > > > /* TSO requires that SG is present as well. */ > > > - if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG))= { > > > + if ((features[0] & NETIF_F_ALL_TSO) && !(features[0] & NETIF_= F_SG)) { > > > netdev_dbg(dev, "Dropping TSO features since no SG fe= ature.\n"); > > > - features &=3D ~NETIF_F_ALL_TSO; > > > + features[0] &=3D ~NETIF_F_ALL_TSO; > > > } > > > > > > - if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM)= && > > > - !(features & NETIF_F_IP_CSUM)= ) { > > > + if ((features[0] & NETIF_F_TSO) && !(features[0] & NETIF_F_HW= _CSUM) && > > > + !(features[0] & NETIF_F_IP_CSUM)) { > > > netdev_dbg(dev, "Dropping TSO features since no CSUM > > > feature.\n"); > > > - features &=3D ~NETIF_F_TSO; > > > - features &=3D ~NETIF_F_TSO_ECN; > > > + features[0] &=3D ~NETIF_F_TSO; > > > + features[0] &=3D ~NETIF_F_TSO_ECN; > > > } > > > > > > - if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM= ) && > > > - !(features & NETIF_F_IPV6_CS= UM)) { > > > + if ((features[0] & NETIF_F_TSO6) && !(features[0] & NETIF_F_H= W_CSUM) && > > > + !(features[0] & NETIF_F_IPV6_CSUM)) { > > > netdev_dbg(dev, "Dropping TSO6 features since no CSUM > > > feature.\n"); > > > - features &=3D ~NETIF_F_TSO6; > > > + features[0] &=3D ~NETIF_F_TSO6; > > > } > > > > > > /* TSO with IPv4 ID mangling requires IPv4 TSO be enabled */ > > > - if ((features & NETIF_F_TSO_MANGLEID) && !(features & NETIF_F= _TSO)) > > > - features &=3D ~NETIF_F_TSO_MANGLEID; > > > + if ((features[0] & NETIF_F_TSO_MANGLEID) && > > > + !(features[0] & NETIF_F_TSO)) > > > + features[0] &=3D ~NETIF_F_TSO_MANGLEID; > > > > > > /* TSO ECN requires that TSO is present as well. */ > > > - if ((features & NETIF_F_ALL_TSO) =3D=3D NETIF_F_TSO_ECN) > > > - features &=3D ~NETIF_F_TSO_ECN; > > > + if ((features[0] & NETIF_F_ALL_TSO) =3D=3D NETIF_F_TSO_ECN) > > > + features[0] &=3D ~NETIF_F_TSO_ECN; > > > > > > /* Software GSO depends on SG. */ > > > - if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) { > > > + if ((features[0] & NETIF_F_GSO) && !(features[0] & NETIF_F_SG= )) { > > > netdev_dbg(dev, "Dropping NETIF_F_GSO since no SG fea= ture.\n"); > > > - features &=3D ~NETIF_F_GSO; > > > + features[0] &=3D ~NETIF_F_GSO; > > > } > > > > > > /* GSO partial features require GSO partial be set */ > > > - if ((features & dev->gso_partial_features) && > > > - !(features & NETIF_F_GSO_PARTIAL)) { > > > + if ((features[0] & dev->gso_partial_features) && > > > + !(features[0] & NETIF_F_GSO_PARTIAL)) { > > > netdev_dbg(dev, > > > "Dropping partially supported GSO features > > > since no GSO partial.\n"); > > > - features &=3D ~dev->gso_partial_features; > > > + features[0] &=3D ~dev->gso_partial_features; > > > } > > > > > > - if (!(features & NETIF_F_RXCSUM)) { > > > + if (!(features[0] & NETIF_F_RXCSUM)) { > > > /* NETIF_F_GRO_HW implies doing RXCSUM since every pa= cket > > > * successfully merged by hardware must also have the > > > * checksum verified by hardware. If the user does n= ot > > > * want to enable RXCSUM, logically, we should disabl= e GRO_HW. > > > */ > > > - if (features & NETIF_F_GRO_HW) { > > > + if (features[0] & NETIF_F_GRO_HW) { > > > netdev_dbg(dev, "Dropping NETIF_F_GRO_HW sinc= e > > > no RXCSUM feature.\n"); > > > - features &=3D ~NETIF_F_GRO_HW; > > > + features[0] &=3D ~NETIF_F_GRO_HW; > > > } > > > } > > > > > > /* LRO/HW-GRO features cannot be combined with RX-FCS */ > > > - if (features & NETIF_F_RXFCS) { > > > - if (features & NETIF_F_LRO) { > > > + if (features[0] & NETIF_F_RXFCS) { > > > + if (features[0] & NETIF_F_LRO) { > > > netdev_dbg(dev, "Dropping LRO feature since > > > RX-FCS is requested.\n"); > > > - features &=3D ~NETIF_F_LRO; > > > + features[0] &=3D ~NETIF_F_LRO; > > > } > > > > > > - if (features & NETIF_F_GRO_HW) { > > > + if (features[0] & NETIF_F_GRO_HW) { > > > netdev_dbg(dev, "Dropping HW-GRO feature sinc= e > > > RX-FCS is requested.\n"); > > > - features &=3D ~NETIF_F_GRO_HW; > > > + features[0] &=3D ~NETIF_F_GRO_HW; > > > } > > > } > > > > > > - if (features & NETIF_F_HW_TLS_TX) { > > > - bool ip_csum =3D (features & (NETIF_F_IP_CSUM | > > > NETIF_F_IPV6_CSUM)) =3D=3D > > > + if (features[0] & NETIF_F_HW_TLS_TX) { > > > + bool ip_csum =3D (features[0] & (NETIF_F_IP_CSUM | > > > NETIF_F_IPV6_CSUM)) =3D=3D > > > (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); > > > - bool hw_csum =3D features & NETIF_F_HW_CSUM; > > > + bool hw_csum =3D features[0] & NETIF_F_HW_CSUM; > > > > > > if (!ip_csum && !hw_csum) { > > > netdev_dbg(dev, "Dropping TLS TX HW offload > > > feature since no CSUM feature.\n"); > > > - features &=3D ~NETIF_F_HW_TLS_TX; > > > + features[0] &=3D ~NETIF_F_HW_TLS_TX; > > > } > > > } > > > > > > - if ((features & NETIF_F_HW_TLS_RX) && !(features & NETIF_F_RX= CSUM)) { > > > + if ((features[0] & NETIF_F_HW_TLS_RX) && > > > + !(features[0] & NETIF_F_RXCSUM)) { > > > netdev_dbg(dev, "Dropping TLS RX HW offload feature > > > since no RXCSUM feature.\n"); > > > - features &=3D ~NETIF_F_HW_TLS_RX; > > > + features[0] &=3D ~NETIF_F_HW_TLS_RX; > > > } > > > - > > > - return features; > > > } > > > > > > int __netdev_update_features(struct net_device *dev) > > > { > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > struct net_device *upper, *lower; > > > - netdev_features_t features; > > > struct list_head *iter; > > > + unsigned int i; > > > int err =3D -1; > > > > > > ASSERT_RTNL(); > > > > > > - features =3D netdev_get_wanted_features(dev); > > > + netdev_get_wanted_features(dev, features); > > > > > > if (dev->netdev_ops->ndo_fix_features) > > > - features =3D dev->netdev_ops->ndo_fix_features(dev, f= eatures); > > > + dev->netdev_ops->ndo_fix_features(dev, features); > > > > > > /* driver might be less strict about feature dependencies */ > > > - features =3D netdev_fix_features(dev, features); > > > + netdev_fix_features(dev, features); > > > > > > /* some features can't be enabled if they're off on an upper = device */ > > > netdev_for_each_upper_dev_rcu(dev, upper, iter) > > > - features =3D netdev_sync_upper_features(dev, upper, f= eatures); > > > + netdev_sync_upper_features(dev, upper, features); > > > > > > - if (dev->features =3D=3D features) > > > + if (netdev_features_equal(dev->features, features)) > > > goto sync_lower; > > > > > > - netdev_dbg(dev, "Features changed: %pNF -> %pNF\n", > > > - &dev->features, &features); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + netdev_dbg(dev, "Features[%u] changed: %pNF -> %pNF\n= ", > > > + i, &dev->features[i], &features[i]); > > > > > > if (dev->netdev_ops->ndo_set_features) > > > err =3D dev->netdev_ops->ndo_set_features(dev, featur= es); > > > @@ -9971,9 +9979,10 @@ int __netdev_update_features(struct net_device= *dev) > > > err =3D 0; > > > > > > if (unlikely(err < 0)) { > > > - netdev_err(dev, > > > - "set_features() failed (%d); wanted %pNF, lef= t %pNF\n", > > > - err, &features, &dev->features); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + netdev_err(dev, > > > + "set_features() failed (%d); > > > wanted[%u] %pNF, left[%u] %pNF\n", > > > + err, i, &features[i], i, &dev->fea= tures[i]); > > > /* return non-0 since some features might have change= d and > > > * it's better to fire a spurious notification than m= iss it > > > */ > > > @@ -9988,9 +9997,10 @@ int __netdev_update_features(struct net_device= *dev) > > > netdev_sync_lower_features(dev, lower, features); > > > > > > if (!err) { > > > - netdev_features_t diff =3D features ^ dev->features; > > > + netdev_features_t diff[NETDEV_FEATURE_DWORDS]; > > > > > > - if (diff & NETIF_F_RX_UDP_TUNNEL_PORT) { > > > + netdev_features_xor(diff, features, dev->features); > > > + if (diff[0] & NETIF_F_RX_UDP_TUNNEL_PORT) { > > > /* udp_tunnel_{get,drop}_rx_info both need > > > * NETIF_F_RX_UDP_TUNNEL_PORT enabled on the > > > * device, or they won't do anything. > > > @@ -9998,33 +10008,33 @@ int __netdev_update_features(struct net_devi= ce *dev) > > > * *before* calling udp_tunnel_get_rx_info, > > > * but *after* calling udp_tunnel_drop_rx_inf= o. > > > */ > > > - if (features & NETIF_F_RX_UDP_TUNNEL_PORT) { > > > - dev->features =3D features; > > > + if (features[0] & NETIF_F_RX_UDP_TUNNEL_PORT)= { > > > + dev->features[0] =3D features[0]; > > > udp_tunnel_get_rx_info(dev); > > > } else { > > > udp_tunnel_drop_rx_info(dev); > > > } > > > } > > > > > > - if (diff & NETIF_F_HW_VLAN_CTAG_FILTER) { > > > - if (features & NETIF_F_HW_VLAN_CTAG_FILTER) { > > > - dev->features =3D features; > > > + if (diff[0] & NETIF_F_HW_VLAN_CTAG_FILTER) { > > > + if (features[0] & NETIF_F_HW_VLAN_CTAG_FILTER= ) { > > > + dev->features[0] =3D features[0]; > > > err |=3D vlan_get_rx_ctag_filter_info= (dev); > > > } else { > > > vlan_drop_rx_ctag_filter_info(dev); > > > } > > > } > > > > > > - if (diff & NETIF_F_HW_VLAN_STAG_FILTER) { > > > + if (diff[0] & NETIF_F_HW_VLAN_STAG_FILTER) { > > > if (features & NETIF_F_HW_VLAN_STAG_FILTER) { > > > - dev->features =3D features; > > > + dev->features[0] =3D features[0]; > > > err |=3D vlan_get_rx_stag_filter_info= (dev); > > > } else { > > > vlan_drop_rx_stag_filter_info(dev); > > > } > > > } > > > > > > - dev->features =3D features; > > > + netdev_features_copy(dev->features, features); > > > } > > > > > > return err < 0 ? 0 : 1; > > > @@ -10213,7 +10223,7 @@ int register_netdevice(struct net_device *dev= ) > > > int ret; > > > struct net *net =3D dev_net(dev); > > > > > > - BUILD_BUG_ON(sizeof(netdev_features_t) * BITS_PER_BYTE < > > > + BUILD_BUG_ON(sizeof(dev->features) * BITS_PER_BYTE < > > > NETDEV_FEATURE_COUNT); > > > BUG_ON(dev_boot_phase); > > > ASSERT_RTNL(); > > > @@ -10250,7 +10260,7 @@ int register_netdevice(struct net_device *dev= ) > > > } > > > } > > > > > > - if (((dev->hw_features | dev->features) & > > > + if (((dev->hw_features[0] | dev->features[0]) & > > > NETIF_F_HW_VLAN_CTAG_FILTER) && > > > (!dev->netdev_ops->ndo_vlan_rx_add_vid || > > > !dev->netdev_ops->ndo_vlan_rx_kill_vid)) { > > > @@ -10268,44 +10278,46 @@ int register_netdevice(struct net_device *d= ev) > > > /* Transfer changeable features to wanted_features and enable > > > * software offloads (GSO and GRO). > > > */ > > > - dev->hw_features |=3D (NETIF_F_SOFT_FEATURES | NETIF_F_SOFT_F= EATURES_OFF); > > > - dev->features |=3D NETIF_F_SOFT_FEATURES; > > > + dev->hw_features[0] |=3D > > > + (NETIF_F_SOFT_FEATURES | NETIF_F_SOFT_FEATURE= S_OFF); > > > + dev->features[0] |=3D NETIF_F_SOFT_FEATURES; > > > > > > if (dev->udp_tunnel_nic_info) { > > > - dev->features |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > - dev->hw_features |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > + dev->features[0] |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > + dev->hw_features[0] |=3D NETIF_F_RX_UDP_TUNNEL_PORT; > > > } > > > > > > - dev->wanted_features =3D dev->features & dev->hw_features; > > > + netdev_features_and(dev->wanted_features, dev->features, > > > + dev->hw_features); > > > > > > if (!(dev->flags & IFF_LOOPBACK)) > > > - dev->hw_features |=3D NETIF_F_NOCACHE_COPY; > > > + dev->hw_features[0] |=3D NETIF_F_NOCACHE_COPY; > > > > > > /* If IPv4 TCP segmentation offload is supported we should al= so > > > * allow the device to enable segmenting the frame with the o= ption > > > * of ignoring a static IP ID value. This doesn't enable the > > > * feature itself but allows the user to enable it later. > > > */ > > > - if (dev->hw_features & NETIF_F_TSO) > > > - dev->hw_features |=3D NETIF_F_TSO_MANGLEID; > > > - if (dev->vlan_features & NETIF_F_TSO) > > > - dev->vlan_features |=3D NETIF_F_TSO_MANGLEID; > > > - if (dev->mpls_features & NETIF_F_TSO) > > > - dev->mpls_features |=3D NETIF_F_TSO_MANGLEID; > > > - if (dev->hw_enc_features & NETIF_F_TSO) > > > - dev->hw_enc_features |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->hw_features[0] & NETIF_F_TSO) > > > + dev->hw_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->vlan_features[0] & NETIF_F_TSO) > > > + dev->vlan_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->mpls_features[0] & NETIF_F_TSO) > > > + dev->mpls_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > + if (dev->hw_enc_features[0] & NETIF_F_TSO) > > > + dev->hw_enc_features[0] |=3D NETIF_F_TSO_MANGLEID; > > > > > > /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. > > > */ > > > - dev->vlan_features |=3D NETIF_F_HIGHDMA; > > > + dev->vlan_features[0] |=3D NETIF_F_HIGHDMA; > > > > > > /* Make NETIF_F_SG inheritable to tunnel devices. > > > */ > > > - dev->hw_enc_features |=3D NETIF_F_SG | NETIF_F_GSO_PARTIAL; > > > + dev->hw_enc_features[0] |=3D NETIF_F_SG | NETIF_F_GSO_PARTIAL= ; > > > > > > /* Make NETIF_F_SG inheritable to MPLS. > > > */ > > > - dev->mpls_features |=3D NETIF_F_SG; > > > + dev->mpls_features[0] |=3D NETIF_F_SG; > > > > > > ret =3D call_netdevice_notifiers(NETDEV_POST_INIT, dev); > > > ret =3D notifier_to_errno(ret); > > > @@ -11146,7 +11158,7 @@ int __dev_change_net_namespace(struct > > > net_device *dev, struct net *net, > > > > > > /* Don't allow namespace local devices to be moved. */ > > > err =3D -EINVAL; > > > - if (dev->features & NETIF_F_NETNS_LOCAL) > > > + if (dev->features[0] & NETIF_F_NETNS_LOCAL) > > > goto out; > > > > > > /* Ensure the device has been registrered */ > > > @@ -11506,7 +11518,7 @@ static void __net_exit > > > default_device_exit(struct net *net) > > > char fb_name[IFNAMSIZ]; > > > > > > /* Ignore unmoveable devices (i.e. loopback) */ > > > - if (dev->features & NETIF_F_NETNS_LOCAL) > > > + if (dev->features[0] & NETIF_F_NETNS_LOCAL) > > > continue; > > > > > > /* Leave virtual devices for the generic cleanup */ > > > diff --git a/net/core/netpoll.c b/net/core/netpoll.c > > > index 0a6b047..2c0adf4 100644 > > > --- a/net/core/netpoll.c > > > +++ b/net/core/netpoll.c > > > @@ -74,13 +74,13 @@ static netdev_tx_t netpoll_start_xmit(struct sk_b= uff *skb, > > > struct net_device *dev, > > > struct netdev_queue *txq) > > > { > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > netdev_tx_t status =3D NETDEV_TX_OK; > > > - netdev_features_t features; > > > > > > - features =3D netif_skb_features(skb); > > > + netif_skb_features(skb, features); > > > > > > if (skb_vlan_tag_present(skb) && > > > - !vlan_hw_offload_capable(features, skb->vlan_proto)) { > > > + !vlan_hw_offload_capable(features[0], skb->vlan_proto)) { > > > skb =3D __vlan_hwaccel_push_inside(skb); > > > if (unlikely(!skb)) { > > > /* This is actually a packet drop, but we > > > diff --git a/net/ethtool/features.c b/net/ethtool/features.c > > > index 1c9f4df..0eedb17 100644 > > > --- a/net/ethtool/features.c > > > +++ b/net/ethtool/features.c > > > @@ -25,12 +25,13 @@ const struct nla_policy ethnl_features_get_policy= [] =3D { > > > NLA_POLICY_NESTED(ethnl_header_policy), > > > }; > > > > > > -static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t = src) > > > +static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t = *src) > > > { > > > + u32 *__src =3D (u32 *)src; > > > unsigned int i; > > > > > > for (i =3D 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++) > > > - dest[i] =3D src >> (32 * i); > > > + dest[i] =3D __src[i]; > > > } > > > > > > static int features_prepare_data(const struct ethnl_req_info *req_ba= se, > > > @@ -38,15 +39,23 @@ static int features_prepare_data(const struct > > > ethnl_req_info *req_base, > > > struct genl_info *info) > > > { > > > struct features_reply_data *data =3D FEATURES_REPDATA(reply_b= ase); > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS] =3D {0}; > > > struct net_device *dev =3D reply_base->dev; > > > - netdev_features_t all_features; > > > + unsigned int i; > > > > > > ethnl_features_to_bitmap32(data->hw, dev->hw_features); > > > ethnl_features_to_bitmap32(data->wanted, dev->wanted_features= ); > > > ethnl_features_to_bitmap32(data->active, dev->features); > > > - ethnl_features_to_bitmap32(data->nochange, NETIF_F_NEVER_CHAN= GE); > > > - all_features =3D GENMASK_ULL(NETDEV_FEATURE_COUNT - 1, 0); > > > - ethnl_features_to_bitmap32(data->all, all_features); > > > + features[0] =3D NETIF_F_NEVER_CHANGE; > > > + ethnl_features_to_bitmap32(data->nochange, features); > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) { > > > + if (NETDEV_FEATURE_COUNT >=3D (i + 1) * 64) > > > + features[i] =3D GENMASK_ULL(63, 0); > > > + else > > > + features[i] =3D GENMASK_ULL(NETDEV_FEATURE_CO= UNT - i * 64, > > > + 0); > > > + } > > > + ethnl_features_to_bitmap32(data->all, features); > > > > > > return 0; > > > } > > > @@ -131,27 +140,29 @@ const struct nla_policy ethnl_features_set_poli= cy[] =3D { > > > [ETHTOOL_A_FEATURES_WANTED] =3D { .type =3D NLA_NESTED }, > > > }; > > > > > > -static void ethnl_features_to_bitmap(unsigned long *dest, > > > netdev_features_t val) > > > +static void ethnl_features_to_bitmap(unsigned long *dest, > > > + netdev_features_t *val) > > > { > > > const unsigned int words =3D BITS_TO_LONGS(NETDEV_FEATURE_COU= NT); > > > unsigned int i; > > > > > > bitmap_zero(dest, NETDEV_FEATURE_COUNT); > > > for (i =3D 0; i < words; i++) > > > - dest[i] =3D (unsigned long)(val >> (i * BITS_PER_LONG= )); > > > + dest[i] =3D > > > + (unsigned long)(val[i / 2] >> (i % 2 * BITS_P= ER_LONG)); > > > } > > > > > > -static netdev_features_t ethnl_bitmap_to_features(unsigned long *src= ) > > > +static void ethnl_bitmap_to_features(netdev_features_t *val, unsigne= d > > > long *src) > > > { > > > - const unsigned int nft_bits =3D sizeof(netdev_features_t) * B= ITS_PER_BYTE; > > > const unsigned int words =3D BITS_TO_LONGS(NETDEV_FEATURE_COU= NT); > > > - netdev_features_t ret =3D 0; > > > unsigned int i; > > > > > > + for (i =3D 0; i < NETDEV_FEATURE_DWORDS; i++) > > > + val[i] =3D 0; > > > + > > > for (i =3D 0; i < words; i++) > > > - ret |=3D (netdev_features_t)(src[i]) << (i * BITS_PER= _LONG); > > > - ret &=3D ~(netdev_features_t)0 >> (nft_bits - NETDEV_FEATURE_= COUNT); > > > - return ret; > > > + val[i / 2] |=3D > > > + (netdev_features_t)(src[i]) << (i % 2 * BITS_= PER_LONG); > > > } > > > > > > static int features_send_reply(struct net_device *dev, struct genl_i= nfo *info, > > > @@ -212,12 +223,14 @@ int ethnl_set_features(struct sk_buff *skb, > > > struct genl_info *info) > > > { > > > DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT); > > > + netdev_features_t features[NETDEV_FEATURE_DWORDS]; > > > DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(old_wanted, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT); > > > DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT); > > > + netdev_features_t tmp[NETDEV_FEATURE_DWORDS]; > > > struct ethnl_req_info req_info =3D {}; > > > struct nlattr **tb =3D info->attrs; > > > struct net_device --