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