From: Haiyang Zhang <haiya...@microsoft.com>

[ Upstream commit b4a10c750424e01b5e37372fef0a574ebf7b56c3 ]

Hyper-V hosts require us to disable RSS before changing RSS key,
otherwise the changing request will fail. This patch fixes the
coding error.

Fixes: ff4a44199012 ("netvsc: allow get/set of RSS indirection table")
Reported-by: Wei Hu <w...@microsoft.com>
Signed-off-by: Haiyang Zhang <haiya...@microsoft.com>
Reviewed-by: Michael Kelley <mikel...@microsoft.com>
[sl: fix up subject line]
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/net/hyperv/rndis_filter.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/net/hyperv/rndis_filter.c 
b/drivers/net/hyperv/rndis_filter.c
index 8b537a049c1e..a4661d396e3c 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -774,8 +774,8 @@ rndis_filter_set_offload_params(struct net_device *ndev,
        return ret;
 }
 
-int rndis_filter_set_rss_param(struct rndis_device *rdev,
-                              const u8 *rss_key)
+static int rndis_set_rss_param_msg(struct rndis_device *rdev,
+                                  const u8 *rss_key, u16 flag)
 {
        struct net_device *ndev = rdev->ndev;
        struct rndis_request *request;
@@ -804,7 +804,7 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev,
        rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS;
        rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
        rssp->hdr.size = sizeof(struct ndis_recv_scale_param);
-       rssp->flag = 0;
+       rssp->flag = flag;
        rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 |
                         NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 |
                         NDIS_HASH_TCP_IPV6;
@@ -829,9 +829,12 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev,
 
        wait_for_completion(&request->wait_event);
        set_complete = &request->response_msg.msg.set_complete;
-       if (set_complete->status == RNDIS_STATUS_SUCCESS)
-               memcpy(rdev->rss_key, rss_key, NETVSC_HASH_KEYLEN);
-       else {
+       if (set_complete->status == RNDIS_STATUS_SUCCESS) {
+               if (!(flag & NDIS_RSS_PARAM_FLAG_DISABLE_RSS) &&
+                   !(flag & NDIS_RSS_PARAM_FLAG_HASH_KEY_UNCHANGED))
+                       memcpy(rdev->rss_key, rss_key, NETVSC_HASH_KEYLEN);
+
+       } else {
                netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
                           set_complete->status);
                ret = -EINVAL;
@@ -842,6 +845,16 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev,
        return ret;
 }
 
+int rndis_filter_set_rss_param(struct rndis_device *rdev,
+                              const u8 *rss_key)
+{
+       /* Disable RSS before change */
+       rndis_set_rss_param_msg(rdev, rss_key,
+                               NDIS_RSS_PARAM_FLAG_DISABLE_RSS);
+
+       return rndis_set_rss_param_msg(rdev, rss_key, 0);
+}
+
 static int rndis_filter_query_device_link_status(struct rndis_device *dev,
                                                 struct netvsc_device 
*net_device)
 {
-- 
2.19.1

Reply via email to