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