summaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r--drivers/net/hyperv/hyperv_net.h6
-rw-r--r--drivers/net/hyperv/netvsc.c37
-rw-r--r--drivers/net/hyperv/netvsc_drv.c30
3 files changed, 40 insertions, 33 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 02a3ee282ee..2f48f790c9b 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -585,13 +585,13 @@ struct nvsp_message {
#define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */
#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */
-#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024 * 16) /* 16MB */
+#define NETVSC_SEND_BUFFER_SIZE (1024 * 1024 * 15) /* 15MB */
#define NETVSC_INVALID_INDEX -1
#define NETVSC_RECEIVE_BUFFER_ID 0xcafe
-#define NETVSC_PACKET_SIZE 2048
+#define NETVSC_PACKET_SIZE 4096
#define VRSS_SEND_TAB_SIZE 16
@@ -642,7 +642,7 @@ struct netvsc_device {
int ring_size;
/* The primary channel callback buffer */
- unsigned char cb_buffer[NETVSC_PACKET_SIZE];
+ unsigned char *cb_buffer;
/* The sub channel callback buffer */
unsigned char *sub_cb_buf;
};
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 66979cf7fca..7d76c952339 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -42,6 +42,12 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
if (!net_device)
return NULL;
+ net_device->cb_buffer = kzalloc(NETVSC_PACKET_SIZE, GFP_KERNEL);
+ if (!net_device->cb_buffer) {
+ kfree(net_device);
+ return NULL;
+ }
+
init_waitqueue_head(&net_device->wait_drain);
net_device->start_remove = false;
net_device->destroy = false;
@@ -52,6 +58,12 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
return net_device;
}
+static void free_netvsc_device(struct netvsc_device *nvdev)
+{
+ kfree(nvdev->cb_buffer);
+ kfree(nvdev);
+}
+
static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
{
struct netvsc_device *net_device;
@@ -551,7 +563,7 @@ int netvsc_device_remove(struct hv_device *device)
if (net_device->sub_cb_buf)
vfree(net_device->sub_cb_buf);
- kfree(net_device);
+ free_netvsc_device(net_device);
return 0;
}
@@ -705,6 +717,7 @@ int netvsc_send(struct hv_device *device,
unsigned int section_index = NETVSC_INVALID_INDEX;
u32 msg_size = 0;
struct sk_buff *skb;
+ u16 q_idx = packet->q_idx;
net_device = get_outbound_net_device(device);
@@ -769,24 +782,24 @@ int netvsc_send(struct hv_device *device,
if (ret == 0) {
atomic_inc(&net_device->num_outstanding_sends);
- atomic_inc(&net_device->queue_sends[packet->q_idx]);
+ atomic_inc(&net_device->queue_sends[q_idx]);
if (hv_ringbuf_avail_percent(&out_channel->outbound) <
RING_AVAIL_PERCENT_LOWATER) {
netif_tx_stop_queue(netdev_get_tx_queue(
- ndev, packet->q_idx));
+ ndev, q_idx));
if (atomic_read(&net_device->
- queue_sends[packet->q_idx]) < 1)
+ queue_sends[q_idx]) < 1)
netif_tx_wake_queue(netdev_get_tx_queue(
- ndev, packet->q_idx));
+ ndev, q_idx));
}
} else if (ret == -EAGAIN) {
netif_tx_stop_queue(netdev_get_tx_queue(
- ndev, packet->q_idx));
- if (atomic_read(&net_device->queue_sends[packet->q_idx]) < 1) {
+ ndev, q_idx));
+ if (atomic_read(&net_device->queue_sends[q_idx]) < 1) {
netif_tx_wake_queue(netdev_get_tx_queue(
- ndev, packet->q_idx));
+ ndev, q_idx));
ret = -ENOSPC;
}
} else {
@@ -1042,10 +1055,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
struct net_device *ndev;
net_device = alloc_net_device(device);
- if (!net_device) {
- ret = -ENOMEM;
- goto cleanup;
- }
+ if (!net_device)
+ return -ENOMEM;
net_device->ring_size = ring_size;
@@ -1093,7 +1104,7 @@ close:
vmbus_close(device->channel);
cleanup:
- kfree(net_device);
+ free_netvsc_device(net_device);
return ret;
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index a9c5eaadc42..78ec33f5100 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -162,7 +162,7 @@ union sub_key {
* data: network byte order
* return: host byte order
*/
-static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen)
+static u32 comp_hash(u8 *key, int klen, void *data, int dlen)
{
union sub_key subk;
int k_next = 4;
@@ -176,7 +176,7 @@ static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen)
for (i = 0; i < dlen; i++) {
subk.kb = key[k_next];
k_next = (k_next + 1) % klen;
- dt = data[i];
+ dt = ((u8 *)data)[i];
for (j = 0; j < 8; j++) {
if (dt & 0x80)
ret ^= subk.ka;
@@ -190,26 +190,20 @@ static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen)
static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
{
- struct iphdr *iphdr;
+ struct flow_keys flow;
int data_len;
- bool ret = false;
- if (eth_hdr(skb)->h_proto != htons(ETH_P_IP))
+ if (!skb_flow_dissect(skb, &flow) || flow.n_proto != htons(ETH_P_IP))
return false;
- iphdr = ip_hdr(skb);
+ if (flow.ip_proto == IPPROTO_TCP)
+ data_len = 12;
+ else
+ data_len = 8;
- if (iphdr->version == 4) {
- if (iphdr->protocol == IPPROTO_TCP)
- data_len = 12;
- else
- data_len = 8;
- *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN,
- (u8 *)&iphdr->saddr, data_len);
- ret = true;
- }
+ *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, &flow, data_len);
- return ret;
+ return true;
}
static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
@@ -387,6 +381,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
int hdr_offset;
u32 net_trans_info;
u32 hash;
+ u32 skb_length = skb->len;
/* We will atmost need two pages to describe the rndis
@@ -555,6 +550,7 @@ do_lso:
do_send:
/* Start filling in the page buffers with the rndis hdr */
rndis_msg->msg_len += rndis_msg_size;
+ packet->total_data_buflen = rndis_msg->msg_len;
packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
skb, &packet->page_buf[0]);
@@ -562,7 +558,7 @@ do_send:
drop:
if (ret == 0) {
- net->stats.tx_bytes += skb->len;
+ net->stats.tx_bytes += skb_length;
net->stats.tx_packets++;
} else {
kfree(packet);