Staging: hv: remove WaitEventClose()
[deliverable/linux.git] / drivers / staging / hv / Channel.c
1 /*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
21 *
22 */
23
24 #include <linux/kernel.h>
25 #include "include/osd.h"
26 #include "include/logging.h"
27
28 #include "VmbusPrivate.h"
29
30 /* Internal routines */
31 static int
32 VmbusChannelCreateGpadlHeader(
33 void * Kbuffer, /* must be phys and virt contiguous */
34 u32 Size, /* page-size multiple */
35 VMBUS_CHANNEL_MSGINFO **msgInfo,
36 u32 *MessageCount
37 );
38
39 static void
40 DumpVmbusChannel(
41 VMBUS_CHANNEL *Channel
42 );
43
44
45 static void
46 VmbusChannelSetEvent(
47 VMBUS_CHANNEL *Channel
48 );
49
50
51 #if 0
52 static void
53 DumpMonitorPage(
54 HV_MONITOR_PAGE *MonitorPage
55 )
56 {
57 int i=0;
58 int j=0;
59
60 DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState);
61
62 for (i=0; i<4; i++)
63 {
64 DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64);
65 }
66
67 for (i=0; i<4; i++)
68 {
69 for (j=0; j<32; j++)
70 {
71 DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]);
72 }
73 }
74 for (i=0; i<4; i++)
75 {
76 for (j=0; j<32; j++)
77 {
78 DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].ConnectionId.Asu32);
79 DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].FlagNumber);
80
81 }
82 }
83 }
84 #endif
85
86 /*++
87
88 Name:
89 VmbusChannelSetEvent()
90
91 Description:
92 Trigger an event notification on the specified channel.
93
94 --*/
95 static void
96 VmbusChannelSetEvent(
97 VMBUS_CHANNEL *Channel
98 )
99 {
100 HV_MONITOR_PAGE *monitorPage;
101
102 DPRINT_ENTER(VMBUS);
103
104 if (Channel->OfferMsg.MonitorAllocated)
105 {
106 /* Each u32 represents 32 channels */
107 BitSet((u32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
108
109 monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
110 monitorPage++; /* Get the child to parent monitor page */
111
112 BitSet((u32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
113 }
114 else
115 {
116 VmbusSetEvent(Channel->OfferMsg.ChildRelId);
117 }
118
119 DPRINT_EXIT(VMBUS);
120 }
121
122 #if 0
123 static void
124 VmbusChannelClearEvent(
125 VMBUS_CHANNEL *Channel
126 )
127 {
128 HV_MONITOR_PAGE *monitorPage;
129
130 DPRINT_ENTER(VMBUS);
131
132 if (Channel->OfferMsg.MonitorAllocated)
133 {
134 /* Each u32 represents 32 channels */
135 BitClear((u32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
136
137 monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
138 monitorPage++; /* Get the child to parent monitor page */
139
140 BitClear((u32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
141 }
142
143 DPRINT_EXIT(VMBUS);
144 }
145
146 #endif
147 /*++;
148
149 Name:
150 VmbusChannelGetDebugInfo()
151
152 Description:
153 Retrieve various channel debug info
154
155 --*/
156 static void
157 VmbusChannelGetDebugInfo(
158 VMBUS_CHANNEL *Channel,
159 VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
160 )
161 {
162 HV_MONITOR_PAGE *monitorPage;
163 u8 monitorGroup = (u8)Channel->OfferMsg.MonitorId / 32;
164 u8 monitorOffset = (u8)Channel->OfferMsg.MonitorId % 32;
165 /* u32 monitorBit = 1 << monitorOffset; */
166
167 DebugInfo->RelId = Channel->OfferMsg.ChildRelId;
168 DebugInfo->State = Channel->State;
169 memcpy(&DebugInfo->InterfaceType, &Channel->OfferMsg.Offer.InterfaceType, sizeof(GUID));
170 memcpy(&DebugInfo->InterfaceInstance, &Channel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID));
171
172 monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
173
174 DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
175
176 DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
177 DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
178 DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
179
180 monitorPage++;
181
182 DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
183 DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
184 DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
185
186 RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
187 RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
188 }
189
190
191 /*++;
192
193 Name:
194 VmbusChannelOpen()
195
196 Description:
197 Open the specified channel.
198
199 --*/
200 static int
201 VmbusChannelOpen(
202 VMBUS_CHANNEL *NewChannel,
203 u32 SendRingBufferSize,
204 u32 RecvRingBufferSize,
205 void * UserData,
206 u32 UserDataLen,
207 PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
208 void * Context
209 )
210 {
211 int ret=0;
212 VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
213 VMBUS_CHANNEL_MSGINFO* openInfo;
214 void *in, *out;
215 unsigned long flags;
216
217 DPRINT_ENTER(VMBUS);
218
219 /* Aligned to page size */
220 ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1)));
221 ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1)));
222
223 NewChannel->OnChannelCallback = pfnOnChannelCallback;
224 NewChannel->ChannelCallbackContext = Context;
225
226 /* Allocate the ring buffer */
227 out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT);
228 /* out = kzalloc(sendRingBufferSize + recvRingBufferSize, GFP_KERNEL); */
229 ASSERT(out);
230 ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0);
231
232 in = (void*)((unsigned long)out + SendRingBufferSize);
233
234 NewChannel->RingBufferPages = out;
235 NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT;
236
237 RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
238
239 RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
240
241 /* Establish the gpadl for the ring buffer */
242 DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel);
243
244 NewChannel->RingBufferGpadlHandle = 0;
245
246 ret = VmbusChannelEstablishGpadl(NewChannel,
247 NewChannel->Outbound.RingBuffer,
248 SendRingBufferSize + RecvRingBufferSize,
249 &NewChannel->RingBufferGpadlHandle);
250
251 DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>",
252 NewChannel,
253 NewChannel->OfferMsg.ChildRelId,
254 NewChannel->RingBufferGpadlHandle,
255 NewChannel->Outbound.RingBuffer,
256 NewChannel->Outbound.RingSize,
257 NewChannel->Inbound.RingBuffer,
258 NewChannel->Inbound.RingSize,
259 SendRingBufferSize);
260
261 /* Create and init the channel open message */
262 openInfo = kmalloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL), GFP_KERNEL);
263 ASSERT(openInfo != NULL);
264
265 openInfo->WaitEvent = WaitEventCreate();
266
267 openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)openInfo->Msg;
268 openMsg->Header.MessageType = ChannelMessageOpenChannel;
269 openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; /* FIXME */
270 openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId;
271 openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle;
272 ASSERT(openMsg->RingBufferGpadlHandle);
273 openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >> PAGE_SHIFT;
274 openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
275
276 ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES);
277 if (UserDataLen)
278 {
279 memcpy(openMsg->UserData, UserData, UserDataLen);
280 }
281
282 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
283 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry);
284 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
285
286 DPRINT_DBG(VMBUS, "Sending channel open msg...");
287
288 ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
289 if (ret != 0)
290 {
291 DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
292 goto Cleanup;
293 }
294
295 /* FIXME: Need to time-out here */
296 WaitEventWait(openInfo->WaitEvent);
297
298 if (openInfo->Response.OpenResult.Status == 0)
299 {
300 DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
301 }
302 else
303 {
304 DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status);
305 }
306
307 Cleanup:
308 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
309 REMOVE_ENTRY_LIST(&openInfo->MsgListEntry);
310 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
311
312 kfree(openInfo->WaitEvent);
313 kfree(openInfo);
314
315 DPRINT_EXIT(VMBUS);
316
317 return 0;
318 }
319
320 /*++;
321
322 Name:
323 DumpGpadlBody()
324
325 Description:
326 Dump the gpadl body message to the console for debugging purposes.
327
328 --*/
329 static void DumpGpadlBody(
330 VMBUS_CHANNEL_GPADL_BODY *Gpadl,
331 u32 Len)
332 {
333 int i=0;
334 int pfnCount=0;
335
336 pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(u64);
337 DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
338
339 for (i=0; i< pfnCount; i++)
340 {
341 DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]);
342 }
343 }
344
345
346 /*++;
347
348 Name:
349 DumpGpadlHeader()
350
351 Description:
352 Dump the gpadl header message to the console for debugging purposes.
353
354 --*/
355 static void DumpGpadlHeader(
356 VMBUS_CHANNEL_GPADL_HEADER *Gpadl
357 )
358 {
359 int i=0,j=0;
360 int pageCount=0;
361
362
363 DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d",
364 Gpadl->ChildRelId,
365 Gpadl->RangeCount,
366 Gpadl->RangeBufLen);
367 for (i=0; i< Gpadl->RangeCount; i++)
368 {
369 pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
370 pageCount = (pageCount > 26)? 26 : pageCount;
371
372 DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d page count %d",
373 i, Gpadl->Range[i].ByteCount, Gpadl->Range[i].ByteOffset, pageCount);
374
375 for (j=0; j< pageCount; j++)
376 {
377 DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]);
378 }
379 }
380 }
381
382 /*++;
383
384 Name:
385 VmbusChannelCreateGpadlHeader()
386
387 Description:
388 Creates a gpadl for the specified buffer
389
390 --*/
391 static int
392 VmbusChannelCreateGpadlHeader(
393 void * Kbuffer, /* from kmalloc() */
394 u32 Size, /* page-size multiple */
395 VMBUS_CHANNEL_MSGINFO **MsgInfo,
396 u32 *MessageCount)
397 {
398 int i;
399 int pageCount;
400 unsigned long long pfn;
401 VMBUS_CHANNEL_GPADL_HEADER* gpaHeader;
402 VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
403 VMBUS_CHANNEL_MSGINFO* msgHeader;
404 VMBUS_CHANNEL_MSGINFO* msgBody;
405 u32 msgSize;
406
407 int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
408
409 /* ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0); */
410 ASSERT( (Size & (PAGE_SIZE-1)) == 0);
411
412 pageCount = Size >> PAGE_SHIFT;
413 pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT;
414
415 /* do we need a gpadl body msg */
416 pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_HEADER) - sizeof(GPA_RANGE);
417 pfnCount = pfnSize / sizeof(u64);
418
419 if (pageCount > pfnCount) /* we need a gpadl body */
420 {
421 /* fill in the header */
422 msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pfnCount*sizeof(u64);
423 msgHeader = kzalloc(msgSize, GFP_KERNEL);
424
425 INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList);
426 msgHeader->MessageSize=msgSize;
427
428 gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg;
429 gpaHeader->RangeCount = 1;
430 gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(u64);
431 gpaHeader->Range[0].ByteOffset = 0;
432 gpaHeader->Range[0].ByteCount = Size;
433 for (i=0; i<pfnCount; i++)
434 {
435 gpaHeader->Range[0].PfnArray[i] = pfn+i;
436 }
437 *MsgInfo = msgHeader;
438 *MessageCount = 1;
439
440 pfnSum = pfnCount;
441 pfnLeft = pageCount - pfnCount;
442
443 /* how many pfns can we fit */
444 pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY);
445 pfnCount = pfnSize / sizeof(u64);
446
447 /* fill in the body */
448 while (pfnLeft)
449 {
450 if (pfnLeft > pfnCount)
451 {
452 pfnCurr = pfnCount;
453 }
454 else
455 {
456 pfnCurr = pfnLeft;
457 }
458
459 msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(u64);
460 msgBody = kzalloc(msgSize, GFP_KERNEL);
461 ASSERT(msgBody);
462 msgBody->MessageSize = msgSize;
463 (*MessageCount)++;
464 gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg;
465
466 /* FIXME: Gpadl is u32 and we are using a pointer which could be 64-bit */
467 /* gpadlBody->Gpadl = kbuffer; */
468 for (i=0; i<pfnCurr; i++)
469 {
470 gpadlBody->Pfn[i] = pfn + pfnSum + i;
471 }
472
473 /* add to msg header */
474 INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry);
475 pfnSum += pfnCurr;
476 pfnLeft -= pfnCurr;
477 }
478 }
479 else
480 {
481 /* everything fits in a header */
482 msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pageCount*sizeof(u64);
483 msgHeader = kzalloc(msgSize, GFP_KERNEL);
484 msgHeader->MessageSize=msgSize;
485
486 gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg;
487 gpaHeader->RangeCount = 1;
488 gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(u64);
489 gpaHeader->Range[0].ByteOffset = 0;
490 gpaHeader->Range[0].ByteCount = Size;
491 for (i=0; i<pageCount; i++)
492 {
493 gpaHeader->Range[0].PfnArray[i] = pfn+i;
494 }
495
496 *MsgInfo = msgHeader;
497 *MessageCount = 1;
498 }
499
500 return 0;
501 }
502
503
504 /*++;
505
506 Name:
507 VmbusChannelEstablishGpadl()
508
509 Description:
510 Estabish a GPADL for the specified buffer
511
512 --*/
513 static int
514 VmbusChannelEstablishGpadl(
515 VMBUS_CHANNEL *Channel,
516 void * Kbuffer, /* from kmalloc() */
517 u32 Size, /* page-size multiple */
518 u32 *GpadlHandle
519 )
520 {
521 int ret=0;
522 VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg;
523 VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
524 /* VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated; */
525
526 VMBUS_CHANNEL_MSGINFO *msgInfo;
527 VMBUS_CHANNEL_MSGINFO *subMsgInfo;
528
529 u32 msgCount;
530 LIST_ENTRY* anchor;
531 LIST_ENTRY* curr;
532 u32 nextGpadlHandle;
533 unsigned long flags;
534
535 DPRINT_ENTER(VMBUS);
536
537 nextGpadlHandle = gVmbusConnection.NextGpadlHandle;
538 InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle);
539
540 VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
541 ASSERT(msgInfo != NULL);
542 ASSERT(msgCount >0);
543
544 msgInfo->WaitEvent = WaitEventCreate();
545 gpadlMsg = (VMBUS_CHANNEL_GPADL_HEADER*)msgInfo->Msg;
546 gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader;
547 gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId;
548 gpadlMsg->Gpadl = nextGpadlHandle;
549
550 DumpGpadlHeader(gpadlMsg);
551
552 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
553 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
554 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
555
556 DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount);
557
558 DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
559
560 ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
561 if (ret != 0)
562 {
563 DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
564 goto Cleanup;
565 }
566
567 if (msgCount>1)
568 {
569 ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList)
570 {
571 subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
572 gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg;
573
574 gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
575 gpadlBody->Gpadl = nextGpadlHandle;
576
577 DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
578
579 DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
580 ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
581 ASSERT(ret == 0);
582 }
583 }
584 WaitEventWait(msgInfo->WaitEvent);
585
586 /* At this point, we received the gpadl created msg */
587 DPRINT_DBG(VMBUS, "Received GPADL created (relid %d, status %d handle %x)",
588 Channel->OfferMsg.ChildRelId,
589 msgInfo->Response.GpadlCreated.CreationStatus,
590 gpadlMsg->Gpadl);
591
592 *GpadlHandle = gpadlMsg->Gpadl;
593
594 Cleanup:
595 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
596 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
597 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
598
599 kfree(msgInfo->WaitEvent);
600 kfree(msgInfo);
601
602 DPRINT_EXIT(VMBUS);
603
604 return ret;
605 }
606
607
608
609 /*++;
610
611 Name:
612 VmbusChannelTeardownGpadl()
613
614 Description:
615 Teardown the specified GPADL handle
616
617 --*/
618 static int
619 VmbusChannelTeardownGpadl(
620 VMBUS_CHANNEL *Channel,
621 u32 GpadlHandle
622 )
623 {
624 int ret=0;
625 VMBUS_CHANNEL_GPADL_TEARDOWN *msg;
626 VMBUS_CHANNEL_MSGINFO* info;
627 unsigned long flags;
628
629 DPRINT_ENTER(VMBUS);
630
631 ASSERT(GpadlHandle != 0);
632
633 info = kmalloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN), GFP_KERNEL);
634 ASSERT(info != NULL);
635
636 info->WaitEvent = WaitEventCreate();
637
638 msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg;
639
640 msg->Header.MessageType = ChannelMessageGpadlTeardown;
641 msg->ChildRelId = Channel->OfferMsg.ChildRelId;
642 msg->Gpadl = GpadlHandle;
643
644 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
645 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry);
646 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
647
648 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
649 if (ret != 0)
650 {
651 /* TODO: */
652 }
653
654 WaitEventWait(info->WaitEvent);
655
656 /* Received a torndown response */
657 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
658 REMOVE_ENTRY_LIST(&info->MsgListEntry);
659 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
660
661 kfree(info->WaitEvent);
662 kfree(info);
663
664 DPRINT_EXIT(VMBUS);
665
666 return ret;
667 }
668
669
670 /*++
671
672 Name:
673 VmbusChannelClose()
674
675 Description:
676 Close the specified channel
677
678 --*/
679 static void
680 VmbusChannelClose(
681 VMBUS_CHANNEL *Channel
682 )
683 {
684 int ret=0;
685 VMBUS_CHANNEL_CLOSE_CHANNEL* msg;
686 VMBUS_CHANNEL_MSGINFO* info;
687 unsigned long flags;
688
689 DPRINT_ENTER(VMBUS);
690
691 /* Stop callback and cancel the timer asap */
692 Channel->OnChannelCallback = NULL;
693 TimerStop(Channel->PollTimer);
694
695 /* Send a closing message */
696 info = kmalloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL), GFP_KERNEL);
697 ASSERT(info != NULL);
698
699 /* info->waitEvent = WaitEventCreate(); */
700
701 msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg;
702 msg->Header.MessageType = ChannelMessageCloseChannel;
703 msg->ChildRelId = Channel->OfferMsg.ChildRelId;
704
705 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
706 if (ret != 0)
707 {
708 /* TODO: */
709 }
710
711 /* Tear down the gpadl for the channel's ring buffer */
712 if (Channel->RingBufferGpadlHandle)
713 {
714 VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle);
715 }
716
717 /* TODO: Send a msg to release the childRelId */
718
719 /* Cleanup the ring buffers for this channel */
720 RingBufferCleanup(&Channel->Outbound);
721 RingBufferCleanup(&Channel->Inbound);
722
723 PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
724
725 kfree(info);
726
727
728 /*
729 * If we are closing the channel during an error path in
730 * opening the channel, don't free the channel since the
731 * caller will free the channel
732 */
733
734 if (Channel->State == CHANNEL_OPEN_STATE)
735 {
736 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
737 REMOVE_ENTRY_LIST(&Channel->ListEntry);
738 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
739
740 FreeVmbusChannel(Channel);
741 }
742
743 DPRINT_EXIT(VMBUS);
744 }
745
746
747 /*++
748
749 Name:
750 VmbusChannelSendPacket()
751
752 Description:
753 Send the specified buffer on the given channel
754
755 --*/
756 static int
757 VmbusChannelSendPacket(
758 VMBUS_CHANNEL *Channel,
759 const void * Buffer,
760 u32 BufferLen,
761 u64 RequestId,
762 VMBUS_PACKET_TYPE Type,
763 u32 Flags
764 )
765 {
766 int ret=0;
767 VMPACKET_DESCRIPTOR desc;
768 u32 packetLen = sizeof(VMPACKET_DESCRIPTOR) + BufferLen;
769 u32 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
770 SG_BUFFER_LIST bufferList[3];
771 u64 alignedData=0;
772
773 DPRINT_ENTER(VMBUS);
774 DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen);
775
776 DumpVmbusChannel(Channel);
777
778 ASSERT((packetLenAligned - packetLen) < sizeof(u64));
779
780 /* Setup the descriptor */
781 desc.Type = Type; /* VmbusPacketTypeDataInBand; */
782 desc.Flags = Flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
783 desc.DataOffset8 = sizeof(VMPACKET_DESCRIPTOR) >> 3; /* in 8-bytes granularity */
784 desc.Length8 = (u16)(packetLenAligned >> 3);
785 desc.TransactionId = RequestId;
786
787 bufferList[0].Data = &desc;
788 bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR);
789
790 bufferList[1].Data = Buffer;
791 bufferList[1].Length = BufferLen;
792
793 bufferList[2].Data = &alignedData;
794 bufferList[2].Length = packetLenAligned - packetLen;
795
796 ret = RingBufferWrite(
797 &Channel->Outbound,
798 bufferList,
799 3);
800
801 /* TODO: We should determine if this is optional */
802 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
803 {
804 VmbusChannelSetEvent(Channel);
805 }
806
807 DPRINT_EXIT(VMBUS);
808
809 return ret;
810 }
811
812
813 /*++
814
815 Name:
816 VmbusChannelSendPacketPageBuffer()
817
818 Description:
819 Send a range of single-page buffer packets using a GPADL Direct packet type.
820
821 --*/
822 static int
823 VmbusChannelSendPacketPageBuffer(
824 VMBUS_CHANNEL *Channel,
825 PAGE_BUFFER PageBuffers[],
826 u32 PageCount,
827 void * Buffer,
828 u32 BufferLen,
829 u64 RequestId
830 )
831 {
832 int ret=0;
833 int i=0;
834 struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
835 u32 descSize;
836 u32 packetLen;
837 u32 packetLenAligned;
838 SG_BUFFER_LIST bufferList[3];
839 u64 alignedData=0;
840
841 DPRINT_ENTER(VMBUS);
842
843 ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT);
844
845 DumpVmbusChannel(Channel);
846
847 /* Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support */
848 descSize = sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER) - ((MAX_PAGE_BUFFER_COUNT - PageCount)*sizeof(PAGE_BUFFER));
849 packetLen = descSize + BufferLen;
850 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
851
852 ASSERT((packetLenAligned - packetLen) < sizeof(u64));
853
854 /* Setup the descriptor */
855 desc.Type = VmbusPacketTypeDataUsingGpaDirect;
856 desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
857 desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
858 desc.Length8 = (u16)(packetLenAligned >> 3);
859 desc.TransactionId = RequestId;
860 desc.RangeCount = PageCount;
861
862 for (i=0; i<PageCount; i++)
863 {
864 desc.Range[i].Length = PageBuffers[i].Length;
865 desc.Range[i].Offset = PageBuffers[i].Offset;
866 desc.Range[i].Pfn = PageBuffers[i].Pfn;
867 }
868
869 bufferList[0].Data = &desc;
870 bufferList[0].Length = descSize;
871
872 bufferList[1].Data = Buffer;
873 bufferList[1].Length = BufferLen;
874
875 bufferList[2].Data = &alignedData;
876 bufferList[2].Length = packetLenAligned - packetLen;
877
878 ret = RingBufferWrite(
879 &Channel->Outbound,
880 bufferList,
881 3);
882
883 /* TODO: We should determine if this is optional */
884 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
885 {
886 VmbusChannelSetEvent(Channel);
887 }
888
889 DPRINT_EXIT(VMBUS);
890
891 return ret;
892 }
893
894
895
896 /*++
897
898 Name:
899 VmbusChannelSendPacketMultiPageBuffer()
900
901 Description:
902 Send a multi-page buffer packet using a GPADL Direct packet type.
903
904 --*/
905 static int
906 VmbusChannelSendPacketMultiPageBuffer(
907 VMBUS_CHANNEL *Channel,
908 MULTIPAGE_BUFFER *MultiPageBuffer,
909 void * Buffer,
910 u32 BufferLen,
911 u64 RequestId
912 )
913 {
914 int ret=0;
915 struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
916 u32 descSize;
917 u32 packetLen;
918 u32 packetLenAligned;
919 SG_BUFFER_LIST bufferList[3];
920 u64 alignedData=0;
921 u32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length);
922
923 DPRINT_ENTER(VMBUS);
924
925 DumpVmbusChannel(Channel);
926
927 DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
928
929 ASSERT(PfnCount > 0);
930 ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT);
931
932 /* Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support */
933 descSize = sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) - ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount)*sizeof(u64));
934 packetLen = descSize + BufferLen;
935 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
936
937 ASSERT((packetLenAligned - packetLen) < sizeof(u64));
938
939 /* Setup the descriptor */
940 desc.Type = VmbusPacketTypeDataUsingGpaDirect;
941 desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
942 desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
943 desc.Length8 = (u16)(packetLenAligned >> 3);
944 desc.TransactionId = RequestId;
945 desc.RangeCount = 1;
946
947 desc.Range.Length = MultiPageBuffer->Length;
948 desc.Range.Offset = MultiPageBuffer->Offset;
949
950 memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(u64));
951
952 bufferList[0].Data = &desc;
953 bufferList[0].Length = descSize;
954
955 bufferList[1].Data = Buffer;
956 bufferList[1].Length = BufferLen;
957
958 bufferList[2].Data = &alignedData;
959 bufferList[2].Length = packetLenAligned - packetLen;
960
961 ret = RingBufferWrite(
962 &Channel->Outbound,
963 bufferList,
964 3);
965
966 /* TODO: We should determine if this is optional */
967 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
968 {
969 VmbusChannelSetEvent(Channel);
970 }
971
972 DPRINT_EXIT(VMBUS);
973
974 return ret;
975 }
976
977
978 /*++
979
980 Name:
981 VmbusChannelRecvPacket()
982
983 Description:
984 Retrieve the user packet on the specified channel
985
986 --*/
987 /* TODO: Do we ever receive a gpa direct packet other than the ones we send ? */
988 static int
989 VmbusChannelRecvPacket(
990 VMBUS_CHANNEL *Channel,
991 void * Buffer,
992 u32 BufferLen,
993 u32* BufferActualLen,
994 u64* RequestId
995 )
996 {
997 VMPACKET_DESCRIPTOR desc;
998 u32 packetLen;
999 u32 userLen;
1000 int ret;
1001 unsigned long flags;
1002
1003 DPRINT_ENTER(VMBUS);
1004
1005 *BufferActualLen = 0;
1006 *RequestId = 0;
1007
1008 spin_lock_irqsave(&Channel->inbound_lock, flags);
1009
1010 ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1011 if (ret != 0)
1012 {
1013 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1014
1015 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
1016 DPRINT_EXIT(VMBUS);
1017 return 0;
1018 }
1019
1020 /* VmbusChannelClearEvent(Channel); */
1021
1022 packetLen = desc.Length8 << 3;
1023 userLen = packetLen - (desc.DataOffset8 << 3);
1024 /* ASSERT(userLen > 0); */
1025
1026 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1027 Channel,
1028 Channel->OfferMsg.ChildRelId,
1029 desc.Type,
1030 desc.Flags,
1031 desc.TransactionId, packetLen, userLen);
1032
1033 *BufferActualLen = userLen;
1034
1035 if (userLen > BufferLen)
1036 {
1037 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1038
1039 DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen);
1040 DPRINT_EXIT(VMBUS);
1041
1042 return -1;
1043 }
1044
1045 *RequestId = desc.TransactionId;
1046
1047 /* Copy over the packet to the user buffer */
1048 ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3));
1049
1050 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1051
1052 DPRINT_EXIT(VMBUS);
1053
1054 return 0;
1055 }
1056
1057 /*++
1058
1059 Name:
1060 VmbusChannelRecvPacketRaw()
1061
1062 Description:
1063 Retrieve the raw packet on the specified channel
1064
1065 --*/
1066 static int
1067 VmbusChannelRecvPacketRaw(
1068 VMBUS_CHANNEL *Channel,
1069 void * Buffer,
1070 u32 BufferLen,
1071 u32* BufferActualLen,
1072 u64* RequestId
1073 )
1074 {
1075 VMPACKET_DESCRIPTOR desc;
1076 u32 packetLen;
1077 u32 userLen;
1078 int ret;
1079 unsigned long flags;
1080
1081 DPRINT_ENTER(VMBUS);
1082
1083 *BufferActualLen = 0;
1084 *RequestId = 0;
1085
1086 spin_lock_irqsave(&Channel->inbound_lock, flags);
1087
1088 ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1089 if (ret != 0)
1090 {
1091 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1092
1093 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
1094 DPRINT_EXIT(VMBUS);
1095 return 0;
1096 }
1097
1098 /* VmbusChannelClearEvent(Channel); */
1099
1100 packetLen = desc.Length8 << 3;
1101 userLen = packetLen - (desc.DataOffset8 << 3);
1102
1103 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1104 Channel,
1105 Channel->OfferMsg.ChildRelId,
1106 desc.Type,
1107 desc.Flags,
1108 desc.TransactionId, packetLen, userLen);
1109
1110 *BufferActualLen = packetLen;
1111
1112 if (packetLen > BufferLen)
1113 {
1114 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1115
1116 DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen);
1117 DPRINT_EXIT(VMBUS);
1118 return -2;
1119 }
1120
1121 *RequestId = desc.TransactionId;
1122
1123 /* Copy over the entire packet to the user buffer */
1124 ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
1125
1126 spin_unlock_irqrestore(&Channel->inbound_lock, flags);
1127
1128 DPRINT_EXIT(VMBUS);
1129
1130 return 0;
1131 }
1132
1133
1134 /*++
1135
1136 Name:
1137 VmbusChannelOnChannelEvent()
1138
1139 Description:
1140 Channel event callback
1141
1142 --*/
1143 static void
1144 VmbusChannelOnChannelEvent(
1145 VMBUS_CHANNEL *Channel
1146 )
1147 {
1148 DumpVmbusChannel(Channel);
1149 ASSERT(Channel->OnChannelCallback);
1150 #ifdef ENABLE_POLLING
1151 TimerStop(Channel->PollTimer);
1152 Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1153 TimerStart(Channel->PollTimer, 100 /* 100us */);
1154 #else
1155 Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1156 #endif
1157 }
1158
1159 /*++
1160
1161 Name:
1162 VmbusChannelOnTimer()
1163
1164 Description:
1165 Timer event callback
1166
1167 --*/
1168 static void
1169 VmbusChannelOnTimer(
1170 void *Context
1171 )
1172 {
1173 VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context;
1174
1175 if (channel->OnChannelCallback)
1176 {
1177 channel->OnChannelCallback(channel->ChannelCallbackContext);
1178 #ifdef ENABLE_POLLING
1179 TimerStart(channel->PollTimer, 100 /* 100us */);
1180 #endif
1181 }
1182 }
1183
1184
1185 /*++
1186
1187 Name:
1188 DumpVmbusChannel()
1189
1190 Description:
1191 Dump vmbus channel info to the console
1192
1193 --*/
1194 static void
1195 DumpVmbusChannel(
1196 VMBUS_CHANNEL *Channel
1197 )
1198 {
1199 DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
1200 DumpRingInfo(&Channel->Outbound, "Outbound ");
1201 DumpRingInfo(&Channel->Inbound, "Inbound ");
1202 }
1203
1204
1205 /* eof */
This page took 0.053795 seconds and 6 git commands to generate.