aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/hv/Channel.c1199
-rw-r--r--drivers/staging/hv/Channel.h157
-rw-r--r--drivers/staging/hv/ChannelInterface.c222
-rw-r--r--drivers/staging/hv/ChannelInterface.h41
-rw-r--r--drivers/staging/hv/ChannelMgmt.c826
-rw-r--r--drivers/staging/hv/ChannelMgmt.h156
-rw-r--r--drivers/staging/hv/Connection.c432
-rw-r--r--drivers/staging/hv/Hv.c672
-rw-r--r--drivers/staging/hv/Hv.h184
-rw-r--r--drivers/staging/hv/RingBuffer.c630
-rw-r--r--drivers/staging/hv/RingBuffer.h123
-rw-r--r--drivers/staging/hv/Sources.c31
-rw-r--r--drivers/staging/hv/VersionInfo.h29
-rw-r--r--drivers/staging/hv/Vmbus.c508
-rw-r--r--drivers/staging/hv/VmbusPrivate.h170
-rw-r--r--drivers/staging/hv/osd.c500
-rw-r--r--drivers/staging/hv/vmbus_drv.c1228
17 files changed, 7108 insertions, 0 deletions
diff --git a/drivers/staging/hv/Channel.c b/drivers/staging/hv/Channel.c
new file mode 100644
index 00000000000..0b78604c40b
--- /dev/null
+++ b/drivers/staging/hv/Channel.c
@@ -0,0 +1,1199 @@
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
25#include "osd.h"
26#include "logging.h"
27
28#include "VmbusPrivate.h"
29
30//
31// Internal routines
32//
33static int
34VmbusChannelCreateGpadlHeader(
35 PVOID Kbuffer, // must be phys and virt contiguous
36 UINT32 Size, // page-size multiple
37 VMBUS_CHANNEL_MSGINFO **msgInfo,
38 UINT32 *MessageCount
39 );
40
41static void
42DumpVmbusChannel(
43 VMBUS_CHANNEL *Channel
44 );
45
46
47static void
48VmbusChannelSetEvent(
49 VMBUS_CHANNEL *Channel
50 );
51
52
53#if 0
54static void
55DumpMonitorPage(
56 HV_MONITOR_PAGE *MonitorPage
57 )
58{
59 int i=0;
60 int j=0;
61
62 DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState);
63
64 for (i=0; i<4; i++)
65 {
66 DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64);
67 }
68
69 for (i=0; i<4; i++)
70 {
71 for (j=0; j<32; j++)
72 {
73 DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]);
74 }
75 }
76 for (i=0; i<4; i++)
77 {
78 for (j=0; j<32; j++)
79 {
80 DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].ConnectionId.AsUINT32);
81 DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].FlagNumber);
82
83 }
84 }
85}
86#endif
87
88/*++
89
90Name:
91 VmbusChannelSetEvent()
92
93Description:
94 Trigger an event notification on the specified channel.
95
96--*/
97static void
98VmbusChannelSetEvent(
99 VMBUS_CHANNEL *Channel
100 )
101{
102 HV_MONITOR_PAGE *monitorPage;
103
104 DPRINT_ENTER(VMBUS);
105
106 if (Channel->OfferMsg.MonitorAllocated)
107 {
108 // Each UINT32 represents 32 channels
109 BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
110
111 monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
112 monitorPage++; // Get the child to parent monitor page
113
114 BitSet((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
115 }
116 else
117 {
118 VmbusSetEvent(Channel->OfferMsg.ChildRelId);
119 }
120
121 DPRINT_EXIT(VMBUS);
122}
123
124#if 0
125static void
126VmbusChannelClearEvent(
127 VMBUS_CHANNEL *Channel
128 )
129{
130 HV_MONITOR_PAGE *monitorPage;
131
132 DPRINT_ENTER(VMBUS);
133
134 if (Channel->OfferMsg.MonitorAllocated)
135 {
136 // Each UINT32 represents 32 channels
137 BitClear((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31);
138
139 monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
140 monitorPage++; // Get the child to parent monitor page
141
142 BitClear((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit);
143 }
144
145 DPRINT_EXIT(VMBUS);
146}
147
148#endif
149/*++;
150
151Name:
152 VmbusChannelGetDebugInfo()
153
154Description:
155 Retrieve various channel debug info
156
157--*/
158void
159VmbusChannelGetDebugInfo(
160 VMBUS_CHANNEL *Channel,
161 VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
162 )
163{
164 HV_MONITOR_PAGE *monitorPage;
165 UINT8 monitorGroup = (UINT8)Channel->OfferMsg.MonitorId / 32;
166 UINT8 monitorOffset = (UINT8)Channel->OfferMsg.MonitorId % 32;
167 //UINT32 monitorBit = 1 << monitorOffset;
168
169 DebugInfo->RelId = Channel->OfferMsg.ChildRelId;
170 DebugInfo->State = Channel->State;
171 memcpy(&DebugInfo->InterfaceType, &Channel->OfferMsg.Offer.InterfaceType, sizeof(GUID));
172 memcpy(&DebugInfo->InterfaceInstance, &Channel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID));
173
174 monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages;
175
176 DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
177
178 DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
179 DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
180 DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
181
182 monitorPage++;
183
184 DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending;
185 DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset];
186 DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id;
187
188 RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
189 RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
190}
191
192
193/*++;
194
195Name:
196 VmbusChannelOpen()
197
198Description:
199 Open the specified channel.
200
201--*/
202int
203VmbusChannelOpen(
204 VMBUS_CHANNEL *NewChannel,
205 UINT32 SendRingBufferSize,
206 UINT32 RecvRingBufferSize,
207 PVOID UserData,
208 UINT32 UserDataLen,
209 PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
210 PVOID Context
211 )
212{
213 int ret=0;
214 VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
215 VMBUS_CHANNEL_MSGINFO* openInfo;
216 void *in, *out;
217
218 DPRINT_ENTER(VMBUS);
219
220 // Aligned to page size
221 ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1)));
222 ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1)));
223
224 NewChannel->OnChannelCallback = pfnOnChannelCallback;
225 NewChannel->ChannelCallbackContext = Context;
226
227 // Allocate the ring buffer
228 out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT);
229 //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize);
230 ASSERT(out);
231 ASSERT(((ULONG_PTR)out & (PAGE_SIZE-1)) == 0);
232
233 in = (void*)((ULONG_PTR)out + SendRingBufferSize);
234
235 NewChannel->RingBufferPages = out;
236 NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT;
237
238 RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
239
240 RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
241
242 // Establish the gpadl for the ring buffer
243 DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel);
244
245 NewChannel->RingBufferGpadlHandle = 0;
246
247 ret = VmbusChannelEstablishGpadl(NewChannel,
248 NewChannel->Outbound.RingBuffer,
249 SendRingBufferSize + RecvRingBufferSize,
250 &NewChannel->RingBufferGpadlHandle);
251
252 DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>",
253 NewChannel,
254 NewChannel->OfferMsg.ChildRelId,
255 NewChannel->RingBufferGpadlHandle,
256 NewChannel->Outbound.RingBuffer,
257 NewChannel->Outbound.RingSize,
258 NewChannel->Inbound.RingBuffer,
259 NewChannel->Inbound.RingSize,
260 SendRingBufferSize);
261
262 // Create and init the channel open message
263 openInfo =
264 (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
265 ASSERT(openInfo != NULL);
266
267 openInfo->WaitEvent = WaitEventCreate();
268
269 openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)openInfo->Msg;
270 openMsg->Header.MessageType = ChannelMessageOpenChannel;
271 openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; // FIXME
272 openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId;
273 openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle;
274 ASSERT(openMsg->RingBufferGpadlHandle);
275 openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >> PAGE_SHIFT;
276 openMsg->ServerContextAreaGpadlHandle = 0; // TODO
277
278 ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES);
279 if (UserDataLen)
280 {
281 memcpy(openMsg->UserData, UserData, UserDataLen);
282 }
283
284 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
285 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry);
286 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
287
288 DPRINT_DBG(VMBUS, "Sending channel open msg...");
289
290 ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL));
291 if (ret != 0)
292 {
293 DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
294 goto Cleanup;
295 }
296
297 // FIXME: Need to time-out here
298 WaitEventWait(openInfo->WaitEvent);
299
300 if (openInfo->Response.OpenResult.Status == 0)
301 {
302 DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
303 }
304 else
305 {
306 DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status);
307 }
308
309Cleanup:
310 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
311 REMOVE_ENTRY_LIST(&openInfo->MsgListEntry);
312 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
313
314 WaitEventClose(openInfo->WaitEvent);
315 MemFree(openInfo);
316
317 DPRINT_EXIT(VMBUS);
318
319 return 0;
320}
321
322/*++;
323
324Name:
325 DumpGpadlBody()
326
327Description:
328 Dump the gpadl body message to the console for debugging purposes.
329
330--*/
331static void DumpGpadlBody(
332 VMBUS_CHANNEL_GPADL_BODY *Gpadl,
333 UINT32 Len)
334{
335 int i=0;
336 int pfnCount=0;
337
338 pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(UINT64);
339 DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
340
341 for (i=0; i< pfnCount; i++)
342 {
343 DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]);
344 }
345}
346
347
348/*++;
349
350Name:
351 DumpGpadlHeader()
352
353Description:
354 Dump the gpadl header message to the console for debugging purposes.
355
356--*/
357static void DumpGpadlHeader(
358 VMBUS_CHANNEL_GPADL_HEADER *Gpadl
359 )
360{
361 int i=0,j=0;
362 int pageCount=0;
363
364
365 DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d",
366 Gpadl->ChildRelId,
367 Gpadl->RangeCount,
368 Gpadl->RangeBufLen);
369 for (i=0; i< Gpadl->RangeCount; i++)
370 {
371 pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
372 pageCount = (pageCount > 26)? 26 : pageCount;
373
374 DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d page count %d",
375 i, Gpadl->Range[i].ByteCount, Gpadl->Range[i].ByteOffset, pageCount);
376
377 for (j=0; j< pageCount; j++)
378 {
379 DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]);
380 }
381 }
382}
383
384/*++;
385
386Name:
387 VmbusChannelCreateGpadlHeader()
388
389Description:
390 Creates a gpadl for the specified buffer
391
392--*/
393static int
394VmbusChannelCreateGpadlHeader(
395 PVOID Kbuffer, // from kmalloc()
396 UINT32 Size, // page-size multiple
397 VMBUS_CHANNEL_MSGINFO **MsgInfo,
398 UINT32 *MessageCount)
399{
400 int i;
401 int pageCount;
402 unsigned long long pfn;
403 VMBUS_CHANNEL_GPADL_HEADER* gpaHeader;
404 VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
405 VMBUS_CHANNEL_MSGINFO* msgHeader;
406 VMBUS_CHANNEL_MSGINFO* msgBody;
407 UINT32 msgSize;
408
409 int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
410
411 //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0);
412 ASSERT( (Size & (PAGE_SIZE-1)) == 0);
413
414 pageCount = Size >> PAGE_SHIFT;
415 pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT;
416
417 // do we need a gpadl body msg
418 pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_HEADER) - sizeof(GPA_RANGE);
419 pfnCount = pfnSize / sizeof(UINT64);
420
421 if (pageCount > pfnCount) // we need a gpadl body
422 {
423 // fill in the header
424 msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pfnCount*sizeof(UINT64);
425 msgHeader = MemAllocZeroed(msgSize);
426
427 INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList);
428 msgHeader->MessageSize=msgSize;
429
430 gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg;
431 gpaHeader->RangeCount = 1;
432 gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64);
433 gpaHeader->Range[0].ByteOffset = 0;
434 gpaHeader->Range[0].ByteCount = Size;
435 for (i=0; i<pfnCount; i++)
436 {
437 gpaHeader->Range[0].PfnArray[i] = pfn+i;
438 }
439 *MsgInfo = msgHeader;
440 *MessageCount = 1;
441
442 pfnSum = pfnCount;
443 pfnLeft = pageCount - pfnCount;
444
445 // how many pfns can we fit
446 pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY);
447 pfnCount = pfnSize / sizeof(UINT64);
448
449 // fill in the body
450 while (pfnLeft)
451 {
452 if (pfnLeft > pfnCount)
453 {
454 pfnCurr = pfnCount;
455 }
456 else
457 {
458 pfnCurr = pfnLeft;
459 }
460
461 msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(UINT64);
462 msgBody = MemAllocZeroed(msgSize);
463 ASSERT(msgBody);
464 msgBody->MessageSize = msgSize;
465 (*MessageCount)++;
466 gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg;
467
468 // FIXME: Gpadl is UINT32 and we are using a pointer which could be 64-bit
469 //gpadlBody->Gpadl = kbuffer;
470 for (i=0; i<pfnCurr; i++)
471 {
472 gpadlBody->Pfn[i] = pfn + pfnSum + i;
473 }
474
475 // add to msg header
476 INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry);
477 pfnSum += pfnCurr;
478 pfnLeft -= pfnCurr;
479 }
480 }
481 else
482 {
483 // everything fits in a header
484 msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pageCount*sizeof(UINT64);
485 msgHeader = MemAllocZeroed(msgSize);
486 msgHeader->MessageSize=msgSize;
487
488 gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg;
489 gpaHeader->RangeCount = 1;
490 gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64);
491 gpaHeader->Range[0].ByteOffset = 0;
492 gpaHeader->Range[0].ByteCount = Size;
493 for (i=0; i<pageCount; i++)
494 {
495 gpaHeader->Range[0].PfnArray[i] = pfn+i;
496 }
497
498 *MsgInfo = msgHeader;
499 *MessageCount = 1;
500 }
501
502 return 0;
503}
504
505
506/*++;
507
508Name:
509 VmbusChannelEstablishGpadl()
510
511Description:
512 Estabish a GPADL for the specified buffer
513
514--*/
515int
516VmbusChannelEstablishGpadl(
517 VMBUS_CHANNEL *Channel,
518 PVOID Kbuffer, // from kmalloc()
519 UINT32 Size, // page-size multiple
520 UINT32 *GpadlHandle
521 )
522{
523 int ret=0;
524 VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg;
525 VMBUS_CHANNEL_GPADL_BODY* gpadlBody;
526 //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated;
527
528 VMBUS_CHANNEL_MSGINFO *msgInfo;
529 VMBUS_CHANNEL_MSGINFO *subMsgInfo;
530
531 UINT32 msgCount;
532 LIST_ENTRY* anchor;
533 LIST_ENTRY* curr;
534 UINT32 nextGpadlHandle;
535
536 DPRINT_ENTER(VMBUS);
537
538 nextGpadlHandle = gVmbusConnection.NextGpadlHandle;
539 InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle);
540
541 VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
542 ASSERT(msgInfo != NULL);
543 ASSERT(msgCount >0);
544
545 msgInfo->WaitEvent = WaitEventCreate();
546 gpadlMsg = (VMBUS_CHANNEL_GPADL_HEADER*)msgInfo->Msg;
547 gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader;
548 gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId;
549 gpadlMsg->Gpadl = nextGpadlHandle;
550
551 DumpGpadlHeader(gpadlMsg);
552
553 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
554 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
555 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
556
557 DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount);
558
559 DPRINT_DBG(VMBUS, "Sending GPADL Header - len %d", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
560
561 ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
562 if (ret != 0)
563 {
564 DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
565 goto Cleanup;
566 }
567
568 if (msgCount>1)
569 {
570 ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList)
571 {
572 subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
573 gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg;
574
575 gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
576 gpadlBody->Gpadl = nextGpadlHandle;
577
578 DPRINT_DBG(VMBUS, "Sending GPADL Body - len %d", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
579
580 DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
581 ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO));
582 ASSERT(ret == 0);
583 }
584 }
585 WaitEventWait(msgInfo->WaitEvent);
586
587 // At this point, we received the gpadl created msg
588 DPRINT_DBG(VMBUS, "Received GPADL created (relid %d, status %d handle %x)",
589 Channel->OfferMsg.ChildRelId,
590 msgInfo->Response.GpadlCreated.CreationStatus,
591 gpadlMsg->Gpadl);
592
593 *GpadlHandle = gpadlMsg->Gpadl;
594
595Cleanup:
596 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
597 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
598 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
599
600 WaitEventClose(msgInfo->WaitEvent);
601 MemFree(msgInfo);
602
603 DPRINT_EXIT(VMBUS);
604
605 return ret;
606}
607
608
609
610/*++;
611
612Name:
613 VmbusChannelTeardownGpadl()
614
615Description:
616 Teardown the specified GPADL handle
617
618--*/
619int
620VmbusChannelTeardownGpadl(
621 VMBUS_CHANNEL *Channel,
622 UINT32 GpadlHandle
623 )
624{
625 int ret=0;
626 VMBUS_CHANNEL_GPADL_TEARDOWN *msg;
627 VMBUS_CHANNEL_MSGINFO* info;
628
629 DPRINT_ENTER(VMBUS);
630
631 ASSERT(GpadlHandle != 0);
632
633 info =
634 (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
635 ASSERT(info != NULL);
636
637 info->WaitEvent = WaitEventCreate();
638
639 msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg;
640
641 msg->Header.MessageType = ChannelMessageGpadlTeardown;
642 msg->ChildRelId = Channel->OfferMsg.ChildRelId;
643 msg->Gpadl = GpadlHandle;
644
645 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
646 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry);
647 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
648
649 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN));
650 if (ret != 0)
651 {
652 // TODO:
653 }
654
655 WaitEventWait(info->WaitEvent);
656
657 // Received a torndown response
658 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
659 REMOVE_ENTRY_LIST(&info->MsgListEntry);
660 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
661
662 WaitEventClose(info->WaitEvent);
663 MemFree(info);
664
665 DPRINT_EXIT(VMBUS);
666
667 return ret;
668}
669
670
671/*++
672
673Name:
674 VmbusChannelClose()
675
676Description:
677 Close the specified channel
678
679--*/
680VOID
681VmbusChannelClose(
682 VMBUS_CHANNEL *Channel
683 )
684{
685 int ret=0;
686 VMBUS_CHANNEL_CLOSE_CHANNEL* msg;
687 VMBUS_CHANNEL_MSGINFO* info;
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 =
697 (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
698 ASSERT(info != NULL);
699
700 //info->waitEvent = WaitEventCreate();
701
702 msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg;
703 msg->Header.MessageType = ChannelMessageCloseChannel;
704 msg->ChildRelId = Channel->OfferMsg.ChildRelId;
705
706 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL));
707 if (ret != 0)
708 {
709 // TODO:
710 }
711
712 // Tear down the gpadl for the channel's ring buffer
713 if (Channel->RingBufferGpadlHandle)
714 {
715 VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle);
716 }
717
718 // TODO: Send a msg to release the childRelId
719
720 // Cleanup the ring buffers for this channel
721 RingBufferCleanup(&Channel->Outbound);
722 RingBufferCleanup(&Channel->Inbound);
723
724 PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
725
726 MemFree(info);
727
728 // If we are closing the channel during an error path in opening the channel, don't free the channel
729 // since the caller will free the channel
730 if (Channel->State == CHANNEL_OPEN_STATE)
731 {
732 SpinlockAcquire(gVmbusConnection.ChannelLock);
733 REMOVE_ENTRY_LIST(&Channel->ListEntry);
734 SpinlockRelease(gVmbusConnection.ChannelLock);
735
736 FreeVmbusChannel(Channel);
737 }
738
739 DPRINT_EXIT(VMBUS);
740}
741
742
743/*++
744
745Name:
746 VmbusChannelSendPacket()
747
748Description:
749 Send the specified buffer on the given channel
750
751--*/
752int
753VmbusChannelSendPacket(
754 VMBUS_CHANNEL *Channel,
755 const PVOID Buffer,
756 UINT32 BufferLen,
757 UINT64 RequestId,
758 VMBUS_PACKET_TYPE Type,
759 UINT32 Flags
760)
761{
762 int ret=0;
763 VMPACKET_DESCRIPTOR desc;
764 UINT32 packetLen = sizeof(VMPACKET_DESCRIPTOR) + BufferLen;
765 UINT32 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64));
766 SG_BUFFER_LIST bufferList[3];
767 UINT64 alignedData=0;
768
769 DPRINT_ENTER(VMBUS);
770 DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen);
771
772 DumpVmbusChannel(Channel);
773
774 ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
775
776 // Setup the descriptor
777 desc.Type = Type;//VmbusPacketTypeDataInBand;
778 desc.Flags = Flags;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
779 desc.DataOffset8 = sizeof(VMPACKET_DESCRIPTOR) >> 3; // in 8-bytes granularity
780 desc.Length8 = (UINT16)(packetLenAligned >> 3);
781 desc.TransactionId = RequestId;
782
783 bufferList[0].Data = &desc;
784 bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR);
785
786 bufferList[1].Data = Buffer;
787 bufferList[1].Length = BufferLen;
788
789 bufferList[2].Data = &alignedData;
790 bufferList[2].Length = packetLenAligned - packetLen;
791
792 ret = RingBufferWrite(
793 &Channel->Outbound,
794 bufferList,
795 3);
796
797 // TODO: We should determine if this is optional
798 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
799 {
800 VmbusChannelSetEvent(Channel);
801 }
802
803 DPRINT_EXIT(VMBUS);
804
805 return ret;
806}
807
808
809/*++
810
811Name:
812 VmbusChannelSendPacketPageBuffer()
813
814Description:
815 Send a range of single-page buffer packets using a GPADL Direct packet type.
816
817--*/
818int
819VmbusChannelSendPacketPageBuffer(
820 VMBUS_CHANNEL *Channel,
821 PAGE_BUFFER PageBuffers[],
822 UINT32 PageCount,
823 PVOID Buffer,
824 UINT32 BufferLen,
825 UINT64 RequestId
826)
827{
828 int ret=0;
829 int i=0;
830 VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
831 UINT32 descSize;
832 UINT32 packetLen;
833 UINT32 packetLenAligned;
834 SG_BUFFER_LIST bufferList[3];
835 UINT64 alignedData=0;
836
837 DPRINT_ENTER(VMBUS);
838
839 ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT);
840
841 DumpVmbusChannel(Channel);
842
843 // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support
844 descSize = sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER) - ((MAX_PAGE_BUFFER_COUNT - PageCount)*sizeof(PAGE_BUFFER));
845 packetLen = descSize + BufferLen;
846 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64));
847
848 ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
849
850 // Setup the descriptor
851 desc.Type = VmbusPacketTypeDataUsingGpaDirect;
852 desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
853 desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity
854 desc.Length8 = (UINT16)(packetLenAligned >> 3);
855 desc.TransactionId = RequestId;
856 desc.RangeCount = PageCount;
857
858 for (i=0; i<PageCount; i++)
859 {
860 desc.Range[i].Length = PageBuffers[i].Length;
861 desc.Range[i].Offset = PageBuffers[i].Offset;
862 desc.Range[i].Pfn = PageBuffers[i].Pfn;
863 }
864
865 bufferList[0].Data = &desc;
866 bufferList[0].Length = descSize;
867
868 bufferList[1].Data = Buffer;
869 bufferList[1].Length = BufferLen;
870
871 bufferList[2].Data = &alignedData;
872 bufferList[2].Length = packetLenAligned - packetLen;
873
874 ret = RingBufferWrite(
875 &Channel->Outbound,
876 bufferList,
877 3);
878
879 // TODO: We should determine if this is optional
880 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
881 {
882 VmbusChannelSetEvent(Channel);
883 }
884
885 DPRINT_EXIT(VMBUS);
886
887 return ret;
888}
889
890
891
892/*++
893
894Name:
895 VmbusChannelSendPacketMultiPageBuffer()
896
897Description:
898 Send a multi-page buffer packet using a GPADL Direct packet type.
899
900--*/
901int
902VmbusChannelSendPacketMultiPageBuffer(
903 VMBUS_CHANNEL *Channel,
904 MULTIPAGE_BUFFER *MultiPageBuffer,
905 PVOID Buffer,
906 UINT32 BufferLen,
907 UINT64 RequestId
908)
909{
910 int ret=0;
911 VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
912 UINT32 descSize;
913 UINT32 packetLen;
914 UINT32 packetLenAligned;
915 SG_BUFFER_LIST bufferList[3];
916 UINT64 alignedData=0;
917 UINT32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length);
918
919 DPRINT_ENTER(VMBUS);
920
921 DumpVmbusChannel(Channel);
922
923 DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
924
925 ASSERT(PfnCount > 0);
926 ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT);
927
928 // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support
929 descSize = sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) - ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount)*sizeof(UINT64));
930 packetLen = descSize + BufferLen;
931 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64));
932
933 ASSERT((packetLenAligned - packetLen) < sizeof(UINT64));
934
935 // Setup the descriptor
936 desc.Type = VmbusPacketTypeDataUsingGpaDirect;
937 desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
938 desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity
939 desc.Length8 = (UINT16)(packetLenAligned >> 3);
940 desc.TransactionId = RequestId;
941 desc.RangeCount = 1;
942
943 desc.Range.Length = MultiPageBuffer->Length;
944 desc.Range.Offset = MultiPageBuffer->Offset;
945
946 memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(UINT64));
947
948 bufferList[0].Data = &desc;
949 bufferList[0].Length = descSize;
950
951 bufferList[1].Data = Buffer;
952 bufferList[1].Length = BufferLen;
953
954 bufferList[2].Data = &alignedData;
955 bufferList[2].Length = packetLenAligned - packetLen;
956
957 ret = RingBufferWrite(
958 &Channel->Outbound,
959 bufferList,
960 3);
961
962 // TODO: We should determine if this is optional
963 if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
964 {
965 VmbusChannelSetEvent(Channel);
966 }
967
968 DPRINT_EXIT(VMBUS);
969
970 return ret;
971}
972
973
974/*++
975
976Name:
977 VmbusChannelRecvPacket()
978
979Description:
980 Retrieve the user packet on the specified channel
981
982--*/
983// TODO: Do we ever receive a gpa direct packet other than the ones we send ?
984int
985VmbusChannelRecvPacket(
986 VMBUS_CHANNEL *Channel,
987 PVOID Buffer,
988 UINT32 BufferLen,
989 UINT32* BufferActualLen,
990 UINT64* RequestId
991 )
992{
993 VMPACKET_DESCRIPTOR desc;
994 UINT32 packetLen;
995 UINT32 userLen;
996 int ret;
997
998 DPRINT_ENTER(VMBUS);
999
1000 *BufferActualLen = 0;
1001 *RequestId = 0;
1002
1003 SpinlockAcquire(Channel->InboundLock);
1004
1005 ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1006 if (ret != 0)
1007 {
1008 SpinlockRelease(Channel->InboundLock);
1009
1010 //DPRINT_DBG(VMBUS, "nothing to read!!");
1011 DPRINT_EXIT(VMBUS);
1012 return 0;
1013 }
1014
1015 //VmbusChannelClearEvent(Channel);
1016
1017 packetLen = desc.Length8 << 3;
1018 userLen = packetLen - (desc.DataOffset8 << 3);
1019 //ASSERT(userLen > 0);
1020
1021 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1022 Channel,
1023 Channel->OfferMsg.ChildRelId,
1024 desc.Type,
1025 desc.Flags,
1026 desc.TransactionId, packetLen, userLen);
1027
1028 *BufferActualLen = userLen;
1029
1030 if (userLen > BufferLen)
1031 {
1032 SpinlockRelease(Channel->InboundLock);
1033
1034 DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen);
1035 DPRINT_EXIT(VMBUS);
1036
1037 return -1;
1038 }
1039
1040 *RequestId = desc.TransactionId;
1041
1042 // Copy over the packet to the user buffer
1043 ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3));
1044
1045 SpinlockRelease(Channel->InboundLock);
1046
1047 DPRINT_EXIT(VMBUS);
1048
1049 return 0;
1050}
1051
1052/*++
1053
1054Name:
1055 VmbusChannelRecvPacketRaw()
1056
1057Description:
1058 Retrieve the raw packet on the specified channel
1059
1060--*/
1061int
1062VmbusChannelRecvPacketRaw(
1063 VMBUS_CHANNEL *Channel,
1064 PVOID Buffer,
1065 UINT32 BufferLen,
1066 UINT32* BufferActualLen,
1067 UINT64* RequestId
1068 )
1069{
1070 VMPACKET_DESCRIPTOR desc;
1071 UINT32 packetLen;
1072 UINT32 userLen;
1073 int ret;
1074
1075 DPRINT_ENTER(VMBUS);
1076
1077 *BufferActualLen = 0;
1078 *RequestId = 0;
1079
1080 SpinlockAcquire(Channel->InboundLock);
1081
1082 ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR));
1083 if (ret != 0)
1084 {
1085 SpinlockRelease(Channel->InboundLock);
1086
1087 //DPRINT_DBG(VMBUS, "nothing to read!!");
1088 DPRINT_EXIT(VMBUS);
1089 return 0;
1090 }
1091
1092 //VmbusChannelClearEvent(Channel);
1093
1094 packetLen = desc.Length8 << 3;
1095 userLen = packetLen - (desc.DataOffset8 << 3);
1096
1097 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ",
1098 Channel,
1099 Channel->OfferMsg.ChildRelId,
1100 desc.Type,
1101 desc.Flags,
1102 desc.TransactionId, packetLen, userLen);
1103
1104 *BufferActualLen = packetLen;
1105
1106 if (packetLen > BufferLen)
1107 {
1108 SpinlockRelease(Channel->InboundLock);
1109
1110 DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen);
1111 DPRINT_EXIT(VMBUS);
1112 return -2;
1113 }
1114
1115 *RequestId = desc.TransactionId;
1116
1117 // Copy over the entire packet to the user buffer
1118 ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
1119
1120 SpinlockRelease(Channel->InboundLock);
1121
1122 DPRINT_EXIT(VMBUS);
1123
1124 return 0;
1125}
1126
1127
1128/*++
1129
1130Name:
1131 VmbusChannelOnChannelEvent()
1132
1133Description:
1134 Channel event callback
1135
1136--*/
1137void
1138VmbusChannelOnChannelEvent(
1139 VMBUS_CHANNEL *Channel
1140 )
1141{
1142 DumpVmbusChannel(Channel);
1143 ASSERT(Channel->OnChannelCallback);
1144#ifdef ENABLE_POLLING
1145 TimerStop(Channel->PollTimer);
1146 Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1147 TimerStart(Channel->PollTimer, 100 /* 100us */);
1148#else
1149 Channel->OnChannelCallback(Channel->ChannelCallbackContext);
1150#endif
1151}
1152
1153/*++
1154
1155Name:
1156 VmbusChannelOnTimer()
1157
1158Description:
1159 Timer event callback
1160
1161--*/
1162void
1163VmbusChannelOnTimer(
1164 void *Context
1165 )
1166{
1167 VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context;
1168
1169 if (channel->OnChannelCallback)
1170 {
1171 channel->OnChannelCallback(channel->ChannelCallbackContext);
1172#ifdef ENABLE_POLLING
1173 TimerStart(channel->PollTimer, 100 /* 100us */);
1174#endif
1175 }
1176}
1177
1178
1179/*++
1180
1181Name:
1182 DumpVmbusChannel()
1183
1184Description:
1185 Dump vmbus channel info to the console
1186
1187--*/
1188static void
1189DumpVmbusChannel(
1190 VMBUS_CHANNEL *Channel
1191 )
1192{
1193 DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
1194 DumpRingInfo(&Channel->Outbound, "Outbound ");
1195 DumpRingInfo(&Channel->Inbound, "Inbound ");
1196}
1197
1198
1199// eof
diff --git a/drivers/staging/hv/Channel.h b/drivers/staging/hv/Channel.h
new file mode 100644
index 00000000000..117b2e1bb7c
--- /dev/null
+++ b/drivers/staging/hv/Channel.h
@@ -0,0 +1,157 @@
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
25#ifndef _CHANNEL_H_
26#define _CHANNEL_H_
27
28#include "osd.h"
29#include "ChannelMgmt.h"
30
31#pragma pack(push,1)
32
33
34// The format must be the same as VMDATA_GPA_DIRECT
35typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
36 UINT16 Type;
37 UINT16 DataOffset8;
38 UINT16 Length8;
39 UINT16 Flags;
40 UINT64 TransactionId;
41 UINT32 Reserved;
42 UINT32 RangeCount;
43 PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT];
44} VMBUS_CHANNEL_PACKET_PAGE_BUFFER;
45
46
47// The format must be the same as VMDATA_GPA_DIRECT
48typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER {
49 UINT16 Type;
50 UINT16 DataOffset8;
51 UINT16 Length8;
52 UINT16 Flags;
53 UINT64 TransactionId;
54 UINT32 Reserved;
55 UINT32 RangeCount; // Always 1 in this case
56 MULTIPAGE_BUFFER Range;
57} VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER;
58
59#pragma pack(pop)
60
61//
62// Routines
63//
64
65INTERNAL int
66VmbusChannelOpen(
67 VMBUS_CHANNEL *Channel,
68 UINT32 SendRingBufferSize,
69 UINT32 RecvRingBufferSize,
70 PVOID UserData,
71 UINT32 UserDataLen,
72 PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
73 PVOID Context
74 );
75
76INTERNAL void
77VmbusChannelClose(
78 VMBUS_CHANNEL *Channel
79 );
80
81INTERNAL int
82VmbusChannelSendPacket(
83 VMBUS_CHANNEL *Channel,
84 const PVOID Buffer,
85 UINT32 BufferLen,
86 UINT64 RequestId,
87 VMBUS_PACKET_TYPE Type,
88 UINT32 Flags
89);
90
91INTERNAL int
92VmbusChannelSendPacketPageBuffer(
93 VMBUS_CHANNEL *Channel,
94 PAGE_BUFFER PageBuffers[],
95 UINT32 PageCount,
96 PVOID Buffer,
97 UINT32 BufferLen,
98 UINT64 RequestId
99 );
100
101INTERNAL int
102VmbusChannelSendPacketMultiPageBuffer(
103 VMBUS_CHANNEL *Channel,
104 MULTIPAGE_BUFFER *MultiPageBuffer,
105 PVOID Buffer,
106 UINT32 BufferLen,
107 UINT64 RequestId
108);
109
110INTERNAL int
111VmbusChannelEstablishGpadl(
112 VMBUS_CHANNEL *Channel,
113 PVOID Kbuffer, // from kmalloc()
114 UINT32 Size, // page-size multiple
115 UINT32 *GpadlHandle
116 );
117
118INTERNAL int
119VmbusChannelTeardownGpadl(
120 VMBUS_CHANNEL *Channel,
121 UINT32 GpadlHandle
122 );
123
124INTERNAL int
125VmbusChannelRecvPacket(
126 VMBUS_CHANNEL *Channel,
127 PVOID Buffer,
128 UINT32 BufferLen,
129 UINT32* BufferActualLen,
130 UINT64* RequestId
131 );
132
133INTERNAL int
134VmbusChannelRecvPacketRaw(
135 VMBUS_CHANNEL *Channel,
136 PVOID Buffer,
137 UINT32 BufferLen,
138 UINT32* BufferActualLen,
139 UINT64* RequestId
140 );
141
142INTERNAL void
143VmbusChannelOnChannelEvent(
144 VMBUS_CHANNEL *Channel
145 );
146
147INTERNAL void
148VmbusChannelGetDebugInfo(
149 VMBUS_CHANNEL *Channel,
150 VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
151 );
152
153INTERNAL void
154VmbusChannelOnTimer(
155 void *Context
156 );
157#endif //_CHANNEL_H_
diff --git a/drivers/staging/hv/ChannelInterface.c b/drivers/staging/hv/ChannelInterface.c
new file mode 100644
index 00000000000..1a7663e37e5
--- /dev/null
+++ b/drivers/staging/hv/ChannelInterface.c
@@ -0,0 +1,222 @@
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 "VmbusPrivate.h"
25
26INTERNAL int
27IVmbusChannelOpen(
28 PDEVICE_OBJECT Device,
29 UINT32 SendBufferSize,
30 UINT32 RecvRingBufferSize,
31 PVOID UserData,
32 UINT32 UserDataLen,
33 VMBUS_CHANNEL_CALLBACK ChannelCallback,
34 PVOID Context
35 )
36{
37 return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context,
38 SendBufferSize,
39 RecvRingBufferSize,
40 UserData,
41 UserDataLen,
42 ChannelCallback,
43 Context);
44}
45
46
47INTERNAL void
48IVmbusChannelClose(
49 PDEVICE_OBJECT Device
50 )
51{
52 VmbusChannelClose((VMBUS_CHANNEL*)Device->context);
53}
54
55
56INTERNAL int
57IVmbusChannelSendPacket(
58 PDEVICE_OBJECT Device,
59 const PVOID Buffer,
60 UINT32 BufferLen,
61 UINT64 RequestId,
62 UINT32 Type,
63 UINT32 Flags
64 )
65{
66 return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context,
67 Buffer,
68 BufferLen,
69 RequestId,
70 Type,
71 Flags);
72}
73
74INTERNAL int
75IVmbusChannelSendPacketPageBuffer(
76 PDEVICE_OBJECT Device,
77 PAGE_BUFFER PageBuffers[],
78 UINT32 PageCount,
79 PVOID Buffer,
80 UINT32 BufferLen,
81 UINT64 RequestId
82 )
83{
84 return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context,
85 PageBuffers,
86 PageCount,
87 Buffer,
88 BufferLen,
89 RequestId);
90}
91
92INTERNAL int
93IVmbusChannelSendPacketMultiPageBuffer(
94 PDEVICE_OBJECT Device,
95 MULTIPAGE_BUFFER *MultiPageBuffer,
96 PVOID Buffer,
97 UINT32 BufferLen,
98 UINT64 RequestId
99 )
100{
101 return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context,
102 MultiPageBuffer,
103 Buffer,
104 BufferLen,
105 RequestId);
106}
107
108INTERNAL int
109IVmbusChannelRecvPacket (
110 PDEVICE_OBJECT Device,
111 PVOID Buffer,
112 UINT32 BufferLen,
113 UINT32* BufferActualLen,
114 UINT64* RequestId
115 )
116{
117 return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context,
118 Buffer,
119 BufferLen,
120 BufferActualLen,
121 RequestId);
122}
123
124INTERNAL int
125IVmbusChannelRecvPacketRaw(
126 PDEVICE_OBJECT Device,
127 PVOID Buffer,
128 UINT32 BufferLen,
129 UINT32* BufferActualLen,
130 UINT64* RequestId
131 )
132{
133 return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context,
134 Buffer,
135 BufferLen,
136 BufferActualLen,
137 RequestId);
138}
139
140INTERNAL int
141IVmbusChannelEstablishGpadl(
142 PDEVICE_OBJECT Device,
143 PVOID Buffer,
144 UINT32 BufferLen,
145 UINT32* GpadlHandle
146 )
147{
148 return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context,
149 Buffer,
150 BufferLen,
151 GpadlHandle);
152}
153
154INTERNAL int
155IVmbusChannelTeardownGpadl(
156 PDEVICE_OBJECT Device,
157 UINT32 GpadlHandle
158 )
159{
160 return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context,
161 GpadlHandle);
162
163}
164
165INTERNAL void
166GetChannelInterface(
167 VMBUS_CHANNEL_INTERFACE *ChannelInterface
168 )
169{
170 ChannelInterface->Open = IVmbusChannelOpen;
171 ChannelInterface->Close = IVmbusChannelClose;
172 ChannelInterface->SendPacket = IVmbusChannelSendPacket;
173 ChannelInterface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer;
174 ChannelInterface->SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer;
175 ChannelInterface->RecvPacket = IVmbusChannelRecvPacket;
176 ChannelInterface->RecvPacketRaw = IVmbusChannelRecvPacketRaw;
177 ChannelInterface->EstablishGpadl = IVmbusChannelEstablishGpadl;
178 ChannelInterface->TeardownGpadl = IVmbusChannelTeardownGpadl;
179 ChannelInterface->GetInfo = GetChannelInfo;
180}
181
182
183INTERNAL void
184GetChannelInfo(
185 PDEVICE_OBJECT Device,
186 DEVICE_INFO *DeviceInfo
187 )
188{
189 VMBUS_CHANNEL_DEBUG_INFO debugInfo;
190
191 if (Device->context)
192 {
193 VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo);
194
195 DeviceInfo->ChannelId = debugInfo.RelId;
196 DeviceInfo->ChannelState = debugInfo.State;
197 memcpy(&DeviceInfo->ChannelType, &debugInfo.InterfaceType, sizeof(GUID));
198 memcpy(&DeviceInfo->ChannelInstance, &debugInfo.InterfaceInstance, sizeof(GUID));
199
200 DeviceInfo->MonitorId = debugInfo.MonitorId;
201
202 DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending;
203 DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
204 DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
205
206 DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending;
207 DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
208 DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
209
210 DeviceInfo->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask;
211 DeviceInfo->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex;
212 DeviceInfo->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex;
213 DeviceInfo->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead;
214 DeviceInfo->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite;
215
216 DeviceInfo->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask;
217 DeviceInfo->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex;
218 DeviceInfo->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex;
219 DeviceInfo->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead;
220 DeviceInfo->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite;
221 }
222}
diff --git a/drivers/staging/hv/ChannelInterface.h b/drivers/staging/hv/ChannelInterface.h
new file mode 100644
index 00000000000..8f5a4a99269
--- /dev/null
+++ b/drivers/staging/hv/ChannelInterface.h
@@ -0,0 +1,41 @@
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
25#ifndef _CHANNEL_INTERFACE_H_
26#define _CHANNEL_INTERFACE_H_
27
28#include "VmbusApi.h"
29
30INTERNAL void
31GetChannelInterface(
32 VMBUS_CHANNEL_INTERFACE *ChannelInterface
33 );
34
35INTERNAL void
36GetChannelInfo(
37 PDEVICE_OBJECT Device,
38 DEVICE_INFO *DeviceInfo
39 );
40
41#endif // _CHANNEL_INTERFACE_H_
diff --git a/drivers/staging/hv/ChannelMgmt.c b/drivers/staging/hv/ChannelMgmt.c
new file mode 100644
index 00000000000..c058d53321c
--- /dev/null
+++ b/drivers/staging/hv/ChannelMgmt.c
@@ -0,0 +1,826 @@
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
25#include "osd.h"
26#include "logging.h"
27
28#include "VmbusPrivate.h"
29
30//
31// Defines
32//
33
34//
35// Data types
36//
37
38typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg);
39
40typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY {
41 VMBUS_CHANNEL_MESSAGE_TYPE messageType;
42 PFN_CHANNEL_MESSAGE_HANDLER messageHandler;
43} VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY;
44
45//
46// Internal routines
47//
48
49static void
50VmbusChannelOnOffer(
51 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
52 );
53static void
54VmbusChannelOnOpenResult(
55 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
56 );
57
58static void
59VmbusChannelOnOfferRescind(
60 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
61 );
62
63static void
64VmbusChannelOnGpadlCreated(
65 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
66 );
67
68static void
69VmbusChannelOnGpadlTorndown(
70 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
71 );
72
73static void
74VmbusChannelOnOffersDelivered(
75 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
76 );
77
78static void
79VmbusChannelOnVersionResponse(
80 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
81 );
82
83static void
84VmbusChannelProcessOffer(
85 PVOID context
86 );
87
88static void
89VmbusChannelProcessRescindOffer(
90 PVOID context
91 );
92
93
94//
95// Globals
96//
97
98#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
99
100const GUID gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED]= {
101 //{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
102 {.Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}},// Storage - SCSI
103 //{F8615163-DF3E-46c5-913F-F2D2F965ED0E}
104 {.Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}}, // Network
105 //{CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A}
106 {.Data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}}, // Input
107 //{32412632-86cb-44a2-9b5c-50d1417354f5}
108 {.Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}}, // IDE
109
110};
111
112// Channel message dispatch table
113VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= {
114 {ChannelMessageInvalid, NULL},
115 {ChannelMessageOfferChannel, VmbusChannelOnOffer},
116 {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
117 {ChannelMessageRequestOffers, NULL},
118 {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
119 {ChannelMessageOpenChannel, NULL},
120 {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
121 {ChannelMessageCloseChannel, NULL},
122 {ChannelMessageGpadlHeader, NULL},
123 {ChannelMessageGpadlBody, NULL},
124 {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
125 {ChannelMessageGpadlTeardown, NULL},
126 {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
127 {ChannelMessageRelIdReleased, NULL},
128 {ChannelMessageInitiateContact, NULL},
129 {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
130 {ChannelMessageUnload, NULL},
131};
132
133/*++
134
135Name:
136 AllocVmbusChannel()
137
138Description:
139 Allocate and initialize a vmbus channel object
140
141--*/
142VMBUS_CHANNEL* AllocVmbusChannel(void)
143{
144 VMBUS_CHANNEL* channel;
145
146 channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL));
147 if (!channel)
148 {
149 return NULL;
150 }
151
152 memset(channel, 0,sizeof(VMBUS_CHANNEL));
153 channel->InboundLock = SpinlockCreate();
154 if (!channel->InboundLock)
155 {
156 MemFree(channel);
157 return NULL;
158 }
159
160 channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel);
161 if (!channel->PollTimer)
162 {
163 SpinlockClose(channel->InboundLock);
164 MemFree(channel);
165 return NULL;
166 }
167
168 //channel->dataWorkQueue = WorkQueueCreate("data");
169 channel->ControlWQ = WorkQueueCreate("control");
170 if (!channel->ControlWQ)
171 {
172 TimerClose(channel->PollTimer);
173 SpinlockClose(channel->InboundLock);
174 MemFree(channel);
175 return NULL;
176 }
177
178 return channel;
179}
180
181/*++
182
183Name:
184 ReleaseVmbusChannel()
185
186Description:
187 Release the vmbus channel object itself
188
189--*/
190static inline void ReleaseVmbusChannel(void* Context)
191{
192 VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context;
193
194 DPRINT_ENTER(VMBUS);
195
196 DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
197 WorkQueueClose(channel->ControlWQ);
198 DPRINT_DBG(VMBUS, "channel released (%p)", channel);
199
200 MemFree(channel);
201
202 DPRINT_EXIT(VMBUS);
203}
204
205/*++
206
207Name:
208 FreeVmbusChannel()
209
210Description:
211 Release the resources used by the vmbus channel object
212
213--*/
214void FreeVmbusChannel(VMBUS_CHANNEL* Channel)
215{
216 SpinlockClose(Channel->InboundLock);
217 TimerClose(Channel->PollTimer);
218
219 // We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context
220 // ie we can't destroy ourselves.
221 WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, ReleaseVmbusChannel, (void*)Channel);
222}
223
224
225/*++
226
227Name:
228 VmbusChannelProcessOffer()
229
230Description:
231 Process the offer by creating a channel/device associated with this offer
232
233--*/
234static void
235VmbusChannelProcessOffer(
236 PVOID context
237 )
238{
239 int ret=0;
240 VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context;
241 LIST_ENTRY* anchor;
242 LIST_ENTRY* curr;
243 BOOL fNew=TRUE;
244 VMBUS_CHANNEL* channel;
245
246 DPRINT_ENTER(VMBUS);
247
248 // Make sure this is a new offer
249 SpinlockAcquire(gVmbusConnection.ChannelLock);
250
251 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
252 {
253 channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
254
255 if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(GUID)) &&
256 !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID)))
257 {
258 fNew = FALSE;
259 break;
260 }
261 }
262
263 if (fNew)
264 {
265 INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry);
266 }
267 SpinlockRelease(gVmbusConnection.ChannelLock);
268
269 if (!fNew)
270 {
271 DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId);
272 FreeVmbusChannel(newChannel);
273 DPRINT_EXIT(VMBUS);
274 return;
275 }
276
277 // Start the process of binding this offer to the driver
278 // We need to set the DeviceObject field before calling VmbusChildDeviceAdd()
279 newChannel->DeviceObject = VmbusChildDeviceCreate(
280 newChannel->OfferMsg.Offer.InterfaceType,
281 newChannel->OfferMsg.Offer.InterfaceInstance,
282 newChannel);
283
284 DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject);
285
286 // Add the new device to the bus. This will kick off device-driver binding
287 // which eventually invokes the device driver's AddDevice() method.
288 ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
289 if (ret != 0)
290 {
291 DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)",
292 newChannel->OfferMsg.ChildRelId);
293
294 SpinlockAcquire(gVmbusConnection.ChannelLock);
295 REMOVE_ENTRY_LIST(&newChannel->ListEntry);
296 SpinlockRelease(gVmbusConnection.ChannelLock);
297
298 FreeVmbusChannel(newChannel);
299 }
300 else
301 {
302 // This state is used to indicate a successful open so that when we do close the channel normally,
303 // we can cleanup properly
304 newChannel->State = CHANNEL_OPEN_STATE;
305 }
306 DPRINT_EXIT(VMBUS);
307}
308
309/*++
310
311Name:
312 VmbusChannelProcessRescindOffer()
313
314Description:
315 Rescind the offer by initiating a device removal
316
317--*/
318static void
319VmbusChannelProcessRescindOffer(
320 PVOID context
321 )
322{
323 VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context;
324
325 DPRINT_ENTER(VMBUS);
326
327 VmbusChildDeviceRemove(channel->DeviceObject);
328
329 DPRINT_EXIT(VMBUS);
330}
331
332
333/*++
334
335Name:
336 VmbusChannelOnOffer()
337
338Description:
339 Handler for channel offers from vmbus in parent partition. We ignore all offers except
340 network and storage offers. For each network and storage offers, we create a channel object
341 and queue a work item to the channel object to process the offer synchronously
342
343--*/
344static void
345VmbusChannelOnOffer(
346 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
347 )
348{
349 VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr;
350 VMBUS_CHANNEL* newChannel;
351
352 GUID *guidType;
353 GUID *guidInstance;
354 int i;
355 int fSupported=0;
356
357 DPRINT_ENTER(VMBUS);
358
359 for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++)
360 {
361 if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0)
362 {
363 fSupported = 1;
364 break;
365 }
366 }
367
368 if (!fSupported)
369 {
370 DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId);
371 DPRINT_EXIT(VMBUS);
372
373 return;
374 }
375
376 guidType = &offer->Offer.InterfaceType;
377 guidInstance = &offer->Offer.InterfaceInstance;
378
379 DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, "
380 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} "
381 "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
382 offer->ChildRelId,
383 offer->MonitorId,
384 offer->MonitorAllocated,
385 guidType->Data[3], guidType->Data[2], guidType->Data[1], guidType->Data[0], guidType->Data[5], guidType->Data[4], guidType->Data[7], guidType->Data[6], guidType->Data[8], guidType->Data[9], guidType->Data[10], guidType->Data[11], guidType->Data[12], guidType->Data[13], guidType->Data[14], guidType->Data[15],
386 guidInstance->Data[3], guidInstance->Data[2], guidInstance->Data[1], guidInstance->Data[0], guidInstance->Data[5], guidInstance->Data[4], guidInstance->Data[7], guidInstance->Data[6], guidInstance->Data[8], guidInstance->Data[9], guidInstance->Data[10], guidInstance->Data[11], guidInstance->Data[12], guidInstance->Data[13], guidInstance->Data[14], guidInstance->Data[15]);
387
388 // Allocate the channel object and save this offer.
389 newChannel = AllocVmbusChannel();
390 if (!newChannel)
391 {
392 DPRINT_ERR(VMBUS, "unable to allocate channel object");
393 return;
394 }
395
396 DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
397
398 memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL));
399 newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32;
400 newChannel->MonitorBit = (UINT8)offer->MonitorId % 32;
401
402 // TODO: Make sure the offer comes from our parent partition
403 WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel);
404
405 DPRINT_EXIT(VMBUS);
406}
407
408
409/*++
410
411Name:
412 VmbusChannelOnOfferRescind()
413
414Description:
415 Rescind offer handler. We queue a work item to process this offer
416 synchronously
417
418--*/
419static void
420VmbusChannelOnOfferRescind(
421 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
422 )
423{
424 VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr;
425 VMBUS_CHANNEL* channel;
426
427 DPRINT_ENTER(VMBUS);
428
429 channel = GetChannelFromRelId(rescind->ChildRelId);
430 if (channel == NULL)
431 {
432 DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId);
433 return;
434 }
435
436 WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel);
437
438 DPRINT_EXIT(VMBUS);
439}
440
441
442/*++
443
444Name:
445 VmbusChannelOnOffersDelivered()
446
447Description:
448 This is invoked when all offers have been delivered.
449 Nothing to do here.
450
451--*/
452static void
453VmbusChannelOnOffersDelivered(
454 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
455 )
456{
457 DPRINT_ENTER(VMBUS);
458 DPRINT_EXIT(VMBUS);
459}
460
461
462/*++
463
464Name:
465 VmbusChannelOnOpenResult()
466
467Description:
468 Open result handler. This is invoked when we received a response
469 to our channel open request. Find the matching request, copy the
470 response and signal the requesting thread.
471
472--*/
473static void
474VmbusChannelOnOpenResult(
475 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
476 )
477{
478 VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr;
479 LIST_ENTRY* anchor;
480 LIST_ENTRY* curr;
481 VMBUS_CHANNEL_MSGINFO* msgInfo;
482 VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader;
483 VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
484
485 DPRINT_ENTER(VMBUS);
486
487 DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
488
489 // Find the open msg, copy the result and signal/unblock the wait event
490 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
491
492 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
493 {
494 msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
495 requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
496
497 if (requestHeader->MessageType == ChannelMessageOpenChannel)
498 {
499 openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg;
500 if (openMsg->ChildRelId == result->ChildRelId &&
501 openMsg->OpenId == result->OpenId)
502 {
503 memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT));
504 WaitEventSet(msgInfo->WaitEvent);
505 break;
506 }
507 }
508 }
509 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
510
511 DPRINT_EXIT(VMBUS);
512}
513
514
515/*++
516
517Name:
518 VmbusChannelOnGpadlCreated()
519
520Description:
521 GPADL created handler. This is invoked when we received a response
522 to our gpadl create request. Find the matching request, copy the
523 response and signal the requesting thread.
524
525--*/
526static void
527VmbusChannelOnGpadlCreated(
528 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
529 )
530{
531 VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr;
532 LIST_ENTRY *anchor;
533 LIST_ENTRY *curr;
534 VMBUS_CHANNEL_MSGINFO *msgInfo;
535 VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
536 VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader;
537
538 DPRINT_ENTER(VMBUS);
539
540 DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus);
541
542 // Find the establish msg, copy the result and signal/unblock the wait event
543 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
544
545 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
546 {
547 msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
548 requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
549
550 if (requestHeader->MessageType == ChannelMessageGpadlHeader)
551 {
552 gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader;
553
554 if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) &&
555 (gpadlCreated->Gpadl == gpadlHeader->Gpadl))
556 {
557 memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED));
558 WaitEventSet(msgInfo->WaitEvent);
559 break;
560 }
561 }
562 }
563 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
564
565 DPRINT_EXIT(VMBUS);
566}
567
568
569/*++
570
571Name:
572 VmbusChannelOnGpadlTorndown()
573
574Description:
575 GPADL torndown handler. This is invoked when we received a response
576 to our gpadl teardown request. Find the matching request, copy the
577 response and signal the requesting thread.
578
579--*/
580static void
581VmbusChannelOnGpadlTorndown(
582 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
583 )
584{
585 VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr;
586 LIST_ENTRY* anchor;
587 LIST_ENTRY* curr;
588 VMBUS_CHANNEL_MSGINFO* msgInfo;
589 VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
590 VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown;
591
592 DPRINT_ENTER(VMBUS);
593
594 // Find the open msg, copy the result and signal/unblock the wait event
595 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
596
597 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
598 {
599 msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
600 requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
601
602 if (requestHeader->MessageType == ChannelMessageGpadlTeardown)
603 {
604 gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader;
605
606 if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl)
607 {
608 memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN));
609 WaitEventSet(msgInfo->WaitEvent);
610 break;
611 }
612 }
613 }
614 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
615
616 DPRINT_EXIT(VMBUS);
617}
618
619
620/*++
621
622Name:
623 VmbusChannelOnVersionResponse()
624
625Description:
626 Version response handler. This is invoked when we received a response
627 to our initiate contact request. Find the matching request, copy the
628 response and signal the requesting thread.
629
630--*/
631static void
632VmbusChannelOnVersionResponse(
633 PVMBUS_CHANNEL_MESSAGE_HEADER hdr
634 )
635{
636 LIST_ENTRY* anchor;
637 LIST_ENTRY* curr;
638 VMBUS_CHANNEL_MSGINFO *msgInfo;
639 VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
640 VMBUS_CHANNEL_INITIATE_CONTACT *initiate;
641 VMBUS_CHANNEL_VERSION_RESPONSE *versionResponse = (VMBUS_CHANNEL_VERSION_RESPONSE*)hdr;
642
643 DPRINT_ENTER(VMBUS);
644
645 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
646
647 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
648 {
649 msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
650 requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
651
652 if (requestHeader->MessageType == ChannelMessageInitiateContact)
653 {
654 initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader;
655 memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE));
656 WaitEventSet(msgInfo->WaitEvent);
657 }
658 }
659 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
660
661 DPRINT_EXIT(VMBUS);
662}
663
664
665/*++
666
667Name:
668 VmbusOnChannelMessage()
669
670Description:
671 Handler for channel protocol messages.
672 This is invoked in the vmbus worker thread context.
673
674--*/
675VOID
676VmbusOnChannelMessage(
677 void *Context
678 )
679{
680 HV_MESSAGE *msg=(HV_MESSAGE*)Context;
681 VMBUS_CHANNEL_MESSAGE_HEADER* hdr;
682 int size;
683
684 DPRINT_ENTER(VMBUS);
685
686 hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload;
687 size=msg->Header.PayloadSize;
688
689 DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
690
691 if (hdr->MessageType >= ChannelMessageCount)
692 {
693 DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size);
694 PrintBytes((unsigned char *)msg->u.Payload, size);
695 MemFree(msg);
696 return;
697 }
698
699 if (gChannelMessageTable[hdr->MessageType].messageHandler)
700 {
701 gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
702 }
703 else
704 {
705 DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType);
706 }
707
708 // Free the msg that was allocated in VmbusOnMsgDPC()
709 MemFree(msg);
710 DPRINT_EXIT(VMBUS);
711}
712
713
714/*++
715
716Name:
717 VmbusChannelRequestOffers()
718
719Description:
720 Send a request to get all our pending offers.
721
722--*/
723int
724VmbusChannelRequestOffers(
725 VOID
726 )
727{
728 int ret=0;
729 VMBUS_CHANNEL_MESSAGE_HEADER* msg;
730 VMBUS_CHANNEL_MSGINFO* msgInfo;
731
732 DPRINT_ENTER(VMBUS);
733
734 msgInfo =
735 (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
736 ASSERT(msgInfo != NULL);
737
738 msgInfo->WaitEvent = WaitEventCreate();
739 msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
740
741 msg->MessageType = ChannelMessageRequestOffers;
742
743 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
744 INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry);
745 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
746
747 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
748 if (ret != 0)
749 {
750 DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
751
752 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
753 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
754 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
755
756 goto Cleanup;
757 }
758 //WaitEventWait(msgInfo->waitEvent);
759
760 /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
761 REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
762 SpinlockRelease(gVmbusConnection.channelMsgLock);*/
763
764
765Cleanup:
766 if (msgInfo)
767 {
768 WaitEventClose(msgInfo->WaitEvent);
769 MemFree(msgInfo);
770 }
771
772 DPRINT_EXIT(VMBUS);
773
774 return ret;
775}
776
777/*++
778
779Name:
780 VmbusChannelReleaseUnattachedChannels()
781
782Description:
783 Release channels that are unattached/unconnected ie (no drivers associated)
784
785--*/
786void
787VmbusChannelReleaseUnattachedChannels(
788 VOID
789 )
790{
791 LIST_ENTRY *entry;
792 VMBUS_CHANNEL *channel;
793 VMBUS_CHANNEL *start=NULL;
794
795 SpinlockAcquire(gVmbusConnection.ChannelLock);
796
797 while (!IsListEmpty(&gVmbusConnection.ChannelList))
798 {
799 entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList);
800 channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry);
801
802 if (channel == start)
803 break;
804
805 if (!channel->DeviceObject->Driver)
806 {
807 REMOVE_ENTRY_LIST(&channel->ListEntry);
808 DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject);
809
810 VmbusChildDeviceRemove(channel->DeviceObject);
811 FreeVmbusChannel(channel);
812 }
813 else
814 {
815 if (!start)
816 {
817 start = channel;
818 }
819 }
820 }
821
822 SpinlockRelease(gVmbusConnection.ChannelLock);
823}
824
825// eof
826
diff --git a/drivers/staging/hv/ChannelMgmt.h b/drivers/staging/hv/ChannelMgmt.h
new file mode 100644
index 00000000000..d5ba5d13594
--- /dev/null
+++ b/drivers/staging/hv/ChannelMgmt.h
@@ -0,0 +1,156 @@
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
25#ifndef _CHANNEL_MGMT_H_
26#define _CHANNEL_MGMT_H_
27
28#include "osd.h"
29#include "List.h"
30#include "RingBuffer.h"
31
32#include "VmbusChannelInterface.h"
33#include "ChannelMessages.h"
34
35
36
37typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context);
38
39typedef enum {
40 CHANNEL_OFFER_STATE,
41 CHANNEL_OPENING_STATE,
42 CHANNEL_OPEN_STATE,
43} VMBUS_CHANNEL_STATE;
44
45typedef struct _VMBUS_CHANNEL {
46 LIST_ENTRY ListEntry;
47
48 DEVICE_OBJECT* DeviceObject;
49
50 HANDLE PollTimer; // SA-111 workaround
51
52 VMBUS_CHANNEL_STATE State;
53
54 VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg;
55 // These are based on the OfferMsg.MonitorId. Save it here for easy access.
56 UINT8 MonitorGroup;
57 UINT8 MonitorBit;
58
59 UINT32 RingBufferGpadlHandle;
60
61 // Allocated memory for ring buffer
62 VOID* RingBufferPages;
63 UINT32 RingBufferPageCount;
64 RING_BUFFER_INFO Outbound; // send to parent
65 RING_BUFFER_INFO Inbound; // receive from parent
66 HANDLE InboundLock;
67 HANDLE ControlWQ;
68
69 // Channel callback are invoked in this workqueue context
70 //HANDLE dataWorkQueue;
71
72 PFN_CHANNEL_CALLBACK OnChannelCallback;
73 PVOID ChannelCallbackContext;
74
75} VMBUS_CHANNEL;
76
77
78typedef struct _VMBUS_CHANNEL_DEBUG_INFO {
79 UINT32 RelId;
80 VMBUS_CHANNEL_STATE State;
81 GUID InterfaceType;
82 GUID InterfaceInstance;
83 UINT32 MonitorId;
84 UINT32 ServerMonitorPending;
85 UINT32 ServerMonitorLatency;
86 UINT32 ServerMonitorConnectionId;
87 UINT32 ClientMonitorPending;
88 UINT32 ClientMonitorLatency;
89 UINT32 ClientMonitorConnectionId;
90
91 RING_BUFFER_DEBUG_INFO Inbound;
92 RING_BUFFER_DEBUG_INFO Outbound;
93} VMBUS_CHANNEL_DEBUG_INFO;
94
95
96typedef union {
97 VMBUS_CHANNEL_VERSION_SUPPORTED VersionSupported;
98 VMBUS_CHANNEL_OPEN_RESULT OpenResult;
99 VMBUS_CHANNEL_GPADL_TORNDOWN GpadlTorndown;
100 VMBUS_CHANNEL_GPADL_CREATED GpadlCreated;
101 VMBUS_CHANNEL_VERSION_RESPONSE VersionResponse;
102} VMBUS_CHANNEL_MESSAGE_RESPONSE;
103
104
105// Represents each channel msg on the vmbus connection
106// This is a variable-size data structure depending on
107// the msg type itself
108typedef struct _VMBUS_CHANNEL_MSGINFO {
109 // Bookkeeping stuff
110 LIST_ENTRY MsgListEntry;
111
112 // So far, this is only used to handle gpadl body message
113 LIST_ENTRY SubMsgList;
114
115 // Synchronize the request/response if needed
116 HANDLE WaitEvent;
117
118 VMBUS_CHANNEL_MESSAGE_RESPONSE Response;
119
120 UINT32 MessageSize;
121 // The channel message that goes out on the "wire".
122 // It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
123 unsigned char Msg[0];
124} VMBUS_CHANNEL_MSGINFO;
125
126
127//
128// Routines
129//
130
131INTERNAL VMBUS_CHANNEL*
132AllocVmbusChannel(
133 void
134 );
135
136INTERNAL void
137FreeVmbusChannel(
138 VMBUS_CHANNEL *Channel
139 );
140
141INTERNAL void
142VmbusOnChannelMessage(
143 void *Context
144 );
145
146INTERNAL int
147VmbusChannelRequestOffers(
148 void
149 );
150
151INTERNAL void
152VmbusChannelReleaseUnattachedChannels(
153 void
154 );
155
156#endif //_CHANNEL_MGMT_H_
diff --git a/drivers/staging/hv/Connection.c b/drivers/staging/hv/Connection.c
new file mode 100644
index 00000000000..fba195aa4b9
--- /dev/null
+++ b/drivers/staging/hv/Connection.c
@@ -0,0 +1,432 @@
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
25#include "logging.h"
26
27#include "VmbusPrivate.h"
28
29//
30// Globals
31//
32
33
34VMBUS_CONNECTION gVmbusConnection = {
35 .ConnectState = Disconnected,
36 .NextGpadlHandle = 0xE1E10,
37};
38
39
40/*++
41
42Name:
43 VmbusConnect()
44
45Description:
46 Sends a connect request on the partition service connection
47
48--*/
49int
50VmbusConnect(
51 )
52{
53 int ret=0;
54 VMBUS_CHANNEL_MSGINFO *msgInfo=NULL;
55 VMBUS_CHANNEL_INITIATE_CONTACT *msg;
56
57 DPRINT_ENTER(VMBUS);
58
59 // Make sure we are not connecting or connected
60 if (gVmbusConnection.ConnectState != Disconnected)
61 return -1;
62
63 // Initialize the vmbus connection
64 gVmbusConnection.ConnectState = Connecting;
65 gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ");
66
67 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
68 gVmbusConnection.ChannelMsgLock = SpinlockCreate();
69
70 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
71 gVmbusConnection.ChannelLock = SpinlockCreate();
72
73 // Setup the vmbus event connection for channel interrupt abstraction stuff
74 gVmbusConnection.InterruptPage = PageAlloc(1);
75 if (gVmbusConnection.InterruptPage == NULL)
76 {
77 ret = -1;
78 goto Cleanup;
79 }
80
81 gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
82 gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
83
84 // Setup the monitor notification facility. The 1st page for parent->child and the 2nd page for child->parent
85 gVmbusConnection.MonitorPages = PageAlloc(2);
86 if (gVmbusConnection.MonitorPages == NULL)
87 {
88 ret = -1;
89 goto Cleanup;
90 }
91
92 msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
93 if (msgInfo == NULL)
94 {
95 ret = -1;
96 goto Cleanup;
97 }
98
99 msgInfo->WaitEvent = WaitEventCreate();
100 msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
101
102 msg->Header.MessageType = ChannelMessageInitiateContact;
103 msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
104 msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage);
105 msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages);
106 msg->MonitorPage2 = GetPhysicalAddress((PVOID)((ULONG_PTR)gVmbusConnection.MonitorPages + PAGE_SIZE));
107
108 // Add to list before we send the request since we may receive the response
109 // before returning from this routine
110 SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
111 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
112 SpinlockRelease(gVmbusConnection.ChannelMsgLock);
113
114 DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
115 msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
116
117 DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
118
119 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
120 if (ret != 0)
121 {
122 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
123 goto Cleanup;
124 }
125
126 // Wait for the connection response
127 WaitEventWait(msgInfo->WaitEvent);
128
129 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
130
131 // Check if successful
132 if (msgInfo->Response.VersionResponse.VersionSupported)
133 {
134 DPRINT_INFO(VMBUS, "Vmbus connected!!");
135 gVmbusConnection.ConnectState = Connected;
136
137 }
138 else
139 {
140 DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
141 ret = -1;
142
143 goto Cleanup;
144 }
145
146
147 WaitEventClose(msgInfo->WaitEvent);
148 MemFree(msgInfo);
149 DPRINT_EXIT(VMBUS);
150
151 return 0;
152
153Cleanup:
154
155 gVmbusConnection.ConnectState = Disconnected;
156
157 WorkQueueClose(gVmbusConnection.WorkQueue);
158 SpinlockClose(gVmbusConnection.ChannelLock);
159 SpinlockClose(gVmbusConnection.ChannelMsgLock);
160
161 if (gVmbusConnection.InterruptPage)
162 {
163 PageFree(gVmbusConnection.InterruptPage, 1);
164 gVmbusConnection.InterruptPage = NULL;
165 }
166
167 if (gVmbusConnection.MonitorPages)
168 {
169 PageFree(gVmbusConnection.MonitorPages, 2);
170 gVmbusConnection.MonitorPages = NULL;
171 }
172
173 if (msgInfo)
174 {
175 if (msgInfo->WaitEvent)
176 WaitEventClose(msgInfo->WaitEvent);
177
178 MemFree(msgInfo);
179 }
180
181 DPRINT_EXIT(VMBUS);
182
183 return ret;
184}
185
186
187/*++
188
189Name:
190 VmbusDisconnect()
191
192Description:
193 Sends a disconnect request on the partition service connection
194
195--*/
196int
197VmbusDisconnect(
198 VOID
199 )
200{
201 int ret=0;
202 VMBUS_CHANNEL_UNLOAD *msg;
203
204 DPRINT_ENTER(VMBUS);
205
206 // Make sure we are connected
207 if (gVmbusConnection.ConnectState != Connected)
208 return -1;
209
210 msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD));
211
212 msg->MessageType = ChannelMessageUnload;
213
214 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
215
216 if (ret != 0)
217 {
218 goto Cleanup;
219 }
220
221 PageFree(gVmbusConnection.InterruptPage, 1);
222
223 // TODO: iterate thru the msg list and free up
224
225 SpinlockClose(gVmbusConnection.ChannelMsgLock);
226
227 WorkQueueClose(gVmbusConnection.WorkQueue);
228
229 gVmbusConnection.ConnectState = Disconnected;
230
231 DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
232
233Cleanup:
234 if (msg)
235 {
236 MemFree(msg);
237 }
238
239 DPRINT_EXIT(VMBUS);
240
241 return ret;
242}
243
244
245/*++
246
247Name:
248 GetChannelFromRelId()
249
250Description:
251 Get the channel object given its child relative id (ie channel id)
252
253--*/
254VMBUS_CHANNEL*
255GetChannelFromRelId(
256 UINT32 relId
257 )
258{
259 VMBUS_CHANNEL* channel;
260 VMBUS_CHANNEL* foundChannel=NULL;
261 LIST_ENTRY* anchor;
262 LIST_ENTRY* curr;
263
264 SpinlockAcquire(gVmbusConnection.ChannelLock);
265 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
266 {
267 channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
268
269 if (channel->OfferMsg.ChildRelId == relId)
270 {
271 foundChannel = channel;
272 break;
273 }
274 }
275 SpinlockRelease(gVmbusConnection.ChannelLock);
276
277 return foundChannel;
278}
279
280
281
282/*++
283
284Name:
285 VmbusProcessChannelEvent()
286
287Description:
288 Process a channel event notification
289
290--*/
291static void
292VmbusProcessChannelEvent(
293 PVOID context
294 )
295{
296 VMBUS_CHANNEL* channel;
297 UINT32 relId = (UINT32)(ULONG_PTR)context;
298
299 ASSERT(relId > 0);
300
301 // Find the channel based on this relid and invokes
302 // the channel callback to process the event
303 channel = GetChannelFromRelId(relId);
304
305 if (channel)
306 {
307 VmbusChannelOnChannelEvent(channel);
308 //WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel);
309 }
310 else
311 {
312 DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
313 }
314}
315
316
317/*++
318
319Name:
320 VmbusOnEvents()
321
322Description:
323 Handler for events
324
325--*/
326VOID
327VmbusOnEvents(
328 VOID
329 )
330{
331 int dword;
332 //int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes
333 int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
334 int bit;
335 int relid;
336 UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
337 //VMBUS_CHANNEL_MESSAGE* receiveMsg;
338
339 DPRINT_ENTER(VMBUS);
340
341 // Check events
342 if (recvInterruptPage)
343 {
344 for (dword = 0; dword < maxdword; dword++)
345 {
346 if (recvInterruptPage[dword])
347 {
348 for (bit = 0; bit < 32; bit++)
349 {
350 if (BitTestAndClear(&recvInterruptPage[dword], bit))
351 {
352 relid = (dword << 5) + bit;
353
354 DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
355
356 if (relid == 0) // special case - vmbus channel protocol msg
357 {
358 DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
359
360 continue; }
361 else
362 {
363 //QueueWorkItem(VmbusProcessEvent, (void*)relid);
364 //ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid);
365 VmbusProcessChannelEvent((void*)(ULONG_PTR)relid);
366 }
367 }
368 }
369 }
370 }
371 }
372 DPRINT_EXIT(VMBUS);
373
374 return;
375}
376
377/*++
378
379Name:
380 VmbusPostMessage()
381
382Description:
383 Send a msg on the vmbus's message connection
384
385--*/
386int
387VmbusPostMessage(
388 PVOID buffer,
389 SIZE_T bufferLen
390 )
391{
392 int ret=0;
393 HV_CONNECTION_ID connId;
394
395
396 connId.AsUINT32 =0;
397 connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
398 ret = HvPostMessage(
399 connId,
400 1,
401 buffer,
402 bufferLen);
403
404 return ret;
405}
406
407/*++
408
409Name:
410 VmbusSetEvent()
411
412Description:
413 Send an event notification to the parent
414
415--*/
416int
417VmbusSetEvent(UINT32 childRelId)
418{
419 int ret=0;
420
421 DPRINT_ENTER(VMBUS);
422
423 // Each UINT32 represents 32 channels
424 BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31);
425 ret = HvSignalEvent();
426
427 DPRINT_EXIT(VMBUS);
428
429 return ret;
430}
431
432// EOF
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c
new file mode 100644
index 00000000000..7aec8c94b2e
--- /dev/null
+++ b/drivers/staging/hv/Hv.c
@@ -0,0 +1,672 @@
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
25#include "logging.h"
26#include "VmbusPrivate.h"
27
28//
29// Globals
30//
31
32// The one and only
33HV_CONTEXT gHvContext={
34 .SynICInitialized = FALSE,
35 .HypercallPage = NULL,
36 .SignalEventParam = NULL,
37 .SignalEventBuffer = NULL,
38};
39
40
41/*++
42
43Name:
44 HvQueryHypervisorPresence()
45
46Description:
47 Query the cpuid for presense of windows hypervisor
48
49--*/
50static int
51HvQueryHypervisorPresence (
52 void
53 )
54{
55 unsigned int eax;
56 unsigned int ebx;
57 unsigned int ecx;
58 unsigned int edx;
59 unsigned int op;
60
61 eax = 0;
62 ebx = 0;
63 ecx = 0;
64 edx = 0;
65 op = HvCpuIdFunctionVersionAndFeatures;
66 do_cpuid(op, &eax, &ebx, &ecx, &edx);
67
68 return (ecx & HV_PRESENT_BIT);
69}
70
71
72/*++
73
74Name:
75 HvQueryHypervisorInfo()
76
77Description:
78 Get version info of the windows hypervisor
79
80--*/
81static int
82HvQueryHypervisorInfo (
83 void
84 )
85{
86 unsigned int eax;
87 unsigned int ebx;
88 unsigned int ecx;
89 unsigned int edx;
90 unsigned int maxLeaf;
91 unsigned int op;
92
93 //
94 // Its assumed that this is called after confirming that Viridian is present.
95 // Query id and revision.
96 //
97
98 eax = 0;
99 ebx = 0;
100 ecx = 0;
101 edx = 0;
102 op = HvCpuIdFunctionHvVendorAndMaxFunction;
103 do_cpuid(op, &eax, &ebx, &ecx, &edx);
104
105 DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
106 (ebx & 0xFF),
107 ((ebx >> 8) & 0xFF),
108 ((ebx >> 16) & 0xFF),
109 ((ebx >> 24) & 0xFF),
110 (ecx & 0xFF),
111 ((ecx >> 8) & 0xFF),
112 ((ecx >> 16) & 0xFF),
113 ((ecx >> 24) & 0xFF),
114 (edx & 0xFF),
115 ((edx >> 8) & 0xFF),
116 ((edx >> 16) & 0xFF),
117 ((edx >> 24) & 0xFF));
118
119 maxLeaf = eax;
120 eax = 0;
121 ebx = 0;
122 ecx = 0;
123 edx = 0;
124 op = HvCpuIdFunctionHvInterface;
125 do_cpuid(op, &eax, &ebx, &ecx, &edx);
126
127 DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
128 (eax & 0xFF),
129 ((eax >> 8) & 0xFF),
130 ((eax >> 16) & 0xFF),
131 ((eax >> 24) & 0xFF));
132
133 if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
134 eax = 0;
135 ebx = 0;
136 ecx = 0;
137 edx = 0;
138 op = HvCpuIdFunctionMsHvVersion;
139 do_cpuid(op, &eax, &ebx, &ecx, &edx);
140 DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
141 eax,
142 ebx >> 16,
143 ebx & 0xFFFF,
144 ecx,
145 edx >> 24,
146 edx & 0xFFFFFF);
147 }
148 return maxLeaf;
149}
150
151
152/*++
153
154Name:
155 HvDoHypercall()
156
157Description:
158 Invoke the specified hypercall
159
160--*/
161static UINT64
162HvDoHypercall (
163 UINT64 Control,
164 void* Input,
165 void* Output
166 )
167{
168#ifdef x86_64
169 UINT64 hvStatus=0;
170 UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0;
171 UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0;
172 volatile void* hypercallPage = gHvContext.HypercallPage;
173
174 DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
175 Control,
176 inputAddress,
177 Input,
178 outputAddress,
179 Output,
180 hypercallPage);
181
182 __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
183 __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
184
185 DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
186
187 return hvStatus;
188
189#else
190
191 UINT32 controlHi = Control >> 32;
192 UINT32 controlLo = Control & 0xFFFFFFFF;
193 UINT32 hvStatusHi = 1;
194 UINT32 hvStatusLo = 1;
195 UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0;
196 UINT32 inputAddressHi = inputAddress >> 32;
197 UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF;
198 UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0;
199 UINT32 outputAddressHi = outputAddress >> 32;
200 UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF;
201 volatile void* hypercallPage = gHvContext.HypercallPage;
202
203 DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
204 Control,
205 Input,
206 Output);
207
208 __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
209
210
211 DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32));
212
213 return (hvStatusLo | ((UINT64)hvStatusHi << 32));
214#endif // x86_64
215}
216
217/*++
218
219Name:
220 HvInit()
221
222Description:
223 Main initialization routine. This routine must be called
224 before any other routines in here are called
225
226--*/
227static int
228HvInit (
229 void
230 )
231{
232 int ret=0;
233 int maxLeaf;
234 HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
235 void* virtAddr=0;
236 ULONG_PTR physAddr=0;
237
238 DPRINT_ENTER(VMBUS);
239
240 memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
241 memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
242
243 if (!HvQueryHypervisorPresence())
244 {
245 DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
246 goto Cleanup;
247 }
248
249 DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
250
251 maxLeaf = HvQueryHypervisorInfo();
252 //HvQueryHypervisorFeatures(maxLeaf);
253
254 // Determine if we are running on xenlinux (ie x2v shim) or native linux
255 gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
256
257 if (gHvContext.GuestId == 0)
258 {
259 // Write our OS info
260 WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
261
262 gHvContext.GuestId = HV_LINUX_GUEST_ID;
263 }
264
265 // See if the hypercall page is already set
266 hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
267
268 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
269 {
270 // Allocate the hypercall page memory
271 //virtAddr = PageAlloc(1);
272 virtAddr = VirtualAllocExec(PAGE_SIZE);
273
274 if (!virtAddr)
275 {
276 DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
277 goto Cleanup;
278 }
279
280 hypercallMsr.Enable = 1;
281 //hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT;
282 hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT;
283 WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
284
285 // Confirm that hypercall page did get setup.
286 hypercallMsr.AsUINT64 = 0;
287 hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
288
289 if (!hypercallMsr.Enable)
290 {
291 DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
292 goto Cleanup;
293 }
294
295 gHvContext.HypercallPage = virtAddr;
296 }
297 else
298 {
299 DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
300 goto Cleanup;
301 }
302
303 DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x",
304 (unsigned long)gHvContext.HypercallPage,
305 (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
306
307 // Setup the global signal event param for the signal event hypercall
308 gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER));
309 if (!gHvContext.SignalEventBuffer)
310 {
311 goto Cleanup;
312 }
313
314 gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN));
315 gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0;
316 gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID;
317 gHvContext.SignalEventParam->FlagNumber = 0;
318 gHvContext.SignalEventParam->RsvdZ = 0;
319
320 //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId());
321
322 DPRINT_EXIT(VMBUS);
323
324 return ret;
325
326Cleanup:
327 if (virtAddr)
328 {
329 if (hypercallMsr.Enable)
330 {
331 hypercallMsr.AsUINT64 = 0;
332 WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
333 }
334
335 VirtualFree(virtAddr);
336 }
337 ret = -1;
338 DPRINT_EXIT(VMBUS);
339
340 return ret;
341}
342
343
344/*++
345
346Name:
347 HvCleanup()
348
349Description:
350 Cleanup routine. This routine is called normally during driver unloading or exiting.
351
352--*/
353void
354HvCleanup (
355 void
356 )
357{
358 HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
359
360 DPRINT_ENTER(VMBUS);
361
362 if (gHvContext.SignalEventBuffer)
363 {
364 MemFree(gHvContext.SignalEventBuffer);
365 gHvContext.SignalEventBuffer = NULL;
366 gHvContext.SignalEventParam = NULL;
367 }
368
369 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
370 {
371 if (gHvContext.HypercallPage)
372 {
373 hypercallMsr.AsUINT64 = 0;
374 WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
375 VirtualFree(gHvContext.HypercallPage);
376 gHvContext.HypercallPage = NULL;
377 }
378 }
379
380 DPRINT_EXIT(VMBUS);
381
382}
383
384
385/*++
386
387Name:
388 HvPostMessage()
389
390Description:
391 Post a message using the hypervisor message IPC. This
392 involves a hypercall.
393
394--*/
395HV_STATUS
396HvPostMessage(
397 HV_CONNECTION_ID connectionId,
398 HV_MESSAGE_TYPE messageType,
399 PVOID payload,
400 SIZE_T payloadSize
401 )
402{
403 struct alignedInput {
404 UINT64 alignment8;
405 HV_INPUT_POST_MESSAGE msg;
406 };
407
408 PHV_INPUT_POST_MESSAGE alignedMsg;
409 HV_STATUS status;
410 ULONG_PTR addr;
411
412 if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
413 {
414 return -1;
415 }
416
417 addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput));
418
419 if (!addr)
420 {
421 return -1;
422 }
423
424 alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
425
426 alignedMsg->ConnectionId = connectionId;
427 alignedMsg->MessageType = messageType;
428 alignedMsg->PayloadSize = payloadSize;
429 memcpy((void*)alignedMsg->Payload, payload, payloadSize);
430
431 status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF;
432
433 MemFree((void*)addr);
434
435 return status;
436}
437
438
439/*++
440
441Name:
442 HvSignalEvent()
443
444Description:
445 Signal an event on the specified connection using the hypervisor event IPC. This
446 involves a hypercall.
447
448--*/
449HV_STATUS
450HvSignalEvent(
451 )
452{
453 HV_STATUS status;
454
455 status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF;
456
457 return status;
458}
459
460
461/*++
462
463Name:
464 HvSynicInit()
465
466Description:
467 Initialize the Synthethic Interrupt Controller. If it is already initialized by
468 another entity (ie x2v shim), we need to retrieve the initialized message and event pages.
469 Otherwise, we create and initialize the message and event pages.
470
471--*/
472int
473HvSynicInit (
474 UINT32 irqVector
475 )
476{
477 UINT64 version;
478 HV_SYNIC_SIMP simp;
479 HV_SYNIC_SIEFP siefp;
480 HV_SYNIC_SINT sharedSint;
481 HV_SYNIC_SCONTROL sctrl;
482 UINT64 guestID;
483 int ret=0;
484
485 DPRINT_ENTER(VMBUS);
486
487 if (!gHvContext.HypercallPage)
488 {
489 DPRINT_EXIT(VMBUS);
490 return ret;
491 }
492
493 // Check the version
494 version = ReadMsr(HV_X64_MSR_SVERSION);
495
496 DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
497
498 // TODO: Handle SMP
499 if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
500 {
501 DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
502
503 simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
504 siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
505
506 DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
507
508 // Determine if we are running on xenlinux (ie x2v shim) or native linux
509 guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
510
511 if (guestID == HV_LINUX_GUEST_ID)
512 {
513 gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT);
514 gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT);
515 }
516 else
517 {
518 DPRINT_ERR(VMBUS, "unknown guest id!!");
519 goto Cleanup;
520 }
521 DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
522 }
523 else
524 {
525 gHvContext.synICMessagePage[0] = PageAlloc(1);
526 if (gHvContext.synICMessagePage[0] == NULL)
527 {
528 DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
529 goto Cleanup;
530 }
531
532 gHvContext.synICEventPage[0] = PageAlloc(1);
533 if (gHvContext.synICEventPage[0] == NULL)
534 {
535 DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
536 goto Cleanup;
537 }
538
539 //
540 // Setup the Synic's message page
541 //
542 simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
543 simp.SimpEnabled = 1;
544 simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
545
546 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
547
548 WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
549
550 //
551 // Setup the Synic's event page
552 //
553 siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
554 siefp.SiefpEnabled = 1;
555 siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
556
557 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
558
559 WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
560 }
561 //
562 // Setup the interception SINT.
563 //
564 //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX),
565 // interceptionSint.AsUINT64);
566
567 //
568 // Setup the shared SINT.
569 //
570 sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
571
572 sharedSint.AsUINT64 = 0;
573 sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20;
574 sharedSint.Masked = FALSE;
575 sharedSint.AutoEoi = TRUE;
576
577 DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
578
579 WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
580
581 // Enable the global synic bit
582 sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL);
583 sctrl.Enable = 1;
584
585 WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
586
587 gHvContext.SynICInitialized = TRUE;
588
589 DPRINT_EXIT(VMBUS);
590
591 return ret;
592
593Cleanup:
594 ret = -1;
595
596 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
597 {
598 if (gHvContext.synICEventPage[0])
599 {
600 PageFree(gHvContext.synICEventPage[0],1);
601 }
602
603 if (gHvContext.synICMessagePage[0])
604 {
605 PageFree(gHvContext.synICMessagePage[0], 1);
606 }
607 }
608
609 DPRINT_EXIT(VMBUS);
610
611 return ret;
612
613}
614
615/*++
616
617Name:
618 HvSynicCleanup()
619
620Description:
621 Cleanup routine for HvSynicInit().
622
623--*/
624VOID
625HvSynicCleanup(
626 VOID
627 )
628{
629 HV_SYNIC_SINT sharedSint;
630 HV_SYNIC_SIMP simp;
631 HV_SYNIC_SIEFP siefp;
632
633 DPRINT_ENTER(VMBUS);
634
635 if (!gHvContext.SynICInitialized)
636 {
637 DPRINT_EXIT(VMBUS);
638 return;
639 }
640
641 sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
642
643 sharedSint.Masked = 1;
644
645 // Disable the interrupt
646 WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
647
648 // Disable and free the resources only if we are running as native linux
649 // since in xenlinux, we are sharing the resources with the x2v shim
650 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
651 {
652 simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
653 simp.SimpEnabled = 0;
654 simp.BaseSimpGpa = 0;
655
656 WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
657
658 siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
659 siefp.SiefpEnabled = 0;
660 siefp.BaseSiefpGpa = 0;
661
662 WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
663
664 PageFree(gHvContext.synICMessagePage[0], 1);
665 PageFree(gHvContext.synICEventPage[0], 1);
666 }
667
668 DPRINT_EXIT(VMBUS);
669}
670
671
672// eof
diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h
new file mode 100644
index 00000000000..cbc77d2d086
--- /dev/null
+++ b/drivers/staging/hv/Hv.h
@@ -0,0 +1,184 @@
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
25#ifndef __HV_H__
26#define __HV_H__
27
28#include "osd.h"
29
30#include "HvTypes.h"
31#include "HvStatus.h"
32//#include "HvVmApi.h"
33//#include "HvKeApi.h"
34//#include "HvMmApi.h"
35//#include "HvCpuApi.h"
36#include "HvHalApi.h"
37#include "HvVpApi.h"
38//#include "HvTrApi.h"
39#include "HvSynicApi.h"
40//#include "HvAmApi.h"
41//#include "HvHkApi.h"
42//#include "HvValApi.h"
43#include "HvHcApi.h"
44#include "HvPtApi.h"
45
46enum
47{
48 VMBUS_MESSAGE_CONNECTION_ID = 1,
49 VMBUS_MESSAGE_PORT_ID = 1,
50 VMBUS_EVENT_CONNECTION_ID = 2,
51 VMBUS_EVENT_PORT_ID = 2,
52 VMBUS_MONITOR_CONNECTION_ID = 3,
53 VMBUS_MONITOR_PORT_ID = 3,
54 VMBUS_MESSAGE_SINT = 2
55};
56//
57// #defines
58//
59#define HV_PRESENT_BIT 0x80000000
60
61#define HV_XENLINUX_GUEST_ID_LO 0x00000000
62#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135
63#define HV_XENLINUX_GUEST_ID (((UINT64)HV_XENLINUX_GUEST_ID_HI << 32) | HV_XENLINUX_GUEST_ID_LO)
64
65#define HV_LINUX_GUEST_ID_LO 0x00000000
66#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
67#define HV_LINUX_GUEST_ID (((UINT64)HV_LINUX_GUEST_ID_HI << 32) | HV_LINUX_GUEST_ID_LO)
68
69#define HV_CPU_POWER_MANAGEMENT (1 << 0)
70#define HV_RECOMMENDATIONS_MAX 4
71
72#define HV_X64_MAX 5
73#define HV_CAPS_MAX 8
74
75
76#define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64)
77
78//
79// Service definitions
80//
81#define HV_SERVICE_PARENT_PORT (0)
82#define HV_SERVICE_PARENT_CONNECTION (0)
83
84#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
85#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
86#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
87#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
88
89#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
90#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
91#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
92#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
93#define HV_SERVICE_MAX_MESSAGE_ID (4)
94
95#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
96#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
97
98//#define VMBUS_REVISION_NUMBER 6
99//#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine
100
101// 628180B8-308D-4c5e-B7DB-1BEB62E62EF4
102static const GUID VMBUS_SERVICE_ID = {.Data = {0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c, 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4} };
103
104#define MAX_NUM_CPUS 1
105
106
107typedef struct {
108 UINT64 Align8;
109 HV_INPUT_SIGNAL_EVENT Event;
110} HV_INPUT_SIGNAL_EVENT_BUFFER;
111
112typedef struct {
113 UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized
114 void* HypercallPage;
115
116 BOOL SynICInitialized;
117 // This is used as an input param to HvCallSignalEvent hypercall. The input param is immutable
118 // in our usage and must be dynamic mem (vs stack or global).
119 HV_INPUT_SIGNAL_EVENT_BUFFER *SignalEventBuffer;
120 HV_INPUT_SIGNAL_EVENT *SignalEventParam; // 8-bytes aligned of the buffer above
121
122 HANDLE synICMessagePage[MAX_NUM_CPUS];
123 HANDLE synICEventPage[MAX_NUM_CPUS];
124} HV_CONTEXT;
125
126extern HV_CONTEXT gHvContext;
127
128
129//
130// Inline routines
131//
132static inline unsigned long long ReadMsr(int msr)
133{
134 unsigned long long val;
135
136 RDMSR(msr, val);
137
138 return val;
139}
140
141static inline void WriteMsr(int msr, UINT64 val)
142{
143 WRMSR(msr, val);
144
145 return;
146}
147
148//
149// Hv Interface
150//
151INTERNAL int
152HvInit(
153 VOID
154 );
155
156INTERNAL VOID
157HvCleanup(
158 VOID
159 );
160
161INTERNAL HV_STATUS
162HvPostMessage(
163 HV_CONNECTION_ID connectionId,
164 HV_MESSAGE_TYPE messageType,
165 PVOID payload,
166 SIZE_T payloadSize
167 );
168
169INTERNAL HV_STATUS
170HvSignalEvent(
171 VOID
172 );
173
174INTERNAL int
175HvSynicInit(
176 UINT32 irqVector
177 );
178
179INTERNAL VOID
180HvSynicCleanup(
181 VOID
182 );
183
184#endif // __HV_H__
diff --git a/drivers/staging/hv/RingBuffer.c b/drivers/staging/hv/RingBuffer.c
new file mode 100644
index 00000000000..57d944e883b
--- /dev/null
+++ b/drivers/staging/hv/RingBuffer.c
@@ -0,0 +1,630 @@
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
25#include "logging.h"
26#include "RingBuffer.h"
27
28//
29// #defines
30//
31
32// Amount of space to write to
33#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
34
35
36/*++
37
38Name:
39 GetRingBufferAvailBytes()
40
41Description:
42 Get number of bytes available to read and to write to
43 for the specified ring buffer
44
45--*/
46static inline void
47GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write)
48{
49 UINT32 read_loc,write_loc;
50
51 // Capture the read/write indices before they changed
52 read_loc = rbi->RingBuffer->ReadIndex;
53 write_loc = rbi->RingBuffer->WriteIndex;
54
55 *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
56 *read = rbi->RingDataSize - *write;
57}
58
59/*++
60
61Name:
62 GetNextWriteLocation()
63
64Description:
65 Get the next write location for the specified ring buffer
66
67--*/
68static inline UINT32
69GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
70{
71 UINT32 next = RingInfo->RingBuffer->WriteIndex;
72
73 ASSERT(next < RingInfo->RingDataSize);
74
75 return next;
76}
77
78/*++
79
80Name:
81 SetNextWriteLocation()
82
83Description:
84 Set the next write location for the specified ring buffer
85
86--*/
87static inline void
88SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation)
89{
90 RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
91}
92
93/*++
94
95Name:
96 GetNextReadLocation()
97
98Description:
99 Get the next read location for the specified ring buffer
100
101--*/
102static inline UINT32
103GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
104{
105 UINT32 next = RingInfo->RingBuffer->ReadIndex;
106
107 ASSERT(next < RingInfo->RingDataSize);
108
109 return next;
110}
111
112/*++
113
114Name:
115 GetNextReadLocationWithOffset()
116
117Description:
118 Get the next read location + offset for the specified ring buffer.
119 This allows the caller to skip
120
121--*/
122static inline UINT32
123GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset)
124{
125 UINT32 next = RingInfo->RingBuffer->ReadIndex;
126
127 ASSERT(next < RingInfo->RingDataSize);
128 next += Offset;
129 next %= RingInfo->RingDataSize;
130
131 return next;
132}
133
134/*++
135
136Name:
137 SetNextReadLocation()
138
139Description:
140 Set the next read location for the specified ring buffer
141
142--*/
143static inline void
144SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation)
145{
146 RingInfo->RingBuffer->ReadIndex = NextReadLocation;
147}
148
149
150/*++
151
152Name:
153 GetRingBuffer()
154
155Description:
156 Get the start of the ring buffer
157
158--*/
159static inline PVOID
160GetRingBuffer(RING_BUFFER_INFO* RingInfo)
161{
162 return (PVOID)RingInfo->RingBuffer->Buffer;
163}
164
165
166/*++
167
168Name:
169 GetRingBufferSize()
170
171Description:
172 Get the size of the ring buffer
173
174--*/
175static inline UINT32
176GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
177{
178 return RingInfo->RingDataSize;
179}
180
181/*++
182
183Name:
184 GetRingBufferIndices()
185
186Description:
187 Get the read and write indices as UINT64 of the specified ring buffer
188
189--*/
190static inline UINT64
191GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
192{
193 return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
194}
195
196
197/*++
198
199Name:
200 DumpRingInfo()
201
202Description:
203 Dump out to console the ring buffer info
204
205--*/
206void
207DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix)
208{
209 UINT32 bytesAvailToWrite;
210 UINT32 bytesAvailToRead;
211
212 GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
213
214 DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
215 Prefix,
216 RingInfo,
217 RingInfo->RingBuffer->Buffer,
218 bytesAvailToWrite,
219 bytesAvailToRead,
220 RingInfo->RingBuffer->ReadIndex,
221 RingInfo->RingBuffer->WriteIndex);
222}
223
224//
225// Internal routines
226//
227static UINT32
228CopyToRingBuffer(
229 RING_BUFFER_INFO *RingInfo,
230 UINT32 StartWriteOffset,
231 PVOID Src,
232 UINT32 SrcLen);
233
234static UINT32
235CopyFromRingBuffer(
236 RING_BUFFER_INFO *RingInfo,
237 PVOID Dest,
238 UINT32 DestLen,
239 UINT32 StartReadOffset);
240
241
242
243/*++
244
245Name:
246 RingBufferGetDebugInfo()
247
248Description:
249 Get various debug metrics for the specified ring buffer
250
251--*/
252void
253RingBufferGetDebugInfo(
254 RING_BUFFER_INFO *RingInfo,
255 RING_BUFFER_DEBUG_INFO *DebugInfo
256 )
257{
258 UINT32 bytesAvailToWrite;
259 UINT32 bytesAvailToRead;
260
261 if (RingInfo->RingBuffer)
262 {
263 GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
264
265 DebugInfo->BytesAvailToRead = bytesAvailToRead;
266 DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
267 DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
268 DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
269
270 DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
271 }
272}
273
274
275/*++
276
277Name:
278 GetRingBufferInterruptMask()
279
280Description:
281 Get the interrupt mask for the specified ring buffer
282
283--*/
284UINT32
285GetRingBufferInterruptMask(
286 RING_BUFFER_INFO *rbi
287 )
288{
289 return rbi->RingBuffer->InterruptMask;
290}
291
292/*++
293
294Name:
295 RingBufferInit()
296
297Description:
298 Initialize the ring buffer
299
300--*/
301int
302RingBufferInit(
303 RING_BUFFER_INFO *RingInfo,
304 VOID *Buffer,
305 UINT32 BufferLen
306 )
307{
308 ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE);
309
310 memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
311
312 RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
313 RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
314
315 RingInfo->RingSize = BufferLen;
316 RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
317
318 RingInfo->RingLock = SpinlockCreate();
319
320 return 0;
321}
322
323/*++
324
325Name:
326 RingBufferCleanup()
327
328Description:
329 Cleanup the ring buffer
330
331--*/
332void
333RingBufferCleanup(
334 RING_BUFFER_INFO* RingInfo
335 )
336{
337 SpinlockClose(RingInfo->RingLock);
338}
339
340/*++
341
342Name:
343 RingBufferWrite()
344
345Description:
346 Write to the ring buffer
347
348--*/
349int
350RingBufferWrite(
351 RING_BUFFER_INFO* OutRingInfo,
352 SG_BUFFER_LIST SgBuffers[],
353 UINT32 SgBufferCount
354 )
355{
356 int i=0;
357 UINT32 byteAvailToWrite;
358 UINT32 byteAvailToRead;
359 UINT32 totalBytesToWrite=0;
360
361 volatile UINT32 nextWriteLocation;
362 UINT64 prevIndices=0;
363
364 DPRINT_ENTER(VMBUS);
365
366 for (i=0; i < SgBufferCount; i++)
367 {
368 totalBytesToWrite += SgBuffers[i].Length;
369 }
370
371 totalBytesToWrite += sizeof(UINT64);
372
373 SpinlockAcquire(OutRingInfo->RingLock);
374
375 GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
376
377 DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
378
379 //DumpRingInfo(OutRingInfo, "BEFORE ");
380
381 // If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer
382 // is empty since the read index == write index
383 if (byteAvailToWrite <= totalBytesToWrite)
384 {
385 DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
386
387 SpinlockRelease(OutRingInfo->RingLock);
388
389 DPRINT_EXIT(VMBUS);
390
391 return -1;
392 }
393
394 // Write to the ring buffer
395 nextWriteLocation = GetNextWriteLocation(OutRingInfo);
396
397 for (i=0; i < SgBufferCount; i++)
398 {
399 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
400 nextWriteLocation,
401 SgBuffers[i].Data,
402 SgBuffers[i].Length);
403 }
404
405 // Set previous packet start
406 prevIndices = GetRingBufferIndices(OutRingInfo);
407
408 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
409 nextWriteLocation,
410 &prevIndices,
411 sizeof(UINT64));
412
413 // Make sure we flush all writes before updating the writeIndex
414 MemoryFence();
415
416 // Now, update the write location
417 SetNextWriteLocation(OutRingInfo, nextWriteLocation);
418
419 //DumpRingInfo(OutRingInfo, "AFTER ");
420
421 SpinlockRelease(OutRingInfo->RingLock);
422
423 DPRINT_EXIT(VMBUS);
424
425 return 0;
426}
427
428
429/*++
430
431Name:
432 RingBufferPeek()
433
434Description:
435 Read without advancing the read index
436
437--*/
438int
439RingBufferPeek(
440 RING_BUFFER_INFO* InRingInfo,
441 void* Buffer,
442 UINT32 BufferLen
443 )
444{
445 UINT32 bytesAvailToWrite;
446 UINT32 bytesAvailToRead;
447 UINT32 nextReadLocation=0;
448
449 SpinlockAcquire(InRingInfo->RingLock);
450
451 GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
452
453 // Make sure there is something to read
454 if (bytesAvailToRead < BufferLen )
455 {
456 //DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
457
458 SpinlockRelease(InRingInfo->RingLock);
459
460 return -1;
461 }
462
463 // Convert to byte offset
464 nextReadLocation = GetNextReadLocation(InRingInfo);
465
466 nextReadLocation = CopyFromRingBuffer(InRingInfo,
467 Buffer,
468 BufferLen,
469 nextReadLocation);
470
471 SpinlockRelease(InRingInfo->RingLock);
472
473 return 0;
474}
475
476
477/*++
478
479Name:
480 RingBufferRead()
481
482Description:
483 Read and advance the read index
484
485--*/
486int
487RingBufferRead(
488 RING_BUFFER_INFO* InRingInfo,
489 PVOID Buffer,
490 UINT32 BufferLen,
491 UINT32 Offset
492 )
493{
494 UINT32 bytesAvailToWrite;
495 UINT32 bytesAvailToRead;
496 UINT32 nextReadLocation=0;
497 UINT64 prevIndices=0;
498
499 ASSERT(BufferLen > 0);
500
501 SpinlockAcquire(InRingInfo->RingLock);
502
503 GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
504
505 DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
506
507 //DumpRingInfo(InRingInfo, "BEFORE ");
508
509 // Make sure there is something to read
510 if (bytesAvailToRead < BufferLen )
511 {
512 DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
513
514 SpinlockRelease(InRingInfo->RingLock);
515
516 return -1;
517 }
518
519 nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
520
521 nextReadLocation = CopyFromRingBuffer(InRingInfo,
522 Buffer,
523 BufferLen,
524 nextReadLocation);
525
526 nextReadLocation = CopyFromRingBuffer(InRingInfo,
527 &prevIndices,
528 sizeof(UINT64),
529 nextReadLocation);
530
531 // Make sure all reads are done before we update the read index since
532 // the writer may start writing to the read area once the read index is updated
533 MemoryFence();
534
535 // Update the read index
536 SetNextReadLocation(InRingInfo, nextReadLocation);
537
538 //DumpRingInfo(InRingInfo, "AFTER ");
539
540 SpinlockRelease(InRingInfo->RingLock);
541
542 return 0;
543}
544
545
546/*++
547
548Name:
549 CopyToRingBuffer()
550
551Description:
552 Helper routine to copy from source to ring buffer.
553 Assume there is enough room. Handles wrap-around in dest case only!!
554
555--*/
556UINT32
557CopyToRingBuffer(
558 RING_BUFFER_INFO *RingInfo,
559 UINT32 StartWriteOffset,
560 PVOID Src,
561 UINT32 SrcLen)
562{
563 PVOID ringBuffer=GetRingBuffer(RingInfo);
564 UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
565 UINT32 fragLen;
566
567 if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected!
568 {
569 DPRINT_DBG(VMBUS, "wrap-around detected!");
570
571 fragLen = ringBufferSize - StartWriteOffset;
572 memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
573 memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
574 }
575 else
576 {
577 memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
578 }
579
580 StartWriteOffset += SrcLen;
581 StartWriteOffset %= ringBufferSize;
582
583 return StartWriteOffset;
584}
585
586
587/*++
588
589Name:
590 CopyFromRingBuffer()
591
592Description:
593 Helper routine to copy to source from ring buffer.
594 Assume there is enough room. Handles wrap-around in src case only!!
595
596--*/
597UINT32
598CopyFromRingBuffer(
599 RING_BUFFER_INFO *RingInfo,
600 PVOID Dest,
601 UINT32 DestLen,
602 UINT32 StartReadOffset)
603{
604 PVOID ringBuffer=GetRingBuffer(RingInfo);
605 UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
606
607 UINT32 fragLen;
608
609 if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src
610 {
611 DPRINT_DBG(VMBUS, "src wrap-around detected!");
612
613 fragLen = ringBufferSize - StartReadOffset;
614
615 memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
616 memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
617 }
618 else
619 {
620 memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
621 }
622
623 StartReadOffset += DestLen;
624 StartReadOffset %= ringBufferSize;
625
626 return StartReadOffset;
627}
628
629
630// eof
diff --git a/drivers/staging/hv/RingBuffer.h b/drivers/staging/hv/RingBuffer.h
new file mode 100644
index 00000000000..9af5df006e3
--- /dev/null
+++ b/drivers/staging/hv/RingBuffer.h
@@ -0,0 +1,123 @@
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
25#ifndef _RING_BUFFER_H_
26#define _RING_BUFFER_H_
27
28#include "osd.h"
29
30typedef struct _SG_BUFFER_LIST {
31 PVOID Data;
32 UINT32 Length;
33} SG_BUFFER_LIST;
34
35typedef struct _RING_BUFFER {
36 volatile UINT32 WriteIndex; // Offset in bytes from the start of ring data below
37 volatile UINT32 ReadIndex; // Offset in bytes from the start of ring data below
38
39 volatile UINT32 InterruptMask;
40 UINT8 Reserved[4084]; // Pad it to PAGE_SIZE so that data starts on page boundary
41 // NOTE: The InterruptMask field is used only for channels but since our vmbus connection
42 // also uses this data structure and its data starts here, we commented out this field.
43 // volatile UINT32 InterruptMask;
44 // Ring data starts here + RingDataStartOffset !!! DO NOT place any fields below this !!!
45 UINT8 Buffer[0];
46} STRUCT_PACKED RING_BUFFER;
47
48typedef struct _RING_BUFFER_INFO {
49 RING_BUFFER* RingBuffer;
50 UINT32 RingSize; // Include the shared header
51 HANDLE RingLock;
52
53 UINT32 RingDataSize; // < ringSize
54 UINT32 RingDataStartOffset;
55
56} RING_BUFFER_INFO;
57
58
59typedef struct _RING_BUFFER_DEBUG_INFO {
60 UINT32 CurrentInterruptMask;
61 UINT32 CurrentReadIndex;
62 UINT32 CurrentWriteIndex;
63 UINT32 BytesAvailToRead;
64 UINT32 BytesAvailToWrite;
65}RING_BUFFER_DEBUG_INFO;
66
67
68//
69// Interface
70//
71
72INTERNAL int
73RingBufferInit(
74 RING_BUFFER_INFO *RingInfo,
75 PVOID Buffer,
76 UINT32 BufferLen
77 );
78
79INTERNAL void
80RingBufferCleanup(
81 RING_BUFFER_INFO *RingInfo
82 );
83
84INTERNAL int
85RingBufferWrite(
86 RING_BUFFER_INFO *RingInfo,
87 SG_BUFFER_LIST SgBuffers[],
88 UINT32 SgBufferCount
89 );
90
91INTERNAL int
92RingBufferPeek(
93 RING_BUFFER_INFO *RingInfo,
94 PVOID Buffer,
95 UINT32 BufferLen
96 );
97
98INTERNAL int
99RingBufferRead(
100 RING_BUFFER_INFO *RingInfo,
101 PVOID Buffer,
102 UINT32 BufferLen,
103 UINT32 Offset
104 );
105
106INTERNAL UINT32
107GetRingBufferInterruptMask(
108 RING_BUFFER_INFO *RingInfo
109 );
110
111INTERNAL void
112DumpRingInfo(
113 RING_BUFFER_INFO* RingInfo,
114 char *Prefix
115 );
116
117INTERNAL void
118RingBufferGetDebugInfo(
119 RING_BUFFER_INFO *RingInfo,
120 RING_BUFFER_DEBUG_INFO *DebugInfo
121 );
122
123#endif // _RING_BUFFER_H_
diff --git a/drivers/staging/hv/Sources.c b/drivers/staging/hv/Sources.c
new file mode 100644
index 00000000000..bc154642be7
--- /dev/null
+++ b/drivers/staging/hv/Sources.c
@@ -0,0 +1,31 @@
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
25#include "Vmbus.c"
26#include "Hv.c"
27#include "Connection.c"
28#include "Channel.c"
29#include "ChannelMgmt.c"
30#include "ChannelInterface.c"
31#include "RingBuffer.c"
diff --git a/drivers/staging/hv/VersionInfo.h b/drivers/staging/hv/VersionInfo.h
new file mode 100644
index 00000000000..a827f7fa73b
--- /dev/null
+++ b/drivers/staging/hv/VersionInfo.h
@@ -0,0 +1,29 @@
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
25#pragma once
26
27const char VersionDate[]=__DATE__;
28const char VersionTime[]=__TIME__;
29const char VersionDesc[]= "Version 2.0";
diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c
new file mode 100644
index 00000000000..54a120dc055
--- /dev/null
+++ b/drivers/staging/hv/Vmbus.c
@@ -0,0 +1,508 @@
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
25#include "logging.h"
26#include "VersionInfo.h"
27#include "VmbusPrivate.h"
28
29//
30// Globals
31//
32static const char* gDriverName="vmbus";
33
34// Windows vmbus does not defined this. We defined this to be consistent with other devices
35//{c5295816-f63a-4d5f-8d1a-4daf999ca185}
36static const GUID gVmbusDeviceType={
37 .Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85}
38};
39
40//{ac3760fc-9adf-40aa-9427-a70ed6de95c5}
41static const GUID gVmbusDeviceId={
42 .Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5}
43};
44
45static DRIVER_OBJECT* gDriver; // vmbus driver object
46static DEVICE_OBJECT* gDevice; // vmbus root device
47
48
49//
50// Internal routines
51//
52
53static void
54VmbusGetChannelInterface(
55 VMBUS_CHANNEL_INTERFACE *Interface
56 );
57
58static void
59VmbusGetChannelInfo(
60 DEVICE_OBJECT *DeviceObject,
61 DEVICE_INFO *DeviceInfo
62 );
63
64static void
65VmbusGetChannelOffers(
66 void
67 );
68
69static int
70VmbusOnDeviceAdd(
71 DEVICE_OBJECT *Device,
72 void *AdditionalInfo
73 );
74
75static int
76VmbusOnDeviceRemove(
77 DEVICE_OBJECT* dev
78 );
79
80static void
81VmbusOnCleanup(
82 DRIVER_OBJECT* drv
83 );
84
85static int
86VmbusOnISR(
87 DRIVER_OBJECT* drv
88 );
89
90static void
91VmbusOnMsgDPC(
92 DRIVER_OBJECT* drv
93 );
94
95static void
96VmbusOnEventDPC(
97 DRIVER_OBJECT* drv
98 );
99
100/*++;
101
102Name:
103 VmbusInitialize()
104
105Description:
106 Main entry point
107
108--*/
109int
110VmbusInitialize(
111 DRIVER_OBJECT* drv
112 )
113{
114 VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
115 int ret=0;
116
117 DPRINT_ENTER(VMBUS);
118
119 DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
120 DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
121
122 DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
123 DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
124
125 DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%d, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%d",
126 sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
127
128 drv->name = gDriverName;
129 memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID));
130
131 // Setup dispatch table
132 driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
133 driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
134 driver->Base.OnCleanup = VmbusOnCleanup;
135 driver->OnIsr = VmbusOnISR;
136 driver->OnMsgDpc = VmbusOnMsgDPC;
137 driver->OnEventDpc = VmbusOnEventDPC;
138 driver->GetChannelOffers = VmbusGetChannelOffers;
139 driver->GetChannelInterface = VmbusGetChannelInterface;
140 driver->GetChannelInfo = VmbusGetChannelInfo;
141
142 // Hypervisor initialization...setup hypercall page..etc
143 ret = HvInit();
144 if (ret != 0)
145 {
146 DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
147 }
148
149 gDriver = drv;
150
151 DPRINT_EXIT(VMBUS);
152
153 return ret;
154}
155
156
157/*++;
158
159Name:
160 VmbusGetChannelOffers()
161
162Description:
163 Retrieve the channel offers from the parent partition
164
165--*/
166
167static void
168VmbusGetChannelOffers(void)
169{
170 DPRINT_ENTER(VMBUS);
171 VmbusChannelRequestOffers();
172 DPRINT_EXIT(VMBUS);
173}
174
175
176/*++;
177
178Name:
179 VmbusGetChannelInterface()
180
181Description:
182 Get the channel interface
183
184--*/
185static void
186VmbusGetChannelInterface(
187 VMBUS_CHANNEL_INTERFACE *Interface
188 )
189{
190 GetChannelInterface(Interface);
191}
192
193
194/*++;
195
196Name:
197 VmbusGetChannelInterface()
198
199Description:
200 Get the device info for the specified device object
201
202--*/
203static void
204VmbusGetChannelInfo(
205 DEVICE_OBJECT *DeviceObject,
206 DEVICE_INFO *DeviceInfo
207 )
208{
209 GetChannelInfo(DeviceObject, DeviceInfo);
210}
211
212
213
214/*++
215
216Name:
217 VmbusCreateChildDevice()
218
219Description:
220 Creates the child device on the bus that represents the channel offer
221
222--*/
223
224DEVICE_OBJECT*
225VmbusChildDeviceCreate(
226 GUID DeviceType,
227 GUID DeviceInstance,
228 void *Context)
229{
230 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
231
232 return vmbusDriver->OnChildDeviceCreate(
233 DeviceType,
234 DeviceInstance,
235 Context);
236}
237
238
239/*++
240
241Name:
242 VmbusChildDeviceAdd()
243
244Description:
245 Registers the child device with the vmbus
246
247--*/
248int
249VmbusChildDeviceAdd(
250 DEVICE_OBJECT* ChildDevice)
251{
252 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
253
254 return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
255}
256
257
258/*++
259
260Name:
261 VmbusChildDeviceRemove()
262
263Description:
264 Unregisters the child device from the vmbus
265
266--*/
267void
268VmbusChildDeviceRemove(
269 DEVICE_OBJECT* ChildDevice)
270{
271 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
272
273 vmbusDriver->OnChildDeviceRemove(ChildDevice);
274}
275
276/*++
277
278Name:
279 VmbusChildDeviceDestroy()
280
281Description:
282 Release the child device from the vmbus
283
284--*/
285//void
286//VmbusChildDeviceDestroy(
287// DEVICE_OBJECT* ChildDevice
288// )
289//{
290// VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
291//
292// vmbusDriver->OnChildDeviceDestroy(ChildDevice);
293//}
294
295/*++
296
297Name:
298 VmbusOnDeviceAdd()
299
300Description:
301 Callback when the root bus device is added
302
303--*/
304static int
305VmbusOnDeviceAdd(
306 DEVICE_OBJECT *dev,
307 void *AdditionalInfo
308 )
309{
310 UINT32 *irqvector = (UINT32*) AdditionalInfo;
311 int ret=0;
312
313 DPRINT_ENTER(VMBUS);
314
315 gDevice = dev;
316
317 memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID));
318 memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID));
319
320 //strcpy(dev->name, "vmbus");
321 // SynIC setup...
322 ret = HvSynicInit(*irqvector);
323
324 // Connect to VMBus in the root partition
325 ret = VmbusConnect();
326
327 //VmbusSendEvent(device->localPortId+1);
328 DPRINT_EXIT(VMBUS);
329
330 return ret;
331}
332
333
334/*++
335
336Name:
337 VmbusOnDeviceRemove()
338
339Description:
340 Callback when the root bus device is removed
341
342--*/
343int VmbusOnDeviceRemove(
344 DEVICE_OBJECT* dev
345 )
346{
347 int ret=0;
348
349 DPRINT_ENTER(VMBUS);
350
351 VmbusChannelReleaseUnattachedChannels();
352
353 VmbusDisconnect();
354
355 HvSynicCleanup();
356
357 DPRINT_EXIT(VMBUS);
358
359 return ret;
360}
361
362
363/*++
364
365Name:
366 VmbusOnCleanup()
367
368Description:
369 Perform any cleanup when the driver is removed
370
371--*/
372void
373VmbusOnCleanup(
374 DRIVER_OBJECT* drv
375 )
376{
377 //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
378
379 DPRINT_ENTER(VMBUS);
380
381 HvCleanup();
382
383 DPRINT_EXIT(VMBUS);
384}
385
386
387/*++
388
389Name:
390 VmbusOnMsgDPC()
391
392Description:
393 DPC routine to handle messages from the hypervisior
394
395--*/
396void
397VmbusOnMsgDPC(
398 DRIVER_OBJECT* drv
399 )
400{
401 void *page_addr = gHvContext.synICMessagePage[0];
402
403 HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
404 HV_MESSAGE *copied;
405 while (1)
406 {
407 if (msg->Header.MessageType == HvMessageTypeNone) // no msg
408 {
409 break;
410 }
411 else
412 {
413 copied = MemAllocAtomic(sizeof(HV_MESSAGE));
414 if (copied == NULL)
415 {
416 continue;
417 }
418
419 memcpy(copied, msg, sizeof(HV_MESSAGE));
420 WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied);
421 }
422
423 msg->Header.MessageType = HvMessageTypeNone;
424
425 // Make sure the write to MessageType (ie set to HvMessageTypeNone) happens
426 // before we read the MessagePending and EOMing. Otherwise, the EOMing will not deliver
427 // any more messages since there is no empty slot
428 MemoryFence();
429
430 if (msg->Header.MessageFlags.MessagePending)
431 {
432 // This will cause message queue rescan to possibly deliver another msg from the hypervisor
433 WriteMsr(HV_X64_MSR_EOM, 0);
434 }
435 }
436}
437
438/*++
439
440Name:
441 VmbusOnEventDPC()
442
443Description:
444 DPC routine to handle events from the hypervisior
445
446--*/
447void
448VmbusOnEventDPC(
449 DRIVER_OBJECT* drv
450 )
451{
452 // TODO: Process any events
453 VmbusOnEvents();
454}
455
456
457/*++
458
459Name:
460 VmbusOnISR()
461
462Description:
463 ISR routine
464
465--*/
466int
467VmbusOnISR(
468 DRIVER_OBJECT* drv
469 )
470{
471 //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
472
473 int ret=0;
474 //struct page* page;
475 void *page_addr;
476 HV_MESSAGE* msg;
477 HV_SYNIC_EVENT_FLAGS* event;
478
479 //page = SynICMessagePage[0];
480 //page_addr = page_address(page);
481 page_addr = gHvContext.synICMessagePage[0];
482 msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
483
484 DPRINT_ENTER(VMBUS);
485
486 // Check if there are actual msgs to be process
487 if (msg->Header.MessageType != HvMessageTypeNone)
488 {
489 DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
490 ret |= 0x1;
491 }
492
493 // TODO: Check if there are events to be process
494 page_addr = gHvContext.synICEventPage[0];
495 event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT;
496
497 // Since we are a child, we only need to check bit 0
498 if (BitTestAndClear(&event->Flags32[0], 0))
499 {
500 DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
501 ret |= 0x2;
502 }
503
504 DPRINT_EXIT(VMBUS);
505 return ret;
506}
507
508// eof
diff --git a/drivers/staging/hv/VmbusPrivate.h b/drivers/staging/hv/VmbusPrivate.h
new file mode 100644
index 00000000000..5e86165dea2
--- /dev/null
+++ b/drivers/staging/hv/VmbusPrivate.h
@@ -0,0 +1,170 @@
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
25#ifndef _VMBUS_PRIVATE_H_
26#define _VMBUS_PRIVATE_H_
27
28#ifndef INTERNAL
29#define INTERNAL static
30#endif
31
32#include "Hv.h"
33#include "VmbusApi.h"
34#include "Channel.h"
35#include "ChannelMgmt.h"
36#include "ChannelInterface.h"
37//#include "ChannelMessages.h"
38#include "RingBuffer.h"
39//#include "Packet.h"
40#include "List.h"
41
42//
43// Defines
44//
45
46// Maximum channels is determined by the size of the interrupt page which is PAGE_SIZE. 1/2 of PAGE_SIZE is for
47// send endpoint interrupt and the other is receive endpoint interrupt
48#define MAX_NUM_CHANNELS (PAGE_SIZE >> 1) << 3 // 16348 channels
49
50// The value here must be in multiple of 32
51// TODO: Need to make this configurable
52#define MAX_NUM_CHANNELS_SUPPORTED 256
53
54//
55// Data types
56//
57
58typedef enum {
59 Disconnected,
60 Connecting,
61 Connected,
62 Disconnecting
63} VMBUS_CONNECT_STATE;
64
65#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
66
67typedef struct _VMBUS_CONNECTION {
68
69 VMBUS_CONNECT_STATE ConnectState;
70
71 UINT32 NextGpadlHandle;
72
73 // Represents channel interrupts. Each bit position
74 // represents a channel.
75 // When a channel sends an interrupt via VMBUS, it
76 // finds its bit in the sendInterruptPage, set it and
77 // calls Hv to generate a port event. The other end
78 // receives the port event and parse the recvInterruptPage
79 // to see which bit is set
80 VOID* InterruptPage;
81 VOID* SendInterruptPage;
82 VOID* RecvInterruptPage;
83
84 // 2 pages - 1st page for parent->child notification and 2nd is child->parent notification
85 VOID* MonitorPages;
86 LIST_ENTRY ChannelMsgList;
87 HANDLE ChannelMsgLock;
88
89 // List of channels
90 LIST_ENTRY ChannelList;
91 HANDLE ChannelLock;
92
93 HANDLE WorkQueue;
94} VMBUS_CONNECTION;
95
96
97typedef struct _VMBUS_MSGINFO {
98 // Bookkeeping stuff
99 LIST_ENTRY MsgListEntry;
100
101 // Synchronize the request/response if needed
102 HANDLE WaitEvent;
103
104 // The message itself
105 unsigned char Msg[0];
106} VMBUS_MSGINFO;
107
108
109//
110// Externs
111//
112extern VMBUS_CONNECTION gVmbusConnection;
113
114//
115// General vmbus interface
116//
117INTERNAL DEVICE_OBJECT*
118VmbusChildDeviceCreate(
119 GUID deviceType,
120 GUID deviceInstance,
121 void *context);
122
123INTERNAL int
124VmbusChildDeviceAdd(
125 DEVICE_OBJECT* Device);
126
127INTERNAL void
128VmbusChildDeviceRemove(
129 DEVICE_OBJECT* Device);
130
131//INTERNAL void
132//VmbusChildDeviceDestroy(
133// DEVICE_OBJECT*);
134
135INTERNAL VMBUS_CHANNEL*
136GetChannelFromRelId(
137 UINT32 relId
138 );
139
140//
141// Connection interface
142//
143INTERNAL int
144VmbusConnect(
145 VOID
146 );
147
148INTERNAL int
149VmbusDisconnect(
150 VOID
151 );
152
153INTERNAL int
154VmbusPostMessage(
155 PVOID buffer,
156 SIZE_T bufSize
157 );
158
159INTERNAL int
160VmbusSetEvent(
161 UINT32 childRelId
162 );
163
164INTERNAL VOID
165VmbusOnEvents(
166 VOID
167 );
168
169
170#endif // _VMBUS_PRIVATE_H_
diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c
new file mode 100644
index 00000000000..83885252049
--- /dev/null
+++ b/drivers/staging/hv/osd.c
@@ -0,0 +1,500 @@
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
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/types.h>
28#include <linux/mm.h>
29#include <linux/highmem.h>
30#include <linux/vmalloc.h>
31//#include <linux/config.h>
32#include <linux/ioport.h>
33#include <linux/irq.h>
34#include <linux/interrupt.h>
35#include <linux/wait.h>
36#include <linux/spinlock.h>
37#include <linux/workqueue.h>
38#include <linux/kernel.h>
39#include <linux/timer.h>
40#include <linux/jiffies.h>
41#include <linux/delay.h>
42#include <linux/time.h>
43
44#include <asm/io.h>
45#include <asm/bitops.h>
46#include <asm/kmap_types.h>
47#include <asm/atomic.h>
48
49#include "osd.h"
50
51//
52// Data types
53//
54typedef struct _TIMER {
55 struct timer_list timer;
56 PFN_TIMER_CALLBACK callback;
57 void* context;
58}TIMER;
59
60
61typedef struct _WAITEVENT {
62 int condition;
63 wait_queue_head_t event;
64} WAITEVENT;
65
66typedef struct _SPINLOCK {
67 spinlock_t lock;
68 unsigned long flags;
69} SPINLOCK;
70
71typedef struct _WORKQUEUE {
72 struct workqueue_struct *queue;
73} WORKQUEUE;
74
75typedef struct _WORKITEM {
76 struct work_struct work;
77 PFN_WORKITEM_CALLBACK callback;
78 void* context;
79} WORKITEM;
80
81
82//
83// Global
84//
85
86void LogMsg(const char *fmt, ...)
87{
88#ifdef KERNEL_2_6_5
89 char buf[1024];
90#endif
91 va_list args;
92
93 va_start(args, fmt);
94#ifdef KERNEL_2_6_5
95 vsnprintf(buf, 1024, fmt, args);
96 va_end(args);
97 printk(buf);
98#else
99 vprintk(fmt, args);
100 va_end(args);
101#endif
102}
103
104void BitSet(unsigned int* addr, int bit)
105{
106 set_bit(bit, (unsigned long*)addr);
107}
108
109int BitTest(unsigned int* addr, int bit)
110{
111 return test_bit(bit, (unsigned long*)addr);
112}
113
114void BitClear(unsigned int* addr, int bit)
115{
116 clear_bit(bit, (unsigned long*)addr);
117}
118
119int BitTestAndClear(unsigned int* addr, int bit)
120{
121 return test_and_clear_bit(bit, (unsigned long*)addr);
122}
123
124int BitTestAndSet(unsigned int* addr, int bit)
125{
126 return test_and_set_bit(bit, (unsigned long*)addr);
127}
128
129
130int InterlockedIncrement(int *val)
131{
132#ifdef KERNEL_2_6_5
133 int i;
134 local_irq_disable();
135 i = atomic_read((atomic_t*)val);
136 atomic_set((atomic_t*)val, i+1);
137 local_irq_enable();
138 return i+1;
139#else
140 return atomic_inc_return((atomic_t*)val);
141#endif
142}
143
144int InterlockedDecrement(int *val)
145{
146#ifdef KERNEL_2_6_5
147 int i;
148 local_irq_disable();
149 i = atomic_read((atomic_t*)val);
150 atomic_set((atomic_t*)val, i-1);
151 local_irq_enable();
152 return i-1;
153#else
154 return atomic_dec_return((atomic_t*)val);
155#endif
156}
157
158#ifndef atomic_cmpxchg
159#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
160#endif
161int InterlockedCompareExchange(int *val, int new, int curr)
162{
163 //return ((int)cmpxchg(((atomic_t*)val), curr, new));
164 return atomic_cmpxchg((atomic_t*)val, curr, new);
165
166}
167
168void Sleep(unsigned long usecs)
169{
170 udelay(usecs);
171}
172
173void* VirtualAllocExec(unsigned int size)
174{
175#ifdef __x86_64__
176 return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
177#else
178 return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX)));
179#endif
180}
181
182void VirtualFree(void* VirtAddr)
183{
184 return vfree(VirtAddr);
185}
186
187void* PageAlloc(unsigned int count)
188{
189 void *p;
190 p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE));
191 if (p) memset(p, 0, count * PAGE_SIZE);
192 return p;
193
194 //struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO);
195 //void *p;
196
197 ////BUGBUG: We need to use kmap in case we are in HIMEM region
198 //p = page_address(page);
199 //if (p) memset(p, 0, PAGE_SIZE);
200 //return p;
201}
202
203void PageFree(void* page, unsigned int count)
204{
205 free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
206 /*struct page* p = virt_to_page(page);
207 __free_page(p);*/
208}
209
210
211void* PageMapVirtualAddress(unsigned long Pfn)
212{
213 return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0);
214}
215
216void PageUnmapVirtualAddress(void* VirtAddr)
217{
218 kunmap_atomic(VirtAddr, KM_IRQ0);
219}
220
221void* MemAlloc(unsigned int size)
222{
223 return kmalloc(size, GFP_KERNEL);
224}
225
226void* MemAllocZeroed(unsigned int size)
227{
228 void *p = kmalloc(size, GFP_KERNEL);
229 if (p) memset(p, 0, size);
230 return p;
231}
232
233void* MemAllocAtomic(unsigned int size)
234{
235 return kmalloc(size, GFP_ATOMIC);
236}
237
238void MemFree(void* buf)
239{
240 kfree(buf);
241}
242
243void *MemMapIO(unsigned long phys, unsigned long size)
244{
245#if X2V_LINUX
246#ifdef __x86_64__
247 return (void*)(phys + 0xFFFF83000C000000);
248#else // i386
249 return (void*)(phys + 0xfb000000);
250#endif
251#else
252 return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size);
253#endif
254}
255
256void MemUnmapIO(void *virt)
257{
258 //iounmap(virt);
259}
260
261void MemoryFence()
262{
263 mb();
264}
265
266void TimerCallback(unsigned long data)
267{
268 TIMER* t = (TIMER*)data;
269
270 t->callback(t->context);
271}
272
273HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context)
274{
275 TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL);
276 if (!t)
277 {
278 return NULL;
279 }
280
281 t->callback = pfnTimerCB;
282 t->context = context;
283
284 init_timer(&t->timer);
285 t->timer.data = (unsigned long)t;
286 t->timer.function = TimerCallback;
287
288 return t;
289}
290
291void TimerStart(HANDLE hTimer, UINT32 expirationInUs)
292{
293 TIMER* t = (TIMER* )hTimer;
294
295 t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs);
296 add_timer(&t->timer);
297}
298
299int TimerStop(HANDLE hTimer)
300{
301 TIMER* t = (TIMER* )hTimer;
302
303 return del_timer(&t->timer);
304}
305
306void TimerClose(HANDLE hTimer)
307{
308 TIMER* t = (TIMER* )hTimer;
309
310 del_timer(&t->timer);
311 kfree(t);
312}
313
314SIZE_T GetTickCount(void)
315{
316 return jiffies;
317}
318
319signed long long GetTimestamp(void)
320{
321 struct timeval t;
322
323 do_gettimeofday(&t);
324
325 return timeval_to_ns(&t);
326}
327
328HANDLE WaitEventCreate(void)
329{
330 WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL);
331 if (!wait)
332 {
333 return NULL;
334 }
335
336 wait->condition = 0;
337 init_waitqueue_head(&wait->event);
338 return wait;
339}
340
341void WaitEventClose(HANDLE hWait)
342{
343 WAITEVENT* waitEvent = (WAITEVENT* )hWait;
344 kfree(waitEvent);
345}
346
347void WaitEventSet(HANDLE hWait)
348{
349 WAITEVENT* waitEvent = (WAITEVENT* )hWait;
350 waitEvent->condition = 1;
351 wake_up_interruptible(&waitEvent->event);
352}
353
354int WaitEventWait(HANDLE hWait)
355{
356 int ret=0;
357 WAITEVENT* waitEvent = (WAITEVENT* )hWait;
358
359 ret= wait_event_interruptible(waitEvent->event,
360 waitEvent->condition);
361 waitEvent->condition = 0;
362 return ret;
363}
364
365int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs)
366{
367 int ret=0;
368 WAITEVENT* waitEvent = (WAITEVENT* )hWait;
369
370 ret= wait_event_interruptible_timeout(waitEvent->event,
371 waitEvent->condition,
372 msecs_to_jiffies(TimeoutInMs));
373 waitEvent->condition = 0;
374 return ret;
375}
376
377HANDLE SpinlockCreate(VOID)
378{
379 SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL);
380 if (!spin)
381 {
382 return NULL;
383 }
384 spin_lock_init(&spin->lock);
385
386 return spin;
387}
388
389VOID SpinlockAcquire(HANDLE hSpin)
390{
391 SPINLOCK* spin = (SPINLOCK* )hSpin;
392
393 spin_lock_irqsave(&spin->lock, spin->flags);
394}
395
396VOID SpinlockRelease(HANDLE hSpin)
397{
398 SPINLOCK* spin = (SPINLOCK* )hSpin;
399
400 spin_unlock_irqrestore(&spin->lock, spin->flags);
401}
402
403VOID SpinlockClose(HANDLE hSpin)
404{
405 SPINLOCK* spin = (SPINLOCK* )hSpin;
406 kfree(spin);
407}
408
409void* Physical2LogicalAddr(ULONG_PTR PhysAddr)
410{
411 void* logicalAddr = phys_to_virt(PhysAddr);
412 BUG_ON(!virt_addr_valid(logicalAddr));
413 return logicalAddr;
414}
415
416ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr)
417{
418 BUG_ON(!virt_addr_valid(LogicalAddr));
419 return virt_to_phys(LogicalAddr);
420}
421
422
423ULONG_PTR Virtual2Physical(PVOID VirtAddr)
424{
425 ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr);
426
427 return pfn << PAGE_SHIFT;
428}
429
430#ifdef KERNEL_2_6_27
431void WorkItemCallback(struct work_struct *work)
432#else
433void WorkItemCallback(void* work)
434#endif
435{
436 WORKITEM* w = (WORKITEM*)work;
437
438 w->callback(w->context);
439
440 kfree(w);
441}
442
443HANDLE WorkQueueCreate(char* name)
444{
445 WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL);
446 if (!wq)
447 {
448 return NULL;
449 }
450 wq->queue = create_workqueue(name);
451
452 return wq;
453}
454
455void WorkQueueClose(HANDLE hWorkQueue)
456{
457 WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
458
459 destroy_workqueue(wq->queue);
460
461 return;
462}
463
464int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context)
465{
466 WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
467
468 WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
469 if (!w)
470 {
471 return -1;
472 }
473
474 w->callback = workItem,
475 w->context = context;
476#ifdef KERNEL_2_6_27
477 INIT_WORK(&w->work, WorkItemCallback);
478#else
479 INIT_WORK(&w->work, WorkItemCallback, w);
480#endif
481 return queue_work(wq->queue, &w->work);
482}
483
484void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context)
485{
486 WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
487 if (!w)
488 {
489 return;
490 }
491
492 w->callback = workItem,
493 w->context = context;
494#ifdef KERNEL_2_6_27
495 INIT_WORK(&w->work, WorkItemCallback);
496#else
497 INIT_WORK(&w->work, WorkItemCallback, w);
498#endif
499 schedule_work(&w->work);
500}
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
new file mode 100644
index 00000000000..0acf42c3566
--- /dev/null
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -0,0 +1,1228 @@
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
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/device.h>
28#include <linux/irq.h>
29#include <linux/interrupt.h>
30#include <linux/sysctl.h>
31
32#include "logging.h"
33#include "vmbus.h"
34
35//
36// Defines
37//
38
39// FIXME! We need to do this dynamically for PIC and APIC system
40#define VMBUS_IRQ 0x5
41#ifdef KERNEL_2_6_27
42#define VMBUS_IRQ_VECTOR IRQ5_VECTOR
43#endif
44//
45// Data types
46//
47
48// Main vmbus driver data structure
49struct vmbus_driver_context {
50 // !! These must be the first 2 fields !!
51 // The driver field is not used in here. Instead, the bus field is
52 // used to represent the driver
53 struct driver_context drv_ctx;
54 VMBUS_DRIVER_OBJECT drv_obj;
55
56 struct bus_type bus;
57 struct tasklet_struct msg_dpc;
58 struct tasklet_struct event_dpc;
59
60 // The bus root device
61 struct device_context device_ctx;
62};
63
64//
65// Static decl
66//
67static int vmbus_match(struct device *device, struct device_driver *driver);
68static int vmbus_probe(struct device *device);
69static int vmbus_remove(struct device *device);
70static void vmbus_shutdown(struct device *device);
71#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
72#elif defined(KERNEL_2_6_27)
73static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env);
74#else
75static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size);
76#endif
77static void vmbus_msg_dpc(unsigned long data);
78static void vmbus_event_dpc(unsigned long data);
79
80#ifdef KERNEL_2_6_27
81static irqreturn_t vmbus_isr(int irq, void* dev_id);
82#else
83static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs);
84#endif
85
86static void vmbus_device_release(struct device *device);
87static void vmbus_bus_release(struct device *device);
88
89static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context);
90static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj);
91static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj);
92static void vmbus_child_device_unregister(DEVICE_OBJECT* child_device_obj);
93static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info);
94
95//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf);
96//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf);
97
98static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf);
99
100//
101// Global
102//
103
104// Global logging setting
105
106//unsigned int vmbus_loglevel= (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT);
107//unsigned int vmbus_loglevel= (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT);
108unsigned int vmbus_loglevel= (ALL_MODULES << 16 | INFO_LVL);
109EXPORT_SYMBOL(vmbus_loglevel);
110
111static int vmbus_irq = VMBUS_IRQ;
112
113// Setup /proc/sys/bus/vmbus/vmbus_loglevel
114// Allow usage of sysctl cmd to set the logging level
115static struct ctl_table_header *vmbus_ctl_table_hdr;
116
117static ctl_table vmbus_dev_ctl_table[] = {
118 { .ctl_name = 8461,
119 .procname = "vmbus_loglevel",
120 .data = &vmbus_loglevel,
121 .maxlen = sizeof(vmbus_loglevel),
122 .mode = 0644,
123 .proc_handler = &proc_dointvec },
124 { }
125};
126
127static ctl_table vmbus_ctl_table[] = {
128 { .ctl_name = CTL_DEV,
129 .procname = "vmbus",
130 .mode = 0555,
131 .child = vmbus_dev_ctl_table },
132 { }
133};
134
135static ctl_table vmus_root_ctl_table[] = {
136 { .ctl_name = CTL_BUS,
137 .procname = "bus",
138 .mode = 0555,
139 .child = vmbus_ctl_table },
140 { }
141};
142
143#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
144#else
145//
146// Set up per device attributes in /sys/bus/vmbus/devices/<bus device>
147//
148static struct device_attribute vmbus_device_attrs[] = {
149 __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL),
150 __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL),
151 __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL),
152 __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL),
153 __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL),
154
155 __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
156 __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
157 __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
158
159 __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
160 __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
161 __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
162
163 __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
164 __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
165 __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
166 __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
167 __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
168
169 __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
170 __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
171 __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
172 __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
173 __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
174 __ATTR_NULL
175};
176#endif
177
178// The one and only one
179static struct vmbus_driver_context g_vmbus_drv={
180 .bus.name = "vmbus",
181 .bus.match = vmbus_match,
182#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
183#else
184 .bus.shutdown = vmbus_shutdown,
185 .bus.remove = vmbus_remove,
186 .bus.probe = vmbus_probe,
187 .bus.uevent = vmbus_uevent,
188 .bus.dev_attrs = vmbus_device_attrs,
189#endif
190};
191
192//
193// Routines
194//
195
196
197/*++
198
199Name: vmbus_show_device_attr()
200
201Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices/<bus device>/<attr name>"
202
203--*/
204static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf)
205{
206 struct device_context *device_ctx = device_to_device_context(dev);
207 DEVICE_INFO device_info;
208
209 memset(&device_info, 0, sizeof(DEVICE_INFO));
210
211 vmbus_child_device_get_info(&device_ctx->device_obj, &device_info);
212
213 if (!strcmp(dev_attr->attr.name, "class_id"))
214 {
215 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
216 device_info.ChannelType.Data[3], device_info.ChannelType.Data[2], device_info.ChannelType.Data[1], device_info.ChannelType.Data[0],
217 device_info.ChannelType.Data[5], device_info.ChannelType.Data[4],
218 device_info.ChannelType.Data[7], device_info.ChannelType.Data[6],
219 device_info.ChannelType.Data[8], device_info.ChannelType.Data[9], device_info.ChannelType.Data[10], device_info.ChannelType.Data[11], device_info.ChannelType.Data[12], device_info.ChannelType.Data[13], device_info.ChannelType.Data[14], device_info.ChannelType.Data[15]);
220
221 }
222 else if (!strcmp(dev_attr->attr.name, "device_id"))
223 {
224 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
225 device_info.ChannelInstance.Data[3], device_info.ChannelInstance.Data[2], device_info.ChannelInstance.Data[1], device_info.ChannelInstance.Data[0],
226 device_info.ChannelInstance.Data[5], device_info.ChannelInstance.Data[4],
227 device_info.ChannelInstance.Data[7], device_info.ChannelInstance.Data[6],
228 device_info.ChannelInstance.Data[8], device_info.ChannelInstance.Data[9], device_info.ChannelInstance.Data[10], device_info.ChannelInstance.Data[11], device_info.ChannelInstance.Data[12], device_info.ChannelInstance.Data[13], device_info.ChannelInstance.Data[14], device_info.ChannelInstance.Data[15]);
229 }
230 else if (!strcmp(dev_attr->attr.name, "state"))
231 {
232 return sprintf(buf, "%d\n", device_info.ChannelState);
233 }
234 else if (!strcmp(dev_attr->attr.name, "id"))
235 {
236 return sprintf(buf, "%d\n", device_info.ChannelId);
237 }
238 else if (!strcmp(dev_attr->attr.name, "out_intr_mask"))
239 {
240 return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask);
241 }
242 else if (!strcmp(dev_attr->attr.name, "out_read_index"))
243 {
244 return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex);
245 }
246 else if (!strcmp(dev_attr->attr.name, "out_write_index"))
247 {
248 return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex);
249 }
250 else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail"))
251 {
252 return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead);
253 }
254 else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail"))
255 {
256 return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite);
257 }
258 else if (!strcmp(dev_attr->attr.name, "in_intr_mask"))
259 {
260 return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask);
261 }
262 else if (!strcmp(dev_attr->attr.name, "in_read_index"))
263 {
264 return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex);
265 }
266 else if (!strcmp(dev_attr->attr.name, "in_write_index"))
267 {
268 return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex);
269 }
270 else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail"))
271 {
272 return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead);
273 }
274 else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail"))
275 {
276 return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite);
277 }
278 else if (!strcmp(dev_attr->attr.name, "monitor_id"))
279 {
280 return sprintf(buf, "%d\n", device_info.MonitorId);
281 }
282 else if (!strcmp(dev_attr->attr.name, "server_monitor_pending"))
283 {
284 return sprintf(buf, "%d\n", device_info.ServerMonitorPending);
285 }
286 else if (!strcmp(dev_attr->attr.name, "server_monitor_latency"))
287 {
288 return sprintf(buf, "%d\n", device_info.ServerMonitorLatency);
289 }
290 else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id"))
291 {
292 return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId);
293 }
294 else if (!strcmp(dev_attr->attr.name, "client_monitor_pending"))
295 {
296 return sprintf(buf, "%d\n", device_info.ClientMonitorPending);
297 }
298 else if (!strcmp(dev_attr->attr.name, "client_monitor_latency"))
299 {
300 return sprintf(buf, "%d\n", device_info.ClientMonitorLatency);
301 }
302 else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id"))
303 {
304 return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId);
305 }
306 else
307 {
308 return 0;
309 }
310}
311
312/*++
313
314Name: vmbus_show_class_id()
315
316Desc: Show the device class id in sysfs
317
318--*/
319//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf)
320//{
321// struct device_context *device_ctx = device_to_device_context(dev);
322// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
323// device_ctx->class_id[3], device_ctx->class_id[2], device_ctx->class_id[1], device_ctx->class_id[0],
324// device_ctx->class_id[5], device_ctx->class_id[4],
325// device_ctx->class_id[7], device_ctx->class_id[6],
326// device_ctx->class_id[8], device_ctx->class_id[9], device_ctx->class_id[10], device_ctx->class_id[11], device_ctx->class_id[12], device_ctx->class_id[13], device_ctx->class_id[14], device_ctx->class_id[15]);
327//}
328
329/*++
330
331Name: vmbus_show_device_id()
332
333Desc: Show the device instance id in sysfs
334
335--*/
336//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf)
337//{
338// struct device_context *device_ctx = device_to_device_context(dev);
339// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
340// device_ctx->device_id[3], device_ctx->device_id[2], device_ctx->device_id[1], device_ctx->device_id[0],
341// device_ctx->device_id[5], device_ctx->device_id[4],
342// device_ctx->device_id[7], device_ctx->device_id[6],
343// device_ctx->device_id[8], device_ctx->device_id[9], device_ctx->device_id[10], device_ctx->device_id[11], device_ctx->device_id[12], device_ctx->device_id[13], device_ctx->device_id[14], device_ctx->device_id[15]);
344//}
345
346/*++
347
348Name: vmbus_bus_init()
349
350Desc: Main vmbus driver initialization routine. Here, we
351 - initialize the vmbus driver context
352 - setup various driver entry points
353 - invoke the vmbus hv main init routine
354 - get the irq resource
355 - invoke the vmbus to add the vmbus root device
356 - setup the vmbus root device
357 - retrieve the channel offers
358--*/
359int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init)
360{
361 int ret=0;
362 unsigned int vector=0;
363
364 struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
365 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
366
367 struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
368
369 DPRINT_ENTER(VMBUS_DRV);
370
371 // Set this up to allow lower layer to callback to add/remove child devices on the bus
372 vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create;
373 vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy;
374 vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register;
375 vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister;
376
377 // Call to bus driver to initialize
378 ret = pfn_drv_init(&vmbus_drv_obj->Base);
379 if (ret != 0)
380 {
381 DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret);
382 goto cleanup;
383 }
384
385 // Sanity checks
386 if (!vmbus_drv_obj->Base.OnDeviceAdd)
387 {
388 DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
389 ret = -1;
390 goto cleanup;
391 }
392
393 vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name;
394
395 // Initialize the bus context
396 tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, (unsigned long)vmbus_drv_obj);
397 tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, (unsigned long)vmbus_drv_obj);
398
399 // Now, register the bus driver with LDM
400 bus_register(&vmbus_drv_ctx->bus);
401
402 // Get the interrupt resource
403#ifdef KERNEL_2_6_27
404 ret = request_irq(vmbus_irq,
405 vmbus_isr,
406 IRQF_SAMPLE_RANDOM,
407 vmbus_drv_obj->Base.name,
408 NULL);
409#else
410 ret = request_irq(vmbus_irq,
411 vmbus_isr,
412 SA_SAMPLE_RANDOM,
413 vmbus_drv_obj->Base.name,
414 NULL);
415#endif
416
417 if (ret != 0)
418 {
419 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq);
420
421 bus_unregister(&vmbus_drv_ctx->bus);
422
423 ret = -1;
424 goto cleanup;
425 }
426#ifdef KERNEL_2_6_27
427 vector = VMBUS_IRQ_VECTOR;
428#else
429#if X2V_LINUX
430 vector = vmbus_irq + FIRST_DEVICE_VECTOR - 2;
431#else
432 vector = vmbus_irq + FIRST_EXTERNAL_VECTOR;
433#endif
434#endif
435
436 DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
437
438 // Call to bus driver to add the root device
439 memset(dev_ctx, 0, sizeof(struct device_context));
440
441 ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
442 if (ret != 0)
443 {
444 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device");
445
446 free_irq(vmbus_irq, NULL);
447
448 bus_unregister(&vmbus_drv_ctx->bus);
449
450 ret = -1;
451 goto cleanup;
452 }
453 //strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name);
454 sprintf(dev_ctx->device.bus_id, "vmbus_0_0");
455 memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(GUID));
456 memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(GUID));
457
458 // No need to bind a driver to the root device.
459 dev_ctx->device.parent = NULL;
460 dev_ctx->device.bus = &vmbus_drv_ctx->bus; //NULL; // vmbus_remove() does not get invoked
461
462 // Setup the device dispatch table
463 dev_ctx->device.release = vmbus_bus_release;
464
465 // Setup the bus as root device
466 device_register(&dev_ctx->device);
467
468 vmbus_drv_obj->GetChannelOffers();
469
470cleanup:
471 DPRINT_EXIT(VMBUS_DRV);
472
473 return ret;
474}
475
476
477/*++
478
479Name: vmbus_bus_exit()
480
481Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init()
482
483--*/
484void vmbus_bus_exit(void)
485{
486 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
487 struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
488
489 struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
490
491 DPRINT_ENTER(VMBUS_DRV);
492
493 // Remove the root device
494 if (vmbus_drv_obj->Base.OnDeviceRemove)
495 vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
496
497 if (vmbus_drv_obj->Base.OnCleanup)
498 vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base);
499
500 // Unregister the root bus device
501 device_unregister(&dev_ctx->device);
502
503 bus_unregister(&vmbus_drv_ctx->bus);
504
505 free_irq(vmbus_irq, NULL);
506
507 tasklet_kill(&vmbus_drv_ctx->msg_dpc);
508 tasklet_kill(&vmbus_drv_ctx->event_dpc);
509
510 DPRINT_EXIT(VMBUS_DRV);
511
512 return;
513}
514
515/*++
516
517Name: vmbus_child_driver_register()
518
519Desc: Register a vmbus's child driver
520
521--*/
522void vmbus_child_driver_register(struct driver_context* driver_ctx)
523{
524 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
525
526 DPRINT_ENTER(VMBUS_DRV);
527
528 DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name);
529
530 // The child driver on this vmbus
531 driver_ctx->driver.bus = &g_vmbus_drv.bus;
532
533 driver_register(&driver_ctx->driver);
534
535 vmbus_drv_obj->GetChannelOffers();
536
537 DPRINT_EXIT(VMBUS_DRV);
538}
539
540EXPORT_SYMBOL(vmbus_child_driver_register);
541
542/*++
543
544Name: vmbus_child_driver_unregister()
545
546Desc: Unregister a vmbus's child driver
547
548--*/
549void vmbus_child_driver_unregister(struct driver_context* driver_ctx)
550{
551 DPRINT_ENTER(VMBUS_DRV);
552
553 DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name);
554
555 driver_unregister(&driver_ctx->driver);
556
557 driver_ctx->driver.bus = NULL;
558
559 DPRINT_EXIT(VMBUS_DRV);
560}
561
562EXPORT_SYMBOL(vmbus_child_driver_unregister);
563
564/*++
565
566Name: vmbus_get_interface()
567
568Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits
569 above vmbus
570--*/
571void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface)
572{
573 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
574
575 vmbus_drv_obj->GetChannelInterface(interface);
576}
577
578EXPORT_SYMBOL(vmbus_get_interface);
579
580
581/*++
582
583Name: vmbus_child_device_get_info()
584
585Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs.
586--*/
587static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info)
588{
589 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
590
591 vmbus_drv_obj->GetChannelInfo(device_obj, device_info);
592}
593
594
595/*++
596
597Name: vmbus_child_device_create()
598
599Desc: Creates and registers a new child device on the vmbus.
600
601--*/
602static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context)
603{
604 struct device_context *child_device_ctx;
605 DEVICE_OBJECT* child_device_obj;
606
607 DPRINT_ENTER(VMBUS_DRV);
608
609 // Allocate the new child device
610 child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL);
611 if (!child_device_ctx)
612 {
613 DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device");
614 DPRINT_EXIT(VMBUS_DRV);
615
616 return NULL;
617 }
618
619 DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
620 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x},"
621 "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
622 &child_device_ctx->device,
623 type.Data[3], type.Data[2], type.Data[1], type.Data[0], type.Data[5], type.Data[4], type.Data[7], type.Data[6], type.Data[8], type.Data[9], type.Data[10], type.Data[11], type.Data[12], type.Data[13], type.Data[14], type.Data[15],
624 instance.Data[3], instance.Data[2], instance.Data[1], instance.Data[0], instance.Data[5], instance.Data[4], instance.Data[7], instance.Data[6], instance.Data[8], instance.Data[9], instance.Data[10], instance.Data[11], instance.Data[12], instance.Data[13], instance.Data[14], instance.Data[15]);
625
626 child_device_obj = &child_device_ctx->device_obj;
627 child_device_obj->context = context;
628 memcpy(&child_device_obj->deviceType, &type, sizeof(GUID));
629 memcpy(&child_device_obj->deviceInstance, &instance, sizeof(GUID));
630
631 memcpy(&child_device_ctx->class_id, &type, sizeof(GUID));
632 memcpy(&child_device_ctx->device_id, &instance, sizeof(GUID));
633
634 DPRINT_EXIT(VMBUS_DRV);
635
636 return child_device_obj;
637}
638
639/*++
640
641Name: vmbus_child_device_register()
642
643Desc: Register the child device on the specified bus
644
645--*/
646static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj)
647{
648 int ret=0;
649 struct device_context *root_device_ctx = to_device_context(root_device_obj);
650 struct device_context *child_device_ctx = to_device_context(child_device_obj);
651 static int device_num=0;
652
653 DPRINT_ENTER(VMBUS_DRV);
654
655 DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx);
656 //
657 // Make sure we are not registered already
658 //
659 if (child_device_ctx->device.bus_id[0] != '\0')
660 {
661 DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id);
662
663 ret = -1;
664 goto Cleanup;
665 }
666
667 // Set the device bus id. Otherwise, device_register()will fail.
668 sprintf(child_device_ctx->device.bus_id, "vmbus_0_%d", InterlockedIncrement(&device_num));
669
670 // The new device belongs to this bus
671 child_device_ctx->device.bus = &g_vmbus_drv.bus; //device->dev.bus;
672 child_device_ctx->device.parent = &root_device_ctx->device;
673 child_device_ctx->device.release = vmbus_device_release;
674
675 // Register with the LDM. This will kick off the driver/device binding...which will
676 // eventually call vmbus_match() and vmbus_probe()
677 ret = device_register(&child_device_ctx->device);
678
679 // vmbus_probe() error does not get propergate to device_register().
680 ret = child_device_ctx->probe_error;
681
682 if (ret)
683 DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p) (%d)", &child_device_ctx->device);
684 else
685 DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device);
686
687Cleanup:
688 DPRINT_EXIT(VMBUS_DRV);
689
690 return ret;
691}
692
693/*++
694
695Name: vmbus_child_device_unregister()
696
697Desc: Remove the specified child device from the vmbus.
698
699--*/
700static void vmbus_child_device_unregister(DEVICE_OBJECT* device_obj)
701{
702 struct device_context *device_ctx = to_device_context(device_obj);
703
704 DPRINT_ENTER(VMBUS_DRV);
705
706 DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device);
707
708 // Kick off the process of unregistering the device.
709 // This will call vmbus_remove() and eventually vmbus_device_release()
710 device_unregister(&device_ctx->device);
711
712 DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device);
713
714 DPRINT_EXIT(VMBUS_DRV);
715}
716
717
718/*++
719
720Name: vmbus_child_device_destroy()
721
722Desc: Destroy the specified child device on the vmbus.
723
724--*/
725static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj)
726{
727 DPRINT_ENTER(VMBUS_DRV);
728
729 DPRINT_EXIT(VMBUS_DRV);
730}
731
732/*++
733
734Name: vmbus_uevent()
735
736Desc: This routine is invoked when a device is added or removed on the vmbus to generate a uevent to udev in the
737 userspace. The udev will then look at its rule and the uevent generated here to load the appropriate driver
738
739--*/
740#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9)
741#elif defined(KERNEL_2_6_27)
742static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
743{
744 struct device_context *device_ctx = device_to_device_context(device);
745 int i=0;
746 int len=0;
747 int ret;
748
749 DPRINT_ENTER(VMBUS_DRV);
750
751 DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
752 device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
753 device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
754 device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
755 device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
756 device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
757
758 env->envp_idx = i;
759 env->buflen = len;
760 ret = add_uevent_var(env,
761 "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
762 device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
763 device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
764 device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
765 device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
766 device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
767
768 if (ret)
769 {
770 return ret;
771 }
772
773 ret = add_uevent_var(env,
774 "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
775 device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0],
776 device_ctx->device_id.Data[5], device_ctx->device_id.Data[4],
777 device_ctx->device_id.Data[7], device_ctx->device_id.Data[6],
778 device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11],
779 device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]);
780
781 if (ret)
782 {
783 return ret;
784 }
785
786 env->envp[env->envp_idx] = NULL;
787
788 DPRINT_EXIT(VMBUS_DRV);
789
790 return 0;
791}
792
793#else
794static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size)
795{
796 struct device_context *device_ctx = device_to_device_context(device);
797 int i=0;
798 int len=0;
799 int ret;
800
801 DPRINT_ENTER(VMBUS_DRV);
802
803 DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
804 device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
805 device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
806 device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
807 device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
808 device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
809
810 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
811 "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
812 device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0],
813 device_ctx->class_id.Data[5], device_ctx->class_id.Data[4],
814 device_ctx->class_id.Data[7], device_ctx->class_id.Data[6],
815 device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11],
816 device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]);
817
818 if (ret)
819 {
820 return ret;
821 }
822
823 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
824 "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
825 device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0],
826 device_ctx->device_id.Data[5], device_ctx->device_id.Data[4],
827 device_ctx->device_id.Data[7], device_ctx->device_id.Data[6],
828 device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11],
829 device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]);
830
831 if (ret)
832 {
833 return ret;
834 }
835
836 envp[i] = NULL;
837
838 DPRINT_EXIT(VMBUS_DRV);
839
840 return 0;
841}
842#endif
843
844/*++
845
846Name: vmbus_match()
847
848Desc: Attempt to match the specified device to the specified driver
849
850--*/
851static int vmbus_match(struct device *device, struct device_driver *driver)
852{
853 int match=0;
854 struct driver_context *driver_ctx = driver_to_driver_context(driver);
855 struct device_context *device_ctx = device_to_device_context(device);
856
857 DPRINT_ENTER(VMBUS_DRV);
858
859 // We found our driver ?
860 if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(GUID)) == 0)
861 {
862 // !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast it here to access the
863 // DRIVER_OBJECT field
864 struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context*)driver_ctx;
865 device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base;
866 DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, device_ctx->device_obj.Driver);
867
868 match = 1;
869 }
870
871 DPRINT_EXIT(VMBUS_DRV);
872
873 return match;
874}
875
876
877/*++
878
879Name: vmbus_probe_failed_cb()
880
881Desc: Callback when a driver probe failed in vmbus_probe(). We need a callback because
882 we cannot invoked device_unregister() inside vmbus_probe() since vmbus_probe() may be
883 invoked inside device_register() i.e. we cannot call device_unregister() inside
884 device_register()
885--*/
886#ifdef KERNEL_2_6_27
887static void vmbus_probe_failed_cb(struct work_struct *context)
888#else
889static void vmbus_probe_failed_cb(void* context)
890#endif
891{
892 struct device_context *device_ctx = (struct device_context*)context;
893
894
895 DPRINT_ENTER(VMBUS_DRV);
896
897 // Kick off the process of unregistering the device.
898 // This will call vmbus_remove() and eventually vmbus_device_release()
899 device_unregister(&device_ctx->device);
900
901 //put_device(&device_ctx->device);
902 DPRINT_EXIT(VMBUS_DRV);
903}
904
905
906/*++
907
908Name: vmbus_probe()
909
910Desc: Add the new vmbus's child device
911
912--*/
913static int vmbus_probe(struct device *child_device)
914{
915 int ret=0;
916 struct driver_context *driver_ctx = driver_to_driver_context(child_device->driver);
917 struct device_context *device_ctx = device_to_device_context(child_device);
918
919 DPRINT_ENTER(VMBUS_DRV);
920
921 // Let the specific open-source driver handles the probe if it can
922 if (driver_ctx->probe)
923 {
924 ret = device_ctx->probe_error = driver_ctx->probe(child_device);
925 if (ret != 0)
926 {
927 DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s (%p) on driver %s (%d)...", child_device->bus_id, child_device, child_device->driver->name, ret);
928
929#ifdef KERNEL_2_6_27
930 INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb);
931#else
932 INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb, device_ctx);
933#endif
934 schedule_work(&device_ctx->probe_failed_work_item);
935 }
936 }
937 else
938 {
939 DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name);
940 ret = -1;
941 }
942
943 DPRINT_EXIT(VMBUS_DRV);
944 return ret;
945}
946
947
948/*++
949
950Name: vmbus_remove()
951
952Desc: Remove a vmbus device
953
954--*/
955static int vmbus_remove(struct device *child_device)
956{
957 int ret=0;
958 struct driver_context *driver_ctx;
959
960 DPRINT_ENTER(VMBUS_DRV);
961
962 // Special case root bus device
963 if (child_device->parent == NULL)
964 {
965 // No-op since it is statically defined and handle in vmbus_bus_exit()
966 DPRINT_EXIT(VMBUS_DRV);
967 return 0;
968 }
969
970 if (child_device->driver)
971 {
972 driver_ctx = driver_to_driver_context(child_device->driver);
973
974 // Let the specific open-source driver handles the removal if it can
975 if (driver_ctx->remove)
976 {
977 ret = driver_ctx->remove(child_device);
978 }
979 else
980 {
981 DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name);
982 ret = -1;
983 }
984 }
985 else
986 {
987
988 }
989
990 DPRINT_EXIT(VMBUS_DRV);
991
992 return 0;
993}
994
995/*++
996
997Name: vmbus_shutdown()
998
999Desc: Shutdown a vmbus device
1000
1001--*/
1002static void vmbus_shutdown(struct device *child_device)
1003{
1004 struct driver_context *driver_ctx;
1005
1006 DPRINT_ENTER(VMBUS_DRV);
1007
1008 // Special case root bus device
1009 if (child_device->parent == NULL)
1010 {
1011 // No-op since it is statically defined and handle in vmbus_bus_exit()
1012 DPRINT_EXIT(VMBUS_DRV);
1013 return;
1014 }
1015
1016 // The device may not be attached yet
1017 if (!child_device->driver)
1018 {
1019 DPRINT_EXIT(VMBUS_DRV);
1020 return;
1021 }
1022
1023 driver_ctx = driver_to_driver_context(child_device->driver);
1024
1025 // Let the specific open-source driver handles the removal if it can
1026 if (driver_ctx->shutdown)
1027 {
1028 driver_ctx->shutdown(child_device);
1029 }
1030
1031 DPRINT_EXIT(VMBUS_DRV);
1032
1033 return;
1034}
1035
1036/*++
1037
1038Name: vmbus_bus_release()
1039
1040Desc: Final callback release of the vmbus root device
1041
1042--*/
1043static void vmbus_bus_release(struct device *device)
1044{
1045 DPRINT_ENTER(VMBUS_DRV);
1046 DPRINT_EXIT(VMBUS_DRV);
1047}
1048
1049/*++
1050
1051Name: vmbus_device_release()
1052
1053Desc: Final callback release of the vmbus child device
1054
1055--*/
1056static void vmbus_device_release(struct device *device)
1057{
1058 struct device_context *device_ctx = device_to_device_context(device);
1059
1060 DPRINT_ENTER(VMBUS_DRV);
1061
1062 //vmbus_child_device_destroy(&device_ctx->device_obj);
1063 kfree(device_ctx);
1064
1065 // !!DO NOT REFERENCE device_ctx anymore at this point!!
1066
1067 DPRINT_EXIT(VMBUS_DRV);
1068
1069 return;
1070}
1071
1072/*++
1073
1074Name: vmbus_msg_dpc()
1075
1076Desc: Tasklet routine to handle hypervisor messages
1077
1078--*/
1079static void vmbus_msg_dpc(unsigned long data)
1080{
1081 VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
1082
1083 DPRINT_ENTER(VMBUS_DRV);
1084
1085 ASSERT(vmbus_drv_obj->OnMsgDpc != NULL);
1086
1087 // Call to bus driver to handle interrupt
1088 vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
1089
1090 DPRINT_EXIT(VMBUS_DRV);
1091}
1092
1093/*++
1094
1095Name: vmbus_msg_dpc()
1096
1097Desc: Tasklet routine to handle hypervisor events
1098
1099--*/
1100static void vmbus_event_dpc(unsigned long data)
1101{
1102 VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
1103
1104 DPRINT_ENTER(VMBUS_DRV);
1105
1106 ASSERT(vmbus_drv_obj->OnEventDpc != NULL);
1107
1108 // Call to bus driver to handle interrupt
1109 vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
1110
1111 DPRINT_EXIT(VMBUS_DRV);
1112}
1113
1114/*++
1115
1116Name: vmbus_msg_dpc()
1117
1118Desc: ISR routine
1119
1120--*/
1121#ifdef KERNEL_2_6_27
1122static irqreturn_t vmbus_isr(int irq, void* dev_id)
1123#else
1124static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs)
1125#endif
1126{
1127 int ret=0;
1128 VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj;
1129
1130 DPRINT_ENTER(VMBUS_DRV);
1131
1132 ASSERT(vmbus_driver_obj->OnIsr != NULL);
1133
1134 // Call to bus driver to handle interrupt
1135 ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
1136
1137 // Schedules a dpc if necessary
1138 if (ret > 0)
1139 {
1140 if (test_bit(0, (unsigned long*)&ret))
1141 {
1142 tasklet_schedule(&g_vmbus_drv.msg_dpc);
1143 }
1144
1145 if (test_bit(1, (unsigned long*)&ret))
1146 {
1147 tasklet_schedule(&g_vmbus_drv.event_dpc);
1148 }
1149
1150 DPRINT_EXIT(VMBUS_DRV);
1151 return IRQ_HANDLED;
1152 }
1153 else
1154 {
1155 DPRINT_EXIT(VMBUS_DRV);
1156 return IRQ_NONE;
1157 }
1158}
1159
1160MODULE_LICENSE("GPL");
1161
1162
1163/*++
1164
1165Name: vmbus_init()
1166
1167Desc: Main vmbus driver entry routine
1168
1169--*/
1170static int __init vmbus_init(void)
1171{
1172 int ret=0;
1173
1174 DPRINT_ENTER(VMBUS_DRV);
1175
1176 DPRINT_INFO(VMBUS_DRV,
1177 "Vmbus initializing.... current log level 0x%x (%x,%x)",
1178 vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
1179#ifdef KERNEL_2_6_27
1180//Todo: it is used for loglevel, to be ported to new kernel.
1181#else
1182 vmbus_ctl_table_hdr = register_sysctl_table(vmus_root_ctl_table, 0);
1183 if (!vmbus_ctl_table_hdr)
1184 {
1185 DPRINT_EXIT(VMBUS_DRV);
1186 return -ENOMEM;
1187 }
1188#endif
1189
1190 ret = vmbus_bus_init(VmbusInitialize);
1191
1192 DPRINT_EXIT(VMBUS_DRV);
1193 return ret;
1194}
1195
1196
1197
1198/*++
1199
1200Name: vmbus_init()
1201
1202Desc: Main vmbus driver exit routine
1203
1204--*/
1205static void __exit vmbus_exit(void)
1206{
1207 DPRINT_ENTER(VMBUS_DRV);
1208
1209 vmbus_bus_exit();
1210#ifdef KERNEL_2_6_27
1211//Todo: it is used for loglevel, to be ported to new kernel.
1212#else
1213 unregister_sysctl_table(vmbus_ctl_table_hdr);
1214#endif
1215 DPRINT_EXIT(VMBUS_DRV);
1216
1217 return;
1218}
1219
1220#if defined(KERNEL_2_6_5)
1221#else
1222module_param(vmbus_irq, int, S_IRUGO);
1223module_param(vmbus_loglevel, int, S_IRUGO);
1224#endif
1225
1226module_init(vmbus_init);
1227module_exit(vmbus_exit);
1228// eof