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