Staging: hv: Use native page allocation/free functions
[deliverable/linux.git] / drivers / staging / hv / channel.c
CommitLineData
3e7ee490 1/*
3e7ee490
HJ
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>
3e7ee490 20 */
5654e932 21#include <linux/kernel.h>
a0086dc5 22#include <linux/mm.h>
5a0e3ad6 23#include <linux/slab.h>
c88c4e4c 24#include <linux/module.h>
4983b39a 25#include "osd.h"
645954c5 26#include "logging.h"
72daf320 27#include "vmbus_private.h"
3e7ee490 28
454f18a9 29/* Internal routines */
fff41b2e 30static int create_gpadl_header(
39d70a4a
HZ
31 void *kbuffer, /* must be phys and virt contiguous */
32 u32 size, /* page-size multiple */
33 struct vmbus_channel_msginfo **msginfo,
34 u32 *messagecount);
fff41b2e
HZ
35static void dump_vmbus_channel(struct vmbus_channel *channel);
36static void vmbus_setevent(struct vmbus_channel *channel);
3e7ee490
HJ
37
38
39#if 0
f4266e34 40static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
3e7ee490 41{
f4266e34
GKH
42 int i = 0;
43 int j = 0;
3e7ee490 44
f4266e34 45 DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
f6feebe0 46 MonitorPage, MonitorPage->trigger_state);
3e7ee490 47
f4266e34
GKH
48 for (i = 0; i < 4; i++)
49 DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
f6feebe0 50 MonitorPage->trigger_group[i].as_uint64);
3e7ee490 51
f4266e34
GKH
52 for (i = 0; i < 4; i++) {
53 for (j = 0; j < 32; j++) {
54 DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
f6feebe0 55 MonitorPage->latency[i][j]);
3e7ee490
HJ
56 }
57 }
f4266e34
GKH
58 for (i = 0; i < 4; i++) {
59 for (j = 0; j < 32; j++) {
60 DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
f6feebe0 61 MonitorPage->parameter[i][j].connectionid.asu32);
f4266e34 62 DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
f6feebe0 63 MonitorPage->parameter[i][j].flag_number);
3e7ee490
HJ
64 }
65 }
66}
67#endif
68
3e189519 69/*
fff41b2e 70 * vmbus_setevent- Trigger an event notification on the specified
3e189519 71 * channel.
f4266e34 72 */
fff41b2e 73static void vmbus_setevent(struct vmbus_channel *channel)
3e7ee490 74{
39d70a4a 75 struct hv_monitor_page *monitorpage;
3e7ee490 76
c50f7fb2 77 if (channel->offermsg.monitor_allocated) {
454f18a9 78 /* Each u32 represents 32 channels */
c50f7fb2 79 set_bit(channel->offermsg.child_relid & 31,
da9fcb72 80 (unsigned long *) vmbus_connection.send_int_page +
c50f7fb2 81 (channel->offermsg.child_relid >> 5));
3e7ee490 82
da9fcb72 83 monitorpage = vmbus_connection.monitor_pages;
39d70a4a 84 monitorpage++; /* Get the child to parent monitor page */
3e7ee490 85
c50f7fb2 86 set_bit(channel->monitor_bit,
f6feebe0
HZ
87 (unsigned long *)&monitorpage->trigger_group
88 [channel->monitor_grp].pending);
7c369f40 89
f4266e34 90 } else {
c6977677 91 vmbus_set_event(channel->offermsg.child_relid);
3e7ee490 92 }
3e7ee490
HJ
93}
94
95#if 0
aded7165 96static void VmbusChannelClearEvent(struct vmbus_channel *channel)
3e7ee490 97{
eacb1b4d 98 struct hv_monitor_page *monitorPage;
3e7ee490 99
c50f7fb2 100 if (Channel->offermsg.monitor_allocated) {
454f18a9 101 /* Each u32 represents 32 channels */
c50f7fb2 102 clear_bit(Channel->offermsg.child_relid & 31,
da9fcb72 103 (unsigned long *)vmbus_connection.send_int_page +
c50f7fb2 104 (Channel->offermsg.child_relid >> 5));
3e7ee490 105
da9fcb72
HZ
106 monitorPage = (struct hv_monitor_page *)
107 vmbus_connection.monitor_pages;
454f18a9 108 monitorPage++; /* Get the child to parent monitor page */
3e7ee490 109
c50f7fb2 110 clear_bit(Channel->monitor_bit,
f6feebe0 111 (unsigned long *)&monitorPage->trigger_group
c50f7fb2 112 [Channel->monitor_grp].Pending);
3e7ee490 113 }
3e7ee490
HJ
114}
115
116#endif
3e189519 117/*
fff41b2e 118 * vmbus_get_debug_info -Retrieve various channel debug info
f4266e34 119 */
fff41b2e 120void vmbus_get_debug_info(struct vmbus_channel *channel,
39d70a4a 121 struct vmbus_channel_debug_info *debuginfo)
3e7ee490 122{
39d70a4a 123 struct hv_monitor_page *monitorpage;
c50f7fb2
HZ
124 u8 monitor_group = (u8)channel->offermsg.monitorid / 32;
125 u8 monitor_offset = (u8)channel->offermsg.monitorid % 32;
454f18a9 126 /* u32 monitorBit = 1 << monitorOffset; */
3e7ee490 127
c50f7fb2
HZ
128 debuginfo->relid = channel->offermsg.child_relid;
129 debuginfo->state = channel->state;
130 memcpy(&debuginfo->interfacetype,
767dff68 131 &channel->offermsg.offer.if_type, sizeof(struct hv_guid));
c50f7fb2 132 memcpy(&debuginfo->interface_instance,
767dff68 133 &channel->offermsg.offer.if_instance,
f4266e34 134 sizeof(struct hv_guid));
3e7ee490 135
da9fcb72 136 monitorpage = (struct hv_monitor_page *)vmbus_connection.monitor_pages;
3e7ee490 137
c50f7fb2 138 debuginfo->monitorid = channel->offermsg.monitorid;
3e7ee490 139
c50f7fb2 140 debuginfo->servermonitor_pending =
f6feebe0 141 monitorpage->trigger_group[monitor_group].pending;
c50f7fb2 142 debuginfo->servermonitor_latency =
f6feebe0 143 monitorpage->latency[monitor_group][monitor_offset];
c50f7fb2 144 debuginfo->servermonitor_connectionid =
f6feebe0
HZ
145 monitorpage->parameter[monitor_group]
146 [monitor_offset].connectionid.u.id;
3e7ee490 147
39d70a4a 148 monitorpage++;
3e7ee490 149
c50f7fb2 150 debuginfo->clientmonitor_pending =
f6feebe0 151 monitorpage->trigger_group[monitor_group].pending;
c50f7fb2 152 debuginfo->clientmonitor_latency =
f6feebe0 153 monitorpage->latency[monitor_group][monitor_offset];
c50f7fb2 154 debuginfo->clientmonitor_connectionid =
f6feebe0
HZ
155 monitorpage->parameter[monitor_group]
156 [monitor_offset].connectionid.u.id;
3e7ee490 157
1ac58644
HZ
158 ringbuffer_get_debuginfo(&channel->inbound, &debuginfo->inbound);
159 ringbuffer_get_debuginfo(&channel->outbound, &debuginfo->outbound);
3e7ee490
HJ
160}
161
3e189519 162/*
fff41b2e 163 * vmbus_open - Open the specified channel.
f4266e34 164 */
fff41b2e 165int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
39d70a4a
HZ
166 u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
167 void (*onchannelcallback)(void *context), void *context)
3e7ee490 168{
82250213 169 struct vmbus_channel_open_channel *openMsg;
b94ef345 170 struct vmbus_channel_msginfo *openInfo = NULL;
3e7ee490 171 void *in, *out;
dd0813b6 172 unsigned long flags;
c3bf2e26 173 int ret, err = 0;
3e7ee490 174
454f18a9 175 /* Aligned to page size */
0ace247e
BP
176 /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
177 /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
3e7ee490 178
c50f7fb2
HZ
179 newchannel->onchannel_callback = onchannelcallback;
180 newchannel->channel_callback_context = context;
3e7ee490 181
454f18a9 182 /* Allocate the ring buffer */
df3493e0
S
183 out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
184 get_order(send_ringbuffer_size + recv_ringbuffer_size));
185
7e052d98
BP
186 if (!out)
187 return -ENOMEM;
188
0ace247e 189 /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
3e7ee490 190
39d70a4a 191 in = (void *)((unsigned long)out + send_ringbuffer_size);
3e7ee490 192
c50f7fb2
HZ
193 newchannel->ringbuffer_pages = out;
194 newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
39d70a4a 195 recv_ringbuffer_size) >> PAGE_SHIFT;
3e7ee490 196
1ac58644 197 ret = ringbuffer_init(&newchannel->outbound, out, send_ringbuffer_size);
fd4dc88e 198 if (ret != 0) {
3324fb40
BP
199 err = ret;
200 goto errorout;
201 }
202
1ac58644 203 ret = ringbuffer_init(&newchannel->inbound, in, recv_ringbuffer_size);
fd4dc88e 204 if (ret != 0) {
3324fb40
BP
205 err = ret;
206 goto errorout;
207 }
3e7ee490 208
3e7ee490 209
454f18a9 210 /* Establish the gpadl for the ring buffer */
f4266e34 211 DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
39d70a4a 212 newchannel);
3e7ee490 213
c50f7fb2 214 newchannel->ringbuffer_gpadlhandle = 0;
3e7ee490 215
fff41b2e 216 ret = vmbus_establish_gpadl(newchannel,
82f8bd40 217 newchannel->outbound.ring_buffer,
39d70a4a
HZ
218 send_ringbuffer_size +
219 recv_ringbuffer_size,
c50f7fb2 220 &newchannel->ringbuffer_gpadlhandle);
b94ef345 221
fd4dc88e 222 if (ret != 0) {
b94ef345
BP
223 err = ret;
224 goto errorout;
225 }
f4266e34
GKH
226
227 DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
228 "size %d recv ring %p size %d, downstreamoffset %d>",
c50f7fb2
HZ
229 newchannel, newchannel->offermsg.child_relid,
230 newchannel->ringbuffer_gpadlhandle,
82f8bd40
HZ
231 newchannel->outbound.ring_buffer,
232 newchannel->outbound.ring_size,
233 newchannel->inbound.ring_buffer,
234 newchannel->inbound.ring_size,
39d70a4a 235 send_ringbuffer_size);
3e7ee490 236
454f18a9 237 /* Create and init the channel open message */
f4266e34
GKH
238 openInfo = kmalloc(sizeof(*openInfo) +
239 sizeof(struct vmbus_channel_open_channel),
240 GFP_KERNEL);
c3bf2e26
BP
241 if (!openInfo) {
242 err = -ENOMEM;
243 goto errorout;
244 }
3e7ee490 245
203df82d 246 openInfo->waitevent = osd_waitevent_create();
c50f7fb2 247 if (!openInfo->waitevent) {
c3bf2e26
BP
248 err = -ENOMEM;
249 goto errorout;
250 }
3e7ee490 251
c50f7fb2
HZ
252 openMsg = (struct vmbus_channel_open_channel *)openInfo->msg;
253 openMsg->header.msgtype = CHANNELMSG_OPENCHANNEL;
254 openMsg->openid = newchannel->offermsg.child_relid; /* FIXME */
255 openMsg->child_relid = newchannel->offermsg.child_relid;
256 openMsg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle;
257 openMsg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >>
f4266e34 258 PAGE_SHIFT;
c50f7fb2 259 openMsg->server_contextarea_gpadlhandle = 0; /* TODO */
3e7ee490 260
39d70a4a 261 if (userdatalen > MAX_USER_DEFINED_BYTES) {
c827f944
BP
262 err = -EINVAL;
263 goto errorout;
264 }
265
39d70a4a 266 if (userdatalen)
c50f7fb2 267 memcpy(openMsg->userdata, userdata, userdatalen);
3e7ee490 268
15b2f647 269 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
c50f7fb2 270 list_add_tail(&openInfo->msglistentry,
da9fcb72 271 &vmbus_connection.chn_msg_list);
15b2f647 272 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
3e7ee490
HJ
273
274 DPRINT_DBG(VMBUS, "Sending channel open msg...");
275
c6977677 276 ret = vmbus_post_msg(openMsg,
f4266e34
GKH
277 sizeof(struct vmbus_channel_open_channel));
278 if (ret != 0) {
3e7ee490
HJ
279 DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
280 goto Cleanup;
281 }
282
454f18a9 283 /* FIXME: Need to time-out here */
203df82d 284 osd_waitevent_wait(openInfo->waitevent);
3e7ee490 285
c50f7fb2 286 if (openInfo->response.open_result.status == 0)
39d70a4a 287 DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel);
3e7ee490 288 else
f4266e34 289 DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
c50f7fb2 290 newchannel, openInfo->response.open_result.status);
3e7ee490
HJ
291
292Cleanup:
15b2f647 293 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
c50f7fb2 294 list_del(&openInfo->msglistentry);
15b2f647 295 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
3e7ee490 296
c50f7fb2 297 kfree(openInfo->waitevent);
8c69f52a 298 kfree(openInfo);
3e7ee490 299 return 0;
c3bf2e26
BP
300
301errorout:
1ac58644
HZ
302 ringbuffer_cleanup(&newchannel->outbound);
303 ringbuffer_cleanup(&newchannel->inbound);
df3493e0
S
304 free_pages((unsigned long)out,
305 get_order(send_ringbuffer_size + recv_ringbuffer_size));
c3bf2e26
BP
306 kfree(openInfo);
307 return err;
3e7ee490 308}
36ceadfc 309EXPORT_SYMBOL_GPL(vmbus_open);
3e7ee490 310
3e189519 311/*
fff41b2e 312 * dump_gpadl_body - Dump the gpadl body message to the console for
3e189519 313 * debugging purposes.
f4266e34 314 */
fff41b2e 315static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len)
3e7ee490 316{
f4266e34 317 int i;
39d70a4a 318 int pfncount;
3e7ee490 319
39d70a4a 320 pfncount = (len - sizeof(struct vmbus_channel_gpadl_body)) /
f4266e34 321 sizeof(u64);
39d70a4a 322 DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", len, pfncount);
3e7ee490 323
39d70a4a 324 for (i = 0; i < pfncount; i++)
f4266e34 325 DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
c50f7fb2 326 i, gpadl->pfn[i]);
3e7ee490
HJ
327}
328
3e189519 329/*
fff41b2e 330 * dump_gpadl_header - Dump the gpadl header message to the console for
3e189519 331 * debugging purposes.
f4266e34 332 */
fff41b2e 333static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl)
3e7ee490 334{
f4266e34 335 int i, j;
39d70a4a 336 int pagecount;
3e7ee490 337
f4266e34
GKH
338 DPRINT_DBG(VMBUS,
339 "gpadl header - relid %d, range count %d, range buflen %d",
c50f7fb2
HZ
340 gpadl->child_relid, gpadl->rangecount, gpadl->range_buflen);
341 for (i = 0; i < gpadl->rangecount; i++) {
415f2287 342 pagecount = gpadl->range[i].byte_count >> PAGE_SHIFT;
39d70a4a 343 pagecount = (pagecount > 26) ? 26 : pagecount;
3e7ee490 344
f4266e34 345 DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
415f2287
HZ
346 "page count %d", i, gpadl->range[i].byte_count,
347 gpadl->range[i].byte_offset, pagecount);
3e7ee490 348
39d70a4a 349 for (j = 0; j < pagecount; j++)
f4266e34 350 DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
415f2287 351 gpadl->range[i].pfn_array[j]);
3e7ee490
HJ
352 }
353}
354
3e189519 355/*
fff41b2e 356 * create_gpadl_header - Creates a gpadl for the specified buffer
f4266e34 357 */
fff41b2e 358static int create_gpadl_header(void *kbuffer, u32 size,
39d70a4a
HZ
359 struct vmbus_channel_msginfo **msginfo,
360 u32 *messagecount)
3e7ee490
HJ
361{
362 int i;
39d70a4a 363 int pagecount;
f4266e34 364 unsigned long long pfn;
39d70a4a
HZ
365 struct vmbus_channel_gpadl_header *gpadl_header;
366 struct vmbus_channel_gpadl_body *gpadl_body;
367 struct vmbus_channel_msginfo *msgheader;
368 struct vmbus_channel_msginfo *msgbody = NULL;
369 u32 msgsize;
3e7ee490 370
39d70a4a 371 int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
3e7ee490 372
f4266e34 373 /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
0ace247e 374 /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
3e7ee490 375
39d70a4a
HZ
376 pagecount = size >> PAGE_SHIFT;
377 pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
3e7ee490 378
454f18a9 379 /* do we need a gpadl body msg */
39d70a4a 380 pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
f4266e34
GKH
381 sizeof(struct vmbus_channel_gpadl_header) -
382 sizeof(struct gpa_range);
39d70a4a 383 pfncount = pfnsize / sizeof(u64);
3e7ee490 384
39d70a4a 385 if (pagecount > pfncount) {
f4266e34 386 /* we need a gpadl body */
454f18a9 387 /* fill in the header */
39d70a4a 388 msgsize = sizeof(struct vmbus_channel_msginfo) +
f4266e34 389 sizeof(struct vmbus_channel_gpadl_header) +
39d70a4a
HZ
390 sizeof(struct gpa_range) + pfncount * sizeof(u64);
391 msgheader = kzalloc(msgsize, GFP_KERNEL);
392 if (!msgheader)
d1c250bb 393 goto nomem;
3e7ee490 394
c50f7fb2
HZ
395 INIT_LIST_HEAD(&msgheader->submsglist);
396 msgheader->msgsize = msgsize;
3e7ee490 397
39d70a4a 398 gpadl_header = (struct vmbus_channel_gpadl_header *)
c50f7fb2
HZ
399 msgheader->msg;
400 gpadl_header->rangecount = 1;
401 gpadl_header->range_buflen = sizeof(struct gpa_range) +
39d70a4a 402 pagecount * sizeof(u64);
415f2287
HZ
403 gpadl_header->range[0].byte_offset = 0;
404 gpadl_header->range[0].byte_count = size;
39d70a4a 405 for (i = 0; i < pfncount; i++)
415f2287 406 gpadl_header->range[0].pfn_array[i] = pfn+i;
39d70a4a
HZ
407 *msginfo = msgheader;
408 *messagecount = 1;
3e7ee490 409
39d70a4a
HZ
410 pfnsum = pfncount;
411 pfnleft = pagecount - pfncount;
3e7ee490 412
454f18a9 413 /* how many pfns can we fit */
39d70a4a 414 pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
f4266e34 415 sizeof(struct vmbus_channel_gpadl_body);
39d70a4a 416 pfncount = pfnsize / sizeof(u64);
3e7ee490 417
454f18a9 418 /* fill in the body */
39d70a4a
HZ
419 while (pfnleft) {
420 if (pfnleft > pfncount)
421 pfncurr = pfncount;
3e7ee490 422 else
39d70a4a 423 pfncurr = pfnleft;
3e7ee490 424
39d70a4a 425 msgsize = sizeof(struct vmbus_channel_msginfo) +
f4266e34 426 sizeof(struct vmbus_channel_gpadl_body) +
39d70a4a
HZ
427 pfncurr * sizeof(u64);
428 msgbody = kzalloc(msgsize, GFP_KERNEL);
d1c250bb 429 /* FIXME: we probably need to more if this fails */
39d70a4a 430 if (!msgbody)
d1c250bb 431 goto nomem;
c50f7fb2 432 msgbody->msgsize = msgsize;
39d70a4a
HZ
433 (*messagecount)++;
434 gpadl_body =
c50f7fb2 435 (struct vmbus_channel_gpadl_body *)msgbody->msg;
f4266e34
GKH
436
437 /*
438 * FIXME:
439 * Gpadl is u32 and we are using a pointer which could
440 * be 64-bit
441 */
39d70a4a
HZ
442 /* gpadl_body->Gpadl = kbuffer; */
443 for (i = 0; i < pfncurr; i++)
c50f7fb2 444 gpadl_body->pfn[i] = pfn + pfnsum + i;
3e7ee490 445
454f18a9 446 /* add to msg header */
c50f7fb2
HZ
447 list_add_tail(&msgbody->msglistentry,
448 &msgheader->submsglist);
39d70a4a
HZ
449 pfnsum += pfncurr;
450 pfnleft -= pfncurr;
3e7ee490 451 }
f4266e34 452 } else {
454f18a9 453 /* everything fits in a header */
39d70a4a 454 msgsize = sizeof(struct vmbus_channel_msginfo) +
f4266e34 455 sizeof(struct vmbus_channel_gpadl_header) +
39d70a4a
HZ
456 sizeof(struct gpa_range) + pagecount * sizeof(u64);
457 msgheader = kzalloc(msgsize, GFP_KERNEL);
458 if (msgheader == NULL)
e3eb7cdd 459 goto nomem;
c50f7fb2 460 msgheader->msgsize = msgsize;
39d70a4a
HZ
461
462 gpadl_header = (struct vmbus_channel_gpadl_header *)
c50f7fb2
HZ
463 msgheader->msg;
464 gpadl_header->rangecount = 1;
465 gpadl_header->range_buflen = sizeof(struct gpa_range) +
39d70a4a 466 pagecount * sizeof(u64);
415f2287
HZ
467 gpadl_header->range[0].byte_offset = 0;
468 gpadl_header->range[0].byte_count = size;
39d70a4a 469 for (i = 0; i < pagecount; i++)
415f2287 470 gpadl_header->range[0].pfn_array[i] = pfn+i;
39d70a4a
HZ
471
472 *msginfo = msgheader;
473 *messagecount = 1;
3e7ee490
HJ
474 }
475
476 return 0;
d1c250bb 477nomem:
39d70a4a
HZ
478 kfree(msgheader);
479 kfree(msgbody);
d1c250bb 480 return -ENOMEM;
3e7ee490
HJ
481}
482
3e189519 483/*
fff41b2e 484 * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer
f4266e34 485 *
39d70a4a
HZ
486 * @channel: a channel
487 * @kbuffer: from kmalloc
488 * @size: page-size multiple
489 * @gpadl_handle: some funky thing
f4266e34 490 */
fff41b2e 491int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
39d70a4a 492 u32 size, u32 *gpadl_handle)
3e7ee490 493{
39d70a4a
HZ
494 struct vmbus_channel_gpadl_header *gpadlmsg;
495 struct vmbus_channel_gpadl_body *gpadl_body;
82250213 496 /* struct vmbus_channel_gpadl_created *gpadlCreated; */
39d70a4a
HZ
497 struct vmbus_channel_msginfo *msginfo = NULL;
498 struct vmbus_channel_msginfo *submsginfo;
499 u32 msgcount;
53af545b 500 struct list_head *curr;
39d70a4a 501 u32 next_gpadl_handle;
dd0813b6 502 unsigned long flags;
c3bf2e26 503 int ret = 0;
3e7ee490 504
da9fcb72
HZ
505 next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
506 atomic_inc(&vmbus_connection.next_gpadl_handle);
3e7ee490 507
fff41b2e 508 ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
c3bf2e26
BP
509 if (ret)
510 return ret;
3e7ee490 511
203df82d 512 msginfo->waitevent = osd_waitevent_create();
c50f7fb2 513 if (!msginfo->waitevent) {
c3bf2e26
BP
514 ret = -ENOMEM;
515 goto Cleanup;
516 }
517
c50f7fb2
HZ
518 gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
519 gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
520 gpadlmsg->child_relid = channel->offermsg.child_relid;
521 gpadlmsg->gpadl = next_gpadl_handle;
3e7ee490 522
fff41b2e 523 dump_gpadl_header(gpadlmsg);
3e7ee490 524
15b2f647 525 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
c50f7fb2 526 list_add_tail(&msginfo->msglistentry,
da9fcb72 527 &vmbus_connection.chn_msg_list);
3e7ee490 528
15b2f647 529 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
f4266e34 530 DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
39d70a4a 531 kbuffer, size, msgcount);
3e7ee490 532
f4266e34 533 DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
c50f7fb2 534 msginfo->msgsize - sizeof(*msginfo));
3e7ee490 535
c6977677 536 ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize -
39d70a4a 537 sizeof(*msginfo));
f4266e34 538 if (ret != 0) {
3e7ee490
HJ
539 DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
540 goto Cleanup;
541 }
542
39d70a4a 543 if (msgcount > 1) {
c50f7fb2 544 list_for_each(curr, &msginfo->submsglist) {
53af545b
BP
545
546 /* FIXME: should this use list_entry() instead ? */
39d70a4a
HZ
547 submsginfo = (struct vmbus_channel_msginfo *)curr;
548 gpadl_body =
c50f7fb2 549 (struct vmbus_channel_gpadl_body *)submsginfo->msg;
3e7ee490 550
c50f7fb2
HZ
551 gpadl_body->header.msgtype =
552 CHANNELMSG_GPADL_BODY;
553 gpadl_body->gpadl = next_gpadl_handle;
3e7ee490 554
f4266e34 555 DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
c50f7fb2 556 submsginfo->msgsize -
39d70a4a
HZ
557 sizeof(*submsginfo));
558
c50f7fb2 559 dump_gpadl_body(gpadl_body, submsginfo->msgsize -
39d70a4a 560 sizeof(*submsginfo));
c6977677 561 ret = vmbus_post_msg(gpadl_body,
c50f7fb2 562 submsginfo->msgsize -
39d70a4a 563 sizeof(*submsginfo));
fd4dc88e 564 if (ret != 0)
99259159
BP
565 goto Cleanup;
566
3e7ee490
HJ
567 }
568 }
203df82d 569 osd_waitevent_wait(msginfo->waitevent);
3e7ee490 570
454f18a9 571 /* At this point, we received the gpadl created msg */
f4266e34
GKH
572 DPRINT_DBG(VMBUS, "Received GPADL created "
573 "(relid %d, status %d handle %x)",
c50f7fb2
HZ
574 channel->offermsg.child_relid,
575 msginfo->response.gpadl_created.creation_status,
576 gpadlmsg->gpadl);
3e7ee490 577
c50f7fb2 578 *gpadl_handle = gpadlmsg->gpadl;
3e7ee490
HJ
579
580Cleanup:
15b2f647 581 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
c50f7fb2 582 list_del(&msginfo->msglistentry);
15b2f647 583 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
3e7ee490 584
c50f7fb2 585 kfree(msginfo->waitevent);
39d70a4a 586 kfree(msginfo);
3e7ee490
HJ
587 return ret;
588}
98873724 589EXPORT_SYMBOL_GPL(vmbus_establish_gpadl);
3e7ee490 590
3e189519 591/*
fff41b2e 592 * vmbus_teardown_gpadl -Teardown the specified GPADL handle
f4266e34 593 */
fff41b2e 594int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
3e7ee490 595{
82250213 596 struct vmbus_channel_gpadl_teardown *msg;
aded7165 597 struct vmbus_channel_msginfo *info;
dd0813b6 598 unsigned long flags;
f4266e34 599 int ret;
3e7ee490 600
39d70a4a 601 /* ASSERT(gpadl_handle != 0); */
3e7ee490 602
f4266e34
GKH
603 info = kmalloc(sizeof(*info) +
604 sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
c3bf2e26
BP
605 if (!info)
606 return -ENOMEM;
3e7ee490 607
203df82d 608 info->waitevent = osd_waitevent_create();
c50f7fb2 609 if (!info->waitevent) {
c3bf2e26
BP
610 kfree(info);
611 return -ENOMEM;
612 }
3e7ee490 613
c50f7fb2 614 msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
3e7ee490 615
c50f7fb2
HZ
616 msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN;
617 msg->child_relid = channel->offermsg.child_relid;
618 msg->gpadl = gpadl_handle;
3e7ee490 619
15b2f647 620 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
c50f7fb2 621 list_add_tail(&info->msglistentry,
da9fcb72 622 &vmbus_connection.chn_msg_list);
15b2f647 623 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
3e7ee490 624
c6977677 625 ret = vmbus_post_msg(msg,
f4266e34
GKH
626 sizeof(struct vmbus_channel_gpadl_teardown));
627 if (ret != 0) {
454f18a9 628 /* TODO: */
f4266e34 629 /* something... */
3e7ee490
HJ
630 }
631
203df82d 632 osd_waitevent_wait(info->waitevent);
3e7ee490 633
454f18a9 634 /* Received a torndown response */
15b2f647 635 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
c50f7fb2 636 list_del(&info->msglistentry);
15b2f647 637 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
3e7ee490 638
c50f7fb2 639 kfree(info->waitevent);
8c69f52a 640 kfree(info);
3e7ee490
HJ
641 return ret;
642}
18726d7a 643EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
3e7ee490 644
3e189519 645/*
fff41b2e 646 * vmbus_close - Close the specified channel
f4266e34 647 */
fff41b2e 648void vmbus_close(struct vmbus_channel *channel)
3e7ee490 649{
82250213 650 struct vmbus_channel_close_channel *msg;
aded7165 651 struct vmbus_channel_msginfo *info;
0f5e44ca 652 unsigned long flags;
f4266e34 653 int ret;
3e7ee490 654
454f18a9 655 /* Stop callback and cancel the timer asap */
c50f7fb2 656 channel->onchannel_callback = NULL;
39d70a4a 657 del_timer_sync(&channel->poll_timer);
3e7ee490 658
454f18a9 659 /* Send a closing message */
f4266e34
GKH
660 info = kmalloc(sizeof(*info) +
661 sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
c3bf2e26
BP
662 /* FIXME: can't do anything other than return here because the
663 * function is void */
664 if (!info)
665 return;
3e7ee490 666
203df82d 667 /* info->waitEvent = osd_waitevent_create(); */
3e7ee490 668
c50f7fb2
HZ
669 msg = (struct vmbus_channel_close_channel *)info->msg;
670 msg->header.msgtype = CHANNELMSG_CLOSECHANNEL;
671 msg->child_relid = channel->offermsg.child_relid;
3e7ee490 672
c6977677 673 ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel));
f4266e34 674 if (ret != 0) {
454f18a9 675 /* TODO: */
f4266e34 676 /* something... */
3e7ee490
HJ
677 }
678
454f18a9 679 /* Tear down the gpadl for the channel's ring buffer */
c50f7fb2 680 if (channel->ringbuffer_gpadlhandle)
fff41b2e 681 vmbus_teardown_gpadl(channel,
c50f7fb2 682 channel->ringbuffer_gpadlhandle);
3e7ee490 683
454f18a9 684 /* TODO: Send a msg to release the childRelId */
3e7ee490 685
454f18a9 686 /* Cleanup the ring buffers for this channel */
1ac58644
HZ
687 ringbuffer_cleanup(&channel->outbound);
688 ringbuffer_cleanup(&channel->inbound);
3e7ee490 689
df3493e0
S
690 free_pages((unsigned long)channel->ringbuffer_pages,
691 get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
3e7ee490 692
8c69f52a 693 kfree(info);
3e7ee490 694
454f18a9
BP
695 /*
696 * If we are closing the channel during an error path in
697 * opening the channel, don't free the channel since the
698 * caller will free the channel
699 */
700
c50f7fb2 701 if (channel->state == CHANNEL_OPEN_STATE) {
15b2f647 702 spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
c50f7fb2 703 list_del(&channel->listentry);
15b2f647 704 spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
3e7ee490 705
e98cb276 706 free_channel(channel);
3e7ee490 707 }
3e7ee490 708}
70bfa307 709EXPORT_SYMBOL_GPL(vmbus_close);
3e7ee490 710
c88c4e4c 711/**
fff41b2e 712 * vmbus_sendpacket() - Send the specified buffer on the given channel
39d70a4a
HZ
713 * @channel: Pointer to vmbus_channel structure.
714 * @buffer: Pointer to the buffer you want to receive the data into.
715 * @bufferlen: Maximum size of what the the buffer will hold
716 * @requestid: Identifier of the request
717 * @type: Type of packet that is being send e.g. negotiate, time
c88c4e4c
HJ
718 * packet etc.
719 *
39d70a4a 720 * Sends data in @buffer directly to hyper-v via the vmbus
c88c4e4c
HJ
721 * This will send the data unparsed to hyper-v.
722 *
723 * Mainly used by Hyper-V drivers.
f4266e34 724 */
fff41b2e 725int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
39d70a4a
HZ
726 u32 bufferlen, u64 requestid,
727 enum vmbus_packet_type type, u32 flags)
3e7ee490 728{
8dc0a06a 729 struct vmpacket_descriptor desc;
39d70a4a 730 u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
73509681 731 u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
39d70a4a
HZ
732 struct scatterlist bufferlist[3];
733 u64 aligned_data = 0;
f4266e34 734 int ret;
3e7ee490 735
f4266e34 736 DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
39d70a4a 737 channel, buffer, bufferlen);
3e7ee490 738
fff41b2e 739 dump_vmbus_channel(channel);
3e7ee490 740
0ace247e 741 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
3e7ee490 742
454f18a9 743 /* Setup the descriptor */
415f2287
HZ
744 desc.type = type; /* VmbusPacketTypeDataInBand; */
745 desc.flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
f4266e34 746 /* in 8-bytes granularity */
415f2287
HZ
747 desc.offset8 = sizeof(struct vmpacket_descriptor) >> 3;
748 desc.len8 = (u16)(packetlen_aligned >> 3);
749 desc.trans_id = requestid;
3e7ee490 750
39d70a4a
HZ
751 sg_init_table(bufferlist, 3);
752 sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
753 sg_set_buf(&bufferlist[1], buffer, bufferlen);
754 sg_set_buf(&bufferlist[2], &aligned_data,
755 packetlen_aligned - packetlen);
3e7ee490 756
1ac58644 757 ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
3e7ee490 758
454f18a9 759 /* TODO: We should determine if this is optional */
1ac58644 760 if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
fff41b2e 761 vmbus_setevent(channel);
3e7ee490 762
3e7ee490
HJ
763 return ret;
764}
fff41b2e 765EXPORT_SYMBOL(vmbus_sendpacket);
3e7ee490 766
3e189519 767/*
fff41b2e 768 * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer
3e189519 769 * packets using a GPADL Direct packet type.
f4266e34 770 */
fff41b2e 771int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
39d70a4a
HZ
772 struct hv_page_buffer pagebuffers[],
773 u32 pagecount, void *buffer, u32 bufferlen,
774 u64 requestid)
3e7ee490 775{
f4266e34
GKH
776 int ret;
777 int i;
430a8e9a 778 struct vmbus_channel_packet_page_buffer desc;
39d70a4a
HZ
779 u32 descsize;
780 u32 packetlen;
781 u32 packetlen_aligned;
782 struct scatterlist bufferlist[3];
783 u64 aligned_data = 0;
3e7ee490 784
39d70a4a 785 if (pagecount > MAX_PAGE_BUFFER_COUNT)
002b53ea 786 return -EINVAL;
3e7ee490 787
fff41b2e 788 dump_vmbus_channel(channel);
3e7ee490 789
f4266e34 790 /*
430a8e9a 791 * Adjust the size down since vmbus_channel_packet_page_buffer is the
f4266e34
GKH
792 * largest size we support
793 */
39d70a4a
HZ
794 descsize = sizeof(struct vmbus_channel_packet_page_buffer) -
795 ((MAX_PAGE_BUFFER_COUNT - pagecount) *
f4266e34 796 sizeof(struct hv_page_buffer));
39d70a4a 797 packetlen = descsize + bufferlen;
73509681 798 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
3e7ee490 799
0ace247e 800 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
3e7ee490 801
454f18a9 802 /* Setup the descriptor */
415f2287 803 desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
430a8e9a 804 desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
39d70a4a
HZ
805 desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
806 desc.length8 = (u16)(packetlen_aligned >> 3);
807 desc.transactionid = requestid;
808 desc.rangecount = pagecount;
809
810 for (i = 0; i < pagecount; i++) {
ca623ad3
HZ
811 desc.range[i].len = pagebuffers[i].len;
812 desc.range[i].offset = pagebuffers[i].offset;
813 desc.range[i].pfn = pagebuffers[i].pfn;
3e7ee490
HJ
814 }
815
39d70a4a
HZ
816 sg_init_table(bufferlist, 3);
817 sg_set_buf(&bufferlist[0], &desc, descsize);
818 sg_set_buf(&bufferlist[1], buffer, bufferlen);
819 sg_set_buf(&bufferlist[2], &aligned_data,
820 packetlen_aligned - packetlen);
3e7ee490 821
1ac58644 822 ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
3e7ee490 823
454f18a9 824 /* TODO: We should determine if this is optional */
1ac58644 825 if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
fff41b2e 826 vmbus_setevent(channel);
3e7ee490 827
3e7ee490
HJ
828 return ret;
829}
713efeb4 830EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
3e7ee490 831
3e189519 832/*
fff41b2e 833 * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
3e189519 834 * using a GPADL Direct packet type.
f4266e34 835 */
fff41b2e 836int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
39d70a4a
HZ
837 struct hv_multipage_buffer *multi_pagebuffer,
838 void *buffer, u32 bufferlen, u64 requestid)
3e7ee490 839{
f4266e34 840 int ret;
430a8e9a 841 struct vmbus_channel_packet_multipage_buffer desc;
39d70a4a
HZ
842 u32 descsize;
843 u32 packetlen;
844 u32 packetlen_aligned;
845 struct scatterlist bufferlist[3];
846 u64 aligned_data = 0;
ca623ad3
HZ
847 u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
848 multi_pagebuffer->len);
3e7ee490 849
fff41b2e 850 dump_vmbus_channel(channel);
3e7ee490 851
f4266e34 852 DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
ca623ad3
HZ
853 multi_pagebuffer->offset,
854 multi_pagebuffer->len, pfncount);
3e7ee490 855
39d70a4a 856 if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
002b53ea 857 return -EINVAL;
3e7ee490 858
f4266e34 859 /*
430a8e9a 860 * Adjust the size down since vmbus_channel_packet_multipage_buffer is
f4266e34
GKH
861 * the largest size we support
862 */
39d70a4a
HZ
863 descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) -
864 ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) *
f4266e34 865 sizeof(u64));
39d70a4a 866 packetlen = descsize + bufferlen;
73509681 867 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
3e7ee490 868
0ace247e 869 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
3e7ee490 870
454f18a9 871 /* Setup the descriptor */
415f2287 872 desc.type = VM_PKT_DATA_USING_GPA_DIRECT;
430a8e9a 873 desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
39d70a4a
HZ
874 desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
875 desc.length8 = (u16)(packetlen_aligned >> 3);
876 desc.transactionid = requestid;
430a8e9a 877 desc.rangecount = 1;
3e7ee490 878
ca623ad3
HZ
879 desc.range.len = multi_pagebuffer->len;
880 desc.range.offset = multi_pagebuffer->offset;
3e7ee490 881
ca623ad3 882 memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
39d70a4a 883 pfncount * sizeof(u64));
3e7ee490 884
39d70a4a
HZ
885 sg_init_table(bufferlist, 3);
886 sg_set_buf(&bufferlist[0], &desc, descsize);
887 sg_set_buf(&bufferlist[1], buffer, bufferlen);
888 sg_set_buf(&bufferlist[2], &aligned_data,
889 packetlen_aligned - packetlen);
3e7ee490 890
1ac58644 891 ret = ringbuffer_write(&channel->outbound, bufferlist, 3);
3e7ee490 892
454f18a9 893 /* TODO: We should determine if this is optional */
1ac58644 894 if (ret == 0 && !get_ringbuffer_interrupt_mask(&channel->outbound))
fff41b2e 895 vmbus_setevent(channel);
3e7ee490 896
3e7ee490
HJ
897 return ret;
898}
4cb106fa 899EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
c88c4e4c
HJ
900
901/**
fff41b2e 902 * vmbus_recvpacket() - Retrieve the user packet on the specified channel
39d70a4a
HZ
903 * @channel: Pointer to vmbus_channel structure.
904 * @buffer: Pointer to the buffer you want to receive the data into.
905 * @bufferlen: Maximum size of what the the buffer will hold
906 * @buffer_actual_len: The actual size of the data after it was received
907 * @requestid: Identifier of the request
c88c4e4c
HJ
908 *
909 * Receives directly from the hyper-v vmbus and puts the data it received
910 * into Buffer. This will receive the data unparsed from hyper-v.
911 *
912 * Mainly used by Hyper-V drivers.
f4266e34 913 */
fff41b2e 914int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
39d70a4a 915 u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
3e7ee490 916{
8dc0a06a 917 struct vmpacket_descriptor desc;
39d70a4a
HZ
918 u32 packetlen;
919 u32 userlen;
3e7ee490 920 int ret;
54411c42 921 unsigned long flags;
3e7ee490 922
39d70a4a
HZ
923 *buffer_actual_len = 0;
924 *requestid = 0;
3e7ee490 925
39d70a4a 926 spin_lock_irqsave(&channel->inbound_lock, flags);
3e7ee490 927
1ac58644 928 ret = ringbuffer_peek(&channel->inbound, &desc,
f4266e34
GKH
929 sizeof(struct vmpacket_descriptor));
930 if (ret != 0) {
39d70a4a 931 spin_unlock_irqrestore(&channel->inbound_lock, flags);
3e7ee490 932
454f18a9 933 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
3e7ee490
HJ
934 return 0;
935 }
936
454f18a9 937 /* VmbusChannelClearEvent(Channel); */
3e7ee490 938
415f2287
HZ
939 packetlen = desc.len8 << 3;
940 userlen = packetlen - (desc.offset8 << 3);
454f18a9 941 /* ASSERT(userLen > 0); */
3e7ee490 942
f4266e34
GKH
943 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
944 "flag %d tid %llx pktlen %d datalen %d> ",
415f2287
HZ
945 channel, channel->offermsg.child_relid, desc.type,
946 desc.flags, desc.trans_id, packetlen, userlen);
3e7ee490 947
39d70a4a 948 *buffer_actual_len = userlen;
3e7ee490 949
39d70a4a
HZ
950 if (userlen > bufferlen) {
951 spin_unlock_irqrestore(&channel->inbound_lock, flags);
3e7ee490 952
f4266e34 953 DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
39d70a4a 954 bufferlen, userlen);
3e7ee490
HJ
955 return -1;
956 }
957
415f2287 958 *requestid = desc.trans_id;
3e7ee490 959
454f18a9 960 /* Copy over the packet to the user buffer */
1ac58644 961 ret = ringbuffer_read(&channel->inbound, buffer, userlen,
415f2287 962 (desc.offset8 << 3));
3e7ee490 963
39d70a4a 964 spin_unlock_irqrestore(&channel->inbound_lock, flags);
3e7ee490 965
3e7ee490
HJ
966 return 0;
967}
fff41b2e 968EXPORT_SYMBOL(vmbus_recvpacket);
3e7ee490 969
3e189519 970/*
fff41b2e 971 * vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel
f4266e34 972 */
fff41b2e 973int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
39d70a4a
HZ
974 u32 bufferlen, u32 *buffer_actual_len,
975 u64 *requestid)
3e7ee490 976{
8dc0a06a 977 struct vmpacket_descriptor desc;
39d70a4a
HZ
978 u32 packetlen;
979 u32 userlen;
3e7ee490 980 int ret;
54411c42 981 unsigned long flags;
3e7ee490 982
39d70a4a
HZ
983 *buffer_actual_len = 0;
984 *requestid = 0;
3e7ee490 985
39d70a4a 986 spin_lock_irqsave(&channel->inbound_lock, flags);
3e7ee490 987
1ac58644 988 ret = ringbuffer_peek(&channel->inbound, &desc,
f4266e34
GKH
989 sizeof(struct vmpacket_descriptor));
990 if (ret != 0) {
39d70a4a 991 spin_unlock_irqrestore(&channel->inbound_lock, flags);
3e7ee490 992
454f18a9 993 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
3e7ee490
HJ
994 return 0;
995 }
996
454f18a9 997 /* VmbusChannelClearEvent(Channel); */
3e7ee490 998
415f2287
HZ
999 packetlen = desc.len8 << 3;
1000 userlen = packetlen - (desc.offset8 << 3);
3e7ee490 1001
f4266e34
GKH
1002 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
1003 "flag %d tid %llx pktlen %d datalen %d> ",
415f2287
HZ
1004 channel, channel->offermsg.child_relid, desc.type,
1005 desc.flags, desc.trans_id, packetlen, userlen);
3e7ee490 1006
39d70a4a 1007 *buffer_actual_len = packetlen;
3e7ee490 1008
39d70a4a
HZ
1009 if (packetlen > bufferlen) {
1010 spin_unlock_irqrestore(&channel->inbound_lock, flags);
3e7ee490 1011
f4266e34 1012 DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
39d70a4a 1013 "got space for only %d bytes", packetlen, bufferlen);
3e7ee490
HJ
1014 return -2;
1015 }
1016
415f2287 1017 *requestid = desc.trans_id;
3e7ee490 1018
454f18a9 1019 /* Copy over the entire packet to the user buffer */
1ac58644 1020 ret = ringbuffer_read(&channel->inbound, buffer, packetlen, 0);
3e7ee490 1021
39d70a4a 1022 spin_unlock_irqrestore(&channel->inbound_lock, flags);
3e7ee490
HJ
1023 return 0;
1024}
adaee6bd 1025EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
3e7ee490 1026
3e189519 1027/*
fff41b2e 1028 * vmbus_onchannel_event - Channel event callback
f4266e34 1029 */
fff41b2e 1030void vmbus_onchannel_event(struct vmbus_channel *channel)
3e7ee490 1031{
fff41b2e 1032 dump_vmbus_channel(channel);
0ace247e 1033 /* ASSERT(Channel->OnChannelCallback); */
5996b3dd 1034
c50f7fb2 1035 channel->onchannel_callback(channel->channel_callback_context);
5996b3dd 1036
39d70a4a 1037 mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100));
3e7ee490
HJ
1038}
1039
3e189519 1040/*
fff41b2e 1041 * vmbus_ontimer - Timer event callback
f4266e34 1042 */
fff41b2e 1043void vmbus_ontimer(unsigned long data)
3e7ee490 1044{
aded7165 1045 struct vmbus_channel *channel = (struct vmbus_channel *)data;
3e7ee490 1046
c50f7fb2
HZ
1047 if (channel->onchannel_callback)
1048 channel->onchannel_callback(channel->channel_callback_context);
3e7ee490
HJ
1049}
1050
3e189519 1051/*
fff41b2e 1052 * dump_vmbus_channel- Dump vmbus channel info to the console
f4266e34 1053 */
fff41b2e 1054static void dump_vmbus_channel(struct vmbus_channel *channel)
3e7ee490 1055{
c50f7fb2 1056 DPRINT_DBG(VMBUS, "Channel (%d)", channel->offermsg.child_relid);
1ac58644
HZ
1057 dump_ring_info(&channel->outbound, "Outbound ");
1058 dump_ring_info(&channel->inbound, "Inbound ");
3e7ee490 1059}
This page took 0.236399 seconds and 5 git commands to generate.