Commit | Line | Data |
---|---|---|
fceaf24a | 1 | /* |
fceaf24a HJ |
2 | * Copyright (c) 2009, Microsoft Corporation. |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | |
16 | * | |
17 | * Authors: | |
d0e94d17 | 18 | * Haiyang Zhang <haiyangz@microsoft.com> |
fceaf24a | 19 | * Hank Janssen <hjanssen@microsoft.com> |
fceaf24a | 20 | */ |
5654e932 | 21 | #include <linux/kernel.h> |
0ffa63b0 | 22 | #include <linux/mm.h> |
b4362c9c | 23 | #include <linux/delay.h> |
21a80820 | 24 | #include <linux/io.h> |
5a0e3ad6 | 25 | #include <linux/slab.h> |
4983b39a | 26 | #include "osd.h" |
645954c5 | 27 | #include "logging.h" |
af167ae9 | 28 | #include "netvsc.h" |
043efcc3 | 29 | #include "rndis_filter.h" |
314bf1d1 | 30 | #include "channel.h" |
fceaf24a HJ |
31 | |
32 | ||
454f18a9 | 33 | /* Globals */ |
85799a37 | 34 | static const char *driver_name = "netvsc"; |
fceaf24a | 35 | |
454f18a9 | 36 | /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ |
85799a37 | 37 | static const struct hv_guid netvsc_device_type = { |
caf26a31 GKH |
38 | .data = { |
39 | 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, | |
40 | 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E | |
41 | } | |
fceaf24a HJ |
42 | }; |
43 | ||
5a71ae30 | 44 | static int netvsc_device_add(struct hv_device *device, void *additional_info); |
21a80820 | 45 | |
5a71ae30 | 46 | static int netvsc_device_remove(struct hv_device *device); |
21a80820 | 47 | |
5a71ae30 | 48 | static void netvsc_cleanup(struct hv_driver *driver); |
21a80820 | 49 | |
5a71ae30 | 50 | static void netvsc_channel_cb(void *context); |
21a80820 | 51 | |
5a71ae30 | 52 | static int netvsc_init_send_buf(struct hv_device *device); |
21a80820 | 53 | |
5a71ae30 | 54 | static int netvsc_init_recv_buf(struct hv_device *device); |
21a80820 | 55 | |
5a71ae30 | 56 | static int netvsc_destroy_send_buf(struct netvsc_device *net_device); |
21a80820 | 57 | |
5a71ae30 | 58 | static int netvsc_destroy_recv_buf(struct netvsc_device *net_device); |
21a80820 | 59 | |
5a71ae30 | 60 | static int netvsc_connect_vsp(struct hv_device *device); |
21a80820 | 61 | |
5a71ae30 | 62 | static void netvsc_send_completion(struct hv_device *device, |
85799a37 | 63 | struct vmpacket_descriptor *packet); |
21a80820 | 64 | |
5a71ae30 | 65 | static int netvsc_send(struct hv_device *device, |
85799a37 | 66 | struct hv_netvsc_packet *packet); |
21a80820 | 67 | |
5a71ae30 | 68 | static void netvsc_receive(struct hv_device *device, |
85799a37 | 69 | struct vmpacket_descriptor *packet); |
21a80820 | 70 | |
5a71ae30 | 71 | static void netvsc_receive_completion(void *context); |
21a80820 | 72 | |
5a71ae30 | 73 | static void netvsc_send_recv_completion(struct hv_device *device, |
85799a37 | 74 | u64 transaction_id); |
21a80820 | 75 | |
fceaf24a | 76 | |
5a71ae30 | 77 | static struct netvsc_device *alloc_net_device(struct hv_device *device) |
fceaf24a | 78 | { |
85799a37 | 79 | struct netvsc_device *net_device; |
fceaf24a | 80 | |
85799a37 HZ |
81 | net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL); |
82 | if (!net_device) | |
fceaf24a HJ |
83 | return NULL; |
84 | ||
454f18a9 | 85 | /* Set to 2 to allow both inbound and outbound traffic */ |
85799a37 | 86 | atomic_cmpxchg(&net_device->RefCount, 0, 2); |
fceaf24a | 87 | |
85799a37 HZ |
88 | net_device->Device = device; |
89 | device->Extension = net_device; | |
fceaf24a | 90 | |
85799a37 | 91 | return net_device; |
fceaf24a HJ |
92 | } |
93 | ||
5a71ae30 | 94 | static void free_net_device(struct netvsc_device *device) |
fceaf24a | 95 | { |
85799a37 HZ |
96 | WARN_ON(atomic_read(&device->RefCount) == 0); |
97 | device->Device->Extension = NULL; | |
98 | kfree(device); | |
fceaf24a HJ |
99 | } |
100 | ||
101 | ||
454f18a9 | 102 | /* Get the net device object iff exists and its refcount > 1 */ |
5a71ae30 | 103 | static struct netvsc_device *get_outbound_net_device(struct hv_device *device) |
fceaf24a | 104 | { |
85799a37 | 105 | struct netvsc_device *net_device; |
fceaf24a | 106 | |
85799a37 HZ |
107 | net_device = device->Extension; |
108 | if (net_device && atomic_read(&net_device->RefCount) > 1) | |
109 | atomic_inc(&net_device->RefCount); | |
fceaf24a | 110 | else |
85799a37 | 111 | net_device = NULL; |
fceaf24a | 112 | |
85799a37 | 113 | return net_device; |
fceaf24a HJ |
114 | } |
115 | ||
454f18a9 | 116 | /* Get the net device object iff exists and its refcount > 0 */ |
5a71ae30 | 117 | static struct netvsc_device *get_inbound_net_device(struct hv_device *device) |
fceaf24a | 118 | { |
85799a37 | 119 | struct netvsc_device *net_device; |
fceaf24a | 120 | |
85799a37 HZ |
121 | net_device = device->Extension; |
122 | if (net_device && atomic_read(&net_device->RefCount)) | |
123 | atomic_inc(&net_device->RefCount); | |
fceaf24a | 124 | else |
85799a37 | 125 | net_device = NULL; |
fceaf24a | 126 | |
85799a37 | 127 | return net_device; |
fceaf24a HJ |
128 | } |
129 | ||
5a71ae30 | 130 | static void put_net_device(struct hv_device *device) |
fceaf24a | 131 | { |
85799a37 | 132 | struct netvsc_device *net_device; |
fceaf24a | 133 | |
85799a37 | 134 | net_device = device->Extension; |
972b9529 | 135 | /* ASSERT(netDevice); */ |
fceaf24a | 136 | |
85799a37 | 137 | atomic_dec(&net_device->RefCount); |
fceaf24a HJ |
138 | } |
139 | ||
5a71ae30 HZ |
140 | static struct netvsc_device *release_outbound_net_device( |
141 | struct hv_device *device) | |
fceaf24a | 142 | { |
85799a37 | 143 | struct netvsc_device *net_device; |
fceaf24a | 144 | |
85799a37 HZ |
145 | net_device = device->Extension; |
146 | if (net_device == NULL) | |
fceaf24a HJ |
147 | return NULL; |
148 | ||
454f18a9 | 149 | /* Busy wait until the ref drop to 2, then set it to 1 */ |
85799a37 | 150 | while (atomic_cmpxchg(&net_device->RefCount, 2, 1) != 2) |
b4362c9c | 151 | udelay(100); |
fceaf24a | 152 | |
85799a37 | 153 | return net_device; |
fceaf24a HJ |
154 | } |
155 | ||
5a71ae30 HZ |
156 | static struct netvsc_device *release_inbound_net_device( |
157 | struct hv_device *device) | |
fceaf24a | 158 | { |
85799a37 | 159 | struct netvsc_device *net_device; |
fceaf24a | 160 | |
85799a37 HZ |
161 | net_device = device->Extension; |
162 | if (net_device == NULL) | |
fceaf24a HJ |
163 | return NULL; |
164 | ||
454f18a9 | 165 | /* Busy wait until the ref drop to 1, then set it to 0 */ |
85799a37 | 166 | while (atomic_cmpxchg(&net_device->RefCount, 1, 0) != 1) |
b4362c9c | 167 | udelay(100); |
fceaf24a | 168 | |
85799a37 HZ |
169 | device->Extension = NULL; |
170 | return net_device; | |
fceaf24a HJ |
171 | } |
172 | ||
3e189519 | 173 | /* |
5a71ae30 | 174 | * netvsc_initialize - Main entry point |
21a80820 | 175 | */ |
5a71ae30 | 176 | int netvsc_initialize(struct hv_driver *drv) |
fceaf24a | 177 | { |
7e23a6e9 | 178 | struct netvsc_driver *driver = (struct netvsc_driver *)drv; |
fceaf24a | 179 | |
21a80820 GKH |
180 | DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, " |
181 | "sizeof(struct nvsp_message)=%zd, " | |
182 | "sizeof(struct vmtransfer_page_packet_header)=%zd", | |
183 | sizeof(struct hv_netvsc_packet), | |
184 | sizeof(struct nvsp_message), | |
185 | sizeof(struct vmtransfer_page_packet_header)); | |
fceaf24a | 186 | |
454f18a9 | 187 | /* Make sure we are at least 2 pages since 1 page is used for control */ |
972b9529 | 188 | /* ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); */ |
fceaf24a | 189 | |
85799a37 HZ |
190 | drv->name = driver_name; |
191 | memcpy(&drv->deviceType, &netvsc_device_type, sizeof(struct hv_guid)); | |
fceaf24a | 192 | |
454f18a9 | 193 | /* Make sure it is set by the caller */ |
972b9529 BP |
194 | /* FIXME: These probably should still be tested in some way */ |
195 | /* ASSERT(driver->OnReceiveCallback); */ | |
196 | /* ASSERT(driver->OnLinkStatusChanged); */ | |
fceaf24a | 197 | |
454f18a9 | 198 | /* Setup the dispatch table */ |
5a71ae30 HZ |
199 | driver->Base.OnDeviceAdd = netvsc_device_add; |
200 | driver->Base.OnDeviceRemove = netvsc_device_remove; | |
201 | driver->Base.OnCleanup = netvsc_cleanup; | |
fceaf24a | 202 | |
5a71ae30 | 203 | driver->OnSend = netvsc_send; |
fceaf24a | 204 | |
9c26aa0d | 205 | rndis_filter_init(driver); |
21a80820 | 206 | return 0; |
fceaf24a HJ |
207 | } |
208 | ||
5a71ae30 | 209 | static int netvsc_init_recv_buf(struct hv_device *device) |
fceaf24a | 210 | { |
21a80820 | 211 | int ret = 0; |
85799a37 HZ |
212 | struct netvsc_device *net_device; |
213 | struct nvsp_message *init_packet; | |
fceaf24a | 214 | |
5a71ae30 | 215 | net_device = get_outbound_net_device(device); |
85799a37 | 216 | if (!net_device) { |
21a80820 GKH |
217 | DPRINT_ERR(NETVSC, "unable to get net device..." |
218 | "device being destroyed?"); | |
fceaf24a HJ |
219 | return -1; |
220 | } | |
972b9529 | 221 | /* ASSERT(netDevice->ReceiveBufferSize > 0); */ |
21a80820 | 222 | /* page-size grandularity */ |
972b9529 | 223 | /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */ |
fceaf24a | 224 | |
85799a37 HZ |
225 | net_device->ReceiveBuffer = |
226 | osd_page_alloc(net_device->ReceiveBufferSize >> PAGE_SHIFT); | |
227 | if (!net_device->ReceiveBuffer) { | |
21a80820 GKH |
228 | DPRINT_ERR(NETVSC, |
229 | "unable to allocate receive buffer of size %d", | |
85799a37 | 230 | net_device->ReceiveBufferSize); |
fceaf24a HJ |
231 | ret = -1; |
232 | goto Cleanup; | |
233 | } | |
21a80820 | 234 | /* page-aligned buffer */ |
972b9529 BP |
235 | /* ASSERT(((unsigned long)netDevice->ReceiveBuffer & (PAGE_SIZE - 1)) == */ |
236 | /* 0); */ | |
fceaf24a HJ |
237 | |
238 | DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL..."); | |
239 | ||
454f18a9 BP |
240 | /* |
241 | * Establish the gpadl handle for this buffer on this | |
242 | * channel. Note: This call uses the vmbus connection rather | |
243 | * than the channel to establish the gpadl handle. | |
244 | */ | |
85799a37 HZ |
245 | ret = vmbus_establish_gpadl(device->channel, net_device->ReceiveBuffer, |
246 | net_device->ReceiveBufferSize, | |
247 | &net_device->ReceiveBufferGpadlHandle); | |
21a80820 GKH |
248 | if (ret != 0) { |
249 | DPRINT_ERR(NETVSC, | |
250 | "unable to establish receive buffer's gpadl"); | |
fceaf24a HJ |
251 | goto Cleanup; |
252 | } | |
253 | ||
203df82d | 254 | /* osd_waitevent_wait(ext->ChannelInitEvent); */ |
fceaf24a | 255 | |
454f18a9 | 256 | /* Notify the NetVsp of the gpadl handle */ |
fceaf24a HJ |
257 | DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer..."); |
258 | ||
85799a37 | 259 | init_packet = &net_device->ChannelInitPacket; |
fceaf24a | 260 | |
85799a37 | 261 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
fceaf24a | 262 | |
85799a37 HZ |
263 | init_packet->Header.MessageType = NvspMessage1TypeSendReceiveBuffer; |
264 | init_packet->Messages.Version1Messages.SendReceiveBuffer. | |
265 | GpadlHandle = net_device->ReceiveBufferGpadlHandle; | |
266 | init_packet->Messages.Version1Messages. | |
267 | SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; | |
fceaf24a | 268 | |
454f18a9 | 269 | /* Send the gpadl notification request */ |
85799a37 | 270 | ret = vmbus_sendpacket(device->channel, init_packet, |
5a4df290 | 271 | sizeof(struct nvsp_message), |
85799a37 | 272 | (unsigned long)init_packet, |
5a4df290 GKH |
273 | VmbusPacketTypeDataInBand, |
274 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
21a80820 GKH |
275 | if (ret != 0) { |
276 | DPRINT_ERR(NETVSC, | |
277 | "unable to send receive buffer's gpadl to netvsp"); | |
fceaf24a HJ |
278 | goto Cleanup; |
279 | } | |
280 | ||
85799a37 | 281 | osd_waitevent_wait(net_device->ChannelInitEvent); |
fceaf24a | 282 | |
454f18a9 | 283 | /* Check the response */ |
85799a37 HZ |
284 | if (init_packet->Messages.Version1Messages. |
285 | SendReceiveBufferComplete.Status != NvspStatusSuccess) { | |
21a80820 GKH |
286 | DPRINT_ERR(NETVSC, "Unable to complete receive buffer " |
287 | "initialzation with NetVsp - status %d", | |
85799a37 HZ |
288 | init_packet->Messages.Version1Messages. |
289 | SendReceiveBufferComplete.Status); | |
fceaf24a HJ |
290 | ret = -1; |
291 | goto Cleanup; | |
292 | } | |
293 | ||
454f18a9 | 294 | /* Parse the response */ |
972b9529 BP |
295 | /* ASSERT(netDevice->ReceiveSectionCount == 0); */ |
296 | /* ASSERT(netDevice->ReceiveSections == NULL); */ | |
fceaf24a | 297 | |
85799a37 HZ |
298 | net_device->ReceiveSectionCount = init_packet->Messages. |
299 | Version1Messages.SendReceiveBufferComplete.NumSections; | |
fceaf24a | 300 | |
85799a37 HZ |
301 | net_device->ReceiveSections = kmalloc(net_device->ReceiveSectionCount |
302 | * sizeof(struct nvsp_1_receive_buffer_section), GFP_KERNEL); | |
303 | if (net_device->ReceiveSections == NULL) { | |
fceaf24a HJ |
304 | ret = -1; |
305 | goto Cleanup; | |
306 | } | |
307 | ||
85799a37 HZ |
308 | memcpy(net_device->ReceiveSections, |
309 | init_packet->Messages.Version1Messages. | |
310 | SendReceiveBufferComplete.Sections, | |
311 | net_device->ReceiveSectionCount * | |
312 | sizeof(struct nvsp_1_receive_buffer_section)); | |
fceaf24a | 313 | |
21a80820 GKH |
314 | DPRINT_INFO(NETVSC, "Receive sections info (count %d, offset %d, " |
315 | "endoffset %d, suballoc size %d, num suballocs %d)", | |
85799a37 HZ |
316 | net_device->ReceiveSectionCount, |
317 | net_device->ReceiveSections[0].Offset, | |
318 | net_device->ReceiveSections[0].EndOffset, | |
319 | net_device->ReceiveSections[0].SubAllocationSize, | |
320 | net_device->ReceiveSections[0].NumSubAllocations); | |
fceaf24a | 321 | |
21a80820 GKH |
322 | /* |
323 | * For 1st release, there should only be 1 section that represents the | |
324 | * entire receive buffer | |
325 | */ | |
85799a37 HZ |
326 | if (net_device->ReceiveSectionCount != 1 || |
327 | net_device->ReceiveSections->Offset != 0) { | |
fceaf24a HJ |
328 | ret = -1; |
329 | goto Cleanup; | |
330 | } | |
331 | ||
332 | goto Exit; | |
333 | ||
334 | Cleanup: | |
5a71ae30 | 335 | netvsc_destroy_recv_buf(net_device); |
fceaf24a HJ |
336 | |
337 | Exit: | |
5a71ae30 | 338 | put_net_device(device); |
fceaf24a HJ |
339 | return ret; |
340 | } | |
341 | ||
5a71ae30 | 342 | static int netvsc_init_send_buf(struct hv_device *device) |
fceaf24a | 343 | { |
21a80820 | 344 | int ret = 0; |
85799a37 HZ |
345 | struct netvsc_device *net_device; |
346 | struct nvsp_message *init_packet; | |
fceaf24a | 347 | |
5a71ae30 | 348 | net_device = get_outbound_net_device(device); |
85799a37 | 349 | if (!net_device) { |
21a80820 GKH |
350 | DPRINT_ERR(NETVSC, "unable to get net device..." |
351 | "device being destroyed?"); | |
fceaf24a HJ |
352 | return -1; |
353 | } | |
85799a37 | 354 | if (net_device->SendBufferSize <= 0) { |
79069684 BP |
355 | ret = -EINVAL; |
356 | goto Cleanup; | |
357 | } | |
358 | ||
21a80820 | 359 | /* page-size grandularity */ |
972b9529 | 360 | /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */ |
21a80820 | 361 | |
85799a37 HZ |
362 | net_device->SendBuffer = |
363 | osd_page_alloc(net_device->SendBufferSize >> PAGE_SHIFT); | |
364 | if (!net_device->SendBuffer) { | |
21a80820 | 365 | DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", |
85799a37 | 366 | net_device->SendBufferSize); |
fceaf24a HJ |
367 | ret = -1; |
368 | goto Cleanup; | |
369 | } | |
21a80820 | 370 | /* page-aligned buffer */ |
972b9529 | 371 | /* ASSERT(((unsigned long)netDevice->SendBuffer & (PAGE_SIZE - 1)) == 0); */ |
fceaf24a HJ |
372 | |
373 | DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL..."); | |
374 | ||
454f18a9 BP |
375 | /* |
376 | * Establish the gpadl handle for this buffer on this | |
377 | * channel. Note: This call uses the vmbus connection rather | |
378 | * than the channel to establish the gpadl handle. | |
379 | */ | |
85799a37 HZ |
380 | ret = vmbus_establish_gpadl(device->channel, net_device->SendBuffer, |
381 | net_device->SendBufferSize, | |
382 | &net_device->SendBufferGpadlHandle); | |
21a80820 | 383 | if (ret != 0) { |
fceaf24a HJ |
384 | DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl"); |
385 | goto Cleanup; | |
386 | } | |
387 | ||
203df82d | 388 | /* osd_waitevent_wait(ext->ChannelInitEvent); */ |
fceaf24a | 389 | |
454f18a9 | 390 | /* Notify the NetVsp of the gpadl handle */ |
fceaf24a HJ |
391 | DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer..."); |
392 | ||
85799a37 | 393 | init_packet = &net_device->ChannelInitPacket; |
fceaf24a | 394 | |
85799a37 | 395 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
fceaf24a | 396 | |
85799a37 HZ |
397 | init_packet->Header.MessageType = NvspMessage1TypeSendSendBuffer; |
398 | init_packet->Messages.Version1Messages.SendReceiveBuffer. | |
399 | GpadlHandle = net_device->SendBufferGpadlHandle; | |
400 | init_packet->Messages.Version1Messages.SendReceiveBuffer.Id = | |
401 | NETVSC_SEND_BUFFER_ID; | |
fceaf24a | 402 | |
454f18a9 | 403 | /* Send the gpadl notification request */ |
85799a37 | 404 | ret = vmbus_sendpacket(device->channel, init_packet, |
5a4df290 | 405 | sizeof(struct nvsp_message), |
85799a37 | 406 | (unsigned long)init_packet, |
5a4df290 GKH |
407 | VmbusPacketTypeDataInBand, |
408 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
21a80820 GKH |
409 | if (ret != 0) { |
410 | DPRINT_ERR(NETVSC, | |
411 | "unable to send receive buffer's gpadl to netvsp"); | |
fceaf24a HJ |
412 | goto Cleanup; |
413 | } | |
414 | ||
85799a37 | 415 | osd_waitevent_wait(net_device->ChannelInitEvent); |
fceaf24a | 416 | |
454f18a9 | 417 | /* Check the response */ |
85799a37 HZ |
418 | if (init_packet->Messages.Version1Messages. |
419 | SendSendBufferComplete.Status != NvspStatusSuccess) { | |
21a80820 GKH |
420 | DPRINT_ERR(NETVSC, "Unable to complete send buffer " |
421 | "initialzation with NetVsp - status %d", | |
85799a37 HZ |
422 | init_packet->Messages.Version1Messages. |
423 | SendSendBufferComplete.Status); | |
fceaf24a HJ |
424 | ret = -1; |
425 | goto Cleanup; | |
426 | } | |
427 | ||
85799a37 HZ |
428 | net_device->SendSectionSize = init_packet-> |
429 | Messages.Version1Messages.SendSendBufferComplete.SectionSize; | |
fceaf24a HJ |
430 | |
431 | goto Exit; | |
432 | ||
433 | Cleanup: | |
5a71ae30 | 434 | netvsc_destroy_send_buf(net_device); |
fceaf24a HJ |
435 | |
436 | Exit: | |
5a71ae30 | 437 | put_net_device(device); |
fceaf24a HJ |
438 | return ret; |
439 | } | |
440 | ||
5a71ae30 | 441 | static int netvsc_destroy_recv_buf(struct netvsc_device *net_device) |
fceaf24a | 442 | { |
85799a37 | 443 | struct nvsp_message *revoke_packet; |
21a80820 | 444 | int ret = 0; |
fceaf24a | 445 | |
454f18a9 BP |
446 | /* |
447 | * If we got a section count, it means we received a | |
448 | * SendReceiveBufferComplete msg (ie sent | |
449 | * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need | |
450 | * to send a revoke msg here | |
451 | */ | |
85799a37 | 452 | if (net_device->ReceiveSectionCount) { |
21a80820 GKH |
453 | DPRINT_INFO(NETVSC, |
454 | "Sending NvspMessage1TypeRevokeReceiveBuffer..."); | |
fceaf24a | 455 | |
454f18a9 | 456 | /* Send the revoke receive buffer */ |
85799a37 HZ |
457 | revoke_packet = &net_device->RevokePacket; |
458 | memset(revoke_packet, 0, sizeof(struct nvsp_message)); | |
fceaf24a | 459 | |
85799a37 HZ |
460 | revoke_packet->Header.MessageType = |
461 | NvspMessage1TypeRevokeReceiveBuffer; | |
462 | revoke_packet->Messages.Version1Messages. | |
463 | RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; | |
fceaf24a | 464 | |
85799a37 HZ |
465 | ret = vmbus_sendpacket(net_device->Device->channel, |
466 | revoke_packet, | |
5a4df290 | 467 | sizeof(struct nvsp_message), |
85799a37 | 468 | (unsigned long)revoke_packet, |
5a4df290 | 469 | VmbusPacketTypeDataInBand, 0); |
454f18a9 BP |
470 | /* |
471 | * If we failed here, we might as well return and | |
472 | * have a leak rather than continue and a bugchk | |
473 | */ | |
21a80820 GKH |
474 | if (ret != 0) { |
475 | DPRINT_ERR(NETVSC, "unable to send revoke receive " | |
476 | "buffer to netvsp"); | |
fceaf24a HJ |
477 | return -1; |
478 | } | |
479 | } | |
480 | ||
454f18a9 | 481 | /* Teardown the gpadl on the vsp end */ |
85799a37 | 482 | if (net_device->ReceiveBufferGpadlHandle) { |
fceaf24a HJ |
483 | DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL..."); |
484 | ||
85799a37 HZ |
485 | ret = vmbus_teardown_gpadl(net_device->Device->channel, |
486 | net_device->ReceiveBufferGpadlHandle); | |
fceaf24a | 487 | |
454f18a9 | 488 | /* If we failed here, we might as well return and have a leak rather than continue and a bugchk */ |
21a80820 GKH |
489 | if (ret != 0) { |
490 | DPRINT_ERR(NETVSC, | |
491 | "unable to teardown receive buffer's gpadl"); | |
fceaf24a HJ |
492 | return -1; |
493 | } | |
85799a37 | 494 | net_device->ReceiveBufferGpadlHandle = 0; |
fceaf24a HJ |
495 | } |
496 | ||
85799a37 | 497 | if (net_device->ReceiveBuffer) { |
fceaf24a HJ |
498 | DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); |
499 | ||
454f18a9 | 500 | /* Free up the receive buffer */ |
85799a37 HZ |
501 | osd_page_free(net_device->ReceiveBuffer, |
502 | net_device->ReceiveBufferSize >> PAGE_SHIFT); | |
503 | net_device->ReceiveBuffer = NULL; | |
fceaf24a HJ |
504 | } |
505 | ||
85799a37 HZ |
506 | if (net_device->ReceiveSections) { |
507 | net_device->ReceiveSectionCount = 0; | |
508 | kfree(net_device->ReceiveSections); | |
509 | net_device->ReceiveSections = NULL; | |
fceaf24a HJ |
510 | } |
511 | ||
fceaf24a HJ |
512 | return ret; |
513 | } | |
514 | ||
5a71ae30 | 515 | static int netvsc_destroy_send_buf(struct netvsc_device *net_device) |
fceaf24a | 516 | { |
85799a37 | 517 | struct nvsp_message *revoke_packet; |
21a80820 | 518 | int ret = 0; |
fceaf24a | 519 | |
454f18a9 BP |
520 | /* |
521 | * If we got a section count, it means we received a | |
522 | * SendReceiveBufferComplete msg (ie sent | |
523 | * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need | |
524 | * to send a revoke msg here | |
525 | */ | |
85799a37 | 526 | if (net_device->SendSectionSize) { |
21a80820 GKH |
527 | DPRINT_INFO(NETVSC, |
528 | "Sending NvspMessage1TypeRevokeSendBuffer..."); | |
fceaf24a | 529 | |
454f18a9 | 530 | /* Send the revoke send buffer */ |
85799a37 HZ |
531 | revoke_packet = &net_device->RevokePacket; |
532 | memset(revoke_packet, 0, sizeof(struct nvsp_message)); | |
fceaf24a | 533 | |
85799a37 HZ |
534 | revoke_packet->Header.MessageType = |
535 | NvspMessage1TypeRevokeSendBuffer; | |
536 | revoke_packet->Messages.Version1Messages. | |
537 | RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID; | |
fceaf24a | 538 | |
85799a37 HZ |
539 | ret = vmbus_sendpacket(net_device->Device->channel, |
540 | revoke_packet, | |
5a4df290 | 541 | sizeof(struct nvsp_message), |
85799a37 | 542 | (unsigned long)revoke_packet, |
5a4df290 | 543 | VmbusPacketTypeDataInBand, 0); |
21a80820 GKH |
544 | /* |
545 | * If we failed here, we might as well return and have a leak | |
546 | * rather than continue and a bugchk | |
547 | */ | |
548 | if (ret != 0) { | |
549 | DPRINT_ERR(NETVSC, "unable to send revoke send buffer " | |
550 | "to netvsp"); | |
fceaf24a HJ |
551 | return -1; |
552 | } | |
553 | } | |
554 | ||
454f18a9 | 555 | /* Teardown the gpadl on the vsp end */ |
85799a37 | 556 | if (net_device->SendBufferGpadlHandle) { |
fceaf24a | 557 | DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL..."); |
85799a37 HZ |
558 | ret = vmbus_teardown_gpadl(net_device->Device->channel, |
559 | net_device->SendBufferGpadlHandle); | |
fceaf24a | 560 | |
21a80820 GKH |
561 | /* |
562 | * If we failed here, we might as well return and have a leak | |
563 | * rather than continue and a bugchk | |
564 | */ | |
565 | if (ret != 0) { | |
566 | DPRINT_ERR(NETVSC, "unable to teardown send buffer's " | |
567 | "gpadl"); | |
fceaf24a HJ |
568 | return -1; |
569 | } | |
85799a37 | 570 | net_device->SendBufferGpadlHandle = 0; |
fceaf24a HJ |
571 | } |
572 | ||
85799a37 | 573 | if (net_device->SendBuffer) { |
fceaf24a HJ |
574 | DPRINT_INFO(NETVSC, "Freeing up send buffer..."); |
575 | ||
454f18a9 | 576 | /* Free up the receive buffer */ |
85799a37 HZ |
577 | osd_page_free(net_device->SendBuffer, |
578 | net_device->SendBufferSize >> PAGE_SHIFT); | |
579 | net_device->SendBuffer = NULL; | |
fceaf24a HJ |
580 | } |
581 | ||
fceaf24a HJ |
582 | return ret; |
583 | } | |
584 | ||
585 | ||
5a71ae30 | 586 | static int netvsc_connect_vsp(struct hv_device *device) |
fceaf24a | 587 | { |
21a80820 | 588 | int ret; |
85799a37 HZ |
589 | struct netvsc_device *net_device; |
590 | struct nvsp_message *init_packet; | |
591 | int ndis_version; | |
fceaf24a | 592 | |
5a71ae30 | 593 | net_device = get_outbound_net_device(device); |
85799a37 | 594 | if (!net_device) { |
21a80820 GKH |
595 | DPRINT_ERR(NETVSC, "unable to get net device..." |
596 | "device being destroyed?"); | |
fceaf24a HJ |
597 | return -1; |
598 | } | |
599 | ||
85799a37 | 600 | init_packet = &net_device->ChannelInitPacket; |
fceaf24a | 601 | |
85799a37 HZ |
602 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
603 | init_packet->Header.MessageType = NvspMessageTypeInit; | |
604 | init_packet->Messages.InitMessages.Init.MinProtocolVersion = | |
605 | NVSP_MIN_PROTOCOL_VERSION; | |
606 | init_packet->Messages.InitMessages.Init.MaxProtocolVersion = | |
607 | NVSP_MAX_PROTOCOL_VERSION; | |
fceaf24a HJ |
608 | |
609 | DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit..."); | |
610 | ||
454f18a9 | 611 | /* Send the init request */ |
85799a37 | 612 | ret = vmbus_sendpacket(device->channel, init_packet, |
5a4df290 | 613 | sizeof(struct nvsp_message), |
85799a37 | 614 | (unsigned long)init_packet, |
5a4df290 GKH |
615 | VmbusPacketTypeDataInBand, |
616 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
21a80820 GKH |
617 | |
618 | if (ret != 0) { | |
fceaf24a HJ |
619 | DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit"); |
620 | goto Cleanup; | |
621 | } | |
622 | ||
85799a37 | 623 | osd_waitevent_wait(net_device->ChannelInitEvent); |
fceaf24a | 624 | |
454f18a9 BP |
625 | /* Now, check the response */ |
626 | /* ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); */ | |
fceaf24a | 627 | DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)", |
85799a37 HZ |
628 | init_packet->Messages.InitMessages.InitComplete.Status, |
629 | init_packet->Messages.InitMessages. | |
630 | InitComplete.MaximumMdlChainLength); | |
fceaf24a | 631 | |
85799a37 | 632 | if (init_packet->Messages.InitMessages.InitComplete.Status != |
21a80820 GKH |
633 | NvspStatusSuccess) { |
634 | DPRINT_ERR(NETVSC, | |
635 | "unable to initialize with netvsp (status 0x%x)", | |
85799a37 | 636 | init_packet->Messages.InitMessages.InitComplete.Status); |
fceaf24a HJ |
637 | ret = -1; |
638 | goto Cleanup; | |
639 | } | |
640 | ||
85799a37 HZ |
641 | if (init_packet->Messages.InitMessages.InitComplete. |
642 | NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) { | |
21a80820 GKH |
643 | DPRINT_ERR(NETVSC, "unable to initialize with netvsp " |
644 | "(version expected 1 got %d)", | |
85799a37 HZ |
645 | init_packet->Messages.InitMessages. |
646 | InitComplete.NegotiatedProtocolVersion); | |
fceaf24a HJ |
647 | ret = -1; |
648 | goto Cleanup; | |
649 | } | |
650 | DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion..."); | |
651 | ||
454f18a9 | 652 | /* Send the ndis version */ |
85799a37 | 653 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
fceaf24a | 654 | |
85799a37 | 655 | ndis_version = 0x00050000; |
fceaf24a | 656 | |
85799a37 HZ |
657 | init_packet->Header.MessageType = NvspMessage1TypeSendNdisVersion; |
658 | init_packet->Messages.Version1Messages. | |
659 | SendNdisVersion.NdisMajorVersion = | |
660 | (ndis_version & 0xFFFF0000) >> 16; | |
661 | init_packet->Messages.Version1Messages. | |
662 | SendNdisVersion.NdisMinorVersion = | |
663 | ndis_version & 0xFFFF; | |
fceaf24a | 664 | |
454f18a9 | 665 | /* Send the init request */ |
85799a37 | 666 | ret = vmbus_sendpacket(device->channel, init_packet, |
5a4df290 | 667 | sizeof(struct nvsp_message), |
85799a37 | 668 | (unsigned long)init_packet, |
5a4df290 | 669 | VmbusPacketTypeDataInBand, 0); |
21a80820 GKH |
670 | if (ret != 0) { |
671 | DPRINT_ERR(NETVSC, | |
672 | "unable to send NvspMessage1TypeSendNdisVersion"); | |
fceaf24a HJ |
673 | ret = -1; |
674 | goto Cleanup; | |
675 | } | |
454f18a9 BP |
676 | /* |
677 | * BUGBUG - We have to wait for the above msg since the | |
678 | * netvsp uses KMCL which acknowledges packet (completion | |
679 | * packet) since our Vmbus always set the | |
680 | * VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag | |
681 | */ | |
203df82d | 682 | /* osd_waitevent_wait(NetVscChannel->ChannelInitEvent); */ |
454f18a9 BP |
683 | |
684 | /* Post the big receive buffer to NetVSP */ | |
5a71ae30 | 685 | ret = netvsc_init_recv_buf(device); |
fceaf24a | 686 | if (ret == 0) |
5a71ae30 | 687 | ret = netvsc_init_send_buf(device); |
fceaf24a HJ |
688 | |
689 | Cleanup: | |
5a71ae30 | 690 | put_net_device(device); |
fceaf24a HJ |
691 | return ret; |
692 | } | |
693 | ||
85799a37 | 694 | static void NetVscDisconnectFromVsp(struct netvsc_device *net_device) |
fceaf24a | 695 | { |
5a71ae30 HZ |
696 | netvsc_destroy_recv_buf(net_device); |
697 | netvsc_destroy_send_buf(net_device); | |
fceaf24a HJ |
698 | } |
699 | ||
3e189519 | 700 | /* |
5a71ae30 HZ |
701 | * netvsc_device_add - Callback when the device belonging to this |
702 | * driver is added | |
21a80820 | 703 | */ |
5a71ae30 | 704 | static int netvsc_device_add(struct hv_device *device, void *additional_info) |
fceaf24a | 705 | { |
21a80820 | 706 | int ret = 0; |
fceaf24a | 707 | int i; |
85799a37 | 708 | struct netvsc_device *net_device; |
d29274ef | 709 | struct hv_netvsc_packet *packet, *pos; |
85799a37 HZ |
710 | struct netvsc_driver *net_driver = |
711 | (struct netvsc_driver *)device->Driver; | |
fceaf24a | 712 | |
5a71ae30 | 713 | net_device = alloc_net_device(device); |
85799a37 | 714 | if (!net_device) { |
fceaf24a HJ |
715 | ret = -1; |
716 | goto Cleanup; | |
717 | } | |
718 | ||
85799a37 | 719 | DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", net_device); |
fceaf24a | 720 | |
454f18a9 | 721 | /* Initialize the NetVSC channel extension */ |
85799a37 HZ |
722 | net_device->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE; |
723 | spin_lock_init(&net_device->receive_packet_list_lock); | |
fceaf24a | 724 | |
85799a37 | 725 | net_device->SendBufferSize = NETVSC_SEND_BUFFER_SIZE; |
fceaf24a | 726 | |
85799a37 | 727 | INIT_LIST_HEAD(&net_device->ReceivePacketList); |
fceaf24a | 728 | |
21a80820 GKH |
729 | for (i = 0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { |
730 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | |
731 | (NETVSC_RECEIVE_SG_COUNT * | |
732 | sizeof(struct hv_page_buffer)), GFP_KERNEL); | |
733 | if (!packet) { | |
734 | DPRINT_DBG(NETVSC, "unable to allocate netvsc pkts " | |
735 | "for receive pool (wanted %d got %d)", | |
736 | NETVSC_RECEIVE_PACKETLIST_COUNT, i); | |
fceaf24a HJ |
737 | break; |
738 | } | |
d29274ef | 739 | list_add_tail(&packet->ListEntry, |
85799a37 | 740 | &net_device->ReceivePacketList); |
fceaf24a | 741 | } |
85799a37 HZ |
742 | net_device->ChannelInitEvent = osd_waitevent_create(); |
743 | if (!net_device->ChannelInitEvent) { | |
80d11b2a BP |
744 | ret = -ENOMEM; |
745 | goto Cleanup; | |
746 | } | |
fceaf24a | 747 | |
454f18a9 | 748 | /* Open the channel */ |
85799a37 HZ |
749 | ret = vmbus_open(device->channel, net_driver->RingBufferSize, |
750 | net_driver->RingBufferSize, NULL, 0, | |
5a71ae30 | 751 | netvsc_channel_cb, device); |
fceaf24a | 752 | |
21a80820 | 753 | if (ret != 0) { |
fceaf24a HJ |
754 | DPRINT_ERR(NETVSC, "unable to open channel: %d", ret); |
755 | ret = -1; | |
756 | goto Cleanup; | |
757 | } | |
758 | ||
454f18a9 | 759 | /* Channel is opened */ |
fceaf24a HJ |
760 | DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***"); |
761 | ||
454f18a9 | 762 | /* Connect with the NetVsp */ |
5a71ae30 | 763 | ret = netvsc_connect_vsp(device); |
21a80820 | 764 | if (ret != 0) { |
fceaf24a HJ |
765 | DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret); |
766 | ret = -1; | |
1fb9dff0 | 767 | goto close; |
fceaf24a HJ |
768 | } |
769 | ||
21a80820 GKH |
770 | DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***", |
771 | ret); | |
fceaf24a | 772 | |
fceaf24a HJ |
773 | return ret; |
774 | ||
1fb9dff0 | 775 | close: |
454f18a9 | 776 | /* Now, we can close the channel safely */ |
85799a37 | 777 | vmbus_close(device->channel); |
fceaf24a HJ |
778 | |
779 | Cleanup: | |
780 | ||
85799a37 HZ |
781 | if (net_device) { |
782 | kfree(net_device->ChannelInitEvent); | |
fceaf24a | 783 | |
d29274ef | 784 | list_for_each_entry_safe(packet, pos, |
85799a37 | 785 | &net_device->ReceivePacketList, |
d29274ef BP |
786 | ListEntry) { |
787 | list_del(&packet->ListEntry); | |
8c69f52a | 788 | kfree(packet); |
fceaf24a HJ |
789 | } |
790 | ||
5a71ae30 HZ |
791 | release_outbound_net_device(device); |
792 | release_inbound_net_device(device); | |
fceaf24a | 793 | |
5a71ae30 | 794 | free_net_device(net_device); |
fceaf24a HJ |
795 | } |
796 | ||
fceaf24a HJ |
797 | return ret; |
798 | } | |
799 | ||
3e189519 | 800 | /* |
5a71ae30 | 801 | * netvsc_device_remove - Callback when the root bus device is removed |
21a80820 | 802 | */ |
5a71ae30 | 803 | static int netvsc_device_remove(struct hv_device *device) |
fceaf24a | 804 | { |
85799a37 HZ |
805 | struct netvsc_device *net_device; |
806 | struct hv_netvsc_packet *netvsc_packet, *pos; | |
fceaf24a | 807 | |
21a80820 | 808 | DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...", |
85799a37 | 809 | device->Extension); |
fceaf24a | 810 | |
454f18a9 | 811 | /* Stop outbound traffic ie sends and receives completions */ |
5a71ae30 | 812 | net_device = release_outbound_net_device(device); |
85799a37 | 813 | if (!net_device) { |
fceaf24a HJ |
814 | DPRINT_ERR(NETVSC, "No net device present!!"); |
815 | return -1; | |
816 | } | |
817 | ||
454f18a9 | 818 | /* Wait for all send completions */ |
85799a37 | 819 | while (atomic_read(&net_device->NumOutstandingSends)) { |
21a80820 | 820 | DPRINT_INFO(NETVSC, "waiting for %d requests to complete...", |
85799a37 | 821 | atomic_read(&net_device->NumOutstandingSends)); |
b4362c9c | 822 | udelay(100); |
fceaf24a HJ |
823 | } |
824 | ||
825 | DPRINT_INFO(NETVSC, "Disconnecting from netvsp..."); | |
826 | ||
85799a37 | 827 | NetVscDisconnectFromVsp(net_device); |
fceaf24a | 828 | |
21a80820 | 829 | DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...", |
85799a37 | 830 | device->Extension); |
fceaf24a | 831 | |
454f18a9 | 832 | /* Stop inbound traffic ie receives and sends completions */ |
5a71ae30 | 833 | net_device = release_inbound_net_device(device); |
fceaf24a | 834 | |
454f18a9 | 835 | /* At this point, no one should be accessing netDevice except in here */ |
85799a37 | 836 | DPRINT_INFO(NETVSC, "net device (%p) safe to remove", net_device); |
fceaf24a | 837 | |
454f18a9 | 838 | /* Now, we can close the channel safely */ |
85799a37 | 839 | vmbus_close(device->channel); |
fceaf24a | 840 | |
454f18a9 | 841 | /* Release all resources */ |
85799a37 HZ |
842 | list_for_each_entry_safe(netvsc_packet, pos, |
843 | &net_device->ReceivePacketList, ListEntry) { | |
844 | list_del(&netvsc_packet->ListEntry); | |
845 | kfree(netvsc_packet); | |
fceaf24a HJ |
846 | } |
847 | ||
85799a37 | 848 | kfree(net_device->ChannelInitEvent); |
5a71ae30 | 849 | free_net_device(net_device); |
21a80820 | 850 | return 0; |
fceaf24a HJ |
851 | } |
852 | ||
3e189519 | 853 | /* |
5a71ae30 | 854 | * netvsc_cleanup - Perform any cleanup when the driver is removed |
21a80820 | 855 | */ |
5a71ae30 | 856 | static void netvsc_cleanup(struct hv_driver *drv) |
fceaf24a | 857 | { |
fceaf24a HJ |
858 | } |
859 | ||
5a71ae30 | 860 | static void netvsc_send_completion(struct hv_device *device, |
85799a37 | 861 | struct vmpacket_descriptor *packet) |
fceaf24a | 862 | { |
85799a37 HZ |
863 | struct netvsc_device *net_device; |
864 | struct nvsp_message *nvsp_packet; | |
865 | struct hv_netvsc_packet *nvsc_packet; | |
fceaf24a | 866 | |
5a71ae30 | 867 | net_device = get_inbound_net_device(device); |
85799a37 | 868 | if (!net_device) { |
21a80820 GKH |
869 | DPRINT_ERR(NETVSC, "unable to get net device..." |
870 | "device being destroyed?"); | |
fceaf24a HJ |
871 | return; |
872 | } | |
873 | ||
85799a37 HZ |
874 | nvsp_packet = (struct nvsp_message *)((unsigned long)packet + |
875 | (packet->DataOffset8 << 3)); | |
fceaf24a | 876 | |
21a80820 | 877 | DPRINT_DBG(NETVSC, "send completion packet - type %d", |
85799a37 | 878 | nvsp_packet->Header.MessageType); |
fceaf24a | 879 | |
85799a37 HZ |
880 | if ((nvsp_packet->Header.MessageType == NvspMessageTypeInitComplete) || |
881 | (nvsp_packet->Header.MessageType == | |
21a80820 | 882 | NvspMessage1TypeSendReceiveBufferComplete) || |
85799a37 | 883 | (nvsp_packet->Header.MessageType == |
21a80820 | 884 | NvspMessage1TypeSendSendBufferComplete)) { |
454f18a9 | 885 | /* Copy the response back */ |
85799a37 | 886 | memcpy(&net_device->ChannelInitPacket, nvsp_packet, |
21a80820 | 887 | sizeof(struct nvsp_message)); |
85799a37 HZ |
888 | osd_waitevent_set(net_device->ChannelInitEvent); |
889 | } else if (nvsp_packet->Header.MessageType == | |
21a80820 | 890 | NvspMessage1TypeSendRNDISPacketComplete) { |
454f18a9 | 891 | /* Get the send context */ |
85799a37 HZ |
892 | nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) |
893 | packet->TransactionId; | |
972b9529 | 894 | /* ASSERT(nvscPacket); */ |
fceaf24a | 895 | |
454f18a9 | 896 | /* Notify the layer above us */ |
85799a37 HZ |
897 | nvsc_packet->Completion.Send.OnSendCompletion( |
898 | nvsc_packet->Completion.Send.SendCompletionContext); | |
fceaf24a | 899 | |
85799a37 | 900 | atomic_dec(&net_device->NumOutstandingSends); |
21a80820 GKH |
901 | } else { |
902 | DPRINT_ERR(NETVSC, "Unknown send completion packet type - " | |
85799a37 | 903 | "%d received!!", nvsp_packet->Header.MessageType); |
fceaf24a HJ |
904 | } |
905 | ||
5a71ae30 | 906 | put_net_device(device); |
fceaf24a HJ |
907 | } |
908 | ||
5a71ae30 | 909 | static int netvsc_send(struct hv_device *device, |
85799a37 | 910 | struct hv_netvsc_packet *packet) |
fceaf24a | 911 | { |
85799a37 | 912 | struct netvsc_device *net_device; |
21a80820 | 913 | int ret = 0; |
fceaf24a | 914 | |
223c1aa6 | 915 | struct nvsp_message sendMessage; |
fceaf24a | 916 | |
5a71ae30 | 917 | net_device = get_outbound_net_device(device); |
85799a37 | 918 | if (!net_device) { |
21a80820 | 919 | DPRINT_ERR(NETVSC, "net device (%p) shutting down..." |
85799a37 | 920 | "ignoring outbound packets", net_device); |
fceaf24a HJ |
921 | return -2; |
922 | } | |
923 | ||
924 | sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket; | |
85799a37 | 925 | if (packet->IsDataPacket) { |
21a80820 GKH |
926 | /* 0 is RMC_DATA; */ |
927 | sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0; | |
928 | } else { | |
929 | /* 1 is RMC_CONTROL; */ | |
930 | sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1; | |
931 | } | |
fceaf24a | 932 | |
454f18a9 | 933 | /* Not using send buffer section */ |
21a80820 GKH |
934 | sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF; |
935 | sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0; | |
936 | ||
85799a37 HZ |
937 | if (packet->PageBufferCount) { |
938 | ret = vmbus_sendpacket_pagebuffer(device->channel, | |
939 | packet->PageBuffers, | |
940 | packet->PageBufferCount, | |
ff3f8eec GKH |
941 | &sendMessage, |
942 | sizeof(struct nvsp_message), | |
85799a37 | 943 | (unsigned long)packet); |
21a80820 | 944 | } else { |
85799a37 | 945 | ret = vmbus_sendpacket(device->channel, &sendMessage, |
5a4df290 | 946 | sizeof(struct nvsp_message), |
85799a37 | 947 | (unsigned long)packet, |
5a4df290 GKH |
948 | VmbusPacketTypeDataInBand, |
949 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | |
fceaf24a HJ |
950 | |
951 | } | |
952 | ||
953 | if (ret != 0) | |
21a80820 | 954 | DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", |
85799a37 | 955 | packet, ret); |
fceaf24a | 956 | |
85799a37 | 957 | atomic_inc(&net_device->NumOutstandingSends); |
5a71ae30 | 958 | put_net_device(device); |
fceaf24a HJ |
959 | return ret; |
960 | } | |
961 | ||
5a71ae30 | 962 | static void netvsc_receive(struct hv_device *device, |
85799a37 | 963 | struct vmpacket_descriptor *packet) |
fceaf24a | 964 | { |
85799a37 HZ |
965 | struct netvsc_device *net_device; |
966 | struct vmtransfer_page_packet_header *vmxferpage_packet; | |
967 | struct nvsp_message *nvsp_packet; | |
968 | struct hv_netvsc_packet *netvsc_packet = NULL; | |
c4b0bc94 | 969 | unsigned long start; |
85799a37 | 970 | unsigned long end, end_virtual; |
7e23a6e9 | 971 | /* struct netvsc_driver *netvscDriver; */ |
85799a37 | 972 | struct xferpage_packet *xferpage_packet = NULL; |
21a80820 | 973 | int i, j; |
85799a37 | 974 | int count = 0, bytes_remain = 0; |
6436873a | 975 | unsigned long flags; |
d29274ef | 976 | LIST_HEAD(listHead); |
fceaf24a | 977 | |
5a71ae30 | 978 | net_device = get_inbound_net_device(device); |
85799a37 | 979 | if (!net_device) { |
21a80820 GKH |
980 | DPRINT_ERR(NETVSC, "unable to get net device..." |
981 | "device being destroyed?"); | |
fceaf24a HJ |
982 | return; |
983 | } | |
984 | ||
21a80820 GKH |
985 | /* |
986 | * All inbound packets other than send completion should be xfer page | |
987 | * packet | |
988 | */ | |
85799a37 | 989 | if (packet->Type != VmbusPacketTypeDataUsingTransferPages) { |
21a80820 | 990 | DPRINT_ERR(NETVSC, "Unknown packet type received - %d", |
85799a37 | 991 | packet->Type); |
5a71ae30 | 992 | put_net_device(device); |
fceaf24a HJ |
993 | return; |
994 | } | |
995 | ||
85799a37 HZ |
996 | nvsp_packet = (struct nvsp_message *)((unsigned long)packet + |
997 | (packet->DataOffset8 << 3)); | |
fceaf24a | 998 | |
454f18a9 | 999 | /* Make sure this is a valid nvsp packet */ |
85799a37 HZ |
1000 | if (nvsp_packet->Header.MessageType != |
1001 | NvspMessage1TypeSendRNDISPacket) { | |
21a80820 | 1002 | DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", |
85799a37 | 1003 | nvsp_packet->Header.MessageType); |
5a71ae30 | 1004 | put_net_device(device); |
fceaf24a HJ |
1005 | return; |
1006 | } | |
1007 | ||
21a80820 | 1008 | DPRINT_DBG(NETVSC, "NVSP packet received - type %d", |
85799a37 | 1009 | nvsp_packet->Header.MessageType); |
fceaf24a | 1010 | |
85799a37 | 1011 | vmxferpage_packet = (struct vmtransfer_page_packet_header *)packet; |
fceaf24a | 1012 | |
85799a37 | 1013 | if (vmxferpage_packet->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) { |
21a80820 GKH |
1014 | DPRINT_ERR(NETVSC, "Invalid xfer page set id - " |
1015 | "expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, | |
85799a37 | 1016 | vmxferpage_packet->TransferPageSetId); |
5a71ae30 | 1017 | put_net_device(device); |
fceaf24a HJ |
1018 | return; |
1019 | } | |
1020 | ||
21a80820 | 1021 | DPRINT_DBG(NETVSC, "xfer page - range count %d", |
85799a37 | 1022 | vmxferpage_packet->RangeCount); |
fceaf24a | 1023 | |
454f18a9 BP |
1024 | /* |
1025 | * Grab free packets (range count + 1) to represent this xfer | |
1026 | * page packet. +1 to represent the xfer page packet itself. | |
1027 | * We grab it here so that we know exactly how many we can | |
1028 | * fulfil | |
1029 | */ | |
85799a37 HZ |
1030 | spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); |
1031 | while (!list_empty(&net_device->ReceivePacketList)) { | |
1032 | list_move_tail(net_device->ReceivePacketList.next, &listHead); | |
1033 | if (++count == vmxferpage_packet->RangeCount + 1) | |
fceaf24a HJ |
1034 | break; |
1035 | } | |
85799a37 | 1036 | spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); |
fceaf24a | 1037 | |
454f18a9 BP |
1038 | /* |
1039 | * We need at least 2 netvsc pkts (1 to represent the xfer | |
1040 | * page and at least 1 for the range) i.e. we can handled | |
1041 | * some of the xfer page packet ranges... | |
1042 | */ | |
21a80820 GKH |
1043 | if (count < 2) { |
1044 | DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. " | |
1045 | "Dropping this xfer page packet completely!", | |
85799a37 | 1046 | count, vmxferpage_packet->RangeCount + 1); |
fceaf24a | 1047 | |
454f18a9 | 1048 | /* Return it to the freelist */ |
85799a37 | 1049 | spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); |
21a80820 | 1050 | for (i = count; i != 0; i--) { |
92ec0893 | 1051 | list_move_tail(listHead.next, |
85799a37 | 1052 | &net_device->ReceivePacketList); |
fceaf24a | 1053 | } |
85799a37 | 1054 | spin_unlock_irqrestore(&net_device->receive_packet_list_lock, |
21a80820 | 1055 | flags); |
fceaf24a | 1056 | |
5a71ae30 | 1057 | netvsc_send_recv_completion(device, |
85799a37 | 1058 | vmxferpage_packet->d.TransactionId); |
fceaf24a | 1059 | |
5a71ae30 | 1060 | put_net_device(device); |
fceaf24a HJ |
1061 | return; |
1062 | } | |
1063 | ||
454f18a9 | 1064 | /* Remove the 1st packet to represent the xfer page packet itself */ |
85799a37 HZ |
1065 | xferpage_packet = (struct xferpage_packet *)listHead.next; |
1066 | list_del(&xferpage_packet->ListEntry); | |
d29274ef | 1067 | |
21a80820 | 1068 | /* This is how much we can satisfy */ |
85799a37 | 1069 | xferpage_packet->Count = count - 1; |
972b9529 BP |
1070 | /* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */ |
1071 | /* vmxferpagePacket->RangeCount); */ | |
21a80820 | 1072 | |
85799a37 | 1073 | if (xferpage_packet->Count != vmxferpage_packet->RangeCount) { |
21a80820 | 1074 | DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer " |
85799a37 HZ |
1075 | "page...got %d", vmxferpage_packet->RangeCount, |
1076 | xferpage_packet->Count); | |
fceaf24a HJ |
1077 | } |
1078 | ||
454f18a9 | 1079 | /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ |
21a80820 | 1080 | for (i = 0; i < (count - 1); i++) { |
85799a37 HZ |
1081 | netvsc_packet = (struct hv_netvsc_packet *)listHead.next; |
1082 | list_del(&netvsc_packet->ListEntry); | |
fceaf24a | 1083 | |
454f18a9 | 1084 | /* Initialize the netvsc packet */ |
85799a37 HZ |
1085 | netvsc_packet->XferPagePacket = xferpage_packet; |
1086 | netvsc_packet->Completion.Recv.OnReceiveCompletion = | |
5a71ae30 | 1087 | netvsc_receive_completion; |
85799a37 HZ |
1088 | netvsc_packet->Completion.Recv.ReceiveCompletionContext = |
1089 | netvsc_packet; | |
1090 | netvsc_packet->Device = device; | |
21a80820 | 1091 | /* Save this so that we can send it back */ |
85799a37 HZ |
1092 | netvsc_packet->Completion.Recv.ReceiveCompletionTid = |
1093 | vmxferpage_packet->d.TransactionId; | |
fceaf24a | 1094 | |
85799a37 HZ |
1095 | netvsc_packet->TotalDataBufferLength = |
1096 | vmxferpage_packet->Ranges[i].ByteCount; | |
1097 | netvsc_packet->PageBufferCount = 1; | |
fceaf24a | 1098 | |
972b9529 BP |
1099 | /* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */ |
1100 | /* vmxferpagePacket->Ranges[i].ByteCount < */ | |
1101 | /* netDevice->ReceiveBufferSize); */ | |
fceaf24a | 1102 | |
85799a37 HZ |
1103 | netvsc_packet->PageBuffers[0].Length = |
1104 | vmxferpage_packet->Ranges[i].ByteCount; | |
fceaf24a | 1105 | |
85799a37 HZ |
1106 | start = virt_to_phys((void *)((unsigned long)net_device-> |
1107 | ReceiveBuffer + vmxferpage_packet->Ranges[i].ByteOffset)); | |
fceaf24a | 1108 | |
85799a37 HZ |
1109 | netvsc_packet->PageBuffers[0].Pfn = start >> PAGE_SHIFT; |
1110 | end_virtual = (unsigned long)net_device->ReceiveBuffer | |
1111 | + vmxferpage_packet->Ranges[i].ByteOffset | |
1112 | + vmxferpage_packet->Ranges[i].ByteCount - 1; | |
1113 | end = virt_to_phys((void *)end_virtual); | |
fceaf24a | 1114 | |
454f18a9 | 1115 | /* Calculate the page relative offset */ |
85799a37 HZ |
1116 | netvsc_packet->PageBuffers[0].Offset = |
1117 | vmxferpage_packet->Ranges[i].ByteOffset & | |
1118 | (PAGE_SIZE - 1); | |
21a80820 GKH |
1119 | if ((end >> PAGE_SHIFT) != (start >> PAGE_SHIFT)) { |
1120 | /* Handle frame across multiple pages: */ | |
85799a37 HZ |
1121 | netvsc_packet->PageBuffers[0].Length = |
1122 | (netvsc_packet->PageBuffers[0].Pfn << | |
1123 | PAGE_SHIFT) | |
21a80820 | 1124 | + PAGE_SIZE - start; |
85799a37 HZ |
1125 | bytes_remain = netvsc_packet->TotalDataBufferLength - |
1126 | netvsc_packet->PageBuffers[0].Length; | |
21a80820 | 1127 | for (j = 1; j < NETVSC_PACKET_MAXPAGE; j++) { |
85799a37 HZ |
1128 | netvsc_packet->PageBuffers[j].Offset = 0; |
1129 | if (bytes_remain <= PAGE_SIZE) { | |
1130 | netvsc_packet->PageBuffers[j].Length = | |
1131 | bytes_remain; | |
1132 | bytes_remain = 0; | |
21a80820 | 1133 | } else { |
85799a37 HZ |
1134 | netvsc_packet->PageBuffers[j].Length = |
1135 | PAGE_SIZE; | |
1136 | bytes_remain -= PAGE_SIZE; | |
21a80820 | 1137 | } |
85799a37 HZ |
1138 | netvsc_packet->PageBuffers[j].Pfn = |
1139 | virt_to_phys((void *)(end_virtual - | |
1140 | bytes_remain)) >> PAGE_SHIFT; | |
1141 | netvsc_packet->PageBufferCount++; | |
1142 | if (bytes_remain == 0) | |
21a80820 | 1143 | break; |
fceaf24a | 1144 | } |
972b9529 | 1145 | /* ASSERT(bytesRemain == 0); */ |
fceaf24a | 1146 | } |
21a80820 GKH |
1147 | DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => " |
1148 | "(pfn %llx, offset %u, len %u)", i, | |
85799a37 HZ |
1149 | vmxferpage_packet->Ranges[i].ByteOffset, |
1150 | vmxferpage_packet->Ranges[i].ByteCount, | |
1151 | netvsc_packet->PageBuffers[0].Pfn, | |
1152 | netvsc_packet->PageBuffers[0].Offset, | |
1153 | netvsc_packet->PageBuffers[0].Length); | |
fceaf24a | 1154 | |
454f18a9 | 1155 | /* Pass it to the upper layer */ |
85799a37 HZ |
1156 | ((struct netvsc_driver *)device->Driver)-> |
1157 | OnReceiveCallback(device, netvsc_packet); | |
fceaf24a | 1158 | |
5a71ae30 | 1159 | netvsc_receive_completion(netvsc_packet-> |
85799a37 | 1160 | Completion.Recv.ReceiveCompletionContext); |
fceaf24a HJ |
1161 | } |
1162 | ||
972b9529 | 1163 | /* ASSERT(list_empty(&listHead)); */ |
fceaf24a | 1164 | |
5a71ae30 | 1165 | put_net_device(device); |
fceaf24a HJ |
1166 | } |
1167 | ||
5a71ae30 | 1168 | static void netvsc_send_recv_completion(struct hv_device *device, |
85799a37 | 1169 | u64 transaction_id) |
fceaf24a | 1170 | { |
223c1aa6 | 1171 | struct nvsp_message recvcompMessage; |
21a80820 GKH |
1172 | int retries = 0; |
1173 | int ret; | |
fceaf24a | 1174 | |
21a80820 | 1175 | DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx", |
85799a37 | 1176 | transaction_id); |
fceaf24a | 1177 | |
21a80820 GKH |
1178 | recvcompMessage.Header.MessageType = |
1179 | NvspMessage1TypeSendRNDISPacketComplete; | |
fceaf24a | 1180 | |
454f18a9 | 1181 | /* FIXME: Pass in the status */ |
fceaf24a HJ |
1182 | recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess; |
1183 | ||
1184 | retry_send_cmplt: | |
454f18a9 | 1185 | /* Send the completion */ |
85799a37 HZ |
1186 | ret = vmbus_sendpacket(device->channel, &recvcompMessage, |
1187 | sizeof(struct nvsp_message), transaction_id, | |
5a4df290 | 1188 | VmbusPacketTypeCompletion, 0); |
21a80820 GKH |
1189 | if (ret == 0) { |
1190 | /* success */ | |
454f18a9 | 1191 | /* no-op */ |
21a80820 GKH |
1192 | } else if (ret == -1) { |
1193 | /* no more room...wait a bit and attempt to retry 3 times */ | |
fceaf24a | 1194 | retries++; |
21a80820 | 1195 | DPRINT_ERR(NETVSC, "unable to send receive completion pkt " |
85799a37 | 1196 | "(tid %llx)...retrying %d", transaction_id, retries); |
fceaf24a | 1197 | |
21a80820 | 1198 | if (retries < 4) { |
b4362c9c | 1199 | udelay(100); |
fceaf24a | 1200 | goto retry_send_cmplt; |
21a80820 GKH |
1201 | } else { |
1202 | DPRINT_ERR(NETVSC, "unable to send receive completion " | |
1203 | "pkt (tid %llx)...give up retrying", | |
85799a37 | 1204 | transaction_id); |
fceaf24a | 1205 | } |
21a80820 GKH |
1206 | } else { |
1207 | DPRINT_ERR(NETVSC, "unable to send receive completion pkt - " | |
85799a37 | 1208 | "%llx", transaction_id); |
fceaf24a HJ |
1209 | } |
1210 | } | |
1211 | ||
454f18a9 | 1212 | /* Send a receive completion packet to RNDIS device (ie NetVsp) */ |
5a71ae30 | 1213 | static void netvsc_receive_completion(void *context) |
fceaf24a | 1214 | { |
85799a37 | 1215 | struct hv_netvsc_packet *packet = context; |
21a80820 | 1216 | struct hv_device *device = (struct hv_device *)packet->Device; |
85799a37 HZ |
1217 | struct netvsc_device *net_device; |
1218 | u64 transaction_id = 0; | |
1219 | bool fsend_receive_comp = false; | |
6436873a | 1220 | unsigned long flags; |
fceaf24a | 1221 | |
972b9529 | 1222 | /* ASSERT(packet->XferPagePacket); */ |
fceaf24a | 1223 | |
21a80820 GKH |
1224 | /* |
1225 | * Even though it seems logical to do a GetOutboundNetDevice() here to | |
1226 | * send out receive completion, we are using GetInboundNetDevice() | |
1227 | * since we may have disable outbound traffic already. | |
1228 | */ | |
5a71ae30 | 1229 | net_device = get_inbound_net_device(device); |
85799a37 | 1230 | if (!net_device) { |
21a80820 GKH |
1231 | DPRINT_ERR(NETVSC, "unable to get net device..." |
1232 | "device being destroyed?"); | |
fceaf24a HJ |
1233 | return; |
1234 | } | |
1235 | ||
454f18a9 | 1236 | /* Overloading use of the lock. */ |
85799a37 | 1237 | spin_lock_irqsave(&net_device->receive_packet_list_lock, flags); |
fceaf24a | 1238 | |
972b9529 | 1239 | /* ASSERT(packet->XferPagePacket->Count > 0); */ |
fceaf24a HJ |
1240 | packet->XferPagePacket->Count--; |
1241 | ||
21a80820 GKH |
1242 | /* |
1243 | * Last one in the line that represent 1 xfer page packet. | |
1244 | * Return the xfer page packet itself to the freelist | |
1245 | */ | |
1246 | if (packet->XferPagePacket->Count == 0) { | |
85799a37 HZ |
1247 | fsend_receive_comp = true; |
1248 | transaction_id = packet->Completion.Recv.ReceiveCompletionTid; | |
d29274ef | 1249 | list_add_tail(&packet->XferPagePacket->ListEntry, |
85799a37 | 1250 | &net_device->ReceivePacketList); |
fceaf24a | 1251 | |
fceaf24a HJ |
1252 | } |
1253 | ||
454f18a9 | 1254 | /* Put the packet back */ |
85799a37 HZ |
1255 | list_add_tail(&packet->ListEntry, &net_device->ReceivePacketList); |
1256 | spin_unlock_irqrestore(&net_device->receive_packet_list_lock, flags); | |
fceaf24a | 1257 | |
454f18a9 | 1258 | /* Send a receive completion for the xfer page packet */ |
85799a37 | 1259 | if (fsend_receive_comp) |
5a71ae30 | 1260 | netvsc_send_recv_completion(device, transaction_id); |
fceaf24a | 1261 | |
5a71ae30 | 1262 | put_net_device(device); |
fceaf24a HJ |
1263 | } |
1264 | ||
5a71ae30 | 1265 | static void netvsc_channel_cb(void *context) |
fceaf24a | 1266 | { |
21a80820 | 1267 | int ret; |
85799a37 HZ |
1268 | struct hv_device *device = context; |
1269 | struct netvsc_device *net_device; | |
1270 | u32 bytes_recvd; | |
1271 | u64 request_id; | |
c6fcf0ba | 1272 | unsigned char *packet; |
8dc0a06a | 1273 | struct vmpacket_descriptor *desc; |
c6fcf0ba BP |
1274 | unsigned char *buffer; |
1275 | int bufferlen = NETVSC_PACKET_SIZE; | |
fceaf24a | 1276 | |
972b9529 | 1277 | /* ASSERT(device); */ |
fceaf24a | 1278 | |
c6fcf0ba BP |
1279 | packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char), |
1280 | GFP_KERNEL); | |
1281 | if (!packet) | |
1282 | return; | |
1283 | buffer = packet; | |
1284 | ||
5a71ae30 | 1285 | net_device = get_inbound_net_device(device); |
85799a37 | 1286 | if (!net_device) { |
21a80820 | 1287 | DPRINT_ERR(NETVSC, "net device (%p) shutting down..." |
85799a37 | 1288 | "ignoring inbound packets", net_device); |
c6fcf0ba | 1289 | goto out; |
fceaf24a HJ |
1290 | } |
1291 | ||
21a80820 | 1292 | do { |
9f630068 | 1293 | ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, |
85799a37 | 1294 | &bytes_recvd, &request_id); |
21a80820 | 1295 | if (ret == 0) { |
85799a37 | 1296 | if (bytes_recvd > 0) { |
21a80820 | 1297 | DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx", |
85799a37 | 1298 | bytes_recvd, request_id); |
21a80820 GKH |
1299 | |
1300 | desc = (struct vmpacket_descriptor *)buffer; | |
1301 | switch (desc->Type) { | |
1302 | case VmbusPacketTypeCompletion: | |
5a71ae30 | 1303 | netvsc_send_completion(device, desc); |
21a80820 GKH |
1304 | break; |
1305 | ||
1306 | case VmbusPacketTypeDataUsingTransferPages: | |
5a71ae30 | 1307 | netvsc_receive(device, desc); |
21a80820 GKH |
1308 | break; |
1309 | ||
1310 | default: | |
1311 | DPRINT_ERR(NETVSC, | |
1312 | "unhandled packet type %d, " | |
1313 | "tid %llx len %d\n", | |
85799a37 HZ |
1314 | desc->Type, request_id, |
1315 | bytes_recvd); | |
21a80820 | 1316 | break; |
fceaf24a HJ |
1317 | } |
1318 | ||
454f18a9 | 1319 | /* reset */ |
c6fcf0ba | 1320 | if (bufferlen > NETVSC_PACKET_SIZE) { |
8c69f52a | 1321 | kfree(buffer); |
fceaf24a | 1322 | buffer = packet; |
c6fcf0ba | 1323 | bufferlen = NETVSC_PACKET_SIZE; |
fceaf24a | 1324 | } |
21a80820 | 1325 | } else { |
454f18a9 | 1326 | /* reset */ |
c6fcf0ba | 1327 | if (bufferlen > NETVSC_PACKET_SIZE) { |
8c69f52a | 1328 | kfree(buffer); |
fceaf24a | 1329 | buffer = packet; |
c6fcf0ba | 1330 | bufferlen = NETVSC_PACKET_SIZE; |
fceaf24a HJ |
1331 | } |
1332 | ||
1333 | break; | |
1334 | } | |
21a80820 GKH |
1335 | } else if (ret == -2) { |
1336 | /* Handle large packet */ | |
85799a37 | 1337 | buffer = kmalloc(bytes_recvd, GFP_ATOMIC); |
21a80820 | 1338 | if (buffer == NULL) { |
454f18a9 | 1339 | /* Try again next time around */ |
21a80820 GKH |
1340 | DPRINT_ERR(NETVSC, |
1341 | "unable to allocate buffer of size " | |
85799a37 | 1342 | "(%d)!!", bytes_recvd); |
fceaf24a HJ |
1343 | break; |
1344 | } | |
1345 | ||
85799a37 | 1346 | bufferlen = bytes_recvd; |
fceaf24a HJ |
1347 | } |
1348 | } while (1); | |
1349 | ||
5a71ae30 | 1350 | put_net_device(device); |
c6fcf0ba BP |
1351 | out: |
1352 | kfree(buffer); | |
fceaf24a HJ |
1353 | return; |
1354 | } |