Skip to content

Commit

Permalink
Merge branch 'net-NETIF_F_GRO_HW'
Browse files Browse the repository at this point in the history
Michael Chan says:

====================
Introduce NETIF_F_GRO_HW

Introduce NETIF_F_GRO_HW feature flag and convert drivers that support
hardware GRO to use the new flag.

v5:
- Documentation changes requested by Alexander Duyck.
- bnx2x changes requested by Manish Chopra to enable LRO by default, and
disable GRO_HW if disable_tpa module parameter is set.

v4:
- more changes requested by Alexander Duyck:
- check GRO_HW/GRO dependency in drivers's ndo_fix_features().
- Reverse the order of RXCSUM and GRO_HW dependency check in
netdev_fix_features().
- No propagation in netdev_disable_gro_hw().

v3:
- Let driver's ndo_fix_features() disable NETIF_F_LRO when NETIF_F_GRO_HW
is set instead of doing it in common netdev_fix_features().

v2:
- NETIF_F_GRO_HW flag propagation between upper and lower devices not
required (see patch 1).
- NETIF_F_GRO_HW depends on NETIF_F_GRO and NETIF_F_RXCSUM.
- Add dev_disable_gro_hw() to disable GRO_HW for generic XDP.
- Use ndo_fix_features() on all 3 drivers to drop GRO_HW when it is not
supported
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 19, 2017
2 parents 398b841 + 18c602d commit e9c5a10
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 40 deletions.
9 changes: 9 additions & 0 deletions Documentation/networking/netdev-features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,12 @@ This requests that the NIC receive all possible frames, including errored
frames (such as bad FCS, etc). This can be helpful when sniffing a link with
bad packets on it. Some NICs may receive more packets if also put into normal
PROMISC mode.

* rx-gro-hw

This requests that the NIC enables Hardware GRO (generic receive offload).
Hardware GRO is basically the exact reverse of TSO, and is generally
stricter than Hardware LRO. A packet stream merged by Hardware GRO must
be re-segmentable by GSO or TSO back to the exact original packet stream.
Hardware GRO is dependent on RXCSUM since every packet successfully merged
by hardware must also have the checksum verified by hardware.
24 changes: 12 additions & 12 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2482,8 +2482,7 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
*/
if (bp->dev->features & NETIF_F_LRO)
fp->mode = TPA_MODE_LRO;
else if (bp->dev->features & NETIF_F_GRO &&
bnx2x_mtu_allows_gro(bp->dev->mtu))
else if (bp->dev->features & NETIF_F_GRO_HW)
fp->mode = TPA_MODE_GRO;
else
fp->mode = TPA_MODE_DISABLED;
Expand Down Expand Up @@ -4874,6 +4873,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
*/
dev->mtu = new_mtu;

if (!bnx2x_mtu_allows_gro(new_mtu))
dev->features &= ~NETIF_F_GRO_HW;

if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg))
SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS);

Expand Down Expand Up @@ -4903,10 +4905,13 @@ netdev_features_t bnx2x_fix_features(struct net_device *dev,
}

/* TPA requires Rx CSUM offloading */
if (!(features & NETIF_F_RXCSUM)) {
if (!(features & NETIF_F_RXCSUM))
features &= ~NETIF_F_LRO;

if (!(features & NETIF_F_GRO) || !bnx2x_mtu_allows_gro(dev->mtu))
features &= ~NETIF_F_GRO_HW;
if (features & NETIF_F_GRO_HW)
features &= ~NETIF_F_LRO;
features &= ~NETIF_F_GRO;
}

return features;
}
Expand All @@ -4933,13 +4938,8 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
}
}

/* if GRO is changed while LRO is enabled, don't force a reload */
if ((changes & NETIF_F_GRO) && (features & NETIF_F_LRO))
changes &= ~NETIF_F_GRO;

/* if GRO is changed while HW TPA is off, don't force a reload */
if ((changes & NETIF_F_GRO) && bp->disable_tpa)
changes &= ~NETIF_F_GRO;
/* Don't care about GRO changes */
changes &= ~NETIF_F_GRO;

if (changes)
bnx2x_reload = true;
Expand Down
8 changes: 5 additions & 3 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12400,8 +12400,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)

/* Set TPA flags */
if (bp->disable_tpa) {
bp->dev->hw_features &= ~NETIF_F_LRO;
bp->dev->features &= ~NETIF_F_LRO;
bp->dev->hw_features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
bp->dev->features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
}

if (CHIP_IS_E1(bp))
Expand Down Expand Up @@ -13273,7 +13273,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,

dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO |
NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO | NETIF_F_GRO_HW |
NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX;
if (!chip_is_e1x) {
dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM |
Expand Down Expand Up @@ -13309,6 +13309,8 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,

dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX;
dev->features |= NETIF_F_HIGHDMA;
if (dev->features & NETIF_F_LRO)
dev->features &= ~NETIF_F_GRO_HW;

/* Add Loopback capability to the device */
dev->hw_features |= NETIF_F_LOOPBACK;
Expand Down
27 changes: 20 additions & 7 deletions drivers/net/ethernet/broadcom/bnxt/bnxt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2755,7 +2755,7 @@ void bnxt_set_tpa_flags(struct bnxt *bp)
return;
if (bp->dev->features & NETIF_F_LRO)
bp->flags |= BNXT_FLAG_LRO;
if (bp->dev->features & NETIF_F_GRO)
else if (bp->dev->features & NETIF_F_GRO_HW)
bp->flags |= BNXT_FLAG_GRO;
}

Expand Down Expand Up @@ -2843,10 +2843,10 @@ int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode)
min_t(u16, bp->max_mtu, BNXT_MAX_PAGE_MODE_MTU);
bp->flags &= ~BNXT_FLAG_AGG_RINGS;
bp->flags |= BNXT_FLAG_NO_AGG_RINGS | BNXT_FLAG_RX_PAGE_MODE;
bp->dev->hw_features &= ~NETIF_F_LRO;
bp->dev->features &= ~NETIF_F_LRO;
bp->rx_dir = DMA_BIDIRECTIONAL;
bp->rx_skb_func = bnxt_rx_page_skb;
/* Disable LRO or GRO_HW */
netdev_update_features(bp->dev);
} else {
bp->dev->max_mtu = bp->max_mtu;
bp->flags &= ~BNXT_FLAG_RX_PAGE_MODE;
Expand Down Expand Up @@ -6788,6 +6788,15 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev,
if ((features & NETIF_F_NTUPLE) && !bnxt_rfs_capable(bp))
features &= ~NETIF_F_NTUPLE;

if (bp->flags & BNXT_FLAG_NO_AGG_RINGS)
features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);

if (!(features & NETIF_F_GRO))
features &= ~NETIF_F_GRO_HW;

if (features & NETIF_F_GRO_HW)
features &= ~NETIF_F_LRO;

/* Both CTAG and STAG VLAN accelaration on the RX side have to be
* turned on or off together.
*/
Expand Down Expand Up @@ -6821,9 +6830,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
bool update_tpa = false;

flags &= ~BNXT_FLAG_ALL_CONFIG_FEATS;
if ((features & NETIF_F_GRO) && !BNXT_CHIP_TYPE_NITRO_A0(bp))
if (features & NETIF_F_GRO_HW)
flags |= BNXT_FLAG_GRO;
if (features & NETIF_F_LRO)
else if (features & NETIF_F_LRO)
flags |= BNXT_FLAG_LRO;

if (bp->flags & BNXT_FLAG_NO_AGG_RINGS)
Expand Down Expand Up @@ -7924,8 +7933,8 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx,
if (rc)
return rc;
bp->flags |= BNXT_FLAG_NO_AGG_RINGS;
bp->dev->hw_features &= ~NETIF_F_LRO;
bp->dev->features &= ~NETIF_F_LRO;
bp->dev->hw_features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
bp->dev->features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
bnxt_set_ring_params(bp);
}

Expand Down Expand Up @@ -8108,7 +8117,11 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->vlan_features = dev->hw_features | NETIF_F_HIGHDMA;
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX;
if (!BNXT_CHIP_TYPE_NITRO_A0(bp))
dev->hw_features |= NETIF_F_GRO_HW;
dev->features |= dev->hw_features | NETIF_F_HIGHDMA;
if (dev->features & NETIF_F_GRO_HW)
dev->features &= ~NETIF_F_LRO;
dev->priv_flags |= IFF_UNICAST_FLT;

#ifdef CONFIG_BNXT_SRIOV
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/qlogic/qede/qede.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ int qede_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid);
void qede_vlan_mark_nonconfigured(struct qede_dev *edev);
int qede_configure_vlan_filters(struct qede_dev *edev);

netdev_features_t qede_fix_features(struct net_device *dev,
netdev_features_t features);
int qede_set_features(struct net_device *dev, netdev_features_t features);
void qede_set_rx_mode(struct net_device *ndev);
void qede_config_rx_mode(struct net_device *ndev);
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/qlogic/qede/qede_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,9 @@ int qede_change_mtu(struct net_device *ndev, int new_mtu)
DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
"Configuring MTU size of %d\n", new_mtu);

if (new_mtu > PAGE_SIZE)
ndev->features &= ~NETIF_F_GRO_HW;

/* Set the mtu field and re-start the interface if needed */
args.u.mtu = new_mtu;
args.func = &qede_update_mtu;
Expand Down
21 changes: 14 additions & 7 deletions drivers/net/ethernet/qlogic/qede/qede_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -895,19 +895,26 @@ static void qede_set_features_reload(struct qede_dev *edev,
edev->ndev->features = args->u.features;
}

netdev_features_t qede_fix_features(struct net_device *dev,
netdev_features_t features)
{
struct qede_dev *edev = netdev_priv(dev);

if (edev->xdp_prog || edev->ndev->mtu > PAGE_SIZE ||
!(features & NETIF_F_GRO))
features &= ~NETIF_F_GRO_HW;

return features;
}

int qede_set_features(struct net_device *dev, netdev_features_t features)
{
struct qede_dev *edev = netdev_priv(dev);
netdev_features_t changes = features ^ dev->features;
bool need_reload = false;

/* No action needed if hardware GRO is disabled during driver load */
if (changes & NETIF_F_GRO) {
if (dev->features & NETIF_F_GRO)
need_reload = !edev->gro_disable;
else
need_reload = edev->gro_disable;
}
if (changes & NETIF_F_GRO_HW)
need_reload = true;

if (need_reload) {
struct qede_reload_args args;
Expand Down
17 changes: 6 additions & 11 deletions drivers/net/ethernet/qlogic/qede/qede_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ static const struct net_device_ops qede_netdev_ops = {
#endif
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
.ndo_fix_features = qede_fix_features,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
#ifdef CONFIG_QED_SRIOV
Expand Down Expand Up @@ -572,6 +573,7 @@ static const struct net_device_ops qede_netdev_vf_ops = {
.ndo_change_mtu = qede_change_mtu,
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
.ndo_fix_features = qede_fix_features,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
.ndo_udp_tunnel_add = qede_udp_tunnel_add,
Expand All @@ -589,6 +591,7 @@ static const struct net_device_ops qede_netdev_vf_xdp_ops = {
.ndo_change_mtu = qede_change_mtu,
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
.ndo_fix_features = qede_fix_features,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
.ndo_udp_tunnel_add = qede_udp_tunnel_add,
Expand Down Expand Up @@ -676,7 +679,7 @@ static void qede_init_ndev(struct qede_dev *edev)
ndev->priv_flags |= IFF_UNICAST_FLT;

/* user-changeble features */
hw_features = NETIF_F_GRO | NETIF_F_SG |
hw_features = NETIF_F_GRO | NETIF_F_GRO_HW | NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;

Expand Down Expand Up @@ -1228,18 +1231,9 @@ static int qede_alloc_sge_mem(struct qede_dev *edev, struct qede_rx_queue *rxq)
dma_addr_t mapping;
int i;

/* Don't perform FW aggregations in case of XDP */
if (edev->xdp_prog)
edev->gro_disable = 1;

if (edev->gro_disable)
return 0;

if (edev->ndev->mtu > PAGE_SIZE) {
edev->gro_disable = 1;
return 0;
}

for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) {
struct qede_agg_info *tpa_info = &rxq->tpa_info[i];
struct sw_rx_data *replace_buf = &tpa_info->buffer;
Expand Down Expand Up @@ -1269,6 +1263,7 @@ static int qede_alloc_sge_mem(struct qede_dev *edev, struct qede_rx_queue *rxq)
err:
qede_free_sge_mem(edev, rxq);
edev->gro_disable = 1;
edev->ndev->features &= ~NETIF_F_GRO_HW;
return -ENOMEM;
}

Expand Down Expand Up @@ -1511,7 +1506,7 @@ static void qede_init_fp(struct qede_dev *edev)
edev->ndev->name, queue_id);
}

edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO);
edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
}

static int qede_set_real_num_queues(struct qede_dev *edev)
Expand Down
3 changes: 3 additions & 0 deletions include/linux/netdev_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ enum {
NETIF_F_HW_ESP_TX_CSUM_BIT, /* ESP with TX checksum offload */
NETIF_F_RX_UDP_TUNNEL_PORT_BIT, /* Offload of RX port for UDP tunnels */

NETIF_F_GRO_HW_BIT, /* Hardware Generic receive offload */

/*
* Add your fresh new feature above and remember to update
* netdev_features_strings[] in net/core/ethtool.c and maybe
Expand All @@ -97,6 +99,7 @@ enum {
#define NETIF_F_FRAGLIST __NETIF_F(FRAGLIST)
#define NETIF_F_FSO __NETIF_F(FSO)
#define NETIF_F_GRO __NETIF_F(GRO)
#define NETIF_F_GRO_HW __NETIF_F(GRO_HW)
#define NETIF_F_GSO __NETIF_F(GSO)
#define NETIF_F_GSO_ROBUST __NETIF_F(GSO_ROBUST)
#define NETIF_F_HIGHDMA __NETIF_F(HIGHDMA)
Expand Down
30 changes: 30 additions & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,23 @@ void dev_disable_lro(struct net_device *dev)
}
EXPORT_SYMBOL(dev_disable_lro);

/**
* dev_disable_gro_hw - disable HW Generic Receive Offload on a device
* @dev: device
*
* Disable HW Generic Receive Offload (GRO_HW) on a net device. Must be
* called under RTNL. This is needed if Generic XDP is installed on
* the device.
*/
static void dev_disable_gro_hw(struct net_device *dev)
{
dev->wanted_features &= ~NETIF_F_GRO_HW;
netdev_update_features(dev);

if (unlikely(dev->features & NETIF_F_GRO_HW))
netdev_WARN(dev, "failed to disable GRO_HW!\n");
}

static int call_netdevice_notifier(struct notifier_block *nb, unsigned long val,
struct net_device *dev)
{
Expand Down Expand Up @@ -4564,6 +4581,7 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)
} else if (new && !old) {
static_key_slow_inc(&generic_xdp_needed);
dev_disable_lro(dev);
dev_disable_gro_hw(dev);
}
break;

Expand Down Expand Up @@ -7424,6 +7442,18 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
features &= ~dev->gso_partial_features;
}

if (!(features & NETIF_F_RXCSUM)) {
/* NETIF_F_GRO_HW implies doing RXCSUM since every packet
* successfully merged by hardware must also have the
* checksum verified by hardware. If the user does not
* want to enable RXCSUM, logically, we should disable GRO_HW.
*/
if (features & NETIF_F_GRO_HW) {
netdev_dbg(dev, "Dropping NETIF_F_GRO_HW since no RXCSUM feature.\n");
features &= ~NETIF_F_GRO_HW;
}
}

return features;
}

Expand Down
1 change: 1 addition & 0 deletions net/core/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_LLTX_BIT] = "tx-lockless",
[NETIF_F_NETNS_LOCAL_BIT] = "netns-local",
[NETIF_F_GRO_BIT] = "rx-gro",
[NETIF_F_GRO_HW_BIT] = "rx-gro-hw",
[NETIF_F_LRO_BIT] = "rx-lro",

[NETIF_F_TSO_BIT] = "tx-tcp-segmentation",
Expand Down

0 comments on commit e9c5a10

Please sign in to comment.