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