diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 30 | 
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e8fce6d715ef..39dddcd8b3cb 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -435,7 +435,7 @@ static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,  		skb_frag_t *frag = skb_shinfo(skb)->frags + i;  		slots_used += fill_pg_buf(skb_frag_page(frag), -					frag->page_offset, +					skb_frag_off(frag),  					skb_frag_size(frag), &pb[slots_used]);  	}  	return slots_used; @@ -449,7 +449,7 @@ static int count_skb_frag_slots(struct sk_buff *skb)  	for (i = 0; i < frags; i++) {  		skb_frag_t *frag = skb_shinfo(skb)->frags + i;  		unsigned long size = skb_frag_size(frag); -		unsigned long offset = frag->page_offset; +		unsigned long offset = skb_frag_off(frag);  		/* Skip unused frames from start of page */  		offset &= ~PAGE_MASK; @@ -1785,13 +1785,15 @@ static int netvsc_set_features(struct net_device *ndev,  	netdev_features_t change = features ^ ndev->features;  	struct net_device_context *ndevctx = netdev_priv(ndev);  	struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); +	struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev);  	struct ndis_offload_params offloads; +	int ret = 0;  	if (!nvdev || nvdev->destroy)  		return -ENODEV;  	if (!(change & NETIF_F_LRO)) -		return 0; +		goto syncvf;  	memset(&offloads, 0, sizeof(struct ndis_offload_params)); @@ -1803,7 +1805,19 @@ static int netvsc_set_features(struct net_device *ndev,  		offloads.rsc_ip_v6 = NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED;  	} -	return rndis_filter_set_offload_params(ndev, nvdev, &offloads); +	ret = rndis_filter_set_offload_params(ndev, nvdev, &offloads); + +	if (ret) +		features ^= NETIF_F_LRO; + +syncvf: +	if (!vf_netdev) +		return ret; + +	vf_netdev->wanted_features = features; +	netdev_update_features(vf_netdev); + +	return ret;  }  static u32 netvsc_get_msglevel(struct net_device *ndev) @@ -2181,6 +2195,10 @@ static int netvsc_register_vf(struct net_device *vf_netdev)  	dev_hold(vf_netdev);  	rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev); + +	vf_netdev->wanted_features = ndev->features; +	netdev_update_features(vf_netdev); +  	return NOTIFY_OK;  } @@ -2313,8 +2331,8 @@ static int netvsc_probe(struct hv_device *dev,  	/* 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; +		NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX | +		NETIF_F_HW_VLAN_CTAG_RX;  	net->vlan_features = net->features;  	netdev_lockdep_set_classes(net);  |