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