[PATCH] hv_netvsc: fix comments

2016-09-23 Thread sthemmin
From: Stephen Hemminger 

Typo's and spelling errors. Also remove old comment from staging era.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |7 +++
 1 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 284b97b..d7c1cc6 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -433,7 +433,7 @@ struct nvsp_1_message_revoke_send_buffer {
  */
 struct nvsp_1_message_send_rndis_packet {
/*
-* This field is specified by RNIDS. They assume there's two different
+* This field is specified by RNDIS. They assume there's two different
 * channels of communication. However, the Network VSP only has one.
 * Therefore, the channel travels with the RNDIS packet.
 */
@@ -578,7 +578,7 @@ struct nvsp_5_send_indirect_table {
/* The number of entries in the send indirection table */
u32 count;
 
-   /* The offset of the send indireciton table from top of this struct.
+   /* The offset of the send indirection table from top of this struct.
 * The send indirection table tells which channel to put the send
 * traffic on. Each entry is a channel number.
 */
@@ -733,7 +733,6 @@ struct netvsc_device {
struct nvsp_message channel_init_pkt;
 
struct nvsp_message revoke_packet;
-   /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */
 
struct vmbus_channel *chn_table[VRSS_CHANNEL_MAX];
u32 send_table[VRSS_SEND_TAB_SIZE];
@@ -1238,7 +1237,7 @@ struct rndis_message {
u32 ndis_msg_type;
 
/* Total length of this message, from the beginning */
-   /* of the sruct rndis_message, in bytes. */
+   /* of the struct rndis_message, in bytes. */
u32 msg_len;
 
/* Actual message */
-- 
1.7.4.1



[PATCH 2/7] hv_netvsc: dev hold/put reference to VF

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

The netvsc driver holds a pointer to the virtual function network device if
managing SR-IOV association. In order to ensure that the VF network device
does not disappear, it should be using dev_hold/dev_put to get a reference
count.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 2360e70..e74dbcc 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1262,6 +1262,8 @@ static int netvsc_register_vf(struct net_device 
*vf_netdev)
 * Take a reference on the module.
 */
try_module_get(THIS_MODULE);
+
+   dev_hold(vf_netdev);
net_device_ctx->vf_netdev = vf_netdev;
return NOTIFY_OK;
 }
@@ -1376,6 +1378,7 @@ static int netvsc_unregister_vf(struct net_device 
*vf_netdev)
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
netvsc_inject_disable(net_device_ctx);
net_device_ctx->vf_netdev = NULL;
+   dev_put(vf_netdev);
module_put(THIS_MODULE);
return NOTIFY_OK;
 }
-- 
1.7.4.1



[PATCH 4/7] hv_netvsc: improve VF device matching

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

The code to associate netvsc and VF devices can be made less error prone
by using a better matching algorithms.

On registration, use the permanent address which avoids any possible
issues caused by device MAC address being changed. For all other callbacks,
search by the netdevice pointer value to ensure getting the correct
network device.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c |   60 +-
 1 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 849b566..8768219 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1215,22 +1215,44 @@ static void netvsc_free_netdev(struct net_device 
*netdev)
free_netdev(netdev);
 }
 
-static struct net_device *get_netvsc_net_device(char *mac)
+static struct net_device *get_netvsc_bymac(const u8 *mac)
 {
-   struct net_device *dev, *found = NULL;
+   struct net_device *dev;
 
ASSERT_RTNL();
 
for_each_netdev(_net, dev) {
-   if (memcmp(dev->dev_addr, mac, ETH_ALEN) == 0) {
-   if (dev->netdev_ops != _ops)
-   continue;
-   found = dev;
-   break;
-   }
+   if (dev->netdev_ops != _ops)
+   continue;   /* not a netvsc device */
+
+   if (ether_addr_equal(mac, dev->perm_addr))
+   return dev;
+   }
+
+   return NULL;
+}
+
+static struct net_device *get_netvsc_byref(const struct net_device *vf_netdev)
+{
+   struct net_device *dev;
+
+   ASSERT_RTNL();
+
+   for_each_netdev(_net, dev) {
+   struct net_device_context *net_device_ctx;
+
+   if (dev->netdev_ops != _ops)
+   continue;   /* not a netvsc device */
+
+   net_device_ctx = netdev_priv(dev);
+   if (net_device_ctx->nvdev == NULL)
+   continue;   /* device is removed */
+
+   if (net_device_ctx->vf_netdev == vf_netdev)
+   return dev; /* a match */
}
 
-   return found;
+   return NULL;
 }
 
 static int netvsc_register_vf(struct net_device *vf_netdev)
@@ -1239,12 +1261,15 @@ static int netvsc_register_vf(struct net_device 
*vf_netdev)
struct net_device_context *net_device_ctx;
struct netvsc_device *netvsc_dev;
 
+   if (vf_netdev->addr_len != ETH_ALEN)
+   return NOTIFY_DONE;
+
/*
 * We will use the MAC address to locate the synthetic interface to
 * associate with the VF interface. If we don't find a matching
 * synthetic interface, move on.
 */
-   ndev = get_netvsc_net_device(vf_netdev->dev_addr);
+   ndev = get_netvsc_bymac(vf_netdev->perm_addr);
if (!ndev)
return NOTIFY_DONE;
 
@@ -1284,16 +1309,13 @@ static int netvsc_vf_up(struct net_device *vf_netdev)
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;
 
-   ndev = get_netvsc_net_device(vf_netdev->dev_addr);
+   ndev = get_netvsc_byref(vf_netdev);
if (!ndev)
return NOTIFY_DONE;
 
net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;
 
-   if (!netvsc_dev || !net_device_ctx->vf_netdev)
-   return NOTIFY_DONE;
-
netdev_info(ndev, "VF up: %s\n", vf_netdev->name);
netvsc_inject_enable(net_device_ctx);
 
@@ -1322,16 +1344,13 @@ static int netvsc_vf_down(struct net_device *vf_netdev)
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;
 
-   ndev = get_netvsc_net_device(vf_netdev->dev_addr);
+   ndev = get_netvsc_byref(vf_netdev);
if (!ndev)
return NOTIFY_DONE;
 
net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;
 
-   if (!netvsc_dev || !net_device_ctx->vf_netdev)
-   return NOTIFY_DONE;
-
netdev_info(ndev, "VF down: %s\n", vf_netdev->name);
netvsc_inject_disable(net_device_ctx);
netvsc_switch_datapath(ndev, false);
@@ -1351,14 +1370,13 @@ static int netvsc_unregister_vf(struct net_device 
*vf_netdev)
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;
 
-   ndev = get_netvsc_net_device(vf_netdev->dev_addr);
+   ndev = get_netvsc_byref(vf_netdev);
if (!ndev)
return NOTIFY_DONE;
 
net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;
-   if (!netvsc_dev || !net_device_ctx->vf_netdev)
-   return NOTIFY_DONE;
+
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
netvsc_inject_disable(net_device_ctx);

[PATCH 5/7] hv_netvsc: use RCU to protect vf_netdev

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

The vf_netdev pointer in the netvsc device context can simply be protected
by RCU because network device destruction is already RCU synchronized.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |2 +-
 drivers/net/hyperv/netvsc_drv.c |   29 +++--
 2 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 284b97b..6b79487 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -695,7 +695,7 @@ struct net_device_context {
bool start_remove;
 
/* State to manage the associated VF interface. */
-   struct net_device *vf_netdev;
+   struct net_device __rcu *vf_netdev;
bool vf_inject;
atomic_t vf_use_cnt;
/* 1: allocated, serial number is valid. 0: not allocated */
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 8768219..dde17c0 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -667,8 +667,8 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 {
struct net_device *net = hv_get_drvdata(device_obj);
struct net_device_context *net_device_ctx = netdev_priv(net);
+   struct net_device *vf_netdev;
struct sk_buff *skb;
-   struct sk_buff *vf_skb;
struct netvsc_stats *rx_stats;
u32 bytes_recvd = packet->total_data_buflen;
int ret = 0;
@@ -676,9 +676,12 @@ int netvsc_recv_callback(struct hv_device *device_obj,
if (!net || net->reg_state != NETREG_REGISTERED)
return NVSP_STAT_FAIL;
 
-   if (READ_ONCE(net_device_ctx->vf_inject)) {
+   vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
+   if (vf_netdev) {
+   struct sk_buff *vf_skb;
+
atomic_inc(_device_ctx->vf_use_cnt);
-   if (!READ_ONCE(net_device_ctx->vf_inject)) {
+   if (!net_device_ctx->vf_inject) {
/*
 * We raced; just move on.
 */
@@ -694,13 +697,12 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 * the host). Deliver these via the VF interface
 * in the guest.
 */
-   vf_skb = netvsc_alloc_recv_skb(net_device_ctx->vf_netdev,
+   vf_skb = netvsc_alloc_recv_skb(vf_netdev,
   packet, csum_info, *data,
   vlan_tci);
if (vf_skb != NULL) {
-   ++net_device_ctx->vf_netdev->stats.rx_packets;
-   net_device_ctx->vf_netdev->stats.rx_bytes +=
-   bytes_recvd;
+   ++vf_netdev->stats.rx_packets;
+   vf_netdev->stats.rx_bytes += bytes_recvd;
netif_receive_skb(vf_skb);
} else {
++net->stats.rx_dropped;
@@ -1232,7 +1234,7 @@ static struct net_device *get_netvsc_bymac(const u8 *mac)
return NULL;
 }
 
-static struct net_device *get_netvsc_byref(const struct net_device *vf_netdev)
+static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
 {
struct net_device *dev;
 
@@ -1248,7 +1250,7 @@ static struct net_device *get_netvsc_byref(const struct 
net_device *vf_netdev)
if (net_device_ctx->nvdev == NULL)
continue;   /* device is removed */
 
-   if (net_device_ctx->vf_netdev == vf_netdev)
+   if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev)
return dev; /* a match */
}
 
@@ -1275,7 +1277,7 @@ static int netvsc_register_vf(struct net_device 
*vf_netdev)
 
net_device_ctx = netdev_priv(ndev);
netvsc_dev = net_device_ctx->nvdev;
-   if (!netvsc_dev || net_device_ctx->vf_netdev)
+   if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
return NOTIFY_DONE;
 
netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
@@ -1285,7 +1287,7 @@ static int netvsc_register_vf(struct net_device 
*vf_netdev)
try_module_get(THIS_MODULE);
 
dev_hold(vf_netdev);
-   net_device_ctx->vf_netdev = vf_netdev;
+   rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
return NOTIFY_OK;
 }
 
@@ -1379,7 +1381,8 @@ static int netvsc_unregister_vf(struct net_device 
*vf_netdev)
 
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
netvsc_inject_disable(net_device_ctx);
-   net_device_ctx->vf_netdev = NULL;
+
+   RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
dev_put(vf_netdev);
module_put(THIS_MODULE);
return NOTIFY_OK;
@@ -1433,8 +1436,6 @@ static int netvsc_probe(struct hv_device *dev,
  

[PATCH 6/7] hv_netvsc: remove VF in flight counters

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

Since VF reference is now protected by RCU, no longer need the VF usage
counter and can use device flags to see whether to inject or not.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |3 +-
 drivers/net/hyperv/netvsc_drv.c |   81 ++-
 2 files changed, 21 insertions(+), 63 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 6b79487..1d49740 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -696,8 +696,7 @@ struct net_device_context {
 
/* State to manage the associated VF interface. */
struct net_device __rcu *vf_netdev;
-   bool vf_inject;
-   atomic_t vf_use_cnt;
+
/* 1: allocated, serial number is valid. 0: not allocated */
u32 vf_alloc;
/* Serial number of the VF to team with */
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index dde17c0..9375d82 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -670,50 +670,20 @@ int netvsc_recv_callback(struct hv_device *device_obj,
struct net_device *vf_netdev;
struct sk_buff *skb;
struct netvsc_stats *rx_stats;
-   u32 bytes_recvd = packet->total_data_buflen;
-   int ret = 0;
 
-   if (!net || net->reg_state != NETREG_REGISTERED)
+   if (net->reg_state != NETREG_REGISTERED)
return NVSP_STAT_FAIL;
 
+   /*
+* If necessary, inject this packet into the VF interface.
+* On Hyper-V, multicast and brodcast packets are only delivered
+* to the synthetic interface (after subjecting these to
+* policy filters on the host). Deliver these via the VF
+* interface in the guest.
+*/
vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
-   if (vf_netdev) {
-   struct sk_buff *vf_skb;
-
-   atomic_inc(_device_ctx->vf_use_cnt);
-   if (!net_device_ctx->vf_inject) {
-   /*
-* We raced; just move on.
-*/
-   atomic_dec(_device_ctx->vf_use_cnt);
-   goto vf_injection_done;
-   }
-
-   /*
-* Inject this packet into the VF inerface.
-* On Hyper-V, multicast and brodcast packets
-* are only delivered on the synthetic interface
-* (after subjecting these to policy filters on
-* the host). Deliver these via the VF interface
-* in the guest.
-*/
-   vf_skb = netvsc_alloc_recv_skb(vf_netdev,
-  packet, csum_info, *data,
-  vlan_tci);
-   if (vf_skb != NULL) {
-   ++vf_netdev->stats.rx_packets;
-   vf_netdev->stats.rx_bytes += bytes_recvd;
-   netif_receive_skb(vf_skb);
-   } else {
-   ++net->stats.rx_dropped;
-   ret = NVSP_STAT_FAIL;
-   }
-   atomic_dec(_device_ctx->vf_use_cnt);
-   return ret;
-   }
-
-vf_injection_done:
-   rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
+   if (vf_netdev && (vf_netdev->flags & IFF_UP))
+   net = vf_netdev;
 
/* Allocate a skb - TODO direct I/O to pages? */
skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci);
@@ -721,9 +691,17 @@ vf_injection_done:
++net->stats.rx_dropped;
return NVSP_STAT_FAIL;
}
-   skb_record_rx_queue(skb, channel->
-   offermsg.offer.sub_channel_index);
 
+   if (net != vf_netdev)
+   skb_record_rx_queue(skb,
+   channel->offermsg.offer.sub_channel_index);
+
+   /*
+* Even if injecting the packet, record the statistics
+* on the synthetic device because modifying the VF device
+* statistics will not work correctly.
+*/
+   rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
u64_stats_update_begin(_stats->syncp);
rx_stats->packets++;
rx_stats->bytes += packet->total_data_buflen;
@@ -1291,20 +1269,6 @@ static int netvsc_register_vf(struct net_device 
*vf_netdev)
return NOTIFY_OK;
 }
 
-static void netvsc_inject_enable(struct net_device_context *net_device_ctx)
-{
-   net_device_ctx->vf_inject = true;
-}
-
-static void netvsc_inject_disable(struct net_device_context *net_device_ctx)
-{
-   net_device_ctx->vf_inject = false;
-
-   /* Wait for currently active users to drain out. */
-   while (atomic_read(_device_ctx->vf_use_cnt) != 0)
-   udelay(50);
-}
-
 static int 

[PATCH net-next 0/7] hv_netvsc changes

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

These are mostly about improving the handling of interaction between
the virtual network device (netvsc) and the SR-IOV VF network device.

Stephen Hemminger (7):
  hv_netvsc: use consume_skb
  hv_netvsc: dev hold/put reference to VF
  hv_netvsc: simplify callback event code
  hv_netvsc: improve VF device matching
  hv_netvsc: use RCU to protect vf_netdev
  hv_netvsc: remove VF in flight counters
  hv_netvsc: count multicast packets received

 drivers/net/hyperv/hyperv_net.h |7 +-
 drivers/net/hyperv/netvsc.c |4 +-
 drivers/net/hyperv/netvsc_drv.c |  188 +-
 3 files changed, 90 insertions(+), 109 deletions(-)

-- 
1.7.4.1



[PATCH 1/7] hv_netvsc: use consume_skb

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

Packets that are transmitted in normal path should use consume_skb
instead of kfree_skb. This allows for better tracing of packet drops.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index ff05b9b..720b5fa 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -635,7 +635,7 @@ static void netvsc_send_tx_complete(struct netvsc_device 
*net_device,
q_idx = nvsc_packet->q_idx;
channel = incoming_channel;
 
-   dev_kfree_skb_any(skb);
+   dev_consume_skb_any(skb);
}
 
num_outstanding_sends =
@@ -944,7 +944,7 @@ int netvsc_send(struct hv_device *device,
}
 
if (msdp->skb)
-   dev_kfree_skb_any(msdp->skb);
+   dev_consume_skb_any(msdp->skb);
 
if (xmit_more && !packet->cp_partial) {
msdp->skb = skb;
-- 
1.7.4.1



[PATCH 3/7] hv_netvsc: simplify callback event code

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

The callback handler for netlink events can be simplified:
 * Consolidate check for netlink callback events about this driver itself.
 * Ignore non-Ethernet devices.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c |   28 ++--
 1 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index e74dbcc..849b566 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1238,10 +1238,6 @@ static int netvsc_register_vf(struct net_device 
*vf_netdev)
struct net_device *ndev;
struct net_device_context *net_device_ctx;
struct netvsc_device *netvsc_dev;
-   const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
-
-   if (eth_ops == NULL || eth_ops == _ops)
-   return NOTIFY_DONE;
 
/*
 * We will use the MAC address to locate the synthetic interface to
@@ -1286,12 +1282,8 @@ static int netvsc_vf_up(struct net_device *vf_netdev)
 {
struct net_device *ndev;
struct netvsc_device *netvsc_dev;
-   const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
struct net_device_context *net_device_ctx;
 
-   if (eth_ops == _ops)
-   return NOTIFY_DONE;
-
ndev = get_netvsc_net_device(vf_netdev->dev_addr);
if (!ndev)
return NOTIFY_DONE;
@@ -1329,10 +1321,6 @@ static int netvsc_vf_down(struct net_device *vf_netdev)
struct net_device *ndev;
struct netvsc_device *netvsc_dev;
struct net_device_context *net_device_ctx;
-   const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
-
-   if (eth_ops == _ops)
-   return NOTIFY_DONE;
 
ndev = get_netvsc_net_device(vf_netdev->dev_addr);
if (!ndev)
@@ -1361,12 +1349,8 @@ static int netvsc_unregister_vf(struct net_device 
*vf_netdev)
 {
struct net_device *ndev;
struct netvsc_device *netvsc_dev;
-   const struct ethtool_ops *eth_ops = vf_netdev->ethtool_ops;
struct net_device_context *net_device_ctx;
 
-   if (eth_ops == _ops)
-   return NOTIFY_DONE;
-
ndev = get_netvsc_net_device(vf_netdev->dev_addr);
if (!ndev)
return NOTIFY_DONE;
@@ -1542,13 +1526,21 @@ static int netvsc_netdev_event(struct notifier_block 
*this,
 {
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
 
+   /* Skip our own events */
+   if (event_dev->netdev_ops == _ops)
+   return NOTIFY_DONE;
+
+   /* Avoid non-Ethernet type devices */
+   if (event_dev->type != ARPHRD_ETHER)
+   return NOTIFY_DONE;
+
/* Avoid Vlan dev with same MAC registering as VF */
if (event_dev->priv_flags & IFF_802_1Q_VLAN)
return NOTIFY_DONE;
 
/* Avoid Bonding master dev with same MAC registering as VF */
-   if (event_dev->priv_flags & IFF_BONDING &&
-   event_dev->flags & IFF_MASTER)
+   if ((event_dev->priv_flags & IFF_BONDING) &&
+   (event_dev->flags & IFF_MASTER))
return NOTIFY_DONE;
 
switch (event) {
-- 
1.7.4.1



[PATCH 7/7] hv_netvsc: count multicast packets received

2016-09-22 Thread sthemmin
From: Stephen Hemminger 

Useful for debugging issues with multicast and SR-IOV to keep track
of number of received multicast packets.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |2 ++
 drivers/net/hyperv/netvsc_drv.c |9 -
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 1d49740..7130bf9 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -649,6 +649,8 @@ struct multi_recv_comp {
 struct netvsc_stats {
u64 packets;
u64 bytes;
+   u64 broadcast;
+   u64 multicast;
struct u64_stats_sync syncp;
 };
 
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 9375d82..52eeb2f 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -705,6 +705,11 @@ int netvsc_recv_callback(struct hv_device *device_obj,
u64_stats_update_begin(_stats->syncp);
rx_stats->packets++;
rx_stats->bytes += packet->total_data_buflen;
+
+   if (skb->pkt_type == PACKET_BROADCAST)
+   ++rx_stats->broadcast;
+   else if (skb->pkt_type == PACKET_MULTICAST)
+   ++rx_stats->multicast;
u64_stats_update_end(_stats->syncp);
 
/*
@@ -947,7 +952,7 @@ static struct rtnl_link_stats64 *netvsc_get_stats64(struct 
net_device *net,
cpu);
struct netvsc_stats *rx_stats = per_cpu_ptr(ndev_ctx->rx_stats,
cpu);
-   u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
+   u64 tx_packets, tx_bytes, rx_packets, rx_bytes, rx_multicast;
unsigned int start;
 
do {
@@ -960,12 +965,14 @@ static struct rtnl_link_stats64 
*netvsc_get_stats64(struct net_device *net,
start = u64_stats_fetch_begin_irq(_stats->syncp);
rx_packets = rx_stats->packets;
rx_bytes = rx_stats->bytes;
+   rx_multicast = rx_stats->multicast + 
rx_stats->broadcast;
} while (u64_stats_fetch_retry_irq(_stats->syncp, start));
 
t->tx_bytes += tx_bytes;
t->tx_packets   += tx_packets;
t->rx_bytes += rx_bytes;
t->rx_packets   += rx_packets;
+   t->multicast+= rx_multicast;
}
 
t->tx_dropped   = net->stats.tx_dropped;
-- 
1.7.4.1



[PATCH net-next] Revert "hv_netvsc: make inline functions static"

2016-09-09 Thread sthemmin
From: Stephen Hemminger 

These functions are used by other code misc-next tree.

This reverts commit 30d1de08c87ddde6f73936c3350e7e153988fe02.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 85 +
 include/linux/hyperv.h  | 84 
 2 files changed, 85 insertions(+), 84 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 2a9ccc4..ff05b9b 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -34,89 +34,6 @@
 #include "hyperv_net.h"
 
 /*
- * An API to support in-place processing of incoming VMBUS packets.
- */
-#define VMBUS_PKT_TRAILER  8
-
-static struct vmpacket_descriptor *
-get_next_pkt_raw(struct vmbus_channel *channel)
-{
-   struct hv_ring_buffer_info *ring_info = >inbound;
-   u32 read_loc = ring_info->priv_read_index;
-   void *ring_buffer = hv_get_ring_buffer(ring_info);
-   struct vmpacket_descriptor *cur_desc;
-   u32 packetlen;
-   u32 dsize = ring_info->ring_datasize;
-   u32 delta = read_loc - ring_info->ring_buffer->read_index;
-   u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
-
-   if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
-   return NULL;
-
-   if ((read_loc + sizeof(*cur_desc)) > dsize)
-   return NULL;
-
-   cur_desc = ring_buffer + read_loc;
-   packetlen = cur_desc->len8 << 3;
-
-   /*
-* If the packet under consideration is wrapping around,
-* return failure.
-*/
-   if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > (dsize - 1))
-   return NULL;
-
-   return cur_desc;
-}
-
-/*
- * A helper function to step through packets "in-place"
- * This API is to be called after each successful call
- * get_next_pkt_raw().
- */
-static void put_pkt_raw(struct vmbus_channel *channel,
-   struct vmpacket_descriptor *desc)
-{
-   struct hv_ring_buffer_info *ring_info = >inbound;
-   u32 read_loc = ring_info->priv_read_index;
-   u32 packetlen = desc->len8 << 3;
-   u32 dsize = ring_info->ring_datasize;
-
-   BUG_ON((read_loc + packetlen + VMBUS_PKT_TRAILER) > dsize);
-
-   /*
-* Include the packet trailer.
-*/
-   ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
-}
-
-/*
- * This call commits the read index and potentially signals the host.
- * Here is the pattern for using the "in-place" consumption APIs:
- *
- * while (get_next_pkt_raw() {
- * process the packet "in-place";
- * put_pkt_raw();
- * }
- * if (packets processed in place)
- * commit_rd_index();
- */
-static void commit_rd_index(struct vmbus_channel *channel)
-{
-   struct hv_ring_buffer_info *ring_info = >inbound;
-   /*
-* Make sure all reads are done before we update the read index since
-* the writer may start writing to the read area once the read index
-* is updated.
-*/
-   virt_rmb();
-   ring_info->ring_buffer->read_index = ring_info->priv_read_index;
-
-   if (hv_need_to_signal_on_read(ring_info))
-   vmbus_set_event(channel);
-}
-
-/*
  * Switch the data path from the synthetic interface to the VF
  * interface.
  */
@@ -840,7 +757,7 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device 
*net_device,
return msg_size;
 }
 
-static int netvsc_send_pkt(
+static inline int netvsc_send_pkt(
struct hv_device *device,
struct hv_netvsc_packet *packet,
struct netvsc_device *net_device,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index b01c8c3..5df444b 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1429,4 +1429,88 @@ static inline  bool hv_need_to_signal_on_read(struct 
hv_ring_buffer_info *rbi)
return false;
 }
 
+/*
+ * An API to support in-place processing of incoming VMBUS packets.
+ */
+#define VMBUS_PKT_TRAILER  8
+
+static inline struct vmpacket_descriptor *
+get_next_pkt_raw(struct vmbus_channel *channel)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   u32 read_loc = ring_info->priv_read_index;
+   void *ring_buffer = hv_get_ring_buffer(ring_info);
+   struct vmpacket_descriptor *cur_desc;
+   u32 packetlen;
+   u32 dsize = ring_info->ring_datasize;
+   u32 delta = read_loc - ring_info->ring_buffer->read_index;
+   u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
+
+   if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
+   return NULL;
+
+   if ((read_loc + sizeof(*cur_desc)) > dsize)
+   return NULL;
+
+   cur_desc = ring_buffer + read_loc;
+   packetlen = cur_desc->len8 << 3;
+
+   /*
+* If the packet under consideration is wrapping around,
+* return failure.
+*/
+   

[PATCH 13/14] hv_netvsc: report vmbus name in ethtool

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Make netvsc on vmbus behave more like PCI.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c | 4 
 include/linux/hyperv.h  | 7 +++
 2 files changed, 11 insertions(+)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7ed9f13..b874ab1 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -734,8 +734,12 @@ vf_injection_done:
 static void netvsc_get_drvinfo(struct net_device *net,
   struct ethtool_drvinfo *info)
 {
+   struct net_device_context *net_device_ctx = netdev_priv(net);
+   struct hv_device *dev = net_device_ctx->device_ctx;
+
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+   strlcpy(info->bus_info, vmbus_dev_name(dev), sizeof(info->bus_info));
 }
 
 static void netvsc_get_channels(struct net_device *net,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index a6bc974..b01c8c3 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1114,6 +1114,13 @@ int __must_check __vmbus_driver_register(struct 
hv_driver *hv_driver,
 const char *mod_name);
 void vmbus_driver_unregister(struct hv_driver *hv_driver);
 
+static inline const char *vmbus_dev_name(const struct hv_device *device_obj)
+{
+   const struct kobject *kobj = _obj->device.kobj;
+
+   return kobj->name;
+}
+
 void vmbus_hvsock_device_unregister(struct vmbus_channel *channel);
 
 int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
-- 
2.9.3



[PATCH 11/14] hv_netvsc: make netvsc_destroy_buf void

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

No caller checks the return value.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 14 ++
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 830aae2..471c476 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -206,12 +206,12 @@ get_in_err:
return net_device;
 }
 
-static int netvsc_destroy_buf(struct hv_device *device)
+static void netvsc_destroy_buf(struct hv_device *device)
 {
struct nvsp_message *revoke_packet;
-   int ret = 0;
struct net_device *ndev = hv_get_drvdata(device);
struct netvsc_device *net_device = net_device_to_netvsc_device(ndev);
+   int ret;
 
/*
 * If we got a section count, it means we received a
@@ -241,7 +241,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev, "unable to send "
"revoke receive buffer to netvsp\n");
-   return ret;
+   return;
}
}
 
@@ -256,7 +256,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev,
   "unable to teardown receive buffer's 
gpadl\n");
-   return ret;
+   return;
}
net_device->recv_buf_gpadl_handle = 0;
}
@@ -300,7 +300,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev, "unable to send "
   "revoke send buffer to netvsp\n");
-   return ret;
+   return;
}
}
/* Teardown the gpadl on the vsp end */
@@ -314,7 +314,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev,
   "unable to teardown send buffer's gpadl\n");
-   return ret;
+   return;
}
net_device->send_buf_gpadl_handle = 0;
}
@@ -324,8 +324,6 @@ static int netvsc_destroy_buf(struct hv_device *device)
net_device->send_buf = NULL;
}
kfree(net_device->send_section_map);
-
-   return ret;
 }
 
 static int netvsc_init_buf(struct hv_device *device)
-- 
2.9.3



[PATCH 05/14] hv_netvsc: make inline functions static

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Several new functions were introduced into hyperv.h but only used in one file.
Move them and let compiler decide on inline.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 85 -
 include/linux/hyperv.h  | 84 
 2 files changed, 84 insertions(+), 85 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index fe83de3..4ef2af6 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -34,6 +34,89 @@
 #include "hyperv_net.h"
 
 /*
+ * An API to support in-place processing of incoming VMBUS packets.
+ */
+#define VMBUS_PKT_TRAILER  8
+
+static struct vmpacket_descriptor *
+get_next_pkt_raw(struct vmbus_channel *channel)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   u32 read_loc = ring_info->priv_read_index;
+   void *ring_buffer = hv_get_ring_buffer(ring_info);
+   struct vmpacket_descriptor *cur_desc;
+   u32 packetlen;
+   u32 dsize = ring_info->ring_datasize;
+   u32 delta = read_loc - ring_info->ring_buffer->read_index;
+   u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
+
+   if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
+   return NULL;
+
+   if ((read_loc + sizeof(*cur_desc)) > dsize)
+   return NULL;
+
+   cur_desc = ring_buffer + read_loc;
+   packetlen = cur_desc->len8 << 3;
+
+   /*
+* If the packet under consideration is wrapping around,
+* return failure.
+*/
+   if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > (dsize - 1))
+   return NULL;
+
+   return cur_desc;
+}
+
+/*
+ * A helper function to step through packets "in-place"
+ * This API is to be called after each successful call
+ * get_next_pkt_raw().
+ */
+static void put_pkt_raw(struct vmbus_channel *channel,
+   struct vmpacket_descriptor *desc)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   u32 read_loc = ring_info->priv_read_index;
+   u32 packetlen = desc->len8 << 3;
+   u32 dsize = ring_info->ring_datasize;
+
+   BUG_ON((read_loc + packetlen + VMBUS_PKT_TRAILER) > dsize);
+
+   /*
+* Include the packet trailer.
+*/
+   ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
+}
+
+/*
+ * This call commits the read index and potentially signals the host.
+ * Here is the pattern for using the "in-place" consumption APIs:
+ *
+ * while (get_next_pkt_raw() {
+ * process the packet "in-place";
+ * put_pkt_raw();
+ * }
+ * if (packets processed in place)
+ * commit_rd_index();
+ */
+static void commit_rd_index(struct vmbus_channel *channel)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   /*
+* Make sure all reads are done before we update the read index since
+* the writer may start writing to the read area once the read index
+* is updated.
+*/
+   virt_rmb();
+   ring_info->ring_buffer->read_index = ring_info->priv_read_index;
+
+   if (hv_need_to_signal_on_read(ring_info))
+   vmbus_set_event(channel);
+}
+
+/*
  * Switch the data path from the synthetic interface to the VF
  * interface.
  */
@@ -749,7 +832,7 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device 
*net_device,
return msg_size;
 }
 
-static inline int netvsc_send_pkt(
+static int netvsc_send_pkt(
struct hv_device *device,
struct hv_netvsc_packet *packet,
struct netvsc_device *net_device,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index b10954a..a6bc974 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1422,88 +1422,4 @@ static inline  bool hv_need_to_signal_on_read(struct 
hv_ring_buffer_info *rbi)
return false;
 }
 
-/*
- * An API to support in-place processing of incoming VMBUS packets.
- */
-#define VMBUS_PKT_TRAILER  8
-
-static inline struct vmpacket_descriptor *
-get_next_pkt_raw(struct vmbus_channel *channel)
-{
-   struct hv_ring_buffer_info *ring_info = >inbound;
-   u32 read_loc = ring_info->priv_read_index;
-   void *ring_buffer = hv_get_ring_buffer(ring_info);
-   struct vmpacket_descriptor *cur_desc;
-   u32 packetlen;
-   u32 dsize = ring_info->ring_datasize;
-   u32 delta = read_loc - ring_info->ring_buffer->read_index;
-   u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
-
-   if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
-   return NULL;
-
-   if ((read_loc + sizeof(*cur_desc)) > dsize)
-   return NULL;
-
-   cur_desc = ring_buffer + read_loc;
-   packetlen = cur_desc->len8 << 3;
-
-   /*
-* If the packet under consideration is wrapping around,
-* return failure.
-*/
-  

[PATCH 08/14] hv_netvsc: init completion during alloc

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Move initialization to allocate where other fields are initialized.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 2ece27a..27eb507 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -164,6 +164,7 @@ static struct netvsc_device *alloc_net_device(void)
atomic_set(_device->open_cnt, 0);
net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
+   init_completion(_device->channel_init_wait);
 
return net_device;
 }
@@ -1442,9 +1443,6 @@ int netvsc_device_add(struct hv_device *device, void 
*additional_info)
 
net_device->ring_size = ring_size;
 
-   /* Initialize the NetVSC channel extension */
-   init_completion(_device->channel_init_wait);
-
set_per_channel_state(device->channel, net_device->cb_buffer);
 
/* Open the channel */
-- 
2.9.3



[PATCH 09/14] hv_netvsc: rearrange start_xmit

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Rearrange the transmit routine to eliminate goto's and unnecessary
boolean variables. Use standard functions to test for vlan tag.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c | 106 +++-
 1 file changed, 51 insertions(+), 55 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 3bbf073..7ed9f13 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -357,11 +357,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
struct rndis_message *rndis_msg;
struct rndis_packet *rndis_pkt;
u32 rndis_msg_size;
-   bool isvlan;
-   bool linear = false;
struct rndis_per_packet_info *ppi;
struct ndis_tcp_ip_checksum_info *csum_info;
-   struct ndis_tcp_lso_info *lso_info;
int  hdr_offset;
u32 net_trans_info;
u32 hash;
@@ -376,22 +373,23 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
 * more pages we try linearizing it.
 */
 
-check_size:
skb_length = skb->len;
num_data_pgs = netvsc_get_slots(skb) + 2;
-   if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) {
-   net_alert_ratelimited("packet too big: %u pages (%u bytes)\n",
- num_data_pgs, skb->len);
-   ret = -EFAULT;
-   goto drop;
-   } else if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+
+   if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
if (skb_linearize(skb)) {
net_alert_ratelimited("failed to linearize skb\n");
ret = -ENOMEM;
goto drop;
}
-   linear = true;
-   goto check_size;
+
+   num_data_pgs = netvsc_get_slots(skb) + 2;
+   if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+   net_alert_ratelimited("packet too big: %u pages (%u 
bytes)\n",
+ num_data_pgs, skb->len);
+   ret = -EFAULT;
+   goto drop;
+   }
}
 
/*
@@ -418,8 +416,6 @@ check_size:
 
memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE);
 
-   isvlan = skb->vlan_tci & VLAN_TAG_PRESENT;
-
/* Add the rndis header */
rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
rndis_msg->msg_len = packet->total_data_buflen;
@@ -438,7 +434,7 @@ check_size:
*(u32 *)((void *)ppi + ppi->ppi_offset) = hash;
}
 
-   if (isvlan) {
+   if (skb_vlan_tag_present(skb)) {
struct ndis_pkt_8021q_info *vlan;
 
rndis_msg_size += NDIS_VLAN_PPI_SIZE;
@@ -459,8 +455,37 @@ check_size:
 * Setup the sendside checksum offload only if this is not a
 * GSO packet.
 */
-   if (skb_is_gso(skb))
-   goto do_lso;
+   if (skb_is_gso(skb)) {
+   struct ndis_tcp_lso_info *lso_info;
+
+   rndis_msg_size += NDIS_LSO_PPI_SIZE;
+   ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
+   TCP_LARGESEND_PKTINFO);
+
+   lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
+   ppi->ppi_offset);
+
+   lso_info->lso_v2_transmit.type = 
NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
+   if (net_trans_info & (INFO_IPV4 << 16)) {
+   lso_info->lso_v2_transmit.ip_version =
+   NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
+   ip_hdr(skb)->tot_len = 0;
+   ip_hdr(skb)->check = 0;
+   tcp_hdr(skb)->check =
+   ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+  ip_hdr(skb)->daddr, 0, 
IPPROTO_TCP, 0);
+   } else {
+   lso_info->lso_v2_transmit.ip_version =
+   NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
+   ipv6_hdr(skb)->payload_len = 0;
+   tcp_hdr(skb)->check =
+   ~csum_ipv6_magic(_hdr(skb)->saddr,
+_hdr(skb)->daddr, 0, 
IPPROTO_TCP, 0);
+   }
+   lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
+   lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
+   goto do_send;
+   }
 
if ((skb->ip_summed == CHECKSUM_NONE) ||
(skb->ip_summed == CHECKSUM_UNNECESSARY))
@@ -507,35 +532,6 @@ check_size:
 
csum_info->transmit.udp_checksum = 0;
}
-   goto do_send;
-
-do_lso:
-   rndis_msg_size += NDIS_LSO_PPI_SIZE;
-   ppi = 

[PATCH 01/14] hv_netvsc: fix rtnl locking in callback

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

The function get_netvsc_net_device had conditional locking. This was
unnecessary, incorrect, but harmless. It was unnecessary since the
code is only called from netlink netdev event callback where RTNL
is always acquired before the callbacks are run. It was incorrect
because of use of trylock and then continuing.
Fix by replacing with proper assertion.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c | 5 +
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index eb2c122..6924d01a 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1167,9 +1167,8 @@ static void netvsc_free_netdev(struct net_device *netdev)
 static struct net_device *get_netvsc_net_device(char *mac)
 {
struct net_device *dev, *found = NULL;
-   int rtnl_locked;
 
-   rtnl_locked = rtnl_trylock();
+   ASSERT_RTNL();
 
for_each_netdev(_net, dev) {
if (memcmp(dev->dev_addr, mac, ETH_ALEN) == 0) {
@@ -1179,8 +1178,6 @@ static struct net_device *get_netvsc_net_device(char *mac)
break;
}
}
-   if (rtnl_locked)
-   rtnl_unlock();
 
return found;
 }
-- 
2.9.3



[PATCH 10/14] hv_netvsc: refactor completion function

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Break the different cases, code is cleaner if broken up

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 103 
 1 file changed, 56 insertions(+), 47 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 27eb507..830aae2 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -696,69 +696,78 @@ static inline void netvsc_free_send_slot(struct 
netvsc_device *net_device,
sync_change_bit(index, net_device->send_section_map);
 }
 
+static void netvsc_send_tx_complete(struct netvsc_device *net_device,
+   struct vmbus_channel *incoming_channel,
+   struct hv_device *device,
+   struct vmpacket_descriptor *packet)
+{
+   struct sk_buff *skb = (struct sk_buff *)(unsigned long)packet->trans_id;
+   struct net_device *ndev = hv_get_drvdata(device);
+   struct net_device_context *net_device_ctx = netdev_priv(ndev);
+   struct vmbus_channel *channel = device->channel;
+   int num_outstanding_sends;
+   u16 q_idx = 0;
+   int queue_sends;
+
+   /* Notify the layer above us */
+   if (likely(skb)) {
+   struct hv_netvsc_packet *nvsc_packet
+   = (struct hv_netvsc_packet *)skb->cb;
+   u32 send_index = nvsc_packet->send_buf_index;
+
+   if (send_index != NETVSC_INVALID_INDEX)
+   netvsc_free_send_slot(net_device, send_index);
+   q_idx = nvsc_packet->q_idx;
+   channel = incoming_channel;
+
+   dev_kfree_skb_any(skb);
+   }
+
+   num_outstanding_sends =
+   atomic_dec_return(_device->num_outstanding_sends);
+   queue_sends = atomic_dec_return(_device->queue_sends[q_idx]);
+
+   if (net_device->destroy && num_outstanding_sends == 0)
+   wake_up(_device->wait_drain);
+
+   if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
+   !net_device_ctx->start_remove &&
+   (hv_ringbuf_avail_percent(>outbound) > 
RING_AVAIL_PERCENT_HIWATER ||
+queue_sends < 1))
+   netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
+}
+
 static void netvsc_send_completion(struct netvsc_device *net_device,
   struct vmbus_channel *incoming_channel,
   struct hv_device *device,
   struct vmpacket_descriptor *packet)
 {
struct nvsp_message *nvsp_packet;
-   struct hv_netvsc_packet *nvsc_packet;
struct net_device *ndev = hv_get_drvdata(device);
-   struct net_device_context *net_device_ctx = netdev_priv(ndev);
-   u32 send_index;
-   struct sk_buff *skb;
 
nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
-   (packet->offset8 << 3));
+ (packet->offset8 << 3));
 
-   if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
-   (nvsp_packet->hdr.msg_type ==
-NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
-   (nvsp_packet->hdr.msg_type ==
-NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE) ||
-   (nvsp_packet->hdr.msg_type ==
-NVSP_MSG5_TYPE_SUBCHANNEL)) {
+   switch (nvsp_packet->hdr.msg_type) {
+   case NVSP_MSG_TYPE_INIT_COMPLETE:
+   case NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE:
+   case NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE:
+   case NVSP_MSG5_TYPE_SUBCHANNEL:
/* Copy the response back */
memcpy(_device->channel_init_pkt, nvsp_packet,
   sizeof(struct nvsp_message));
complete(_device->channel_init_wait);
-   } else if (nvsp_packet->hdr.msg_type ==
-  NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
-   int num_outstanding_sends;
-   u16 q_idx = 0;
-   struct vmbus_channel *channel = device->channel;
-   int queue_sends;
-
-   /* Get the send context */
-   skb = (struct sk_buff *)(unsigned long)packet->trans_id;
-
-   /* Notify the layer above us */
-   if (skb) {
-   nvsc_packet = (struct hv_netvsc_packet *) skb->cb;
-   send_index = nvsc_packet->send_buf_index;
-   if (send_index != NETVSC_INVALID_INDEX)
-   netvsc_free_send_slot(net_device, send_index);
-   q_idx = nvsc_packet->q_idx;
-   channel = incoming_channel;
-   dev_kfree_skb_any(skb);
-   }
-
-   num_outstanding_sends =
-   atomic_dec_return(_device->num_outstanding_sends);
-   queue_sends = 

[PATCH 07/14] hv_netvsc: make device_remove void

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Always returns 0 and no callers check.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h | 2 +-
 drivers/net/hyperv/netvsc.c | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index b58e559..8031dee 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -173,7 +173,7 @@ struct rndis_device {
 struct rndis_message;
 struct netvsc_device;
 int netvsc_device_add(struct hv_device *device, void *additional_info);
-int netvsc_device_remove(struct hv_device *device);
+void netvsc_device_remove(struct hv_device *device);
 int netvsc_send(struct hv_device *device,
struct hv_netvsc_packet *packet,
struct rndis_message *rndis_msg,
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 110bbb8..2ece27a 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -648,7 +648,7 @@ static void netvsc_disconnect_vsp(struct hv_device *device)
 /*
  * netvsc_device_remove - Callback when the root bus device is removed
  */
-int netvsc_device_remove(struct hv_device *device)
+void netvsc_device_remove(struct hv_device *device)
 {
struct net_device *ndev = hv_get_drvdata(device);
struct net_device_context *net_device_ctx = netdev_priv(ndev);
@@ -670,7 +670,6 @@ int netvsc_device_remove(struct hv_device *device)
/* Release all resources */
vfree(net_device->sub_cb_buf);
free_netvsc_device(net_device);
-   return 0;
 }
 
 #define RING_AVAIL_PERCENT_HIWATER 20
-- 
2.9.3



[PATCH 14/14] hv_netvsc: add ethtool statistics for tx packet issues

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Printing console messages is not helpful when system is out of memory;
and can be disastrous with netconsole. Instead keep statistics
of these anomalous conditions.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |  9 +
 drivers/net/hyperv/netvsc_drv.c | 86 +
 2 files changed, 79 insertions(+), 16 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 8031dee..284b97b 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -652,6 +652,14 @@ struct netvsc_stats {
struct u64_stats_sync syncp;
 };
 
+struct netvsc_ethtool_stats {
+   unsigned long tx_scattered;
+   unsigned long tx_no_memory;
+   unsigned long tx_no_space;
+   unsigned long tx_too_big;
+   unsigned long tx_busy;
+};
+
 struct netvsc_reconfig {
struct list_head list;
u32 event;
@@ -681,6 +689,7 @@ struct net_device_context {
/* Ethtool settings */
u8 duplex;
u32 speed;
+   struct netvsc_ethtool_stats eth_stats;
 
/* the device is going away */
bool start_remove;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index b874ab1..2360e70 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -365,7 +365,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
u32 skb_length;
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
struct hv_page_buffer *pb = page_buf;
-   struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
 
/* We will atmost need two pages to describe the rndis
 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
@@ -377,17 +376,14 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
num_data_pgs = netvsc_get_slots(skb) + 2;
 
if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
-   if (skb_linearize(skb)) {
-   net_alert_ratelimited("failed to linearize skb\n");
-   ret = -ENOMEM;
-   goto drop;
-   }
+   ++net_device_ctx->eth_stats.tx_scattered;
+
+   if (skb_linearize(skb))
+   goto no_memory;
 
num_data_pgs = netvsc_get_slots(skb) + 2;
if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
-   net_alert_ratelimited("packet too big: %u pages (%u 
bytes)\n",
- num_data_pgs, skb->len);
-   ret = -EFAULT;
+   ++net_device_ctx->eth_stats.tx_too_big;
goto drop;
}
}
@@ -398,11 +394,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
 * structure.
 */
ret = skb_cow_head(skb, RNDIS_AND_PPI_SIZE);
-   if (ret) {
-   netdev_err(net, "unable to alloc hv_netvsc_packet\n");
-   ret = -ENOMEM;
-   goto drop;
-   }
+   if (ret)
+   goto no_memory;
+
/* Use the skb control buffer for building up the packet */
BUILD_BUG_ON(sizeof(struct hv_netvsc_packet) >
FIELD_SIZEOF(struct sk_buff, cb));
@@ -518,7 +512,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
 
ret = skb_cow_head(skb, 0);
if (ret)
-   goto drop;
+   goto no_memory;
 
uh = udp_hdr(skb);
udp_len = ntohs(uh->len);
@@ -545,20 +539,32 @@ do_send:
ret = netvsc_send(net_device_ctx->device_ctx, packet,
  rndis_msg, , skb);
if (likely(ret == 0)) {
+   struct netvsc_stats *tx_stats = 
this_cpu_ptr(net_device_ctx->tx_stats);
+
u64_stats_update_begin(_stats->syncp);
tx_stats->packets++;
tx_stats->bytes += skb_length;
u64_stats_update_end(_stats->syncp);
return NETDEV_TX_OK;
}
-   if (ret == -EAGAIN)
+
+   if (ret == -EAGAIN) {
+   ++net_device_ctx->eth_stats.tx_busy;
return NETDEV_TX_BUSY;
+   }
+
+   if (ret == -ENOSPC)
+   ++net_device_ctx->eth_stats.tx_no_space;
 
 drop:
dev_kfree_skb_any(skb);
net->stats.tx_dropped++;
 
return NETDEV_TX_OK;
+
+no_memory:
+   ++net_device_ctx->eth_stats.tx_no_memory;
+   goto drop;
 }
 
 /*
@@ -1015,6 +1021,51 @@ static int netvsc_set_mac_addr(struct net_device *ndev, 
void *p)
return err;
 }
 
+static const struct {
+   char name[ETH_GSTRING_LEN];
+   u16 offset;
+} netvsc_stats[] = {
+   { "tx_scattered", offsetof(struct netvsc_ethtool_stats, 

[PATCH 06/14] hv_netvsc: use ARRAY_SIZE() for NDIS versions

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Don't hard code size of array of NDIS versions.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 4ef2af6..110bbb8 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -577,9 +577,10 @@ static int netvsc_connect_vsp(struct hv_device *device)
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
int ndis_version;
-   u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
+   const u32 ver_list[] = {
+   NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
-   int i, num_ver = 4; /* number of different NVSP versions */
+   int i;
 
net_device = get_outbound_net_device(device);
if (!net_device)
@@ -588,7 +589,7 @@ static int netvsc_connect_vsp(struct hv_device *device)
init_packet = _device->channel_init_pkt;
 
/* Negotiate the latest NVSP protocol supported */
-   for (i = num_ver - 1; i >= 0; i--)
+   for (i = ARRAY_SIZE(ver_list) - 1; i >= 0; i--)
if (negotiate_nvsp_ver(device, net_device, init_packet,
   ver_list[i])  == 0) {
net_device->nvsp_version = ver_list[i];
-- 
2.9.3



[PATCH 02/14] hv_netvsc: make RSS hash key static

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h   | 2 --
 drivers/net/hyperv/rndis_filter.c | 3 ++-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index ce45d68..b58e559 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -84,8 +84,6 @@ struct ndis_recv_scale_cap { /* 
NDIS_RECEIVE_SCALE_CAPABILITIES */
 #define NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2   40
 
 #define ITAB_NUM 128
-#define HASH_KEYLEN NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2
-extern u8 netvsc_hash_key[];
 
 struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */
struct ndis_obj_header hdr;
diff --git a/drivers/net/hyperv/rndis_filter.c 
b/drivers/net/hyperv/rndis_filter.c
index 3ecb2d0..a100380 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -663,13 +663,14 @@ cleanup:
return ret;
 }
 
-u8 netvsc_hash_key[HASH_KEYLEN] = {
+static const u8 netvsc_hash_key[] = {
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
 };
+#define HASH_KEYLEN ARRAY_SIZE(netvsc_hash_key)
 
 static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
 {
-- 
2.9.3



[PATCH 04/14] hv_netvsc: style cleanups

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Fix most of the complaints about the style of the code.
Things like extra blank lines and return statements.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c   | 18 ++
 drivers/net/hyperv/netvsc_drv.c   |  7 ---
 drivers/net/hyperv/rndis_filter.c |  8 +---
 3 files changed, 3 insertions(+), 30 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index f64c978..fe83de3 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -59,7 +59,6 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
   VM_PKT_DATA_INBAND, 0);
 }
 
-
 static struct netvsc_device *alloc_net_device(void)
 {
struct netvsc_device *net_device;
@@ -123,7 +122,6 @@ get_in_err:
return net_device;
 }
 
-
 static int netvsc_destroy_buf(struct hv_device *device)
 {
struct nvsp_message *revoke_packet;
@@ -285,7 +283,6 @@ static int netvsc_init_buf(struct hv_device *device)
goto cleanup;
}
 
-
/* Notify the NetVsp of the gpadl handle */
init_packet = _device->channel_init_pkt;
 
@@ -412,7 +409,7 @@ static int netvsc_init_buf(struct hv_device *device)
/* Section count is simply the size divided by the section size.
 */
net_device->send_section_cnt =
-   net_device->send_buf_size/net_device->send_section_size;
+   net_device->send_buf_size / net_device->send_section_size;
 
dev_info(>device, "Send section size: %d, Section count:%d\n",
 net_device->send_section_size, net_device->send_section_cnt);
@@ -437,7 +434,6 @@ exit:
return ret;
 }
 
-
 /* Negotiate NVSP protocol version */
 static int negotiate_nvsp_ver(struct hv_device *device,
  struct netvsc_device *net_device,
@@ -593,7 +589,6 @@ int netvsc_device_remove(struct hv_device *device)
return 0;
 }
 
-
 #define RING_AVAIL_PERCENT_HIWATER 20
 #define RING_AVAIL_PERCENT_LOWATER 10
 
@@ -676,13 +671,11 @@ static void netvsc_send_completion(struct netvsc_device 
*net_device,
!net_device_ctx->start_remove &&
(hv_ringbuf_avail_percent(>outbound) >
 RING_AVAIL_PERCENT_HIWATER || queue_sends < 1))
-   netif_tx_wake_queue(netdev_get_tx_queue(
-   ndev, q_idx));
+   netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
} else {
netdev_err(ndev, "Unknown send completion packet type- "
   "%d received!!\n", nvsp_packet->hdr.msg_type);
}
-
 }
 
 static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
@@ -1157,7 +1150,6 @@ static void netvsc_receive(struct netvsc_device 
*net_device,
/* Pass it to the upper layer */
status = rndis_filter_receive(device, netvsc_packet, ,
  channel);
-
}
 
if (!net_device->mrc[q_idx].buf) {
@@ -1182,7 +1174,6 @@ static void netvsc_receive(struct netvsc_device 
*net_device,
rcd->status = status;
 }
 
-
 static void netvsc_send_table(struct hv_device *hdev,
  struct nvsp_message *nvmsg)
 {
@@ -1263,7 +1254,6 @@ static void netvsc_process_raw_pkt(struct hv_device 
*device,
}
 }
 
-
 void netvsc_channel_cb(void *context)
 {
int ret;
@@ -1320,8 +1310,6 @@ void netvsc_channel_cb(void *context)
   ndev,
   request_id,
   desc);
-
-
} else {
/*
 * We are done for this pass.
@@ -1350,8 +1338,6 @@ void netvsc_channel_cb(void *context)
kfree(buffer);
 
netvsc_chk_recv_comp(net_device, channel, q_idx);
-
-   return;
 }
 
 /*
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 6924d01a..3bbf073 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -40,7 +40,6 @@
 
 #include "hyperv_net.h"
 
-
 #define RING_SIZE_MIN 64
 #define LINKCHANGE_INT (2 * HZ)
 #define NETVSC_HW_FEATURES (NETIF_F_RXCSUM | \
@@ -411,7 +410,6 @@ check_size:
FIELD_SIZEOF(struct sk_buff, cb));
packet = (struct hv_netvsc_packet *)skb->cb;
 
-
packet->q_idx = skb_get_queue_mapping(skb);
 
packet->total_data_buflen = skb->len;
@@ -617,7 +615,6 @@ void netvsc_linkstatus_callback(struct hv_device 
*device_obj,
schedule_delayed_work(_ctx->dwork, 0);
 }
 
-
 static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
struct hv_netvsc_packet 

[PATCH 12/14] hv_netvsc: make variable local

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

The variable m_ret is only used in one basic block.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 471c476..2a9ccc4 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -956,7 +956,7 @@ int netvsc_send(struct hv_device *device,
struct sk_buff *skb)
 {
struct netvsc_device *net_device;
-   int ret = 0, m_ret = 0;
+   int ret = 0;
struct vmbus_channel *out_channel;
u16 q_idx = packet->q_idx;
u32 pktlen = packet->total_data_buflen, msd_len = 0;
@@ -1045,8 +1045,8 @@ int netvsc_send(struct hv_device *device,
}
 
if (msd_send) {
-   m_ret = netvsc_send_pkt(device, msd_send, net_device,
-   NULL, msd_skb);
+   int m_ret = netvsc_send_pkt(device, msd_send, net_device,
+   NULL, msd_skb);
 
if (m_ret != 0) {
netvsc_free_send_slot(net_device,
-- 
2.9.3



[PATCH 03/14] hv_netvsc: use kcalloc

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Better to use kcalloc rather than kzalloc and multiply for an array.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index b15edfc..f64c978 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -421,8 +421,8 @@ static int netvsc_init_buf(struct hv_device *device)
net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt,
 BITS_PER_LONG);
 
-   net_device->send_section_map =
-   kzalloc(net_device->map_words * sizeof(ulong), GFP_KERNEL);
+   net_device->send_section_map = kcalloc(net_device->map_words,
+  sizeof(ulong), GFP_KERNEL);
if (net_device->send_section_map == NULL) {
ret = -ENOMEM;
goto cleanup;
-- 
2.9.3



[PATCH net-next 00/14] hv_netvsc: cleanups

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Hyper-V network driver cleanups.

The only new functionality is minor extensions to ethtool.

Apologies if this was already sent, still working out the
new email send methodolgy.

Stephen Hemminger (14):
  hv_netvsc: fix rtnl locking in callback
  hv_netvsc: make RSS hash key static
  hv_netvsc: use kcalloc
  hv_netvsc: style cleanups
  hv_netvsc: make inline functions static
  hv_netvsc: use ARRAY_SIZE() for NDIS versions
  hv_netvsc: make device_remove void
  hv_netvsc: init completion during alloc
  hv_netvsc: rearrange start_xmit
  hv_netvsc: refactor completion function
  hv_netvsc: make netvsc_destroy_buf void
  hv_netvsc: make variable local
  hv_netvsc: report vmbus name in ethtool
  hv_netvsc: add ethtool statistics for tx packet issues

 drivers/net/hyperv/hyperv_net.h   |   13 ++-
 drivers/net/hyperv/netvsc.c   |  242 -
 drivers/net/hyperv/netvsc_drv.c   |  194 ++
 drivers/net/hyperv/rndis_filter.c |   11 +--
 include/linux/hyperv.h|   91 +-
 5 files changed, 297 insertions(+), 254 deletions(-)

-- 
1.7.4.1



[PATCH 12/14] hv_netvsc: make variable local

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

The variable m_ret is only used in one basic block.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 471c476..2a9ccc4 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -956,7 +956,7 @@ int netvsc_send(struct hv_device *device,
struct sk_buff *skb)
 {
struct netvsc_device *net_device;
-   int ret = 0, m_ret = 0;
+   int ret = 0;
struct vmbus_channel *out_channel;
u16 q_idx = packet->q_idx;
u32 pktlen = packet->total_data_buflen, msd_len = 0;
@@ -1045,8 +1045,8 @@ int netvsc_send(struct hv_device *device,
}
 
if (msd_send) {
-   m_ret = netvsc_send_pkt(device, msd_send, net_device,
-   NULL, msd_skb);
+   int m_ret = netvsc_send_pkt(device, msd_send, net_device,
+   NULL, msd_skb);
 
if (m_ret != 0) {
netvsc_free_send_slot(net_device,
-- 
1.7.4.1



[PATCH 10/14] hv_netvsc: refactor completion function

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Break the different cases, code is cleaner if broken up

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |  107 +++
 1 files changed, 58 insertions(+), 49 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 27eb507..830aae2 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -696,69 +696,78 @@ static inline void netvsc_free_send_slot(struct 
netvsc_device *net_device,
sync_change_bit(index, net_device->send_section_map);
 }
 
+static void netvsc_send_tx_complete(struct netvsc_device *net_device,
+   struct vmbus_channel *incoming_channel,
+   struct hv_device *device,
+   struct vmpacket_descriptor *packet)
+{
+   struct sk_buff *skb = (struct sk_buff *)(unsigned long)packet->trans_id;
+   struct net_device *ndev = hv_get_drvdata(device);
+   struct net_device_context *net_device_ctx = netdev_priv(ndev);
+   struct vmbus_channel *channel = device->channel;
+   int num_outstanding_sends;
+   u16 q_idx = 0;
+   int queue_sends;
+
+   /* Notify the layer above us */
+   if (likely(skb)) {
+   struct hv_netvsc_packet *nvsc_packet
+   = (struct hv_netvsc_packet *)skb->cb;
+   u32 send_index = nvsc_packet->send_buf_index;
+
+   if (send_index != NETVSC_INVALID_INDEX)
+   netvsc_free_send_slot(net_device, send_index);
+   q_idx = nvsc_packet->q_idx;
+   channel = incoming_channel;
+
+   dev_kfree_skb_any(skb);
+   }
+
+   num_outstanding_sends =
+   atomic_dec_return(_device->num_outstanding_sends);
+   queue_sends = atomic_dec_return(_device->queue_sends[q_idx]);
+
+   if (net_device->destroy && num_outstanding_sends == 0)
+   wake_up(_device->wait_drain);
+
+   if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
+   !net_device_ctx->start_remove &&
+   (hv_ringbuf_avail_percent(>outbound) > 
RING_AVAIL_PERCENT_HIWATER ||
+queue_sends < 1))
+   netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
+}
+
 static void netvsc_send_completion(struct netvsc_device *net_device,
   struct vmbus_channel *incoming_channel,
   struct hv_device *device,
   struct vmpacket_descriptor *packet)
 {
struct nvsp_message *nvsp_packet;
-   struct hv_netvsc_packet *nvsc_packet;
struct net_device *ndev = hv_get_drvdata(device);
-   struct net_device_context *net_device_ctx = netdev_priv(ndev);
-   u32 send_index;
-   struct sk_buff *skb;
 
nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
-   (packet->offset8 << 3));
+ (packet->offset8 << 3));
 
-   if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
-   (nvsp_packet->hdr.msg_type ==
-NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
-   (nvsp_packet->hdr.msg_type ==
-NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE) ||
-   (nvsp_packet->hdr.msg_type ==
-NVSP_MSG5_TYPE_SUBCHANNEL)) {
+   switch (nvsp_packet->hdr.msg_type) {
+   case NVSP_MSG_TYPE_INIT_COMPLETE:
+   case NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE:
+   case NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE:
+   case NVSP_MSG5_TYPE_SUBCHANNEL:
/* Copy the response back */
memcpy(_device->channel_init_pkt, nvsp_packet,
   sizeof(struct nvsp_message));
complete(_device->channel_init_wait);
-   } else if (nvsp_packet->hdr.msg_type ==
-  NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
-   int num_outstanding_sends;
-   u16 q_idx = 0;
-   struct vmbus_channel *channel = device->channel;
-   int queue_sends;
-
-   /* Get the send context */
-   skb = (struct sk_buff *)(unsigned long)packet->trans_id;
-
-   /* Notify the layer above us */
-   if (skb) {
-   nvsc_packet = (struct hv_netvsc_packet *) skb->cb;
-   send_index = nvsc_packet->send_buf_index;
-   if (send_index != NETVSC_INVALID_INDEX)
-   netvsc_free_send_slot(net_device, send_index);
-   q_idx = nvsc_packet->q_idx;
-   channel = incoming_channel;
-   dev_kfree_skb_any(skb);
-   }
-
-   num_outstanding_sends =
-   atomic_dec_return(_device->num_outstanding_sends);
-   queue_sends = 

[PATCH 03/14] hv_netvsc: use kcalloc

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Better to use kcalloc rather than kzalloc and multiply for an array.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index b15edfc..f64c978 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -421,8 +421,8 @@ static int netvsc_init_buf(struct hv_device *device)
net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt,
 BITS_PER_LONG);
 
-   net_device->send_section_map =
-   kzalloc(net_device->map_words * sizeof(ulong), GFP_KERNEL);
+   net_device->send_section_map = kcalloc(net_device->map_words,
+  sizeof(ulong), GFP_KERNEL);
if (net_device->send_section_map == NULL) {
ret = -ENOMEM;
goto cleanup;
-- 
1.7.4.1



[PATCH 11/14] hv_netvsc: make netvsc_destroy_buf void

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

No caller checks the return value.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |   14 ++
 1 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 830aae2..471c476 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -206,12 +206,12 @@ get_in_err:
return net_device;
 }
 
-static int netvsc_destroy_buf(struct hv_device *device)
+static void netvsc_destroy_buf(struct hv_device *device)
 {
struct nvsp_message *revoke_packet;
-   int ret = 0;
struct net_device *ndev = hv_get_drvdata(device);
struct netvsc_device *net_device = net_device_to_netvsc_device(ndev);
+   int ret;
 
/*
 * If we got a section count, it means we received a
@@ -241,7 +241,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev, "unable to send "
"revoke receive buffer to netvsp\n");
-   return ret;
+   return;
}
}
 
@@ -256,7 +256,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev,
   "unable to teardown receive buffer's 
gpadl\n");
-   return ret;
+   return;
}
net_device->recv_buf_gpadl_handle = 0;
}
@@ -300,7 +300,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev, "unable to send "
   "revoke send buffer to netvsp\n");
-   return ret;
+   return;
}
}
/* Teardown the gpadl on the vsp end */
@@ -314,7 +314,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
if (ret != 0) {
netdev_err(ndev,
   "unable to teardown send buffer's gpadl\n");
-   return ret;
+   return;
}
net_device->send_buf_gpadl_handle = 0;
}
@@ -324,8 +324,6 @@ static int netvsc_destroy_buf(struct hv_device *device)
net_device->send_buf = NULL;
}
kfree(net_device->send_section_map);
-
-   return ret;
 }
 
 static int netvsc_init_buf(struct hv_device *device)
-- 
1.7.4.1



[PATCH 14/14] hv_netvsc: add ethtool statistics for tx packet issues

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Printing console messages is not helpful when system is out of memory;
and can be disastrous with netconsole. Instead keep statistics
of these anomalous conditions.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |9 
 drivers/net/hyperv/netvsc_drv.c |   86 +++---
 2 files changed, 79 insertions(+), 16 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 8031dee..284b97b 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -652,6 +652,14 @@ struct netvsc_stats {
struct u64_stats_sync syncp;
 };
 
+struct netvsc_ethtool_stats {
+   unsigned long tx_scattered;
+   unsigned long tx_no_memory;
+   unsigned long tx_no_space;
+   unsigned long tx_too_big;
+   unsigned long tx_busy;
+};
+
 struct netvsc_reconfig {
struct list_head list;
u32 event;
@@ -681,6 +689,7 @@ struct net_device_context {
/* Ethtool settings */
u8 duplex;
u32 speed;
+   struct netvsc_ethtool_stats eth_stats;
 
/* the device is going away */
bool start_remove;
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index b874ab1..2360e70 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -365,7 +365,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
u32 skb_length;
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
struct hv_page_buffer *pb = page_buf;
-   struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
 
/* We will atmost need two pages to describe the rndis
 * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
@@ -377,17 +376,14 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
num_data_pgs = netvsc_get_slots(skb) + 2;
 
if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
-   if (skb_linearize(skb)) {
-   net_alert_ratelimited("failed to linearize skb\n");
-   ret = -ENOMEM;
-   goto drop;
-   }
+   ++net_device_ctx->eth_stats.tx_scattered;
+
+   if (skb_linearize(skb))
+   goto no_memory;
 
num_data_pgs = netvsc_get_slots(skb) + 2;
if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
-   net_alert_ratelimited("packet too big: %u pages (%u 
bytes)\n",
- num_data_pgs, skb->len);
-   ret = -EFAULT;
+   ++net_device_ctx->eth_stats.tx_too_big;
goto drop;
}
}
@@ -398,11 +394,9 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
 * structure.
 */
ret = skb_cow_head(skb, RNDIS_AND_PPI_SIZE);
-   if (ret) {
-   netdev_err(net, "unable to alloc hv_netvsc_packet\n");
-   ret = -ENOMEM;
-   goto drop;
-   }
+   if (ret)
+   goto no_memory;
+
/* Use the skb control buffer for building up the packet */
BUILD_BUG_ON(sizeof(struct hv_netvsc_packet) >
FIELD_SIZEOF(struct sk_buff, cb));
@@ -518,7 +512,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
 
ret = skb_cow_head(skb, 0);
if (ret)
-   goto drop;
+   goto no_memory;
 
uh = udp_hdr(skb);
udp_len = ntohs(uh->len);
@@ -545,20 +539,32 @@ do_send:
ret = netvsc_send(net_device_ctx->device_ctx, packet,
  rndis_msg, , skb);
if (likely(ret == 0)) {
+   struct netvsc_stats *tx_stats = 
this_cpu_ptr(net_device_ctx->tx_stats);
+
u64_stats_update_begin(_stats->syncp);
tx_stats->packets++;
tx_stats->bytes += skb_length;
u64_stats_update_end(_stats->syncp);
return NETDEV_TX_OK;
}
-   if (ret == -EAGAIN)
+
+   if (ret == -EAGAIN) {
+   ++net_device_ctx->eth_stats.tx_busy;
return NETDEV_TX_BUSY;
+   }
+
+   if (ret == -ENOSPC)
+   ++net_device_ctx->eth_stats.tx_no_space;
 
 drop:
dev_kfree_skb_any(skb);
net->stats.tx_dropped++;
 
return NETDEV_TX_OK;
+
+no_memory:
+   ++net_device_ctx->eth_stats.tx_no_memory;
+   goto drop;
 }
 
 /*
@@ -1015,6 +1021,51 @@ static int netvsc_set_mac_addr(struct net_device *ndev, 
void *p)
return err;
 }
 
+static const struct {
+   char name[ETH_GSTRING_LEN];
+   u16 offset;
+} netvsc_stats[] = {
+   { "tx_scattered", offsetof(struct netvsc_ethtool_stats, 

[PATCH 04/14] hv_netvsc: style cleanups

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Fix most of the complaints about the style of the code.
Things like extra blank lines and return statements.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c   |   18 ++
 drivers/net/hyperv/netvsc_drv.c   |7 ---
 drivers/net/hyperv/rndis_filter.c |8 +---
 3 files changed, 3 insertions(+), 30 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index f64c978..fe83de3 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -59,7 +59,6 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
   VM_PKT_DATA_INBAND, 0);
 }
 
-
 static struct netvsc_device *alloc_net_device(void)
 {
struct netvsc_device *net_device;
@@ -123,7 +122,6 @@ get_in_err:
return net_device;
 }
 
-
 static int netvsc_destroy_buf(struct hv_device *device)
 {
struct nvsp_message *revoke_packet;
@@ -285,7 +283,6 @@ static int netvsc_init_buf(struct hv_device *device)
goto cleanup;
}
 
-
/* Notify the NetVsp of the gpadl handle */
init_packet = _device->channel_init_pkt;
 
@@ -412,7 +409,7 @@ static int netvsc_init_buf(struct hv_device *device)
/* Section count is simply the size divided by the section size.
 */
net_device->send_section_cnt =
-   net_device->send_buf_size/net_device->send_section_size;
+   net_device->send_buf_size / net_device->send_section_size;
 
dev_info(>device, "Send section size: %d, Section count:%d\n",
 net_device->send_section_size, net_device->send_section_cnt);
@@ -437,7 +434,6 @@ exit:
return ret;
 }
 
-
 /* Negotiate NVSP protocol version */
 static int negotiate_nvsp_ver(struct hv_device *device,
  struct netvsc_device *net_device,
@@ -593,7 +589,6 @@ int netvsc_device_remove(struct hv_device *device)
return 0;
 }
 
-
 #define RING_AVAIL_PERCENT_HIWATER 20
 #define RING_AVAIL_PERCENT_LOWATER 10
 
@@ -676,13 +671,11 @@ static void netvsc_send_completion(struct netvsc_device 
*net_device,
!net_device_ctx->start_remove &&
(hv_ringbuf_avail_percent(>outbound) >
 RING_AVAIL_PERCENT_HIWATER || queue_sends < 1))
-   netif_tx_wake_queue(netdev_get_tx_queue(
-   ndev, q_idx));
+   netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
} else {
netdev_err(ndev, "Unknown send completion packet type- "
   "%d received!!\n", nvsp_packet->hdr.msg_type);
}
-
 }
 
 static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
@@ -1157,7 +1150,6 @@ static void netvsc_receive(struct netvsc_device 
*net_device,
/* Pass it to the upper layer */
status = rndis_filter_receive(device, netvsc_packet, ,
  channel);
-
}
 
if (!net_device->mrc[q_idx].buf) {
@@ -1182,7 +1174,6 @@ static void netvsc_receive(struct netvsc_device 
*net_device,
rcd->status = status;
 }
 
-
 static void netvsc_send_table(struct hv_device *hdev,
  struct nvsp_message *nvmsg)
 {
@@ -1263,7 +1254,6 @@ static void netvsc_process_raw_pkt(struct hv_device 
*device,
}
 }
 
-
 void netvsc_channel_cb(void *context)
 {
int ret;
@@ -1320,8 +1310,6 @@ void netvsc_channel_cb(void *context)
   ndev,
   request_id,
   desc);
-
-
} else {
/*
 * We are done for this pass.
@@ -1350,8 +1338,6 @@ void netvsc_channel_cb(void *context)
kfree(buffer);
 
netvsc_chk_recv_comp(net_device, channel, q_idx);
-
-   return;
 }
 
 /*
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 6924d01a..3bbf073 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -40,7 +40,6 @@
 
 #include "hyperv_net.h"
 
-
 #define RING_SIZE_MIN 64
 #define LINKCHANGE_INT (2 * HZ)
 #define NETVSC_HW_FEATURES (NETIF_F_RXCSUM | \
@@ -411,7 +410,6 @@ check_size:
FIELD_SIZEOF(struct sk_buff, cb));
packet = (struct hv_netvsc_packet *)skb->cb;
 
-
packet->q_idx = skb_get_queue_mapping(skb);
 
packet->total_data_buflen = skb->len;
@@ -617,7 +615,6 @@ void netvsc_linkstatus_callback(struct hv_device 
*device_obj,
schedule_delayed_work(_ctx->dwork, 0);
 }
 
-
 static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
struct 

[PATCH 06/14] hv_netvsc: use ARRAY_SIZE() for NDIS versions

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Don't hard code size of array of NDIS versions.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |7 ---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 4ef2af6..110bbb8 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -577,9 +577,10 @@ static int netvsc_connect_vsp(struct hv_device *device)
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
int ndis_version;
-   u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
+   const u32 ver_list[] = {
+   NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
-   int i, num_ver = 4; /* number of different NVSP versions */
+   int i;
 
net_device = get_outbound_net_device(device);
if (!net_device)
@@ -588,7 +589,7 @@ static int netvsc_connect_vsp(struct hv_device *device)
init_packet = _device->channel_init_pkt;
 
/* Negotiate the latest NVSP protocol supported */
-   for (i = num_ver - 1; i >= 0; i--)
+   for (i = ARRAY_SIZE(ver_list) - 1; i >= 0; i--)
if (negotiate_nvsp_ver(device, net_device, init_packet,
   ver_list[i])  == 0) {
net_device->nvsp_version = ver_list[i];
-- 
1.7.4.1



[PATCH 01/14] hv_netvsc: fix rtnl locking in callback

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

The function get_netvsc_net_device had conditional locking. This was
unnecessary, incorrect, but harmless. It was unnecessary since the
code is only called from netlink netdev event callback where RTNL
is always acquired before the callbacks are run. It was incorrect
because of use of trylock and then continuing.
Fix by replacing with proper assertion.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c |5 +
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index eb2c122..6924d01a 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1167,9 +1167,8 @@ static void netvsc_free_netdev(struct net_device *netdev)
 static struct net_device *get_netvsc_net_device(char *mac)
 {
struct net_device *dev, *found = NULL;
-   int rtnl_locked;
 
-   rtnl_locked = rtnl_trylock();
+   ASSERT_RTNL();
 
for_each_netdev(_net, dev) {
if (memcmp(dev->dev_addr, mac, ETH_ALEN) == 0) {
@@ -1179,8 +1178,6 @@ static struct net_device *get_netvsc_net_device(char *mac)
break;
}
}
-   if (rtnl_locked)
-   rtnl_unlock();
 
return found;
 }
-- 
1.7.4.1



[PATCH 08/14] hv_netvsc: init completion during alloc

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Move initialization to allocate where other fields are initialized.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 2ece27a..27eb507 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -164,6 +164,7 @@ static struct netvsc_device *alloc_net_device(void)
atomic_set(_device->open_cnt, 0);
net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
+   init_completion(_device->channel_init_wait);
 
return net_device;
 }
@@ -1442,9 +1443,6 @@ int netvsc_device_add(struct hv_device *device, void 
*additional_info)
 
net_device->ring_size = ring_size;
 
-   /* Initialize the NetVSC channel extension */
-   init_completion(_device->channel_init_wait);
-
set_per_channel_state(device->channel, net_device->cb_buffer);
 
/* Open the channel */
-- 
1.7.4.1



[PATCH 13/14] hv_netvsc: report vmbus name in ethtool

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Make netvsc on vmbus behave more like PCI.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c |4 
 include/linux/hyperv.h  |7 +++
 2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 7ed9f13..b874ab1 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -734,8 +734,12 @@ vf_injection_done:
 static void netvsc_get_drvinfo(struct net_device *net,
   struct ethtool_drvinfo *info)
 {
+   struct net_device_context *net_device_ctx = netdev_priv(net);
+   struct hv_device *dev = net_device_ctx->device_ctx;
+
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+   strlcpy(info->bus_info, vmbus_dev_name(dev), sizeof(info->bus_info));
 }
 
 static void netvsc_get_channels(struct net_device *net,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index a6bc974..b01c8c3 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1114,6 +1114,13 @@ int __must_check __vmbus_driver_register(struct 
hv_driver *hv_driver,
 const char *mod_name);
 void vmbus_driver_unregister(struct hv_driver *hv_driver);
 
+static inline const char *vmbus_dev_name(const struct hv_device *device_obj)
+{
+   const struct kobject *kobj = _obj->device.kobj;
+
+   return kobj->name;
+}
+
 void vmbus_hvsock_device_unregister(struct vmbus_channel *channel);
 
 int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
-- 
1.7.4.1



[PATCH 05/14] hv_netvsc: make inline functions static

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Several new functions were introduced into hyperv.h but only used in one file.
Move them and let compiler decide on inline.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc.c |   85 ++-
 include/linux/hyperv.h  |   84 --
 2 files changed, 84 insertions(+), 85 deletions(-)

diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index fe83de3..4ef2af6 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -34,6 +34,89 @@
 #include "hyperv_net.h"
 
 /*
+ * An API to support in-place processing of incoming VMBUS packets.
+ */
+#define VMBUS_PKT_TRAILER  8
+
+static struct vmpacket_descriptor *
+get_next_pkt_raw(struct vmbus_channel *channel)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   u32 read_loc = ring_info->priv_read_index;
+   void *ring_buffer = hv_get_ring_buffer(ring_info);
+   struct vmpacket_descriptor *cur_desc;
+   u32 packetlen;
+   u32 dsize = ring_info->ring_datasize;
+   u32 delta = read_loc - ring_info->ring_buffer->read_index;
+   u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
+
+   if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
+   return NULL;
+
+   if ((read_loc + sizeof(*cur_desc)) > dsize)
+   return NULL;
+
+   cur_desc = ring_buffer + read_loc;
+   packetlen = cur_desc->len8 << 3;
+
+   /*
+* If the packet under consideration is wrapping around,
+* return failure.
+*/
+   if ((read_loc + packetlen + VMBUS_PKT_TRAILER) > (dsize - 1))
+   return NULL;
+
+   return cur_desc;
+}
+
+/*
+ * A helper function to step through packets "in-place"
+ * This API is to be called after each successful call
+ * get_next_pkt_raw().
+ */
+static void put_pkt_raw(struct vmbus_channel *channel,
+   struct vmpacket_descriptor *desc)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   u32 read_loc = ring_info->priv_read_index;
+   u32 packetlen = desc->len8 << 3;
+   u32 dsize = ring_info->ring_datasize;
+
+   BUG_ON((read_loc + packetlen + VMBUS_PKT_TRAILER) > dsize);
+
+   /*
+* Include the packet trailer.
+*/
+   ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
+}
+
+/*
+ * This call commits the read index and potentially signals the host.
+ * Here is the pattern for using the "in-place" consumption APIs:
+ *
+ * while (get_next_pkt_raw() {
+ * process the packet "in-place";
+ * put_pkt_raw();
+ * }
+ * if (packets processed in place)
+ * commit_rd_index();
+ */
+static void commit_rd_index(struct vmbus_channel *channel)
+{
+   struct hv_ring_buffer_info *ring_info = >inbound;
+   /*
+* Make sure all reads are done before we update the read index since
+* the writer may start writing to the read area once the read index
+* is updated.
+*/
+   virt_rmb();
+   ring_info->ring_buffer->read_index = ring_info->priv_read_index;
+
+   if (hv_need_to_signal_on_read(ring_info))
+   vmbus_set_event(channel);
+}
+
+/*
  * Switch the data path from the synthetic interface to the VF
  * interface.
  */
@@ -749,7 +832,7 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device 
*net_device,
return msg_size;
 }
 
-static inline int netvsc_send_pkt(
+static int netvsc_send_pkt(
struct hv_device *device,
struct hv_netvsc_packet *packet,
struct netvsc_device *net_device,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index b10954a..a6bc974 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1422,88 +1422,4 @@ static inline  bool hv_need_to_signal_on_read(struct 
hv_ring_buffer_info *rbi)
return false;
 }
 
-/*
- * An API to support in-place processing of incoming VMBUS packets.
- */
-#define VMBUS_PKT_TRAILER  8
-
-static inline struct vmpacket_descriptor *
-get_next_pkt_raw(struct vmbus_channel *channel)
-{
-   struct hv_ring_buffer_info *ring_info = >inbound;
-   u32 read_loc = ring_info->priv_read_index;
-   void *ring_buffer = hv_get_ring_buffer(ring_info);
-   struct vmpacket_descriptor *cur_desc;
-   u32 packetlen;
-   u32 dsize = ring_info->ring_datasize;
-   u32 delta = read_loc - ring_info->ring_buffer->read_index;
-   u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
-
-   if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
-   return NULL;
-
-   if ((read_loc + sizeof(*cur_desc)) > dsize)
-   return NULL;
-
-   cur_desc = ring_buffer + read_loc;
-   packetlen = cur_desc->len8 << 3;
-
-   /*
-* If the packet under consideration is wrapping around,
-* return failure.
-*/
-  

[PATCH 09/14] hv_netvsc: rearrange start_xmit

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Rearrange the transmit routine to eliminate goto's and unnecessary
boolean variables. Use standard functions to test for vlan tag.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/netvsc_drv.c |  106 +++
 1 files changed, 51 insertions(+), 55 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 3bbf073..7ed9f13 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -357,11 +357,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
struct rndis_message *rndis_msg;
struct rndis_packet *rndis_pkt;
u32 rndis_msg_size;
-   bool isvlan;
-   bool linear = false;
struct rndis_per_packet_info *ppi;
struct ndis_tcp_ip_checksum_info *csum_info;
-   struct ndis_tcp_lso_info *lso_info;
int  hdr_offset;
u32 net_trans_info;
u32 hash;
@@ -376,22 +373,23 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct 
net_device *net)
 * more pages we try linearizing it.
 */
 
-check_size:
skb_length = skb->len;
num_data_pgs = netvsc_get_slots(skb) + 2;
-   if (num_data_pgs > MAX_PAGE_BUFFER_COUNT && linear) {
-   net_alert_ratelimited("packet too big: %u pages (%u bytes)\n",
- num_data_pgs, skb->len);
-   ret = -EFAULT;
-   goto drop;
-   } else if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+
+   if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
if (skb_linearize(skb)) {
net_alert_ratelimited("failed to linearize skb\n");
ret = -ENOMEM;
goto drop;
}
-   linear = true;
-   goto check_size;
+
+   num_data_pgs = netvsc_get_slots(skb) + 2;
+   if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+   net_alert_ratelimited("packet too big: %u pages (%u 
bytes)\n",
+ num_data_pgs, skb->len);
+   ret = -EFAULT;
+   goto drop;
+   }
}
 
/*
@@ -418,8 +416,6 @@ check_size:
 
memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE);
 
-   isvlan = skb->vlan_tci & VLAN_TAG_PRESENT;
-
/* Add the rndis header */
rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
rndis_msg->msg_len = packet->total_data_buflen;
@@ -438,7 +434,7 @@ check_size:
*(u32 *)((void *)ppi + ppi->ppi_offset) = hash;
}
 
-   if (isvlan) {
+   if (skb_vlan_tag_present(skb)) {
struct ndis_pkt_8021q_info *vlan;
 
rndis_msg_size += NDIS_VLAN_PPI_SIZE;
@@ -459,8 +455,37 @@ check_size:
 * Setup the sendside checksum offload only if this is not a
 * GSO packet.
 */
-   if (skb_is_gso(skb))
-   goto do_lso;
+   if (skb_is_gso(skb)) {
+   struct ndis_tcp_lso_info *lso_info;
+
+   rndis_msg_size += NDIS_LSO_PPI_SIZE;
+   ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
+   TCP_LARGESEND_PKTINFO);
+
+   lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
+   ppi->ppi_offset);
+
+   lso_info->lso_v2_transmit.type = 
NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
+   if (net_trans_info & (INFO_IPV4 << 16)) {
+   lso_info->lso_v2_transmit.ip_version =
+   NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
+   ip_hdr(skb)->tot_len = 0;
+   ip_hdr(skb)->check = 0;
+   tcp_hdr(skb)->check =
+   ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+  ip_hdr(skb)->daddr, 0, 
IPPROTO_TCP, 0);
+   } else {
+   lso_info->lso_v2_transmit.ip_version =
+   NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
+   ipv6_hdr(skb)->payload_len = 0;
+   tcp_hdr(skb)->check =
+   ~csum_ipv6_magic(_hdr(skb)->saddr,
+_hdr(skb)->daddr, 0, 
IPPROTO_TCP, 0);
+   }
+   lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
+   lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
+   goto do_send;
+   }
 
if ((skb->ip_summed == CHECKSUM_NONE) ||
(skb->ip_summed == CHECKSUM_UNNECESSARY))
@@ -507,35 +532,6 @@ check_size:
 
csum_info->transmit.udp_checksum = 0;
}
-   goto do_send;
-
-do_lso:
-   rndis_msg_size += NDIS_LSO_PPI_SIZE;
-   ppi = 

[PATCH 07/14] hv_netvsc: make device_remove void

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Always returns 0 and no callers check.

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h |2 +-
 drivers/net/hyperv/netvsc.c |3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index b58e559..8031dee 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -173,7 +173,7 @@ struct rndis_device {
 struct rndis_message;
 struct netvsc_device;
 int netvsc_device_add(struct hv_device *device, void *additional_info);
-int netvsc_device_remove(struct hv_device *device);
+void netvsc_device_remove(struct hv_device *device);
 int netvsc_send(struct hv_device *device,
struct hv_netvsc_packet *packet,
struct rndis_message *rndis_msg,
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 110bbb8..2ece27a 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -648,7 +648,7 @@ static void netvsc_disconnect_vsp(struct hv_device *device)
 /*
  * netvsc_device_remove - Callback when the root bus device is removed
  */
-int netvsc_device_remove(struct hv_device *device)
+void netvsc_device_remove(struct hv_device *device)
 {
struct net_device *ndev = hv_get_drvdata(device);
struct net_device_context *net_device_ctx = netdev_priv(ndev);
@@ -670,7 +670,6 @@ int netvsc_device_remove(struct hv_device *device)
/* Release all resources */
vfree(net_device->sub_cb_buf);
free_netvsc_device(net_device);
-   return 0;
 }
 
 #define RING_AVAIL_PERCENT_HIWATER 20
-- 
1.7.4.1



[PATCH 02/14] hv_netvsc: make RSS hash key static

2016-08-23 Thread sthemmin
From: Stephen Hemminger 

Signed-off-by: Stephen Hemminger 
---
 drivers/net/hyperv/hyperv_net.h   |2 --
 drivers/net/hyperv/rndis_filter.c |3 ++-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index ce45d68..b58e559 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -84,8 +84,6 @@ struct ndis_recv_scale_cap { /* 
NDIS_RECEIVE_SCALE_CAPABILITIES */
 #define NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2   40
 
 #define ITAB_NUM 128
-#define HASH_KEYLEN NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2
-extern u8 netvsc_hash_key[];
 
 struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */
struct ndis_obj_header hdr;
diff --git a/drivers/net/hyperv/rndis_filter.c 
b/drivers/net/hyperv/rndis_filter.c
index 3ecb2d0..a100380 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -663,13 +663,14 @@ cleanup:
return ret;
 }
 
-u8 netvsc_hash_key[HASH_KEYLEN] = {
+static const u8 netvsc_hash_key[] = {
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
 };
+#define HASH_KEYLEN ARRAY_SIZE(netvsc_hash_key)
 
 static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
 {
-- 
1.7.4.1