linux/drivers/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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  22
  23#include <linux/kernel.h>
  24#include <linux/sched.h>
  25#include <linux/wait.h>
  26#include <linux/mm.h>
  27#include <linux/slab.h>
  28#include <linux/module.h>
  29#include <linux/hyperv.h>
  30
  31#include "hyperv_vmbus.h"
  32
  33#define NUM_PAGES_SPANNED(addr, len) \
  34((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT))
  35
  36/*
  37 * vmbus_setevent- Trigger an event notification on the specified
  38 * channel.
  39 */
  40static void vmbus_setevent(struct vmbus_channel *channel)
  41{
  42        struct hv_monitor_page *monitorpage;
  43
  44        if (channel->offermsg.monitor_allocated) {
  45                /* Each u32 represents 32 channels */
  46                sync_set_bit(channel->offermsg.child_relid & 31,
  47                        (unsigned long *) vmbus_connection.send_int_page +
  48                        (channel->offermsg.child_relid >> 5));
  49
  50                monitorpage = vmbus_connection.monitor_pages;
  51                monitorpage++; /* Get the child to parent monitor page */
  52
  53                sync_set_bit(channel->monitor_bit,
  54                        (unsigned long *)&monitorpage->trigger_group
  55                                        [channel->monitor_grp].pending);
  56
  57        } else {
  58                vmbus_set_event(channel->offermsg.child_relid);
  59        }
  60}
  61
  62/*
  63 * vmbus_get_debug_info -Retrieve various channel debug info
  64 */
  65void vmbus_get_debug_info(struct vmbus_channel *channel,
  66                              struct vmbus_channel_debug_info *debuginfo)
  67{
  68        struct hv_monitor_page *monitorpage;
  69        u8 monitor_group = (u8)channel->offermsg.monitorid / 32;
  70        u8 monitor_offset = (u8)channel->offermsg.monitorid % 32;
  71
  72        debuginfo->relid = channel->offermsg.child_relid;
  73        debuginfo->state = channel->state;
  74        memcpy(&debuginfo->interfacetype,
  75               &channel->offermsg.offer.if_type, sizeof(uuid_le));
  76        memcpy(&debuginfo->interface_instance,
  77               &channel->offermsg.offer.if_instance,
  78               sizeof(uuid_le));
  79
  80        monitorpage = (struct hv_monitor_page *)vmbus_connection.monitor_pages;
  81
  82        debuginfo->monitorid = channel->offermsg.monitorid;
  83
  84        debuginfo->servermonitor_pending =
  85                        monitorpage->trigger_group[monitor_group].pending;
  86        debuginfo->servermonitor_latency =
  87                        monitorpage->latency[monitor_group][monitor_offset];
  88        debuginfo->servermonitor_connectionid =
  89                        monitorpage->parameter[monitor_group]
  90                                        [monitor_offset].connectionid.u.id;
  91
  92        monitorpage++;
  93
  94        debuginfo->clientmonitor_pending =
  95                        monitorpage->trigger_group[monitor_group].pending;
  96        debuginfo->clientmonitor_latency =
  97                        monitorpage->latency[monitor_group][monitor_offset];
  98        debuginfo->clientmonitor_connectionid =
  99                        monitorpage->parameter[monitor_group]
 100                                        [monitor_offset].connectionid.u.id;
 101
 102        hv_ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound);
 103        hv_ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound);
 104}
 105
 106/*
 107 * vmbus_open - Open the specified channel.
 108 */
 109int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
 110                     u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
 111                     void (*onchannelcallback)(void *context), void *context)
 112{
 113        struct vmbus_channel_open_channel *open_msg;
 114        struct vmbus_channel_msginfo *open_info = NULL;
 115        void *in, *out;
 116        unsigned long flags;
 117        int ret, t, err = 0;
 118
 119        newchannel->onchannel_callback = onchannelcallback;
 120        newchannel->channel_callback_context = context;
 121
 122        /* Allocate the ring buffer */
 123        out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
 124                get_order(send_ringbuffer_size + recv_ringbuffer_size));
 125
 126        if (!out)
 127                return -ENOMEM;
 128
 129
 130        in = (void *)((unsigned long)out + send_ringbuffer_size);
 131
 132        newchannel->ringbuffer_pages = out;
 133        newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
 134                                           recv_ringbuffer_size) >> PAGE_SHIFT;
 135
 136        ret = hv_ringbuffer_init(
 137                &newchannel->outbound, out, send_ringbuffer_size);
 138
 139        if (ret != 0) {
 140                err = ret;
 141                goto error0;
 142        }
 143
 144        ret = hv_ringbuffer_init(
 145                &newchannel->inbound, in, recv_ringbuffer_size);
 146        if (ret != 0) {
 147                err = ret;
 148                goto error0;
 149        }
 150
 151
 152        /* Establish the gpadl for the ring buffer */
 153        newchannel->ringbuffer_gpadlhandle = 0;
 154
 155        ret = vmbus_establish_gpadl(newchannel,
 156                                         newchannel->outbound.ring_buffer,
 157                                         send_ringbuffer_size +
 158                                         recv_ringbuffer_size,
 159                                         &newchannel->ringbuffer_gpadlhandle);
 160
 161        if (ret != 0) {
 162                err = ret;
 163                goto error0;
 164        }
 165
 166        /* Create and init the channel open message */
 167        open_info = kmalloc(sizeof(*open_info) +
 168                           sizeof(struct vmbus_channel_open_channel),
 169                           GFP_KERNEL);
 170        if (!open_info) {
 171                err = -ENOMEM;
 172                goto error0;
 173        }
 174
 175        init_completion(&open_info->waitevent);
 176
 177        open_msg = (struct vmbus_channel_open_channel *)open_info->msg;
 178        open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL;
 179        open_msg->openid = newchannel->offermsg.child_relid;
 180        open_msg->child_relid = newchannel->offermsg.child_relid;
 181        open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle;
 182        open_msg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >>
 183                                                  PAGE_SHIFT;
 184        open_msg->server_contextarea_gpadlhandle = 0;
 185
 186        if (userdatalen > MAX_USER_DEFINED_BYTES) {
 187                err = -EINVAL;
 188                goto error0;
 189        }
 190
 191        if (userdatalen)
 192                memcpy(open_msg->userdata, userdata, userdatalen);
 193
 194        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 195        list_add_tail(&open_info->msglistentry,
 196                      &vmbus_connection.chn_msg_list);
 197        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 198
 199        ret = vmbus_post_msg(open_msg,
 200                               sizeof(struct vmbus_channel_open_channel));
 201
 202        if (ret != 0)
 203                goto error1;
 204
 205        t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
 206        if (t == 0) {
 207                err = -ETIMEDOUT;
 208                goto error1;
 209        }
 210
 211
 212        if (open_info->response.open_result.status)
 213                err = open_info->response.open_result.status;
 214
 215        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 216        list_del(&open_info->msglistentry);
 217        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 218
 219        kfree(open_info);
 220        return err;
 221
 222error1:
 223        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 224        list_del(&open_info->msglistentry);
 225        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 226
 227error0:
 228        free_pages((unsigned long)out,
 229                get_order(send_ringbuffer_size + recv_ringbuffer_size));
 230        kfree(open_info);
 231        return err;
 232}
 233EXPORT_SYMBOL_GPL(vmbus_open);
 234
 235/*
 236 * create_gpadl_header - Creates a gpadl for the specified buffer
 237 */
 238static int create_gpadl_header(void *kbuffer, u32 size,
 239                                         struct vmbus_channel_msginfo **msginfo,
 240                                         u32 *messagecount)
 241{
 242        int i;
 243        int pagecount;
 244        unsigned long long pfn;
 245        struct vmbus_channel_gpadl_header *gpadl_header;
 246        struct vmbus_channel_gpadl_body *gpadl_body;
 247        struct vmbus_channel_msginfo *msgheader;
 248        struct vmbus_channel_msginfo *msgbody = NULL;
 249        u32 msgsize;
 250
 251        int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
 252
 253        pagecount = size >> PAGE_SHIFT;
 254        pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
 255
 256        /* do we need a gpadl body msg */
 257        pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
 258                  sizeof(struct vmbus_channel_gpadl_header) -
 259                  sizeof(struct gpa_range);
 260        pfncount = pfnsize / sizeof(u64);
 261
 262        if (pagecount > pfncount) {
 263                /* we need a gpadl body */
 264                /* fill in the header */
 265                msgsize = sizeof(struct vmbus_channel_msginfo) +
 266                          sizeof(struct vmbus_channel_gpadl_header) +
 267                          sizeof(struct gpa_range) + pfncount * sizeof(u64);
 268                msgheader =  kzalloc(msgsize, GFP_KERNEL);
 269                if (!msgheader)
 270                        goto nomem;
 271
 272                INIT_LIST_HEAD(&msgheader->submsglist);
 273                msgheader->msgsize = msgsize;
 274
 275                gpadl_header = (struct vmbus_channel_gpadl_header *)
 276                        msgheader->msg;
 277                gpadl_header->rangecount = 1;
 278                gpadl_header->range_buflen = sizeof(struct gpa_range) +
 279                                         pagecount * sizeof(u64);
 280                gpadl_header->range[0].byte_offset = 0;
 281                gpadl_header->range[0].byte_count = size;
 282                for (i = 0; i < pfncount; i++)
 283                        gpadl_header->range[0].pfn_array[i] = pfn+i;
 284                *msginfo = msgheader;
 285                *messagecount = 1;
 286
 287                pfnsum = pfncount;
 288                pfnleft = pagecount - pfncount;
 289
 290                /* how many pfns can we fit */
 291                pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
 292                          sizeof(struct vmbus_channel_gpadl_body);
 293                pfncount = pfnsize / sizeof(u64);
 294
 295                /* fill in the body */
 296                while (pfnleft) {
 297                        if (pfnleft > pfncount)
 298                                pfncurr = pfncount;
 299                        else
 300                                pfncurr = pfnleft;
 301
 302                        msgsize = sizeof(struct vmbus_channel_msginfo) +
 303                                  sizeof(struct vmbus_channel_gpadl_body) +
 304                                  pfncurr * sizeof(u64);
 305                        msgbody = kzalloc(msgsize, GFP_KERNEL);
 306
 307                        if (!msgbody) {
 308                                struct vmbus_channel_msginfo *pos = NULL;
 309                                struct vmbus_channel_msginfo *tmp = NULL;
 310                                /*
 311                                 * Free up all the allocated messages.
 312                                 */
 313                                list_for_each_entry_safe(pos, tmp,
 314                                        &msgheader->submsglist,
 315                                        msglistentry) {
 316
 317                                        list_del(&pos->msglistentry);
 318                                        kfree(pos);
 319                                }
 320
 321                                goto nomem;
 322                        }
 323
 324                        msgbody->msgsize = msgsize;
 325                        (*messagecount)++;
 326                        gpadl_body =
 327                                (struct vmbus_channel_gpadl_body *)msgbody->msg;
 328
 329                        /*
 330                         * Gpadl is u32 and we are using a pointer which could
 331                         * be 64-bit
 332                         * This is governed by the guest/host protocol and
 333                         * so the hypervisor gurantees that this is ok.
 334                         */
 335                        for (i = 0; i < pfncurr; i++)
 336                                gpadl_body->pfn[i] = pfn + pfnsum + i;
 337
 338                        /* add to msg header */
 339                        list_add_tail(&msgbody->msglistentry,
 340                                      &msgheader->submsglist);
 341                        pfnsum += pfncurr;
 342                        pfnleft -= pfncurr;
 343                }
 344        } else {
 345                /* everything fits in a header */
 346                msgsize = sizeof(struct vmbus_channel_msginfo) +
 347                          sizeof(struct vmbus_channel_gpadl_header) +
 348                          sizeof(struct gpa_range) + pagecount * sizeof(u64);
 349                msgheader = kzalloc(msgsize, GFP_KERNEL);
 350                if (msgheader == NULL)
 351                        goto nomem;
 352                msgheader->msgsize = msgsize;
 353
 354                gpadl_header = (struct vmbus_channel_gpadl_header *)
 355                        msgheader->msg;
 356                gpadl_header->rangecount = 1;
 357                gpadl_header->range_buflen = sizeof(struct gpa_range) +
 358                                         pagecount * sizeof(u64);
 359                gpadl_header->range[0].byte_offset = 0;
 360                gpadl_header->range[0].byte_count = size;
 361                for (i = 0; i < pagecount; i++)
 362                        gpadl_header->range[0].pfn_array[i] = pfn+i;
 363
 364                *msginfo = msgheader;
 365                *messagecount = 1;
 366        }
 367
 368        return 0;
 369nomem:
 370        kfree(msgheader);
 371        kfree(msgbody);
 372        return -ENOMEM;
 373}
 374
 375/*
 376 * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer
 377 *
 378 * @channel: a channel
 379 * @kbuffer: from kmalloc
 380 * @size: page-size multiple
 381 * @gpadl_handle: some funky thing
 382 */
 383int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
 384                               u32 size, u32 *gpadl_handle)
 385{
 386        struct vmbus_channel_gpadl_header *gpadlmsg;
 387        struct vmbus_channel_gpadl_body *gpadl_body;
 388        struct vmbus_channel_msginfo *msginfo = NULL;
 389        struct vmbus_channel_msginfo *submsginfo;
 390        u32 msgcount;
 391        struct list_head *curr;
 392        u32 next_gpadl_handle;
 393        unsigned long flags;
 394        int ret = 0;
 395        int t;
 396
 397        next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
 398        atomic_inc(&vmbus_connection.next_gpadl_handle);
 399
 400        ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
 401        if (ret)
 402                return ret;
 403
 404        init_completion(&msginfo->waitevent);
 405
 406        gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
 407        gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
 408        gpadlmsg->child_relid = channel->offermsg.child_relid;
 409        gpadlmsg->gpadl = next_gpadl_handle;
 410
 411
 412        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 413        list_add_tail(&msginfo->msglistentry,
 414                      &vmbus_connection.chn_msg_list);
 415
 416        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 417
 418        ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
 419                               sizeof(*msginfo));
 420        if (ret != 0)
 421                goto cleanup;
 422
 423        if (msgcount > 1) {
 424                list_for_each(curr, &msginfo->submsglist) {
 425
 426                        submsginfo = (struct vmbus_channel_msginfo *)curr;
 427                        gpadl_body =
 428                             (struct vmbus_channel_gpadl_body *)submsginfo->msg;
 429
 430                        gpadl_body->header.msgtype =
 431                                CHANNELMSG_GPADL_BODY;
 432                        gpadl_body->gpadl = next_gpadl_handle;
 433
 434                        ret = vmbus_post_msg(gpadl_body,
 435                                               submsginfo->msgsize -
 436                                               sizeof(*submsginfo));
 437                        if (ret != 0)
 438                                goto cleanup;
 439
 440                }
 441        }
 442        t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
 443        BUG_ON(t == 0);
 444
 445
 446        /* At this point, we received the gpadl created msg */
 447        *gpadl_handle = gpadlmsg->gpadl;
 448
 449cleanup:
 450        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 451        list_del(&msginfo->msglistentry);
 452        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 453
 454        kfree(msginfo);
 455        return ret;
 456}
 457EXPORT_SYMBOL_GPL(vmbus_establish_gpadl);
 458
 459/*
 460 * vmbus_teardown_gpadl -Teardown the specified GPADL handle
 461 */
 462int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
 463{
 464        struct vmbus_channel_gpadl_teardown *msg;
 465        struct vmbus_channel_msginfo *info;
 466        unsigned long flags;
 467        int ret, t;
 468
 469        info = kmalloc(sizeof(*info) +
 470                       sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
 471        if (!info)
 472                return -ENOMEM;
 473
 474        init_completion(&info->waitevent);
 475
 476        msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
 477
 478        msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN;
 479        msg->child_relid = channel->offermsg.child_relid;
 480        msg->gpadl = gpadl_handle;
 481
 482        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 483        list_add_tail(&info->msglistentry,
 484                      &vmbus_connection.chn_msg_list);
 485        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 486        ret = vmbus_post_msg(msg,
 487                               sizeof(struct vmbus_channel_gpadl_teardown));
 488
 489        BUG_ON(ret != 0);
 490        t = wait_for_completion_timeout(&info->waitevent, 5*HZ);
 491        BUG_ON(t == 0);
 492
 493        /* Received a torndown response */
 494        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
 495        list_del(&info->msglistentry);
 496        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 497
 498        kfree(info);
 499        return ret;
 500}
 501EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
 502
 503/*
 504 * vmbus_close - Close the specified channel
 505 */
 506void vmbus_close(struct vmbus_channel *channel)
 507{
 508        struct vmbus_channel_close_channel *msg;
 509        int ret;
 510        unsigned long flags;
 511
 512        /* Stop callback and cancel the timer asap */
 513        spin_lock_irqsave(&channel->inbound_lock, flags);
 514        channel->onchannel_callback = NULL;
 515        spin_unlock_irqrestore(&channel->inbound_lock, flags);
 516
 517        /* Send a closing message */
 518
 519        msg = &channel->close_msg.msg;
 520
 521        msg->header.msgtype = CHANNELMSG_CLOSECHANNEL;
 522        msg->child_relid = channel->offermsg.child_relid;
 523
 524        ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
 525
 526        BUG_ON(ret != 0);
 527        /* Tear down the gpadl for the channel's ring buffer */
 528        if (channel->ringbuffer_gpadlhandle)
 529                vmbus_teardown_gpadl(channel,
 530                                          channel->ringbuffer_gpadlhandle);
 531
 532        /* Cleanup the ring buffers for this channel */
 533        hv_ringbuffer_cleanup(&channel->outbound);
 534        hv_ringbuffer_cleanup(&channel->inbound);
 535
 536        free_pages((unsigned long)channel->ringbuffer_pages,
 537                get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
 538
 539
 540}
 541EXPORT_SYMBOL_GPL(vmbus_close);
 542
 543/**
 544 * vmbus_sendpacket() - Send the specified buffer on the given channel
 545 * @channel: Pointer to vmbus_channel structure.
 546 * @buffer: Pointer to the buffer you want to receive the data into.
 547 * @bufferlen: Maximum size of what the the buffer will hold
 548 * @requestid: Identifier of the request
 549 * @type: Type of packet that is being send e.g. negotiate, time
 550 * packet etc.
 551 *
 552 * Sends data in @buffer directly to hyper-v via the vmbus
 553 * This will send the data unparsed to hyper-v.
 554 *
 555 * Mainly used by Hyper-V drivers.
 556 */
 557int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
 558                           u32 bufferlen, u64 requestid,
 559                           enum vmbus_packet_type type, u32 flags)
 560{
 561        struct vmpacket_descriptor desc;
 562        u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
 563        u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
 564        struct scatterlist bufferlist[3];
 565        u64 aligned_data = 0;
 566        int ret;
 567
 568
 569        /* Setup the descriptor */
 570        desc.type = type; /* VmbusPacketTypeDataInBand; */
 571        desc.flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
 572        /* in 8-bytes granularity */
 573        desc.offset8 = sizeof(struct vmpacket_descriptor) >> 3;
 574        desc.len8 = (u16)(packetlen_aligned >> 3);
 575        desc.trans_id = requestid;
 576
 577        sg_init_table(bufferlist, 3);
 578        sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
 579        sg_set_buf(&bufferlist[1], buffer, bufferlen);
 580        sg_set_buf(&bufferlist[2], &aligned_data,
 581                   packetlen_aligned - packetlen);
 582
 583        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
 584
 585        if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
 586                vmbus_setevent(channel);
 587
 588        return ret;
 589}
 590EXPORT_SYMBOL(vmbus_sendpacket);
 591
 592/*
 593 * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer
 594 * packets using a GPADL Direct packet type.
 595 */
 596int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
 597                                     struct hv_page_buffer pagebuffers[],
 598                                     u32 pagecount, void *buffer, u32 bufferlen,
 599                                     u64 requestid)
 600{
 601        int ret;
 602        int i;
 603        struct vmbus_channel_packet_page_buffer desc;
 604        u32 descsize;
 605        u32 packetlen;
 606        u32 packetlen_aligned;
 607        struct scatterlist bufferlist[3];
 608        u64 aligned_data = 0;
 609
 610        if (pagecount > MAX_PAGE_BUFFER_COUNT)
 611                return -EINVAL;
 612
 613
 614        /*
 615         * Adjust the size down since vmbus_channel_packet_page_buffer is the
 616         * largest size we support
 617         */
 618        descsize = sizeof(struct vmbus_channel_packet_page_buffer) -
 619                          ((MAX_PAGE_BUFFER_COUNT - pagecount) *
 620                          sizeof(struct hv_page_buffer));
 621        packetlen = descsize + bufferlen;
 622        packetlen_aligned = ALIGN(packetlen, sizeof(u64));
 623
 624        /* Setup the descriptor */
 625        desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
 626        desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
 627        desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
 628        desc.length8 = (u16)(packetlen_aligned >> 3);
 629        desc.transactionid = requestid;
 630        desc.rangecount = pagecount;
 631
 632        for (i = 0; i < pagecount; i++) {
 633                desc.range[i].len = pagebuffers[i].len;
 634                desc.range[i].offset = pagebuffers[i].offset;
 635                desc.range[i].pfn        = pagebuffers[i].pfn;
 636        }
 637
 638        sg_init_table(bufferlist, 3);
 639        sg_set_buf(&bufferlist[0], &desc, descsize);
 640        sg_set_buf(&bufferlist[1], buffer, bufferlen);
 641        sg_set_buf(&bufferlist[2], &aligned_data,
 642                packetlen_aligned - packetlen);
 643
 644        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
 645
 646        if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
 647                vmbus_setevent(channel);
 648
 649        return ret;
 650}
 651EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
 652
 653/*
 654 * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
 655 * using a GPADL Direct packet type.
 656 */
 657int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
 658                                struct hv_multipage_buffer *multi_pagebuffer,
 659                                void *buffer, u32 bufferlen, u64 requestid)
 660{
 661        int ret;
 662        struct vmbus_channel_packet_multipage_buffer desc;
 663        u32 descsize;
 664        u32 packetlen;
 665        u32 packetlen_aligned;
 666        struct scatterlist bufferlist[3];
 667        u64 aligned_data = 0;
 668        u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
 669                                         multi_pagebuffer->len);
 670
 671
 672        if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
 673                return -EINVAL;
 674
 675        /*
 676         * Adjust the size down since vmbus_channel_packet_multipage_buffer is
 677         * the largest size we support
 678         */
 679        descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) -
 680                          ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) *
 681                          sizeof(u64));
 682        packetlen = descsize + bufferlen;
 683        packetlen_aligned = ALIGN(packetlen, sizeof(u64));
 684
 685
 686        /* Setup the descriptor */
 687        desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
 688        desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
 689        desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
 690        desc.length8 = (u16)(packetlen_aligned >> 3);
 691        desc.transactionid = requestid;
 692        desc.rangecount = 1;
 693
 694        desc.range.len = multi_pagebuffer->len;
 695        desc.range.offset = multi_pagebuffer->offset;
 696
 697        memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
 698               pfncount * sizeof(u64));
 699
 700        sg_init_table(bufferlist, 3);
 701        sg_set_buf(&bufferlist[0], &desc, descsize);
 702        sg_set_buf(&bufferlist[1], buffer, bufferlen);
 703        sg_set_buf(&bufferlist[2], &aligned_data,
 704                packetlen_aligned - packetlen);
 705
 706        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3);
 707
 708        if (ret == 0 && !hv_get_ringbuffer_interrupt_mask(&channel->outbound))
 709                vmbus_setevent(channel);
 710
 711        return ret;
 712}
 713EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
 714
 715/**
 716 * vmbus_recvpacket() - Retrieve the user packet on the specified channel
 717 * @channel: Pointer to vmbus_channel structure.
 718 * @buffer: Pointer to the buffer you want to receive the data into.
 719 * @bufferlen: Maximum size of what the the buffer will hold
 720 * @buffer_actual_len: The actual size of the data after it was received
 721 * @requestid: Identifier of the request
 722 *
 723 * Receives directly from the hyper-v vmbus and puts the data it received
 724 * into Buffer. This will receive the data unparsed from hyper-v.
 725 *
 726 * Mainly used by Hyper-V drivers.
 727 */
 728int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
 729                        u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
 730{
 731        struct vmpacket_descriptor desc;
 732        u32 packetlen;
 733        u32 userlen;
 734        int ret;
 735
 736        *buffer_actual_len = 0;
 737        *requestid = 0;
 738
 739
 740        ret = hv_ringbuffer_peek(&channel->inbound, &desc,
 741                             sizeof(struct vmpacket_descriptor));
 742        if (ret != 0)
 743                return 0;
 744
 745        packetlen = desc.len8 << 3;
 746        userlen = packetlen - (desc.offset8 << 3);
 747
 748        *buffer_actual_len = userlen;
 749
 750        if (userlen > bufferlen) {
 751
 752                pr_err("Buffer too small - got %d needs %d\n",
 753                           bufferlen, userlen);
 754                return -ETOOSMALL;
 755        }
 756
 757        *requestid = desc.trans_id;
 758
 759        /* Copy over the packet to the user buffer */
 760        ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen,
 761                             (desc.offset8 << 3));
 762
 763
 764        return 0;
 765}
 766EXPORT_SYMBOL(vmbus_recvpacket);
 767
 768/*
 769 * vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel
 770 */
 771int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
 772                              u32 bufferlen, u32 *buffer_actual_len,
 773                              u64 *requestid)
 774{
 775        struct vmpacket_descriptor desc;
 776        u32 packetlen;
 777        u32 userlen;
 778        int ret;
 779
 780        *buffer_actual_len = 0;
 781        *requestid = 0;
 782
 783
 784        ret = hv_ringbuffer_peek(&channel->inbound, &desc,
 785                             sizeof(struct vmpacket_descriptor));
 786        if (ret != 0)
 787                return 0;
 788
 789
 790        packetlen = desc.len8 << 3;
 791        userlen = packetlen - (desc.offset8 << 3);
 792
 793        *buffer_actual_len = packetlen;
 794
 795        if (packetlen > bufferlen) {
 796                pr_err("Buffer too small - needed %d bytes but "
 797                        "got space for only %d bytes\n",
 798                        packetlen, bufferlen);
 799                return -ENOBUFS;
 800        }
 801
 802        *requestid = desc.trans_id;
 803
 804        /* Copy over the entire packet to the user buffer */
 805        ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
 806
 807        return 0;
 808}
 809EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
 810
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.