channel_mgmt.c 22.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Copyright (c) 2009, Microsoft Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * Authors:
 *   Haiyang Zhang <haiyangz@microsoft.com>
 *   Hank Janssen  <hjanssen@microsoft.com>
 */
21 22
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

23
#include <linux/kernel.h>
24 25
#include <linux/sched.h>
#include <linux/wait.h>
26
#include <linux/mm.h>
27
#include <linux/slab.h>
28
#include <linux/list.h>
29
#include <linux/module.h>
30
#include <linux/completion.h>
31
#include <linux/hyperv.h>
32

33
#include "hyperv_vmbus.h"
34

35
struct vmbus_channel_message_table_entry {
36
	enum vmbus_channel_message_type message_type;
37
	void (*message_handler)(struct vmbus_channel_message_header *msg);
38
};
39

40 41

/**
42
 * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
43 44 45 46 47 48
 * @icmsghdrp: Pointer to msg header structure
 * @icmsg_negotiate: Pointer to negotiate message structure
 * @buf: Raw buffer channel data
 *
 * @icmsghdrp is of type &struct icmsg_hdr.
 * @negop is of type &struct icmsg_negotiate.
49 50
 * Set up and fill in default negotiate response message.
 *
51 52 53
 * The fw_version specifies the  framework version that
 * we can support and srv_version specifies the service
 * version we can support.
54 55 56
 *
 * Mainly used by Hyper-V drivers.
 */
57
bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
58
				struct icmsg_negotiate *negop, u8 *buf,
59
				int fw_version, int srv_version)
60
{
61 62 63 64
	int icframe_major, icframe_minor;
	int icmsg_major, icmsg_minor;
	int fw_major, fw_minor;
	int srv_major, srv_minor;
65
	int i;
66
	bool found_match = false;
67

68
	icmsghdrp->icmsgsize = 0x10;
69 70 71 72 73
	fw_major = (fw_version >> 16);
	fw_minor = (fw_version & 0xFFFF);

	srv_major = (srv_version >> 16);
	srv_minor = (srv_version & 0xFFFF);
74

75 76 77
	negop = (struct icmsg_negotiate *)&buf[
		sizeof(struct vmbuspipe_hdr) +
		sizeof(struct icmsg_hdr)];
78

79 80 81 82 83
	icframe_major = negop->icframe_vercnt;
	icframe_minor = 0;

	icmsg_major = negop->icmsg_vercnt;
	icmsg_minor = 0;
84 85 86 87 88 89 90

	/*
	 * Select the framework version number we will
	 * support.
	 */

	for (i = 0; i < negop->icframe_vercnt; i++) {
91 92 93 94 95 96
		if ((negop->icversion_data[i].major == fw_major) &&
		   (negop->icversion_data[i].minor == fw_minor)) {
			icframe_major = negop->icversion_data[i].major;
			icframe_minor = negop->icversion_data[i].minor;
			found_match = true;
		}
97 98
	}

99 100 101 102 103
	if (!found_match)
		goto fw_error;

	found_match = false;

104 105
	for (i = negop->icframe_vercnt;
		 (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
106 107 108 109 110 111
		if ((negop->icversion_data[i].major == srv_major) &&
		   (negop->icversion_data[i].minor == srv_minor)) {
			icmsg_major = negop->icversion_data[i].major;
			icmsg_minor = negop->icversion_data[i].minor;
			found_match = true;
		}
112
	}
113

114
	/*
115
	 * Respond with the framework and service
116 117
	 * version numbers we can support.
	 */
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

fw_error:
	if (!found_match) {
		negop->icframe_vercnt = 0;
		negop->icmsg_vercnt = 0;
	} else {
		negop->icframe_vercnt = 1;
		negop->icmsg_vercnt = 1;
	}

	negop->icversion_data[0].major = icframe_major;
	negop->icversion_data[0].minor = icframe_minor;
	negop->icversion_data[1].major = icmsg_major;
	negop->icversion_data[1].minor = icmsg_minor;
	return found_match;
133
}
134

135
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
136

137
/*
138
 * alloc_channel - Allocate and initialize a vmbus channel object
139
 */
140
static struct vmbus_channel *alloc_channel(void)
141
{
142
	struct vmbus_channel *channel;
143

144
	channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
145 146 147
	if (!channel)
		return NULL;

148
	spin_lock_init(&channel->inbound_lock);
149 150 151
	spin_lock_init(&channel->sc_lock);

	INIT_LIST_HEAD(&channel->sc_list);
152

153 154
	channel->controlwq = create_workqueue("hv_vmbus_ctl");
	if (!channel->controlwq) {
155
		kfree(channel);
156 157 158 159 160 161
		return NULL;
	}

	return channel;
}

162
/*
163
 * release_hannel - Release the vmbus channel object itself
164
 */
165
static void release_channel(struct work_struct *work)
166
{
167 168 169
	struct vmbus_channel *channel = container_of(work,
						     struct vmbus_channel,
						     work);
170

171
	destroy_workqueue(channel->controlwq);
172

173
	kfree(channel);
174 175
}

176
/*
177
 * free_channel - Release the resources used by the vmbus channel object
178
 */
179
static void free_channel(struct vmbus_channel *channel)
180 181
{

182 183 184 185 186
	/*
	 * We have to release the channel's workqueue/thread in the vmbus's
	 * workqueue/thread context
	 * ie we can't destroy ourselves.
	 */
187
	INIT_WORK(&channel->work, release_channel);
188
	queue_work(vmbus_connection.work_queue, &channel->work);
189 190
}

191 192


193 194 195 196 197 198 199 200 201
/*
 * vmbus_process_rescind_offer -
 * Rescind the offer by initiating a device removal
 */
static void vmbus_process_rescind_offer(struct work_struct *work)
{
	struct vmbus_channel *channel = container_of(work,
						     struct vmbus_channel,
						     work);
202
	unsigned long flags;
203
	struct vmbus_channel *primary_channel;
204
	struct vmbus_channel_relid_released msg;
205

206
	vmbus_device_unregister(channel->device_obj);
207 208 209 210 211
	memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
	msg.child_relid = channel->offermsg.child_relid;
	msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
	vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));

212 213 214 215 216 217 218 219 220 221
	if (channel->primary_channel == NULL) {
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
		list_del(&channel->listentry);
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
	} else {
		primary_channel = channel->primary_channel;
		spin_lock_irqsave(&primary_channel->sc_lock, flags);
		list_del(&channel->listentry);
		spin_unlock_irqrestore(&primary_channel->sc_lock, flags);
	}
222
	free_channel(channel);
223
}
224

225 226 227 228 229 230 231 232 233 234 235
void vmbus_free_channels(void)
{
	struct vmbus_channel *channel;

	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
		vmbus_device_unregister(channel->device_obj);
		kfree(channel->device_obj);
		free_channel(channel);
	}
}

236
/*
237
 * vmbus_process_offer - Process the offer by creating a channel/device
238
 * associated with this offer
239
 */
240
static void vmbus_process_offer(struct work_struct *work)
241
{
242 243 244
	struct vmbus_channel *newchannel = container_of(work,
							struct vmbus_channel,
							work);
245
	struct vmbus_channel *channel;
246
	bool fnew = true;
247
	int ret;
248
	unsigned long flags;
249

250 251 252
	/* The next possible work is rescind handling */
	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);

253
	/* Make sure this is a new offer */
254
	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
255

256
	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
257 258 259 260
		if (!uuid_le_cmp(channel->offermsg.offer.if_type,
			newchannel->offermsg.offer.if_type) &&
			!uuid_le_cmp(channel->offermsg.offer.if_instance,
				newchannel->offermsg.offer.if_instance)) {
261
			fnew = false;
262 263 264 265
			break;
		}
	}

266
	if (fnew)
267
		list_add_tail(&newchannel->listentry,
268
			      &vmbus_connection.chn_list);
269

270
	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
271

272
	if (!fnew) {
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
		/*
		 * Check to see if this is a sub-channel.
		 */
		if (newchannel->offermsg.offer.sub_channel_index != 0) {
			/*
			 * Process the sub-channel.
			 */
			newchannel->primary_channel = channel;
			spin_lock_irqsave(&channel->sc_lock, flags);
			list_add_tail(&newchannel->sc_list, &channel->sc_list);
			spin_unlock_irqrestore(&channel->sc_lock, flags);
			newchannel->state = CHANNEL_OPEN_STATE;
			if (channel->sc_creation_callback != NULL)
				channel->sc_creation_callback(newchannel);

			return;
		}

291
		free_channel(newchannel);
292 293 294
		return;
	}

295 296 297
	/*
	 * Start the process of binding this offer to the driver
	 * We need to set the DeviceObject field before calling
298
	 * vmbus_child_dev_add()
299
	 */
300
	newchannel->device_obj = vmbus_device_create(
301 302
		&newchannel->offermsg.offer.if_type,
		&newchannel->offermsg.offer.if_instance,
303
		newchannel);
304

305 306 307 308 309
	/*
	 * Add the new device to the bus. This will kick off device-driver
	 * binding which eventually invokes the device driver's AddDevice()
	 * method.
	 */
310
	ret = vmbus_device_register(newchannel->device_obj);
311
	if (ret != 0) {
312
		pr_err("unable to add child device object (relid %d)\n",
313
			   newchannel->offermsg.child_relid);
314

315
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
316
		list_del(&newchannel->listentry);
317
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
K
K. Y. Srinivasan 已提交
318
		kfree(newchannel->device_obj);
319

320
		free_channel(newchannel);
321
	} else {
322 323 324 325 326
		/*
		 * This state is used to indicate a successful open
		 * so that when we do close the channel normally, we
		 * can cleanup properly
		 */
327
		newchannel->state = CHANNEL_OPEN_STATE;
328 329 330
	}
}

331 332 333 334 335 336 337 338
enum {
	IDE = 0,
	SCSI,
	NIC,
	MAX_PERF_CHN,
};

/*
339
 * This is an array of device_ids (device types) that are performance critical.
340 341 342
 * We attempt to distribute the interrupt load for these devices across
 * all available CPUs.
 */
343
static const struct hv_vmbus_device_id hp_devs[] = {
344
	/* IDE */
345
	{ HV_IDE_GUID, },
346
	/* Storage - SCSI */
347
	{ HV_SCSI_GUID, },
348
	/* Network */
349
	{ HV_NIC_GUID, },
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
};


/*
 * We use this state to statically distribute the channel interrupt load.
 */
static u32  next_vp;

/*
 * Starting with Win8, we can statically distribute the incoming
 * channel interrupt load by binding a channel to VCPU. We
 * implement here a simple round robin scheme for distributing
 * the interrupt load.
 * We will bind channels that are not performance critical to cpu 0 and
 * performance critical channels (IDE, SCSI and Network) will be uniformly
 * distributed across all available CPUs.
 */
static u32 get_vp_index(uuid_le *type_guid)
{
	u32 cur_cpu;
	int i;
	bool perf_chn = false;
	u32 max_cpus = num_online_cpus();

	for (i = IDE; i < MAX_PERF_CHN; i++) {
375
		if (!memcmp(type_guid->b, hp_devs[i].guid,
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
				 sizeof(uuid_le))) {
			perf_chn = true;
			break;
		}
	}
	if ((vmbus_proto_version == VERSION_WS2008) ||
	    (vmbus_proto_version == VERSION_WIN7) || (!perf_chn)) {
		/*
		 * Prior to win8, all channel interrupts are
		 * delivered on cpu 0.
		 * Also if the channel is not a performance critical
		 * channel, bind it to cpu 0.
		 */
		return 0;
	}
	cur_cpu = (++next_vp % max_cpus);
392
	return hv_context.vp_index[cur_cpu];
393 394
}

395
/*
396
 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
397 398
 *
 */
399
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
400
{
401
	struct vmbus_channel_offer_channel *offer;
402
	struct vmbus_channel *newchannel;
403

404
	offer = (struct vmbus_channel_offer_channel *)hdr;
405

406
	/* Allocate the channel object and save this offer. */
407
	newchannel = alloc_channel();
408
	if (!newchannel) {
409
		pr_err("Unable to allocate channel object\n");
410 411 412
		return;
	}

413 414 415 416 417 418 419
	/*
	 * By default we setup state to enable batched
	 * reading. A specific service can choose to
	 * disable this prior to opening the channel.
	 */
	newchannel->batched_reading = true;

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	/*
	 * Setup state for signalling the host.
	 */
	newchannel->sig_event = (struct hv_input_signal_event *)
				(ALIGN((unsigned long)
				&newchannel->sig_buf,
				HV_HYPERCALL_PARAM_ALIGN));

	newchannel->sig_event->connectionid.asu32 = 0;
	newchannel->sig_event->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID;
	newchannel->sig_event->flag_number = 0;
	newchannel->sig_event->rsvdz = 0;

	if (vmbus_proto_version != VERSION_WS2008) {
		newchannel->is_dedicated_interrupt =
				(offer->is_dedicated_interrupt != 0);
		newchannel->sig_event->connectionid.u.id =
				offer->connection_id;
	}

440
	newchannel->target_vp = get_vp_index(&offer->offer.if_type);
441

442
	memcpy(&newchannel->offermsg, offer,
443
	       sizeof(struct vmbus_channel_offer_channel));
444 445
	newchannel->monitor_grp = (u8)offer->monitorid / 32;
	newchannel->monitor_bit = (u8)offer->monitorid % 32;
446

447 448
	INIT_WORK(&newchannel->work, vmbus_process_offer);
	queue_work(newchannel->controlwq, &newchannel->work);
449 450
}

451
/*
452
 * vmbus_onoffer_rescind - Rescind offer handler.
453 454 455
 *
 * We queue a work item to process this offer synchronously
 */
456
static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
457
{
458
	struct vmbus_channel_rescind_offer *rescind;
459
	struct vmbus_channel *channel;
460

461
	rescind = (struct vmbus_channel_rescind_offer *)hdr;
462
	channel = relid2channel(rescind->child_relid);
463 464 465

	if (channel == NULL)
		/* Just return here, no channel found */
466 467
		return;

468 469 470
	/* work is initialized for vmbus_process_rescind_offer() from
	 * vmbus_process_offer() where the channel got created */
	queue_work(channel->controlwq, &channel->work);
471 472
}

473
/*
474 475
 * vmbus_onoffers_delivered -
 * This is invoked when all offers have been delivered.
476 477 478
 *
 * Nothing to do here.
 */
479
static void vmbus_onoffers_delivered(
480
			struct vmbus_channel_message_header *hdr)
481 482 483
{
}

484
/*
485
 * vmbus_onopen_result - Open result handler.
486 487 488 489 490
 *
 * This is invoked when we received a response to our channel open request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
491
static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
492
{
493
	struct vmbus_channel_open_result *result;
494 495 496
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_open_channel *openmsg;
497
	unsigned long flags;
498

499
	result = (struct vmbus_channel_open_result *)hdr;
500

501 502 503
	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
504
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
505

506 507
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
508
		requestheader =
509
			(struct vmbus_channel_message_header *)msginfo->msg;
510

511
		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
512
			openmsg =
513 514 515 516
			(struct vmbus_channel_open_channel *)msginfo->msg;
			if (openmsg->child_relid == result->child_relid &&
			    openmsg->openid == result->openid) {
				memcpy(&msginfo->response.open_result,
517
				       result,
518 519 520
				       sizeof(
					struct vmbus_channel_open_result));
				complete(&msginfo->waitevent);
521 522 523 524
				break;
			}
		}
	}
525
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
526 527
}

528
/*
529
 * vmbus_ongpadl_created - GPADL created handler.
530 531 532 533 534
 *
 * This is invoked when we received a response to our gpadl create request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
535
static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
536
{
537 538 539 540
	struct vmbus_channel_gpadl_created *gpadlcreated;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_header *gpadlheader;
541
	unsigned long flags;
542

543
	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
544

545 546 547 548
	/*
	 * Find the establish msg, copy the result and signal/unblock the wait
	 * event
	 */
549
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
550

551 552
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
553
		requestheader =
554
			(struct vmbus_channel_message_header *)msginfo->msg;
555

556
		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
557 558 559
			gpadlheader =
			(struct vmbus_channel_gpadl_header *)requestheader;

560 561 562 563
			if ((gpadlcreated->child_relid ==
			     gpadlheader->child_relid) &&
			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
				memcpy(&msginfo->response.gpadl_created,
564
				       gpadlcreated,
565 566 567
				       sizeof(
					struct vmbus_channel_gpadl_created));
				complete(&msginfo->waitevent);
568 569 570 571
				break;
			}
		}
	}
572
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
573 574
}

575
/*
576
 * vmbus_ongpadl_torndown - GPADL torndown handler.
577 578 579 580 581
 *
 * This is invoked when we received a response to our gpadl teardown request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
582
static void vmbus_ongpadl_torndown(
583
			struct vmbus_channel_message_header *hdr)
584
{
585 586 587 588
	struct vmbus_channel_gpadl_torndown *gpadl_torndown;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_teardown *gpadl_teardown;
589
	unsigned long flags;
590

591
	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
592 593 594 595

	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
596
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
597

598 599
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
600
		requestheader =
601
			(struct vmbus_channel_message_header *)msginfo->msg;
602

603
		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
604 605
			gpadl_teardown =
			(struct vmbus_channel_gpadl_teardown *)requestheader;
606

607 608
			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
				memcpy(&msginfo->response.gpadl_torndown,
609
				       gpadl_torndown,
610 611 612
				       sizeof(
					struct vmbus_channel_gpadl_torndown));
				complete(&msginfo->waitevent);
613 614 615 616
				break;
			}
		}
	}
617
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
618 619
}

620
/*
621
 * vmbus_onversion_response - Version response handler
622 623 624 625 626
 *
 * This is invoked when we received a response to our initiate contact request.
 * Find the matching request, copy the response and signal the requesting
 * thread.
 */
627
static void vmbus_onversion_response(
628
		struct vmbus_channel_message_header *hdr)
629
{
630 631 632
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_version_response *version_response;
633
	unsigned long flags;
634

635
	version_response = (struct vmbus_channel_version_response *)hdr;
636
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
637

638 639
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
640
		requestheader =
641
			(struct vmbus_channel_message_header *)msginfo->msg;
642

643 644 645
		if (requestheader->msgtype ==
		    CHANNELMSG_INITIATE_CONTACT) {
			memcpy(&msginfo->response.version_response,
646
			      version_response,
647
			      sizeof(struct vmbus_channel_version_response));
648
			complete(&msginfo->waitevent);
649 650
		}
	}
651
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
652 653
}

654 655
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
656
	channel_message_table[CHANNELMSG_COUNT] = {
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
	{CHANNELMSG_INVALID,			NULL},
	{CHANNELMSG_OFFERCHANNEL,		vmbus_onoffer},
	{CHANNELMSG_RESCIND_CHANNELOFFER,	vmbus_onoffer_rescind},
	{CHANNELMSG_REQUESTOFFERS,		NULL},
	{CHANNELMSG_ALLOFFERS_DELIVERED,	vmbus_onoffers_delivered},
	{CHANNELMSG_OPENCHANNEL,		NULL},
	{CHANNELMSG_OPENCHANNEL_RESULT,	vmbus_onopen_result},
	{CHANNELMSG_CLOSECHANNEL,		NULL},
	{CHANNELMSG_GPADL_HEADER,		NULL},
	{CHANNELMSG_GPADL_BODY,		NULL},
	{CHANNELMSG_GPADL_CREATED,		vmbus_ongpadl_created},
	{CHANNELMSG_GPADL_TEARDOWN,		NULL},
	{CHANNELMSG_GPADL_TORNDOWN,		vmbus_ongpadl_torndown},
	{CHANNELMSG_RELID_RELEASED,		NULL},
	{CHANNELMSG_INITIATE_CONTACT,		NULL},
	{CHANNELMSG_VERSION_RESPONSE,		vmbus_onversion_response},
	{CHANNELMSG_UNLOAD,			NULL},
674 675
};

676
/*
677
 * vmbus_onmessage - Handler for channel protocol messages.
678 679 680
 *
 * This is invoked in the vmbus worker thread context.
 */
681
void vmbus_onmessage(void *context)
682
{
683
	struct hv_message *msg = context;
684
	struct vmbus_channel_message_header *hdr;
685 686
	int size;

687 688
	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
	size = msg->header.payload_size;
689

690
	if (hdr->msgtype >= CHANNELMSG_COUNT) {
691
		pr_err("Received invalid channel message type %d size %d\n",
692
			   hdr->msgtype, size);
693
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
694
				     (unsigned char *)msg->u.payload, size);
695 696 697
		return;
	}

698 699
	if (channel_message_table[hdr->msgtype].message_handler)
		channel_message_table[hdr->msgtype].message_handler(hdr);
700
	else
701
		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
702 703
}

704
/*
705
 * vmbus_request_offers - Send a request to get all our pending offers.
706
 */
707
int vmbus_request_offers(void)
708
{
709
	struct vmbus_channel_message_header *msg;
710
	struct vmbus_channel_msginfo *msginfo;
711
	int ret, t;
712

713
	msginfo = kmalloc(sizeof(*msginfo) +
714 715
			  sizeof(struct vmbus_channel_message_header),
			  GFP_KERNEL);
716
	if (!msginfo)
717
		return -ENOMEM;
718

719
	init_completion(&msginfo->waitevent);
720

721
	msg = (struct vmbus_channel_message_header *)msginfo->msg;
722

723
	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
724 725


726
	ret = vmbus_post_msg(msg,
727 728
			       sizeof(struct vmbus_channel_message_header));
	if (ret != 0) {
729
		pr_err("Unable to request offers - %d\n", ret);
730

731 732
		goto cleanup;
	}
733

734
	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
735
	if (t == 0) {
736 737
		ret = -ETIMEDOUT;
		goto cleanup;
738 739 740 741
	}



742
cleanup:
743
	kfree(msginfo);
744 745 746 747

	return ret;
}

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
/*
 * Retrieve the (sub) channel on which to send an outgoing request.
 * When a primary channel has multiple sub-channels, we choose a
 * channel whose VCPU binding is closest to the VCPU on which
 * this call is being made.
 */
struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
{
	struct list_head *cur, *tmp;
	int cur_cpu = hv_context.vp_index[smp_processor_id()];
	struct vmbus_channel *cur_channel;
	struct vmbus_channel *outgoing_channel = primary;
	int cpu_distance, new_cpu_distance;

	if (list_empty(&primary->sc_list))
		return outgoing_channel;

	list_for_each_safe(cur, tmp, &primary->sc_list) {
		cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
		if (cur_channel->state != CHANNEL_OPENED_STATE)
			continue;

		if (cur_channel->target_vp == cur_cpu)
			return cur_channel;

		cpu_distance = ((outgoing_channel->target_vp > cur_cpu) ?
				(outgoing_channel->target_vp - cur_cpu) :
				(cur_cpu - outgoing_channel->target_vp));

		new_cpu_distance = ((cur_channel->target_vp > cur_cpu) ?
				(cur_channel->target_vp - cur_cpu) :
				(cur_cpu - cur_channel->target_vp));

		if (cpu_distance < new_cpu_distance)
			continue;

		outgoing_channel = cur_channel;
	}

	return outgoing_channel;
}
EXPORT_SYMBOL_GPL(vmbus_get_outgoing_channel);

static void invoke_sc_cb(struct vmbus_channel *primary_channel)
{
	struct list_head *cur, *tmp;
	struct vmbus_channel *cur_channel;

	if (primary_channel->sc_creation_callback == NULL)
		return;

	list_for_each_safe(cur, tmp, &primary_channel->sc_list) {
		cur_channel = list_entry(cur, struct vmbus_channel, sc_list);

		primary_channel->sc_creation_callback(cur_channel);
	}
}

void vmbus_set_sc_create_callback(struct vmbus_channel *primary_channel,
				void (*sc_cr_cb)(struct vmbus_channel *new_sc))
{
	primary_channel->sc_creation_callback = sc_cr_cb;
}
EXPORT_SYMBOL_GPL(vmbus_set_sc_create_callback);

bool vmbus_are_subchannels_present(struct vmbus_channel *primary)
{
	bool ret;

	ret = !list_empty(&primary->sc_list);

	if (ret) {
		/*
		 * Invoke the callback on sub-channel creation.
		 * This will present a uniform interface to the
		 * clients.
		 */
		invoke_sc_cb(primary);
	}

	return ret;
}
EXPORT_SYMBOL_GPL(vmbus_are_subchannels_present);