]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From foo@baz Mon Jul 13 16:02:34 PDT 2009 |
2 | Date: Mon, 13 Jul 2009 16:02:34 -0700 | |
3 | From: Hank Janssen <hjanssen@microsoft.com> | |
4 | Subject: Staging: hv: add the Hyper-V virtual bus | |
5 | ||
6 | From: Hank Janssen <hjanssen@microsoft.com> | |
7 | ||
8 | This is the virtual bus that all of the Linux Hyper-V drivers use. | |
9 | ||
10 | Signed-off-by: Hank Janssen <hjanssen@microsoft.com> | |
11 | Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> | |
12 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
13 | ||
14 | --- | |
15 | drivers/staging/hv/Channel.c | 1199 +++++++++++++++++++++++++++++++++ | |
16 | drivers/staging/hv/Channel.h | 157 ++++ | |
17 | drivers/staging/hv/ChannelInterface.c | 222 ++++++ | |
18 | drivers/staging/hv/ChannelInterface.h | 41 + | |
19 | drivers/staging/hv/ChannelMgmt.c | 826 ++++++++++++++++++++++ | |
20 | drivers/staging/hv/ChannelMgmt.h | 156 ++++ | |
21 | drivers/staging/hv/Connection.c | 432 +++++++++++ | |
22 | drivers/staging/hv/Hv.c | 672 ++++++++++++++++++ | |
23 | drivers/staging/hv/Hv.h | 184 +++++ | |
24 | drivers/staging/hv/RingBuffer.c | 630 +++++++++++++++++ | |
25 | drivers/staging/hv/RingBuffer.h | 123 +++ | |
26 | drivers/staging/hv/Sources.c | 31 | |
27 | drivers/staging/hv/VersionInfo.h | 29 | |
28 | drivers/staging/hv/Vmbus.c | 508 ++++++++++++++ | |
29 | drivers/staging/hv/VmbusPrivate.h | 170 ++++ | |
30 | drivers/staging/hv/osd.c | 500 +++++++++++++ | |
31 | drivers/staging/hv/vmbus_drv.c | 1228 ++++++++++++++++++++++++++++++++++ | |
32 | 17 files changed, 7108 insertions(+) | |
33 | ||
34 | --- /dev/null | |
35 | +++ b/drivers/staging/hv/Channel.c | |
36 | @@ -0,0 +1,1199 @@ | |
37 | +/* | |
38 | + * | |
39 | + * Copyright (c) 2009, Microsoft Corporation. | |
40 | + * | |
41 | + * This program is free software; you can redistribute it and/or modify it | |
42 | + * under the terms and conditions of the GNU General Public License, | |
43 | + * version 2, as published by the Free Software Foundation. | |
44 | + * | |
45 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
46 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
47 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
48 | + * more details. | |
49 | + * | |
50 | + * You should have received a copy of the GNU General Public License along with | |
51 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
52 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
53 | + * | |
54 | + * Authors: | |
55 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
56 | + * Hank Janssen <hjanssen@microsoft.com> | |
57 | + * | |
58 | + */ | |
59 | + | |
60 | + | |
61 | +#include "osd.h" | |
62 | +#include "logging.h" | |
63 | + | |
64 | +#include "VmbusPrivate.h" | |
65 | + | |
66 | +// | |
67 | +// Internal routines | |
68 | +// | |
69 | +static int | |
70 | +VmbusChannelCreateGpadlHeader( | |
71 | + PVOID Kbuffer, // must be phys and virt contiguous | |
72 | + UINT32 Size, // page-size multiple | |
73 | + VMBUS_CHANNEL_MSGINFO **msgInfo, | |
74 | + UINT32 *MessageCount | |
75 | + ); | |
76 | + | |
77 | +static void | |
78 | +DumpVmbusChannel( | |
79 | + VMBUS_CHANNEL *Channel | |
80 | + ); | |
81 | + | |
82 | + | |
83 | +static void | |
84 | +VmbusChannelSetEvent( | |
85 | + VMBUS_CHANNEL *Channel | |
86 | + ); | |
87 | + | |
88 | + | |
89 | +#if 0 | |
90 | +static void | |
91 | +DumpMonitorPage( | |
92 | + HV_MONITOR_PAGE *MonitorPage | |
93 | + ) | |
94 | +{ | |
95 | + int i=0; | |
96 | + int j=0; | |
97 | + | |
98 | + DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState); | |
99 | + | |
100 | + for (i=0; i<4; i++) | |
101 | + { | |
102 | + DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64); | |
103 | + } | |
104 | + | |
105 | + for (i=0; i<4; i++) | |
106 | + { | |
107 | + for (j=0; j<32; j++) | |
108 | + { | |
109 | + DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]); | |
110 | + } | |
111 | + } | |
112 | + for (i=0; i<4; i++) | |
113 | + { | |
114 | + for (j=0; j<32; j++) | |
115 | + { | |
116 | + DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].ConnectionId.AsUINT32); | |
117 | + DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].FlagNumber); | |
118 | + | |
119 | + } | |
120 | + } | |
121 | +} | |
122 | +#endif | |
123 | + | |
124 | +/*++ | |
125 | + | |
126 | +Name: | |
127 | + VmbusChannelSetEvent() | |
128 | + | |
129 | +Description: | |
130 | + Trigger an event notification on the specified channel. | |
131 | + | |
132 | +--*/ | |
133 | +static void | |
134 | +VmbusChannelSetEvent( | |
135 | + VMBUS_CHANNEL *Channel | |
136 | + ) | |
137 | +{ | |
138 | + HV_MONITOR_PAGE *monitorPage; | |
139 | + | |
140 | + DPRINT_ENTER(VMBUS); | |
141 | + | |
142 | + if (Channel->OfferMsg.MonitorAllocated) | |
143 | + { | |
144 | + // Each UINT32 represents 32 channels | |
145 | + BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31); | |
146 | + | |
147 | + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; | |
148 | + monitorPage++; // Get the child to parent monitor page | |
149 | + | |
150 | + BitSet((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit); | |
151 | + } | |
152 | + else | |
153 | + { | |
154 | + VmbusSetEvent(Channel->OfferMsg.ChildRelId); | |
155 | + } | |
156 | + | |
157 | + DPRINT_EXIT(VMBUS); | |
158 | +} | |
159 | + | |
160 | +#if 0 | |
161 | +static void | |
162 | +VmbusChannelClearEvent( | |
163 | + VMBUS_CHANNEL *Channel | |
164 | + ) | |
165 | +{ | |
166 | + HV_MONITOR_PAGE *monitorPage; | |
167 | + | |
168 | + DPRINT_ENTER(VMBUS); | |
169 | + | |
170 | + if (Channel->OfferMsg.MonitorAllocated) | |
171 | + { | |
172 | + // Each UINT32 represents 32 channels | |
173 | + BitClear((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31); | |
174 | + | |
175 | + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; | |
176 | + monitorPage++; // Get the child to parent monitor page | |
177 | + | |
178 | + BitClear((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit); | |
179 | + } | |
180 | + | |
181 | + DPRINT_EXIT(VMBUS); | |
182 | +} | |
183 | + | |
184 | +#endif | |
185 | +/*++; | |
186 | + | |
187 | +Name: | |
188 | + VmbusChannelGetDebugInfo() | |
189 | + | |
190 | +Description: | |
191 | + Retrieve various channel debug info | |
192 | + | |
193 | +--*/ | |
194 | +void | |
195 | +VmbusChannelGetDebugInfo( | |
196 | + VMBUS_CHANNEL *Channel, | |
197 | + VMBUS_CHANNEL_DEBUG_INFO *DebugInfo | |
198 | + ) | |
199 | +{ | |
200 | + HV_MONITOR_PAGE *monitorPage; | |
201 | + UINT8 monitorGroup = (UINT8)Channel->OfferMsg.MonitorId / 32; | |
202 | + UINT8 monitorOffset = (UINT8)Channel->OfferMsg.MonitorId % 32; | |
203 | + //UINT32 monitorBit = 1 << monitorOffset; | |
204 | + | |
205 | + DebugInfo->RelId = Channel->OfferMsg.ChildRelId; | |
206 | + DebugInfo->State = Channel->State; | |
207 | + memcpy(&DebugInfo->InterfaceType, &Channel->OfferMsg.Offer.InterfaceType, sizeof(GUID)); | |
208 | + memcpy(&DebugInfo->InterfaceInstance, &Channel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID)); | |
209 | + | |
210 | + monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; | |
211 | + | |
212 | + DebugInfo->MonitorId = Channel->OfferMsg.MonitorId; | |
213 | + | |
214 | + DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending; | |
215 | + DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset]; | |
216 | + DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id; | |
217 | + | |
218 | + monitorPage++; | |
219 | + | |
220 | + DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending; | |
221 | + DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset]; | |
222 | + DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id; | |
223 | + | |
224 | + RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound); | |
225 | + RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound); | |
226 | +} | |
227 | + | |
228 | + | |
229 | +/*++; | |
230 | + | |
231 | +Name: | |
232 | + VmbusChannelOpen() | |
233 | + | |
234 | +Description: | |
235 | + Open the specified channel. | |
236 | + | |
237 | +--*/ | |
238 | +int | |
239 | +VmbusChannelOpen( | |
240 | + VMBUS_CHANNEL *NewChannel, | |
241 | + UINT32 SendRingBufferSize, | |
242 | + UINT32 RecvRingBufferSize, | |
243 | + PVOID UserData, | |
244 | + UINT32 UserDataLen, | |
245 | + PFN_CHANNEL_CALLBACK pfnOnChannelCallback, | |
246 | + PVOID Context | |
247 | + ) | |
248 | +{ | |
249 | + int ret=0; | |
250 | + VMBUS_CHANNEL_OPEN_CHANNEL* openMsg; | |
251 | + VMBUS_CHANNEL_MSGINFO* openInfo; | |
252 | + void *in, *out; | |
253 | + | |
254 | + DPRINT_ENTER(VMBUS); | |
255 | + | |
256 | + // Aligned to page size | |
257 | + ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1))); | |
258 | + ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1))); | |
259 | + | |
260 | + NewChannel->OnChannelCallback = pfnOnChannelCallback; | |
261 | + NewChannel->ChannelCallbackContext = Context; | |
262 | + | |
263 | + // Allocate the ring buffer | |
264 | + out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT); | |
265 | + //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize); | |
266 | + ASSERT(out); | |
267 | + ASSERT(((ULONG_PTR)out & (PAGE_SIZE-1)) == 0); | |
268 | + | |
269 | + in = (void*)((ULONG_PTR)out + SendRingBufferSize); | |
270 | + | |
271 | + NewChannel->RingBufferPages = out; | |
272 | + NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT; | |
273 | + | |
274 | + RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize); | |
275 | + | |
276 | + RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize); | |
277 | + | |
278 | + // Establish the gpadl for the ring buffer | |
279 | + DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel); | |
280 | + | |
281 | + NewChannel->RingBufferGpadlHandle = 0; | |
282 | + | |
283 | + ret = VmbusChannelEstablishGpadl(NewChannel, | |
284 | + NewChannel->Outbound.RingBuffer, | |
285 | + SendRingBufferSize + RecvRingBufferSize, | |
286 | + &NewChannel->RingBufferGpadlHandle); | |
287 | + | |
288 | + DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p size %d recv ring %p size %d, downstreamoffset %d>", | |
289 | + NewChannel, | |
290 | + NewChannel->OfferMsg.ChildRelId, | |
291 | + NewChannel->RingBufferGpadlHandle, | |
292 | + NewChannel->Outbound.RingBuffer, | |
293 | + NewChannel->Outbound.RingSize, | |
294 | + NewChannel->Inbound.RingBuffer, | |
295 | + NewChannel->Inbound.RingSize, | |
296 | + SendRingBufferSize); | |
297 | + | |
298 | + // Create and init the channel open message | |
299 | + openInfo = | |
300 | + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL)); | |
301 | + ASSERT(openInfo != NULL); | |
302 | + | |
303 | + openInfo->WaitEvent = WaitEventCreate(); | |
304 | + | |
305 | + openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)openInfo->Msg; | |
306 | + openMsg->Header.MessageType = ChannelMessageOpenChannel; | |
307 | + openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; // FIXME | |
308 | + openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId; | |
309 | + openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle; | |
310 | + ASSERT(openMsg->RingBufferGpadlHandle); | |
311 | + openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >> PAGE_SHIFT; | |
312 | + openMsg->ServerContextAreaGpadlHandle = 0; // TODO | |
313 | + | |
314 | + ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES); | |
315 | + if (UserDataLen) | |
316 | + { | |
317 | + memcpy(openMsg->UserData, UserData, UserDataLen); | |
318 | + } | |
319 | + | |
320 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
321 | + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry); | |
322 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
323 | + | |
324 | + DPRINT_DBG(VMBUS, "Sending channel open msg..."); | |
325 | + | |
326 | + ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL)); | |
327 | + if (ret != 0) | |
328 | + { | |
329 | + DPRINT_ERR(VMBUS, "unable to open channel - %d", ret); | |
330 | + goto Cleanup; | |
331 | + } | |
332 | + | |
333 | + // FIXME: Need to time-out here | |
334 | + WaitEventWait(openInfo->WaitEvent); | |
335 | + | |
336 | + if (openInfo->Response.OpenResult.Status == 0) | |
337 | + { | |
338 | + DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel); | |
339 | + } | |
340 | + else | |
341 | + { | |
342 | + DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status); | |
343 | + } | |
344 | + | |
345 | +Cleanup: | |
346 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
347 | + REMOVE_ENTRY_LIST(&openInfo->MsgListEntry); | |
348 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
349 | + | |
350 | + WaitEventClose(openInfo->WaitEvent); | |
351 | + MemFree(openInfo); | |
352 | + | |
353 | + DPRINT_EXIT(VMBUS); | |
354 | + | |
355 | + return 0; | |
356 | +} | |
357 | + | |
358 | +/*++; | |
359 | + | |
360 | +Name: | |
361 | + DumpGpadlBody() | |
362 | + | |
363 | +Description: | |
364 | + Dump the gpadl body message to the console for debugging purposes. | |
365 | + | |
366 | +--*/ | |
367 | +static void DumpGpadlBody( | |
368 | + VMBUS_CHANNEL_GPADL_BODY *Gpadl, | |
369 | + UINT32 Len) | |
370 | +{ | |
371 | + int i=0; | |
372 | + int pfnCount=0; | |
373 | + | |
374 | + pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(UINT64); | |
375 | + DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount); | |
376 | + | |
377 | + for (i=0; i< pfnCount; i++) | |
378 | + { | |
379 | + DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]); | |
380 | + } | |
381 | +} | |
382 | + | |
383 | + | |
384 | +/*++; | |
385 | + | |
386 | +Name: | |
387 | + DumpGpadlHeader() | |
388 | + | |
389 | +Description: | |
390 | + Dump the gpadl header message to the console for debugging purposes. | |
391 | + | |
392 | +--*/ | |
393 | +static void DumpGpadlHeader( | |
394 | + VMBUS_CHANNEL_GPADL_HEADER *Gpadl | |
395 | + ) | |
396 | +{ | |
397 | + int i=0,j=0; | |
398 | + int pageCount=0; | |
399 | + | |
400 | + | |
401 | + DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d", | |
402 | + Gpadl->ChildRelId, | |
403 | + Gpadl->RangeCount, | |
404 | + Gpadl->RangeBufLen); | |
405 | + for (i=0; i< Gpadl->RangeCount; i++) | |
406 | + { | |
407 | + pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT; | |
408 | + pageCount = (pageCount > 26)? 26 : pageCount; | |
409 | + | |
410 | + DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d page count %d", | |
411 | + i, Gpadl->Range[i].ByteCount, Gpadl->Range[i].ByteOffset, pageCount); | |
412 | + | |
413 | + for (j=0; j< pageCount; j++) | |
414 | + { | |
415 | + DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]); | |
416 | + } | |
417 | + } | |
418 | +} | |
419 | + | |
420 | +/*++; | |
421 | + | |
422 | +Name: | |
423 | + VmbusChannelCreateGpadlHeader() | |
424 | + | |
425 | +Description: | |
426 | + Creates a gpadl for the specified buffer | |
427 | + | |
428 | +--*/ | |
429 | +static int | |
430 | +VmbusChannelCreateGpadlHeader( | |
431 | + PVOID Kbuffer, // from kmalloc() | |
432 | + UINT32 Size, // page-size multiple | |
433 | + VMBUS_CHANNEL_MSGINFO **MsgInfo, | |
434 | + UINT32 *MessageCount) | |
435 | +{ | |
436 | + int i; | |
437 | + int pageCount; | |
438 | + unsigned long long pfn; | |
439 | + VMBUS_CHANNEL_GPADL_HEADER* gpaHeader; | |
440 | + VMBUS_CHANNEL_GPADL_BODY* gpadlBody; | |
441 | + VMBUS_CHANNEL_MSGINFO* msgHeader; | |
442 | + VMBUS_CHANNEL_MSGINFO* msgBody; | |
443 | + UINT32 msgSize; | |
444 | + | |
445 | + int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize; | |
446 | + | |
447 | + //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0); | |
448 | + ASSERT( (Size & (PAGE_SIZE-1)) == 0); | |
449 | + | |
450 | + pageCount = Size >> PAGE_SHIFT; | |
451 | + pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT; | |
452 | + | |
453 | + // do we need a gpadl body msg | |
454 | + pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_HEADER) - sizeof(GPA_RANGE); | |
455 | + pfnCount = pfnSize / sizeof(UINT64); | |
456 | + | |
457 | + if (pageCount > pfnCount) // we need a gpadl body | |
458 | + { | |
459 | + // fill in the header | |
460 | + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pfnCount*sizeof(UINT64); | |
461 | + msgHeader = MemAllocZeroed(msgSize); | |
462 | + | |
463 | + INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList); | |
464 | + msgHeader->MessageSize=msgSize; | |
465 | + | |
466 | + gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg; | |
467 | + gpaHeader->RangeCount = 1; | |
468 | + gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); | |
469 | + gpaHeader->Range[0].ByteOffset = 0; | |
470 | + gpaHeader->Range[0].ByteCount = Size; | |
471 | + for (i=0; i<pfnCount; i++) | |
472 | + { | |
473 | + gpaHeader->Range[0].PfnArray[i] = pfn+i; | |
474 | + } | |
475 | + *MsgInfo = msgHeader; | |
476 | + *MessageCount = 1; | |
477 | + | |
478 | + pfnSum = pfnCount; | |
479 | + pfnLeft = pageCount - pfnCount; | |
480 | + | |
481 | + // how many pfns can we fit | |
482 | + pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY); | |
483 | + pfnCount = pfnSize / sizeof(UINT64); | |
484 | + | |
485 | + // fill in the body | |
486 | + while (pfnLeft) | |
487 | + { | |
488 | + if (pfnLeft > pfnCount) | |
489 | + { | |
490 | + pfnCurr = pfnCount; | |
491 | + } | |
492 | + else | |
493 | + { | |
494 | + pfnCurr = pfnLeft; | |
495 | + } | |
496 | + | |
497 | + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(UINT64); | |
498 | + msgBody = MemAllocZeroed(msgSize); | |
499 | + ASSERT(msgBody); | |
500 | + msgBody->MessageSize = msgSize; | |
501 | + (*MessageCount)++; | |
502 | + gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg; | |
503 | + | |
504 | + // FIXME: Gpadl is UINT32 and we are using a pointer which could be 64-bit | |
505 | + //gpadlBody->Gpadl = kbuffer; | |
506 | + for (i=0; i<pfnCurr; i++) | |
507 | + { | |
508 | + gpadlBody->Pfn[i] = pfn + pfnSum + i; | |
509 | + } | |
510 | + | |
511 | + // add to msg header | |
512 | + INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry); | |
513 | + pfnSum += pfnCurr; | |
514 | + pfnLeft -= pfnCurr; | |
515 | + } | |
516 | + } | |
517 | + else | |
518 | + { | |
519 | + // everything fits in a header | |
520 | + msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); | |
521 | + msgHeader = MemAllocZeroed(msgSize); | |
522 | + msgHeader->MessageSize=msgSize; | |
523 | + | |
524 | + gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg; | |
525 | + gpaHeader->RangeCount = 1; | |
526 | + gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); | |
527 | + gpaHeader->Range[0].ByteOffset = 0; | |
528 | + gpaHeader->Range[0].ByteCount = Size; | |
529 | + for (i=0; i<pageCount; i++) | |
530 | + { | |
531 | + gpaHeader->Range[0].PfnArray[i] = pfn+i; | |
532 | + } | |
533 | + | |
534 | + *MsgInfo = msgHeader; | |
535 | + *MessageCount = 1; | |
536 | + } | |
537 | + | |
538 | + return 0; | |
539 | +} | |
540 | + | |
541 | + | |
542 | +/*++; | |
543 | + | |
544 | +Name: | |
545 | + VmbusChannelEstablishGpadl() | |
546 | + | |
547 | +Description: | |
548 | + Estabish a GPADL for the specified buffer | |
549 | + | |
550 | +--*/ | |
551 | +int | |
552 | +VmbusChannelEstablishGpadl( | |
553 | + VMBUS_CHANNEL *Channel, | |
554 | + PVOID Kbuffer, // from kmalloc() | |
555 | + UINT32 Size, // page-size multiple | |
556 | + UINT32 *GpadlHandle | |
557 | + ) | |
558 | +{ | |
559 | + int ret=0; | |
560 | + VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg; | |
561 | + VMBUS_CHANNEL_GPADL_BODY* gpadlBody; | |
562 | + //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated; | |
563 | + | |
564 | + VMBUS_CHANNEL_MSGINFO *msgInfo; | |
565 | + VMBUS_CHANNEL_MSGINFO *subMsgInfo; | |
566 | + | |
567 | + UINT32 msgCount; | |
568 | + LIST_ENTRY* anchor; | |
569 | + LIST_ENTRY* curr; | |
570 | + UINT32 nextGpadlHandle; | |
571 | + | |
572 | + DPRINT_ENTER(VMBUS); | |
573 | + | |
574 | + nextGpadlHandle = gVmbusConnection.NextGpadlHandle; | |
575 | + InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle); | |
576 | + | |
577 | + VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount); | |
578 | + ASSERT(msgInfo != NULL); | |
579 | + ASSERT(msgCount >0); | |
580 | + | |
581 | + msgInfo->WaitEvent = WaitEventCreate(); | |
582 | + gpadlMsg = (VMBUS_CHANNEL_GPADL_HEADER*)msgInfo->Msg; | |
583 | + gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader; | |
584 | + gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId; | |
585 | + gpadlMsg->Gpadl = nextGpadlHandle; | |
586 | + | |
587 | + DumpGpadlHeader(gpadlMsg); | |
588 | + | |
589 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
590 | + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry); | |
591 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
592 | + | |
593 | + DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount); | |
594 | + | |
595 | + DPRINT_DBG(VMBUS, "Sending GPADL Header - len %d", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | |
596 | + | |
597 | + ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | |
598 | + if (ret != 0) | |
599 | + { | |
600 | + DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret); | |
601 | + goto Cleanup; | |
602 | + } | |
603 | + | |
604 | + if (msgCount>1) | |
605 | + { | |
606 | + ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList) | |
607 | + { | |
608 | + subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | |
609 | + gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg; | |
610 | + | |
611 | + gpadlBody->Header.MessageType = ChannelMessageGpadlBody; | |
612 | + gpadlBody->Gpadl = nextGpadlHandle; | |
613 | + | |
614 | + DPRINT_DBG(VMBUS, "Sending GPADL Body - len %d", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | |
615 | + | |
616 | + DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | |
617 | + ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); | |
618 | + ASSERT(ret == 0); | |
619 | + } | |
620 | + } | |
621 | + WaitEventWait(msgInfo->WaitEvent); | |
622 | + | |
623 | + // At this point, we received the gpadl created msg | |
624 | + DPRINT_DBG(VMBUS, "Received GPADL created (relid %d, status %d handle %x)", | |
625 | + Channel->OfferMsg.ChildRelId, | |
626 | + msgInfo->Response.GpadlCreated.CreationStatus, | |
627 | + gpadlMsg->Gpadl); | |
628 | + | |
629 | + *GpadlHandle = gpadlMsg->Gpadl; | |
630 | + | |
631 | +Cleanup: | |
632 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
633 | + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); | |
634 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
635 | + | |
636 | + WaitEventClose(msgInfo->WaitEvent); | |
637 | + MemFree(msgInfo); | |
638 | + | |
639 | + DPRINT_EXIT(VMBUS); | |
640 | + | |
641 | + return ret; | |
642 | +} | |
643 | + | |
644 | + | |
645 | + | |
646 | +/*++; | |
647 | + | |
648 | +Name: | |
649 | + VmbusChannelTeardownGpadl() | |
650 | + | |
651 | +Description: | |
652 | + Teardown the specified GPADL handle | |
653 | + | |
654 | +--*/ | |
655 | +int | |
656 | +VmbusChannelTeardownGpadl( | |
657 | + VMBUS_CHANNEL *Channel, | |
658 | + UINT32 GpadlHandle | |
659 | + ) | |
660 | +{ | |
661 | + int ret=0; | |
662 | + VMBUS_CHANNEL_GPADL_TEARDOWN *msg; | |
663 | + VMBUS_CHANNEL_MSGINFO* info; | |
664 | + | |
665 | + DPRINT_ENTER(VMBUS); | |
666 | + | |
667 | + ASSERT(GpadlHandle != 0); | |
668 | + | |
669 | + info = | |
670 | + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN)); | |
671 | + ASSERT(info != NULL); | |
672 | + | |
673 | + info->WaitEvent = WaitEventCreate(); | |
674 | + | |
675 | + msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg; | |
676 | + | |
677 | + msg->Header.MessageType = ChannelMessageGpadlTeardown; | |
678 | + msg->ChildRelId = Channel->OfferMsg.ChildRelId; | |
679 | + msg->Gpadl = GpadlHandle; | |
680 | + | |
681 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
682 | + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry); | |
683 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
684 | + | |
685 | + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN)); | |
686 | + if (ret != 0) | |
687 | + { | |
688 | + // TODO: | |
689 | + } | |
690 | + | |
691 | + WaitEventWait(info->WaitEvent); | |
692 | + | |
693 | + // Received a torndown response | |
694 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
695 | + REMOVE_ENTRY_LIST(&info->MsgListEntry); | |
696 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
697 | + | |
698 | + WaitEventClose(info->WaitEvent); | |
699 | + MemFree(info); | |
700 | + | |
701 | + DPRINT_EXIT(VMBUS); | |
702 | + | |
703 | + return ret; | |
704 | +} | |
705 | + | |
706 | + | |
707 | +/*++ | |
708 | + | |
709 | +Name: | |
710 | + VmbusChannelClose() | |
711 | + | |
712 | +Description: | |
713 | + Close the specified channel | |
714 | + | |
715 | +--*/ | |
716 | +VOID | |
717 | +VmbusChannelClose( | |
718 | + VMBUS_CHANNEL *Channel | |
719 | + ) | |
720 | +{ | |
721 | + int ret=0; | |
722 | + VMBUS_CHANNEL_CLOSE_CHANNEL* msg; | |
723 | + VMBUS_CHANNEL_MSGINFO* info; | |
724 | + | |
725 | + DPRINT_ENTER(VMBUS); | |
726 | + | |
727 | + // Stop callback and cancel the timer asap | |
728 | + Channel->OnChannelCallback = NULL; | |
729 | + TimerStop(Channel->PollTimer); | |
730 | + | |
731 | + // Send a closing message | |
732 | + info = | |
733 | + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL)); | |
734 | + ASSERT(info != NULL); | |
735 | + | |
736 | + //info->waitEvent = WaitEventCreate(); | |
737 | + | |
738 | + msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg; | |
739 | + msg->Header.MessageType = ChannelMessageCloseChannel; | |
740 | + msg->ChildRelId = Channel->OfferMsg.ChildRelId; | |
741 | + | |
742 | + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL)); | |
743 | + if (ret != 0) | |
744 | + { | |
745 | + // TODO: | |
746 | + } | |
747 | + | |
748 | + // Tear down the gpadl for the channel's ring buffer | |
749 | + if (Channel->RingBufferGpadlHandle) | |
750 | + { | |
751 | + VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle); | |
752 | + } | |
753 | + | |
754 | + // TODO: Send a msg to release the childRelId | |
755 | + | |
756 | + // Cleanup the ring buffers for this channel | |
757 | + RingBufferCleanup(&Channel->Outbound); | |
758 | + RingBufferCleanup(&Channel->Inbound); | |
759 | + | |
760 | + PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount); | |
761 | + | |
762 | + MemFree(info); | |
763 | + | |
764 | + // If we are closing the channel during an error path in opening the channel, don't free the channel | |
765 | + // since the caller will free the channel | |
766 | + if (Channel->State == CHANNEL_OPEN_STATE) | |
767 | + { | |
768 | + SpinlockAcquire(gVmbusConnection.ChannelLock); | |
769 | + REMOVE_ENTRY_LIST(&Channel->ListEntry); | |
770 | + SpinlockRelease(gVmbusConnection.ChannelLock); | |
771 | + | |
772 | + FreeVmbusChannel(Channel); | |
773 | + } | |
774 | + | |
775 | + DPRINT_EXIT(VMBUS); | |
776 | +} | |
777 | + | |
778 | + | |
779 | +/*++ | |
780 | + | |
781 | +Name: | |
782 | + VmbusChannelSendPacket() | |
783 | + | |
784 | +Description: | |
785 | + Send the specified buffer on the given channel | |
786 | + | |
787 | +--*/ | |
788 | +int | |
789 | +VmbusChannelSendPacket( | |
790 | + VMBUS_CHANNEL *Channel, | |
791 | + const PVOID Buffer, | |
792 | + UINT32 BufferLen, | |
793 | + UINT64 RequestId, | |
794 | + VMBUS_PACKET_TYPE Type, | |
795 | + UINT32 Flags | |
796 | +) | |
797 | +{ | |
798 | + int ret=0; | |
799 | + VMPACKET_DESCRIPTOR desc; | |
800 | + UINT32 packetLen = sizeof(VMPACKET_DESCRIPTOR) + BufferLen; | |
801 | + UINT32 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); | |
802 | + SG_BUFFER_LIST bufferList[3]; | |
803 | + UINT64 alignedData=0; | |
804 | + | |
805 | + DPRINT_ENTER(VMBUS); | |
806 | + DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen); | |
807 | + | |
808 | + DumpVmbusChannel(Channel); | |
809 | + | |
810 | + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); | |
811 | + | |
812 | + // Setup the descriptor | |
813 | + desc.Type = Type;//VmbusPacketTypeDataInBand; | |
814 | + desc.Flags = Flags;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | |
815 | + desc.DataOffset8 = sizeof(VMPACKET_DESCRIPTOR) >> 3; // in 8-bytes granularity | |
816 | + desc.Length8 = (UINT16)(packetLenAligned >> 3); | |
817 | + desc.TransactionId = RequestId; | |
818 | + | |
819 | + bufferList[0].Data = &desc; | |
820 | + bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR); | |
821 | + | |
822 | + bufferList[1].Data = Buffer; | |
823 | + bufferList[1].Length = BufferLen; | |
824 | + | |
825 | + bufferList[2].Data = &alignedData; | |
826 | + bufferList[2].Length = packetLenAligned - packetLen; | |
827 | + | |
828 | + ret = RingBufferWrite( | |
829 | + &Channel->Outbound, | |
830 | + bufferList, | |
831 | + 3); | |
832 | + | |
833 | + // TODO: We should determine if this is optional | |
834 | + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) | |
835 | + { | |
836 | + VmbusChannelSetEvent(Channel); | |
837 | + } | |
838 | + | |
839 | + DPRINT_EXIT(VMBUS); | |
840 | + | |
841 | + return ret; | |
842 | +} | |
843 | + | |
844 | + | |
845 | +/*++ | |
846 | + | |
847 | +Name: | |
848 | + VmbusChannelSendPacketPageBuffer() | |
849 | + | |
850 | +Description: | |
851 | + Send a range of single-page buffer packets using a GPADL Direct packet type. | |
852 | + | |
853 | +--*/ | |
854 | +int | |
855 | +VmbusChannelSendPacketPageBuffer( | |
856 | + VMBUS_CHANNEL *Channel, | |
857 | + PAGE_BUFFER PageBuffers[], | |
858 | + UINT32 PageCount, | |
859 | + PVOID Buffer, | |
860 | + UINT32 BufferLen, | |
861 | + UINT64 RequestId | |
862 | +) | |
863 | +{ | |
864 | + int ret=0; | |
865 | + int i=0; | |
866 | + VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc; | |
867 | + UINT32 descSize; | |
868 | + UINT32 packetLen; | |
869 | + UINT32 packetLenAligned; | |
870 | + SG_BUFFER_LIST bufferList[3]; | |
871 | + UINT64 alignedData=0; | |
872 | + | |
873 | + DPRINT_ENTER(VMBUS); | |
874 | + | |
875 | + ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT); | |
876 | + | |
877 | + DumpVmbusChannel(Channel); | |
878 | + | |
879 | + // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support | |
880 | + descSize = sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER) - ((MAX_PAGE_BUFFER_COUNT - PageCount)*sizeof(PAGE_BUFFER)); | |
881 | + packetLen = descSize + BufferLen; | |
882 | + packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); | |
883 | + | |
884 | + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); | |
885 | + | |
886 | + // Setup the descriptor | |
887 | + desc.Type = VmbusPacketTypeDataUsingGpaDirect; | |
888 | + desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | |
889 | + desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity | |
890 | + desc.Length8 = (UINT16)(packetLenAligned >> 3); | |
891 | + desc.TransactionId = RequestId; | |
892 | + desc.RangeCount = PageCount; | |
893 | + | |
894 | + for (i=0; i<PageCount; i++) | |
895 | + { | |
896 | + desc.Range[i].Length = PageBuffers[i].Length; | |
897 | + desc.Range[i].Offset = PageBuffers[i].Offset; | |
898 | + desc.Range[i].Pfn = PageBuffers[i].Pfn; | |
899 | + } | |
900 | + | |
901 | + bufferList[0].Data = &desc; | |
902 | + bufferList[0].Length = descSize; | |
903 | + | |
904 | + bufferList[1].Data = Buffer; | |
905 | + bufferList[1].Length = BufferLen; | |
906 | + | |
907 | + bufferList[2].Data = &alignedData; | |
908 | + bufferList[2].Length = packetLenAligned - packetLen; | |
909 | + | |
910 | + ret = RingBufferWrite( | |
911 | + &Channel->Outbound, | |
912 | + bufferList, | |
913 | + 3); | |
914 | + | |
915 | + // TODO: We should determine if this is optional | |
916 | + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) | |
917 | + { | |
918 | + VmbusChannelSetEvent(Channel); | |
919 | + } | |
920 | + | |
921 | + DPRINT_EXIT(VMBUS); | |
922 | + | |
923 | + return ret; | |
924 | +} | |
925 | + | |
926 | + | |
927 | + | |
928 | +/*++ | |
929 | + | |
930 | +Name: | |
931 | + VmbusChannelSendPacketMultiPageBuffer() | |
932 | + | |
933 | +Description: | |
934 | + Send a multi-page buffer packet using a GPADL Direct packet type. | |
935 | + | |
936 | +--*/ | |
937 | +int | |
938 | +VmbusChannelSendPacketMultiPageBuffer( | |
939 | + VMBUS_CHANNEL *Channel, | |
940 | + MULTIPAGE_BUFFER *MultiPageBuffer, | |
941 | + PVOID Buffer, | |
942 | + UINT32 BufferLen, | |
943 | + UINT64 RequestId | |
944 | +) | |
945 | +{ | |
946 | + int ret=0; | |
947 | + VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc; | |
948 | + UINT32 descSize; | |
949 | + UINT32 packetLen; | |
950 | + UINT32 packetLenAligned; | |
951 | + SG_BUFFER_LIST bufferList[3]; | |
952 | + UINT64 alignedData=0; | |
953 | + UINT32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length); | |
954 | + | |
955 | + DPRINT_ENTER(VMBUS); | |
956 | + | |
957 | + DumpVmbusChannel(Channel); | |
958 | + | |
959 | + DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount); | |
960 | + | |
961 | + ASSERT(PfnCount > 0); | |
962 | + ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT); | |
963 | + | |
964 | + // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support | |
965 | + descSize = sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) - ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount)*sizeof(UINT64)); | |
966 | + packetLen = descSize + BufferLen; | |
967 | + packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); | |
968 | + | |
969 | + ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); | |
970 | + | |
971 | + // Setup the descriptor | |
972 | + desc.Type = VmbusPacketTypeDataUsingGpaDirect; | |
973 | + desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | |
974 | + desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity | |
975 | + desc.Length8 = (UINT16)(packetLenAligned >> 3); | |
976 | + desc.TransactionId = RequestId; | |
977 | + desc.RangeCount = 1; | |
978 | + | |
979 | + desc.Range.Length = MultiPageBuffer->Length; | |
980 | + desc.Range.Offset = MultiPageBuffer->Offset; | |
981 | + | |
982 | + memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(UINT64)); | |
983 | + | |
984 | + bufferList[0].Data = &desc; | |
985 | + bufferList[0].Length = descSize; | |
986 | + | |
987 | + bufferList[1].Data = Buffer; | |
988 | + bufferList[1].Length = BufferLen; | |
989 | + | |
990 | + bufferList[2].Data = &alignedData; | |
991 | + bufferList[2].Length = packetLenAligned - packetLen; | |
992 | + | |
993 | + ret = RingBufferWrite( | |
994 | + &Channel->Outbound, | |
995 | + bufferList, | |
996 | + 3); | |
997 | + | |
998 | + // TODO: We should determine if this is optional | |
999 | + if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) | |
1000 | + { | |
1001 | + VmbusChannelSetEvent(Channel); | |
1002 | + } | |
1003 | + | |
1004 | + DPRINT_EXIT(VMBUS); | |
1005 | + | |
1006 | + return ret; | |
1007 | +} | |
1008 | + | |
1009 | + | |
1010 | +/*++ | |
1011 | + | |
1012 | +Name: | |
1013 | + VmbusChannelRecvPacket() | |
1014 | + | |
1015 | +Description: | |
1016 | + Retrieve the user packet on the specified channel | |
1017 | + | |
1018 | +--*/ | |
1019 | +// TODO: Do we ever receive a gpa direct packet other than the ones we send ? | |
1020 | +int | |
1021 | +VmbusChannelRecvPacket( | |
1022 | + VMBUS_CHANNEL *Channel, | |
1023 | + PVOID Buffer, | |
1024 | + UINT32 BufferLen, | |
1025 | + UINT32* BufferActualLen, | |
1026 | + UINT64* RequestId | |
1027 | + ) | |
1028 | +{ | |
1029 | + VMPACKET_DESCRIPTOR desc; | |
1030 | + UINT32 packetLen; | |
1031 | + UINT32 userLen; | |
1032 | + int ret; | |
1033 | + | |
1034 | + DPRINT_ENTER(VMBUS); | |
1035 | + | |
1036 | + *BufferActualLen = 0; | |
1037 | + *RequestId = 0; | |
1038 | + | |
1039 | + SpinlockAcquire(Channel->InboundLock); | |
1040 | + | |
1041 | + ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR)); | |
1042 | + if (ret != 0) | |
1043 | + { | |
1044 | + SpinlockRelease(Channel->InboundLock); | |
1045 | + | |
1046 | + //DPRINT_DBG(VMBUS, "nothing to read!!"); | |
1047 | + DPRINT_EXIT(VMBUS); | |
1048 | + return 0; | |
1049 | + } | |
1050 | + | |
1051 | + //VmbusChannelClearEvent(Channel); | |
1052 | + | |
1053 | + packetLen = desc.Length8 << 3; | |
1054 | + userLen = packetLen - (desc.DataOffset8 << 3); | |
1055 | + //ASSERT(userLen > 0); | |
1056 | + | |
1057 | + DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ", | |
1058 | + Channel, | |
1059 | + Channel->OfferMsg.ChildRelId, | |
1060 | + desc.Type, | |
1061 | + desc.Flags, | |
1062 | + desc.TransactionId, packetLen, userLen); | |
1063 | + | |
1064 | + *BufferActualLen = userLen; | |
1065 | + | |
1066 | + if (userLen > BufferLen) | |
1067 | + { | |
1068 | + SpinlockRelease(Channel->InboundLock); | |
1069 | + | |
1070 | + DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen); | |
1071 | + DPRINT_EXIT(VMBUS); | |
1072 | + | |
1073 | + return -1; | |
1074 | + } | |
1075 | + | |
1076 | + *RequestId = desc.TransactionId; | |
1077 | + | |
1078 | + // Copy over the packet to the user buffer | |
1079 | + ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3)); | |
1080 | + | |
1081 | + SpinlockRelease(Channel->InboundLock); | |
1082 | + | |
1083 | + DPRINT_EXIT(VMBUS); | |
1084 | + | |
1085 | + return 0; | |
1086 | +} | |
1087 | + | |
1088 | +/*++ | |
1089 | + | |
1090 | +Name: | |
1091 | + VmbusChannelRecvPacketRaw() | |
1092 | + | |
1093 | +Description: | |
1094 | + Retrieve the raw packet on the specified channel | |
1095 | + | |
1096 | +--*/ | |
1097 | +int | |
1098 | +VmbusChannelRecvPacketRaw( | |
1099 | + VMBUS_CHANNEL *Channel, | |
1100 | + PVOID Buffer, | |
1101 | + UINT32 BufferLen, | |
1102 | + UINT32* BufferActualLen, | |
1103 | + UINT64* RequestId | |
1104 | + ) | |
1105 | +{ | |
1106 | + VMPACKET_DESCRIPTOR desc; | |
1107 | + UINT32 packetLen; | |
1108 | + UINT32 userLen; | |
1109 | + int ret; | |
1110 | + | |
1111 | + DPRINT_ENTER(VMBUS); | |
1112 | + | |
1113 | + *BufferActualLen = 0; | |
1114 | + *RequestId = 0; | |
1115 | + | |
1116 | + SpinlockAcquire(Channel->InboundLock); | |
1117 | + | |
1118 | + ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR)); | |
1119 | + if (ret != 0) | |
1120 | + { | |
1121 | + SpinlockRelease(Channel->InboundLock); | |
1122 | + | |
1123 | + //DPRINT_DBG(VMBUS, "nothing to read!!"); | |
1124 | + DPRINT_EXIT(VMBUS); | |
1125 | + return 0; | |
1126 | + } | |
1127 | + | |
1128 | + //VmbusChannelClearEvent(Channel); | |
1129 | + | |
1130 | + packetLen = desc.Length8 << 3; | |
1131 | + userLen = packetLen - (desc.DataOffset8 << 3); | |
1132 | + | |
1133 | + DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d flag %d tid %llx pktlen %d datalen %d> ", | |
1134 | + Channel, | |
1135 | + Channel->OfferMsg.ChildRelId, | |
1136 | + desc.Type, | |
1137 | + desc.Flags, | |
1138 | + desc.TransactionId, packetLen, userLen); | |
1139 | + | |
1140 | + *BufferActualLen = packetLen; | |
1141 | + | |
1142 | + if (packetLen > BufferLen) | |
1143 | + { | |
1144 | + SpinlockRelease(Channel->InboundLock); | |
1145 | + | |
1146 | + DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen); | |
1147 | + DPRINT_EXIT(VMBUS); | |
1148 | + return -2; | |
1149 | + } | |
1150 | + | |
1151 | + *RequestId = desc.TransactionId; | |
1152 | + | |
1153 | + // Copy over the entire packet to the user buffer | |
1154 | + ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0); | |
1155 | + | |
1156 | + SpinlockRelease(Channel->InboundLock); | |
1157 | + | |
1158 | + DPRINT_EXIT(VMBUS); | |
1159 | + | |
1160 | + return 0; | |
1161 | +} | |
1162 | + | |
1163 | + | |
1164 | +/*++ | |
1165 | + | |
1166 | +Name: | |
1167 | + VmbusChannelOnChannelEvent() | |
1168 | + | |
1169 | +Description: | |
1170 | + Channel event callback | |
1171 | + | |
1172 | +--*/ | |
1173 | +void | |
1174 | +VmbusChannelOnChannelEvent( | |
1175 | + VMBUS_CHANNEL *Channel | |
1176 | + ) | |
1177 | +{ | |
1178 | + DumpVmbusChannel(Channel); | |
1179 | + ASSERT(Channel->OnChannelCallback); | |
1180 | +#ifdef ENABLE_POLLING | |
1181 | + TimerStop(Channel->PollTimer); | |
1182 | + Channel->OnChannelCallback(Channel->ChannelCallbackContext); | |
1183 | + TimerStart(Channel->PollTimer, 100 /* 100us */); | |
1184 | +#else | |
1185 | + Channel->OnChannelCallback(Channel->ChannelCallbackContext); | |
1186 | +#endif | |
1187 | +} | |
1188 | + | |
1189 | +/*++ | |
1190 | + | |
1191 | +Name: | |
1192 | + VmbusChannelOnTimer() | |
1193 | + | |
1194 | +Description: | |
1195 | + Timer event callback | |
1196 | + | |
1197 | +--*/ | |
1198 | +void | |
1199 | +VmbusChannelOnTimer( | |
1200 | + void *Context | |
1201 | + ) | |
1202 | +{ | |
1203 | + VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context; | |
1204 | + | |
1205 | + if (channel->OnChannelCallback) | |
1206 | + { | |
1207 | + channel->OnChannelCallback(channel->ChannelCallbackContext); | |
1208 | +#ifdef ENABLE_POLLING | |
1209 | + TimerStart(channel->PollTimer, 100 /* 100us */); | |
1210 | +#endif | |
1211 | + } | |
1212 | +} | |
1213 | + | |
1214 | + | |
1215 | +/*++ | |
1216 | + | |
1217 | +Name: | |
1218 | + DumpVmbusChannel() | |
1219 | + | |
1220 | +Description: | |
1221 | + Dump vmbus channel info to the console | |
1222 | + | |
1223 | +--*/ | |
1224 | +static void | |
1225 | +DumpVmbusChannel( | |
1226 | + VMBUS_CHANNEL *Channel | |
1227 | + ) | |
1228 | +{ | |
1229 | + DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId); | |
1230 | + DumpRingInfo(&Channel->Outbound, "Outbound "); | |
1231 | + DumpRingInfo(&Channel->Inbound, "Inbound "); | |
1232 | +} | |
1233 | + | |
1234 | + | |
1235 | +// eof | |
1236 | --- /dev/null | |
1237 | +++ b/drivers/staging/hv/Channel.h | |
1238 | @@ -0,0 +1,157 @@ | |
1239 | +/* | |
1240 | + * | |
1241 | + * Copyright (c) 2009, Microsoft Corporation. | |
1242 | + * | |
1243 | + * This program is free software; you can redistribute it and/or modify it | |
1244 | + * under the terms and conditions of the GNU General Public License, | |
1245 | + * version 2, as published by the Free Software Foundation. | |
1246 | + * | |
1247 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
1248 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
1249 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
1250 | + * more details. | |
1251 | + * | |
1252 | + * You should have received a copy of the GNU General Public License along with | |
1253 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
1254 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
1255 | + * | |
1256 | + * Authors: | |
1257 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
1258 | + * Hank Janssen <hjanssen@microsoft.com> | |
1259 | + * | |
1260 | + */ | |
1261 | + | |
1262 | + | |
1263 | +#ifndef _CHANNEL_H_ | |
1264 | +#define _CHANNEL_H_ | |
1265 | + | |
1266 | +#include "osd.h" | |
1267 | +#include "ChannelMgmt.h" | |
1268 | + | |
1269 | +#pragma pack(push,1) | |
1270 | + | |
1271 | + | |
1272 | +// The format must be the same as VMDATA_GPA_DIRECT | |
1273 | +typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER { | |
1274 | + UINT16 Type; | |
1275 | + UINT16 DataOffset8; | |
1276 | + UINT16 Length8; | |
1277 | + UINT16 Flags; | |
1278 | + UINT64 TransactionId; | |
1279 | + UINT32 Reserved; | |
1280 | + UINT32 RangeCount; | |
1281 | + PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT]; | |
1282 | +} VMBUS_CHANNEL_PACKET_PAGE_BUFFER; | |
1283 | + | |
1284 | + | |
1285 | +// The format must be the same as VMDATA_GPA_DIRECT | |
1286 | +typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER { | |
1287 | + UINT16 Type; | |
1288 | + UINT16 DataOffset8; | |
1289 | + UINT16 Length8; | |
1290 | + UINT16 Flags; | |
1291 | + UINT64 TransactionId; | |
1292 | + UINT32 Reserved; | |
1293 | + UINT32 RangeCount; // Always 1 in this case | |
1294 | + MULTIPAGE_BUFFER Range; | |
1295 | +} VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER; | |
1296 | + | |
1297 | +#pragma pack(pop) | |
1298 | + | |
1299 | +// | |
1300 | +// Routines | |
1301 | +// | |
1302 | + | |
1303 | +INTERNAL int | |
1304 | +VmbusChannelOpen( | |
1305 | + VMBUS_CHANNEL *Channel, | |
1306 | + UINT32 SendRingBufferSize, | |
1307 | + UINT32 RecvRingBufferSize, | |
1308 | + PVOID UserData, | |
1309 | + UINT32 UserDataLen, | |
1310 | + PFN_CHANNEL_CALLBACK pfnOnChannelCallback, | |
1311 | + PVOID Context | |
1312 | + ); | |
1313 | + | |
1314 | +INTERNAL void | |
1315 | +VmbusChannelClose( | |
1316 | + VMBUS_CHANNEL *Channel | |
1317 | + ); | |
1318 | + | |
1319 | +INTERNAL int | |
1320 | +VmbusChannelSendPacket( | |
1321 | + VMBUS_CHANNEL *Channel, | |
1322 | + const PVOID Buffer, | |
1323 | + UINT32 BufferLen, | |
1324 | + UINT64 RequestId, | |
1325 | + VMBUS_PACKET_TYPE Type, | |
1326 | + UINT32 Flags | |
1327 | +); | |
1328 | + | |
1329 | +INTERNAL int | |
1330 | +VmbusChannelSendPacketPageBuffer( | |
1331 | + VMBUS_CHANNEL *Channel, | |
1332 | + PAGE_BUFFER PageBuffers[], | |
1333 | + UINT32 PageCount, | |
1334 | + PVOID Buffer, | |
1335 | + UINT32 BufferLen, | |
1336 | + UINT64 RequestId | |
1337 | + ); | |
1338 | + | |
1339 | +INTERNAL int | |
1340 | +VmbusChannelSendPacketMultiPageBuffer( | |
1341 | + VMBUS_CHANNEL *Channel, | |
1342 | + MULTIPAGE_BUFFER *MultiPageBuffer, | |
1343 | + PVOID Buffer, | |
1344 | + UINT32 BufferLen, | |
1345 | + UINT64 RequestId | |
1346 | +); | |
1347 | + | |
1348 | +INTERNAL int | |
1349 | +VmbusChannelEstablishGpadl( | |
1350 | + VMBUS_CHANNEL *Channel, | |
1351 | + PVOID Kbuffer, // from kmalloc() | |
1352 | + UINT32 Size, // page-size multiple | |
1353 | + UINT32 *GpadlHandle | |
1354 | + ); | |
1355 | + | |
1356 | +INTERNAL int | |
1357 | +VmbusChannelTeardownGpadl( | |
1358 | + VMBUS_CHANNEL *Channel, | |
1359 | + UINT32 GpadlHandle | |
1360 | + ); | |
1361 | + | |
1362 | +INTERNAL int | |
1363 | +VmbusChannelRecvPacket( | |
1364 | + VMBUS_CHANNEL *Channel, | |
1365 | + PVOID Buffer, | |
1366 | + UINT32 BufferLen, | |
1367 | + UINT32* BufferActualLen, | |
1368 | + UINT64* RequestId | |
1369 | + ); | |
1370 | + | |
1371 | +INTERNAL int | |
1372 | +VmbusChannelRecvPacketRaw( | |
1373 | + VMBUS_CHANNEL *Channel, | |
1374 | + PVOID Buffer, | |
1375 | + UINT32 BufferLen, | |
1376 | + UINT32* BufferActualLen, | |
1377 | + UINT64* RequestId | |
1378 | + ); | |
1379 | + | |
1380 | +INTERNAL void | |
1381 | +VmbusChannelOnChannelEvent( | |
1382 | + VMBUS_CHANNEL *Channel | |
1383 | + ); | |
1384 | + | |
1385 | +INTERNAL void | |
1386 | +VmbusChannelGetDebugInfo( | |
1387 | + VMBUS_CHANNEL *Channel, | |
1388 | + VMBUS_CHANNEL_DEBUG_INFO *DebugInfo | |
1389 | + ); | |
1390 | + | |
1391 | +INTERNAL void | |
1392 | +VmbusChannelOnTimer( | |
1393 | + void *Context | |
1394 | + ); | |
1395 | +#endif //_CHANNEL_H_ | |
1396 | --- /dev/null | |
1397 | +++ b/drivers/staging/hv/ChannelInterface.c | |
1398 | @@ -0,0 +1,222 @@ | |
1399 | +/* | |
1400 | + * | |
1401 | + * Copyright (c) 2009, Microsoft Corporation. | |
1402 | + * | |
1403 | + * This program is free software; you can redistribute it and/or modify it | |
1404 | + * under the terms and conditions of the GNU General Public License, | |
1405 | + * version 2, as published by the Free Software Foundation. | |
1406 | + * | |
1407 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
1408 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
1409 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
1410 | + * more details. | |
1411 | + * | |
1412 | + * You should have received a copy of the GNU General Public License along with | |
1413 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
1414 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
1415 | + * | |
1416 | + * Authors: | |
1417 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
1418 | + * Hank Janssen <hjanssen@microsoft.com> | |
1419 | + * | |
1420 | + */ | |
1421 | + | |
1422 | +#include "VmbusPrivate.h" | |
1423 | + | |
1424 | +INTERNAL int | |
1425 | +IVmbusChannelOpen( | |
1426 | + PDEVICE_OBJECT Device, | |
1427 | + UINT32 SendBufferSize, | |
1428 | + UINT32 RecvRingBufferSize, | |
1429 | + PVOID UserData, | |
1430 | + UINT32 UserDataLen, | |
1431 | + VMBUS_CHANNEL_CALLBACK ChannelCallback, | |
1432 | + PVOID Context | |
1433 | + ) | |
1434 | +{ | |
1435 | + return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context, | |
1436 | + SendBufferSize, | |
1437 | + RecvRingBufferSize, | |
1438 | + UserData, | |
1439 | + UserDataLen, | |
1440 | + ChannelCallback, | |
1441 | + Context); | |
1442 | +} | |
1443 | + | |
1444 | + | |
1445 | +INTERNAL void | |
1446 | +IVmbusChannelClose( | |
1447 | + PDEVICE_OBJECT Device | |
1448 | + ) | |
1449 | +{ | |
1450 | + VmbusChannelClose((VMBUS_CHANNEL*)Device->context); | |
1451 | +} | |
1452 | + | |
1453 | + | |
1454 | +INTERNAL int | |
1455 | +IVmbusChannelSendPacket( | |
1456 | + PDEVICE_OBJECT Device, | |
1457 | + const PVOID Buffer, | |
1458 | + UINT32 BufferLen, | |
1459 | + UINT64 RequestId, | |
1460 | + UINT32 Type, | |
1461 | + UINT32 Flags | |
1462 | + ) | |
1463 | +{ | |
1464 | + return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context, | |
1465 | + Buffer, | |
1466 | + BufferLen, | |
1467 | + RequestId, | |
1468 | + Type, | |
1469 | + Flags); | |
1470 | +} | |
1471 | + | |
1472 | +INTERNAL int | |
1473 | +IVmbusChannelSendPacketPageBuffer( | |
1474 | + PDEVICE_OBJECT Device, | |
1475 | + PAGE_BUFFER PageBuffers[], | |
1476 | + UINT32 PageCount, | |
1477 | + PVOID Buffer, | |
1478 | + UINT32 BufferLen, | |
1479 | + UINT64 RequestId | |
1480 | + ) | |
1481 | +{ | |
1482 | + return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context, | |
1483 | + PageBuffers, | |
1484 | + PageCount, | |
1485 | + Buffer, | |
1486 | + BufferLen, | |
1487 | + RequestId); | |
1488 | +} | |
1489 | + | |
1490 | +INTERNAL int | |
1491 | +IVmbusChannelSendPacketMultiPageBuffer( | |
1492 | + PDEVICE_OBJECT Device, | |
1493 | + MULTIPAGE_BUFFER *MultiPageBuffer, | |
1494 | + PVOID Buffer, | |
1495 | + UINT32 BufferLen, | |
1496 | + UINT64 RequestId | |
1497 | + ) | |
1498 | +{ | |
1499 | + return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context, | |
1500 | + MultiPageBuffer, | |
1501 | + Buffer, | |
1502 | + BufferLen, | |
1503 | + RequestId); | |
1504 | +} | |
1505 | + | |
1506 | +INTERNAL int | |
1507 | +IVmbusChannelRecvPacket ( | |
1508 | + PDEVICE_OBJECT Device, | |
1509 | + PVOID Buffer, | |
1510 | + UINT32 BufferLen, | |
1511 | + UINT32* BufferActualLen, | |
1512 | + UINT64* RequestId | |
1513 | + ) | |
1514 | +{ | |
1515 | + return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context, | |
1516 | + Buffer, | |
1517 | + BufferLen, | |
1518 | + BufferActualLen, | |
1519 | + RequestId); | |
1520 | +} | |
1521 | + | |
1522 | +INTERNAL int | |
1523 | +IVmbusChannelRecvPacketRaw( | |
1524 | + PDEVICE_OBJECT Device, | |
1525 | + PVOID Buffer, | |
1526 | + UINT32 BufferLen, | |
1527 | + UINT32* BufferActualLen, | |
1528 | + UINT64* RequestId | |
1529 | + ) | |
1530 | +{ | |
1531 | + return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context, | |
1532 | + Buffer, | |
1533 | + BufferLen, | |
1534 | + BufferActualLen, | |
1535 | + RequestId); | |
1536 | +} | |
1537 | + | |
1538 | +INTERNAL int | |
1539 | +IVmbusChannelEstablishGpadl( | |
1540 | + PDEVICE_OBJECT Device, | |
1541 | + PVOID Buffer, | |
1542 | + UINT32 BufferLen, | |
1543 | + UINT32* GpadlHandle | |
1544 | + ) | |
1545 | +{ | |
1546 | + return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context, | |
1547 | + Buffer, | |
1548 | + BufferLen, | |
1549 | + GpadlHandle); | |
1550 | +} | |
1551 | + | |
1552 | +INTERNAL int | |
1553 | +IVmbusChannelTeardownGpadl( | |
1554 | + PDEVICE_OBJECT Device, | |
1555 | + UINT32 GpadlHandle | |
1556 | + ) | |
1557 | +{ | |
1558 | + return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context, | |
1559 | + GpadlHandle); | |
1560 | + | |
1561 | +} | |
1562 | + | |
1563 | +INTERNAL void | |
1564 | +GetChannelInterface( | |
1565 | + VMBUS_CHANNEL_INTERFACE *ChannelInterface | |
1566 | + ) | |
1567 | +{ | |
1568 | + ChannelInterface->Open = IVmbusChannelOpen; | |
1569 | + ChannelInterface->Close = IVmbusChannelClose; | |
1570 | + ChannelInterface->SendPacket = IVmbusChannelSendPacket; | |
1571 | + ChannelInterface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer; | |
1572 | + ChannelInterface->SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer; | |
1573 | + ChannelInterface->RecvPacket = IVmbusChannelRecvPacket; | |
1574 | + ChannelInterface->RecvPacketRaw = IVmbusChannelRecvPacketRaw; | |
1575 | + ChannelInterface->EstablishGpadl = IVmbusChannelEstablishGpadl; | |
1576 | + ChannelInterface->TeardownGpadl = IVmbusChannelTeardownGpadl; | |
1577 | + ChannelInterface->GetInfo = GetChannelInfo; | |
1578 | +} | |
1579 | + | |
1580 | + | |
1581 | +INTERNAL void | |
1582 | +GetChannelInfo( | |
1583 | + PDEVICE_OBJECT Device, | |
1584 | + DEVICE_INFO *DeviceInfo | |
1585 | + ) | |
1586 | +{ | |
1587 | + VMBUS_CHANNEL_DEBUG_INFO debugInfo; | |
1588 | + | |
1589 | + if (Device->context) | |
1590 | + { | |
1591 | + VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo); | |
1592 | + | |
1593 | + DeviceInfo->ChannelId = debugInfo.RelId; | |
1594 | + DeviceInfo->ChannelState = debugInfo.State; | |
1595 | + memcpy(&DeviceInfo->ChannelType, &debugInfo.InterfaceType, sizeof(GUID)); | |
1596 | + memcpy(&DeviceInfo->ChannelInstance, &debugInfo.InterfaceInstance, sizeof(GUID)); | |
1597 | + | |
1598 | + DeviceInfo->MonitorId = debugInfo.MonitorId; | |
1599 | + | |
1600 | + DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending; | |
1601 | + DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency; | |
1602 | + DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId; | |
1603 | + | |
1604 | + DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending; | |
1605 | + DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency; | |
1606 | + DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId; | |
1607 | + | |
1608 | + DeviceInfo->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask; | |
1609 | + DeviceInfo->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex; | |
1610 | + DeviceInfo->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex; | |
1611 | + DeviceInfo->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead; | |
1612 | + DeviceInfo->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite; | |
1613 | + | |
1614 | + DeviceInfo->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask; | |
1615 | + DeviceInfo->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex; | |
1616 | + DeviceInfo->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex; | |
1617 | + DeviceInfo->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead; | |
1618 | + DeviceInfo->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite; | |
1619 | + } | |
1620 | +} | |
1621 | --- /dev/null | |
1622 | +++ b/drivers/staging/hv/ChannelInterface.h | |
1623 | @@ -0,0 +1,41 @@ | |
1624 | +/* | |
1625 | + * | |
1626 | + * Copyright (c) 2009, Microsoft Corporation. | |
1627 | + * | |
1628 | + * This program is free software; you can redistribute it and/or modify it | |
1629 | + * under the terms and conditions of the GNU General Public License, | |
1630 | + * version 2, as published by the Free Software Foundation. | |
1631 | + * | |
1632 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
1633 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
1634 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
1635 | + * more details. | |
1636 | + * | |
1637 | + * You should have received a copy of the GNU General Public License along with | |
1638 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
1639 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
1640 | + * | |
1641 | + * Authors: | |
1642 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
1643 | + * Hank Janssen <hjanssen@microsoft.com> | |
1644 | + * | |
1645 | + */ | |
1646 | + | |
1647 | + | |
1648 | +#ifndef _CHANNEL_INTERFACE_H_ | |
1649 | +#define _CHANNEL_INTERFACE_H_ | |
1650 | + | |
1651 | +#include "VmbusApi.h" | |
1652 | + | |
1653 | +INTERNAL void | |
1654 | +GetChannelInterface( | |
1655 | + VMBUS_CHANNEL_INTERFACE *ChannelInterface | |
1656 | + ); | |
1657 | + | |
1658 | +INTERNAL void | |
1659 | +GetChannelInfo( | |
1660 | + PDEVICE_OBJECT Device, | |
1661 | + DEVICE_INFO *DeviceInfo | |
1662 | + ); | |
1663 | + | |
1664 | +#endif // _CHANNEL_INTERFACE_H_ | |
1665 | --- /dev/null | |
1666 | +++ b/drivers/staging/hv/ChannelMgmt.c | |
1667 | @@ -0,0 +1,826 @@ | |
1668 | +/* | |
1669 | + * | |
1670 | + * Copyright (c) 2009, Microsoft Corporation. | |
1671 | + * | |
1672 | + * This program is free software; you can redistribute it and/or modify it | |
1673 | + * under the terms and conditions of the GNU General Public License, | |
1674 | + * version 2, as published by the Free Software Foundation. | |
1675 | + * | |
1676 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
1677 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
1678 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
1679 | + * more details. | |
1680 | + * | |
1681 | + * You should have received a copy of the GNU General Public License along with | |
1682 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
1683 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
1684 | + * | |
1685 | + * Authors: | |
1686 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
1687 | + * Hank Janssen <hjanssen@microsoft.com> | |
1688 | + * | |
1689 | + */ | |
1690 | + | |
1691 | + | |
1692 | +#include "osd.h" | |
1693 | +#include "logging.h" | |
1694 | + | |
1695 | +#include "VmbusPrivate.h" | |
1696 | + | |
1697 | +// | |
1698 | +// Defines | |
1699 | +// | |
1700 | + | |
1701 | +// | |
1702 | +// Data types | |
1703 | +// | |
1704 | + | |
1705 | +typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg); | |
1706 | + | |
1707 | +typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY { | |
1708 | + VMBUS_CHANNEL_MESSAGE_TYPE messageType; | |
1709 | + PFN_CHANNEL_MESSAGE_HANDLER messageHandler; | |
1710 | +} VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY; | |
1711 | + | |
1712 | +// | |
1713 | +// Internal routines | |
1714 | +// | |
1715 | + | |
1716 | +static void | |
1717 | +VmbusChannelOnOffer( | |
1718 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1719 | + ); | |
1720 | +static void | |
1721 | +VmbusChannelOnOpenResult( | |
1722 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1723 | + ); | |
1724 | + | |
1725 | +static void | |
1726 | +VmbusChannelOnOfferRescind( | |
1727 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1728 | + ); | |
1729 | + | |
1730 | +static void | |
1731 | +VmbusChannelOnGpadlCreated( | |
1732 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1733 | + ); | |
1734 | + | |
1735 | +static void | |
1736 | +VmbusChannelOnGpadlTorndown( | |
1737 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1738 | + ); | |
1739 | + | |
1740 | +static void | |
1741 | +VmbusChannelOnOffersDelivered( | |
1742 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1743 | + ); | |
1744 | + | |
1745 | +static void | |
1746 | +VmbusChannelOnVersionResponse( | |
1747 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
1748 | + ); | |
1749 | + | |
1750 | +static void | |
1751 | +VmbusChannelProcessOffer( | |
1752 | + PVOID context | |
1753 | + ); | |
1754 | + | |
1755 | +static void | |
1756 | +VmbusChannelProcessRescindOffer( | |
1757 | + PVOID context | |
1758 | + ); | |
1759 | + | |
1760 | + | |
1761 | +// | |
1762 | +// Globals | |
1763 | +// | |
1764 | + | |
1765 | +#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4 | |
1766 | + | |
1767 | +const GUID gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED]= { | |
1768 | + //{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} | |
1769 | + {.Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}},// Storage - SCSI | |
1770 | + //{F8615163-DF3E-46c5-913F-F2D2F965ED0E} | |
1771 | + {.Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}}, // Network | |
1772 | + //{CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} | |
1773 | + {.Data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}}, // Input | |
1774 | + //{32412632-86cb-44a2-9b5c-50d1417354f5} | |
1775 | + {.Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}}, // IDE | |
1776 | + | |
1777 | +}; | |
1778 | + | |
1779 | +// Channel message dispatch table | |
1780 | +VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= { | |
1781 | + {ChannelMessageInvalid, NULL}, | |
1782 | + {ChannelMessageOfferChannel, VmbusChannelOnOffer}, | |
1783 | + {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind}, | |
1784 | + {ChannelMessageRequestOffers, NULL}, | |
1785 | + {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered}, | |
1786 | + {ChannelMessageOpenChannel, NULL}, | |
1787 | + {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult}, | |
1788 | + {ChannelMessageCloseChannel, NULL}, | |
1789 | + {ChannelMessageGpadlHeader, NULL}, | |
1790 | + {ChannelMessageGpadlBody, NULL}, | |
1791 | + {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated}, | |
1792 | + {ChannelMessageGpadlTeardown, NULL}, | |
1793 | + {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown}, | |
1794 | + {ChannelMessageRelIdReleased, NULL}, | |
1795 | + {ChannelMessageInitiateContact, NULL}, | |
1796 | + {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse}, | |
1797 | + {ChannelMessageUnload, NULL}, | |
1798 | +}; | |
1799 | + | |
1800 | +/*++ | |
1801 | + | |
1802 | +Name: | |
1803 | + AllocVmbusChannel() | |
1804 | + | |
1805 | +Description: | |
1806 | + Allocate and initialize a vmbus channel object | |
1807 | + | |
1808 | +--*/ | |
1809 | +VMBUS_CHANNEL* AllocVmbusChannel(void) | |
1810 | +{ | |
1811 | + VMBUS_CHANNEL* channel; | |
1812 | + | |
1813 | + channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL)); | |
1814 | + if (!channel) | |
1815 | + { | |
1816 | + return NULL; | |
1817 | + } | |
1818 | + | |
1819 | + memset(channel, 0,sizeof(VMBUS_CHANNEL)); | |
1820 | + channel->InboundLock = SpinlockCreate(); | |
1821 | + if (!channel->InboundLock) | |
1822 | + { | |
1823 | + MemFree(channel); | |
1824 | + return NULL; | |
1825 | + } | |
1826 | + | |
1827 | + channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel); | |
1828 | + if (!channel->PollTimer) | |
1829 | + { | |
1830 | + SpinlockClose(channel->InboundLock); | |
1831 | + MemFree(channel); | |
1832 | + return NULL; | |
1833 | + } | |
1834 | + | |
1835 | + //channel->dataWorkQueue = WorkQueueCreate("data"); | |
1836 | + channel->ControlWQ = WorkQueueCreate("control"); | |
1837 | + if (!channel->ControlWQ) | |
1838 | + { | |
1839 | + TimerClose(channel->PollTimer); | |
1840 | + SpinlockClose(channel->InboundLock); | |
1841 | + MemFree(channel); | |
1842 | + return NULL; | |
1843 | + } | |
1844 | + | |
1845 | + return channel; | |
1846 | +} | |
1847 | + | |
1848 | +/*++ | |
1849 | + | |
1850 | +Name: | |
1851 | + ReleaseVmbusChannel() | |
1852 | + | |
1853 | +Description: | |
1854 | + Release the vmbus channel object itself | |
1855 | + | |
1856 | +--*/ | |
1857 | +static inline void ReleaseVmbusChannel(void* Context) | |
1858 | +{ | |
1859 | + VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context; | |
1860 | + | |
1861 | + DPRINT_ENTER(VMBUS); | |
1862 | + | |
1863 | + DPRINT_DBG(VMBUS, "releasing channel (%p)", channel); | |
1864 | + WorkQueueClose(channel->ControlWQ); | |
1865 | + DPRINT_DBG(VMBUS, "channel released (%p)", channel); | |
1866 | + | |
1867 | + MemFree(channel); | |
1868 | + | |
1869 | + DPRINT_EXIT(VMBUS); | |
1870 | +} | |
1871 | + | |
1872 | +/*++ | |
1873 | + | |
1874 | +Name: | |
1875 | + FreeVmbusChannel() | |
1876 | + | |
1877 | +Description: | |
1878 | + Release the resources used by the vmbus channel object | |
1879 | + | |
1880 | +--*/ | |
1881 | +void FreeVmbusChannel(VMBUS_CHANNEL* Channel) | |
1882 | +{ | |
1883 | + SpinlockClose(Channel->InboundLock); | |
1884 | + TimerClose(Channel->PollTimer); | |
1885 | + | |
1886 | + // We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context | |
1887 | + // ie we can't destroy ourselves. | |
1888 | + WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, ReleaseVmbusChannel, (void*)Channel); | |
1889 | +} | |
1890 | + | |
1891 | + | |
1892 | +/*++ | |
1893 | + | |
1894 | +Name: | |
1895 | + VmbusChannelProcessOffer() | |
1896 | + | |
1897 | +Description: | |
1898 | + Process the offer by creating a channel/device associated with this offer | |
1899 | + | |
1900 | +--*/ | |
1901 | +static void | |
1902 | +VmbusChannelProcessOffer( | |
1903 | + PVOID context | |
1904 | + ) | |
1905 | +{ | |
1906 | + int ret=0; | |
1907 | + VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context; | |
1908 | + LIST_ENTRY* anchor; | |
1909 | + LIST_ENTRY* curr; | |
1910 | + BOOL fNew=TRUE; | |
1911 | + VMBUS_CHANNEL* channel; | |
1912 | + | |
1913 | + DPRINT_ENTER(VMBUS); | |
1914 | + | |
1915 | + // Make sure this is a new offer | |
1916 | + SpinlockAcquire(gVmbusConnection.ChannelLock); | |
1917 | + | |
1918 | + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) | |
1919 | + { | |
1920 | + channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry); | |
1921 | + | |
1922 | + if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(GUID)) && | |
1923 | + !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID))) | |
1924 | + { | |
1925 | + fNew = FALSE; | |
1926 | + break; | |
1927 | + } | |
1928 | + } | |
1929 | + | |
1930 | + if (fNew) | |
1931 | + { | |
1932 | + INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry); | |
1933 | + } | |
1934 | + SpinlockRelease(gVmbusConnection.ChannelLock); | |
1935 | + | |
1936 | + if (!fNew) | |
1937 | + { | |
1938 | + DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId); | |
1939 | + FreeVmbusChannel(newChannel); | |
1940 | + DPRINT_EXIT(VMBUS); | |
1941 | + return; | |
1942 | + } | |
1943 | + | |
1944 | + // Start the process of binding this offer to the driver | |
1945 | + // We need to set the DeviceObject field before calling VmbusChildDeviceAdd() | |
1946 | + newChannel->DeviceObject = VmbusChildDeviceCreate( | |
1947 | + newChannel->OfferMsg.Offer.InterfaceType, | |
1948 | + newChannel->OfferMsg.Offer.InterfaceInstance, | |
1949 | + newChannel); | |
1950 | + | |
1951 | + DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject); | |
1952 | + | |
1953 | + // Add the new device to the bus. This will kick off device-driver binding | |
1954 | + // which eventually invokes the device driver's AddDevice() method. | |
1955 | + ret = VmbusChildDeviceAdd(newChannel->DeviceObject); | |
1956 | + if (ret != 0) | |
1957 | + { | |
1958 | + DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)", | |
1959 | + newChannel->OfferMsg.ChildRelId); | |
1960 | + | |
1961 | + SpinlockAcquire(gVmbusConnection.ChannelLock); | |
1962 | + REMOVE_ENTRY_LIST(&newChannel->ListEntry); | |
1963 | + SpinlockRelease(gVmbusConnection.ChannelLock); | |
1964 | + | |
1965 | + FreeVmbusChannel(newChannel); | |
1966 | + } | |
1967 | + else | |
1968 | + { | |
1969 | + // This state is used to indicate a successful open so that when we do close the channel normally, | |
1970 | + // we can cleanup properly | |
1971 | + newChannel->State = CHANNEL_OPEN_STATE; | |
1972 | + } | |
1973 | + DPRINT_EXIT(VMBUS); | |
1974 | +} | |
1975 | + | |
1976 | +/*++ | |
1977 | + | |
1978 | +Name: | |
1979 | + VmbusChannelProcessRescindOffer() | |
1980 | + | |
1981 | +Description: | |
1982 | + Rescind the offer by initiating a device removal | |
1983 | + | |
1984 | +--*/ | |
1985 | +static void | |
1986 | +VmbusChannelProcessRescindOffer( | |
1987 | + PVOID context | |
1988 | + ) | |
1989 | +{ | |
1990 | + VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context; | |
1991 | + | |
1992 | + DPRINT_ENTER(VMBUS); | |
1993 | + | |
1994 | + VmbusChildDeviceRemove(channel->DeviceObject); | |
1995 | + | |
1996 | + DPRINT_EXIT(VMBUS); | |
1997 | +} | |
1998 | + | |
1999 | + | |
2000 | +/*++ | |
2001 | + | |
2002 | +Name: | |
2003 | + VmbusChannelOnOffer() | |
2004 | + | |
2005 | +Description: | |
2006 | + Handler for channel offers from vmbus in parent partition. We ignore all offers except | |
2007 | + network and storage offers. For each network and storage offers, we create a channel object | |
2008 | + and queue a work item to the channel object to process the offer synchronously | |
2009 | + | |
2010 | +--*/ | |
2011 | +static void | |
2012 | +VmbusChannelOnOffer( | |
2013 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2014 | + ) | |
2015 | +{ | |
2016 | + VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr; | |
2017 | + VMBUS_CHANNEL* newChannel; | |
2018 | + | |
2019 | + GUID *guidType; | |
2020 | + GUID *guidInstance; | |
2021 | + int i; | |
2022 | + int fSupported=0; | |
2023 | + | |
2024 | + DPRINT_ENTER(VMBUS); | |
2025 | + | |
2026 | + for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) | |
2027 | + { | |
2028 | + if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0) | |
2029 | + { | |
2030 | + fSupported = 1; | |
2031 | + break; | |
2032 | + } | |
2033 | + } | |
2034 | + | |
2035 | + if (!fSupported) | |
2036 | + { | |
2037 | + DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId); | |
2038 | + DPRINT_EXIT(VMBUS); | |
2039 | + | |
2040 | + return; | |
2041 | + } | |
2042 | + | |
2043 | + guidType = &offer->Offer.InterfaceType; | |
2044 | + guidInstance = &offer->Offer.InterfaceInstance; | |
2045 | + | |
2046 | + DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, " | |
2047 | + "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} " | |
2048 | + "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | |
2049 | + offer->ChildRelId, | |
2050 | + offer->MonitorId, | |
2051 | + offer->MonitorAllocated, | |
2052 | + 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], | |
2053 | + 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]); | |
2054 | + | |
2055 | + // Allocate the channel object and save this offer. | |
2056 | + newChannel = AllocVmbusChannel(); | |
2057 | + if (!newChannel) | |
2058 | + { | |
2059 | + DPRINT_ERR(VMBUS, "unable to allocate channel object"); | |
2060 | + return; | |
2061 | + } | |
2062 | + | |
2063 | + DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel); | |
2064 | + | |
2065 | + memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL)); | |
2066 | + newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32; | |
2067 | + newChannel->MonitorBit = (UINT8)offer->MonitorId % 32; | |
2068 | + | |
2069 | + // TODO: Make sure the offer comes from our parent partition | |
2070 | + WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel); | |
2071 | + | |
2072 | + DPRINT_EXIT(VMBUS); | |
2073 | +} | |
2074 | + | |
2075 | + | |
2076 | +/*++ | |
2077 | + | |
2078 | +Name: | |
2079 | + VmbusChannelOnOfferRescind() | |
2080 | + | |
2081 | +Description: | |
2082 | + Rescind offer handler. We queue a work item to process this offer | |
2083 | + synchronously | |
2084 | + | |
2085 | +--*/ | |
2086 | +static void | |
2087 | +VmbusChannelOnOfferRescind( | |
2088 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2089 | + ) | |
2090 | +{ | |
2091 | + VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr; | |
2092 | + VMBUS_CHANNEL* channel; | |
2093 | + | |
2094 | + DPRINT_ENTER(VMBUS); | |
2095 | + | |
2096 | + channel = GetChannelFromRelId(rescind->ChildRelId); | |
2097 | + if (channel == NULL) | |
2098 | + { | |
2099 | + DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId); | |
2100 | + return; | |
2101 | + } | |
2102 | + | |
2103 | + WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel); | |
2104 | + | |
2105 | + DPRINT_EXIT(VMBUS); | |
2106 | +} | |
2107 | + | |
2108 | + | |
2109 | +/*++ | |
2110 | + | |
2111 | +Name: | |
2112 | + VmbusChannelOnOffersDelivered() | |
2113 | + | |
2114 | +Description: | |
2115 | + This is invoked when all offers have been delivered. | |
2116 | + Nothing to do here. | |
2117 | + | |
2118 | +--*/ | |
2119 | +static void | |
2120 | +VmbusChannelOnOffersDelivered( | |
2121 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2122 | + ) | |
2123 | +{ | |
2124 | + DPRINT_ENTER(VMBUS); | |
2125 | + DPRINT_EXIT(VMBUS); | |
2126 | +} | |
2127 | + | |
2128 | + | |
2129 | +/*++ | |
2130 | + | |
2131 | +Name: | |
2132 | + VmbusChannelOnOpenResult() | |
2133 | + | |
2134 | +Description: | |
2135 | + Open result handler. This is invoked when we received a response | |
2136 | + to our channel open request. Find the matching request, copy the | |
2137 | + response and signal the requesting thread. | |
2138 | + | |
2139 | +--*/ | |
2140 | +static void | |
2141 | +VmbusChannelOnOpenResult( | |
2142 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2143 | + ) | |
2144 | +{ | |
2145 | + VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr; | |
2146 | + LIST_ENTRY* anchor; | |
2147 | + LIST_ENTRY* curr; | |
2148 | + VMBUS_CHANNEL_MSGINFO* msgInfo; | |
2149 | + VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader; | |
2150 | + VMBUS_CHANNEL_OPEN_CHANNEL* openMsg; | |
2151 | + | |
2152 | + DPRINT_ENTER(VMBUS); | |
2153 | + | |
2154 | + DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status); | |
2155 | + | |
2156 | + // Find the open msg, copy the result and signal/unblock the wait event | |
2157 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
2158 | + | |
2159 | + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | |
2160 | + { | |
2161 | + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | |
2162 | + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | |
2163 | + | |
2164 | + if (requestHeader->MessageType == ChannelMessageOpenChannel) | |
2165 | + { | |
2166 | + openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg; | |
2167 | + if (openMsg->ChildRelId == result->ChildRelId && | |
2168 | + openMsg->OpenId == result->OpenId) | |
2169 | + { | |
2170 | + memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT)); | |
2171 | + WaitEventSet(msgInfo->WaitEvent); | |
2172 | + break; | |
2173 | + } | |
2174 | + } | |
2175 | + } | |
2176 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
2177 | + | |
2178 | + DPRINT_EXIT(VMBUS); | |
2179 | +} | |
2180 | + | |
2181 | + | |
2182 | +/*++ | |
2183 | + | |
2184 | +Name: | |
2185 | + VmbusChannelOnGpadlCreated() | |
2186 | + | |
2187 | +Description: | |
2188 | + GPADL created handler. This is invoked when we received a response | |
2189 | + to our gpadl create request. Find the matching request, copy the | |
2190 | + response and signal the requesting thread. | |
2191 | + | |
2192 | +--*/ | |
2193 | +static void | |
2194 | +VmbusChannelOnGpadlCreated( | |
2195 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2196 | + ) | |
2197 | +{ | |
2198 | + VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr; | |
2199 | + LIST_ENTRY *anchor; | |
2200 | + LIST_ENTRY *curr; | |
2201 | + VMBUS_CHANNEL_MSGINFO *msgInfo; | |
2202 | + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; | |
2203 | + VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader; | |
2204 | + | |
2205 | + DPRINT_ENTER(VMBUS); | |
2206 | + | |
2207 | + DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus); | |
2208 | + | |
2209 | + // Find the establish msg, copy the result and signal/unblock the wait event | |
2210 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
2211 | + | |
2212 | + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | |
2213 | + { | |
2214 | + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | |
2215 | + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | |
2216 | + | |
2217 | + if (requestHeader->MessageType == ChannelMessageGpadlHeader) | |
2218 | + { | |
2219 | + gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader; | |
2220 | + | |
2221 | + if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) && | |
2222 | + (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) | |
2223 | + { | |
2224 | + memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED)); | |
2225 | + WaitEventSet(msgInfo->WaitEvent); | |
2226 | + break; | |
2227 | + } | |
2228 | + } | |
2229 | + } | |
2230 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
2231 | + | |
2232 | + DPRINT_EXIT(VMBUS); | |
2233 | +} | |
2234 | + | |
2235 | + | |
2236 | +/*++ | |
2237 | + | |
2238 | +Name: | |
2239 | + VmbusChannelOnGpadlTorndown() | |
2240 | + | |
2241 | +Description: | |
2242 | + GPADL torndown handler. This is invoked when we received a response | |
2243 | + to our gpadl teardown request. Find the matching request, copy the | |
2244 | + response and signal the requesting thread. | |
2245 | + | |
2246 | +--*/ | |
2247 | +static void | |
2248 | +VmbusChannelOnGpadlTorndown( | |
2249 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2250 | + ) | |
2251 | +{ | |
2252 | + VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr; | |
2253 | + LIST_ENTRY* anchor; | |
2254 | + LIST_ENTRY* curr; | |
2255 | + VMBUS_CHANNEL_MSGINFO* msgInfo; | |
2256 | + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; | |
2257 | + VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown; | |
2258 | + | |
2259 | + DPRINT_ENTER(VMBUS); | |
2260 | + | |
2261 | + // Find the open msg, copy the result and signal/unblock the wait event | |
2262 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
2263 | + | |
2264 | + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | |
2265 | + { | |
2266 | + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | |
2267 | + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | |
2268 | + | |
2269 | + if (requestHeader->MessageType == ChannelMessageGpadlTeardown) | |
2270 | + { | |
2271 | + gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader; | |
2272 | + | |
2273 | + if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) | |
2274 | + { | |
2275 | + memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN)); | |
2276 | + WaitEventSet(msgInfo->WaitEvent); | |
2277 | + break; | |
2278 | + } | |
2279 | + } | |
2280 | + } | |
2281 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
2282 | + | |
2283 | + DPRINT_EXIT(VMBUS); | |
2284 | +} | |
2285 | + | |
2286 | + | |
2287 | +/*++ | |
2288 | + | |
2289 | +Name: | |
2290 | + VmbusChannelOnVersionResponse() | |
2291 | + | |
2292 | +Description: | |
2293 | + Version response handler. This is invoked when we received a response | |
2294 | + to our initiate contact request. Find the matching request, copy the | |
2295 | + response and signal the requesting thread. | |
2296 | + | |
2297 | +--*/ | |
2298 | +static void | |
2299 | +VmbusChannelOnVersionResponse( | |
2300 | + PVMBUS_CHANNEL_MESSAGE_HEADER hdr | |
2301 | + ) | |
2302 | +{ | |
2303 | + LIST_ENTRY* anchor; | |
2304 | + LIST_ENTRY* curr; | |
2305 | + VMBUS_CHANNEL_MSGINFO *msgInfo; | |
2306 | + VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; | |
2307 | + VMBUS_CHANNEL_INITIATE_CONTACT *initiate; | |
2308 | + VMBUS_CHANNEL_VERSION_RESPONSE *versionResponse = (VMBUS_CHANNEL_VERSION_RESPONSE*)hdr; | |
2309 | + | |
2310 | + DPRINT_ENTER(VMBUS); | |
2311 | + | |
2312 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
2313 | + | |
2314 | + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) | |
2315 | + { | |
2316 | + msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; | |
2317 | + requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | |
2318 | + | |
2319 | + if (requestHeader->MessageType == ChannelMessageInitiateContact) | |
2320 | + { | |
2321 | + initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader; | |
2322 | + memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE)); | |
2323 | + WaitEventSet(msgInfo->WaitEvent); | |
2324 | + } | |
2325 | + } | |
2326 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
2327 | + | |
2328 | + DPRINT_EXIT(VMBUS); | |
2329 | +} | |
2330 | + | |
2331 | + | |
2332 | +/*++ | |
2333 | + | |
2334 | +Name: | |
2335 | + VmbusOnChannelMessage() | |
2336 | + | |
2337 | +Description: | |
2338 | + Handler for channel protocol messages. | |
2339 | + This is invoked in the vmbus worker thread context. | |
2340 | + | |
2341 | +--*/ | |
2342 | +VOID | |
2343 | +VmbusOnChannelMessage( | |
2344 | + void *Context | |
2345 | + ) | |
2346 | +{ | |
2347 | + HV_MESSAGE *msg=(HV_MESSAGE*)Context; | |
2348 | + VMBUS_CHANNEL_MESSAGE_HEADER* hdr; | |
2349 | + int size; | |
2350 | + | |
2351 | + DPRINT_ENTER(VMBUS); | |
2352 | + | |
2353 | + hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload; | |
2354 | + size=msg->Header.PayloadSize; | |
2355 | + | |
2356 | + DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size); | |
2357 | + | |
2358 | + if (hdr->MessageType >= ChannelMessageCount) | |
2359 | + { | |
2360 | + DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size); | |
2361 | + PrintBytes((unsigned char *)msg->u.Payload, size); | |
2362 | + MemFree(msg); | |
2363 | + return; | |
2364 | + } | |
2365 | + | |
2366 | + if (gChannelMessageTable[hdr->MessageType].messageHandler) | |
2367 | + { | |
2368 | + gChannelMessageTable[hdr->MessageType].messageHandler(hdr); | |
2369 | + } | |
2370 | + else | |
2371 | + { | |
2372 | + DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType); | |
2373 | + } | |
2374 | + | |
2375 | + // Free the msg that was allocated in VmbusOnMsgDPC() | |
2376 | + MemFree(msg); | |
2377 | + DPRINT_EXIT(VMBUS); | |
2378 | +} | |
2379 | + | |
2380 | + | |
2381 | +/*++ | |
2382 | + | |
2383 | +Name: | |
2384 | + VmbusChannelRequestOffers() | |
2385 | + | |
2386 | +Description: | |
2387 | + Send a request to get all our pending offers. | |
2388 | + | |
2389 | +--*/ | |
2390 | +int | |
2391 | +VmbusChannelRequestOffers( | |
2392 | + VOID | |
2393 | + ) | |
2394 | +{ | |
2395 | + int ret=0; | |
2396 | + VMBUS_CHANNEL_MESSAGE_HEADER* msg; | |
2397 | + VMBUS_CHANNEL_MSGINFO* msgInfo; | |
2398 | + | |
2399 | + DPRINT_ENTER(VMBUS); | |
2400 | + | |
2401 | + msgInfo = | |
2402 | + (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER)); | |
2403 | + ASSERT(msgInfo != NULL); | |
2404 | + | |
2405 | + msgInfo->WaitEvent = WaitEventCreate(); | |
2406 | + msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; | |
2407 | + | |
2408 | + msg->MessageType = ChannelMessageRequestOffers; | |
2409 | + | |
2410 | + /*SpinlockAcquire(gVmbusConnection.channelMsgLock); | |
2411 | + INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry); | |
2412 | + SpinlockRelease(gVmbusConnection.channelMsgLock);*/ | |
2413 | + | |
2414 | + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER)); | |
2415 | + if (ret != 0) | |
2416 | + { | |
2417 | + DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret); | |
2418 | + | |
2419 | + /*SpinlockAcquire(gVmbusConnection.channelMsgLock); | |
2420 | + REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); | |
2421 | + SpinlockRelease(gVmbusConnection.channelMsgLock);*/ | |
2422 | + | |
2423 | + goto Cleanup; | |
2424 | + } | |
2425 | + //WaitEventWait(msgInfo->waitEvent); | |
2426 | + | |
2427 | + /*SpinlockAcquire(gVmbusConnection.channelMsgLock); | |
2428 | + REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); | |
2429 | + SpinlockRelease(gVmbusConnection.channelMsgLock);*/ | |
2430 | + | |
2431 | + | |
2432 | +Cleanup: | |
2433 | + if (msgInfo) | |
2434 | + { | |
2435 | + WaitEventClose(msgInfo->WaitEvent); | |
2436 | + MemFree(msgInfo); | |
2437 | + } | |
2438 | + | |
2439 | + DPRINT_EXIT(VMBUS); | |
2440 | + | |
2441 | + return ret; | |
2442 | +} | |
2443 | + | |
2444 | +/*++ | |
2445 | + | |
2446 | +Name: | |
2447 | + VmbusChannelReleaseUnattachedChannels() | |
2448 | + | |
2449 | +Description: | |
2450 | + Release channels that are unattached/unconnected ie (no drivers associated) | |
2451 | + | |
2452 | +--*/ | |
2453 | +void | |
2454 | +VmbusChannelReleaseUnattachedChannels( | |
2455 | + VOID | |
2456 | + ) | |
2457 | +{ | |
2458 | + LIST_ENTRY *entry; | |
2459 | + VMBUS_CHANNEL *channel; | |
2460 | + VMBUS_CHANNEL *start=NULL; | |
2461 | + | |
2462 | + SpinlockAcquire(gVmbusConnection.ChannelLock); | |
2463 | + | |
2464 | + while (!IsListEmpty(&gVmbusConnection.ChannelList)) | |
2465 | + { | |
2466 | + entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList); | |
2467 | + channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry); | |
2468 | + | |
2469 | + if (channel == start) | |
2470 | + break; | |
2471 | + | |
2472 | + if (!channel->DeviceObject->Driver) | |
2473 | + { | |
2474 | + REMOVE_ENTRY_LIST(&channel->ListEntry); | |
2475 | + DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject); | |
2476 | + | |
2477 | + VmbusChildDeviceRemove(channel->DeviceObject); | |
2478 | + FreeVmbusChannel(channel); | |
2479 | + } | |
2480 | + else | |
2481 | + { | |
2482 | + if (!start) | |
2483 | + { | |
2484 | + start = channel; | |
2485 | + } | |
2486 | + } | |
2487 | + } | |
2488 | + | |
2489 | + SpinlockRelease(gVmbusConnection.ChannelLock); | |
2490 | +} | |
2491 | + | |
2492 | +// eof | |
2493 | + | |
2494 | --- /dev/null | |
2495 | +++ b/drivers/staging/hv/ChannelMgmt.h | |
2496 | @@ -0,0 +1,156 @@ | |
2497 | +/* | |
2498 | + * | |
2499 | + * Copyright (c) 2009, Microsoft Corporation. | |
2500 | + * | |
2501 | + * This program is free software; you can redistribute it and/or modify it | |
2502 | + * under the terms and conditions of the GNU General Public License, | |
2503 | + * version 2, as published by the Free Software Foundation. | |
2504 | + * | |
2505 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
2506 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
2507 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
2508 | + * more details. | |
2509 | + * | |
2510 | + * You should have received a copy of the GNU General Public License along with | |
2511 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
2512 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
2513 | + * | |
2514 | + * Authors: | |
2515 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
2516 | + * Hank Janssen <hjanssen@microsoft.com> | |
2517 | + * | |
2518 | + */ | |
2519 | + | |
2520 | + | |
2521 | +#ifndef _CHANNEL_MGMT_H_ | |
2522 | +#define _CHANNEL_MGMT_H_ | |
2523 | + | |
2524 | +#include "osd.h" | |
2525 | +#include "List.h" | |
2526 | +#include "RingBuffer.h" | |
2527 | + | |
2528 | +#include "VmbusChannelInterface.h" | |
2529 | +#include "ChannelMessages.h" | |
2530 | + | |
2531 | + | |
2532 | + | |
2533 | +typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context); | |
2534 | + | |
2535 | +typedef enum { | |
2536 | + CHANNEL_OFFER_STATE, | |
2537 | + CHANNEL_OPENING_STATE, | |
2538 | + CHANNEL_OPEN_STATE, | |
2539 | +} VMBUS_CHANNEL_STATE; | |
2540 | + | |
2541 | +typedef struct _VMBUS_CHANNEL { | |
2542 | + LIST_ENTRY ListEntry; | |
2543 | + | |
2544 | + DEVICE_OBJECT* DeviceObject; | |
2545 | + | |
2546 | + HANDLE PollTimer; // SA-111 workaround | |
2547 | + | |
2548 | + VMBUS_CHANNEL_STATE State; | |
2549 | + | |
2550 | + VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg; | |
2551 | + // These are based on the OfferMsg.MonitorId. Save it here for easy access. | |
2552 | + UINT8 MonitorGroup; | |
2553 | + UINT8 MonitorBit; | |
2554 | + | |
2555 | + UINT32 RingBufferGpadlHandle; | |
2556 | + | |
2557 | + // Allocated memory for ring buffer | |
2558 | + VOID* RingBufferPages; | |
2559 | + UINT32 RingBufferPageCount; | |
2560 | + RING_BUFFER_INFO Outbound; // send to parent | |
2561 | + RING_BUFFER_INFO Inbound; // receive from parent | |
2562 | + HANDLE InboundLock; | |
2563 | + HANDLE ControlWQ; | |
2564 | + | |
2565 | + // Channel callback are invoked in this workqueue context | |
2566 | + //HANDLE dataWorkQueue; | |
2567 | + | |
2568 | + PFN_CHANNEL_CALLBACK OnChannelCallback; | |
2569 | + PVOID ChannelCallbackContext; | |
2570 | + | |
2571 | +} VMBUS_CHANNEL; | |
2572 | + | |
2573 | + | |
2574 | +typedef struct _VMBUS_CHANNEL_DEBUG_INFO { | |
2575 | + UINT32 RelId; | |
2576 | + VMBUS_CHANNEL_STATE State; | |
2577 | + GUID InterfaceType; | |
2578 | + GUID InterfaceInstance; | |
2579 | + UINT32 MonitorId; | |
2580 | + UINT32 ServerMonitorPending; | |
2581 | + UINT32 ServerMonitorLatency; | |
2582 | + UINT32 ServerMonitorConnectionId; | |
2583 | + UINT32 ClientMonitorPending; | |
2584 | + UINT32 ClientMonitorLatency; | |
2585 | + UINT32 ClientMonitorConnectionId; | |
2586 | + | |
2587 | + RING_BUFFER_DEBUG_INFO Inbound; | |
2588 | + RING_BUFFER_DEBUG_INFO Outbound; | |
2589 | +} VMBUS_CHANNEL_DEBUG_INFO; | |
2590 | + | |
2591 | + | |
2592 | +typedef union { | |
2593 | + VMBUS_CHANNEL_VERSION_SUPPORTED VersionSupported; | |
2594 | + VMBUS_CHANNEL_OPEN_RESULT OpenResult; | |
2595 | + VMBUS_CHANNEL_GPADL_TORNDOWN GpadlTorndown; | |
2596 | + VMBUS_CHANNEL_GPADL_CREATED GpadlCreated; | |
2597 | + VMBUS_CHANNEL_VERSION_RESPONSE VersionResponse; | |
2598 | +} VMBUS_CHANNEL_MESSAGE_RESPONSE; | |
2599 | + | |
2600 | + | |
2601 | +// Represents each channel msg on the vmbus connection | |
2602 | +// This is a variable-size data structure depending on | |
2603 | +// the msg type itself | |
2604 | +typedef struct _VMBUS_CHANNEL_MSGINFO { | |
2605 | + // Bookkeeping stuff | |
2606 | + LIST_ENTRY MsgListEntry; | |
2607 | + | |
2608 | + // So far, this is only used to handle gpadl body message | |
2609 | + LIST_ENTRY SubMsgList; | |
2610 | + | |
2611 | + // Synchronize the request/response if needed | |
2612 | + HANDLE WaitEvent; | |
2613 | + | |
2614 | + VMBUS_CHANNEL_MESSAGE_RESPONSE Response; | |
2615 | + | |
2616 | + UINT32 MessageSize; | |
2617 | + // The channel message that goes out on the "wire". | |
2618 | + // It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header | |
2619 | + unsigned char Msg[0]; | |
2620 | +} VMBUS_CHANNEL_MSGINFO; | |
2621 | + | |
2622 | + | |
2623 | +// | |
2624 | +// Routines | |
2625 | +// | |
2626 | + | |
2627 | +INTERNAL VMBUS_CHANNEL* | |
2628 | +AllocVmbusChannel( | |
2629 | + void | |
2630 | + ); | |
2631 | + | |
2632 | +INTERNAL void | |
2633 | +FreeVmbusChannel( | |
2634 | + VMBUS_CHANNEL *Channel | |
2635 | + ); | |
2636 | + | |
2637 | +INTERNAL void | |
2638 | +VmbusOnChannelMessage( | |
2639 | + void *Context | |
2640 | + ); | |
2641 | + | |
2642 | +INTERNAL int | |
2643 | +VmbusChannelRequestOffers( | |
2644 | + void | |
2645 | + ); | |
2646 | + | |
2647 | +INTERNAL void | |
2648 | +VmbusChannelReleaseUnattachedChannels( | |
2649 | + void | |
2650 | + ); | |
2651 | + | |
2652 | +#endif //_CHANNEL_MGMT_H_ | |
2653 | --- /dev/null | |
2654 | +++ b/drivers/staging/hv/Connection.c | |
2655 | @@ -0,0 +1,432 @@ | |
2656 | +/* | |
2657 | + * | |
2658 | + * Copyright (c) 2009, Microsoft Corporation. | |
2659 | + * | |
2660 | + * This program is free software; you can redistribute it and/or modify it | |
2661 | + * under the terms and conditions of the GNU General Public License, | |
2662 | + * version 2, as published by the Free Software Foundation. | |
2663 | + * | |
2664 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
2665 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
2666 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
2667 | + * more details. | |
2668 | + * | |
2669 | + * You should have received a copy of the GNU General Public License along with | |
2670 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
2671 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
2672 | + * | |
2673 | + * Authors: | |
2674 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
2675 | + * Hank Janssen <hjanssen@microsoft.com> | |
2676 | + * | |
2677 | + */ | |
2678 | + | |
2679 | + | |
2680 | +#include "logging.h" | |
2681 | + | |
2682 | +#include "VmbusPrivate.h" | |
2683 | + | |
2684 | +// | |
2685 | +// Globals | |
2686 | +// | |
2687 | + | |
2688 | + | |
2689 | +VMBUS_CONNECTION gVmbusConnection = { | |
2690 | + .ConnectState = Disconnected, | |
2691 | + .NextGpadlHandle = 0xE1E10, | |
2692 | +}; | |
2693 | + | |
2694 | + | |
2695 | +/*++ | |
2696 | + | |
2697 | +Name: | |
2698 | + VmbusConnect() | |
2699 | + | |
2700 | +Description: | |
2701 | + Sends a connect request on the partition service connection | |
2702 | + | |
2703 | +--*/ | |
2704 | +int | |
2705 | +VmbusConnect( | |
2706 | + ) | |
2707 | +{ | |
2708 | + int ret=0; | |
2709 | + VMBUS_CHANNEL_MSGINFO *msgInfo=NULL; | |
2710 | + VMBUS_CHANNEL_INITIATE_CONTACT *msg; | |
2711 | + | |
2712 | + DPRINT_ENTER(VMBUS); | |
2713 | + | |
2714 | + // Make sure we are not connecting or connected | |
2715 | + if (gVmbusConnection.ConnectState != Disconnected) | |
2716 | + return -1; | |
2717 | + | |
2718 | + // Initialize the vmbus connection | |
2719 | + gVmbusConnection.ConnectState = Connecting; | |
2720 | + gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ"); | |
2721 | + | |
2722 | + INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList); | |
2723 | + gVmbusConnection.ChannelMsgLock = SpinlockCreate(); | |
2724 | + | |
2725 | + INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList); | |
2726 | + gVmbusConnection.ChannelLock = SpinlockCreate(); | |
2727 | + | |
2728 | + // Setup the vmbus event connection for channel interrupt abstraction stuff | |
2729 | + gVmbusConnection.InterruptPage = PageAlloc(1); | |
2730 | + if (gVmbusConnection.InterruptPage == NULL) | |
2731 | + { | |
2732 | + ret = -1; | |
2733 | + goto Cleanup; | |
2734 | + } | |
2735 | + | |
2736 | + gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage; | |
2737 | + gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1)); | |
2738 | + | |
2739 | + // Setup the monitor notification facility. The 1st page for parent->child and the 2nd page for child->parent | |
2740 | + gVmbusConnection.MonitorPages = PageAlloc(2); | |
2741 | + if (gVmbusConnection.MonitorPages == NULL) | |
2742 | + { | |
2743 | + ret = -1; | |
2744 | + goto Cleanup; | |
2745 | + } | |
2746 | + | |
2747 | + msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT)); | |
2748 | + if (msgInfo == NULL) | |
2749 | + { | |
2750 | + ret = -1; | |
2751 | + goto Cleanup; | |
2752 | + } | |
2753 | + | |
2754 | + msgInfo->WaitEvent = WaitEventCreate(); | |
2755 | + msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg; | |
2756 | + | |
2757 | + msg->Header.MessageType = ChannelMessageInitiateContact; | |
2758 | + msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER; | |
2759 | + msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage); | |
2760 | + msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages); | |
2761 | + msg->MonitorPage2 = GetPhysicalAddress((PVOID)((ULONG_PTR)gVmbusConnection.MonitorPages + PAGE_SIZE)); | |
2762 | + | |
2763 | + // Add to list before we send the request since we may receive the response | |
2764 | + // before returning from this routine | |
2765 | + SpinlockAcquire(gVmbusConnection.ChannelMsgLock); | |
2766 | + INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry); | |
2767 | + SpinlockRelease(gVmbusConnection.ChannelMsgLock); | |
2768 | + | |
2769 | + DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx", | |
2770 | + msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2); | |
2771 | + | |
2772 | + DPRINT_DBG(VMBUS, "Sending channel initiate msg..."); | |
2773 | + | |
2774 | + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT)); | |
2775 | + if (ret != 0) | |
2776 | + { | |
2777 | + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); | |
2778 | + goto Cleanup; | |
2779 | + } | |
2780 | + | |
2781 | + // Wait for the connection response | |
2782 | + WaitEventWait(msgInfo->WaitEvent); | |
2783 | + | |
2784 | + REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); | |
2785 | + | |
2786 | + // Check if successful | |
2787 | + if (msgInfo->Response.VersionResponse.VersionSupported) | |
2788 | + { | |
2789 | + DPRINT_INFO(VMBUS, "Vmbus connected!!"); | |
2790 | + gVmbusConnection.ConnectState = Connected; | |
2791 | + | |
2792 | + } | |
2793 | + else | |
2794 | + { | |
2795 | + DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER); | |
2796 | + ret = -1; | |
2797 | + | |
2798 | + goto Cleanup; | |
2799 | + } | |
2800 | + | |
2801 | + | |
2802 | + WaitEventClose(msgInfo->WaitEvent); | |
2803 | + MemFree(msgInfo); | |
2804 | + DPRINT_EXIT(VMBUS); | |
2805 | + | |
2806 | + return 0; | |
2807 | + | |
2808 | +Cleanup: | |
2809 | + | |
2810 | + gVmbusConnection.ConnectState = Disconnected; | |
2811 | + | |
2812 | + WorkQueueClose(gVmbusConnection.WorkQueue); | |
2813 | + SpinlockClose(gVmbusConnection.ChannelLock); | |
2814 | + SpinlockClose(gVmbusConnection.ChannelMsgLock); | |
2815 | + | |
2816 | + if (gVmbusConnection.InterruptPage) | |
2817 | + { | |
2818 | + PageFree(gVmbusConnection.InterruptPage, 1); | |
2819 | + gVmbusConnection.InterruptPage = NULL; | |
2820 | + } | |
2821 | + | |
2822 | + if (gVmbusConnection.MonitorPages) | |
2823 | + { | |
2824 | + PageFree(gVmbusConnection.MonitorPages, 2); | |
2825 | + gVmbusConnection.MonitorPages = NULL; | |
2826 | + } | |
2827 | + | |
2828 | + if (msgInfo) | |
2829 | + { | |
2830 | + if (msgInfo->WaitEvent) | |
2831 | + WaitEventClose(msgInfo->WaitEvent); | |
2832 | + | |
2833 | + MemFree(msgInfo); | |
2834 | + } | |
2835 | + | |
2836 | + DPRINT_EXIT(VMBUS); | |
2837 | + | |
2838 | + return ret; | |
2839 | +} | |
2840 | + | |
2841 | + | |
2842 | +/*++ | |
2843 | + | |
2844 | +Name: | |
2845 | + VmbusDisconnect() | |
2846 | + | |
2847 | +Description: | |
2848 | + Sends a disconnect request on the partition service connection | |
2849 | + | |
2850 | +--*/ | |
2851 | +int | |
2852 | +VmbusDisconnect( | |
2853 | + VOID | |
2854 | + ) | |
2855 | +{ | |
2856 | + int ret=0; | |
2857 | + VMBUS_CHANNEL_UNLOAD *msg; | |
2858 | + | |
2859 | + DPRINT_ENTER(VMBUS); | |
2860 | + | |
2861 | + // Make sure we are connected | |
2862 | + if (gVmbusConnection.ConnectState != Connected) | |
2863 | + return -1; | |
2864 | + | |
2865 | + msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD)); | |
2866 | + | |
2867 | + msg->MessageType = ChannelMessageUnload; | |
2868 | + | |
2869 | + ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD)); | |
2870 | + | |
2871 | + if (ret != 0) | |
2872 | + { | |
2873 | + goto Cleanup; | |
2874 | + } | |
2875 | + | |
2876 | + PageFree(gVmbusConnection.InterruptPage, 1); | |
2877 | + | |
2878 | + // TODO: iterate thru the msg list and free up | |
2879 | + | |
2880 | + SpinlockClose(gVmbusConnection.ChannelMsgLock); | |
2881 | + | |
2882 | + WorkQueueClose(gVmbusConnection.WorkQueue); | |
2883 | + | |
2884 | + gVmbusConnection.ConnectState = Disconnected; | |
2885 | + | |
2886 | + DPRINT_INFO(VMBUS, "Vmbus disconnected!!"); | |
2887 | + | |
2888 | +Cleanup: | |
2889 | + if (msg) | |
2890 | + { | |
2891 | + MemFree(msg); | |
2892 | + } | |
2893 | + | |
2894 | + DPRINT_EXIT(VMBUS); | |
2895 | + | |
2896 | + return ret; | |
2897 | +} | |
2898 | + | |
2899 | + | |
2900 | +/*++ | |
2901 | + | |
2902 | +Name: | |
2903 | + GetChannelFromRelId() | |
2904 | + | |
2905 | +Description: | |
2906 | + Get the channel object given its child relative id (ie channel id) | |
2907 | + | |
2908 | +--*/ | |
2909 | +VMBUS_CHANNEL* | |
2910 | +GetChannelFromRelId( | |
2911 | + UINT32 relId | |
2912 | + ) | |
2913 | +{ | |
2914 | + VMBUS_CHANNEL* channel; | |
2915 | + VMBUS_CHANNEL* foundChannel=NULL; | |
2916 | + LIST_ENTRY* anchor; | |
2917 | + LIST_ENTRY* curr; | |
2918 | + | |
2919 | + SpinlockAcquire(gVmbusConnection.ChannelLock); | |
2920 | + ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) | |
2921 | + { | |
2922 | + channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry); | |
2923 | + | |
2924 | + if (channel->OfferMsg.ChildRelId == relId) | |
2925 | + { | |
2926 | + foundChannel = channel; | |
2927 | + break; | |
2928 | + } | |
2929 | + } | |
2930 | + SpinlockRelease(gVmbusConnection.ChannelLock); | |
2931 | + | |
2932 | + return foundChannel; | |
2933 | +} | |
2934 | + | |
2935 | + | |
2936 | + | |
2937 | +/*++ | |
2938 | + | |
2939 | +Name: | |
2940 | + VmbusProcessChannelEvent() | |
2941 | + | |
2942 | +Description: | |
2943 | + Process a channel event notification | |
2944 | + | |
2945 | +--*/ | |
2946 | +static void | |
2947 | +VmbusProcessChannelEvent( | |
2948 | + PVOID context | |
2949 | + ) | |
2950 | +{ | |
2951 | + VMBUS_CHANNEL* channel; | |
2952 | + UINT32 relId = (UINT32)(ULONG_PTR)context; | |
2953 | + | |
2954 | + ASSERT(relId > 0); | |
2955 | + | |
2956 | + // Find the channel based on this relid and invokes | |
2957 | + // the channel callback to process the event | |
2958 | + channel = GetChannelFromRelId(relId); | |
2959 | + | |
2960 | + if (channel) | |
2961 | + { | |
2962 | + VmbusChannelOnChannelEvent(channel); | |
2963 | + //WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel); | |
2964 | + } | |
2965 | + else | |
2966 | + { | |
2967 | + DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId); | |
2968 | + } | |
2969 | +} | |
2970 | + | |
2971 | + | |
2972 | +/*++ | |
2973 | + | |
2974 | +Name: | |
2975 | + VmbusOnEvents() | |
2976 | + | |
2977 | +Description: | |
2978 | + Handler for events | |
2979 | + | |
2980 | +--*/ | |
2981 | +VOID | |
2982 | +VmbusOnEvents( | |
2983 | + VOID | |
2984 | + ) | |
2985 | +{ | |
2986 | + int dword; | |
2987 | + //int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes | |
2988 | + int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; | |
2989 | + int bit; | |
2990 | + int relid; | |
2991 | + UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage; | |
2992 | + //VMBUS_CHANNEL_MESSAGE* receiveMsg; | |
2993 | + | |
2994 | + DPRINT_ENTER(VMBUS); | |
2995 | + | |
2996 | + // Check events | |
2997 | + if (recvInterruptPage) | |
2998 | + { | |
2999 | + for (dword = 0; dword < maxdword; dword++) | |
3000 | + { | |
3001 | + if (recvInterruptPage[dword]) | |
3002 | + { | |
3003 | + for (bit = 0; bit < 32; bit++) | |
3004 | + { | |
3005 | + if (BitTestAndClear(&recvInterruptPage[dword], bit)) | |
3006 | + { | |
3007 | + relid = (dword << 5) + bit; | |
3008 | + | |
3009 | + DPRINT_DBG(VMBUS, "event detected for relid - %d", relid); | |
3010 | + | |
3011 | + if (relid == 0) // special case - vmbus channel protocol msg | |
3012 | + { | |
3013 | + DPRINT_DBG(VMBUS, "invalid relid - %d", relid); | |
3014 | + | |
3015 | + continue; } | |
3016 | + else | |
3017 | + { | |
3018 | + //QueueWorkItem(VmbusProcessEvent, (void*)relid); | |
3019 | + //ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); | |
3020 | + VmbusProcessChannelEvent((void*)(ULONG_PTR)relid); | |
3021 | + } | |
3022 | + } | |
3023 | + } | |
3024 | + } | |
3025 | + } | |
3026 | + } | |
3027 | + DPRINT_EXIT(VMBUS); | |
3028 | + | |
3029 | + return; | |
3030 | +} | |
3031 | + | |
3032 | +/*++ | |
3033 | + | |
3034 | +Name: | |
3035 | + VmbusPostMessage() | |
3036 | + | |
3037 | +Description: | |
3038 | + Send a msg on the vmbus's message connection | |
3039 | + | |
3040 | +--*/ | |
3041 | +int | |
3042 | +VmbusPostMessage( | |
3043 | + PVOID buffer, | |
3044 | + SIZE_T bufferLen | |
3045 | + ) | |
3046 | +{ | |
3047 | + int ret=0; | |
3048 | + HV_CONNECTION_ID connId; | |
3049 | + | |
3050 | + | |
3051 | + connId.AsUINT32 =0; | |
3052 | + connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID; | |
3053 | + ret = HvPostMessage( | |
3054 | + connId, | |
3055 | + 1, | |
3056 | + buffer, | |
3057 | + bufferLen); | |
3058 | + | |
3059 | + return ret; | |
3060 | +} | |
3061 | + | |
3062 | +/*++ | |
3063 | + | |
3064 | +Name: | |
3065 | + VmbusSetEvent() | |
3066 | + | |
3067 | +Description: | |
3068 | + Send an event notification to the parent | |
3069 | + | |
3070 | +--*/ | |
3071 | +int | |
3072 | +VmbusSetEvent(UINT32 childRelId) | |
3073 | +{ | |
3074 | + int ret=0; | |
3075 | + | |
3076 | + DPRINT_ENTER(VMBUS); | |
3077 | + | |
3078 | + // Each UINT32 represents 32 channels | |
3079 | + BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31); | |
3080 | + ret = HvSignalEvent(); | |
3081 | + | |
3082 | + DPRINT_EXIT(VMBUS); | |
3083 | + | |
3084 | + return ret; | |
3085 | +} | |
3086 | + | |
3087 | +// EOF | |
3088 | --- /dev/null | |
3089 | +++ b/drivers/staging/hv/Hv.c | |
3090 | @@ -0,0 +1,672 @@ | |
3091 | +/* | |
3092 | + * | |
3093 | + * Copyright (c) 2009, Microsoft Corporation. | |
3094 | + * | |
3095 | + * This program is free software; you can redistribute it and/or modify it | |
3096 | + * under the terms and conditions of the GNU General Public License, | |
3097 | + * version 2, as published by the Free Software Foundation. | |
3098 | + * | |
3099 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
3100 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
3101 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
3102 | + * more details. | |
3103 | + * | |
3104 | + * You should have received a copy of the GNU General Public License along with | |
3105 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
3106 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
3107 | + * | |
3108 | + * Authors: | |
3109 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
3110 | + * Hank Janssen <hjanssen@microsoft.com> | |
3111 | + * | |
3112 | + */ | |
3113 | + | |
3114 | + | |
3115 | +#include "logging.h" | |
3116 | +#include "VmbusPrivate.h" | |
3117 | + | |
3118 | +// | |
3119 | +// Globals | |
3120 | +// | |
3121 | + | |
3122 | +// The one and only | |
3123 | +HV_CONTEXT gHvContext={ | |
3124 | + .SynICInitialized = FALSE, | |
3125 | + .HypercallPage = NULL, | |
3126 | + .SignalEventParam = NULL, | |
3127 | + .SignalEventBuffer = NULL, | |
3128 | +}; | |
3129 | + | |
3130 | + | |
3131 | +/*++ | |
3132 | + | |
3133 | +Name: | |
3134 | + HvQueryHypervisorPresence() | |
3135 | + | |
3136 | +Description: | |
3137 | + Query the cpuid for presense of windows hypervisor | |
3138 | + | |
3139 | +--*/ | |
3140 | +static int | |
3141 | +HvQueryHypervisorPresence ( | |
3142 | + void | |
3143 | + ) | |
3144 | +{ | |
3145 | + unsigned int eax; | |
3146 | + unsigned int ebx; | |
3147 | + unsigned int ecx; | |
3148 | + unsigned int edx; | |
3149 | + unsigned int op; | |
3150 | + | |
3151 | + eax = 0; | |
3152 | + ebx = 0; | |
3153 | + ecx = 0; | |
3154 | + edx = 0; | |
3155 | + op = HvCpuIdFunctionVersionAndFeatures; | |
3156 | + do_cpuid(op, &eax, &ebx, &ecx, &edx); | |
3157 | + | |
3158 | + return (ecx & HV_PRESENT_BIT); | |
3159 | +} | |
3160 | + | |
3161 | + | |
3162 | +/*++ | |
3163 | + | |
3164 | +Name: | |
3165 | + HvQueryHypervisorInfo() | |
3166 | + | |
3167 | +Description: | |
3168 | + Get version info of the windows hypervisor | |
3169 | + | |
3170 | +--*/ | |
3171 | +static int | |
3172 | +HvQueryHypervisorInfo ( | |
3173 | + void | |
3174 | + ) | |
3175 | +{ | |
3176 | + unsigned int eax; | |
3177 | + unsigned int ebx; | |
3178 | + unsigned int ecx; | |
3179 | + unsigned int edx; | |
3180 | + unsigned int maxLeaf; | |
3181 | + unsigned int op; | |
3182 | + | |
3183 | + // | |
3184 | + // Its assumed that this is called after confirming that Viridian is present. | |
3185 | + // Query id and revision. | |
3186 | + // | |
3187 | + | |
3188 | + eax = 0; | |
3189 | + ebx = 0; | |
3190 | + ecx = 0; | |
3191 | + edx = 0; | |
3192 | + op = HvCpuIdFunctionHvVendorAndMaxFunction; | |
3193 | + do_cpuid(op, &eax, &ebx, &ecx, &edx); | |
3194 | + | |
3195 | + DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c", | |
3196 | + (ebx & 0xFF), | |
3197 | + ((ebx >> 8) & 0xFF), | |
3198 | + ((ebx >> 16) & 0xFF), | |
3199 | + ((ebx >> 24) & 0xFF), | |
3200 | + (ecx & 0xFF), | |
3201 | + ((ecx >> 8) & 0xFF), | |
3202 | + ((ecx >> 16) & 0xFF), | |
3203 | + ((ecx >> 24) & 0xFF), | |
3204 | + (edx & 0xFF), | |
3205 | + ((edx >> 8) & 0xFF), | |
3206 | + ((edx >> 16) & 0xFF), | |
3207 | + ((edx >> 24) & 0xFF)); | |
3208 | + | |
3209 | + maxLeaf = eax; | |
3210 | + eax = 0; | |
3211 | + ebx = 0; | |
3212 | + ecx = 0; | |
3213 | + edx = 0; | |
3214 | + op = HvCpuIdFunctionHvInterface; | |
3215 | + do_cpuid(op, &eax, &ebx, &ecx, &edx); | |
3216 | + | |
3217 | + DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c", | |
3218 | + (eax & 0xFF), | |
3219 | + ((eax >> 8) & 0xFF), | |
3220 | + ((eax >> 16) & 0xFF), | |
3221 | + ((eax >> 24) & 0xFF)); | |
3222 | + | |
3223 | + if (maxLeaf >= HvCpuIdFunctionMsHvVersion) { | |
3224 | + eax = 0; | |
3225 | + ebx = 0; | |
3226 | + ecx = 0; | |
3227 | + edx = 0; | |
3228 | + op = HvCpuIdFunctionMsHvVersion; | |
3229 | + do_cpuid(op, &eax, &ebx, &ecx, &edx); | |
3230 | + DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d", | |
3231 | + eax, | |
3232 | + ebx >> 16, | |
3233 | + ebx & 0xFFFF, | |
3234 | + ecx, | |
3235 | + edx >> 24, | |
3236 | + edx & 0xFFFFFF); | |
3237 | + } | |
3238 | + return maxLeaf; | |
3239 | +} | |
3240 | + | |
3241 | + | |
3242 | +/*++ | |
3243 | + | |
3244 | +Name: | |
3245 | + HvDoHypercall() | |
3246 | + | |
3247 | +Description: | |
3248 | + Invoke the specified hypercall | |
3249 | + | |
3250 | +--*/ | |
3251 | +static UINT64 | |
3252 | +HvDoHypercall ( | |
3253 | + UINT64 Control, | |
3254 | + void* Input, | |
3255 | + void* Output | |
3256 | + ) | |
3257 | +{ | |
3258 | +#ifdef x86_64 | |
3259 | + UINT64 hvStatus=0; | |
3260 | + UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; | |
3261 | + UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; | |
3262 | + volatile void* hypercallPage = gHvContext.HypercallPage; | |
3263 | + | |
3264 | + DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>", | |
3265 | + Control, | |
3266 | + inputAddress, | |
3267 | + Input, | |
3268 | + outputAddress, | |
3269 | + Output, | |
3270 | + hypercallPage); | |
3271 | + | |
3272 | + __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8"); | |
3273 | + __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage)); | |
3274 | + | |
3275 | + DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus); | |
3276 | + | |
3277 | + return hvStatus; | |
3278 | + | |
3279 | +#else | |
3280 | + | |
3281 | + UINT32 controlHi = Control >> 32; | |
3282 | + UINT32 controlLo = Control & 0xFFFFFFFF; | |
3283 | + UINT32 hvStatusHi = 1; | |
3284 | + UINT32 hvStatusLo = 1; | |
3285 | + UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0; | |
3286 | + UINT32 inputAddressHi = inputAddress >> 32; | |
3287 | + UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF; | |
3288 | + UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0; | |
3289 | + UINT32 outputAddressHi = outputAddress >> 32; | |
3290 | + UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF; | |
3291 | + volatile void* hypercallPage = gHvContext.HypercallPage; | |
3292 | + | |
3293 | + DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>", | |
3294 | + Control, | |
3295 | + Input, | |
3296 | + Output); | |
3297 | + | |
3298 | + __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage)); | |
3299 | + | |
3300 | + | |
3301 | + DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32)); | |
3302 | + | |
3303 | + return (hvStatusLo | ((UINT64)hvStatusHi << 32)); | |
3304 | +#endif // x86_64 | |
3305 | +} | |
3306 | + | |
3307 | +/*++ | |
3308 | + | |
3309 | +Name: | |
3310 | + HvInit() | |
3311 | + | |
3312 | +Description: | |
3313 | + Main initialization routine. This routine must be called | |
3314 | + before any other routines in here are called | |
3315 | + | |
3316 | +--*/ | |
3317 | +static int | |
3318 | +HvInit ( | |
3319 | + void | |
3320 | + ) | |
3321 | +{ | |
3322 | + int ret=0; | |
3323 | + int maxLeaf; | |
3324 | + HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | |
3325 | + void* virtAddr=0; | |
3326 | + ULONG_PTR physAddr=0; | |
3327 | + | |
3328 | + DPRINT_ENTER(VMBUS); | |
3329 | + | |
3330 | + memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); | |
3331 | + memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); | |
3332 | + | |
3333 | + if (!HvQueryHypervisorPresence()) | |
3334 | + { | |
3335 | + DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!"); | |
3336 | + goto Cleanup; | |
3337 | + } | |
3338 | + | |
3339 | + DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info..."); | |
3340 | + | |
3341 | + maxLeaf = HvQueryHypervisorInfo(); | |
3342 | + //HvQueryHypervisorFeatures(maxLeaf); | |
3343 | + | |
3344 | + // Determine if we are running on xenlinux (ie x2v shim) or native linux | |
3345 | + gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID); | |
3346 | + | |
3347 | + if (gHvContext.GuestId == 0) | |
3348 | + { | |
3349 | + // Write our OS info | |
3350 | + WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); | |
3351 | + | |
3352 | + gHvContext.GuestId = HV_LINUX_GUEST_ID; | |
3353 | + } | |
3354 | + | |
3355 | + // See if the hypercall page is already set | |
3356 | + hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); | |
3357 | + | |
3358 | + if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | |
3359 | + { | |
3360 | + // Allocate the hypercall page memory | |
3361 | + //virtAddr = PageAlloc(1); | |
3362 | + virtAddr = VirtualAllocExec(PAGE_SIZE); | |
3363 | + | |
3364 | + if (!virtAddr) | |
3365 | + { | |
3366 | + DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!"); | |
3367 | + goto Cleanup; | |
3368 | + } | |
3369 | + | |
3370 | + hypercallMsr.Enable = 1; | |
3371 | + //hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT; | |
3372 | + hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT; | |
3373 | + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | |
3374 | + | |
3375 | + // Confirm that hypercall page did get setup. | |
3376 | + hypercallMsr.AsUINT64 = 0; | |
3377 | + hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); | |
3378 | + | |
3379 | + if (!hypercallMsr.Enable) | |
3380 | + { | |
3381 | + DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); | |
3382 | + goto Cleanup; | |
3383 | + } | |
3384 | + | |
3385 | + gHvContext.HypercallPage = virtAddr; | |
3386 | + } | |
3387 | + else | |
3388 | + { | |
3389 | + DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId); | |
3390 | + goto Cleanup; | |
3391 | + } | |
3392 | + | |
3393 | + DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x", | |
3394 | + (unsigned long)gHvContext.HypercallPage, | |
3395 | + (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); | |
3396 | + | |
3397 | + // Setup the global signal event param for the signal event hypercall | |
3398 | + gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER)); | |
3399 | + if (!gHvContext.SignalEventBuffer) | |
3400 | + { | |
3401 | + goto Cleanup; | |
3402 | + } | |
3403 | + | |
3404 | + gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN)); | |
3405 | + gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0; | |
3406 | + gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID; | |
3407 | + gHvContext.SignalEventParam->FlagNumber = 0; | |
3408 | + gHvContext.SignalEventParam->RsvdZ = 0; | |
3409 | + | |
3410 | + //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); | |
3411 | + | |
3412 | + DPRINT_EXIT(VMBUS); | |
3413 | + | |
3414 | + return ret; | |
3415 | + | |
3416 | +Cleanup: | |
3417 | + if (virtAddr) | |
3418 | + { | |
3419 | + if (hypercallMsr.Enable) | |
3420 | + { | |
3421 | + hypercallMsr.AsUINT64 = 0; | |
3422 | + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | |
3423 | + } | |
3424 | + | |
3425 | + VirtualFree(virtAddr); | |
3426 | + } | |
3427 | + ret = -1; | |
3428 | + DPRINT_EXIT(VMBUS); | |
3429 | + | |
3430 | + return ret; | |
3431 | +} | |
3432 | + | |
3433 | + | |
3434 | +/*++ | |
3435 | + | |
3436 | +Name: | |
3437 | + HvCleanup() | |
3438 | + | |
3439 | +Description: | |
3440 | + Cleanup routine. This routine is called normally during driver unloading or exiting. | |
3441 | + | |
3442 | +--*/ | |
3443 | +void | |
3444 | +HvCleanup ( | |
3445 | + void | |
3446 | + ) | |
3447 | +{ | |
3448 | + HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; | |
3449 | + | |
3450 | + DPRINT_ENTER(VMBUS); | |
3451 | + | |
3452 | + if (gHvContext.SignalEventBuffer) | |
3453 | + { | |
3454 | + MemFree(gHvContext.SignalEventBuffer); | |
3455 | + gHvContext.SignalEventBuffer = NULL; | |
3456 | + gHvContext.SignalEventParam = NULL; | |
3457 | + } | |
3458 | + | |
3459 | + if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | |
3460 | + { | |
3461 | + if (gHvContext.HypercallPage) | |
3462 | + { | |
3463 | + hypercallMsr.AsUINT64 = 0; | |
3464 | + WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); | |
3465 | + VirtualFree(gHvContext.HypercallPage); | |
3466 | + gHvContext.HypercallPage = NULL; | |
3467 | + } | |
3468 | + } | |
3469 | + | |
3470 | + DPRINT_EXIT(VMBUS); | |
3471 | + | |
3472 | +} | |
3473 | + | |
3474 | + | |
3475 | +/*++ | |
3476 | + | |
3477 | +Name: | |
3478 | + HvPostMessage() | |
3479 | + | |
3480 | +Description: | |
3481 | + Post a message using the hypervisor message IPC. This | |
3482 | + involves a hypercall. | |
3483 | + | |
3484 | +--*/ | |
3485 | +HV_STATUS | |
3486 | +HvPostMessage( | |
3487 | + HV_CONNECTION_ID connectionId, | |
3488 | + HV_MESSAGE_TYPE messageType, | |
3489 | + PVOID payload, | |
3490 | + SIZE_T payloadSize | |
3491 | + ) | |
3492 | +{ | |
3493 | + struct alignedInput { | |
3494 | + UINT64 alignment8; | |
3495 | + HV_INPUT_POST_MESSAGE msg; | |
3496 | + }; | |
3497 | + | |
3498 | + PHV_INPUT_POST_MESSAGE alignedMsg; | |
3499 | + HV_STATUS status; | |
3500 | + ULONG_PTR addr; | |
3501 | + | |
3502 | + if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT) | |
3503 | + { | |
3504 | + return -1; | |
3505 | + } | |
3506 | + | |
3507 | + addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput)); | |
3508 | + | |
3509 | + if (!addr) | |
3510 | + { | |
3511 | + return -1; | |
3512 | + } | |
3513 | + | |
3514 | + alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); | |
3515 | + | |
3516 | + alignedMsg->ConnectionId = connectionId; | |
3517 | + alignedMsg->MessageType = messageType; | |
3518 | + alignedMsg->PayloadSize = payloadSize; | |
3519 | + memcpy((void*)alignedMsg->Payload, payload, payloadSize); | |
3520 | + | |
3521 | + status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF; | |
3522 | + | |
3523 | + MemFree((void*)addr); | |
3524 | + | |
3525 | + return status; | |
3526 | +} | |
3527 | + | |
3528 | + | |
3529 | +/*++ | |
3530 | + | |
3531 | +Name: | |
3532 | + HvSignalEvent() | |
3533 | + | |
3534 | +Description: | |
3535 | + Signal an event on the specified connection using the hypervisor event IPC. This | |
3536 | + involves a hypercall. | |
3537 | + | |
3538 | +--*/ | |
3539 | +HV_STATUS | |
3540 | +HvSignalEvent( | |
3541 | + ) | |
3542 | +{ | |
3543 | + HV_STATUS status; | |
3544 | + | |
3545 | + status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF; | |
3546 | + | |
3547 | + return status; | |
3548 | +} | |
3549 | + | |
3550 | + | |
3551 | +/*++ | |
3552 | + | |
3553 | +Name: | |
3554 | + HvSynicInit() | |
3555 | + | |
3556 | +Description: | |
3557 | + Initialize the Synthethic Interrupt Controller. If it is already initialized by | |
3558 | + another entity (ie x2v shim), we need to retrieve the initialized message and event pages. | |
3559 | + Otherwise, we create and initialize the message and event pages. | |
3560 | + | |
3561 | +--*/ | |
3562 | +int | |
3563 | +HvSynicInit ( | |
3564 | + UINT32 irqVector | |
3565 | + ) | |
3566 | +{ | |
3567 | + UINT64 version; | |
3568 | + HV_SYNIC_SIMP simp; | |
3569 | + HV_SYNIC_SIEFP siefp; | |
3570 | + HV_SYNIC_SINT sharedSint; | |
3571 | + HV_SYNIC_SCONTROL sctrl; | |
3572 | + UINT64 guestID; | |
3573 | + int ret=0; | |
3574 | + | |
3575 | + DPRINT_ENTER(VMBUS); | |
3576 | + | |
3577 | + if (!gHvContext.HypercallPage) | |
3578 | + { | |
3579 | + DPRINT_EXIT(VMBUS); | |
3580 | + return ret; | |
3581 | + } | |
3582 | + | |
3583 | + // Check the version | |
3584 | + version = ReadMsr(HV_X64_MSR_SVERSION); | |
3585 | + | |
3586 | + DPRINT_INFO(VMBUS, "SynIC version: %llx", version); | |
3587 | + | |
3588 | + // TODO: Handle SMP | |
3589 | + if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) | |
3590 | + { | |
3591 | + DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set."); | |
3592 | + | |
3593 | + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | |
3594 | + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | |
3595 | + | |
3596 | + DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64); | |
3597 | + | |
3598 | + // Determine if we are running on xenlinux (ie x2v shim) or native linux | |
3599 | + guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID); | |
3600 | + | |
3601 | + if (guestID == HV_LINUX_GUEST_ID) | |
3602 | + { | |
3603 | + gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT); | |
3604 | + gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT); | |
3605 | + } | |
3606 | + else | |
3607 | + { | |
3608 | + DPRINT_ERR(VMBUS, "unknown guest id!!"); | |
3609 | + goto Cleanup; | |
3610 | + } | |
3611 | + DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]); | |
3612 | + } | |
3613 | + else | |
3614 | + { | |
3615 | + gHvContext.synICMessagePage[0] = PageAlloc(1); | |
3616 | + if (gHvContext.synICMessagePage[0] == NULL) | |
3617 | + { | |
3618 | + DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!"); | |
3619 | + goto Cleanup; | |
3620 | + } | |
3621 | + | |
3622 | + gHvContext.synICEventPage[0] = PageAlloc(1); | |
3623 | + if (gHvContext.synICEventPage[0] == NULL) | |
3624 | + { | |
3625 | + DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!"); | |
3626 | + goto Cleanup; | |
3627 | + } | |
3628 | + | |
3629 | + // | |
3630 | + // Setup the Synic's message page | |
3631 | + // | |
3632 | + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | |
3633 | + simp.SimpEnabled = 1; | |
3634 | + simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT; | |
3635 | + | |
3636 | + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64); | |
3637 | + | |
3638 | + WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); | |
3639 | + | |
3640 | + // | |
3641 | + // Setup the Synic's event page | |
3642 | + // | |
3643 | + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | |
3644 | + siefp.SiefpEnabled = 1; | |
3645 | + siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT; | |
3646 | + | |
3647 | + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64); | |
3648 | + | |
3649 | + WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); | |
3650 | + } | |
3651 | + // | |
3652 | + // Setup the interception SINT. | |
3653 | + // | |
3654 | + //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), | |
3655 | + // interceptionSint.AsUINT64); | |
3656 | + | |
3657 | + // | |
3658 | + // Setup the shared SINT. | |
3659 | + // | |
3660 | + sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); | |
3661 | + | |
3662 | + sharedSint.AsUINT64 = 0; | |
3663 | + sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20; | |
3664 | + sharedSint.Masked = FALSE; | |
3665 | + sharedSint.AutoEoi = TRUE; | |
3666 | + | |
3667 | + DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64); | |
3668 | + | |
3669 | + WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); | |
3670 | + | |
3671 | + // Enable the global synic bit | |
3672 | + sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL); | |
3673 | + sctrl.Enable = 1; | |
3674 | + | |
3675 | + WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); | |
3676 | + | |
3677 | + gHvContext.SynICInitialized = TRUE; | |
3678 | + | |
3679 | + DPRINT_EXIT(VMBUS); | |
3680 | + | |
3681 | + return ret; | |
3682 | + | |
3683 | +Cleanup: | |
3684 | + ret = -1; | |
3685 | + | |
3686 | + if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | |
3687 | + { | |
3688 | + if (gHvContext.synICEventPage[0]) | |
3689 | + { | |
3690 | + PageFree(gHvContext.synICEventPage[0],1); | |
3691 | + } | |
3692 | + | |
3693 | + if (gHvContext.synICMessagePage[0]) | |
3694 | + { | |
3695 | + PageFree(gHvContext.synICMessagePage[0], 1); | |
3696 | + } | |
3697 | + } | |
3698 | + | |
3699 | + DPRINT_EXIT(VMBUS); | |
3700 | + | |
3701 | + return ret; | |
3702 | + | |
3703 | +} | |
3704 | + | |
3705 | +/*++ | |
3706 | + | |
3707 | +Name: | |
3708 | + HvSynicCleanup() | |
3709 | + | |
3710 | +Description: | |
3711 | + Cleanup routine for HvSynicInit(). | |
3712 | + | |
3713 | +--*/ | |
3714 | +VOID | |
3715 | +HvSynicCleanup( | |
3716 | + VOID | |
3717 | + ) | |
3718 | +{ | |
3719 | + HV_SYNIC_SINT sharedSint; | |
3720 | + HV_SYNIC_SIMP simp; | |
3721 | + HV_SYNIC_SIEFP siefp; | |
3722 | + | |
3723 | + DPRINT_ENTER(VMBUS); | |
3724 | + | |
3725 | + if (!gHvContext.SynICInitialized) | |
3726 | + { | |
3727 | + DPRINT_EXIT(VMBUS); | |
3728 | + return; | |
3729 | + } | |
3730 | + | |
3731 | + sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); | |
3732 | + | |
3733 | + sharedSint.Masked = 1; | |
3734 | + | |
3735 | + // Disable the interrupt | |
3736 | + WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); | |
3737 | + | |
3738 | + // Disable and free the resources only if we are running as native linux | |
3739 | + // since in xenlinux, we are sharing the resources with the x2v shim | |
3740 | + if (gHvContext.GuestId == HV_LINUX_GUEST_ID) | |
3741 | + { | |
3742 | + simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); | |
3743 | + simp.SimpEnabled = 0; | |
3744 | + simp.BaseSimpGpa = 0; | |
3745 | + | |
3746 | + WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); | |
3747 | + | |
3748 | + siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); | |
3749 | + siefp.SiefpEnabled = 0; | |
3750 | + siefp.BaseSiefpGpa = 0; | |
3751 | + | |
3752 | + WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); | |
3753 | + | |
3754 | + PageFree(gHvContext.synICMessagePage[0], 1); | |
3755 | + PageFree(gHvContext.synICEventPage[0], 1); | |
3756 | + } | |
3757 | + | |
3758 | + DPRINT_EXIT(VMBUS); | |
3759 | +} | |
3760 | + | |
3761 | + | |
3762 | +// eof | |
3763 | --- /dev/null | |
3764 | +++ b/drivers/staging/hv/Hv.h | |
3765 | @@ -0,0 +1,184 @@ | |
3766 | +/* | |
3767 | + * | |
3768 | + * Copyright (c) 2009, Microsoft Corporation. | |
3769 | + * | |
3770 | + * This program is free software; you can redistribute it and/or modify it | |
3771 | + * under the terms and conditions of the GNU General Public License, | |
3772 | + * version 2, as published by the Free Software Foundation. | |
3773 | + * | |
3774 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
3775 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
3776 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
3777 | + * more details. | |
3778 | + * | |
3779 | + * You should have received a copy of the GNU General Public License along with | |
3780 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
3781 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
3782 | + * | |
3783 | + * Authors: | |
3784 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
3785 | + * Hank Janssen <hjanssen@microsoft.com> | |
3786 | + * | |
3787 | + */ | |
3788 | + | |
3789 | + | |
3790 | +#ifndef __HV_H__ | |
3791 | +#define __HV_H__ | |
3792 | + | |
3793 | +#include "osd.h" | |
3794 | + | |
3795 | +#include "HvTypes.h" | |
3796 | +#include "HvStatus.h" | |
3797 | +//#include "HvVmApi.h" | |
3798 | +//#include "HvKeApi.h" | |
3799 | +//#include "HvMmApi.h" | |
3800 | +//#include "HvCpuApi.h" | |
3801 | +#include "HvHalApi.h" | |
3802 | +#include "HvVpApi.h" | |
3803 | +//#include "HvTrApi.h" | |
3804 | +#include "HvSynicApi.h" | |
3805 | +//#include "HvAmApi.h" | |
3806 | +//#include "HvHkApi.h" | |
3807 | +//#include "HvValApi.h" | |
3808 | +#include "HvHcApi.h" | |
3809 | +#include "HvPtApi.h" | |
3810 | + | |
3811 | +enum | |
3812 | +{ | |
3813 | + VMBUS_MESSAGE_CONNECTION_ID = 1, | |
3814 | + VMBUS_MESSAGE_PORT_ID = 1, | |
3815 | + VMBUS_EVENT_CONNECTION_ID = 2, | |
3816 | + VMBUS_EVENT_PORT_ID = 2, | |
3817 | + VMBUS_MONITOR_CONNECTION_ID = 3, | |
3818 | + VMBUS_MONITOR_PORT_ID = 3, | |
3819 | + VMBUS_MESSAGE_SINT = 2 | |
3820 | +}; | |
3821 | +// | |
3822 | +// #defines | |
3823 | +// | |
3824 | +#define HV_PRESENT_BIT 0x80000000 | |
3825 | + | |
3826 | +#define HV_XENLINUX_GUEST_ID_LO 0x00000000 | |
3827 | +#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135 | |
3828 | +#define HV_XENLINUX_GUEST_ID (((UINT64)HV_XENLINUX_GUEST_ID_HI << 32) | HV_XENLINUX_GUEST_ID_LO) | |
3829 | + | |
3830 | +#define HV_LINUX_GUEST_ID_LO 0x00000000 | |
3831 | +#define HV_LINUX_GUEST_ID_HI 0xB16B00B5 | |
3832 | +#define HV_LINUX_GUEST_ID (((UINT64)HV_LINUX_GUEST_ID_HI << 32) | HV_LINUX_GUEST_ID_LO) | |
3833 | + | |
3834 | +#define HV_CPU_POWER_MANAGEMENT (1 << 0) | |
3835 | +#define HV_RECOMMENDATIONS_MAX 4 | |
3836 | + | |
3837 | +#define HV_X64_MAX 5 | |
3838 | +#define HV_CAPS_MAX 8 | |
3839 | + | |
3840 | + | |
3841 | +#define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64) | |
3842 | + | |
3843 | +// | |
3844 | +// Service definitions | |
3845 | +// | |
3846 | +#define HV_SERVICE_PARENT_PORT (0) | |
3847 | +#define HV_SERVICE_PARENT_CONNECTION (0) | |
3848 | + | |
3849 | +#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0) | |
3850 | +#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1) | |
3851 | +#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2) | |
3852 | +#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3) | |
3853 | + | |
3854 | +#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1) | |
3855 | +#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2) | |
3856 | +#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3) | |
3857 | +#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4) | |
3858 | +#define HV_SERVICE_MAX_MESSAGE_ID (4) | |
3859 | + | |
3860 | +#define HV_SERVICE_PROTOCOL_VERSION (0x0010) | |
3861 | +#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64 | |
3862 | + | |
3863 | +//#define VMBUS_REVISION_NUMBER 6 | |
3864 | +//#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine | |
3865 | + | |
3866 | +// 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 | |
3867 | +static const GUID VMBUS_SERVICE_ID = {.Data = {0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c, 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4} }; | |
3868 | + | |
3869 | +#define MAX_NUM_CPUS 1 | |
3870 | + | |
3871 | + | |
3872 | +typedef struct { | |
3873 | + UINT64 Align8; | |
3874 | + HV_INPUT_SIGNAL_EVENT Event; | |
3875 | +} HV_INPUT_SIGNAL_EVENT_BUFFER; | |
3876 | + | |
3877 | +typedef struct { | |
3878 | + UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized | |
3879 | + void* HypercallPage; | |
3880 | + | |
3881 | + BOOL SynICInitialized; | |
3882 | + // This is used as an input param to HvCallSignalEvent hypercall. The input param is immutable | |
3883 | + // in our usage and must be dynamic mem (vs stack or global). | |
3884 | + HV_INPUT_SIGNAL_EVENT_BUFFER *SignalEventBuffer; | |
3885 | + HV_INPUT_SIGNAL_EVENT *SignalEventParam; // 8-bytes aligned of the buffer above | |
3886 | + | |
3887 | + HANDLE synICMessagePage[MAX_NUM_CPUS]; | |
3888 | + HANDLE synICEventPage[MAX_NUM_CPUS]; | |
3889 | +} HV_CONTEXT; | |
3890 | + | |
3891 | +extern HV_CONTEXT gHvContext; | |
3892 | + | |
3893 | + | |
3894 | +// | |
3895 | +// Inline routines | |
3896 | +// | |
3897 | +static inline unsigned long long ReadMsr(int msr) | |
3898 | +{ | |
3899 | + unsigned long long val; | |
3900 | + | |
3901 | + RDMSR(msr, val); | |
3902 | + | |
3903 | + return val; | |
3904 | +} | |
3905 | + | |
3906 | +static inline void WriteMsr(int msr, UINT64 val) | |
3907 | +{ | |
3908 | + WRMSR(msr, val); | |
3909 | + | |
3910 | + return; | |
3911 | +} | |
3912 | + | |
3913 | +// | |
3914 | +// Hv Interface | |
3915 | +// | |
3916 | +INTERNAL int | |
3917 | +HvInit( | |
3918 | + VOID | |
3919 | + ); | |
3920 | + | |
3921 | +INTERNAL VOID | |
3922 | +HvCleanup( | |
3923 | + VOID | |
3924 | + ); | |
3925 | + | |
3926 | +INTERNAL HV_STATUS | |
3927 | +HvPostMessage( | |
3928 | + HV_CONNECTION_ID connectionId, | |
3929 | + HV_MESSAGE_TYPE messageType, | |
3930 | + PVOID payload, | |
3931 | + SIZE_T payloadSize | |
3932 | + ); | |
3933 | + | |
3934 | +INTERNAL HV_STATUS | |
3935 | +HvSignalEvent( | |
3936 | + VOID | |
3937 | + ); | |
3938 | + | |
3939 | +INTERNAL int | |
3940 | +HvSynicInit( | |
3941 | + UINT32 irqVector | |
3942 | + ); | |
3943 | + | |
3944 | +INTERNAL VOID | |
3945 | +HvSynicCleanup( | |
3946 | + VOID | |
3947 | + ); | |
3948 | + | |
3949 | +#endif // __HV_H__ | |
3950 | --- /dev/null | |
3951 | +++ b/drivers/staging/hv/osd.c | |
3952 | @@ -0,0 +1,500 @@ | |
3953 | +/* | |
3954 | + * | |
3955 | + * Copyright (c) 2009, Microsoft Corporation. | |
3956 | + * | |
3957 | + * This program is free software; you can redistribute it and/or modify it | |
3958 | + * under the terms and conditions of the GNU General Public License, | |
3959 | + * version 2, as published by the Free Software Foundation. | |
3960 | + * | |
3961 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
3962 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
3963 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
3964 | + * more details. | |
3965 | + * | |
3966 | + * You should have received a copy of the GNU General Public License along with | |
3967 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
3968 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
3969 | + * | |
3970 | + * Authors: | |
3971 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
3972 | + * Hank Janssen <hjanssen@microsoft.com> | |
3973 | + * | |
3974 | + */ | |
3975 | + | |
3976 | + | |
3977 | +#include <linux/module.h> | |
3978 | +#include <linux/init.h> | |
3979 | +#include <linux/types.h> | |
3980 | +#include <linux/mm.h> | |
3981 | +#include <linux/highmem.h> | |
3982 | +#include <linux/vmalloc.h> | |
3983 | +//#include <linux/config.h> | |
3984 | +#include <linux/ioport.h> | |
3985 | +#include <linux/irq.h> | |
3986 | +#include <linux/interrupt.h> | |
3987 | +#include <linux/wait.h> | |
3988 | +#include <linux/spinlock.h> | |
3989 | +#include <linux/workqueue.h> | |
3990 | +#include <linux/kernel.h> | |
3991 | +#include <linux/timer.h> | |
3992 | +#include <linux/jiffies.h> | |
3993 | +#include <linux/delay.h> | |
3994 | +#include <linux/time.h> | |
3995 | + | |
3996 | +#include <asm/io.h> | |
3997 | +#include <asm/bitops.h> | |
3998 | +#include <asm/kmap_types.h> | |
3999 | +#include <asm/atomic.h> | |
4000 | + | |
4001 | +#include "osd.h" | |
4002 | + | |
4003 | +// | |
4004 | +// Data types | |
4005 | +// | |
4006 | +typedef struct _TIMER { | |
4007 | + struct timer_list timer; | |
4008 | + PFN_TIMER_CALLBACK callback; | |
4009 | + void* context; | |
4010 | +}TIMER; | |
4011 | + | |
4012 | + | |
4013 | +typedef struct _WAITEVENT { | |
4014 | + int condition; | |
4015 | + wait_queue_head_t event; | |
4016 | +} WAITEVENT; | |
4017 | + | |
4018 | +typedef struct _SPINLOCK { | |
4019 | + spinlock_t lock; | |
4020 | + unsigned long flags; | |
4021 | +} SPINLOCK; | |
4022 | + | |
4023 | +typedef struct _WORKQUEUE { | |
4024 | + struct workqueue_struct *queue; | |
4025 | +} WORKQUEUE; | |
4026 | + | |
4027 | +typedef struct _WORKITEM { | |
4028 | + struct work_struct work; | |
4029 | + PFN_WORKITEM_CALLBACK callback; | |
4030 | + void* context; | |
4031 | +} WORKITEM; | |
4032 | + | |
4033 | + | |
4034 | +// | |
4035 | +// Global | |
4036 | +// | |
4037 | + | |
4038 | +void LogMsg(const char *fmt, ...) | |
4039 | +{ | |
4040 | +#ifdef KERNEL_2_6_5 | |
4041 | + char buf[1024]; | |
4042 | +#endif | |
4043 | + va_list args; | |
4044 | + | |
4045 | + va_start(args, fmt); | |
4046 | +#ifdef KERNEL_2_6_5 | |
4047 | + vsnprintf(buf, 1024, fmt, args); | |
4048 | + va_end(args); | |
4049 | + printk(buf); | |
4050 | +#else | |
4051 | + vprintk(fmt, args); | |
4052 | + va_end(args); | |
4053 | +#endif | |
4054 | +} | |
4055 | + | |
4056 | +void BitSet(unsigned int* addr, int bit) | |
4057 | +{ | |
4058 | + set_bit(bit, (unsigned long*)addr); | |
4059 | +} | |
4060 | + | |
4061 | +int BitTest(unsigned int* addr, int bit) | |
4062 | +{ | |
4063 | + return test_bit(bit, (unsigned long*)addr); | |
4064 | +} | |
4065 | + | |
4066 | +void BitClear(unsigned int* addr, int bit) | |
4067 | +{ | |
4068 | + clear_bit(bit, (unsigned long*)addr); | |
4069 | +} | |
4070 | + | |
4071 | +int BitTestAndClear(unsigned int* addr, int bit) | |
4072 | +{ | |
4073 | + return test_and_clear_bit(bit, (unsigned long*)addr); | |
4074 | +} | |
4075 | + | |
4076 | +int BitTestAndSet(unsigned int* addr, int bit) | |
4077 | +{ | |
4078 | + return test_and_set_bit(bit, (unsigned long*)addr); | |
4079 | +} | |
4080 | + | |
4081 | + | |
4082 | +int InterlockedIncrement(int *val) | |
4083 | +{ | |
4084 | +#ifdef KERNEL_2_6_5 | |
4085 | + int i; | |
4086 | + local_irq_disable(); | |
4087 | + i = atomic_read((atomic_t*)val); | |
4088 | + atomic_set((atomic_t*)val, i+1); | |
4089 | + local_irq_enable(); | |
4090 | + return i+1; | |
4091 | +#else | |
4092 | + return atomic_inc_return((atomic_t*)val); | |
4093 | +#endif | |
4094 | +} | |
4095 | + | |
4096 | +int InterlockedDecrement(int *val) | |
4097 | +{ | |
4098 | +#ifdef KERNEL_2_6_5 | |
4099 | + int i; | |
4100 | + local_irq_disable(); | |
4101 | + i = atomic_read((atomic_t*)val); | |
4102 | + atomic_set((atomic_t*)val, i-1); | |
4103 | + local_irq_enable(); | |
4104 | + return i-1; | |
4105 | +#else | |
4106 | + return atomic_dec_return((atomic_t*)val); | |
4107 | +#endif | |
4108 | +} | |
4109 | + | |
4110 | +#ifndef atomic_cmpxchg | |
4111 | +#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new)) | |
4112 | +#endif | |
4113 | +int InterlockedCompareExchange(int *val, int new, int curr) | |
4114 | +{ | |
4115 | + //return ((int)cmpxchg(((atomic_t*)val), curr, new)); | |
4116 | + return atomic_cmpxchg((atomic_t*)val, curr, new); | |
4117 | + | |
4118 | +} | |
4119 | + | |
4120 | +void Sleep(unsigned long usecs) | |
4121 | +{ | |
4122 | + udelay(usecs); | |
4123 | +} | |
4124 | + | |
4125 | +void* VirtualAllocExec(unsigned int size) | |
4126 | +{ | |
4127 | +#ifdef __x86_64__ | |
4128 | + return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC); | |
4129 | +#else | |
4130 | + return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX))); | |
4131 | +#endif | |
4132 | +} | |
4133 | + | |
4134 | +void VirtualFree(void* VirtAddr) | |
4135 | +{ | |
4136 | + return vfree(VirtAddr); | |
4137 | +} | |
4138 | + | |
4139 | +void* PageAlloc(unsigned int count) | |
4140 | +{ | |
4141 | + void *p; | |
4142 | + p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE)); | |
4143 | + if (p) memset(p, 0, count * PAGE_SIZE); | |
4144 | + return p; | |
4145 | + | |
4146 | + //struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO); | |
4147 | + //void *p; | |
4148 | + | |
4149 | + ////BUGBUG: We need to use kmap in case we are in HIMEM region | |
4150 | + //p = page_address(page); | |
4151 | + //if (p) memset(p, 0, PAGE_SIZE); | |
4152 | + //return p; | |
4153 | +} | |
4154 | + | |
4155 | +void PageFree(void* page, unsigned int count) | |
4156 | +{ | |
4157 | + free_pages((unsigned long)page, get_order(count * PAGE_SIZE)); | |
4158 | + /*struct page* p = virt_to_page(page); | |
4159 | + __free_page(p);*/ | |
4160 | +} | |
4161 | + | |
4162 | + | |
4163 | +void* PageMapVirtualAddress(unsigned long Pfn) | |
4164 | +{ | |
4165 | + return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0); | |
4166 | +} | |
4167 | + | |
4168 | +void PageUnmapVirtualAddress(void* VirtAddr) | |
4169 | +{ | |
4170 | + kunmap_atomic(VirtAddr, KM_IRQ0); | |
4171 | +} | |
4172 | + | |
4173 | +void* MemAlloc(unsigned int size) | |
4174 | +{ | |
4175 | + return kmalloc(size, GFP_KERNEL); | |
4176 | +} | |
4177 | + | |
4178 | +void* MemAllocZeroed(unsigned int size) | |
4179 | +{ | |
4180 | + void *p = kmalloc(size, GFP_KERNEL); | |
4181 | + if (p) memset(p, 0, size); | |
4182 | + return p; | |
4183 | +} | |
4184 | + | |
4185 | +void* MemAllocAtomic(unsigned int size) | |
4186 | +{ | |
4187 | + return kmalloc(size, GFP_ATOMIC); | |
4188 | +} | |
4189 | + | |
4190 | +void MemFree(void* buf) | |
4191 | +{ | |
4192 | + kfree(buf); | |
4193 | +} | |
4194 | + | |
4195 | +void *MemMapIO(unsigned long phys, unsigned long size) | |
4196 | +{ | |
4197 | +#if X2V_LINUX | |
4198 | +#ifdef __x86_64__ | |
4199 | + return (void*)(phys + 0xFFFF83000C000000); | |
4200 | +#else // i386 | |
4201 | + return (void*)(phys + 0xfb000000); | |
4202 | +#endif | |
4203 | +#else | |
4204 | + return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size); | |
4205 | +#endif | |
4206 | +} | |
4207 | + | |
4208 | +void MemUnmapIO(void *virt) | |
4209 | +{ | |
4210 | + //iounmap(virt); | |
4211 | +} | |
4212 | + | |
4213 | +void MemoryFence() | |
4214 | +{ | |
4215 | + mb(); | |
4216 | +} | |
4217 | + | |
4218 | +void TimerCallback(unsigned long data) | |
4219 | +{ | |
4220 | + TIMER* t = (TIMER*)data; | |
4221 | + | |
4222 | + t->callback(t->context); | |
4223 | +} | |
4224 | + | |
4225 | +HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context) | |
4226 | +{ | |
4227 | + TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL); | |
4228 | + if (!t) | |
4229 | + { | |
4230 | + return NULL; | |
4231 | + } | |
4232 | + | |
4233 | + t->callback = pfnTimerCB; | |
4234 | + t->context = context; | |
4235 | + | |
4236 | + init_timer(&t->timer); | |
4237 | + t->timer.data = (unsigned long)t; | |
4238 | + t->timer.function = TimerCallback; | |
4239 | + | |
4240 | + return t; | |
4241 | +} | |
4242 | + | |
4243 | +void TimerStart(HANDLE hTimer, UINT32 expirationInUs) | |
4244 | +{ | |
4245 | + TIMER* t = (TIMER* )hTimer; | |
4246 | + | |
4247 | + t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs); | |
4248 | + add_timer(&t->timer); | |
4249 | +} | |
4250 | + | |
4251 | +int TimerStop(HANDLE hTimer) | |
4252 | +{ | |
4253 | + TIMER* t = (TIMER* )hTimer; | |
4254 | + | |
4255 | + return del_timer(&t->timer); | |
4256 | +} | |
4257 | + | |
4258 | +void TimerClose(HANDLE hTimer) | |
4259 | +{ | |
4260 | + TIMER* t = (TIMER* )hTimer; | |
4261 | + | |
4262 | + del_timer(&t->timer); | |
4263 | + kfree(t); | |
4264 | +} | |
4265 | + | |
4266 | +SIZE_T GetTickCount(void) | |
4267 | +{ | |
4268 | + return jiffies; | |
4269 | +} | |
4270 | + | |
4271 | +signed long long GetTimestamp(void) | |
4272 | +{ | |
4273 | + struct timeval t; | |
4274 | + | |
4275 | + do_gettimeofday(&t); | |
4276 | + | |
4277 | + return timeval_to_ns(&t); | |
4278 | +} | |
4279 | + | |
4280 | +HANDLE WaitEventCreate(void) | |
4281 | +{ | |
4282 | + WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL); | |
4283 | + if (!wait) | |
4284 | + { | |
4285 | + return NULL; | |
4286 | + } | |
4287 | + | |
4288 | + wait->condition = 0; | |
4289 | + init_waitqueue_head(&wait->event); | |
4290 | + return wait; | |
4291 | +} | |
4292 | + | |
4293 | +void WaitEventClose(HANDLE hWait) | |
4294 | +{ | |
4295 | + WAITEVENT* waitEvent = (WAITEVENT* )hWait; | |
4296 | + kfree(waitEvent); | |
4297 | +} | |
4298 | + | |
4299 | +void WaitEventSet(HANDLE hWait) | |
4300 | +{ | |
4301 | + WAITEVENT* waitEvent = (WAITEVENT* )hWait; | |
4302 | + waitEvent->condition = 1; | |
4303 | + wake_up_interruptible(&waitEvent->event); | |
4304 | +} | |
4305 | + | |
4306 | +int WaitEventWait(HANDLE hWait) | |
4307 | +{ | |
4308 | + int ret=0; | |
4309 | + WAITEVENT* waitEvent = (WAITEVENT* )hWait; | |
4310 | + | |
4311 | + ret= wait_event_interruptible(waitEvent->event, | |
4312 | + waitEvent->condition); | |
4313 | + waitEvent->condition = 0; | |
4314 | + return ret; | |
4315 | +} | |
4316 | + | |
4317 | +int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs) | |
4318 | +{ | |
4319 | + int ret=0; | |
4320 | + WAITEVENT* waitEvent = (WAITEVENT* )hWait; | |
4321 | + | |
4322 | + ret= wait_event_interruptible_timeout(waitEvent->event, | |
4323 | + waitEvent->condition, | |
4324 | + msecs_to_jiffies(TimeoutInMs)); | |
4325 | + waitEvent->condition = 0; | |
4326 | + return ret; | |
4327 | +} | |
4328 | + | |
4329 | +HANDLE SpinlockCreate(VOID) | |
4330 | +{ | |
4331 | + SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL); | |
4332 | + if (!spin) | |
4333 | + { | |
4334 | + return NULL; | |
4335 | + } | |
4336 | + spin_lock_init(&spin->lock); | |
4337 | + | |
4338 | + return spin; | |
4339 | +} | |
4340 | + | |
4341 | +VOID SpinlockAcquire(HANDLE hSpin) | |
4342 | +{ | |
4343 | + SPINLOCK* spin = (SPINLOCK* )hSpin; | |
4344 | + | |
4345 | + spin_lock_irqsave(&spin->lock, spin->flags); | |
4346 | +} | |
4347 | + | |
4348 | +VOID SpinlockRelease(HANDLE hSpin) | |
4349 | +{ | |
4350 | + SPINLOCK* spin = (SPINLOCK* )hSpin; | |
4351 | + | |
4352 | + spin_unlock_irqrestore(&spin->lock, spin->flags); | |
4353 | +} | |
4354 | + | |
4355 | +VOID SpinlockClose(HANDLE hSpin) | |
4356 | +{ | |
4357 | + SPINLOCK* spin = (SPINLOCK* )hSpin; | |
4358 | + kfree(spin); | |
4359 | +} | |
4360 | + | |
4361 | +void* Physical2LogicalAddr(ULONG_PTR PhysAddr) | |
4362 | +{ | |
4363 | + void* logicalAddr = phys_to_virt(PhysAddr); | |
4364 | + BUG_ON(!virt_addr_valid(logicalAddr)); | |
4365 | + return logicalAddr; | |
4366 | +} | |
4367 | + | |
4368 | +ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr) | |
4369 | +{ | |
4370 | + BUG_ON(!virt_addr_valid(LogicalAddr)); | |
4371 | + return virt_to_phys(LogicalAddr); | |
4372 | +} | |
4373 | + | |
4374 | + | |
4375 | +ULONG_PTR Virtual2Physical(PVOID VirtAddr) | |
4376 | +{ | |
4377 | + ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr); | |
4378 | + | |
4379 | + return pfn << PAGE_SHIFT; | |
4380 | +} | |
4381 | + | |
4382 | +#ifdef KERNEL_2_6_27 | |
4383 | +void WorkItemCallback(struct work_struct *work) | |
4384 | +#else | |
4385 | +void WorkItemCallback(void* work) | |
4386 | +#endif | |
4387 | +{ | |
4388 | + WORKITEM* w = (WORKITEM*)work; | |
4389 | + | |
4390 | + w->callback(w->context); | |
4391 | + | |
4392 | + kfree(w); | |
4393 | +} | |
4394 | + | |
4395 | +HANDLE WorkQueueCreate(char* name) | |
4396 | +{ | |
4397 | + WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL); | |
4398 | + if (!wq) | |
4399 | + { | |
4400 | + return NULL; | |
4401 | + } | |
4402 | + wq->queue = create_workqueue(name); | |
4403 | + | |
4404 | + return wq; | |
4405 | +} | |
4406 | + | |
4407 | +void WorkQueueClose(HANDLE hWorkQueue) | |
4408 | +{ | |
4409 | + WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue; | |
4410 | + | |
4411 | + destroy_workqueue(wq->queue); | |
4412 | + | |
4413 | + return; | |
4414 | +} | |
4415 | + | |
4416 | +int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context) | |
4417 | +{ | |
4418 | + WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue; | |
4419 | + | |
4420 | + WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC); | |
4421 | + if (!w) | |
4422 | + { | |
4423 | + return -1; | |
4424 | + } | |
4425 | + | |
4426 | + w->callback = workItem, | |
4427 | + w->context = context; | |
4428 | +#ifdef KERNEL_2_6_27 | |
4429 | + INIT_WORK(&w->work, WorkItemCallback); | |
4430 | +#else | |
4431 | + INIT_WORK(&w->work, WorkItemCallback, w); | |
4432 | +#endif | |
4433 | + return queue_work(wq->queue, &w->work); | |
4434 | +} | |
4435 | + | |
4436 | +void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context) | |
4437 | +{ | |
4438 | + WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC); | |
4439 | + if (!w) | |
4440 | + { | |
4441 | + return; | |
4442 | + } | |
4443 | + | |
4444 | + w->callback = workItem, | |
4445 | + w->context = context; | |
4446 | +#ifdef KERNEL_2_6_27 | |
4447 | + INIT_WORK(&w->work, WorkItemCallback); | |
4448 | +#else | |
4449 | + INIT_WORK(&w->work, WorkItemCallback, w); | |
4450 | +#endif | |
4451 | + schedule_work(&w->work); | |
4452 | +} | |
4453 | --- /dev/null | |
4454 | +++ b/drivers/staging/hv/RingBuffer.c | |
4455 | @@ -0,0 +1,630 @@ | |
4456 | +/* | |
4457 | + * | |
4458 | + * Copyright (c) 2009, Microsoft Corporation. | |
4459 | + * | |
4460 | + * This program is free software; you can redistribute it and/or modify it | |
4461 | + * under the terms and conditions of the GNU General Public License, | |
4462 | + * version 2, as published by the Free Software Foundation. | |
4463 | + * | |
4464 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
4465 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
4466 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
4467 | + * more details. | |
4468 | + * | |
4469 | + * You should have received a copy of the GNU General Public License along with | |
4470 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
4471 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
4472 | + * | |
4473 | + * Authors: | |
4474 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
4475 | + * Hank Janssen <hjanssen@microsoft.com> | |
4476 | + * | |
4477 | + */ | |
4478 | + | |
4479 | + | |
4480 | +#include "logging.h" | |
4481 | +#include "RingBuffer.h" | |
4482 | + | |
4483 | +// | |
4484 | +// #defines | |
4485 | +// | |
4486 | + | |
4487 | +// Amount of space to write to | |
4488 | +#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w)) | |
4489 | + | |
4490 | + | |
4491 | +/*++ | |
4492 | + | |
4493 | +Name: | |
4494 | + GetRingBufferAvailBytes() | |
4495 | + | |
4496 | +Description: | |
4497 | + Get number of bytes available to read and to write to | |
4498 | + for the specified ring buffer | |
4499 | + | |
4500 | +--*/ | |
4501 | +static inline void | |
4502 | +GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write) | |
4503 | +{ | |
4504 | + UINT32 read_loc,write_loc; | |
4505 | + | |
4506 | + // Capture the read/write indices before they changed | |
4507 | + read_loc = rbi->RingBuffer->ReadIndex; | |
4508 | + write_loc = rbi->RingBuffer->WriteIndex; | |
4509 | + | |
4510 | + *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize); | |
4511 | + *read = rbi->RingDataSize - *write; | |
4512 | +} | |
4513 | + | |
4514 | +/*++ | |
4515 | + | |
4516 | +Name: | |
4517 | + GetNextWriteLocation() | |
4518 | + | |
4519 | +Description: | |
4520 | + Get the next write location for the specified ring buffer | |
4521 | + | |
4522 | +--*/ | |
4523 | +static inline UINT32 | |
4524 | +GetNextWriteLocation(RING_BUFFER_INFO* RingInfo) | |
4525 | +{ | |
4526 | + UINT32 next = RingInfo->RingBuffer->WriteIndex; | |
4527 | + | |
4528 | + ASSERT(next < RingInfo->RingDataSize); | |
4529 | + | |
4530 | + return next; | |
4531 | +} | |
4532 | + | |
4533 | +/*++ | |
4534 | + | |
4535 | +Name: | |
4536 | + SetNextWriteLocation() | |
4537 | + | |
4538 | +Description: | |
4539 | + Set the next write location for the specified ring buffer | |
4540 | + | |
4541 | +--*/ | |
4542 | +static inline void | |
4543 | +SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation) | |
4544 | +{ | |
4545 | + RingInfo->RingBuffer->WriteIndex = NextWriteLocation; | |
4546 | +} | |
4547 | + | |
4548 | +/*++ | |
4549 | + | |
4550 | +Name: | |
4551 | + GetNextReadLocation() | |
4552 | + | |
4553 | +Description: | |
4554 | + Get the next read location for the specified ring buffer | |
4555 | + | |
4556 | +--*/ | |
4557 | +static inline UINT32 | |
4558 | +GetNextReadLocation(RING_BUFFER_INFO* RingInfo) | |
4559 | +{ | |
4560 | + UINT32 next = RingInfo->RingBuffer->ReadIndex; | |
4561 | + | |
4562 | + ASSERT(next < RingInfo->RingDataSize); | |
4563 | + | |
4564 | + return next; | |
4565 | +} | |
4566 | + | |
4567 | +/*++ | |
4568 | + | |
4569 | +Name: | |
4570 | + GetNextReadLocationWithOffset() | |
4571 | + | |
4572 | +Description: | |
4573 | + Get the next read location + offset for the specified ring buffer. | |
4574 | + This allows the caller to skip | |
4575 | + | |
4576 | +--*/ | |
4577 | +static inline UINT32 | |
4578 | +GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset) | |
4579 | +{ | |
4580 | + UINT32 next = RingInfo->RingBuffer->ReadIndex; | |
4581 | + | |
4582 | + ASSERT(next < RingInfo->RingDataSize); | |
4583 | + next += Offset; | |
4584 | + next %= RingInfo->RingDataSize; | |
4585 | + | |
4586 | + return next; | |
4587 | +} | |
4588 | + | |
4589 | +/*++ | |
4590 | + | |
4591 | +Name: | |
4592 | + SetNextReadLocation() | |
4593 | + | |
4594 | +Description: | |
4595 | + Set the next read location for the specified ring buffer | |
4596 | + | |
4597 | +--*/ | |
4598 | +static inline void | |
4599 | +SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation) | |
4600 | +{ | |
4601 | + RingInfo->RingBuffer->ReadIndex = NextReadLocation; | |
4602 | +} | |
4603 | + | |
4604 | + | |
4605 | +/*++ | |
4606 | + | |
4607 | +Name: | |
4608 | + GetRingBuffer() | |
4609 | + | |
4610 | +Description: | |
4611 | + Get the start of the ring buffer | |
4612 | + | |
4613 | +--*/ | |
4614 | +static inline PVOID | |
4615 | +GetRingBuffer(RING_BUFFER_INFO* RingInfo) | |
4616 | +{ | |
4617 | + return (PVOID)RingInfo->RingBuffer->Buffer; | |
4618 | +} | |
4619 | + | |
4620 | + | |
4621 | +/*++ | |
4622 | + | |
4623 | +Name: | |
4624 | + GetRingBufferSize() | |
4625 | + | |
4626 | +Description: | |
4627 | + Get the size of the ring buffer | |
4628 | + | |
4629 | +--*/ | |
4630 | +static inline UINT32 | |
4631 | +GetRingBufferSize(RING_BUFFER_INFO* RingInfo) | |
4632 | +{ | |
4633 | + return RingInfo->RingDataSize; | |
4634 | +} | |
4635 | + | |
4636 | +/*++ | |
4637 | + | |
4638 | +Name: | |
4639 | + GetRingBufferIndices() | |
4640 | + | |
4641 | +Description: | |
4642 | + Get the read and write indices as UINT64 of the specified ring buffer | |
4643 | + | |
4644 | +--*/ | |
4645 | +static inline UINT64 | |
4646 | +GetRingBufferIndices(RING_BUFFER_INFO* RingInfo) | |
4647 | +{ | |
4648 | + return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex; | |
4649 | +} | |
4650 | + | |
4651 | + | |
4652 | +/*++ | |
4653 | + | |
4654 | +Name: | |
4655 | + DumpRingInfo() | |
4656 | + | |
4657 | +Description: | |
4658 | + Dump out to console the ring buffer info | |
4659 | + | |
4660 | +--*/ | |
4661 | +void | |
4662 | +DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix) | |
4663 | +{ | |
4664 | + UINT32 bytesAvailToWrite; | |
4665 | + UINT32 bytesAvailToRead; | |
4666 | + | |
4667 | + GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
4668 | + | |
4669 | + DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>", | |
4670 | + Prefix, | |
4671 | + RingInfo, | |
4672 | + RingInfo->RingBuffer->Buffer, | |
4673 | + bytesAvailToWrite, | |
4674 | + bytesAvailToRead, | |
4675 | + RingInfo->RingBuffer->ReadIndex, | |
4676 | + RingInfo->RingBuffer->WriteIndex); | |
4677 | +} | |
4678 | + | |
4679 | +// | |
4680 | +// Internal routines | |
4681 | +// | |
4682 | +static UINT32 | |
4683 | +CopyToRingBuffer( | |
4684 | + RING_BUFFER_INFO *RingInfo, | |
4685 | + UINT32 StartWriteOffset, | |
4686 | + PVOID Src, | |
4687 | + UINT32 SrcLen); | |
4688 | + | |
4689 | +static UINT32 | |
4690 | +CopyFromRingBuffer( | |
4691 | + RING_BUFFER_INFO *RingInfo, | |
4692 | + PVOID Dest, | |
4693 | + UINT32 DestLen, | |
4694 | + UINT32 StartReadOffset); | |
4695 | + | |
4696 | + | |
4697 | + | |
4698 | +/*++ | |
4699 | + | |
4700 | +Name: | |
4701 | + RingBufferGetDebugInfo() | |
4702 | + | |
4703 | +Description: | |
4704 | + Get various debug metrics for the specified ring buffer | |
4705 | + | |
4706 | +--*/ | |
4707 | +void | |
4708 | +RingBufferGetDebugInfo( | |
4709 | + RING_BUFFER_INFO *RingInfo, | |
4710 | + RING_BUFFER_DEBUG_INFO *DebugInfo | |
4711 | + ) | |
4712 | +{ | |
4713 | + UINT32 bytesAvailToWrite; | |
4714 | + UINT32 bytesAvailToRead; | |
4715 | + | |
4716 | + if (RingInfo->RingBuffer) | |
4717 | + { | |
4718 | + GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
4719 | + | |
4720 | + DebugInfo->BytesAvailToRead = bytesAvailToRead; | |
4721 | + DebugInfo->BytesAvailToWrite = bytesAvailToWrite; | |
4722 | + DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; | |
4723 | + DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; | |
4724 | + | |
4725 | + DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; | |
4726 | + } | |
4727 | +} | |
4728 | + | |
4729 | + | |
4730 | +/*++ | |
4731 | + | |
4732 | +Name: | |
4733 | + GetRingBufferInterruptMask() | |
4734 | + | |
4735 | +Description: | |
4736 | + Get the interrupt mask for the specified ring buffer | |
4737 | + | |
4738 | +--*/ | |
4739 | +UINT32 | |
4740 | +GetRingBufferInterruptMask( | |
4741 | + RING_BUFFER_INFO *rbi | |
4742 | + ) | |
4743 | +{ | |
4744 | + return rbi->RingBuffer->InterruptMask; | |
4745 | +} | |
4746 | + | |
4747 | +/*++ | |
4748 | + | |
4749 | +Name: | |
4750 | + RingBufferInit() | |
4751 | + | |
4752 | +Description: | |
4753 | + Initialize the ring buffer | |
4754 | + | |
4755 | +--*/ | |
4756 | +int | |
4757 | +RingBufferInit( | |
4758 | + RING_BUFFER_INFO *RingInfo, | |
4759 | + VOID *Buffer, | |
4760 | + UINT32 BufferLen | |
4761 | + ) | |
4762 | +{ | |
4763 | + ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE); | |
4764 | + | |
4765 | + memset(RingInfo, 0, sizeof(RING_BUFFER_INFO)); | |
4766 | + | |
4767 | + RingInfo->RingBuffer = (RING_BUFFER*)Buffer; | |
4768 | + RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0; | |
4769 | + | |
4770 | + RingInfo->RingSize = BufferLen; | |
4771 | + RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER); | |
4772 | + | |
4773 | + RingInfo->RingLock = SpinlockCreate(); | |
4774 | + | |
4775 | + return 0; | |
4776 | +} | |
4777 | + | |
4778 | +/*++ | |
4779 | + | |
4780 | +Name: | |
4781 | + RingBufferCleanup() | |
4782 | + | |
4783 | +Description: | |
4784 | + Cleanup the ring buffer | |
4785 | + | |
4786 | +--*/ | |
4787 | +void | |
4788 | +RingBufferCleanup( | |
4789 | + RING_BUFFER_INFO* RingInfo | |
4790 | + ) | |
4791 | +{ | |
4792 | + SpinlockClose(RingInfo->RingLock); | |
4793 | +} | |
4794 | + | |
4795 | +/*++ | |
4796 | + | |
4797 | +Name: | |
4798 | + RingBufferWrite() | |
4799 | + | |
4800 | +Description: | |
4801 | + Write to the ring buffer | |
4802 | + | |
4803 | +--*/ | |
4804 | +int | |
4805 | +RingBufferWrite( | |
4806 | + RING_BUFFER_INFO* OutRingInfo, | |
4807 | + SG_BUFFER_LIST SgBuffers[], | |
4808 | + UINT32 SgBufferCount | |
4809 | + ) | |
4810 | +{ | |
4811 | + int i=0; | |
4812 | + UINT32 byteAvailToWrite; | |
4813 | + UINT32 byteAvailToRead; | |
4814 | + UINT32 totalBytesToWrite=0; | |
4815 | + | |
4816 | + volatile UINT32 nextWriteLocation; | |
4817 | + UINT64 prevIndices=0; | |
4818 | + | |
4819 | + DPRINT_ENTER(VMBUS); | |
4820 | + | |
4821 | + for (i=0; i < SgBufferCount; i++) | |
4822 | + { | |
4823 | + totalBytesToWrite += SgBuffers[i].Length; | |
4824 | + } | |
4825 | + | |
4826 | + totalBytesToWrite += sizeof(UINT64); | |
4827 | + | |
4828 | + SpinlockAcquire(OutRingInfo->RingLock); | |
4829 | + | |
4830 | + GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); | |
4831 | + | |
4832 | + DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); | |
4833 | + | |
4834 | + //DumpRingInfo(OutRingInfo, "BEFORE "); | |
4835 | + | |
4836 | + // If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer | |
4837 | + // is empty since the read index == write index | |
4838 | + if (byteAvailToWrite <= totalBytesToWrite) | |
4839 | + { | |
4840 | + DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); | |
4841 | + | |
4842 | + SpinlockRelease(OutRingInfo->RingLock); | |
4843 | + | |
4844 | + DPRINT_EXIT(VMBUS); | |
4845 | + | |
4846 | + return -1; | |
4847 | + } | |
4848 | + | |
4849 | + // Write to the ring buffer | |
4850 | + nextWriteLocation = GetNextWriteLocation(OutRingInfo); | |
4851 | + | |
4852 | + for (i=0; i < SgBufferCount; i++) | |
4853 | + { | |
4854 | + nextWriteLocation = CopyToRingBuffer(OutRingInfo, | |
4855 | + nextWriteLocation, | |
4856 | + SgBuffers[i].Data, | |
4857 | + SgBuffers[i].Length); | |
4858 | + } | |
4859 | + | |
4860 | + // Set previous packet start | |
4861 | + prevIndices = GetRingBufferIndices(OutRingInfo); | |
4862 | + | |
4863 | + nextWriteLocation = CopyToRingBuffer(OutRingInfo, | |
4864 | + nextWriteLocation, | |
4865 | + &prevIndices, | |
4866 | + sizeof(UINT64)); | |
4867 | + | |
4868 | + // Make sure we flush all writes before updating the writeIndex | |
4869 | + MemoryFence(); | |
4870 | + | |
4871 | + // Now, update the write location | |
4872 | + SetNextWriteLocation(OutRingInfo, nextWriteLocation); | |
4873 | + | |
4874 | + //DumpRingInfo(OutRingInfo, "AFTER "); | |
4875 | + | |
4876 | + SpinlockRelease(OutRingInfo->RingLock); | |
4877 | + | |
4878 | + DPRINT_EXIT(VMBUS); | |
4879 | + | |
4880 | + return 0; | |
4881 | +} | |
4882 | + | |
4883 | + | |
4884 | +/*++ | |
4885 | + | |
4886 | +Name: | |
4887 | + RingBufferPeek() | |
4888 | + | |
4889 | +Description: | |
4890 | + Read without advancing the read index | |
4891 | + | |
4892 | +--*/ | |
4893 | +int | |
4894 | +RingBufferPeek( | |
4895 | + RING_BUFFER_INFO* InRingInfo, | |
4896 | + void* Buffer, | |
4897 | + UINT32 BufferLen | |
4898 | + ) | |
4899 | +{ | |
4900 | + UINT32 bytesAvailToWrite; | |
4901 | + UINT32 bytesAvailToRead; | |
4902 | + UINT32 nextReadLocation=0; | |
4903 | + | |
4904 | + SpinlockAcquire(InRingInfo->RingLock); | |
4905 | + | |
4906 | + GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
4907 | + | |
4908 | + // Make sure there is something to read | |
4909 | + if (bytesAvailToRead < BufferLen ) | |
4910 | + { | |
4911 | + //DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); | |
4912 | + | |
4913 | + SpinlockRelease(InRingInfo->RingLock); | |
4914 | + | |
4915 | + return -1; | |
4916 | + } | |
4917 | + | |
4918 | + // Convert to byte offset | |
4919 | + nextReadLocation = GetNextReadLocation(InRingInfo); | |
4920 | + | |
4921 | + nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
4922 | + Buffer, | |
4923 | + BufferLen, | |
4924 | + nextReadLocation); | |
4925 | + | |
4926 | + SpinlockRelease(InRingInfo->RingLock); | |
4927 | + | |
4928 | + return 0; | |
4929 | +} | |
4930 | + | |
4931 | + | |
4932 | +/*++ | |
4933 | + | |
4934 | +Name: | |
4935 | + RingBufferRead() | |
4936 | + | |
4937 | +Description: | |
4938 | + Read and advance the read index | |
4939 | + | |
4940 | +--*/ | |
4941 | +int | |
4942 | +RingBufferRead( | |
4943 | + RING_BUFFER_INFO* InRingInfo, | |
4944 | + PVOID Buffer, | |
4945 | + UINT32 BufferLen, | |
4946 | + UINT32 Offset | |
4947 | + ) | |
4948 | +{ | |
4949 | + UINT32 bytesAvailToWrite; | |
4950 | + UINT32 bytesAvailToRead; | |
4951 | + UINT32 nextReadLocation=0; | |
4952 | + UINT64 prevIndices=0; | |
4953 | + | |
4954 | + ASSERT(BufferLen > 0); | |
4955 | + | |
4956 | + SpinlockAcquire(InRingInfo->RingLock); | |
4957 | + | |
4958 | + GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
4959 | + | |
4960 | + DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); | |
4961 | + | |
4962 | + //DumpRingInfo(InRingInfo, "BEFORE "); | |
4963 | + | |
4964 | + // Make sure there is something to read | |
4965 | + if (bytesAvailToRead < BufferLen ) | |
4966 | + { | |
4967 | + DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); | |
4968 | + | |
4969 | + SpinlockRelease(InRingInfo->RingLock); | |
4970 | + | |
4971 | + return -1; | |
4972 | + } | |
4973 | + | |
4974 | + nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); | |
4975 | + | |
4976 | + nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
4977 | + Buffer, | |
4978 | + BufferLen, | |
4979 | + nextReadLocation); | |
4980 | + | |
4981 | + nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
4982 | + &prevIndices, | |
4983 | + sizeof(UINT64), | |
4984 | + nextReadLocation); | |
4985 | + | |
4986 | + // Make sure all reads are done before we update the read index since | |
4987 | + // the writer may start writing to the read area once the read index is updated | |
4988 | + MemoryFence(); | |
4989 | + | |
4990 | + // Update the read index | |
4991 | + SetNextReadLocation(InRingInfo, nextReadLocation); | |
4992 | + | |
4993 | + //DumpRingInfo(InRingInfo, "AFTER "); | |
4994 | + | |
4995 | + SpinlockRelease(InRingInfo->RingLock); | |
4996 | + | |
4997 | + return 0; | |
4998 | +} | |
4999 | + | |
5000 | + | |
5001 | +/*++ | |
5002 | + | |
5003 | +Name: | |
5004 | + CopyToRingBuffer() | |
5005 | + | |
5006 | +Description: | |
5007 | + Helper routine to copy from source to ring buffer. | |
5008 | + Assume there is enough room. Handles wrap-around in dest case only!! | |
5009 | + | |
5010 | +--*/ | |
5011 | +UINT32 | |
5012 | +CopyToRingBuffer( | |
5013 | + RING_BUFFER_INFO *RingInfo, | |
5014 | + UINT32 StartWriteOffset, | |
5015 | + PVOID Src, | |
5016 | + UINT32 SrcLen) | |
5017 | +{ | |
5018 | + PVOID ringBuffer=GetRingBuffer(RingInfo); | |
5019 | + UINT32 ringBufferSize=GetRingBufferSize(RingInfo); | |
5020 | + UINT32 fragLen; | |
5021 | + | |
5022 | + if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected! | |
5023 | + { | |
5024 | + DPRINT_DBG(VMBUS, "wrap-around detected!"); | |
5025 | + | |
5026 | + fragLen = ringBufferSize - StartWriteOffset; | |
5027 | + memcpy(ringBuffer + StartWriteOffset, Src, fragLen); | |
5028 | + memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen); | |
5029 | + } | |
5030 | + else | |
5031 | + { | |
5032 | + memcpy(ringBuffer + StartWriteOffset, Src, SrcLen); | |
5033 | + } | |
5034 | + | |
5035 | + StartWriteOffset += SrcLen; | |
5036 | + StartWriteOffset %= ringBufferSize; | |
5037 | + | |
5038 | + return StartWriteOffset; | |
5039 | +} | |
5040 | + | |
5041 | + | |
5042 | +/*++ | |
5043 | + | |
5044 | +Name: | |
5045 | + CopyFromRingBuffer() | |
5046 | + | |
5047 | +Description: | |
5048 | + Helper routine to copy to source from ring buffer. | |
5049 | + Assume there is enough room. Handles wrap-around in src case only!! | |
5050 | + | |
5051 | +--*/ | |
5052 | +UINT32 | |
5053 | +CopyFromRingBuffer( | |
5054 | + RING_BUFFER_INFO *RingInfo, | |
5055 | + PVOID Dest, | |
5056 | + UINT32 DestLen, | |
5057 | + UINT32 StartReadOffset) | |
5058 | +{ | |
5059 | + PVOID ringBuffer=GetRingBuffer(RingInfo); | |
5060 | + UINT32 ringBufferSize=GetRingBufferSize(RingInfo); | |
5061 | + | |
5062 | + UINT32 fragLen; | |
5063 | + | |
5064 | + if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src | |
5065 | + { | |
5066 | + DPRINT_DBG(VMBUS, "src wrap-around detected!"); | |
5067 | + | |
5068 | + fragLen = ringBufferSize - StartReadOffset; | |
5069 | + | |
5070 | + memcpy(Dest, ringBuffer + StartReadOffset, fragLen); | |
5071 | + memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen); | |
5072 | + } | |
5073 | + else | |
5074 | + { | |
5075 | + memcpy(Dest, ringBuffer + StartReadOffset, DestLen); | |
5076 | + } | |
5077 | + | |
5078 | + StartReadOffset += DestLen; | |
5079 | + StartReadOffset %= ringBufferSize; | |
5080 | + | |
5081 | + return StartReadOffset; | |
5082 | +} | |
5083 | + | |
5084 | + | |
5085 | +// eof | |
5086 | --- /dev/null | |
5087 | +++ b/drivers/staging/hv/RingBuffer.h | |
5088 | @@ -0,0 +1,123 @@ | |
5089 | +/* | |
5090 | + * | |
5091 | + * Copyright (c) 2009, Microsoft Corporation. | |
5092 | + * | |
5093 | + * This program is free software; you can redistribute it and/or modify it | |
5094 | + * under the terms and conditions of the GNU General Public License, | |
5095 | + * version 2, as published by the Free Software Foundation. | |
5096 | + * | |
5097 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
5098 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
5099 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
5100 | + * more details. | |
5101 | + * | |
5102 | + * You should have received a copy of the GNU General Public License along with | |
5103 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
5104 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
5105 | + * | |
5106 | + * Authors: | |
5107 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
5108 | + * Hank Janssen <hjanssen@microsoft.com> | |
5109 | + * | |
5110 | + */ | |
5111 | + | |
5112 | + | |
5113 | +#ifndef _RING_BUFFER_H_ | |
5114 | +#define _RING_BUFFER_H_ | |
5115 | + | |
5116 | +#include "osd.h" | |
5117 | + | |
5118 | +typedef struct _SG_BUFFER_LIST { | |
5119 | + PVOID Data; | |
5120 | + UINT32 Length; | |
5121 | +} SG_BUFFER_LIST; | |
5122 | + | |
5123 | +typedef struct _RING_BUFFER { | |
5124 | + volatile UINT32 WriteIndex; // Offset in bytes from the start of ring data below | |
5125 | + volatile UINT32 ReadIndex; // Offset in bytes from the start of ring data below | |
5126 | + | |
5127 | + volatile UINT32 InterruptMask; | |
5128 | + UINT8 Reserved[4084]; // Pad it to PAGE_SIZE so that data starts on page boundary | |
5129 | + // NOTE: The InterruptMask field is used only for channels but since our vmbus connection | |
5130 | + // also uses this data structure and its data starts here, we commented out this field. | |
5131 | + // volatile UINT32 InterruptMask; | |
5132 | + // Ring data starts here + RingDataStartOffset !!! DO NOT place any fields below this !!! | |
5133 | + UINT8 Buffer[0]; | |
5134 | +} STRUCT_PACKED RING_BUFFER; | |
5135 | + | |
5136 | +typedef struct _RING_BUFFER_INFO { | |
5137 | + RING_BUFFER* RingBuffer; | |
5138 | + UINT32 RingSize; // Include the shared header | |
5139 | + HANDLE RingLock; | |
5140 | + | |
5141 | + UINT32 RingDataSize; // < ringSize | |
5142 | + UINT32 RingDataStartOffset; | |
5143 | + | |
5144 | +} RING_BUFFER_INFO; | |
5145 | + | |
5146 | + | |
5147 | +typedef struct _RING_BUFFER_DEBUG_INFO { | |
5148 | + UINT32 CurrentInterruptMask; | |
5149 | + UINT32 CurrentReadIndex; | |
5150 | + UINT32 CurrentWriteIndex; | |
5151 | + UINT32 BytesAvailToRead; | |
5152 | + UINT32 BytesAvailToWrite; | |
5153 | +}RING_BUFFER_DEBUG_INFO; | |
5154 | + | |
5155 | + | |
5156 | +// | |
5157 | +// Interface | |
5158 | +// | |
5159 | + | |
5160 | +INTERNAL int | |
5161 | +RingBufferInit( | |
5162 | + RING_BUFFER_INFO *RingInfo, | |
5163 | + PVOID Buffer, | |
5164 | + UINT32 BufferLen | |
5165 | + ); | |
5166 | + | |
5167 | +INTERNAL void | |
5168 | +RingBufferCleanup( | |
5169 | + RING_BUFFER_INFO *RingInfo | |
5170 | + ); | |
5171 | + | |
5172 | +INTERNAL int | |
5173 | +RingBufferWrite( | |
5174 | + RING_BUFFER_INFO *RingInfo, | |
5175 | + SG_BUFFER_LIST SgBuffers[], | |
5176 | + UINT32 SgBufferCount | |
5177 | + ); | |
5178 | + | |
5179 | +INTERNAL int | |
5180 | +RingBufferPeek( | |
5181 | + RING_BUFFER_INFO *RingInfo, | |
5182 | + PVOID Buffer, | |
5183 | + UINT32 BufferLen | |
5184 | + ); | |
5185 | + | |
5186 | +INTERNAL int | |
5187 | +RingBufferRead( | |
5188 | + RING_BUFFER_INFO *RingInfo, | |
5189 | + PVOID Buffer, | |
5190 | + UINT32 BufferLen, | |
5191 | + UINT32 Offset | |
5192 | + ); | |
5193 | + | |
5194 | +INTERNAL UINT32 | |
5195 | +GetRingBufferInterruptMask( | |
5196 | + RING_BUFFER_INFO *RingInfo | |
5197 | + ); | |
5198 | + | |
5199 | +INTERNAL void | |
5200 | +DumpRingInfo( | |
5201 | + RING_BUFFER_INFO* RingInfo, | |
5202 | + char *Prefix | |
5203 | + ); | |
5204 | + | |
5205 | +INTERNAL void | |
5206 | +RingBufferGetDebugInfo( | |
5207 | + RING_BUFFER_INFO *RingInfo, | |
5208 | + RING_BUFFER_DEBUG_INFO *DebugInfo | |
5209 | + ); | |
5210 | + | |
5211 | +#endif // _RING_BUFFER_H_ | |
5212 | --- /dev/null | |
5213 | +++ b/drivers/staging/hv/Sources.c | |
5214 | @@ -0,0 +1,31 @@ | |
5215 | +/* | |
5216 | + * | |
5217 | + * Copyright (c) 2009, Microsoft Corporation. | |
5218 | + * | |
5219 | + * This program is free software; you can redistribute it and/or modify it | |
5220 | + * under the terms and conditions of the GNU General Public License, | |
5221 | + * version 2, as published by the Free Software Foundation. | |
5222 | + * | |
5223 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
5224 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
5225 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
5226 | + * more details. | |
5227 | + * | |
5228 | + * You should have received a copy of the GNU General Public License along with | |
5229 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
5230 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
5231 | + * | |
5232 | + * Authors: | |
5233 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
5234 | + * Hank Janssen <hjanssen@microsoft.com> | |
5235 | + * | |
5236 | + */ | |
5237 | + | |
5238 | + | |
5239 | +#include "Vmbus.c" | |
5240 | +#include "Hv.c" | |
5241 | +#include "Connection.c" | |
5242 | +#include "Channel.c" | |
5243 | +#include "ChannelMgmt.c" | |
5244 | +#include "ChannelInterface.c" | |
5245 | +#include "RingBuffer.c" | |
5246 | --- /dev/null | |
5247 | +++ b/drivers/staging/hv/VersionInfo.h | |
5248 | @@ -0,0 +1,29 @@ | |
5249 | +/* | |
5250 | + * | |
5251 | + * Copyright (c) 2009, Microsoft Corporation. | |
5252 | + * | |
5253 | + * This program is free software; you can redistribute it and/or modify it | |
5254 | + * under the terms and conditions of the GNU General Public License, | |
5255 | + * version 2, as published by the Free Software Foundation. | |
5256 | + * | |
5257 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
5258 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
5259 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
5260 | + * more details. | |
5261 | + * | |
5262 | + * You should have received a copy of the GNU General Public License along with | |
5263 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
5264 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
5265 | + * | |
5266 | + * Authors: | |
5267 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
5268 | + * Hank Janssen <hjanssen@microsoft.com> | |
5269 | + * | |
5270 | + */ | |
5271 | + | |
5272 | + | |
5273 | +#pragma once | |
5274 | + | |
5275 | +const char VersionDate[]=__DATE__; | |
5276 | +const char VersionTime[]=__TIME__; | |
5277 | +const char VersionDesc[]= "Version 2.0"; | |
5278 | --- /dev/null | |
5279 | +++ b/drivers/staging/hv/Vmbus.c | |
5280 | @@ -0,0 +1,508 @@ | |
5281 | +/* | |
5282 | + * | |
5283 | + * Copyright (c) 2009, Microsoft Corporation. | |
5284 | + * | |
5285 | + * This program is free software; you can redistribute it and/or modify it | |
5286 | + * under the terms and conditions of the GNU General Public License, | |
5287 | + * version 2, as published by the Free Software Foundation. | |
5288 | + * | |
5289 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
5290 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
5291 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
5292 | + * more details. | |
5293 | + * | |
5294 | + * You should have received a copy of the GNU General Public License along with | |
5295 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
5296 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
5297 | + * | |
5298 | + * Authors: | |
5299 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
5300 | + * Hank Janssen <hjanssen@microsoft.com> | |
5301 | + * | |
5302 | + */ | |
5303 | + | |
5304 | + | |
5305 | +#include "logging.h" | |
5306 | +#include "VersionInfo.h" | |
5307 | +#include "VmbusPrivate.h" | |
5308 | + | |
5309 | +// | |
5310 | +// Globals | |
5311 | +// | |
5312 | +static const char* gDriverName="vmbus"; | |
5313 | + | |
5314 | +// Windows vmbus does not defined this. We defined this to be consistent with other devices | |
5315 | +//{c5295816-f63a-4d5f-8d1a-4daf999ca185} | |
5316 | +static const GUID gVmbusDeviceType={ | |
5317 | + .Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85} | |
5318 | +}; | |
5319 | + | |
5320 | +//{ac3760fc-9adf-40aa-9427-a70ed6de95c5} | |
5321 | +static const GUID gVmbusDeviceId={ | |
5322 | + .Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5} | |
5323 | +}; | |
5324 | + | |
5325 | +static DRIVER_OBJECT* gDriver; // vmbus driver object | |
5326 | +static DEVICE_OBJECT* gDevice; // vmbus root device | |
5327 | + | |
5328 | + | |
5329 | +// | |
5330 | +// Internal routines | |
5331 | +// | |
5332 | + | |
5333 | +static void | |
5334 | +VmbusGetChannelInterface( | |
5335 | + VMBUS_CHANNEL_INTERFACE *Interface | |
5336 | + ); | |
5337 | + | |
5338 | +static void | |
5339 | +VmbusGetChannelInfo( | |
5340 | + DEVICE_OBJECT *DeviceObject, | |
5341 | + DEVICE_INFO *DeviceInfo | |
5342 | + ); | |
5343 | + | |
5344 | +static void | |
5345 | +VmbusGetChannelOffers( | |
5346 | + void | |
5347 | + ); | |
5348 | + | |
5349 | +static int | |
5350 | +VmbusOnDeviceAdd( | |
5351 | + DEVICE_OBJECT *Device, | |
5352 | + void *AdditionalInfo | |
5353 | + ); | |
5354 | + | |
5355 | +static int | |
5356 | +VmbusOnDeviceRemove( | |
5357 | + DEVICE_OBJECT* dev | |
5358 | + ); | |
5359 | + | |
5360 | +static void | |
5361 | +VmbusOnCleanup( | |
5362 | + DRIVER_OBJECT* drv | |
5363 | + ); | |
5364 | + | |
5365 | +static int | |
5366 | +VmbusOnISR( | |
5367 | + DRIVER_OBJECT* drv | |
5368 | + ); | |
5369 | + | |
5370 | +static void | |
5371 | +VmbusOnMsgDPC( | |
5372 | + DRIVER_OBJECT* drv | |
5373 | + ); | |
5374 | + | |
5375 | +static void | |
5376 | +VmbusOnEventDPC( | |
5377 | + DRIVER_OBJECT* drv | |
5378 | + ); | |
5379 | + | |
5380 | +/*++; | |
5381 | + | |
5382 | +Name: | |
5383 | + VmbusInitialize() | |
5384 | + | |
5385 | +Description: | |
5386 | + Main entry point | |
5387 | + | |
5388 | +--*/ | |
5389 | +int | |
5390 | +VmbusInitialize( | |
5391 | + DRIVER_OBJECT* drv | |
5392 | + ) | |
5393 | +{ | |
5394 | + VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; | |
5395 | + int ret=0; | |
5396 | + | |
5397 | + DPRINT_ENTER(VMBUS); | |
5398 | + | |
5399 | + DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime); | |
5400 | + DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc); | |
5401 | + | |
5402 | + DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER); | |
5403 | + DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT); | |
5404 | + | |
5405 | + DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%d, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%d", | |
5406 | + sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)); | |
5407 | + | |
5408 | + drv->name = gDriverName; | |
5409 | + memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID)); | |
5410 | + | |
5411 | + // Setup dispatch table | |
5412 | + driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; | |
5413 | + driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; | |
5414 | + driver->Base.OnCleanup = VmbusOnCleanup; | |
5415 | + driver->OnIsr = VmbusOnISR; | |
5416 | + driver->OnMsgDpc = VmbusOnMsgDPC; | |
5417 | + driver->OnEventDpc = VmbusOnEventDPC; | |
5418 | + driver->GetChannelOffers = VmbusGetChannelOffers; | |
5419 | + driver->GetChannelInterface = VmbusGetChannelInterface; | |
5420 | + driver->GetChannelInfo = VmbusGetChannelInfo; | |
5421 | + | |
5422 | + // Hypervisor initialization...setup hypercall page..etc | |
5423 | + ret = HvInit(); | |
5424 | + if (ret != 0) | |
5425 | + { | |
5426 | + DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); | |
5427 | + } | |
5428 | + | |
5429 | + gDriver = drv; | |
5430 | + | |
5431 | + DPRINT_EXIT(VMBUS); | |
5432 | + | |
5433 | + return ret; | |
5434 | +} | |
5435 | + | |
5436 | + | |
5437 | +/*++; | |
5438 | + | |
5439 | +Name: | |
5440 | + VmbusGetChannelOffers() | |
5441 | + | |
5442 | +Description: | |
5443 | + Retrieve the channel offers from the parent partition | |
5444 | + | |
5445 | +--*/ | |
5446 | + | |
5447 | +static void | |
5448 | +VmbusGetChannelOffers(void) | |
5449 | +{ | |
5450 | + DPRINT_ENTER(VMBUS); | |
5451 | + VmbusChannelRequestOffers(); | |
5452 | + DPRINT_EXIT(VMBUS); | |
5453 | +} | |
5454 | + | |
5455 | + | |
5456 | +/*++; | |
5457 | + | |
5458 | +Name: | |
5459 | + VmbusGetChannelInterface() | |
5460 | + | |
5461 | +Description: | |
5462 | + Get the channel interface | |
5463 | + | |
5464 | +--*/ | |
5465 | +static void | |
5466 | +VmbusGetChannelInterface( | |
5467 | + VMBUS_CHANNEL_INTERFACE *Interface | |
5468 | + ) | |
5469 | +{ | |
5470 | + GetChannelInterface(Interface); | |
5471 | +} | |
5472 | + | |
5473 | + | |
5474 | +/*++; | |
5475 | + | |
5476 | +Name: | |
5477 | + VmbusGetChannelInterface() | |
5478 | + | |
5479 | +Description: | |
5480 | + Get the device info for the specified device object | |
5481 | + | |
5482 | +--*/ | |
5483 | +static void | |
5484 | +VmbusGetChannelInfo( | |
5485 | + DEVICE_OBJECT *DeviceObject, | |
5486 | + DEVICE_INFO *DeviceInfo | |
5487 | + ) | |
5488 | +{ | |
5489 | + GetChannelInfo(DeviceObject, DeviceInfo); | |
5490 | +} | |
5491 | + | |
5492 | + | |
5493 | + | |
5494 | +/*++ | |
5495 | + | |
5496 | +Name: | |
5497 | + VmbusCreateChildDevice() | |
5498 | + | |
5499 | +Description: | |
5500 | + Creates the child device on the bus that represents the channel offer | |
5501 | + | |
5502 | +--*/ | |
5503 | + | |
5504 | +DEVICE_OBJECT* | |
5505 | +VmbusChildDeviceCreate( | |
5506 | + GUID DeviceType, | |
5507 | + GUID DeviceInstance, | |
5508 | + void *Context) | |
5509 | +{ | |
5510 | + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | |
5511 | + | |
5512 | + return vmbusDriver->OnChildDeviceCreate( | |
5513 | + DeviceType, | |
5514 | + DeviceInstance, | |
5515 | + Context); | |
5516 | +} | |
5517 | + | |
5518 | + | |
5519 | +/*++ | |
5520 | + | |
5521 | +Name: | |
5522 | + VmbusChildDeviceAdd() | |
5523 | + | |
5524 | +Description: | |
5525 | + Registers the child device with the vmbus | |
5526 | + | |
5527 | +--*/ | |
5528 | +int | |
5529 | +VmbusChildDeviceAdd( | |
5530 | + DEVICE_OBJECT* ChildDevice) | |
5531 | +{ | |
5532 | + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | |
5533 | + | |
5534 | + return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice); | |
5535 | +} | |
5536 | + | |
5537 | + | |
5538 | +/*++ | |
5539 | + | |
5540 | +Name: | |
5541 | + VmbusChildDeviceRemove() | |
5542 | + | |
5543 | +Description: | |
5544 | + Unregisters the child device from the vmbus | |
5545 | + | |
5546 | +--*/ | |
5547 | +void | |
5548 | +VmbusChildDeviceRemove( | |
5549 | + DEVICE_OBJECT* ChildDevice) | |
5550 | +{ | |
5551 | + VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | |
5552 | + | |
5553 | + vmbusDriver->OnChildDeviceRemove(ChildDevice); | |
5554 | +} | |
5555 | + | |
5556 | +/*++ | |
5557 | + | |
5558 | +Name: | |
5559 | + VmbusChildDeviceDestroy() | |
5560 | + | |
5561 | +Description: | |
5562 | + Release the child device from the vmbus | |
5563 | + | |
5564 | +--*/ | |
5565 | +//void | |
5566 | +//VmbusChildDeviceDestroy( | |
5567 | +// DEVICE_OBJECT* ChildDevice | |
5568 | +// ) | |
5569 | +//{ | |
5570 | +// VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; | |
5571 | +// | |
5572 | +// vmbusDriver->OnChildDeviceDestroy(ChildDevice); | |
5573 | +//} | |
5574 | + | |
5575 | +/*++ | |
5576 | + | |
5577 | +Name: | |
5578 | + VmbusOnDeviceAdd() | |
5579 | + | |
5580 | +Description: | |
5581 | + Callback when the root bus device is added | |
5582 | + | |
5583 | +--*/ | |
5584 | +static int | |
5585 | +VmbusOnDeviceAdd( | |
5586 | + DEVICE_OBJECT *dev, | |
5587 | + void *AdditionalInfo | |
5588 | + ) | |
5589 | +{ | |
5590 | + UINT32 *irqvector = (UINT32*) AdditionalInfo; | |
5591 | + int ret=0; | |
5592 | + | |
5593 | + DPRINT_ENTER(VMBUS); | |
5594 | + | |
5595 | + gDevice = dev; | |
5596 | + | |
5597 | + memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID)); | |
5598 | + memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID)); | |
5599 | + | |
5600 | + //strcpy(dev->name, "vmbus"); | |
5601 | + // SynIC setup... | |
5602 | + ret = HvSynicInit(*irqvector); | |
5603 | + | |
5604 | + // Connect to VMBus in the root partition | |
5605 | + ret = VmbusConnect(); | |
5606 | + | |
5607 | + //VmbusSendEvent(device->localPortId+1); | |
5608 | + DPRINT_EXIT(VMBUS); | |
5609 | + | |
5610 | + return ret; | |
5611 | +} | |
5612 | + | |
5613 | + | |
5614 | +/*++ | |
5615 | + | |
5616 | +Name: | |
5617 | + VmbusOnDeviceRemove() | |
5618 | + | |
5619 | +Description: | |
5620 | + Callback when the root bus device is removed | |
5621 | + | |
5622 | +--*/ | |
5623 | +int VmbusOnDeviceRemove( | |
5624 | + DEVICE_OBJECT* dev | |
5625 | + ) | |
5626 | +{ | |
5627 | + int ret=0; | |
5628 | + | |
5629 | + DPRINT_ENTER(VMBUS); | |
5630 | + | |
5631 | + VmbusChannelReleaseUnattachedChannels(); | |
5632 | + | |
5633 | + VmbusDisconnect(); | |
5634 | + | |
5635 | + HvSynicCleanup(); | |
5636 | + | |
5637 | + DPRINT_EXIT(VMBUS); | |
5638 | + | |
5639 | + return ret; | |
5640 | +} | |
5641 | + | |
5642 | + | |
5643 | +/*++ | |
5644 | + | |
5645 | +Name: | |
5646 | + VmbusOnCleanup() | |
5647 | + | |
5648 | +Description: | |
5649 | + Perform any cleanup when the driver is removed | |
5650 | + | |
5651 | +--*/ | |
5652 | +void | |
5653 | +VmbusOnCleanup( | |
5654 | + DRIVER_OBJECT* drv | |
5655 | + ) | |
5656 | +{ | |
5657 | + //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; | |
5658 | + | |
5659 | + DPRINT_ENTER(VMBUS); | |
5660 | + | |
5661 | + HvCleanup(); | |
5662 | + | |
5663 | + DPRINT_EXIT(VMBUS); | |
5664 | +} | |
5665 | + | |
5666 | + | |
5667 | +/*++ | |
5668 | + | |
5669 | +Name: | |
5670 | + VmbusOnMsgDPC() | |
5671 | + | |
5672 | +Description: | |
5673 | + DPC routine to handle messages from the hypervisior | |
5674 | + | |
5675 | +--*/ | |
5676 | +void | |
5677 | +VmbusOnMsgDPC( | |
5678 | + DRIVER_OBJECT* drv | |
5679 | + ) | |
5680 | +{ | |
5681 | + void *page_addr = gHvContext.synICMessagePage[0]; | |
5682 | + | |
5683 | + HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT; | |
5684 | + HV_MESSAGE *copied; | |
5685 | + while (1) | |
5686 | + { | |
5687 | + if (msg->Header.MessageType == HvMessageTypeNone) // no msg | |
5688 | + { | |
5689 | + break; | |
5690 | + } | |
5691 | + else | |
5692 | + { | |
5693 | + copied = MemAllocAtomic(sizeof(HV_MESSAGE)); | |
5694 | + if (copied == NULL) | |
5695 | + { | |
5696 | + continue; | |
5697 | + } | |
5698 | + | |
5699 | + memcpy(copied, msg, sizeof(HV_MESSAGE)); | |
5700 | + WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied); | |
5701 | + } | |
5702 | + | |
5703 | + msg->Header.MessageType = HvMessageTypeNone; | |
5704 | + | |
5705 | + // Make sure the write to MessageType (ie set to HvMessageTypeNone) happens | |
5706 | + // before we read the MessagePending and EOMing. Otherwise, the EOMing will not deliver | |
5707 | + // any more messages since there is no empty slot | |
5708 | + MemoryFence(); | |
5709 | + | |
5710 | + if (msg->Header.MessageFlags.MessagePending) | |
5711 | + { | |
5712 | + // This will cause message queue rescan to possibly deliver another msg from the hypervisor | |
5713 | + WriteMsr(HV_X64_MSR_EOM, 0); | |
5714 | + } | |
5715 | + } | |
5716 | +} | |
5717 | + | |
5718 | +/*++ | |
5719 | + | |
5720 | +Name: | |
5721 | + VmbusOnEventDPC() | |
5722 | + | |
5723 | +Description: | |
5724 | + DPC routine to handle events from the hypervisior | |
5725 | + | |
5726 | +--*/ | |
5727 | +void | |
5728 | +VmbusOnEventDPC( | |
5729 | + DRIVER_OBJECT* drv | |
5730 | + ) | |
5731 | +{ | |
5732 | + // TODO: Process any events | |
5733 | + VmbusOnEvents(); | |
5734 | +} | |
5735 | + | |
5736 | + | |
5737 | +/*++ | |
5738 | + | |
5739 | +Name: | |
5740 | + VmbusOnISR() | |
5741 | + | |
5742 | +Description: | |
5743 | + ISR routine | |
5744 | + | |
5745 | +--*/ | |
5746 | +int | |
5747 | +VmbusOnISR( | |
5748 | + DRIVER_OBJECT* drv | |
5749 | + ) | |
5750 | +{ | |
5751 | + //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; | |
5752 | + | |
5753 | + int ret=0; | |
5754 | + //struct page* page; | |
5755 | + void *page_addr; | |
5756 | + HV_MESSAGE* msg; | |
5757 | + HV_SYNIC_EVENT_FLAGS* event; | |
5758 | + | |
5759 | + //page = SynICMessagePage[0]; | |
5760 | + //page_addr = page_address(page); | |
5761 | + page_addr = gHvContext.synICMessagePage[0]; | |
5762 | + msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT; | |
5763 | + | |
5764 | + DPRINT_ENTER(VMBUS); | |
5765 | + | |
5766 | + // Check if there are actual msgs to be process | |
5767 | + if (msg->Header.MessageType != HvMessageTypeNone) | |
5768 | + { | |
5769 | + DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize); | |
5770 | + ret |= 0x1; | |
5771 | + } | |
5772 | + | |
5773 | + // TODO: Check if there are events to be process | |
5774 | + page_addr = gHvContext.synICEventPage[0]; | |
5775 | + event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT; | |
5776 | + | |
5777 | + // Since we are a child, we only need to check bit 0 | |
5778 | + if (BitTestAndClear(&event->Flags32[0], 0)) | |
5779 | + { | |
5780 | + DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]); | |
5781 | + ret |= 0x2; | |
5782 | + } | |
5783 | + | |
5784 | + DPRINT_EXIT(VMBUS); | |
5785 | + return ret; | |
5786 | +} | |
5787 | + | |
5788 | +// eof | |
5789 | --- /dev/null | |
5790 | +++ b/drivers/staging/hv/vmbus_drv.c | |
5791 | @@ -0,0 +1,1228 @@ | |
5792 | +/* | |
5793 | + * | |
5794 | + * Copyright (c) 2009, Microsoft Corporation. | |
5795 | + * | |
5796 | + * This program is free software; you can redistribute it and/or modify it | |
5797 | + * under the terms and conditions of the GNU General Public License, | |
5798 | + * version 2, as published by the Free Software Foundation. | |
5799 | + * | |
5800 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
5801 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
5802 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
5803 | + * more details. | |
5804 | + * | |
5805 | + * You should have received a copy of the GNU General Public License along with | |
5806 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
5807 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
5808 | + * | |
5809 | + * Authors: | |
5810 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
5811 | + * Hank Janssen <hjanssen@microsoft.com> | |
5812 | + * | |
5813 | + */ | |
5814 | + | |
5815 | + | |
5816 | +#include <linux/init.h> | |
5817 | +#include <linux/module.h> | |
5818 | +#include <linux/device.h> | |
5819 | +#include <linux/irq.h> | |
5820 | +#include <linux/interrupt.h> | |
5821 | +#include <linux/sysctl.h> | |
5822 | + | |
5823 | +#include "logging.h" | |
5824 | +#include "vmbus.h" | |
5825 | + | |
5826 | +// | |
5827 | +// Defines | |
5828 | +// | |
5829 | + | |
5830 | +// FIXME! We need to do this dynamically for PIC and APIC system | |
5831 | +#define VMBUS_IRQ 0x5 | |
5832 | +#ifdef KERNEL_2_6_27 | |
5833 | +#define VMBUS_IRQ_VECTOR IRQ5_VECTOR | |
5834 | +#endif | |
5835 | +// | |
5836 | +// Data types | |
5837 | +// | |
5838 | + | |
5839 | +// Main vmbus driver data structure | |
5840 | +struct vmbus_driver_context { | |
5841 | + // !! These must be the first 2 fields !! | |
5842 | + // The driver field is not used in here. Instead, the bus field is | |
5843 | + // used to represent the driver | |
5844 | + struct driver_context drv_ctx; | |
5845 | + VMBUS_DRIVER_OBJECT drv_obj; | |
5846 | + | |
5847 | + struct bus_type bus; | |
5848 | + struct tasklet_struct msg_dpc; | |
5849 | + struct tasklet_struct event_dpc; | |
5850 | + | |
5851 | + // The bus root device | |
5852 | + struct device_context device_ctx; | |
5853 | +}; | |
5854 | + | |
5855 | +// | |
5856 | +// Static decl | |
5857 | +// | |
5858 | +static int vmbus_match(struct device *device, struct device_driver *driver); | |
5859 | +static int vmbus_probe(struct device *device); | |
5860 | +static int vmbus_remove(struct device *device); | |
5861 | +static void vmbus_shutdown(struct device *device); | |
5862 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
5863 | +#elif defined(KERNEL_2_6_27) | |
5864 | +static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env); | |
5865 | +#else | |
5866 | +static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size); | |
5867 | +#endif | |
5868 | +static void vmbus_msg_dpc(unsigned long data); | |
5869 | +static void vmbus_event_dpc(unsigned long data); | |
5870 | + | |
5871 | +#ifdef KERNEL_2_6_27 | |
5872 | +static irqreturn_t vmbus_isr(int irq, void* dev_id); | |
5873 | +#else | |
5874 | +static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs); | |
5875 | +#endif | |
5876 | + | |
5877 | +static void vmbus_device_release(struct device *device); | |
5878 | +static void vmbus_bus_release(struct device *device); | |
5879 | + | |
5880 | +static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context); | |
5881 | +static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj); | |
5882 | +static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj); | |
5883 | +static void vmbus_child_device_unregister(DEVICE_OBJECT* child_device_obj); | |
5884 | +static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info); | |
5885 | + | |
5886 | +//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf); | |
5887 | +//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf); | |
5888 | + | |
5889 | +static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf); | |
5890 | + | |
5891 | +// | |
5892 | +// Global | |
5893 | +// | |
5894 | + | |
5895 | +// Global logging setting | |
5896 | + | |
5897 | +//unsigned int vmbus_loglevel= (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); | |
5898 | +//unsigned int vmbus_loglevel= (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); | |
5899 | +unsigned int vmbus_loglevel= (ALL_MODULES << 16 | INFO_LVL); | |
5900 | +EXPORT_SYMBOL(vmbus_loglevel); | |
5901 | + | |
5902 | +static int vmbus_irq = VMBUS_IRQ; | |
5903 | + | |
5904 | +// Setup /proc/sys/bus/vmbus/vmbus_loglevel | |
5905 | +// Allow usage of sysctl cmd to set the logging level | |
5906 | +static struct ctl_table_header *vmbus_ctl_table_hdr; | |
5907 | + | |
5908 | +static ctl_table vmbus_dev_ctl_table[] = { | |
5909 | + { .ctl_name = 8461, | |
5910 | + .procname = "vmbus_loglevel", | |
5911 | + .data = &vmbus_loglevel, | |
5912 | + .maxlen = sizeof(vmbus_loglevel), | |
5913 | + .mode = 0644, | |
5914 | + .proc_handler = &proc_dointvec }, | |
5915 | + { } | |
5916 | +}; | |
5917 | + | |
5918 | +static ctl_table vmbus_ctl_table[] = { | |
5919 | + { .ctl_name = CTL_DEV, | |
5920 | + .procname = "vmbus", | |
5921 | + .mode = 0555, | |
5922 | + .child = vmbus_dev_ctl_table }, | |
5923 | + { } | |
5924 | +}; | |
5925 | + | |
5926 | +static ctl_table vmus_root_ctl_table[] = { | |
5927 | + { .ctl_name = CTL_BUS, | |
5928 | + .procname = "bus", | |
5929 | + .mode = 0555, | |
5930 | + .child = vmbus_ctl_table }, | |
5931 | + { } | |
5932 | +}; | |
5933 | + | |
5934 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
5935 | +#else | |
5936 | +// | |
5937 | +// Set up per device attributes in /sys/bus/vmbus/devices/<bus device> | |
5938 | +// | |
5939 | +static struct device_attribute vmbus_device_attrs[] = { | |
5940 | + __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL), | |
5941 | + __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL), | |
5942 | + __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL), | |
5943 | + __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL), | |
5944 | + __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL), | |
5945 | + | |
5946 | + __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), | |
5947 | + __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), | |
5948 | + __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), | |
5949 | + | |
5950 | + __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), | |
5951 | + __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), | |
5952 | + __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), | |
5953 | + | |
5954 | + __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), | |
5955 | + __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL), | |
5956 | + __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL), | |
5957 | + __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | |
5958 | + __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | |
5959 | + | |
5960 | + __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), | |
5961 | + __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL), | |
5962 | + __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL), | |
5963 | + __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | |
5964 | + __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), | |
5965 | + __ATTR_NULL | |
5966 | +}; | |
5967 | +#endif | |
5968 | + | |
5969 | +// The one and only one | |
5970 | +static struct vmbus_driver_context g_vmbus_drv={ | |
5971 | + .bus.name = "vmbus", | |
5972 | + .bus.match = vmbus_match, | |
5973 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
5974 | +#else | |
5975 | + .bus.shutdown = vmbus_shutdown, | |
5976 | + .bus.remove = vmbus_remove, | |
5977 | + .bus.probe = vmbus_probe, | |
5978 | + .bus.uevent = vmbus_uevent, | |
5979 | + .bus.dev_attrs = vmbus_device_attrs, | |
5980 | +#endif | |
5981 | +}; | |
5982 | + | |
5983 | +// | |
5984 | +// Routines | |
5985 | +// | |
5986 | + | |
5987 | + | |
5988 | +/*++ | |
5989 | + | |
5990 | +Name: vmbus_show_device_attr() | |
5991 | + | |
5992 | +Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices/<bus device>/<attr name>" | |
5993 | + | |
5994 | +--*/ | |
5995 | +static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf) | |
5996 | +{ | |
5997 | + struct device_context *device_ctx = device_to_device_context(dev); | |
5998 | + DEVICE_INFO device_info; | |
5999 | + | |
6000 | + memset(&device_info, 0, sizeof(DEVICE_INFO)); | |
6001 | + | |
6002 | + vmbus_child_device_get_info(&device_ctx->device_obj, &device_info); | |
6003 | + | |
6004 | + if (!strcmp(dev_attr->attr.name, "class_id")) | |
6005 | + { | |
6006 | + return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | |
6007 | + device_info.ChannelType.Data[3], device_info.ChannelType.Data[2], device_info.ChannelType.Data[1], device_info.ChannelType.Data[0], | |
6008 | + device_info.ChannelType.Data[5], device_info.ChannelType.Data[4], | |
6009 | + device_info.ChannelType.Data[7], device_info.ChannelType.Data[6], | |
6010 | + 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]); | |
6011 | + | |
6012 | + } | |
6013 | + else if (!strcmp(dev_attr->attr.name, "device_id")) | |
6014 | + { | |
6015 | + return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | |
6016 | + device_info.ChannelInstance.Data[3], device_info.ChannelInstance.Data[2], device_info.ChannelInstance.Data[1], device_info.ChannelInstance.Data[0], | |
6017 | + device_info.ChannelInstance.Data[5], device_info.ChannelInstance.Data[4], | |
6018 | + device_info.ChannelInstance.Data[7], device_info.ChannelInstance.Data[6], | |
6019 | + 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]); | |
6020 | + } | |
6021 | + else if (!strcmp(dev_attr->attr.name, "state")) | |
6022 | + { | |
6023 | + return sprintf(buf, "%d\n", device_info.ChannelState); | |
6024 | + } | |
6025 | + else if (!strcmp(dev_attr->attr.name, "id")) | |
6026 | + { | |
6027 | + return sprintf(buf, "%d\n", device_info.ChannelId); | |
6028 | + } | |
6029 | + else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) | |
6030 | + { | |
6031 | + return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask); | |
6032 | + } | |
6033 | + else if (!strcmp(dev_attr->attr.name, "out_read_index")) | |
6034 | + { | |
6035 | + return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex); | |
6036 | + } | |
6037 | + else if (!strcmp(dev_attr->attr.name, "out_write_index")) | |
6038 | + { | |
6039 | + return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex); | |
6040 | + } | |
6041 | + else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) | |
6042 | + { | |
6043 | + return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead); | |
6044 | + } | |
6045 | + else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) | |
6046 | + { | |
6047 | + return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite); | |
6048 | + } | |
6049 | + else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) | |
6050 | + { | |
6051 | + return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask); | |
6052 | + } | |
6053 | + else if (!strcmp(dev_attr->attr.name, "in_read_index")) | |
6054 | + { | |
6055 | + return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex); | |
6056 | + } | |
6057 | + else if (!strcmp(dev_attr->attr.name, "in_write_index")) | |
6058 | + { | |
6059 | + return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex); | |
6060 | + } | |
6061 | + else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) | |
6062 | + { | |
6063 | + return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead); | |
6064 | + } | |
6065 | + else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) | |
6066 | + { | |
6067 | + return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite); | |
6068 | + } | |
6069 | + else if (!strcmp(dev_attr->attr.name, "monitor_id")) | |
6070 | + { | |
6071 | + return sprintf(buf, "%d\n", device_info.MonitorId); | |
6072 | + } | |
6073 | + else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) | |
6074 | + { | |
6075 | + return sprintf(buf, "%d\n", device_info.ServerMonitorPending); | |
6076 | + } | |
6077 | + else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) | |
6078 | + { | |
6079 | + return sprintf(buf, "%d\n", device_info.ServerMonitorLatency); | |
6080 | + } | |
6081 | + else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) | |
6082 | + { | |
6083 | + return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId); | |
6084 | + } | |
6085 | + else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) | |
6086 | + { | |
6087 | + return sprintf(buf, "%d\n", device_info.ClientMonitorPending); | |
6088 | + } | |
6089 | + else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) | |
6090 | + { | |
6091 | + return sprintf(buf, "%d\n", device_info.ClientMonitorLatency); | |
6092 | + } | |
6093 | + else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) | |
6094 | + { | |
6095 | + return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId); | |
6096 | + } | |
6097 | + else | |
6098 | + { | |
6099 | + return 0; | |
6100 | + } | |
6101 | +} | |
6102 | + | |
6103 | +/*++ | |
6104 | + | |
6105 | +Name: vmbus_show_class_id() | |
6106 | + | |
6107 | +Desc: Show the device class id in sysfs | |
6108 | + | |
6109 | +--*/ | |
6110 | +//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf) | |
6111 | +//{ | |
6112 | +// struct device_context *device_ctx = device_to_device_context(dev); | |
6113 | +// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | |
6114 | +// device_ctx->class_id[3], device_ctx->class_id[2], device_ctx->class_id[1], device_ctx->class_id[0], | |
6115 | +// device_ctx->class_id[5], device_ctx->class_id[4], | |
6116 | +// device_ctx->class_id[7], device_ctx->class_id[6], | |
6117 | +// 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]); | |
6118 | +//} | |
6119 | + | |
6120 | +/*++ | |
6121 | + | |
6122 | +Name: vmbus_show_device_id() | |
6123 | + | |
6124 | +Desc: Show the device instance id in sysfs | |
6125 | + | |
6126 | +--*/ | |
6127 | +//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) | |
6128 | +//{ | |
6129 | +// struct device_context *device_ctx = device_to_device_context(dev); | |
6130 | +// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", | |
6131 | +// device_ctx->device_id[3], device_ctx->device_id[2], device_ctx->device_id[1], device_ctx->device_id[0], | |
6132 | +// device_ctx->device_id[5], device_ctx->device_id[4], | |
6133 | +// device_ctx->device_id[7], device_ctx->device_id[6], | |
6134 | +// 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]); | |
6135 | +//} | |
6136 | + | |
6137 | +/*++ | |
6138 | + | |
6139 | +Name: vmbus_bus_init() | |
6140 | + | |
6141 | +Desc: Main vmbus driver initialization routine. Here, we | |
6142 | + - initialize the vmbus driver context | |
6143 | + - setup various driver entry points | |
6144 | + - invoke the vmbus hv main init routine | |
6145 | + - get the irq resource | |
6146 | + - invoke the vmbus to add the vmbus root device | |
6147 | + - setup the vmbus root device | |
6148 | + - retrieve the channel offers | |
6149 | +--*/ | |
6150 | +int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init) | |
6151 | +{ | |
6152 | + int ret=0; | |
6153 | + unsigned int vector=0; | |
6154 | + | |
6155 | + struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv; | |
6156 | + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | |
6157 | + | |
6158 | + struct device_context *dev_ctx=&g_vmbus_drv.device_ctx; | |
6159 | + | |
6160 | + DPRINT_ENTER(VMBUS_DRV); | |
6161 | + | |
6162 | + // Set this up to allow lower layer to callback to add/remove child devices on the bus | |
6163 | + vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create; | |
6164 | + vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy; | |
6165 | + vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; | |
6166 | + vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister; | |
6167 | + | |
6168 | + // Call to bus driver to initialize | |
6169 | + ret = pfn_drv_init(&vmbus_drv_obj->Base); | |
6170 | + if (ret != 0) | |
6171 | + { | |
6172 | + DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret); | |
6173 | + goto cleanup; | |
6174 | + } | |
6175 | + | |
6176 | + // Sanity checks | |
6177 | + if (!vmbus_drv_obj->Base.OnDeviceAdd) | |
6178 | + { | |
6179 | + DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set"); | |
6180 | + ret = -1; | |
6181 | + goto cleanup; | |
6182 | + } | |
6183 | + | |
6184 | + vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name; | |
6185 | + | |
6186 | + // Initialize the bus context | |
6187 | + tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, (unsigned long)vmbus_drv_obj); | |
6188 | + tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, (unsigned long)vmbus_drv_obj); | |
6189 | + | |
6190 | + // Now, register the bus driver with LDM | |
6191 | + bus_register(&vmbus_drv_ctx->bus); | |
6192 | + | |
6193 | + // Get the interrupt resource | |
6194 | +#ifdef KERNEL_2_6_27 | |
6195 | + ret = request_irq(vmbus_irq, | |
6196 | + vmbus_isr, | |
6197 | + IRQF_SAMPLE_RANDOM, | |
6198 | + vmbus_drv_obj->Base.name, | |
6199 | + NULL); | |
6200 | +#else | |
6201 | + ret = request_irq(vmbus_irq, | |
6202 | + vmbus_isr, | |
6203 | + SA_SAMPLE_RANDOM, | |
6204 | + vmbus_drv_obj->Base.name, | |
6205 | + NULL); | |
6206 | +#endif | |
6207 | + | |
6208 | + if (ret != 0) | |
6209 | + { | |
6210 | + DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq); | |
6211 | + | |
6212 | + bus_unregister(&vmbus_drv_ctx->bus); | |
6213 | + | |
6214 | + ret = -1; | |
6215 | + goto cleanup; | |
6216 | + } | |
6217 | +#ifdef KERNEL_2_6_27 | |
6218 | + vector = VMBUS_IRQ_VECTOR; | |
6219 | +#else | |
6220 | +#if X2V_LINUX | |
6221 | + vector = vmbus_irq + FIRST_DEVICE_VECTOR - 2; | |
6222 | +#else | |
6223 | + vector = vmbus_irq + FIRST_EXTERNAL_VECTOR; | |
6224 | +#endif | |
6225 | +#endif | |
6226 | + | |
6227 | + DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector); | |
6228 | + | |
6229 | + // Call to bus driver to add the root device | |
6230 | + memset(dev_ctx, 0, sizeof(struct device_context)); | |
6231 | + | |
6232 | + ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector); | |
6233 | + if (ret != 0) | |
6234 | + { | |
6235 | + DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device"); | |
6236 | + | |
6237 | + free_irq(vmbus_irq, NULL); | |
6238 | + | |
6239 | + bus_unregister(&vmbus_drv_ctx->bus); | |
6240 | + | |
6241 | + ret = -1; | |
6242 | + goto cleanup; | |
6243 | + } | |
6244 | + //strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); | |
6245 | + sprintf(dev_ctx->device.bus_id, "vmbus_0_0"); | |
6246 | + memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(GUID)); | |
6247 | + memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(GUID)); | |
6248 | + | |
6249 | + // No need to bind a driver to the root device. | |
6250 | + dev_ctx->device.parent = NULL; | |
6251 | + dev_ctx->device.bus = &vmbus_drv_ctx->bus; //NULL; // vmbus_remove() does not get invoked | |
6252 | + | |
6253 | + // Setup the device dispatch table | |
6254 | + dev_ctx->device.release = vmbus_bus_release; | |
6255 | + | |
6256 | + // Setup the bus as root device | |
6257 | + device_register(&dev_ctx->device); | |
6258 | + | |
6259 | + vmbus_drv_obj->GetChannelOffers(); | |
6260 | + | |
6261 | +cleanup: | |
6262 | + DPRINT_EXIT(VMBUS_DRV); | |
6263 | + | |
6264 | + return ret; | |
6265 | +} | |
6266 | + | |
6267 | + | |
6268 | +/*++ | |
6269 | + | |
6270 | +Name: vmbus_bus_exit() | |
6271 | + | |
6272 | +Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init() | |
6273 | + | |
6274 | +--*/ | |
6275 | +void vmbus_bus_exit(void) | |
6276 | +{ | |
6277 | + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | |
6278 | + struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv; | |
6279 | + | |
6280 | + struct device_context *dev_ctx=&g_vmbus_drv.device_ctx; | |
6281 | + | |
6282 | + DPRINT_ENTER(VMBUS_DRV); | |
6283 | + | |
6284 | + // Remove the root device | |
6285 | + if (vmbus_drv_obj->Base.OnDeviceRemove) | |
6286 | + vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj); | |
6287 | + | |
6288 | + if (vmbus_drv_obj->Base.OnCleanup) | |
6289 | + vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base); | |
6290 | + | |
6291 | + // Unregister the root bus device | |
6292 | + device_unregister(&dev_ctx->device); | |
6293 | + | |
6294 | + bus_unregister(&vmbus_drv_ctx->bus); | |
6295 | + | |
6296 | + free_irq(vmbus_irq, NULL); | |
6297 | + | |
6298 | + tasklet_kill(&vmbus_drv_ctx->msg_dpc); | |
6299 | + tasklet_kill(&vmbus_drv_ctx->event_dpc); | |
6300 | + | |
6301 | + DPRINT_EXIT(VMBUS_DRV); | |
6302 | + | |
6303 | + return; | |
6304 | +} | |
6305 | + | |
6306 | +/*++ | |
6307 | + | |
6308 | +Name: vmbus_child_driver_register() | |
6309 | + | |
6310 | +Desc: Register a vmbus's child driver | |
6311 | + | |
6312 | +--*/ | |
6313 | +void vmbus_child_driver_register(struct driver_context* driver_ctx) | |
6314 | +{ | |
6315 | + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | |
6316 | + | |
6317 | + DPRINT_ENTER(VMBUS_DRV); | |
6318 | + | |
6319 | + DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name); | |
6320 | + | |
6321 | + // The child driver on this vmbus | |
6322 | + driver_ctx->driver.bus = &g_vmbus_drv.bus; | |
6323 | + | |
6324 | + driver_register(&driver_ctx->driver); | |
6325 | + | |
6326 | + vmbus_drv_obj->GetChannelOffers(); | |
6327 | + | |
6328 | + DPRINT_EXIT(VMBUS_DRV); | |
6329 | +} | |
6330 | + | |
6331 | +EXPORT_SYMBOL(vmbus_child_driver_register); | |
6332 | + | |
6333 | +/*++ | |
6334 | + | |
6335 | +Name: vmbus_child_driver_unregister() | |
6336 | + | |
6337 | +Desc: Unregister a vmbus's child driver | |
6338 | + | |
6339 | +--*/ | |
6340 | +void vmbus_child_driver_unregister(struct driver_context* driver_ctx) | |
6341 | +{ | |
6342 | + DPRINT_ENTER(VMBUS_DRV); | |
6343 | + | |
6344 | + DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name); | |
6345 | + | |
6346 | + driver_unregister(&driver_ctx->driver); | |
6347 | + | |
6348 | + driver_ctx->driver.bus = NULL; | |
6349 | + | |
6350 | + DPRINT_EXIT(VMBUS_DRV); | |
6351 | +} | |
6352 | + | |
6353 | +EXPORT_SYMBOL(vmbus_child_driver_unregister); | |
6354 | + | |
6355 | +/*++ | |
6356 | + | |
6357 | +Name: vmbus_get_interface() | |
6358 | + | |
6359 | +Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits | |
6360 | + above vmbus | |
6361 | +--*/ | |
6362 | +void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface) | |
6363 | +{ | |
6364 | + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | |
6365 | + | |
6366 | + vmbus_drv_obj->GetChannelInterface(interface); | |
6367 | +} | |
6368 | + | |
6369 | +EXPORT_SYMBOL(vmbus_get_interface); | |
6370 | + | |
6371 | + | |
6372 | +/*++ | |
6373 | + | |
6374 | +Name: vmbus_child_device_get_info() | |
6375 | + | |
6376 | +Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs. | |
6377 | +--*/ | |
6378 | +static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info) | |
6379 | +{ | |
6380 | + VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; | |
6381 | + | |
6382 | + vmbus_drv_obj->GetChannelInfo(device_obj, device_info); | |
6383 | +} | |
6384 | + | |
6385 | + | |
6386 | +/*++ | |
6387 | + | |
6388 | +Name: vmbus_child_device_create() | |
6389 | + | |
6390 | +Desc: Creates and registers a new child device on the vmbus. | |
6391 | + | |
6392 | +--*/ | |
6393 | +static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context) | |
6394 | +{ | |
6395 | + struct device_context *child_device_ctx; | |
6396 | + DEVICE_OBJECT* child_device_obj; | |
6397 | + | |
6398 | + DPRINT_ENTER(VMBUS_DRV); | |
6399 | + | |
6400 | + // Allocate the new child device | |
6401 | + child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL); | |
6402 | + if (!child_device_ctx) | |
6403 | + { | |
6404 | + DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device"); | |
6405 | + DPRINT_EXIT(VMBUS_DRV); | |
6406 | + | |
6407 | + return NULL; | |
6408 | + } | |
6409 | + | |
6410 | + DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - " | |
6411 | + "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}," | |
6412 | + "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | |
6413 | + &child_device_ctx->device, | |
6414 | + 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], | |
6415 | + 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]); | |
6416 | + | |
6417 | + child_device_obj = &child_device_ctx->device_obj; | |
6418 | + child_device_obj->context = context; | |
6419 | + memcpy(&child_device_obj->deviceType, &type, sizeof(GUID)); | |
6420 | + memcpy(&child_device_obj->deviceInstance, &instance, sizeof(GUID)); | |
6421 | + | |
6422 | + memcpy(&child_device_ctx->class_id, &type, sizeof(GUID)); | |
6423 | + memcpy(&child_device_ctx->device_id, &instance, sizeof(GUID)); | |
6424 | + | |
6425 | + DPRINT_EXIT(VMBUS_DRV); | |
6426 | + | |
6427 | + return child_device_obj; | |
6428 | +} | |
6429 | + | |
6430 | +/*++ | |
6431 | + | |
6432 | +Name: vmbus_child_device_register() | |
6433 | + | |
6434 | +Desc: Register the child device on the specified bus | |
6435 | + | |
6436 | +--*/ | |
6437 | +static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj) | |
6438 | +{ | |
6439 | + int ret=0; | |
6440 | + struct device_context *root_device_ctx = to_device_context(root_device_obj); | |
6441 | + struct device_context *child_device_ctx = to_device_context(child_device_obj); | |
6442 | + static int device_num=0; | |
6443 | + | |
6444 | + DPRINT_ENTER(VMBUS_DRV); | |
6445 | + | |
6446 | + DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx); | |
6447 | + // | |
6448 | + // Make sure we are not registered already | |
6449 | + // | |
6450 | + if (child_device_ctx->device.bus_id[0] != '\0') | |
6451 | + { | |
6452 | + DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id); | |
6453 | + | |
6454 | + ret = -1; | |
6455 | + goto Cleanup; | |
6456 | + } | |
6457 | + | |
6458 | + // Set the device bus id. Otherwise, device_register()will fail. | |
6459 | + sprintf(child_device_ctx->device.bus_id, "vmbus_0_%d", InterlockedIncrement(&device_num)); | |
6460 | + | |
6461 | + // The new device belongs to this bus | |
6462 | + child_device_ctx->device.bus = &g_vmbus_drv.bus; //device->dev.bus; | |
6463 | + child_device_ctx->device.parent = &root_device_ctx->device; | |
6464 | + child_device_ctx->device.release = vmbus_device_release; | |
6465 | + | |
6466 | + // Register with the LDM. This will kick off the driver/device binding...which will | |
6467 | + // eventually call vmbus_match() and vmbus_probe() | |
6468 | + ret = device_register(&child_device_ctx->device); | |
6469 | + | |
6470 | + // vmbus_probe() error does not get propergate to device_register(). | |
6471 | + ret = child_device_ctx->probe_error; | |
6472 | + | |
6473 | + if (ret) | |
6474 | + DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p) (%d)", &child_device_ctx->device); | |
6475 | + else | |
6476 | + DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device); | |
6477 | + | |
6478 | +Cleanup: | |
6479 | + DPRINT_EXIT(VMBUS_DRV); | |
6480 | + | |
6481 | + return ret; | |
6482 | +} | |
6483 | + | |
6484 | +/*++ | |
6485 | + | |
6486 | +Name: vmbus_child_device_unregister() | |
6487 | + | |
6488 | +Desc: Remove the specified child device from the vmbus. | |
6489 | + | |
6490 | +--*/ | |
6491 | +static void vmbus_child_device_unregister(DEVICE_OBJECT* device_obj) | |
6492 | +{ | |
6493 | + struct device_context *device_ctx = to_device_context(device_obj); | |
6494 | + | |
6495 | + DPRINT_ENTER(VMBUS_DRV); | |
6496 | + | |
6497 | + DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device); | |
6498 | + | |
6499 | + // Kick off the process of unregistering the device. | |
6500 | + // This will call vmbus_remove() and eventually vmbus_device_release() | |
6501 | + device_unregister(&device_ctx->device); | |
6502 | + | |
6503 | + DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device); | |
6504 | + | |
6505 | + DPRINT_EXIT(VMBUS_DRV); | |
6506 | +} | |
6507 | + | |
6508 | + | |
6509 | +/*++ | |
6510 | + | |
6511 | +Name: vmbus_child_device_destroy() | |
6512 | + | |
6513 | +Desc: Destroy the specified child device on the vmbus. | |
6514 | + | |
6515 | +--*/ | |
6516 | +static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj) | |
6517 | +{ | |
6518 | + DPRINT_ENTER(VMBUS_DRV); | |
6519 | + | |
6520 | + DPRINT_EXIT(VMBUS_DRV); | |
6521 | +} | |
6522 | + | |
6523 | +/*++ | |
6524 | + | |
6525 | +Name: vmbus_uevent() | |
6526 | + | |
6527 | +Desc: This routine is invoked when a device is added or removed on the vmbus to generate a uevent to udev in the | |
6528 | + userspace. The udev will then look at its rule and the uevent generated here to load the appropriate driver | |
6529 | + | |
6530 | +--*/ | |
6531 | +#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) | |
6532 | +#elif defined(KERNEL_2_6_27) | |
6533 | +static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) | |
6534 | +{ | |
6535 | + struct device_context *device_ctx = device_to_device_context(device); | |
6536 | + int i=0; | |
6537 | + int len=0; | |
6538 | + int ret; | |
6539 | + | |
6540 | + DPRINT_ENTER(VMBUS_DRV); | |
6541 | + | |
6542 | + 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}", | |
6543 | + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | |
6544 | + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | |
6545 | + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | |
6546 | + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | |
6547 | + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | |
6548 | + | |
6549 | + env->envp_idx = i; | |
6550 | + env->buflen = len; | |
6551 | + ret = add_uevent_var(env, | |
6552 | + "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | |
6553 | + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | |
6554 | + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | |
6555 | + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | |
6556 | + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | |
6557 | + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | |
6558 | + | |
6559 | + if (ret) | |
6560 | + { | |
6561 | + return ret; | |
6562 | + } | |
6563 | + | |
6564 | + ret = add_uevent_var(env, | |
6565 | + "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | |
6566 | + device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0], | |
6567 | + device_ctx->device_id.Data[5], device_ctx->device_id.Data[4], | |
6568 | + device_ctx->device_id.Data[7], device_ctx->device_id.Data[6], | |
6569 | + device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11], | |
6570 | + device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]); | |
6571 | + | |
6572 | + if (ret) | |
6573 | + { | |
6574 | + return ret; | |
6575 | + } | |
6576 | + | |
6577 | + env->envp[env->envp_idx] = NULL; | |
6578 | + | |
6579 | + DPRINT_EXIT(VMBUS_DRV); | |
6580 | + | |
6581 | + return 0; | |
6582 | +} | |
6583 | + | |
6584 | +#else | |
6585 | +static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size) | |
6586 | +{ | |
6587 | + struct device_context *device_ctx = device_to_device_context(device); | |
6588 | + int i=0; | |
6589 | + int len=0; | |
6590 | + int ret; | |
6591 | + | |
6592 | + DPRINT_ENTER(VMBUS_DRV); | |
6593 | + | |
6594 | + 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}", | |
6595 | + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | |
6596 | + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | |
6597 | + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | |
6598 | + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | |
6599 | + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | |
6600 | + | |
6601 | + ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | |
6602 | + "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | |
6603 | + device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], | |
6604 | + device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], | |
6605 | + device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], | |
6606 | + device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], | |
6607 | + device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); | |
6608 | + | |
6609 | + if (ret) | |
6610 | + { | |
6611 | + return ret; | |
6612 | + } | |
6613 | + | |
6614 | + ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | |
6615 | + "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", | |
6616 | + device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0], | |
6617 | + device_ctx->device_id.Data[5], device_ctx->device_id.Data[4], | |
6618 | + device_ctx->device_id.Data[7], device_ctx->device_id.Data[6], | |
6619 | + device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11], | |
6620 | + device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]); | |
6621 | + | |
6622 | + if (ret) | |
6623 | + { | |
6624 | + return ret; | |
6625 | + } | |
6626 | + | |
6627 | + envp[i] = NULL; | |
6628 | + | |
6629 | + DPRINT_EXIT(VMBUS_DRV); | |
6630 | + | |
6631 | + return 0; | |
6632 | +} | |
6633 | +#endif | |
6634 | + | |
6635 | +/*++ | |
6636 | + | |
6637 | +Name: vmbus_match() | |
6638 | + | |
6639 | +Desc: Attempt to match the specified device to the specified driver | |
6640 | + | |
6641 | +--*/ | |
6642 | +static int vmbus_match(struct device *device, struct device_driver *driver) | |
6643 | +{ | |
6644 | + int match=0; | |
6645 | + struct driver_context *driver_ctx = driver_to_driver_context(driver); | |
6646 | + struct device_context *device_ctx = device_to_device_context(device); | |
6647 | + | |
6648 | + DPRINT_ENTER(VMBUS_DRV); | |
6649 | + | |
6650 | + // We found our driver ? | |
6651 | + if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(GUID)) == 0) | |
6652 | + { | |
6653 | + // !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast it here to access the | |
6654 | + // DRIVER_OBJECT field | |
6655 | + struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context*)driver_ctx; | |
6656 | + device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base; | |
6657 | + DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, device_ctx->device_obj.Driver); | |
6658 | + | |
6659 | + match = 1; | |
6660 | + } | |
6661 | + | |
6662 | + DPRINT_EXIT(VMBUS_DRV); | |
6663 | + | |
6664 | + return match; | |
6665 | +} | |
6666 | + | |
6667 | + | |
6668 | +/*++ | |
6669 | + | |
6670 | +Name: vmbus_probe_failed_cb() | |
6671 | + | |
6672 | +Desc: Callback when a driver probe failed in vmbus_probe(). We need a callback because | |
6673 | + we cannot invoked device_unregister() inside vmbus_probe() since vmbus_probe() may be | |
6674 | + invoked inside device_register() i.e. we cannot call device_unregister() inside | |
6675 | + device_register() | |
6676 | +--*/ | |
6677 | +#ifdef KERNEL_2_6_27 | |
6678 | +static void vmbus_probe_failed_cb(struct work_struct *context) | |
6679 | +#else | |
6680 | +static void vmbus_probe_failed_cb(void* context) | |
6681 | +#endif | |
6682 | +{ | |
6683 | + struct device_context *device_ctx = (struct device_context*)context; | |
6684 | + | |
6685 | + | |
6686 | + DPRINT_ENTER(VMBUS_DRV); | |
6687 | + | |
6688 | + // Kick off the process of unregistering the device. | |
6689 | + // This will call vmbus_remove() and eventually vmbus_device_release() | |
6690 | + device_unregister(&device_ctx->device); | |
6691 | + | |
6692 | + //put_device(&device_ctx->device); | |
6693 | + DPRINT_EXIT(VMBUS_DRV); | |
6694 | +} | |
6695 | + | |
6696 | + | |
6697 | +/*++ | |
6698 | + | |
6699 | +Name: vmbus_probe() | |
6700 | + | |
6701 | +Desc: Add the new vmbus's child device | |
6702 | + | |
6703 | +--*/ | |
6704 | +static int vmbus_probe(struct device *child_device) | |
6705 | +{ | |
6706 | + int ret=0; | |
6707 | + struct driver_context *driver_ctx = driver_to_driver_context(child_device->driver); | |
6708 | + struct device_context *device_ctx = device_to_device_context(child_device); | |
6709 | + | |
6710 | + DPRINT_ENTER(VMBUS_DRV); | |
6711 | + | |
6712 | + // Let the specific open-source driver handles the probe if it can | |
6713 | + if (driver_ctx->probe) | |
6714 | + { | |
6715 | + ret = device_ctx->probe_error = driver_ctx->probe(child_device); | |
6716 | + if (ret != 0) | |
6717 | + { | |
6718 | + 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); | |
6719 | + | |
6720 | +#ifdef KERNEL_2_6_27 | |
6721 | + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb); | |
6722 | +#else | |
6723 | + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb, device_ctx); | |
6724 | +#endif | |
6725 | + schedule_work(&device_ctx->probe_failed_work_item); | |
6726 | + } | |
6727 | + } | |
6728 | + else | |
6729 | + { | |
6730 | + DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name); | |
6731 | + ret = -1; | |
6732 | + } | |
6733 | + | |
6734 | + DPRINT_EXIT(VMBUS_DRV); | |
6735 | + return ret; | |
6736 | +} | |
6737 | + | |
6738 | + | |
6739 | +/*++ | |
6740 | + | |
6741 | +Name: vmbus_remove() | |
6742 | + | |
6743 | +Desc: Remove a vmbus device | |
6744 | + | |
6745 | +--*/ | |
6746 | +static int vmbus_remove(struct device *child_device) | |
6747 | +{ | |
6748 | + int ret=0; | |
6749 | + struct driver_context *driver_ctx; | |
6750 | + | |
6751 | + DPRINT_ENTER(VMBUS_DRV); | |
6752 | + | |
6753 | + // Special case root bus device | |
6754 | + if (child_device->parent == NULL) | |
6755 | + { | |
6756 | + // No-op since it is statically defined and handle in vmbus_bus_exit() | |
6757 | + DPRINT_EXIT(VMBUS_DRV); | |
6758 | + return 0; | |
6759 | + } | |
6760 | + | |
6761 | + if (child_device->driver) | |
6762 | + { | |
6763 | + driver_ctx = driver_to_driver_context(child_device->driver); | |
6764 | + | |
6765 | + // Let the specific open-source driver handles the removal if it can | |
6766 | + if (driver_ctx->remove) | |
6767 | + { | |
6768 | + ret = driver_ctx->remove(child_device); | |
6769 | + } | |
6770 | + else | |
6771 | + { | |
6772 | + DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name); | |
6773 | + ret = -1; | |
6774 | + } | |
6775 | + } | |
6776 | + else | |
6777 | + { | |
6778 | + | |
6779 | + } | |
6780 | + | |
6781 | + DPRINT_EXIT(VMBUS_DRV); | |
6782 | + | |
6783 | + return 0; | |
6784 | +} | |
6785 | + | |
6786 | +/*++ | |
6787 | + | |
6788 | +Name: vmbus_shutdown() | |
6789 | + | |
6790 | +Desc: Shutdown a vmbus device | |
6791 | + | |
6792 | +--*/ | |
6793 | +static void vmbus_shutdown(struct device *child_device) | |
6794 | +{ | |
6795 | + struct driver_context *driver_ctx; | |
6796 | + | |
6797 | + DPRINT_ENTER(VMBUS_DRV); | |
6798 | + | |
6799 | + // Special case root bus device | |
6800 | + if (child_device->parent == NULL) | |
6801 | + { | |
6802 | + // No-op since it is statically defined and handle in vmbus_bus_exit() | |
6803 | + DPRINT_EXIT(VMBUS_DRV); | |
6804 | + return; | |
6805 | + } | |
6806 | + | |
6807 | + // The device may not be attached yet | |
6808 | + if (!child_device->driver) | |
6809 | + { | |
6810 | + DPRINT_EXIT(VMBUS_DRV); | |
6811 | + return; | |
6812 | + } | |
6813 | + | |
6814 | + driver_ctx = driver_to_driver_context(child_device->driver); | |
6815 | + | |
6816 | + // Let the specific open-source driver handles the removal if it can | |
6817 | + if (driver_ctx->shutdown) | |
6818 | + { | |
6819 | + driver_ctx->shutdown(child_device); | |
6820 | + } | |
6821 | + | |
6822 | + DPRINT_EXIT(VMBUS_DRV); | |
6823 | + | |
6824 | + return; | |
6825 | +} | |
6826 | + | |
6827 | +/*++ | |
6828 | + | |
6829 | +Name: vmbus_bus_release() | |
6830 | + | |
6831 | +Desc: Final callback release of the vmbus root device | |
6832 | + | |
6833 | +--*/ | |
6834 | +static void vmbus_bus_release(struct device *device) | |
6835 | +{ | |
6836 | + DPRINT_ENTER(VMBUS_DRV); | |
6837 | + DPRINT_EXIT(VMBUS_DRV); | |
6838 | +} | |
6839 | + | |
6840 | +/*++ | |
6841 | + | |
6842 | +Name: vmbus_device_release() | |
6843 | + | |
6844 | +Desc: Final callback release of the vmbus child device | |
6845 | + | |
6846 | +--*/ | |
6847 | +static void vmbus_device_release(struct device *device) | |
6848 | +{ | |
6849 | + struct device_context *device_ctx = device_to_device_context(device); | |
6850 | + | |
6851 | + DPRINT_ENTER(VMBUS_DRV); | |
6852 | + | |
6853 | + //vmbus_child_device_destroy(&device_ctx->device_obj); | |
6854 | + kfree(device_ctx); | |
6855 | + | |
6856 | + // !!DO NOT REFERENCE device_ctx anymore at this point!! | |
6857 | + | |
6858 | + DPRINT_EXIT(VMBUS_DRV); | |
6859 | + | |
6860 | + return; | |
6861 | +} | |
6862 | + | |
6863 | +/*++ | |
6864 | + | |
6865 | +Name: vmbus_msg_dpc() | |
6866 | + | |
6867 | +Desc: Tasklet routine to handle hypervisor messages | |
6868 | + | |
6869 | +--*/ | |
6870 | +static void vmbus_msg_dpc(unsigned long data) | |
6871 | +{ | |
6872 | + VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data; | |
6873 | + | |
6874 | + DPRINT_ENTER(VMBUS_DRV); | |
6875 | + | |
6876 | + ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); | |
6877 | + | |
6878 | + // Call to bus driver to handle interrupt | |
6879 | + vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base); | |
6880 | + | |
6881 | + DPRINT_EXIT(VMBUS_DRV); | |
6882 | +} | |
6883 | + | |
6884 | +/*++ | |
6885 | + | |
6886 | +Name: vmbus_msg_dpc() | |
6887 | + | |
6888 | +Desc: Tasklet routine to handle hypervisor events | |
6889 | + | |
6890 | +--*/ | |
6891 | +static void vmbus_event_dpc(unsigned long data) | |
6892 | +{ | |
6893 | + VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data; | |
6894 | + | |
6895 | + DPRINT_ENTER(VMBUS_DRV); | |
6896 | + | |
6897 | + ASSERT(vmbus_drv_obj->OnEventDpc != NULL); | |
6898 | + | |
6899 | + // Call to bus driver to handle interrupt | |
6900 | + vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base); | |
6901 | + | |
6902 | + DPRINT_EXIT(VMBUS_DRV); | |
6903 | +} | |
6904 | + | |
6905 | +/*++ | |
6906 | + | |
6907 | +Name: vmbus_msg_dpc() | |
6908 | + | |
6909 | +Desc: ISR routine | |
6910 | + | |
6911 | +--*/ | |
6912 | +#ifdef KERNEL_2_6_27 | |
6913 | +static irqreturn_t vmbus_isr(int irq, void* dev_id) | |
6914 | +#else | |
6915 | +static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs) | |
6916 | +#endif | |
6917 | +{ | |
6918 | + int ret=0; | |
6919 | + VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj; | |
6920 | + | |
6921 | + DPRINT_ENTER(VMBUS_DRV); | |
6922 | + | |
6923 | + ASSERT(vmbus_driver_obj->OnIsr != NULL); | |
6924 | + | |
6925 | + // Call to bus driver to handle interrupt | |
6926 | + ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base); | |
6927 | + | |
6928 | + // Schedules a dpc if necessary | |
6929 | + if (ret > 0) | |
6930 | + { | |
6931 | + if (test_bit(0, (unsigned long*)&ret)) | |
6932 | + { | |
6933 | + tasklet_schedule(&g_vmbus_drv.msg_dpc); | |
6934 | + } | |
6935 | + | |
6936 | + if (test_bit(1, (unsigned long*)&ret)) | |
6937 | + { | |
6938 | + tasklet_schedule(&g_vmbus_drv.event_dpc); | |
6939 | + } | |
6940 | + | |
6941 | + DPRINT_EXIT(VMBUS_DRV); | |
6942 | + return IRQ_HANDLED; | |
6943 | + } | |
6944 | + else | |
6945 | + { | |
6946 | + DPRINT_EXIT(VMBUS_DRV); | |
6947 | + return IRQ_NONE; | |
6948 | + } | |
6949 | +} | |
6950 | + | |
6951 | +MODULE_LICENSE("GPL"); | |
6952 | + | |
6953 | + | |
6954 | +/*++ | |
6955 | + | |
6956 | +Name: vmbus_init() | |
6957 | + | |
6958 | +Desc: Main vmbus driver entry routine | |
6959 | + | |
6960 | +--*/ | |
6961 | +static int __init vmbus_init(void) | |
6962 | +{ | |
6963 | + int ret=0; | |
6964 | + | |
6965 | + DPRINT_ENTER(VMBUS_DRV); | |
6966 | + | |
6967 | + DPRINT_INFO(VMBUS_DRV, | |
6968 | + "Vmbus initializing.... current log level 0x%x (%x,%x)", | |
6969 | + vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel)); | |
6970 | +#ifdef KERNEL_2_6_27 | |
6971 | +//Todo: it is used for loglevel, to be ported to new kernel. | |
6972 | +#else | |
6973 | + vmbus_ctl_table_hdr = register_sysctl_table(vmus_root_ctl_table, 0); | |
6974 | + if (!vmbus_ctl_table_hdr) | |
6975 | + { | |
6976 | + DPRINT_EXIT(VMBUS_DRV); | |
6977 | + return -ENOMEM; | |
6978 | + } | |
6979 | +#endif | |
6980 | + | |
6981 | + ret = vmbus_bus_init(VmbusInitialize); | |
6982 | + | |
6983 | + DPRINT_EXIT(VMBUS_DRV); | |
6984 | + return ret; | |
6985 | +} | |
6986 | + | |
6987 | + | |
6988 | + | |
6989 | +/*++ | |
6990 | + | |
6991 | +Name: vmbus_init() | |
6992 | + | |
6993 | +Desc: Main vmbus driver exit routine | |
6994 | + | |
6995 | +--*/ | |
6996 | +static void __exit vmbus_exit(void) | |
6997 | +{ | |
6998 | + DPRINT_ENTER(VMBUS_DRV); | |
6999 | + | |
7000 | + vmbus_bus_exit(); | |
7001 | +#ifdef KERNEL_2_6_27 | |
7002 | +//Todo: it is used for loglevel, to be ported to new kernel. | |
7003 | +#else | |
7004 | + unregister_sysctl_table(vmbus_ctl_table_hdr); | |
7005 | +#endif | |
7006 | + DPRINT_EXIT(VMBUS_DRV); | |
7007 | + | |
7008 | + return; | |
7009 | +} | |
7010 | + | |
7011 | +#if defined(KERNEL_2_6_5) | |
7012 | +#else | |
7013 | +module_param(vmbus_irq, int, S_IRUGO); | |
7014 | +module_param(vmbus_loglevel, int, S_IRUGO); | |
7015 | +#endif | |
7016 | + | |
7017 | +module_init(vmbus_init); | |
7018 | +module_exit(vmbus_exit); | |
7019 | +// eof | |
7020 | --- /dev/null | |
7021 | +++ b/drivers/staging/hv/VmbusPrivate.h | |
7022 | @@ -0,0 +1,170 @@ | |
7023 | +/* | |
7024 | + * | |
7025 | + * Copyright (c) 2009, Microsoft Corporation. | |
7026 | + * | |
7027 | + * This program is free software; you can redistribute it and/or modify it | |
7028 | + * under the terms and conditions of the GNU General Public License, | |
7029 | + * version 2, as published by the Free Software Foundation. | |
7030 | + * | |
7031 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
7032 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
7033 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
7034 | + * more details. | |
7035 | + * | |
7036 | + * You should have received a copy of the GNU General Public License along with | |
7037 | + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
7038 | + * Place - Suite 330, Boston, MA 02111-1307 USA. | |
7039 | + * | |
7040 | + * Authors: | |
7041 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
7042 | + * Hank Janssen <hjanssen@microsoft.com> | |
7043 | + * | |
7044 | + */ | |
7045 | + | |
7046 | + | |
7047 | +#ifndef _VMBUS_PRIVATE_H_ | |
7048 | +#define _VMBUS_PRIVATE_H_ | |
7049 | + | |
7050 | +#ifndef INTERNAL | |
7051 | +#define INTERNAL static | |
7052 | +#endif | |
7053 | + | |
7054 | +#include "Hv.h" | |
7055 | +#include "VmbusApi.h" | |
7056 | +#include "Channel.h" | |
7057 | +#include "ChannelMgmt.h" | |
7058 | +#include "ChannelInterface.h" | |
7059 | +//#include "ChannelMessages.h" | |
7060 | +#include "RingBuffer.h" | |
7061 | +//#include "Packet.h" | |
7062 | +#include "List.h" | |
7063 | + | |
7064 | +// | |
7065 | +// Defines | |
7066 | +// | |
7067 | + | |
7068 | +// Maximum channels is determined by the size of the interrupt page which is PAGE_SIZE. 1/2 of PAGE_SIZE is for | |
7069 | +// send endpoint interrupt and the other is receive endpoint interrupt | |
7070 | +#define MAX_NUM_CHANNELS (PAGE_SIZE >> 1) << 3 // 16348 channels | |
7071 | + | |
7072 | +// The value here must be in multiple of 32 | |
7073 | +// TODO: Need to make this configurable | |
7074 | +#define MAX_NUM_CHANNELS_SUPPORTED 256 | |
7075 | + | |
7076 | +// | |
7077 | +// Data types | |
7078 | +// | |
7079 | + | |
7080 | +typedef enum { | |
7081 | + Disconnected, | |
7082 | + Connecting, | |
7083 | + Connected, | |
7084 | + Disconnecting | |
7085 | +} VMBUS_CONNECT_STATE; | |
7086 | + | |
7087 | +#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT | |
7088 | + | |
7089 | +typedef struct _VMBUS_CONNECTION { | |
7090 | + | |
7091 | + VMBUS_CONNECT_STATE ConnectState; | |
7092 | + | |
7093 | + UINT32 NextGpadlHandle; | |
7094 | + | |
7095 | + // Represents channel interrupts. Each bit position | |
7096 | + // represents a channel. | |
7097 | + // When a channel sends an interrupt via VMBUS, it | |
7098 | + // finds its bit in the sendInterruptPage, set it and | |
7099 | + // calls Hv to generate a port event. The other end | |
7100 | + // receives the port event and parse the recvInterruptPage | |
7101 | + // to see which bit is set | |
7102 | + VOID* InterruptPage; | |
7103 | + VOID* SendInterruptPage; | |
7104 | + VOID* RecvInterruptPage; | |
7105 | + | |
7106 | + // 2 pages - 1st page for parent->child notification and 2nd is child->parent notification | |
7107 | + VOID* MonitorPages; | |
7108 | + LIST_ENTRY ChannelMsgList; | |
7109 | + HANDLE ChannelMsgLock; | |
7110 | + | |
7111 | + // List of channels | |
7112 | + LIST_ENTRY ChannelList; | |
7113 | + HANDLE ChannelLock; | |
7114 | + | |
7115 | + HANDLE WorkQueue; | |
7116 | +} VMBUS_CONNECTION; | |
7117 | + | |
7118 | + | |
7119 | +typedef struct _VMBUS_MSGINFO { | |
7120 | + // Bookkeeping stuff | |
7121 | + LIST_ENTRY MsgListEntry; | |
7122 | + | |
7123 | + // Synchronize the request/response if needed | |
7124 | + HANDLE WaitEvent; | |
7125 | + | |
7126 | + // The message itself | |
7127 | + unsigned char Msg[0]; | |
7128 | +} VMBUS_MSGINFO; | |
7129 | + | |
7130 | + | |
7131 | +// | |
7132 | +// Externs | |
7133 | +// | |
7134 | +extern VMBUS_CONNECTION gVmbusConnection; | |
7135 | + | |
7136 | +// | |
7137 | +// General vmbus interface | |
7138 | +// | |
7139 | +INTERNAL DEVICE_OBJECT* | |
7140 | +VmbusChildDeviceCreate( | |
7141 | + GUID deviceType, | |
7142 | + GUID deviceInstance, | |
7143 | + void *context); | |
7144 | + | |
7145 | +INTERNAL int | |
7146 | +VmbusChildDeviceAdd( | |
7147 | + DEVICE_OBJECT* Device); | |
7148 | + | |
7149 | +INTERNAL void | |
7150 | +VmbusChildDeviceRemove( | |
7151 | + DEVICE_OBJECT* Device); | |
7152 | + | |
7153 | +//INTERNAL void | |
7154 | +//VmbusChildDeviceDestroy( | |
7155 | +// DEVICE_OBJECT*); | |
7156 | + | |
7157 | +INTERNAL VMBUS_CHANNEL* | |
7158 | +GetChannelFromRelId( | |
7159 | + UINT32 relId | |
7160 | + ); | |
7161 | + | |
7162 | +// | |
7163 | +// Connection interface | |
7164 | +// | |
7165 | +INTERNAL int | |
7166 | +VmbusConnect( | |
7167 | + VOID | |
7168 | + ); | |
7169 | + | |
7170 | +INTERNAL int | |
7171 | +VmbusDisconnect( | |
7172 | + VOID | |
7173 | + ); | |
7174 | + | |
7175 | +INTERNAL int | |
7176 | +VmbusPostMessage( | |
7177 | + PVOID buffer, | |
7178 | + SIZE_T bufSize | |
7179 | + ); | |
7180 | + | |
7181 | +INTERNAL int | |
7182 | +VmbusSetEvent( | |
7183 | + UINT32 childRelId | |
7184 | + ); | |
7185 | + | |
7186 | +INTERNAL VOID | |
7187 | +VmbusOnEvents( | |
7188 | + VOID | |
7189 | + ); | |
7190 | + | |
7191 | + | |
7192 | +#endif // _VMBUS_PRIVATE_H_ |