channel_mgmt.c 23.4 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
	INIT_LIST_HEAD(&channel->percpu_list);
153

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

	return channel;
}

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

172
	destroy_workqueue(channel->controlwq);
173

174
	kfree(channel);
175 176
}

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

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

192 193 194 195 196 197 198
static void percpu_channel_enq(void *arg)
{
	struct vmbus_channel *channel = arg;
	int cpu = smp_processor_id();

	list_add_tail(&channel->percpu_list, &hv_context.percpu_list[cpu]);
}
199

200 201 202 203 204 205
static void percpu_channel_deq(void *arg)
{
	struct vmbus_channel *channel = arg;

	list_del(&channel->percpu_list);
}
206

207 208 209 210 211 212 213 214 215
/*
 * 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);
216
	unsigned long flags;
217
	struct vmbus_channel *primary_channel;
218
	struct vmbus_channel_relid_released msg;
219

220 221
	if (channel->device_obj)
		vmbus_device_unregister(channel->device_obj);
222 223 224 225 226
	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));

227 228 229 230 231 232
	if (channel->target_cpu != smp_processor_id())
		smp_call_function_single(channel->target_cpu,
					 percpu_channel_deq, channel, true);
	else
		percpu_channel_deq(channel);

233 234 235 236 237 238 239
	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);
240
		list_del(&channel->sc_list);
241 242
		spin_unlock_irqrestore(&primary_channel->sc_lock, flags);
	}
243
	free_channel(channel);
244
}
245

246 247 248 249 250 251 252 253 254 255 256
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);
	}
}

257
/*
258
 * vmbus_process_offer - Process the offer by creating a channel/device
259
 * associated with this offer
260
 */
261
static void vmbus_process_offer(struct work_struct *work)
262
{
263 264 265
	struct vmbus_channel *newchannel = container_of(work,
							struct vmbus_channel,
							work);
266
	struct vmbus_channel *channel;
267
	bool fnew = true;
268
	bool enq = false;
269
	int ret;
270
	unsigned long flags;
271

272 273 274
	/* The next possible work is rescind handling */
	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);

275
	/* Make sure this is a new offer */
276
	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
277

278
	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
279 280 281 282
		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)) {
283
			fnew = false;
284 285 286 287
			break;
		}
	}

288
	if (fnew) {
289
		list_add_tail(&newchannel->listentry,
290
			      &vmbus_connection.chn_list);
291 292
		enq = true;
	}
293

294
	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
295

296 297 298 299 300 301 302 303
	if (enq) {
		if (newchannel->target_cpu != smp_processor_id())
			smp_call_function_single(newchannel->target_cpu,
						 percpu_channel_enq,
						 newchannel, true);
		else
			percpu_channel_enq(newchannel);
	}
304
	if (!fnew) {
305 306 307 308 309 310 311 312 313 314 315
		/*
		 * 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);
316 317 318 319 320 321 322 323

			if (newchannel->target_cpu != smp_processor_id())
				smp_call_function_single(newchannel->target_cpu,
							 percpu_channel_enq,
							 newchannel, true);
			else
				percpu_channel_enq(newchannel);

324 325 326 327 328 329 330
			newchannel->state = CHANNEL_OPEN_STATE;
			if (channel->sc_creation_callback != NULL)
				channel->sc_creation_callback(newchannel);

			return;
		}

331
		free_channel(newchannel);
332 333 334
		return;
	}

335 336 337 338 339 340 341
	/*
	 * This state is used to indicate a successful open
	 * so that when we do close the channel normally, we
	 * can cleanup properly
	 */
	newchannel->state = CHANNEL_OPEN_STATE;

342 343 344
	/*
	 * Start the process of binding this offer to the driver
	 * We need to set the DeviceObject field before calling
345
	 * vmbus_child_dev_add()
346
	 */
347
	newchannel->device_obj = vmbus_device_create(
348 349
		&newchannel->offermsg.offer.if_type,
		&newchannel->offermsg.offer.if_instance,
350
		newchannel);
351

352 353 354 355 356
	/*
	 * Add the new device to the bus. This will kick off device-driver
	 * binding which eventually invokes the device driver's AddDevice()
	 * method.
	 */
357
	ret = vmbus_device_register(newchannel->device_obj);
358
	if (ret != 0) {
359
		pr_err("unable to add child device object (relid %d)\n",
360
			   newchannel->offermsg.child_relid);
361

362
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
363
		list_del(&newchannel->listentry);
364
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
K
K. Y. Srinivasan 已提交
365
		kfree(newchannel->device_obj);
366

367
		free_channel(newchannel);
368 369 370
	}
}

371 372 373 374 375 376 377 378
enum {
	IDE = 0,
	SCSI,
	NIC,
	MAX_PERF_CHN,
};

/*
379
 * This is an array of device_ids (device types) that are performance critical.
380 381 382
 * We attempt to distribute the interrupt load for these devices across
 * all available CPUs.
 */
383
static const struct hv_vmbus_device_id hp_devs[] = {
384
	/* IDE */
385
	{ HV_IDE_GUID, },
386
	/* Storage - SCSI */
387
	{ HV_SCSI_GUID, },
388
	/* Network */
389
	{ HV_NIC_GUID, },
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
};


/*
 * 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.
 */
407
static void init_vp_index(struct vmbus_channel *channel, uuid_le *type_guid)
408 409 410 411 412 413 414
{
	u32 cur_cpu;
	int i;
	bool perf_chn = false;
	u32 max_cpus = num_online_cpus();

	for (i = IDE; i < MAX_PERF_CHN; i++) {
415
		if (!memcmp(type_guid->b, hp_devs[i].guid,
416 417 418 419 420 421 422 423 424 425 426 427 428
				 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.
		 */
429 430 431
		channel->target_cpu = 0;
		channel->target_vp = 0;
		return;
432 433
	}
	cur_cpu = (++next_vp % max_cpus);
434 435
	channel->target_cpu = cur_cpu;
	channel->target_vp = hv_context.vp_index[cur_cpu];
436 437
}

438
/*
439
 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
440 441
 *
 */
442
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
443
{
444
	struct vmbus_channel_offer_channel *offer;
445
	struct vmbus_channel *newchannel;
446

447
	offer = (struct vmbus_channel_offer_channel *)hdr;
448

449
	/* Allocate the channel object and save this offer. */
450
	newchannel = alloc_channel();
451
	if (!newchannel) {
452
		pr_err("Unable to allocate channel object\n");
453 454 455
		return;
	}

456 457 458 459 460 461 462
	/*
	 * 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;

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
	/*
	 * 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;
	}

483
	init_vp_index(newchannel, &offer->offer.if_type);
484

485
	memcpy(&newchannel->offermsg, offer,
486
	       sizeof(struct vmbus_channel_offer_channel));
487 488
	newchannel->monitor_grp = (u8)offer->monitorid / 32;
	newchannel->monitor_bit = (u8)offer->monitorid % 32;
489

490 491
	INIT_WORK(&newchannel->work, vmbus_process_offer);
	queue_work(newchannel->controlwq, &newchannel->work);
492 493
}

494
/*
495
 * vmbus_onoffer_rescind - Rescind offer handler.
496 497 498
 *
 * We queue a work item to process this offer synchronously
 */
499
static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
500
{
501
	struct vmbus_channel_rescind_offer *rescind;
502
	struct vmbus_channel *channel;
503

504
	rescind = (struct vmbus_channel_rescind_offer *)hdr;
505
	channel = relid2channel(rescind->child_relid);
506 507 508

	if (channel == NULL)
		/* Just return here, no channel found */
509 510
		return;

511 512 513
	/* work is initialized for vmbus_process_rescind_offer() from
	 * vmbus_process_offer() where the channel got created */
	queue_work(channel->controlwq, &channel->work);
514 515
}

516
/*
517 518
 * vmbus_onoffers_delivered -
 * This is invoked when all offers have been delivered.
519 520 521
 *
 * Nothing to do here.
 */
522
static void vmbus_onoffers_delivered(
523
			struct vmbus_channel_message_header *hdr)
524 525 526
{
}

527
/*
528
 * vmbus_onopen_result - Open result handler.
529 530 531 532 533
 *
 * 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.
 */
534
static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
535
{
536
	struct vmbus_channel_open_result *result;
537 538 539
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_open_channel *openmsg;
540
	unsigned long flags;
541

542
	result = (struct vmbus_channel_open_result *)hdr;
543

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

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

554
		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
555
			openmsg =
556 557 558 559
			(struct vmbus_channel_open_channel *)msginfo->msg;
			if (openmsg->child_relid == result->child_relid &&
			    openmsg->openid == result->openid) {
				memcpy(&msginfo->response.open_result,
560
				       result,
561 562 563
				       sizeof(
					struct vmbus_channel_open_result));
				complete(&msginfo->waitevent);
564 565 566 567
				break;
			}
		}
	}
568
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
569 570
}

571
/*
572
 * vmbus_ongpadl_created - GPADL created handler.
573 574 575 576 577
 *
 * 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.
 */
578
static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
579
{
580 581 582 583
	struct vmbus_channel_gpadl_created *gpadlcreated;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_header *gpadlheader;
584
	unsigned long flags;
585

586
	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
587

588 589 590 591
	/*
	 * Find the establish msg, copy the result and signal/unblock the wait
	 * event
	 */
592
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
593

594 595
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
596
		requestheader =
597
			(struct vmbus_channel_message_header *)msginfo->msg;
598

599
		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
600 601 602
			gpadlheader =
			(struct vmbus_channel_gpadl_header *)requestheader;

603 604 605 606
			if ((gpadlcreated->child_relid ==
			     gpadlheader->child_relid) &&
			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
				memcpy(&msginfo->response.gpadl_created,
607
				       gpadlcreated,
608 609 610
				       sizeof(
					struct vmbus_channel_gpadl_created));
				complete(&msginfo->waitevent);
611 612 613 614
				break;
			}
		}
	}
615
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
616 617
}

618
/*
619
 * vmbus_ongpadl_torndown - GPADL torndown handler.
620 621 622 623 624
 *
 * 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.
 */
625
static void vmbus_ongpadl_torndown(
626
			struct vmbus_channel_message_header *hdr)
627
{
628 629 630 631
	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;
632
	unsigned long flags;
633

634
	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
635 636 637 638

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

641 642
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
643
		requestheader =
644
			(struct vmbus_channel_message_header *)msginfo->msg;
645

646
		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
647 648
			gpadl_teardown =
			(struct vmbus_channel_gpadl_teardown *)requestheader;
649

650 651
			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
				memcpy(&msginfo->response.gpadl_torndown,
652
				       gpadl_torndown,
653 654 655
				       sizeof(
					struct vmbus_channel_gpadl_torndown));
				complete(&msginfo->waitevent);
656 657 658 659
				break;
			}
		}
	}
660
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
661 662
}

663
/*
664
 * vmbus_onversion_response - Version response handler
665 666 667 668 669
 *
 * 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.
 */
670
static void vmbus_onversion_response(
671
		struct vmbus_channel_message_header *hdr)
672
{
673 674 675
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_version_response *version_response;
676
	unsigned long flags;
677

678
	version_response = (struct vmbus_channel_version_response *)hdr;
679
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
680

681 682
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
683
		requestheader =
684
			(struct vmbus_channel_message_header *)msginfo->msg;
685

686 687 688
		if (requestheader->msgtype ==
		    CHANNELMSG_INITIATE_CONTACT) {
			memcpy(&msginfo->response.version_response,
689
			      version_response,
690
			      sizeof(struct vmbus_channel_version_response));
691
			complete(&msginfo->waitevent);
692 693
		}
	}
694
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
695 696
}

697 698
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
699
	channel_message_table[CHANNELMSG_COUNT] = {
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
	{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},
717 718
};

719
/*
720
 * vmbus_onmessage - Handler for channel protocol messages.
721 722 723
 *
 * This is invoked in the vmbus worker thread context.
 */
724
void vmbus_onmessage(void *context)
725
{
726
	struct hv_message *msg = context;
727
	struct vmbus_channel_message_header *hdr;
728 729
	int size;

730 731
	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
	size = msg->header.payload_size;
732

733
	if (hdr->msgtype >= CHANNELMSG_COUNT) {
734
		pr_err("Received invalid channel message type %d size %d\n",
735
			   hdr->msgtype, size);
736
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
737
				     (unsigned char *)msg->u.payload, size);
738 739 740
		return;
	}

741 742
	if (channel_message_table[hdr->msgtype].message_handler)
		channel_message_table[hdr->msgtype].message_handler(hdr);
743
	else
744
		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
745 746
}

747
/*
748
 * vmbus_request_offers - Send a request to get all our pending offers.
749
 */
750
int vmbus_request_offers(void)
751
{
752
	struct vmbus_channel_message_header *msg;
753
	struct vmbus_channel_msginfo *msginfo;
754
	int ret, t;
755

756
	msginfo = kmalloc(sizeof(*msginfo) +
757 758
			  sizeof(struct vmbus_channel_message_header),
			  GFP_KERNEL);
759
	if (!msginfo)
760
		return -ENOMEM;
761

762
	init_completion(&msginfo->waitevent);
763

764
	msg = (struct vmbus_channel_message_header *)msginfo->msg;
765

766
	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
767 768


769
	ret = vmbus_post_msg(msg,
770 771
			       sizeof(struct vmbus_channel_message_header));
	if (ret != 0) {
772
		pr_err("Unable to request offers - %d\n", ret);
773

774 775
		goto cleanup;
	}
776

777
	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
778
	if (t == 0) {
779 780
		ret = -ETIMEDOUT;
		goto cleanup;
781 782 783 784
	}



785
cleanup:
786
	kfree(msginfo);
787 788 789 790

	return ret;
}

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 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
/*
 * 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);