1fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen/*
2fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * Copyright (c) 2009, Microsoft Corporation.
3fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen *
4fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * This program is free software; you can redistribute it and/or modify it
5fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * under the terms and conditions of the GNU General Public License,
6fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * version 2, as published by the Free Software Foundation.
7fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen *
8fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * This program is distributed in the hope it will be useful, but WITHOUT
9fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * more details.
12fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen *
13fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * You should have received a copy of the GNU General Public License along with
14fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * Place - Suite 330, Boston, MA 02111-1307 USA.
16fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen *
17fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen * Authors:
18d0e94d17ed8590d53252212414a627125825b379Haiyang Zhang *   Haiyang Zhang <haiyangz@microsoft.com>
19fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen *   Hank Janssen  <hjanssen@microsoft.com>
20fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen */
21eb335bc42781ddc19da98a3c74add1013ba08da2Hank Janssen#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22eb335bc42781ddc19da98a3c74add1013ba08da2Hank Janssen
235654e932262840f853233317689fc59536226d76Greg Kroah-Hartman#include <linux/kernel.h>
240c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan#include <linux/sched.h>
250c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan#include <linux/wait.h>
260ffa63b09bf99ce3ee879c7de1c687267a90d20bGreg Kroah-Hartman#include <linux/mm.h>
27b4362c9c1fe8bec487e275f92fdf57c585ac236aGreg Kroah-Hartman#include <linux/delay.h>
2821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman#include <linux/io.h>
295a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
30d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang#include <linux/netdevice.h>
31f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang#include <linux/if_ether.h>
323f335ea2131b14bca2333b4316c8d4dd737e30dbK. Y. Srinivasan
335ca7252a7e2be5e05772f202d94e173b7224e7a9K. Y. Srinivasan#include "hyperv_net.h"
34fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
35fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
365a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic struct netvsc_device *alloc_net_device(struct hv_device *device)
37fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
3885799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
392ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev = hv_get_drvdata(device);
40fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
4185799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
4285799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	if (!net_device)
43fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return NULL;
44fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
454d447c9a6ebc0142d320f075c5bac6d202a79fd4Haiyang Zhang	net_device->start_remove = false;
46c38b9c7118b95aa48bfa38d3bcd241dba3d23c10K. Y. Srinivasan	net_device->destroy = false;
4753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	net_device->dev = device;
482ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	net_device->ndev = ndev;
49fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
502ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	hv_set_drvdata(device, net_device);
5185799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	return net_device;
52fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
53fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
545a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic struct netvsc_device *get_outbound_net_device(struct hv_device *device)
55fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
5685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
57fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
582ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	net_device = hv_get_drvdata(device);
599d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	if (net_device && net_device->destroy)
6085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		net_device = NULL;
61fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
6285799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	return net_device;
63fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
64fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
655a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic struct netvsc_device *get_inbound_net_device(struct hv_device *device)
66fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
6785799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
68fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
692ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	net_device = hv_get_drvdata(device);
709d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan
719d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	if (!net_device)
729d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan		goto get_in_err;
739d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan
749d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	if (net_device->destroy &&
759d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan		atomic_read(&net_device->num_outstanding_sends) == 0)
7685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		net_device = NULL;
77fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
789d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasanget_in_err:
7985799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	return net_device;
80fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
81fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
82fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
83ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhangstatic int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
84ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang{
85ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	struct nvsp_message *revoke_packet;
86ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	int ret = 0;
872ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev = net_device->ndev;
88ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
89ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	/*
90ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	 * If we got a section count, it means we received a
91ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	 * SendReceiveBufferComplete msg (ie sent
92ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	 * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
93ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	 * to send a revoke msg here
94ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	 */
95ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	if (net_device->recv_section_cnt) {
96ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		/* Send the revoke receive buffer */
97ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		revoke_packet = &net_device->revoke_packet;
98ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		memset(revoke_packet, 0, sizeof(struct nvsp_message));
99ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
100ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		revoke_packet->hdr.msg_type =
101ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang			NVSP_MSG1_TYPE_REVOKE_RECV_BUF;
102ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		revoke_packet->msg.v1_msg.
103ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
104ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
105ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		ret = vmbus_sendpacket(net_device->dev->channel,
106ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang				       revoke_packet,
107ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang				       sizeof(struct nvsp_message),
108ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang				       (unsigned long)revoke_packet,
109ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang				       VM_PKT_DATA_INBAND, 0);
110ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		/*
111ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		 * If we failed here, we might as well return and
112ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		 * have a leak rather than continue and a bugchk
113ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		 */
114ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		if (ret != 0) {
115d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang			netdev_err(ndev, "unable to send "
116c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang				"revoke receive buffer to netvsp\n");
117a3e00530469baa39ccc08b1731a4e120bd63012fK. Y. Srinivasan			return ret;
118ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		}
119ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	}
120ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
121ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	/* Teardown the gpadl on the vsp end */
122ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	if (net_device->recv_buf_gpadl_handle) {
123ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		ret = vmbus_teardown_gpadl(net_device->dev->channel,
124ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang			   net_device->recv_buf_gpadl_handle);
125ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
126ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		/* If we failed here, we might as well return and have a leak
127ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		 * rather than continue and a bugchk
128ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		 */
129ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		if (ret != 0) {
130d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang			netdev_err(ndev,
131c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang				   "unable to teardown receive buffer's gpadl\n");
1327f9615e6f6c703c68f84460fe22b858be6c258d1Dan Carpenter			return ret;
133ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		}
134ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		net_device->recv_buf_gpadl_handle = 0;
135ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	}
136ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
137ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	if (net_device->recv_buf) {
138ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		/* Free up the receive buffer */
139ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		free_pages((unsigned long)net_device->recv_buf,
140ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang			get_order(net_device->recv_buf_size));
141ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		net_device->recv_buf = NULL;
142ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	}
143ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
144ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	if (net_device->recv_section) {
145ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		net_device->recv_section_cnt = 0;
146ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		kfree(net_device->recv_section);
147ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang		net_device->recv_section = NULL;
148ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	}
149ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
150ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang	return ret;
151ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang}
152ec91cd09b153d896d14bb2882d6128a97f00ff41Haiyang Zhang
1535a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic int netvsc_init_recv_buf(struct hv_device *device)
154fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
15521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	int ret = 0;
15635abb21ace3413de6ea8d5c7750cedfd46111f0cK. Y. Srinivasan	int t;
15785799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
15885799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct nvsp_message *init_packet;
1592ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
160fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
1615a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	net_device = get_outbound_net_device(device);
1622ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	if (!net_device)
163927bc33c0a239b706635b23c5cc1f3df2a3c8b86K. Y. Srinivasan		return -ENODEV;
1642ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
165fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
16653d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	net_device->recv_buf =
167df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan		(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
168df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan				get_order(net_device->recv_buf_size));
16953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if (!net_device->recv_buf) {
170d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "unable to allocate receive "
171c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"buffer of size %d\n", net_device->recv_buf_size);
172927bc33c0a239b706635b23c5cc1f3df2a3c8b86K. Y. Srinivasan		ret = -ENOMEM;
1730c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
174fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
175fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
176454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
177454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * Establish the gpadl handle for this buffer on this
178454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * channel.  Note: This call uses the vmbus connection rather
179454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * than the channel to establish the gpadl handle.
180454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
18153d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	ret = vmbus_establish_gpadl(device->channel, net_device->recv_buf,
18253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang				    net_device->recv_buf_size,
18353d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang				    &net_device->recv_buf_gpadl_handle);
18421a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	if (ret != 0) {
185d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev,
186c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"unable to establish receive buffer's gpadl\n");
1870c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
188fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
189fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
190fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
191454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Notify the NetVsp of the gpadl handle */
19253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet = &net_device->channel_init_pkt;
193fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
19485799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	memset(init_packet, 0, sizeof(struct nvsp_message));
195fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
19653d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF;
19753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->msg.v1_msg.send_recv_buf.
19853d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		gpadl_handle = net_device->recv_buf_gpadl_handle;
19953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->msg.v1_msg.
20053d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID;
201fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
202454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Send the gpadl notification request */
20385799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	ret = vmbus_sendpacket(device->channel, init_packet,
2045a4df29058625ce59f549730817961b293f58d49Greg Kroah-Hartman			       sizeof(struct nvsp_message),
20585799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			       (unsigned long)init_packet,
206415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			       VM_PKT_DATA_INBAND,
2075a4df29058625ce59f549730817961b293f58d49Greg Kroah-Hartman			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
20821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	if (ret != 0) {
209d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev,
210c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"unable to send receive buffer's gpadl to netvsp\n");
2110c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
212fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
213fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
2145c5781b3f88567211ecaaada13431af15c8c6003K. Y. Srinivasan	t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
21535abb21ace3413de6ea8d5c7750cedfd46111f0cK. Y. Srinivasan	BUG_ON(t == 0);
2160c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan
217fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
218454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Check the response */
21953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if (init_packet->msg.v1_msg.
22053d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	    send_recv_buf_complete.status != NVSP_STAT_SUCCESS) {
221d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Unable to complete receive buffer "
2228bff33ab417f246dac4ab9835be6894eaddfb546Haiyang Zhang			   "initialization with NetVsp - status %d\n",
22353d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang			   init_packet->msg.v1_msg.
22453d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang			   send_recv_buf_complete.status);
225927bc33c0a239b706635b23c5cc1f3df2a3c8b86K. Y. Srinivasan		ret = -EINVAL;
2260c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
227fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
228fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
229454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Parse the response */
230fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
23153d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	net_device->recv_section_cnt = init_packet->msg.
23253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		v1_msg.send_recv_buf_complete.num_sections;
233fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
234c18132005e711c07523d8c6602e5b2266ab9a0f2Haiyang Zhang	net_device->recv_section = kmemdup(
235c18132005e711c07523d8c6602e5b2266ab9a0f2Haiyang Zhang		init_packet->msg.v1_msg.send_recv_buf_complete.sections,
236c18132005e711c07523d8c6602e5b2266ab9a0f2Haiyang Zhang		net_device->recv_section_cnt *
237c18132005e711c07523d8c6602e5b2266ab9a0f2Haiyang Zhang		sizeof(struct nvsp_1_receive_buffer_section),
238c18132005e711c07523d8c6602e5b2266ab9a0f2Haiyang Zhang		GFP_KERNEL);
23953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if (net_device->recv_section == NULL) {
240927bc33c0a239b706635b23c5cc1f3df2a3c8b86K. Y. Srinivasan		ret = -EINVAL;
2410c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
242fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
243fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
24421a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	/*
24521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	 * For 1st release, there should only be 1 section that represents the
24621a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	 * entire receive buffer
24721a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	 */
24853d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if (net_device->recv_section_cnt != 1 ||
24953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	    net_device->recv_section->offset != 0) {
250927bc33c0a239b706635b23c5cc1f3df2a3c8b86K. Y. Srinivasan		ret = -EINVAL;
2510c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
252fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
253fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
2540c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan	goto exit;
255fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
2560c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasancleanup:
2575a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	netvsc_destroy_recv_buf(net_device);
258fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
2590c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasanexit:
260fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	return ret;
261fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
262fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
263fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
264f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang/* Negotiate NVSP protocol version */
265f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhangstatic int negotiate_nvsp_ver(struct hv_device *device,
266f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang			      struct netvsc_device *net_device,
267f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang			      struct nvsp_message *init_packet,
268f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang			      u32 nvsp_ver)
269fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
27035abb21ace3413de6ea8d5c7750cedfd46111f0cK. Y. Srinivasan	int ret, t;
271fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
27285799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	memset(init_packet, 0, sizeof(struct nvsp_message));
27353d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
274f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver;
275f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver;
276fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
277454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Send the init request */
27885799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	ret = vmbus_sendpacket(device->channel, init_packet,
2795a4df29058625ce59f549730817961b293f58d49Greg Kroah-Hartman			       sizeof(struct nvsp_message),
28085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			       (unsigned long)init_packet,
281415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			       VM_PKT_DATA_INBAND,
2825a4df29058625ce59f549730817961b293f58d49Greg Kroah-Hartman			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
28321a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman
284b8a3d52b2f7db637edcb62f9a332e1b35eefad13Hank Janssen	if (ret != 0)
285f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		return ret;
286fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
2875c5781b3f88567211ecaaada13431af15c8c6003K. Y. Srinivasan	t = wait_for_completion_timeout(&net_device->channel_init_wait, 5*HZ);
28835abb21ace3413de6ea8d5c7750cedfd46111f0cK. Y. Srinivasan
289f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	if (t == 0)
290f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		return -ETIMEDOUT;
291fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
29253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if (init_packet->msg.init_msg.init_complete.status !=
293f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	    NVSP_STAT_SUCCESS)
294f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		return -EINVAL;
295fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
296f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	if (nvsp_ver != NVSP_PROTOCOL_VERSION_2)
297f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		return 0;
298f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
299f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	/* NVSPv2 only: Send NDIS config */
300f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	memset(init_packet, 0, sizeof(struct nvsp_message));
301f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG;
3024d447c9a6ebc0142d320f075c5bac6d202a79fd4Haiyang Zhang	init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu;
3031f5f3a75e216fe771b8d6805e0bb2f43595a6ee1Haiyang Zhang	init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
304f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
305f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	ret = vmbus_sendpacket(device->channel, init_packet,
306f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang				sizeof(struct nvsp_message),
307f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang				(unsigned long)init_packet,
308f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang				VM_PKT_DATA_INBAND, 0);
309f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
310f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	return ret;
311f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang}
312f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
313f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhangstatic int netvsc_connect_vsp(struct hv_device *device)
314f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang{
315f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	int ret;
316f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	struct netvsc_device *net_device;
317f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	struct nvsp_message *init_packet;
318f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	int ndis_version;
319f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	struct net_device *ndev;
320f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
321f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	net_device = get_outbound_net_device(device);
322f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	if (!net_device)
323f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		return -ENODEV;
324f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	ndev = net_device->ndev;
325f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
326f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	init_packet = &net_device->channel_init_pkt;
327f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
328f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	/* Negotiate the latest NVSP protocol supported */
329f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	if (negotiate_nvsp_ver(device, net_device, init_packet,
330f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang			       NVSP_PROTOCOL_VERSION_2) == 0) {
331f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2;
332f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	} else if (negotiate_nvsp_ver(device, net_device, init_packet,
333f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang				    NVSP_PROTOCOL_VERSION_1) == 0) {
334f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang		net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1;
335f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	} else {
3360f48c72ca63a6e1da7f226163c36fecd7a923fedK. Y. Srinivasan		ret = -EPROTO;
3370c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
338fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
339f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
340f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang	pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version);
341f157e78de5923dfb209355f3005ce1b5d64f7998Haiyang Zhang
342454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Send the ndis version */
34385799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	memset(init_packet, 0, sizeof(struct nvsp_message));
344fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
3451f5f3a75e216fe771b8d6805e0bb2f43595a6ee1Haiyang Zhang	ndis_version = 0x00050001;
346fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
34753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER;
34853d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->msg.v1_msg.
34953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		send_ndis_ver.ndis_major_ver =
35085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang				(ndis_version & 0xFFFF0000) >> 16;
35153d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	init_packet->msg.v1_msg.
35253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		send_ndis_ver.ndis_minor_ver =
35385799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang				ndis_version & 0xFFFF;
354fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
355454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Send the init request */
35685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	ret = vmbus_sendpacket(device->channel, init_packet,
3570c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan				sizeof(struct nvsp_message),
3580c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan				(unsigned long)init_packet,
3590c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan				VM_PKT_DATA_INBAND, 0);
3600f48c72ca63a6e1da7f226163c36fecd7a923fedK. Y. Srinivasan	if (ret != 0)
3610c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		goto cleanup;
362454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton
363454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Post the big receive buffer to NetVSP */
3645a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	ret = netvsc_init_recv_buf(device);
365fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
3660c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasancleanup:
367fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	return ret;
368fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
369fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
370648dc59899073d4d23ba346c0281dc96792725b3Haiyang Zhangstatic void netvsc_disconnect_vsp(struct netvsc_device *net_device)
371fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
3725a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	netvsc_destroy_recv_buf(net_device);
373fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
374fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
3753e18951955797872558dad615851a4ca63b2770eHank Janssen/*
3765a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang * netvsc_device_remove - Callback when the root bus device is removed
37721a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman */
378905620d16f5c9e7c8ff850e15f47f5700824f6fbK. Y. Srinivasanint netvsc_device_remove(struct hv_device *device)
379fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
38085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
38185799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct hv_netvsc_packet *netvsc_packet, *pos;
382c38b9c7118b95aa48bfa38d3bcd241dba3d23c10K. Y. Srinivasan	unsigned long flags;
383fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
3842ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	net_device = hv_get_drvdata(device);
385c38b9c7118b95aa48bfa38d3bcd241dba3d23c10K. Y. Srinivasan	spin_lock_irqsave(&device->channel->inbound_lock, flags);
386c38b9c7118b95aa48bfa38d3bcd241dba3d23c10K. Y. Srinivasan	net_device->destroy = true;
387c38b9c7118b95aa48bfa38d3bcd241dba3d23c10K. Y. Srinivasan	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
388c38b9c7118b95aa48bfa38d3bcd241dba3d23c10K. Y. Srinivasan
389454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Wait for all send completions */
39053d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	while (atomic_read(&net_device->num_outstanding_sends)) {
391d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		dev_info(&device->device,
392c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"waiting for %d requests to complete...\n",
393eb335bc42781ddc19da98a3c74add1013ba08da2Hank Janssen			atomic_read(&net_device->num_outstanding_sends));
394b4362c9c1fe8bec487e275f92fdf57c585ac236aGreg Kroah-Hartman		udelay(100);
395fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
396fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
397648dc59899073d4d23ba346c0281dc96792725b3Haiyang Zhang	netvsc_disconnect_vsp(net_device);
398fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
3993852409b88e8ec2a8abb28db5be25a7503297208K. Y. Srinivasan	/*
4009d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	 * Since we have already drained, we don't need to busy wait
4019d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	 * as was done in final_release_stor_device()
4029d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	 * Note that we cannot set the ext pointer to NULL until
4039d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	 * we have drained - to drain the outgoing packets, we need to
4049d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	 * allow incoming packets.
4053852409b88e8ec2a8abb28db5be25a7503297208K. Y. Srinivasan	 */
4069d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan
4079d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	spin_lock_irqsave(&device->channel->inbound_lock, flags);
4082ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	hv_set_drvdata(device, NULL);
4099d88f33a1530f4241227226e7479d36ac959e9ceK. Y. Srinivasan	spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
4103852409b88e8ec2a8abb28db5be25a7503297208K. Y. Srinivasan
41186c921af41f0d40ff9105a73fb20378440f0299fK. Y. Srinivasan	/*
41286c921af41f0d40ff9105a73fb20378440f0299fK. Y. Srinivasan	 * At this point, no one should be accessing net_device
41386c921af41f0d40ff9105a73fb20378440f0299fK. Y. Srinivasan	 * except in here
41486c921af41f0d40ff9105a73fb20378440f0299fK. Y. Srinivasan	 */
415c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang	dev_notice(&device->device, "net device safe to remove\n");
416fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
417454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Now, we can close the channel safely */
41885799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	vmbus_close(device->channel);
419fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
420454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Release all resources */
42185799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	list_for_each_entry_safe(netvsc_packet, pos,
42253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang				 &net_device->recv_pkt_list, list_ent) {
42372a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		list_del(&netvsc_packet->list_ent);
42485799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		kfree(netvsc_packet);
425fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
426fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
427356c4657193c8a5b3aff84fe8cdf5ddc64742801K. Y. Srinivasan	kfree(net_device);
42821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	return 0;
429fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
430fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
4315a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic void netvsc_send_completion(struct hv_device *device,
43285799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang				   struct vmpacket_descriptor *packet)
433fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
43485799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
43585799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct nvsp_message *nvsp_packet;
43685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct hv_netvsc_packet *nvsc_packet;
4372ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
438fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
4395a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	net_device = get_inbound_net_device(device);
4402ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	if (!net_device)
441fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return;
4422ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
443fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
44485799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
445415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			(packet->offset8 << 3));
446fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
44753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
44853d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	    (nvsp_packet->hdr.msg_type ==
44953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	     NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
45053d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	    (nvsp_packet->hdr.msg_type ==
45153d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	     NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE)) {
452454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Copy the response back */
45353d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		memcpy(&net_device->channel_init_pkt, nvsp_packet,
45421a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman		       sizeof(struct nvsp_message));
45535abb21ace3413de6ea8d5c7750cedfd46111f0cK. Y. Srinivasan		complete(&net_device->channel_init_wait);
45653d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	} else if (nvsp_packet->hdr.msg_type ==
45753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		   NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
458454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Get the send context */
45985799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		nvsc_packet = (struct hv_netvsc_packet *)(unsigned long)
460415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			packet->trans_id;
461fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
462454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Notify the layer above us */
46372a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		nvsc_packet->completion.send.send_completion(
46472a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang			nvsc_packet->completion.send.send_completion_ctx);
465fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
46653d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		atomic_dec(&net_device->num_outstanding_sends);
4671d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang
4684d447c9a6ebc0142d320f075c5bac6d202a79fd4Haiyang Zhang		if (netif_queue_stopped(ndev) && !net_device->start_remove)
4691d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang			netif_wake_queue(ndev);
47021a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	} else {
471d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Unknown send completion packet type- "
472c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			   "%d received!!\n", nvsp_packet->hdr.msg_type);
473fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
474fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
475fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
476fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
477f9819f05f2c5a3fb61853c5fc8d20d61dfbfe89bK. Y. Srinivasanint netvsc_send(struct hv_device *device,
47885799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			struct hv_netvsc_packet *packet)
479fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
48085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
48121a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	int ret = 0;
482223c1aa632dbad672ad9b907e5d5e8f385417945Greg Kroah-Hartman	struct nvsp_message sendMessage;
4832ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
484fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
4855a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	net_device = get_outbound_net_device(device);
4862ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	if (!net_device)
487ff2bd69ae3ec164b606114fcbd9b9e4d5f2bcdc7K. Y. Srinivasan		return -ENODEV;
4882ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
489fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
49053d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	sendMessage.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
49172a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang	if (packet->is_data_pkt) {
49221a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman		/* 0 is RMC_DATA; */
49353d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 0;
49421a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	} else {
49521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman		/* 1 is RMC_CONTROL; */
49653d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		sendMessage.msg.v1_msg.send_rndis_pkt.channel_type = 1;
49721a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	}
498fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
499454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Not using send buffer section */
50053d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_index =
50153d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		0xFFFFFFFF;
50253d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0;
50321a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman
50472a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang	if (packet->page_buf_cnt) {
50585799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		ret = vmbus_sendpacket_pagebuffer(device->channel,
50672a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang						  packet->page_buf,
50772a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang						  packet->page_buf_cnt,
508ff3f8eece20bb45f8b515641b3797b6047a657fdGreg Kroah-Hartman						  &sendMessage,
509ff3f8eece20bb45f8b515641b3797b6047a657fdGreg Kroah-Hartman						  sizeof(struct nvsp_message),
51085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang						  (unsigned long)packet);
51121a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	} else {
51285799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		ret = vmbus_sendpacket(device->channel, &sendMessage,
513e4d59ac5c6bbb671b61108dad0c7cd33c753ce22Haiyang Zhang				sizeof(struct nvsp_message),
514e4d59ac5c6bbb671b61108dad0c7cd33c753ce22Haiyang Zhang				(unsigned long)packet,
515e4d59ac5c6bbb671b61108dad0c7cd33c753ce22Haiyang Zhang				VM_PKT_DATA_INBAND,
516e4d59ac5c6bbb671b61108dad0c7cd33c753ce22Haiyang Zhang				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
517fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
518fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
519fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
5201d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang	if (ret == 0) {
5211d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang		atomic_inc(&net_device->num_outstanding_sends);
5221d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang	} else if (ret == -EAGAIN) {
5231d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang		netif_stop_queue(ndev);
5241d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang		if (atomic_read(&net_device->num_outstanding_sends) < 1)
5251d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang			netif_wake_queue(ndev);
5261d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang	} else {
527d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Unable to send packet %p ret %d\n",
52885799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			   packet, ret);
5291d06825b0ede541f63b5577435abd2fc649a9b5eHaiyang Zhang	}
530fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
531fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	return ret;
532fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
533fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
5345fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhangstatic void netvsc_send_recv_completion(struct hv_device *device,
5355fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang					u64 transaction_id)
5365fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang{
5375fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	struct nvsp_message recvcompMessage;
5385fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	int retries = 0;
5395fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	int ret;
5402ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
5412ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct netvsc_device *net_device = hv_get_drvdata(device);
5422ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan
5432ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
5445fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang
5455fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	recvcompMessage.hdr.msg_type =
5465fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang				NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
5475fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang
5485fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	/* FIXME: Pass in the status */
5495fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status =
5505fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		NVSP_STAT_SUCCESS;
5515fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang
5525fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhangretry_send_cmplt:
5535fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	/* Send the completion */
5545fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	ret = vmbus_sendpacket(device->channel, &recvcompMessage,
5555fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang			       sizeof(struct nvsp_message), transaction_id,
5565fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang			       VM_PKT_COMP, 0);
5575fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	if (ret == 0) {
5585fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		/* success */
5595fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		/* no-op */
560d2598f017f02bbc3623503c6e08f22f7ea473cddK. Y. Srinivasan	} else if (ret == -EAGAIN) {
5615fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		/* no more room...wait a bit and attempt to retry 3 times */
5625fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		retries++;
563d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "unable to send receive completion pkt"
564c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			" (tid %llx)...retrying %d\n", transaction_id, retries);
5655fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang
5665fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		if (retries < 4) {
5675fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang			udelay(100);
5685fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang			goto retry_send_cmplt;
5695fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		} else {
570d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang			netdev_err(ndev, "unable to send receive "
571c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang				"completion pkt (tid %llx)...give up retrying\n",
5725fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang				transaction_id);
5735fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang		}
5745fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	} else {
575d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "unable to send receive "
576c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"completion pkt - %llx\n", transaction_id);
5775fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang	}
5785fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang}
5795fa9d3c51d15a3b573c76e385dd9149cc77e7598Haiyang Zhang
58057991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang/* Send a receive completion packet to RNDIS device (ie NetVsp) */
58157991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhangstatic void netvsc_receive_completion(void *context)
58257991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang{
58357991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	struct hv_netvsc_packet *packet = context;
58457991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	struct hv_device *device = (struct hv_device *)packet->device;
58557991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	struct netvsc_device *net_device;
58657991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	u64 transaction_id = 0;
58757991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	bool fsend_receive_comp = false;
58857991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	unsigned long flags;
5892ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
59057991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
59157991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	/*
59257991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 * Even though it seems logical to do a GetOutboundNetDevice() here to
59357991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 * send out receive completion, we are using GetInboundNetDevice()
59457991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 * since we may have disable outbound traffic already.
59557991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 */
59657991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	net_device = get_inbound_net_device(device);
5972ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	if (!net_device)
59857991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang		return;
5992ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
60057991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
60157991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	/* Overloading use of the lock. */
60257991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
60357991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
60457991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	packet->xfer_page_pkt->count--;
60557991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
60657991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	/*
60757991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 * Last one in the line that represent 1 xfer page packet.
60857991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 * Return the xfer page packet itself to the freelist
60957991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	 */
61057991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	if (packet->xfer_page_pkt->count == 0) {
61157991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang		fsend_receive_comp = true;
61257991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang		transaction_id = packet->completion.recv.recv_completion_tid;
61357991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang		list_add_tail(&packet->xfer_page_pkt->list_ent,
61457991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang			      &net_device->recv_pkt_list);
61557991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
61657991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	}
61757991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
61857991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	/* Put the packet back */
61957991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	list_add_tail(&packet->list_ent, &net_device->recv_pkt_list);
62057991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
62157991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
62257991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	/* Send a receive completion for the xfer page packet */
62357991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang	if (fsend_receive_comp)
62457991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang		netvsc_send_recv_completion(device, transaction_id);
62557991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
62657991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang}
62757991156b949cca02737e67d8fa3fa75f80720d9Haiyang Zhang
6285a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic void netvsc_receive(struct hv_device *device,
62985799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			    struct vmpacket_descriptor *packet)
630fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
63185799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
63285799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct vmtransfer_page_packet_header *vmxferpage_packet;
63385799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct nvsp_message *nvsp_packet;
63485799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct hv_netvsc_packet *netvsc_packet = NULL;
6357e23a6e9626bf93242712f146a9657d38dda497bGreg Kroah-Hartman	/* struct netvsc_driver *netvscDriver; */
63685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct xferpage_packet *xferpage_packet = NULL;
637453263421f88b4a7e508c2e7b639c97e99c5b118Haiyang Zhang	int i;
638453263421f88b4a7e508c2e7b639c97e99c5b118Haiyang Zhang	int count = 0;
6396436873afce6f20fecc0c5099db899b25e1e6c2bGreg Kroah-Hartman	unsigned long flags;
6402ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
641779b4d17c177de592141ab01d2a66d025ff4d238K. Y. Srinivasan
642d29274efb73735c6a94f20214b1e4ea994da8848Bill Pemberton	LIST_HEAD(listHead);
643fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
6445a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	net_device = get_inbound_net_device(device);
6452ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	if (!net_device)
646fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return;
6472ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
648fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
64921a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	/*
65021a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	 * All inbound packets other than send completion should be xfer page
65121a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	 * packet
65221a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	 */
653415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang	if (packet->type != VM_PKT_DATA_USING_XFER_PAGES) {
654d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Unknown packet type received - %d\n",
655415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			   packet->type);
656fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return;
657fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
658fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
65985799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
660415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			(packet->offset8 << 3));
661fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
662454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Make sure this is a valid nvsp packet */
66353d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	if (nvsp_packet->hdr.msg_type !=
66453d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	    NVSP_MSG1_TYPE_SEND_RNDIS_PKT) {
665d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Unknown nvsp packet type received-"
666c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			" %d\n", nvsp_packet->hdr.msg_type);
667fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return;
668fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
669fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
67085799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet;
671fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
672415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang	if (vmxferpage_packet->xfer_pageset_id != NETVSC_RECEIVE_BUFFER_ID) {
673d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Invalid xfer page set id - "
674c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			   "expecting %x got %x\n", NETVSC_RECEIVE_BUFFER_ID,
675415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang			   vmxferpage_packet->xfer_pageset_id);
676fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return;
677fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
678fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
679454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
680454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * Grab free packets (range count + 1) to represent this xfer
681454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * page packet. +1 to represent the xfer page packet itself.
682454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * We grab it here so that we know exactly how many we can
683454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * fulfil
684454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
68553d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
68653d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	while (!list_empty(&net_device->recv_pkt_list)) {
68753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		list_move_tail(net_device->recv_pkt_list.next, &listHead);
688415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang		if (++count == vmxferpage_packet->range_cnt + 1)
689fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen			break;
690fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
69153d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang	spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags);
692fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
693454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
694454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * We need at least 2 netvsc pkts (1 to represent the xfer
695454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * page and at least 1 for the range) i.e. we can handled
696454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * some of the xfer page packet ranges...
697454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
69821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	if (count < 2) {
699d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "Got only %d netvsc pkt...needed "
700c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"%d pkts. Dropping this xfer page packet completely!\n",
701eb335bc42781ddc19da98a3c74add1013ba08da2Hank Janssen			count, vmxferpage_packet->range_cnt + 1);
702fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
703454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Return it to the freelist */
70453d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags);
70521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman		for (i = count; i != 0; i--) {
70692ec0893ad0996a534a5b605659d3ca31cf5dfd9Milan Dadok			list_move_tail(listHead.next,
70753d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang				       &net_device->recv_pkt_list);
708fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		}
70953d21fdbf4d38dcfe27173d746acf74ea1a19958Haiyang Zhang		spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
71021a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman				       flags);
711fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
7125a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang		netvsc_send_recv_completion(device,
713415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang					    vmxferpage_packet->d.trans_id);
714fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
715fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		return;
716fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
717fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
718454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Remove the 1st packet to represent the xfer page packet itself */
71985799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	xferpage_packet = (struct xferpage_packet *)listHead.next;
72072a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang	list_del(&xferpage_packet->list_ent);
721d29274efb73735c6a94f20214b1e4ea994da8848Bill Pemberton
72221a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	/* This is how much we can satisfy */
72372a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang	xferpage_packet->count = count - 1;
72421a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman
725415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang	if (xferpage_packet->count != vmxferpage_packet->range_cnt) {
7268bff33ab417f246dac4ab9835be6894eaddfb546Haiyang Zhang		netdev_err(ndev, "Needed %d netvsc pkts to satisfy "
727c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"this xfer page...got %d\n",
728eb335bc42781ddc19da98a3c74add1013ba08da2Hank Janssen			vmxferpage_packet->range_cnt, xferpage_packet->count);
729fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
730fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
731454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
73221a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	for (i = 0; i < (count - 1); i++) {
73385799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang		netvsc_packet = (struct hv_netvsc_packet *)listHead.next;
73472a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		list_del(&netvsc_packet->list_ent);
735fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
736454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Initialize the netvsc packet */
73772a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		netvsc_packet->xfer_page_pkt = xferpage_packet;
73872a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		netvsc_packet->completion.recv.recv_completion =
7395a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang					netvsc_receive_completion;
74072a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		netvsc_packet->completion.recv.recv_completion_ctx =
74185799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang					netvsc_packet;
74272a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		netvsc_packet->device = device;
74321a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman		/* Save this so that we can send it back */
74472a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		netvsc_packet->completion.recv.recv_completion_tid =
745415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang					vmxferpage_packet->d.trans_id;
746fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
747453263421f88b4a7e508c2e7b639c97e99c5b118Haiyang Zhang		netvsc_packet->data = (void *)((unsigned long)net_device->
748453263421f88b4a7e508c2e7b639c97e99c5b118Haiyang Zhang			recv_buf + vmxferpage_packet->ranges[i].byte_offset);
74972a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang		netvsc_packet->total_data_buflen =
750415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang					vmxferpage_packet->ranges[i].byte_count;
751fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
752454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton		/* Pass it to the upper layer */
753ac6f78590104f01036ae7f1ecc062411a251f756K. Y. Srinivasan		rndis_filter_receive(device, netvsc_packet);
754fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
7555a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang		netvsc_receive_completion(netvsc_packet->
75672a2f5bd53bf83302f4dcfe8500d4ec440545d27Haiyang Zhang				completion.recv.recv_completion_ctx);
757fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	}
758fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
759fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
760fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
7615a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhangstatic void netvsc_channel_cb(void *context)
762fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen{
76321a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	int ret;
76485799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct hv_device *device = context;
76585799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	struct netvsc_device *net_device;
76685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	u32 bytes_recvd;
76785799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang	u64 request_id;
768c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	unsigned char *packet;
7698dc0a06ad1f192ea0c8dbe4d2090206c7d880281Greg Kroah-Hartman	struct vmpacket_descriptor *desc;
770c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	unsigned char *buffer;
771c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	int bufferlen = NETVSC_PACKET_SIZE;
7722ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
773fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
774c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
775d70c673153d42e8aefd5ac296c8159ef222d076bTimo Teräs			 GFP_ATOMIC);
776c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	if (!packet)
777c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton		return;
778c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	buffer = packet;
779c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton
7805a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang	net_device = get_inbound_net_device(device);
7812ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	if (!net_device)
782c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton		goto out;
7832ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
784fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
78521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman	do {
7869f630068e8ccba24d728f196cb3ddc120ebee38eGreg Kroah-Hartman		ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
78785799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang					   &bytes_recvd, &request_id);
78821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman		if (ret == 0) {
78985799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			if (bytes_recvd > 0) {
79021a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman				desc = (struct vmpacket_descriptor *)buffer;
791415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang				switch (desc->type) {
792415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang				case VM_PKT_COMP:
7935a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang					netvsc_send_completion(device, desc);
79421a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman					break;
79521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman
796415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang				case VM_PKT_DATA_USING_XFER_PAGES:
7975a71ae303c0f82968d93d86724c1d94d753b34d7Haiyang Zhang					netvsc_receive(device, desc);
79821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman					break;
79921a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman
80021a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman				default:
801d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang					netdev_err(ndev,
80221a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman						   "unhandled packet type %d, "
80321a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman						   "tid %llx len %d\n",
804415f228712d86dd5598f809e8e379ff5ad729652Haiyang Zhang						   desc->type, request_id,
80585799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang						   bytes_recvd);
80621a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman					break;
807fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen				}
808fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
809454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton				/* reset */
810c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton				if (bufferlen > NETVSC_PACKET_SIZE) {
8118c69f52ab3d918be9d91c8202e5321421876ea50Greg Kroah-Hartman					kfree(buffer);
812fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen					buffer = packet;
813c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton					bufferlen = NETVSC_PACKET_SIZE;
814fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen				}
81521a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman			} else {
816454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton				/* reset */
817c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton				if (bufferlen > NETVSC_PACKET_SIZE) {
8188c69f52ab3d918be9d91c8202e5321421876ea50Greg Kroah-Hartman					kfree(buffer);
819fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen					buffer = packet;
820c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton					bufferlen = NETVSC_PACKET_SIZE;
821fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen				}
822fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
823fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen				break;
824fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen			}
8253d5cad97c4be2bfc5cb4e52a0972c6e3bf8c278dK. Y. Srinivasan		} else if (ret == -ENOBUFS) {
82621a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman			/* Handle large packet */
82785799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
82821a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman			if (buffer == NULL) {
829454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton				/* Try again next time around */
830d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang				netdev_err(ndev,
83121a8082043aa474107f4ed62fb62651ffad8e2f6Greg Kroah-Hartman					   "unable to allocate buffer of size "
832c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang					   "(%d)!!\n", bytes_recvd);
833fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen				break;
834fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen			}
835fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
83685799a37553f89b23797ec4f69e45f6c5e9109dfHaiyang Zhang			bufferlen = bytes_recvd;
837fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen		}
838fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	} while (1);
839fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen
840c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pembertonout:
841c6fcf0baa6367fecd3e025253700b64ccff8c1ebBill Pemberton	kfree(buffer);
842fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen	return;
843fceaf24a943d8d50391f409ac7fb888cd1f36f32Hank Janssen}
844af24ce42c51fad4fdc2eb3576b8c0388fd19ed4aHaiyang Zhang
845af24ce42c51fad4fdc2eb3576b8c0388fd19ed4aHaiyang Zhang/*
846b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang * netvsc_device_add - Callback when the device belonging to this
847b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang * driver is added
848b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang */
8497bd23a4d8737777f41cbbe099a027b582b762581K. Y. Srinivasanint netvsc_device_add(struct hv_device *device, void *additional_info)
850b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang{
851b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	int ret = 0;
852b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	int i;
853aae23986fd5baaf48c7112612fbff7fb1094ad03K. Y. Srinivasan	int ring_size =
854aae23986fd5baaf48c7112612fbff7fb1094ad03K. Y. Srinivasan	((struct netvsc_device_info *)additional_info)->ring_size;
855b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	struct netvsc_device *net_device;
856b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	struct hv_netvsc_packet *packet, *pos;
8572ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	struct net_device *ndev;
858b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
859b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	net_device = alloc_net_device(device);
860b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	if (!net_device) {
861ace163a85a9a98e7f91db3a23db3f63689038f1eK. Y. Srinivasan		ret = -ENOMEM;
862b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		goto cleanup;
863b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	}
864b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
8652ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	/*
8662ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	 * Coming into this function, struct net_device * is
8672ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	 * registered as the driver private data.
8682ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	 * In alloc_net_device(), we register struct netvsc_device *
8692ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	 * as the driver private data and stash away struct net_device *
8702ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	 * in struct netvsc_device *.
8712ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	 */
8722ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan	ndev = net_device->ndev;
8732ddd5e5fb342b9f014d61941a4f73c0bd9b50a60K. Y. Srinivasan
874b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	/* Initialize the NetVSC channel extension */
875b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
876b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	spin_lock_init(&net_device->recv_pkt_list_lock);
877b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
878b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	INIT_LIST_HEAD(&net_device->recv_pkt_list);
879b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
880b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) {
881b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		packet = kzalloc(sizeof(struct hv_netvsc_packet) +
882b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang				 (NETVSC_RECEIVE_SG_COUNT *
883b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang				  sizeof(struct hv_page_buffer)), GFP_KERNEL);
884b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		if (!packet)
885b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang			break;
886b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
887b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		list_add_tail(&packet->list_ent,
888b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang			      &net_device->recv_pkt_list);
889b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	}
89035abb21ace3413de6ea8d5c7750cedfd46111f0cK. Y. Srinivasan	init_completion(&net_device->channel_init_wait);
891b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
892b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	/* Open the channel */
893aae23986fd5baaf48c7112612fbff7fb1094ad03K. Y. Srinivasan	ret = vmbus_open(device->channel, ring_size * PAGE_SIZE,
894aae23986fd5baaf48c7112612fbff7fb1094ad03K. Y. Srinivasan			 ring_size * PAGE_SIZE, NULL, 0,
895b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang			 netvsc_channel_cb, device);
896b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
897b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	if (ret != 0) {
898d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev, "unable to open channel: %d\n", ret);
899b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		goto cleanup;
900b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	}
901b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
902b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	/* Channel is opened */
903c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang	pr_info("hv_netvsc channel opened successfully\n");
904b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
905b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	/* Connect with the NetVsp */
906b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	ret = netvsc_connect_vsp(device);
907b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	if (ret != 0) {
908d9871158718778ff060f08cbee0c61eb23041671Haiyang Zhang		netdev_err(ndev,
909c909ebbd0dcf19c617408c2cfde56c4bbd4f6cb4Haiyang Zhang			"unable to connect to NetVSP - %d\n", ret);
910b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		goto close;
911b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	}
912b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
913b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	return ret;
914b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
915b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhangclose:
916b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	/* Now, we can close the channel safely */
917b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	vmbus_close(device->channel);
918b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
919b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhangcleanup:
920b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
921b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	if (net_device) {
922b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		list_for_each_entry_safe(packet, pos,
923b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang					 &net_device->recv_pkt_list,
924b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang					 list_ent) {
925b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang			list_del(&packet->list_ent);
926b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang			kfree(packet);
927b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang		}
928b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
929356c4657193c8a5b3aff84fe8cdf5ddc64742801K. Y. Srinivasan		kfree(net_device);
930b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	}
931b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang
932b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang	return ret;
933b637e023484d420e8df326b561195f8ba74c1a73Haiyang Zhang}
934