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