| From f4830311b5c33b370737dd13754c62c0563a396e Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 19 Dec 2019 18:28:10 -0800 |
| Subject: hv_netvsc: Fix unwanted rx_table reset |
| |
| From: Haiyang Zhang <haiyangz@microsoft.com> |
| |
| [ Upstream commit b0689faa8efc5a3391402d7ae93bd373b7248e51 ] |
| |
| In existing code, the receive indirection table, rx_table, is in |
| struct rndis_device, which will be reset when changing MTU, ringparam, |
| etc. User configured receive indirection table values will be lost. |
| |
| To fix this, move rx_table to struct net_device_context, and check |
| netif_is_rxfh_configured(), so rx_table will be set to default only |
| if no user configured value. |
| |
| Fixes: ff4a44199012 ("netvsc: allow get/set of RSS indirection table") |
| Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/hyperv/hyperv_net.h | 3 ++- |
| drivers/net/hyperv/netvsc_drv.c | 4 ++-- |
| drivers/net/hyperv/rndis_filter.c | 10 +++++++--- |
| 3 files changed, 11 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h |
| index fb547f37af1e..e74f2d1def80 100644 |
| --- a/drivers/net/hyperv/hyperv_net.h |
| +++ b/drivers/net/hyperv/hyperv_net.h |
| @@ -169,7 +169,6 @@ struct rndis_device { |
| |
| u8 hw_mac_adr[ETH_ALEN]; |
| u8 rss_key[NETVSC_HASH_KEYLEN]; |
| - u16 rx_table[ITAB_NUM]; |
| }; |
| |
| |
| @@ -938,6 +937,8 @@ struct net_device_context { |
| |
| u32 tx_table[VRSS_SEND_TAB_SIZE]; |
| |
| + u16 rx_table[ITAB_NUM]; |
| + |
| /* Ethtool settings */ |
| u8 duplex; |
| u32 speed; |
| diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c |
| index 963509add611..78e3e689a733 100644 |
| --- a/drivers/net/hyperv/netvsc_drv.c |
| +++ b/drivers/net/hyperv/netvsc_drv.c |
| @@ -1659,7 +1659,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, |
| rndis_dev = ndev->extension; |
| if (indir) { |
| for (i = 0; i < ITAB_NUM; i++) |
| - indir[i] = rndis_dev->rx_table[i]; |
| + indir[i] = ndc->rx_table[i]; |
| } |
| |
| if (key) |
| @@ -1689,7 +1689,7 @@ static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir, |
| return -EINVAL; |
| |
| for (i = 0; i < ITAB_NUM; i++) |
| - rndis_dev->rx_table[i] = indir[i]; |
| + ndc->rx_table[i] = indir[i]; |
| } |
| |
| if (!key) { |
| diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c |
| index e3d3c9097ff1..f81e58267a6e 100644 |
| --- a/drivers/net/hyperv/rndis_filter.c |
| +++ b/drivers/net/hyperv/rndis_filter.c |
| @@ -767,6 +767,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, |
| const u8 *rss_key, u16 flag) |
| { |
| struct net_device *ndev = rdev->ndev; |
| + struct net_device_context *ndc = netdev_priv(ndev); |
| struct rndis_request *request; |
| struct rndis_set_request *set; |
| struct rndis_set_complete *set_complete; |
| @@ -806,7 +807,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, |
| /* Set indirection table entries */ |
| itab = (u32 *)(rssp + 1); |
| for (i = 0; i < ITAB_NUM; i++) |
| - itab[i] = rdev->rx_table[i]; |
| + itab[i] = ndc->rx_table[i]; |
| |
| /* Set hask key values */ |
| keyp = (u8 *)((unsigned long)rssp + rssp->hashkey_offset); |
| @@ -1305,6 +1306,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, |
| struct netvsc_device_info *device_info) |
| { |
| struct net_device *net = hv_get_drvdata(dev); |
| + struct net_device_context *ndc = netdev_priv(net); |
| struct netvsc_device *net_device; |
| struct rndis_device *rndis_device; |
| struct ndis_recv_scale_cap rsscap; |
| @@ -1391,9 +1393,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, |
| /* We will use the given number of channels if available. */ |
| net_device->num_chn = min(net_device->max_chn, device_info->num_chn); |
| |
| - for (i = 0; i < ITAB_NUM; i++) |
| - rndis_device->rx_table[i] = ethtool_rxfh_indir_default( |
| + if (!netif_is_rxfh_configured(net)) { |
| + for (i = 0; i < ITAB_NUM; i++) |
| + ndc->rx_table[i] = ethtool_rxfh_indir_default( |
| i, net_device->num_chn); |
| + } |
| |
| atomic_set(&net_device->open_chn, 1); |
| vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); |
| -- |
| 2.20.1 |
| |