Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp2007253imm; Thu, 24 May 2018 04:25:13 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqaJxlMjK06Rx5xzPQl4l6WAi7C0nO1T5H40IdCwBHG2zhFgHysebKeXB8rMXyjbshmyaAc X-Received: by 2002:a63:9612:: with SMTP id c18-v6mr5526554pge.361.1527161113727; Thu, 24 May 2018 04:25:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527161113; cv=none; d=google.com; s=arc-20160816; b=td3wqdAf5yOTFjoz4COAFSbxe/FAxd1tidOTz7addPRLzRw2+22xgLXXYXxRVDcLno 4cBCQT3k7IX3giTKmimk01OqSPAxAfUN8PVzb7uEz+SLMk4KJzwXVOYegcnEM0wuYPyI JBveVpErWUR6DhXf+ClhiJLdOMsvqmsAVtJqJqVafo46VdshOJRtjhm8v7ETui7YVToK rEw4fwyeFrIDJyuU/iE/VtovF9///DjDQDFUGx3m+rSQkn1F5KsRh47ZAShtSVchONww yPXx4t8xuLi1y8PstTdqBGyYZiTkXaCx4j8kDpT8+wVPfnpHFHsX5gGUPL9FxfctlG2N Ribg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=HWv/S1yt6eQ8Vy9MF7uDAZVDH5F/4hKCwBqeaqi3IK4=; b=AdW/Or0zMfKSnwtMzeOky0ozyDunSzK1me9UoPumQaPFpWTcQN/3loQ9gwcVXbuklO 9KC5vPNom75xWGWDAnB6qIDlWkbWjITbOKgfDNRLP+VWeKxTSKSU4d8YPT3nKRJOWExn qUjyHJuLtpTjLOeQXJz0GFLdoNfCiEZmDzFj1ZGFnB8vaJF6A4pn/n/hnwXqOGq83stf JUsWV3+1ovPFuTZWEMrYw/mLxHegeO76VWW+ntugnfnFhkpYcKAcHQ8+//nvZmZUQ39D rponMC/bU9uFg7FdamptsyawY8brYFCWdn2d+80z8UP7bWfX5TE+1YbL6WdRv17BKgh9 to9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=OUFgHwEw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o12-v6si20982414plg.463.2018.05.24.04.24.58; Thu, 24 May 2018 04:25:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=OUFgHwEw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S968760AbeEXLYJ (ORCPT + 99 others); Thu, 24 May 2018 07:24:09 -0400 Received: from mail.kernel.org ([198.145.29.99]:48494 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S967440AbeEXJv5 (ORCPT ); Thu, 24 May 2018 05:51:57 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id BA9D320847; Thu, 24 May 2018 09:51:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1527155517; bh=HKHCPhHbfoyHCbUgP1RrYVFSmSPfKakDXkVuhjY7xhQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OUFgHwEwTaJPgTr3va9I0rVHhvUw1TsIvAbDWqbI4ApjiyEdbYbot1va+z6OoOzsx SaeQz7fomwhm/ypRqge+to33KJkeemt7+3P66H2HW3gSw6kJAelQATSx3dCNO9jeuB O9sR0PniKVX2+jge45iHeobq0nsWnRh0LoB/t6nM= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Vitaly Kuznetsov , Haiyang Zhang , "David S. Miller" Subject: [PATCH 4.14 018/165] hv_netvsc: preserve hw_features on mtu/channels/ringparam changes Date: Thu, 24 May 2018 11:37:04 +0200 Message-Id: <20180524093622.719368142@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180524093621.979359379@linuxfoundation.org> References: <20180524093621.979359379@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ From: Vitaly Kuznetsov [ Commit aefd80e874e98a864915df5b7d90824a4340b450 upstream. ] rndis_filter_device_add() is called both from netvsc_probe() when we initially create the device and from set channels/mtu/ringparam routines where we basically remove the device and add it back. hw_features is reset in rndis_filter_device_add() and filled with host data. However, we lose all additional flags which are set outside of the driver, e.g. register_netdevice() adds NETIF_F_SOFT_FEATURES and many others. Unfortunately, calls to rndis_{query_hwcaps(), _set_offload_params()} calls cannot be avoided on every RNDIS reset: host expects us to set required features explicitly. Moreover, in theory hardware capabilities can change and we need to reflect the change in hw_features. Reset net->hw_features bits according to host data in rndis_netdev_set_hwcaps(), clear corresponding feature bits from net->features in case some features went missing (will never happen in real life I guess but let's be consistent). Signed-off-by: Vitaly Kuznetsov Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/hyperv_net.h | 4 + drivers/net/hyperv/netvsc_drv.c | 2 drivers/net/hyperv/rndis_filter.c | 136 +++++++++++++++++++++----------------- 3 files changed, 83 insertions(+), 59 deletions(-) --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -659,6 +659,10 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_ID 0xcafe #define NETVSC_SEND_BUFFER_ID 0 +#define NETVSC_SUPPORTED_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | \ + NETIF_F_TSO | NETIF_F_IPV6_CSUM | \ + NETIF_F_TSO6) + #define VRSS_SEND_TAB_SIZE 16 /* must be power of 2 */ #define VRSS_CHANNEL_MAX 64 #define VRSS_CHANNEL_DEFAULT 8 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1956,7 +1956,7 @@ static int netvsc_probe(struct hv_device memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); - /* hw_features computed in rndis_filter_device_add */ + /* hw_features computed in rndis_netdev_set_hwcaps() */ net->features = net->hw_features | NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1131,69 +1131,20 @@ unlock: rtnl_unlock(); } -struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, - struct netvsc_device_info *device_info) +static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, + struct netvsc_device *nvdev) { - struct net_device *net = hv_get_drvdata(dev); + struct net_device *net = rndis_device->ndev; struct net_device_context *net_device_ctx = netdev_priv(net); - struct netvsc_device *net_device; - struct rndis_device *rndis_device; struct ndis_offload hwcaps; struct ndis_offload_params offloads; - struct ndis_recv_scale_cap rsscap; - u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); unsigned int gso_max_size = GSO_MAX_SIZE; - u32 mtu, size; - const struct cpumask *node_cpu_mask; - u32 num_possible_rss_qs; - int i, ret; - - rndis_device = get_rndis_device(); - if (!rndis_device) - return ERR_PTR(-ENODEV); - - /* - * Let the inner driver handle this first to create the netvsc channel - * NOTE! Once the channel is created, we may get a receive callback - * (RndisFilterOnReceive()) before this call is completed - */ - net_device = netvsc_device_add(dev, device_info); - if (IS_ERR(net_device)) { - kfree(rndis_device); - return net_device; - } - - /* Initialize the rndis device */ - net_device->max_chn = 1; - net_device->num_chn = 1; - - net_device->extension = rndis_device; - rndis_device->ndev = net; - - /* Send the rndis initialization message */ - ret = rndis_filter_init_device(rndis_device, net_device); - if (ret != 0) - goto err_dev_remv; - - /* Get the MTU from the host */ - size = sizeof(u32); - ret = rndis_filter_query_device(rndis_device, net_device, - RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, - &mtu, &size); - if (ret == 0 && size == sizeof(u32) && mtu < net->mtu) - net->mtu = mtu; - - /* Get the mac address */ - ret = rndis_filter_query_device_mac(rndis_device, net_device); - if (ret != 0) - goto err_dev_remv; - - memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); + int ret; /* Find HW offload capabilities */ - ret = rndis_query_hwcaps(rndis_device, net_device, &hwcaps); + ret = rndis_query_hwcaps(rndis_device, nvdev, &hwcaps); if (ret != 0) - goto err_dev_remv; + return ret; /* A value of zero means "no change"; now turn on what we want. */ memset(&offloads, 0, sizeof(struct ndis_offload_params)); @@ -1201,8 +1152,12 @@ struct netvsc_device *rndis_filter_devic /* Linux does not care about IP checksum, always does in kernel */ offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED; + /* Reset previously set hw_features flags */ + net->hw_features &= ~NETVSC_SUPPORTED_HW_FEATURES; + net_device_ctx->tx_checksum_mask = 0; + /* Compute tx offload settings based on hw capabilities */ - net->hw_features = NETIF_F_RXCSUM; + net->hw_features |= NETIF_F_RXCSUM; if ((hwcaps.csum.ip4_txcsum & NDIS_TXCSUM_ALL_TCP4) == NDIS_TXCSUM_ALL_TCP4) { /* Can checksum TCP */ @@ -1246,10 +1201,75 @@ struct netvsc_device *rndis_filter_devic } } + /* In case some hw_features disappeared we need to remove them from + * net->features list as they're no longer supported. + */ + net->features &= ~NETVSC_SUPPORTED_HW_FEATURES | net->hw_features; + netif_set_gso_max_size(net, gso_max_size); - ret = rndis_filter_set_offload_params(net, net_device, &offloads); - if (ret) + ret = rndis_filter_set_offload_params(net, nvdev, &offloads); + + return ret; +} + +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 netvsc_device *net_device; + struct rndis_device *rndis_device; + struct ndis_recv_scale_cap rsscap; + u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); + u32 mtu, size; + const struct cpumask *node_cpu_mask; + u32 num_possible_rss_qs; + int i, ret; + + rndis_device = get_rndis_device(); + if (!rndis_device) + return ERR_PTR(-ENODEV); + + /* Let the inner driver handle this first to create the netvsc channel + * NOTE! Once the channel is created, we may get a receive callback + * (RndisFilterOnReceive()) before this call is completed + */ + net_device = netvsc_device_add(dev, device_info); + if (IS_ERR(net_device)) { + kfree(rndis_device); + return net_device; + } + + /* Initialize the rndis device */ + net_device->max_chn = 1; + net_device->num_chn = 1; + + net_device->extension = rndis_device; + rndis_device->ndev = net; + + /* Send the rndis initialization message */ + ret = rndis_filter_init_device(rndis_device, net_device); + if (ret != 0) + goto err_dev_remv; + + /* Get the MTU from the host */ + size = sizeof(u32); + ret = rndis_filter_query_device(rndis_device, net_device, + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, + &mtu, &size); + if (ret == 0 && size == sizeof(u32) && mtu < net->mtu) + net->mtu = mtu; + + /* Get the mac address */ + ret = rndis_filter_query_device_mac(rndis_device, net_device); + if (ret != 0) + goto err_dev_remv; + + memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); + + /* Query and set hardware capabilities */ + ret = rndis_netdev_set_hwcaps(rndis_device, net_device); + if (ret != 0) goto err_dev_remv; rndis_filter_query_device_link_status(rndis_device, net_device);