forked from luck/tmp_suning_uos_patched
Three patches from Haiyang Zhang to fix settings hash key using ethtool,
and Adrian Vladu's first patch fixing a few spelling mistakes. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE4n5dijQDou9mhzu83qZv95d3LNwFAlxIsZEACgkQ3qZv95d3 LNyoBA/+Oa9dcAo5hMS4jiC7kF3s/G1E12Zb3RRZEuUEDLsFcg3OhDJquHHsiifA j5yd1/GJnV2RiGhTeEhsLE+efCKjcfmEUx76/GYSCskxAHnG244JD6nemmuaxmUq czegsT1TNg00w6Cx36C/9DQ3PApgBImsXSyhSKy1JrAYaYT9QxOsD41R0FrAWig9 d3w3hAsy+63yFcyP6VYivA8/ndj+kW7rscZ0cfEY+1DwW4gBR5v1wUco7UuffS55 2fUQNT6z+ptrOT4pCxGe8CRlJmefGWBcIfiso94DdMgtbEZHZNdE9qytYUn9OO3f 6SKh7qYNrIuS/gYrKqZufRUd5UIulaWGvNkqxS+DvrncWbTQUOygtuW5Av1bcNg5 Xwe3XGjOzwrSErOqDAW9XfbfA5Hx0ZOnihiXOByGOfWgC0C5+h2QOTVgdyYDRGm3 DaESVCsGLnlMX8kkB+hUa2YFoY8XWApubx+yHeHDHLjxYOM5kOpDF4tHjmKYt1si Ym4ZZd0iZKsHRQHSePAfh7SaTxATVltne7cIBSD4q3j+JfM+n0uDikadnUsue0Vp e6ugnNcO530NI/AbHoezfm2k/Wh1eQ1wOMsSlT5qyhG4qP8azxGMUQai1fFgQBtF txryAbMq70/gbwfbUnuyFxgpE+D/B26/5us/y1xxxRG61vVezp4= =GKPZ -----END PGP SIGNATURE----- Merge tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux Sasha Levin says: ==================== Hyper-V hv_netvsc commits for 5.0 Three patches from Haiyang Zhang to fix settings hash key using ethtool, and Adrian Vladu's first patch fixing a few spelling mistakes. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b8812920b5
|
@ -144,6 +144,8 @@ struct hv_netvsc_packet {
|
|||
u32 total_data_buflen;
|
||||
};
|
||||
|
||||
#define NETVSC_HASH_KEYLEN 40
|
||||
|
||||
struct netvsc_device_info {
|
||||
unsigned char mac_adr[ETH_ALEN];
|
||||
u32 num_chn;
|
||||
|
@ -151,6 +153,8 @@ struct netvsc_device_info {
|
|||
u32 recv_sections;
|
||||
u32 send_section_size;
|
||||
u32 recv_section_size;
|
||||
|
||||
u8 rss_key[NETVSC_HASH_KEYLEN];
|
||||
};
|
||||
|
||||
enum rndis_device_state {
|
||||
|
@ -160,8 +164,6 @@ enum rndis_device_state {
|
|||
RNDIS_DEV_DATAINITIALIZED,
|
||||
};
|
||||
|
||||
#define NETVSC_HASH_KEYLEN 40
|
||||
|
||||
struct rndis_device {
|
||||
struct net_device *ndev;
|
||||
|
||||
|
@ -209,7 +211,9 @@ int netvsc_recv_callback(struct net_device *net,
|
|||
void netvsc_channel_cb(void *context);
|
||||
int netvsc_poll(struct napi_struct *napi, int budget);
|
||||
|
||||
int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev);
|
||||
int rndis_set_subchannel(struct net_device *ndev,
|
||||
struct netvsc_device *nvdev,
|
||||
struct netvsc_device_info *dev_info);
|
||||
int rndis_filter_open(struct netvsc_device *nvdev);
|
||||
int rndis_filter_close(struct netvsc_device *nvdev);
|
||||
struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
|
||||
|
@ -1177,7 +1181,7 @@ enum ndis_per_pkt_info_type {
|
|||
|
||||
enum rndis_per_pkt_info_interal_type {
|
||||
RNDIS_PKTINFO_ID = 1,
|
||||
/* Add more memebers here */
|
||||
/* Add more members here */
|
||||
|
||||
RNDIS_PKTINFO_MAX
|
||||
};
|
||||
|
|
|
@ -84,7 +84,7 @@ static void netvsc_subchan_work(struct work_struct *w)
|
|||
|
||||
rdev = nvdev->extension;
|
||||
if (rdev) {
|
||||
ret = rndis_set_subchannel(rdev->ndev, nvdev);
|
||||
ret = rndis_set_subchannel(rdev->ndev, nvdev, NULL);
|
||||
if (ret == 0) {
|
||||
netif_device_attach(rdev->ndev);
|
||||
} else {
|
||||
|
@ -1331,7 +1331,7 @@ void netvsc_channel_cb(void *context)
|
|||
prefetch(hv_get_ring_buffer(rbi) + rbi->priv_read_index);
|
||||
|
||||
if (napi_schedule_prep(&nvchan->napi)) {
|
||||
/* disable interupts from host */
|
||||
/* disable interrupts from host */
|
||||
hv_begin_read(rbi);
|
||||
|
||||
__napi_schedule_irqoff(&nvchan->napi);
|
||||
|
|
|
@ -370,7 +370,7 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
|
|||
{
|
||||
int j = 0;
|
||||
|
||||
/* Deal with compund pages by ignoring unused part
|
||||
/* Deal with compound pages by ignoring unused part
|
||||
* of the page.
|
||||
*/
|
||||
page += (offset >> PAGE_SHIFT);
|
||||
|
@ -858,6 +858,39 @@ static void netvsc_get_channels(struct net_device *net,
|
|||
}
|
||||
}
|
||||
|
||||
/* Alloc struct netvsc_device_info, and initialize it from either existing
|
||||
* struct netvsc_device, or from default values.
|
||||
*/
|
||||
static struct netvsc_device_info *netvsc_devinfo_get
|
||||
(struct netvsc_device *nvdev)
|
||||
{
|
||||
struct netvsc_device_info *dev_info;
|
||||
|
||||
dev_info = kzalloc(sizeof(*dev_info), GFP_ATOMIC);
|
||||
|
||||
if (!dev_info)
|
||||
return NULL;
|
||||
|
||||
if (nvdev) {
|
||||
dev_info->num_chn = nvdev->num_chn;
|
||||
dev_info->send_sections = nvdev->send_section_cnt;
|
||||
dev_info->send_section_size = nvdev->send_section_size;
|
||||
dev_info->recv_sections = nvdev->recv_section_cnt;
|
||||
dev_info->recv_section_size = nvdev->recv_section_size;
|
||||
|
||||
memcpy(dev_info->rss_key, nvdev->extension->rss_key,
|
||||
NETVSC_HASH_KEYLEN);
|
||||
} else {
|
||||
dev_info->num_chn = VRSS_CHANNEL_DEFAULT;
|
||||
dev_info->send_sections = NETVSC_DEFAULT_TX;
|
||||
dev_info->send_section_size = NETVSC_SEND_SECTION_SIZE;
|
||||
dev_info->recv_sections = NETVSC_DEFAULT_RX;
|
||||
dev_info->recv_section_size = NETVSC_RECV_SECTION_SIZE;
|
||||
}
|
||||
|
||||
return dev_info;
|
||||
}
|
||||
|
||||
static int netvsc_detach(struct net_device *ndev,
|
||||
struct netvsc_device *nvdev)
|
||||
{
|
||||
|
@ -909,7 +942,7 @@ static int netvsc_attach(struct net_device *ndev,
|
|||
return PTR_ERR(nvdev);
|
||||
|
||||
if (nvdev->num_chn > 1) {
|
||||
ret = rndis_set_subchannel(ndev, nvdev);
|
||||
ret = rndis_set_subchannel(ndev, nvdev, dev_info);
|
||||
|
||||
/* if unavailable, just proceed with one queue */
|
||||
if (ret) {
|
||||
|
@ -943,7 +976,7 @@ static int netvsc_set_channels(struct net_device *net,
|
|||
struct net_device_context *net_device_ctx = netdev_priv(net);
|
||||
struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
|
||||
unsigned int orig, count = channels->combined_count;
|
||||
struct netvsc_device_info device_info;
|
||||
struct netvsc_device_info *device_info;
|
||||
int ret;
|
||||
|
||||
/* We do not support separate count for rx, tx, or other */
|
||||
|
@ -962,24 +995,26 @@ static int netvsc_set_channels(struct net_device *net,
|
|||
|
||||
orig = nvdev->num_chn;
|
||||
|
||||
memset(&device_info, 0, sizeof(device_info));
|
||||
device_info.num_chn = count;
|
||||
device_info.send_sections = nvdev->send_section_cnt;
|
||||
device_info.send_section_size = nvdev->send_section_size;
|
||||
device_info.recv_sections = nvdev->recv_section_cnt;
|
||||
device_info.recv_section_size = nvdev->recv_section_size;
|
||||
device_info = netvsc_devinfo_get(nvdev);
|
||||
|
||||
if (!device_info)
|
||||
return -ENOMEM;
|
||||
|
||||
device_info->num_chn = count;
|
||||
|
||||
ret = netvsc_detach(net, nvdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = netvsc_attach(net, &device_info);
|
||||
ret = netvsc_attach(net, device_info);
|
||||
if (ret) {
|
||||
device_info.num_chn = orig;
|
||||
if (netvsc_attach(net, &device_info))
|
||||
device_info->num_chn = orig;
|
||||
if (netvsc_attach(net, device_info))
|
||||
netdev_err(net, "restoring channel setting failed\n");
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(device_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1048,48 +1083,45 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
|
|||
struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev);
|
||||
struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
|
||||
int orig_mtu = ndev->mtu;
|
||||
struct netvsc_device_info device_info;
|
||||
struct netvsc_device_info *device_info;
|
||||
int ret = 0;
|
||||
|
||||
if (!nvdev || nvdev->destroy)
|
||||
return -ENODEV;
|
||||
|
||||
device_info = netvsc_devinfo_get(nvdev);
|
||||
|
||||
if (!device_info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Change MTU of underlying VF netdev first. */
|
||||
if (vf_netdev) {
|
||||
ret = dev_set_mtu(vf_netdev, mtu);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&device_info, 0, sizeof(device_info));
|
||||
device_info.num_chn = nvdev->num_chn;
|
||||
device_info.send_sections = nvdev->send_section_cnt;
|
||||
device_info.send_section_size = nvdev->send_section_size;
|
||||
device_info.recv_sections = nvdev->recv_section_cnt;
|
||||
device_info.recv_section_size = nvdev->recv_section_size;
|
||||
|
||||
ret = netvsc_detach(ndev, nvdev);
|
||||
if (ret)
|
||||
goto rollback_vf;
|
||||
|
||||
ndev->mtu = mtu;
|
||||
|
||||
ret = netvsc_attach(ndev, &device_info);
|
||||
if (ret)
|
||||
goto rollback;
|
||||
ret = netvsc_attach(ndev, device_info);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
/* Attempt rollback to original MTU */
|
||||
ndev->mtu = orig_mtu;
|
||||
|
||||
if (netvsc_attach(ndev, &device_info))
|
||||
if (netvsc_attach(ndev, device_info))
|
||||
netdev_err(ndev, "restoring mtu failed\n");
|
||||
rollback_vf:
|
||||
if (vf_netdev)
|
||||
dev_set_mtu(vf_netdev, orig_mtu);
|
||||
|
||||
out:
|
||||
kfree(device_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1674,7 +1706,7 @@ static int netvsc_set_ringparam(struct net_device *ndev,
|
|||
{
|
||||
struct net_device_context *ndevctx = netdev_priv(ndev);
|
||||
struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
|
||||
struct netvsc_device_info device_info;
|
||||
struct netvsc_device_info *device_info;
|
||||
struct ethtool_ringparam orig;
|
||||
u32 new_tx, new_rx;
|
||||
int ret = 0;
|
||||
|
@ -1694,26 +1726,29 @@ static int netvsc_set_ringparam(struct net_device *ndev,
|
|||
new_rx == orig.rx_pending)
|
||||
return 0; /* no change */
|
||||
|
||||
memset(&device_info, 0, sizeof(device_info));
|
||||
device_info.num_chn = nvdev->num_chn;
|
||||
device_info.send_sections = new_tx;
|
||||
device_info.send_section_size = nvdev->send_section_size;
|
||||
device_info.recv_sections = new_rx;
|
||||
device_info.recv_section_size = nvdev->recv_section_size;
|
||||
device_info = netvsc_devinfo_get(nvdev);
|
||||
|
||||
if (!device_info)
|
||||
return -ENOMEM;
|
||||
|
||||
device_info->send_sections = new_tx;
|
||||
device_info->recv_sections = new_rx;
|
||||
|
||||
ret = netvsc_detach(ndev, nvdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = netvsc_attach(ndev, &device_info);
|
||||
ret = netvsc_attach(ndev, device_info);
|
||||
if (ret) {
|
||||
device_info.send_sections = orig.tx_pending;
|
||||
device_info.recv_sections = orig.rx_pending;
|
||||
device_info->send_sections = orig.tx_pending;
|
||||
device_info->recv_sections = orig.rx_pending;
|
||||
|
||||
if (netvsc_attach(ndev, &device_info))
|
||||
if (netvsc_attach(ndev, device_info))
|
||||
netdev_err(ndev, "restoring ringparam failed");
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(device_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2088,7 +2123,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
|
|||
if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* if syntihetic interface is a different namespace,
|
||||
/* if synthetic interface is a different namespace,
|
||||
* then move the VF to that namespace; join will be
|
||||
* done again in that context.
|
||||
*/
|
||||
|
@ -2167,7 +2202,7 @@ static int netvsc_probe(struct hv_device *dev,
|
|||
{
|
||||
struct net_device *net = NULL;
|
||||
struct net_device_context *net_device_ctx;
|
||||
struct netvsc_device_info device_info;
|
||||
struct netvsc_device_info *device_info = NULL;
|
||||
struct netvsc_device *nvdev;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
|
@ -2214,21 +2249,21 @@ static int netvsc_probe(struct hv_device *dev,
|
|||
netif_set_real_num_rx_queues(net, 1);
|
||||
|
||||
/* Notify the netvsc driver of the new device */
|
||||
memset(&device_info, 0, sizeof(device_info));
|
||||
device_info.num_chn = VRSS_CHANNEL_DEFAULT;
|
||||
device_info.send_sections = NETVSC_DEFAULT_TX;
|
||||
device_info.send_section_size = NETVSC_SEND_SECTION_SIZE;
|
||||
device_info.recv_sections = NETVSC_DEFAULT_RX;
|
||||
device_info.recv_section_size = NETVSC_RECV_SECTION_SIZE;
|
||||
device_info = netvsc_devinfo_get(NULL);
|
||||
|
||||
nvdev = rndis_filter_device_add(dev, &device_info);
|
||||
if (!device_info) {
|
||||
ret = -ENOMEM;
|
||||
goto devinfo_failed;
|
||||
}
|
||||
|
||||
nvdev = rndis_filter_device_add(dev, device_info);
|
||||
if (IS_ERR(nvdev)) {
|
||||
ret = PTR_ERR(nvdev);
|
||||
netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
|
||||
goto rndis_failed;
|
||||
}
|
||||
|
||||
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
|
||||
memcpy(net->dev_addr, device_info->mac_adr, ETH_ALEN);
|
||||
|
||||
/* We must get rtnl lock before scheduling nvdev->subchan_work,
|
||||
* otherwise netvsc_subchan_work() can get rtnl lock first and wait
|
||||
|
@ -2236,7 +2271,7 @@ static int netvsc_probe(struct hv_device *dev,
|
|||
* netvsc_probe() can't get rtnl lock and as a result vmbus_onoffer()
|
||||
* -> ... -> device_add() -> ... -> __device_attach() can't get
|
||||
* the device lock, so all the subchannels can't be processed --
|
||||
* finally netvsc_subchan_work() hangs for ever.
|
||||
* finally netvsc_subchan_work() hangs forever.
|
||||
*/
|
||||
rtnl_lock();
|
||||
|
||||
|
@ -2266,12 +2301,16 @@ static int netvsc_probe(struct hv_device *dev,
|
|||
|
||||
list_add(&net_device_ctx->list, &netvsc_dev_list);
|
||||
rtnl_unlock();
|
||||
|
||||
kfree(device_info);
|
||||
return 0;
|
||||
|
||||
register_failed:
|
||||
rtnl_unlock();
|
||||
rndis_filter_device_remove(dev, nvdev);
|
||||
rndis_failed:
|
||||
kfree(device_info);
|
||||
devinfo_failed:
|
||||
free_percpu(net_device_ctx->vf_stats);
|
||||
no_stats:
|
||||
hv_set_drvdata(dev, NULL);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -1121,7 +1134,9 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
|
|||
* This breaks overlap of processing the host message for the
|
||||
* new primary channel with the initialization of sub-channels.
|
||||
*/
|
||||
int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev)
|
||||
int rndis_set_subchannel(struct net_device *ndev,
|
||||
struct netvsc_device *nvdev,
|
||||
struct netvsc_device_info *dev_info)
|
||||
{
|
||||
struct nvsp_message *init_packet = &nvdev->channel_init_pkt;
|
||||
struct net_device_context *ndev_ctx = netdev_priv(ndev);
|
||||
|
@ -1161,8 +1176,11 @@ int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev)
|
|||
wait_event(nvdev->subchan_open,
|
||||
atomic_read(&nvdev->open_chn) == nvdev->num_chn);
|
||||
|
||||
/* ignore failues from setting rss parameters, still have channels */
|
||||
rndis_filter_set_rss_param(rdev, netvsc_hash_key);
|
||||
/* ignore failures from setting rss parameters, still have channels */
|
||||
if (dev_info)
|
||||
rndis_filter_set_rss_param(rdev, dev_info->rss_key);
|
||||
else
|
||||
rndis_filter_set_rss_param(rdev, netvsc_hash_key);
|
||||
|
||||
netif_set_real_num_tx_queues(ndev, nvdev->num_chn);
|
||||
netif_set_real_num_rx_queues(ndev, nvdev->num_chn);
|
||||
|
|
Loading…
Reference in New Issue
Block a user