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