Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.git] / drivers / staging / hv / channel.c
1 /*
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:
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
20 */
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/slab.h>
24 #include <linux/module.h>
25 #include "osd.h"
26 #include "logging.h"
27 #include "vmbus_private.h"
28
29 /* Internal routines */
30 static int VmbusChannelCreateGpadlHeader(
31 void *Kbuffer, /* must be phys and virt contiguous */
32 u32 Size, /* page-size multiple */
33 struct vmbus_channel_msginfo **msgInfo,
34 u32 *MessageCount);
35 static void DumpVmbusChannel(struct vmbus_channel *channel);
36 static void VmbusChannelSetEvent(struct vmbus_channel *channel);
37
38
39 #if 0
40 static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
41 {
42 int i = 0;
43 int j = 0;
44
45 DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
46 MonitorPage, MonitorPage->TriggerState);
47
48 for (i = 0; i < 4; i++)
49 DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
50 MonitorPage->TriggerGroup[i].AsUINT64);
51
52 for (i = 0; i < 4; i++) {
53 for (j = 0; j < 32; j++) {
54 DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
55 MonitorPage->Latency[i][j]);
56 }
57 }
58 for (i = 0; i < 4; i++) {
59 for (j = 0; j < 32; j++) {
60 DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
61 MonitorPage->Parameter[i][j].ConnectionId.Asu32);
62 DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
63 MonitorPage->Parameter[i][j].FlagNumber);
64 }
65 }
66 }
67 #endif
68
69 /*
70 * VmbusChannelSetEvent - Trigger an event notification on the specified
71 * channel.
72 */
73 static void VmbusChannelSetEvent(struct vmbus_channel *Channel)
74 {
75 struct hv_monitor_page *monitorPage;
76
77 if (Channel->OfferMsg.MonitorAllocated) {
78 /* Each u32 represents 32 channels */
79 set_bit(Channel->OfferMsg.ChildRelId & 31,
80 (unsigned long *) gVmbusConnection.SendInterruptPage +
81 (Channel->OfferMsg.ChildRelId >> 5));
82
83 monitorPage = gVmbusConnection.MonitorPages;
84 monitorPage++; /* Get the child to parent monitor page */
85
86 set_bit(Channel->MonitorBit,
87 (unsigned long *)&monitorPage->TriggerGroup
88 [Channel->MonitorGroup].Pending);
89
90 } else {
91 VmbusSetEvent(Channel->OfferMsg.ChildRelId);
92 }
93 }
94
95 #if 0
96 static void VmbusChannelClearEvent(struct vmbus_channel *channel)
97 {
98 struct hv_monitor_page *monitorPage;
99
100 if (Channel->OfferMsg.MonitorAllocated) {
101 /* Each u32 represents 32 channels */
102 clear_bit(Channel->OfferMsg.ChildRelId & 31,
103 (unsigned long *)gVmbusConnection.SendInterruptPage +
104 (Channel->OfferMsg.ChildRelId >> 5));
105
106 monitorPage =
107 (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
108 monitorPage++; /* Get the child to parent monitor page */
109
110 clear_bit(Channel->MonitorBit,
111 (unsigned long *)&monitorPage->TriggerGroup
112 [Channel->MonitorGroup].Pending);
113 }
114 }
115
116 #endif
117 /*
118 * VmbusChannelGetDebugInfo -Retrieve various channel debug info
119 */
120 void VmbusChannelGetDebugInfo(struct vmbus_channel *Channel,
121 struct vmbus_channel_debug_info *DebugInfo)
122 {
123 struct hv_monitor_page *monitorPage;
124 u8 monitorGroup = (u8)Channel->OfferMsg.MonitorId / 32;
125 u8 monitorOffset = (u8)Channel->OfferMsg.MonitorId % 32;
126 /* u32 monitorBit = 1 << monitorOffset; */
127
128 DebugInfo->RelId = Channel->OfferMsg.ChildRelId;
129 DebugInfo->State = Channel->State;
130 memcpy(&DebugInfo->InterfaceType,
131 &Channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
132 memcpy(&DebugInfo->InterfaceInstance,
133 &Channel->OfferMsg.Offer.InterfaceInstance,
134 sizeof(struct hv_guid));
135
136 monitorPage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
137
138 DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
139
140 DebugInfo->ServerMonitorPending =
141 monitorPage->TriggerGroup[monitorGroup].Pending;
142 DebugInfo->ServerMonitorLatency =
143 monitorPage->Latency[monitorGroup][monitorOffset];
144 DebugInfo->ServerMonitorConnectionId =
145 monitorPage->Parameter[monitorGroup]
146 [monitorOffset].ConnectionId.u.Id;
147
148 monitorPage++;
149
150 DebugInfo->ClientMonitorPending =
151 monitorPage->TriggerGroup[monitorGroup].Pending;
152 DebugInfo->ClientMonitorLatency =
153 monitorPage->Latency[monitorGroup][monitorOffset];
154 DebugInfo->ClientMonitorConnectionId =
155 monitorPage->Parameter[monitorGroup]
156 [monitorOffset].ConnectionId.u.Id;
157
158 RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
159 RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
160 }
161
162 /*
163 * VmbusChannelOpen - Open the specified channel.
164 */
165 int VmbusChannelOpen(struct vmbus_channel *NewChannel, u32 SendRingBufferSize,
166 u32 RecvRingBufferSize, void *UserData, u32 UserDataLen,
167 void (*OnChannelCallback)(void *context), void *Context)
168 {
169 struct vmbus_channel_open_channel *openMsg;
170 struct vmbus_channel_msginfo *openInfo = NULL;
171 void *in, *out;
172 unsigned long flags;
173 int ret, err = 0;
174
175 /* Aligned to page size */
176 /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
177 /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
178
179 NewChannel->OnChannelCallback = OnChannelCallback;
180 NewChannel->ChannelCallbackContext = Context;
181
182 /* Allocate the ring buffer */
183 out = osd_PageAlloc((SendRingBufferSize + RecvRingBufferSize)
184 >> PAGE_SHIFT);
185 if (!out)
186 return -ENOMEM;
187
188 /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
189
190 in = (void *)((unsigned long)out + SendRingBufferSize);
191
192 NewChannel->RingBufferPages = out;
193 NewChannel->RingBufferPageCount = (SendRingBufferSize +
194 RecvRingBufferSize) >> PAGE_SHIFT;
195
196 ret = RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
197 if (ret != 0) {
198 err = ret;
199 goto errorout;
200 }
201
202 ret = RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
203 if (ret != 0) {
204 err = ret;
205 goto errorout;
206 }
207
208
209 /* Establish the gpadl for the ring buffer */
210 DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
211 NewChannel);
212
213 NewChannel->RingBufferGpadlHandle = 0;
214
215 ret = VmbusChannelEstablishGpadl(NewChannel,
216 NewChannel->Outbound.RingBuffer,
217 SendRingBufferSize +
218 RecvRingBufferSize,
219 &NewChannel->RingBufferGpadlHandle);
220
221 if (ret != 0) {
222 err = ret;
223 goto errorout;
224 }
225
226 DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
227 "size %d recv ring %p size %d, downstreamoffset %d>",
228 NewChannel, NewChannel->OfferMsg.ChildRelId,
229 NewChannel->RingBufferGpadlHandle,
230 NewChannel->Outbound.RingBuffer,
231 NewChannel->Outbound.RingSize,
232 NewChannel->Inbound.RingBuffer,
233 NewChannel->Inbound.RingSize,
234 SendRingBufferSize);
235
236 /* Create and init the channel open message */
237 openInfo = kmalloc(sizeof(*openInfo) +
238 sizeof(struct vmbus_channel_open_channel),
239 GFP_KERNEL);
240 if (!openInfo) {
241 err = -ENOMEM;
242 goto errorout;
243 }
244
245 openInfo->WaitEvent = osd_WaitEventCreate();
246 if (!openInfo->WaitEvent) {
247 err = -ENOMEM;
248 goto errorout;
249 }
250
251 openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
252 openMsg->Header.MessageType = ChannelMessageOpenChannel;
253 openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; /* FIXME */
254 openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId;
255 openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle;
256 openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >>
257 PAGE_SHIFT;
258 openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
259
260 if (UserDataLen > MAX_USER_DEFINED_BYTES) {
261 err = -EINVAL;
262 goto errorout;
263 }
264
265 if (UserDataLen)
266 memcpy(openMsg->UserData, UserData, UserDataLen);
267
268 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
269 list_add_tail(&openInfo->MsgListEntry,
270 &gVmbusConnection.ChannelMsgList);
271 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
272
273 DPRINT_DBG(VMBUS, "Sending channel open msg...");
274
275 ret = VmbusPostMessage(openMsg,
276 sizeof(struct vmbus_channel_open_channel));
277 if (ret != 0) {
278 DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
279 goto Cleanup;
280 }
281
282 /* FIXME: Need to time-out here */
283 osd_WaitEventWait(openInfo->WaitEvent);
284
285 if (openInfo->Response.OpenResult.Status == 0)
286 DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
287 else
288 DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
289 NewChannel, openInfo->Response.OpenResult.Status);
290
291 Cleanup:
292 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
293 list_del(&openInfo->MsgListEntry);
294 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
295
296 kfree(openInfo->WaitEvent);
297 kfree(openInfo);
298 return 0;
299
300 errorout:
301 RingBufferCleanup(&NewChannel->Outbound);
302 RingBufferCleanup(&NewChannel->Inbound);
303 osd_PageFree(out, (SendRingBufferSize + RecvRingBufferSize)
304 >> PAGE_SHIFT);
305 kfree(openInfo);
306 return err;
307 }
308
309 /*
310 * DumpGpadlBody - Dump the gpadl body message to the console for
311 * debugging purposes.
312 */
313 static void DumpGpadlBody(struct vmbus_channel_gpadl_body *Gpadl, u32 Len)
314 {
315 int i;
316 int pfnCount;
317
318 pfnCount = (Len - sizeof(struct vmbus_channel_gpadl_body)) /
319 sizeof(u64);
320 DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
321
322 for (i = 0; i < pfnCount; i++)
323 DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
324 i, Gpadl->Pfn[i]);
325 }
326
327 /*
328 * DumpGpadlHeader - Dump the gpadl header message to the console for
329 * debugging purposes.
330 */
331 static void DumpGpadlHeader(struct vmbus_channel_gpadl_header *Gpadl)
332 {
333 int i, j;
334 int pageCount;
335
336 DPRINT_DBG(VMBUS,
337 "gpadl header - relid %d, range count %d, range buflen %d",
338 Gpadl->ChildRelId, Gpadl->RangeCount, Gpadl->RangeBufLen);
339 for (i = 0; i < Gpadl->RangeCount; i++) {
340 pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
341 pageCount = (pageCount > 26) ? 26 : pageCount;
342
343 DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
344 "page count %d", i, Gpadl->Range[i].ByteCount,
345 Gpadl->Range[i].ByteOffset, pageCount);
346
347 for (j = 0; j < pageCount; j++)
348 DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
349 Gpadl->Range[i].PfnArray[j]);
350 }
351 }
352
353 /*
354 * VmbusChannelCreateGpadlHeader - Creates a gpadl for the specified buffer
355 */
356 static int VmbusChannelCreateGpadlHeader(void *Kbuffer, u32 Size,
357 struct vmbus_channel_msginfo **MsgInfo,
358 u32 *MessageCount)
359 {
360 int i;
361 int pageCount;
362 unsigned long long pfn;
363 struct vmbus_channel_gpadl_header *gpaHeader;
364 struct vmbus_channel_gpadl_body *gpadlBody;
365 struct vmbus_channel_msginfo *msgHeader;
366 struct vmbus_channel_msginfo *msgBody = NULL;
367 u32 msgSize;
368
369 int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
370
371 /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
372 /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
373
374 pageCount = Size >> PAGE_SHIFT;
375 pfn = virt_to_phys(Kbuffer) >> PAGE_SHIFT;
376
377 /* do we need a gpadl body msg */
378 pfnSize = MAX_SIZE_CHANNEL_MESSAGE -
379 sizeof(struct vmbus_channel_gpadl_header) -
380 sizeof(struct gpa_range);
381 pfnCount = pfnSize / sizeof(u64);
382
383 if (pageCount > pfnCount) {
384 /* we need a gpadl body */
385 /* fill in the header */
386 msgSize = sizeof(struct vmbus_channel_msginfo) +
387 sizeof(struct vmbus_channel_gpadl_header) +
388 sizeof(struct gpa_range) + pfnCount * sizeof(u64);
389 msgHeader = kzalloc(msgSize, GFP_KERNEL);
390 if (!msgHeader)
391 goto nomem;
392
393 INIT_LIST_HEAD(&msgHeader->SubMsgList);
394 msgHeader->MessageSize = msgSize;
395
396 gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
397 gpaHeader->RangeCount = 1;
398 gpaHeader->RangeBufLen = sizeof(struct gpa_range) +
399 pageCount * sizeof(u64);
400 gpaHeader->Range[0].ByteOffset = 0;
401 gpaHeader->Range[0].ByteCount = Size;
402 for (i = 0; i < pfnCount; i++)
403 gpaHeader->Range[0].PfnArray[i] = pfn+i;
404 *MsgInfo = msgHeader;
405 *MessageCount = 1;
406
407 pfnSum = pfnCount;
408 pfnLeft = pageCount - pfnCount;
409
410 /* how many pfns can we fit */
411 pfnSize = MAX_SIZE_CHANNEL_MESSAGE -
412 sizeof(struct vmbus_channel_gpadl_body);
413 pfnCount = pfnSize / sizeof(u64);
414
415 /* fill in the body */
416 while (pfnLeft) {
417 if (pfnLeft > pfnCount)
418 pfnCurr = pfnCount;
419 else
420 pfnCurr = pfnLeft;
421
422 msgSize = sizeof(struct vmbus_channel_msginfo) +
423 sizeof(struct vmbus_channel_gpadl_body) +
424 pfnCurr * sizeof(u64);
425 msgBody = kzalloc(msgSize, GFP_KERNEL);
426 /* FIXME: we probably need to more if this fails */
427 if (!msgBody)
428 goto nomem;
429 msgBody->MessageSize = msgSize;
430 (*MessageCount)++;
431 gpadlBody =
432 (struct vmbus_channel_gpadl_body *)msgBody->Msg;
433
434 /*
435 * FIXME:
436 * Gpadl is u32 and we are using a pointer which could
437 * be 64-bit
438 */
439 /* gpadlBody->Gpadl = kbuffer; */
440 for (i = 0; i < pfnCurr; i++)
441 gpadlBody->Pfn[i] = pfn + pfnSum + i;
442
443 /* add to msg header */
444 list_add_tail(&msgBody->MsgListEntry,
445 &msgHeader->SubMsgList);
446 pfnSum += pfnCurr;
447 pfnLeft -= pfnCurr;
448 }
449 } else {
450 /* everything fits in a header */
451 msgSize = sizeof(struct vmbus_channel_msginfo) +
452 sizeof(struct vmbus_channel_gpadl_header) +
453 sizeof(struct gpa_range) + pageCount * sizeof(u64);
454 msgHeader = kzalloc(msgSize, GFP_KERNEL);
455 if (msgHeader == NULL)
456 goto nomem;
457 msgHeader->MessageSize = msgSize;
458
459 gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
460 gpaHeader->RangeCount = 1;
461 gpaHeader->RangeBufLen = sizeof(struct gpa_range) +
462 pageCount * sizeof(u64);
463 gpaHeader->Range[0].ByteOffset = 0;
464 gpaHeader->Range[0].ByteCount = Size;
465 for (i = 0; i < pageCount; i++)
466 gpaHeader->Range[0].PfnArray[i] = pfn+i;
467
468 *MsgInfo = msgHeader;
469 *MessageCount = 1;
470 }
471
472 return 0;
473 nomem:
474 kfree(msgHeader);
475 kfree(msgBody);
476 return -ENOMEM;
477 }
478
479 /*
480 * VmbusChannelEstablishGpadl - Estabish a GPADL for the specified buffer
481 *
482 * @Channel: a channel
483 * @Kbuffer: from kmalloc
484 * @Size: page-size multiple
485 * @GpadlHandle: some funky thing
486 */
487 int VmbusChannelEstablishGpadl(struct vmbus_channel *Channel, void *Kbuffer,
488 u32 Size, u32 *GpadlHandle)
489 {
490 struct vmbus_channel_gpadl_header *gpadlMsg;
491 struct vmbus_channel_gpadl_body *gpadlBody;
492 /* struct vmbus_channel_gpadl_created *gpadlCreated; */
493 struct vmbus_channel_msginfo *msgInfo = NULL;
494 struct vmbus_channel_msginfo *subMsgInfo;
495 u32 msgCount;
496 struct list_head *curr;
497 u32 nextGpadlHandle;
498 unsigned long flags;
499 int ret = 0;
500
501 nextGpadlHandle = atomic_read(&gVmbusConnection.NextGpadlHandle);
502 atomic_inc(&gVmbusConnection.NextGpadlHandle);
503
504 ret = VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
505 if (ret)
506 return ret;
507
508 msgInfo->WaitEvent = osd_WaitEventCreate();
509 if (!msgInfo->WaitEvent) {
510 ret = -ENOMEM;
511 goto Cleanup;
512 }
513
514 gpadlMsg = (struct vmbus_channel_gpadl_header *)msgInfo->Msg;
515 gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader;
516 gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId;
517 gpadlMsg->Gpadl = nextGpadlHandle;
518
519 DumpGpadlHeader(gpadlMsg);
520
521 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
522 list_add_tail(&msgInfo->MsgListEntry,
523 &gVmbusConnection.ChannelMsgList);
524
525 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
526 DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
527 Kbuffer, Size, msgCount);
528
529 DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
530 msgInfo->MessageSize - sizeof(*msgInfo));
531
532 ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize -
533 sizeof(*msgInfo));
534 if (ret != 0) {
535 DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
536 goto Cleanup;
537 }
538
539 if (msgCount > 1) {
540 list_for_each(curr, &msgInfo->SubMsgList) {
541
542 /* FIXME: should this use list_entry() instead ? */
543 subMsgInfo = (struct vmbus_channel_msginfo *)curr;
544 gpadlBody =
545 (struct vmbus_channel_gpadl_body *)subMsgInfo->Msg;
546
547 gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
548 gpadlBody->Gpadl = nextGpadlHandle;
549
550 DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
551 subMsgInfo->MessageSize -
552 sizeof(*subMsgInfo));
553
554 DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize -
555 sizeof(*subMsgInfo));
556 ret = VmbusPostMessage(gpadlBody,
557 subMsgInfo->MessageSize -
558 sizeof(*subMsgInfo));
559 if (ret != 0)
560 goto Cleanup;
561
562 }
563 }
564 osd_WaitEventWait(msgInfo->WaitEvent);
565
566 /* At this point, we received the gpadl created msg */
567 DPRINT_DBG(VMBUS, "Received GPADL created "
568 "(relid %d, status %d handle %x)",
569 Channel->OfferMsg.ChildRelId,
570 msgInfo->Response.GpadlCreated.CreationStatus,
571 gpadlMsg->Gpadl);
572
573 *GpadlHandle = gpadlMsg->Gpadl;
574
575 Cleanup:
576 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
577 list_del(&msgInfo->MsgListEntry);
578 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
579
580 kfree(msgInfo->WaitEvent);
581 kfree(msgInfo);
582 return ret;
583 }
584
585 /*
586 * VmbusChannelTeardownGpadl -Teardown the specified GPADL handle
587 */
588 int VmbusChannelTeardownGpadl(struct vmbus_channel *Channel, u32 GpadlHandle)
589 {
590 struct vmbus_channel_gpadl_teardown *msg;
591 struct vmbus_channel_msginfo *info;
592 unsigned long flags;
593 int ret;
594
595 /* ASSERT(GpadlHandle != 0); */
596
597 info = kmalloc(sizeof(*info) +
598 sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
599 if (!info)
600 return -ENOMEM;
601
602 info->WaitEvent = osd_WaitEventCreate();
603 if (!info->WaitEvent) {
604 kfree(info);
605 return -ENOMEM;
606 }
607
608 msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
609
610 msg->Header.MessageType = ChannelMessageGpadlTeardown;
611 msg->ChildRelId = Channel->OfferMsg.ChildRelId;
612 msg->Gpadl = GpadlHandle;
613
614 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
615 list_add_tail(&info->MsgListEntry,
616 &gVmbusConnection.ChannelMsgList);
617 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
618
619 ret = VmbusPostMessage(msg,
620 sizeof(struct vmbus_channel_gpadl_teardown));
621 if (ret != 0) {
622 /* TODO: */
623 /* something... */
624 }
625
626 osd_WaitEventWait(info->WaitEvent);
627
628 /* Received a torndown response */
629 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
630 list_del(&info->MsgListEntry);
631 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
632
633 kfree(info->WaitEvent);
634 kfree(info);
635 return ret;
636 }
637
638 /*
639 * VmbusChannelClose - Close the specified channel
640 */
641 void VmbusChannelClose(struct vmbus_channel *Channel)
642 {
643 struct vmbus_channel_close_channel *msg;
644 struct vmbus_channel_msginfo *info;
645 unsigned long flags;
646 int ret;
647
648 /* Stop callback and cancel the timer asap */
649 Channel->OnChannelCallback = NULL;
650 del_timer_sync(&Channel->poll_timer);
651
652 /* Send a closing message */
653 info = kmalloc(sizeof(*info) +
654 sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
655 /* FIXME: can't do anything other than return here because the
656 * function is void */
657 if (!info)
658 return;
659
660 /* info->waitEvent = osd_WaitEventCreate(); */
661
662 msg = (struct vmbus_channel_close_channel *)info->Msg;
663 msg->Header.MessageType = ChannelMessageCloseChannel;
664 msg->ChildRelId = Channel->OfferMsg.ChildRelId;
665
666 ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
667 if (ret != 0) {
668 /* TODO: */
669 /* something... */
670 }
671
672 /* Tear down the gpadl for the channel's ring buffer */
673 if (Channel->RingBufferGpadlHandle)
674 VmbusChannelTeardownGpadl(Channel,
675 Channel->RingBufferGpadlHandle);
676
677 /* TODO: Send a msg to release the childRelId */
678
679 /* Cleanup the ring buffers for this channel */
680 RingBufferCleanup(&Channel->Outbound);
681 RingBufferCleanup(&Channel->Inbound);
682
683 osd_PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
684
685 kfree(info);
686
687 /*
688 * If we are closing the channel during an error path in
689 * opening the channel, don't free the channel since the
690 * caller will free the channel
691 */
692
693 if (Channel->State == CHANNEL_OPEN_STATE) {
694 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
695 list_del(&Channel->ListEntry);
696 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
697
698 FreeVmbusChannel(Channel);
699 }
700 }
701
702 /**
703 * VmbusChannelSendPacket() - Send the specified buffer on the given channel
704 * @Channel: Pointer to vmbus_channel structure.
705 * @Buffer: Pointer to the buffer you want to receive the data into.
706 * @BufferLen: Maximum size of what the the buffer will hold
707 * @RequestId: Identifier of the request
708 * @vmbus_packet_type: Type of packet that is being send e.g. negotiate, time
709 * packet etc.
710 *
711 * Sends data in @Buffer directly to hyper-v via the vmbus
712 * This will send the data unparsed to hyper-v.
713 *
714 * Mainly used by Hyper-V drivers.
715 */
716 int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,
717 u32 BufferLen, u64 RequestId,
718 enum vmbus_packet_type Type, u32 Flags)
719 {
720 struct vmpacket_descriptor desc;
721 u32 packetLen = sizeof(struct vmpacket_descriptor) + BufferLen;
722 u32 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
723 struct scatterlist bufferList[3];
724 u64 alignedData = 0;
725 int ret;
726
727 DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
728 Channel, Buffer, BufferLen);
729
730 DumpVmbusChannel(Channel);
731
732 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
733
734 /* Setup the descriptor */
735 desc.Type = Type; /* VmbusPacketTypeDataInBand; */
736 desc.Flags = Flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
737 /* in 8-bytes granularity */
738 desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3;
739 desc.Length8 = (u16)(packetLenAligned >> 3);
740 desc.TransactionId = RequestId;
741
742 sg_init_table(bufferList, 3);
743 sg_set_buf(&bufferList[0], &desc, sizeof(struct vmpacket_descriptor));
744 sg_set_buf(&bufferList[1], Buffer, BufferLen);
745 sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
746
747 ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
748
749 /* TODO: We should determine if this is optional */
750 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
751 VmbusChannelSetEvent(Channel);
752
753 return ret;
754 }
755 EXPORT_SYMBOL(VmbusChannelSendPacket);
756
757 /*
758 * VmbusChannelSendPacketPageBuffer - Send a range of single-page buffer
759 * packets using a GPADL Direct packet type.
760 */
761 int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *Channel,
762 struct hv_page_buffer PageBuffers[],
763 u32 PageCount, void *Buffer, u32 BufferLen,
764 u64 RequestId)
765 {
766 int ret;
767 int i;
768 struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
769 u32 descSize;
770 u32 packetLen;
771 u32 packetLenAligned;
772 struct scatterlist bufferList[3];
773 u64 alignedData = 0;
774
775 if (PageCount > MAX_PAGE_BUFFER_COUNT)
776 return -EINVAL;
777
778 DumpVmbusChannel(Channel);
779
780 /*
781 * Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the
782 * largest size we support
783 */
784 descSize = sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER) -
785 ((MAX_PAGE_BUFFER_COUNT - PageCount) *
786 sizeof(struct hv_page_buffer));
787 packetLen = descSize + BufferLen;
788 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
789
790 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
791
792 /* Setup the descriptor */
793 desc.Type = VmbusPacketTypeDataUsingGpaDirect;
794 desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
795 desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
796 desc.Length8 = (u16)(packetLenAligned >> 3);
797 desc.TransactionId = RequestId;
798 desc.RangeCount = PageCount;
799
800 for (i = 0; i < PageCount; i++) {
801 desc.Range[i].Length = PageBuffers[i].Length;
802 desc.Range[i].Offset = PageBuffers[i].Offset;
803 desc.Range[i].Pfn = PageBuffers[i].Pfn;
804 }
805
806 sg_init_table(bufferList, 3);
807 sg_set_buf(&bufferList[0], &desc, descSize);
808 sg_set_buf(&bufferList[1], Buffer, BufferLen);
809 sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
810
811 ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
812
813 /* TODO: We should determine if this is optional */
814 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
815 VmbusChannelSetEvent(Channel);
816
817 return ret;
818 }
819
820 /*
821 * VmbusChannelSendPacketMultiPageBuffer - Send a multi-page buffer packet
822 * using a GPADL Direct packet type.
823 */
824 int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *Channel,
825 struct hv_multipage_buffer *MultiPageBuffer,
826 void *Buffer, u32 BufferLen, u64 RequestId)
827 {
828 int ret;
829 struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
830 u32 descSize;
831 u32 packetLen;
832 u32 packetLenAligned;
833 struct scatterlist bufferList[3];
834 u64 alignedData = 0;
835 u32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset,
836 MultiPageBuffer->Length);
837
838 DumpVmbusChannel(Channel);
839
840 DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
841 MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
842
843 if ((PfnCount < 0) || (PfnCount > MAX_MULTIPAGE_BUFFER_COUNT))
844 return -EINVAL;
845
846 /*
847 * Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is
848 * the largest size we support
849 */
850 descSize = sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) -
851 ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount) *
852 sizeof(u64));
853 packetLen = descSize + BufferLen;
854 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
855
856 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
857
858 /* Setup the descriptor */
859 desc.Type = VmbusPacketTypeDataUsingGpaDirect;
860 desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
861 desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
862 desc.Length8 = (u16)(packetLenAligned >> 3);
863 desc.TransactionId = RequestId;
864 desc.RangeCount = 1;
865
866 desc.Range.Length = MultiPageBuffer->Length;
867 desc.Range.Offset = MultiPageBuffer->Offset;
868
869 memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray,
870 PfnCount * sizeof(u64));
871
872 sg_init_table(bufferList, 3);
873 sg_set_buf(&bufferList[0], &desc, descSize);
874 sg_set_buf(&bufferList[1], Buffer, BufferLen);
875 sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
876
877 ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
878
879 /* TODO: We should determine if this is optional */
880 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
881 VmbusChannelSetEvent(Channel);
882
883 return ret;
884 }
885
886
887 /**
888 * VmbusChannelRecvPacket() - Retrieve the user packet on the specified channel
889 * @Channel: Pointer to vmbus_channel structure.
890 * @Buffer: Pointer to the buffer you want to receive the data into.
891 * @BufferLen: Maximum size of what the the buffer will hold
892 * @BufferActualLen: The actual size of the data after it was received
893 * @RequestId: Identifier of the request
894 *
895 * Receives directly from the hyper-v vmbus and puts the data it received
896 * into Buffer. This will receive the data unparsed from hyper-v.
897 *
898 * Mainly used by Hyper-V drivers.
899 */
900 int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
901 u32 BufferLen, u32 *BufferActualLen, u64 *RequestId)
902 {
903 struct vmpacket_descriptor desc;
904 u32 packetLen;
905 u32 userLen;
906 int ret;
907 unsigned long flags;
908
909 *BufferActualLen = 0;
910 *RequestId = 0;
911
912 spin_lock_irqsave(&Channel->inbound_lock, flags);
913
914 ret = RingBufferPeek(&Channel->Inbound, &desc,
915 sizeof(struct vmpacket_descriptor));
916 if (ret != 0) {
917 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
918
919 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
920 return 0;
921 }
922
923 /* VmbusChannelClearEvent(Channel); */
924
925 packetLen = desc.Length8 << 3;
926 userLen = packetLen - (desc.DataOffset8 << 3);
927 /* ASSERT(userLen > 0); */
928
929 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
930 "flag %d tid %llx pktlen %d datalen %d> ",
931 Channel, Channel->OfferMsg.ChildRelId, desc.Type,
932 desc.Flags, desc.TransactionId, packetLen, userLen);
933
934 *BufferActualLen = userLen;
935
936 if (userLen > BufferLen) {
937 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
938
939 DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
940 BufferLen, userLen);
941 return -1;
942 }
943
944 *RequestId = desc.TransactionId;
945
946 /* Copy over the packet to the user buffer */
947 ret = RingBufferRead(&Channel->Inbound, Buffer, userLen,
948 (desc.DataOffset8 << 3));
949
950 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
951
952 return 0;
953 }
954 EXPORT_SYMBOL(VmbusChannelRecvPacket);
955
956 /*
957 * VmbusChannelRecvPacketRaw - Retrieve the raw packet on the specified channel
958 */
959 int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
960 u32 BufferLen, u32 *BufferActualLen,
961 u64 *RequestId)
962 {
963 struct vmpacket_descriptor desc;
964 u32 packetLen;
965 u32 userLen;
966 int ret;
967 unsigned long flags;
968
969 *BufferActualLen = 0;
970 *RequestId = 0;
971
972 spin_lock_irqsave(&Channel->inbound_lock, flags);
973
974 ret = RingBufferPeek(&Channel->Inbound, &desc,
975 sizeof(struct vmpacket_descriptor));
976 if (ret != 0) {
977 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
978
979 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
980 return 0;
981 }
982
983 /* VmbusChannelClearEvent(Channel); */
984
985 packetLen = desc.Length8 << 3;
986 userLen = packetLen - (desc.DataOffset8 << 3);
987
988 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
989 "flag %d tid %llx pktlen %d datalen %d> ",
990 Channel, Channel->OfferMsg.ChildRelId, desc.Type,
991 desc.Flags, desc.TransactionId, packetLen, userLen);
992
993 *BufferActualLen = packetLen;
994
995 if (packetLen > BufferLen) {
996 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
997
998 DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
999 "got space for only %d bytes", packetLen, BufferLen);
1000 return -2;
1001 }
1002
1003 *RequestId = desc.TransactionId;
1004
1005 /* Copy over the entire packet to the user buffer */
1006 ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
1007
1008 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1009 return 0;
1010 }
1011
1012 /*
1013 * VmbusChannelOnChannelEvent - Channel event callback
1014 */
1015 void VmbusChannelOnChannelEvent(struct vmbus_channel *Channel)
1016 {
1017 DumpVmbusChannel(Channel);
1018 /* ASSERT(Channel->OnChannelCallback); */
1019
1020 Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1021
1022 mod_timer(&Channel->poll_timer, jiffies + usecs_to_jiffies(100));
1023 }
1024
1025 /*
1026 * VmbusChannelOnTimer - Timer event callback
1027 */
1028 void VmbusChannelOnTimer(unsigned long data)
1029 {
1030 struct vmbus_channel *channel = (struct vmbus_channel *)data;
1031
1032 if (channel->OnChannelCallback)
1033 channel->OnChannelCallback(channel->ChannelCallbackContext);
1034 }
1035
1036 /*
1037 * DumpVmbusChannel - Dump vmbus channel info to the console
1038 */
1039 static void DumpVmbusChannel(struct vmbus_channel *Channel)
1040 {
1041 DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
1042 DumpRingInfo(&Channel->Outbound, "Outbound ");
1043 DumpRingInfo(&Channel->Inbound, "Inbound ");
1044 }
This page took 0.077649 seconds and 5 git commands to generate.