channel_mgmt.c 23.5 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
	if (channel->target_cpu != get_cpu()) {
		put_cpu();
229 230
		smp_call_function_single(channel->target_cpu,
					 percpu_channel_deq, channel, true);
231
	} else {
232
		percpu_channel_deq(channel);
233 234
		put_cpu();
	}
235

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

249 250 251 252 253 254 255 256 257 258 259
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);
	}
}

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

275 276 277
	/* The next possible work is rescind handling */
	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);

278
	/* Make sure this is a new offer */
279
	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
280

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

291
	if (fnew) {
292
		list_add_tail(&newchannel->listentry,
293
			      &vmbus_connection.chn_list);
294 295
		enq = true;
	}
296

297
	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
298

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

323 324
			if (newchannel->target_cpu != get_cpu()) {
				put_cpu();
325 326 327
				smp_call_function_single(newchannel->target_cpu,
							 percpu_channel_enq,
							 newchannel, true);
328
			} else {
329
				percpu_channel_enq(newchannel);
330 331
				put_cpu();
			}
332

333 334 335 336 337 338 339
			newchannel->state = CHANNEL_OPEN_STATE;
			if (channel->sc_creation_callback != NULL)
				channel->sc_creation_callback(newchannel);

			return;
		}

340
		free_channel(newchannel);
341 342 343
		return;
	}

344 345 346 347 348 349 350
	/*
	 * 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;

351 352 353
	/*
	 * Start the process of binding this offer to the driver
	 * We need to set the DeviceObject field before calling
354
	 * vmbus_child_dev_add()
355
	 */
356
	newchannel->device_obj = vmbus_device_create(
357 358
		&newchannel->offermsg.offer.if_type,
		&newchannel->offermsg.offer.if_instance,
359
		newchannel);
360

361 362 363 364 365
	/*
	 * Add the new device to the bus. This will kick off device-driver
	 * binding which eventually invokes the device driver's AddDevice()
	 * method.
	 */
366
	ret = vmbus_device_register(newchannel->device_obj);
367
	if (ret != 0) {
368
		pr_err("unable to add child device object (relid %d)\n",
369
			   newchannel->offermsg.child_relid);
370

371
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
372
		list_del(&newchannel->listentry);
373
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
K
K. Y. Srinivasan 已提交
374
		kfree(newchannel->device_obj);
375

376
		free_channel(newchannel);
377 378 379
	}
}

380 381 382 383 384 385 386 387
enum {
	IDE = 0,
	SCSI,
	NIC,
	MAX_PERF_CHN,
};

/*
388
 * This is an array of device_ids (device types) that are performance critical.
389 390 391
 * We attempt to distribute the interrupt load for these devices across
 * all available CPUs.
 */
392
static const struct hv_vmbus_device_id hp_devs[] = {
393
	/* IDE */
394
	{ HV_IDE_GUID, },
395
	/* Storage - SCSI */
396
	{ HV_SCSI_GUID, },
397
	/* Network */
398
	{ HV_NIC_GUID, },
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
};


/*
 * 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.
 */
416
static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid)
417 418 419 420 421 422 423
{
	u32 cur_cpu;
	int i;
	bool perf_chn = false;
	u32 max_cpus = num_online_cpus();

	for (i = IDE; i < MAX_PERF_CHN; i++) {
424
		if (!memcmp(type_guid->b, hp_devs[i].guid,
425 426 427 428 429 430 431 432 433 434 435 436 437
				 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.
		 */
438 439 440
		channel->target_cpu = 0;
		channel->target_vp = 0;
		return;
441 442
	}
	cur_cpu = (++next_vp % max_cpus);
443 444
	channel->target_cpu = cur_cpu;
	channel->target_vp = hv_context.vp_index[cur_cpu];
445 446
}

447
/*
448
 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
449 450
 *
 */
451
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
452
{
453
	struct vmbus_channel_offer_channel *offer;
454
	struct vmbus_channel *newchannel;
455

456
	offer = (struct vmbus_channel_offer_channel *)hdr;
457

458
	/* Allocate the channel object and save this offer. */
459
	newchannel = alloc_channel();
460
	if (!newchannel) {
461
		pr_err("Unable to allocate channel object\n");
462 463 464
		return;
	}

465 466 467 468 469 470 471
	/*
	 * 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;

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
	/*
	 * 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;
	}

492
	init_vp_index(newchannel, &offer->offer.if_type);
493

494
	memcpy(&newchannel->offermsg, offer,
495
	       sizeof(struct vmbus_channel_offer_channel));
496 497
	newchannel->monitor_grp = (u8)offer->monitorid / 32;
	newchannel->monitor_bit = (u8)offer->monitorid % 32;
498

499 500
	INIT_WORK(&newchannel->work, vmbus_process_offer);
	queue_work(newchannel->controlwq, &newchannel->work);
501 502
}

503
/*
504
 * vmbus_onoffer_rescind - Rescind offer handler.
505 506 507
 *
 * We queue a work item to process this offer synchronously
 */
508
static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
509
{
510
	struct vmbus_channel_rescind_offer *rescind;
511
	struct vmbus_channel *channel;
512

513
	rescind = (struct vmbus_channel_rescind_offer *)hdr;
514
	channel = relid2channel(rescind->child_relid);
515 516 517

	if (channel == NULL)
		/* Just return here, no channel found */
518 519
		return;

520 521 522
	/* work is initialized for vmbus_process_rescind_offer() from
	 * vmbus_process_offer() where the channel got created */
	queue_work(channel->controlwq, &channel->work);
523 524
}

525
/*
526 527
 * vmbus_onoffers_delivered -
 * This is invoked when all offers have been delivered.
528 529 530
 *
 * Nothing to do here.
 */
531
static void vmbus_onoffers_delivered(
532
			struct vmbus_channel_message_header *hdr)
533 534 535
{
}

536
/*
537
 * vmbus_onopen_result - Open result handler.
538 539 540 541 542
 *
 * 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.
 */
543
static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
544
{
545
	struct vmbus_channel_open_result *result;
546 547 548
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_open_channel *openmsg;
549
	unsigned long flags;
550

551
	result = (struct vmbus_channel_open_result *)hdr;
552

553 554 555
	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
556
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
557

558 559
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
560
		requestheader =
561
			(struct vmbus_channel_message_header *)msginfo->msg;
562

563
		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
564
			openmsg =
565 566 567 568
			(struct vmbus_channel_open_channel *)msginfo->msg;
			if (openmsg->child_relid == result->child_relid &&
			    openmsg->openid == result->openid) {
				memcpy(&msginfo->response.open_result,
569
				       result,
570 571 572
				       sizeof(
					struct vmbus_channel_open_result));
				complete(&msginfo->waitevent);
573 574 575 576
				break;
			}
		}
	}
577
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
578 579
}

580
/*
581
 * vmbus_ongpadl_created - GPADL created handler.
582 583 584 585 586
 *
 * 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.
 */
587
static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
588
{
589 590 591 592
	struct vmbus_channel_gpadl_created *gpadlcreated;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_header *gpadlheader;
593
	unsigned long flags;
594

595
	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
596

597 598 599 600
	/*
	 * Find the establish msg, copy the result and signal/unblock the wait
	 * event
	 */
601
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
602

603 604
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
605
		requestheader =
606
			(struct vmbus_channel_message_header *)msginfo->msg;
607

608
		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
609 610 611
			gpadlheader =
			(struct vmbus_channel_gpadl_header *)requestheader;

612 613 614 615
			if ((gpadlcreated->child_relid ==
			     gpadlheader->child_relid) &&
			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
				memcpy(&msginfo->response.gpadl_created,
616
				       gpadlcreated,
617 618 619
				       sizeof(
					struct vmbus_channel_gpadl_created));
				complete(&msginfo->waitevent);
620 621 622 623
				break;
			}
		}
	}
624
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
625 626
}

627
/*
628
 * vmbus_ongpadl_torndown - GPADL torndown handler.
629 630 631 632 633
 *
 * 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.
 */
634
static void vmbus_ongpadl_torndown(
635
			struct vmbus_channel_message_header *hdr)
636
{
637 638 639 640
	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;
641
	unsigned long flags;
642

643
	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
644 645 646 647

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

650 651
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
652
		requestheader =
653
			(struct vmbus_channel_message_header *)msginfo->msg;
654

655
		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
656 657
			gpadl_teardown =
			(struct vmbus_channel_gpadl_teardown *)requestheader;
658

659 660
			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
				memcpy(&msginfo->response.gpadl_torndown,
661
				       gpadl_torndown,
662 663 664
				       sizeof(
					struct vmbus_channel_gpadl_torndown));
				complete(&msginfo->waitevent);
665 666 667 668
				break;
			}
		}
	}
669
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
670 671
}

672
/*
673
 * vmbus_onversion_response - Version response handler
674 675 676 677 678
 *
 * 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.
 */
679
static void vmbus_onversion_response(
680
		struct vmbus_channel_message_header *hdr)
681
{
682 683 684
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_version_response *version_response;
685
	unsigned long flags;
686

687
	version_response = (struct vmbus_channel_version_response *)hdr;
688
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
689

690 691
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
692
		requestheader =
693
			(struct vmbus_channel_message_header *)msginfo->msg;
694

695 696 697
		if (requestheader->msgtype ==
		    CHANNELMSG_INITIATE_CONTACT) {
			memcpy(&msginfo->response.version_response,
698
			      version_response,
699
			      sizeof(struct vmbus_channel_version_response));
700
			complete(&msginfo->waitevent);
701 702
		}
	}
703
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
704 705
}

706 707
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
708
	channel_message_table[CHANNELMSG_COUNT] = {
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
	{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},
726 727
};

728
/*
729
 * vmbus_onmessage - Handler for channel protocol messages.
730 731 732
 *
 * This is invoked in the vmbus worker thread context.
 */
733
void vmbus_onmessage(void *context)
734
{
735
	struct hv_message *msg = context;
736
	struct vmbus_channel_message_header *hdr;
737 738
	int size;

739 740
	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
	size = msg->header.payload_size;
741

742
	if (hdr->msgtype >= CHANNELMSG_COUNT) {
743
		pr_err("Received invalid channel message type %d size %d\n",
744
			   hdr->msgtype, size);
745
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
746
				     (unsigned char *)msg->u.payload, size);
747 748 749
		return;
	}

750 751
	if (channel_message_table[hdr->msgtype].message_handler)
		channel_message_table[hdr->msgtype].message_handler(hdr);
752
	else
753
		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
754 755
}

756
/*
757
 * vmbus_request_offers - Send a request to get all our pending offers.
758
 */
759
int vmbus_request_offers(void)
760
{
761
	struct vmbus_channel_message_header *msg;
762
	struct vmbus_channel_msginfo *msginfo;
763
	int ret, t;
764

765
	msginfo = kmalloc(sizeof(*msginfo) +
766 767
			  sizeof(struct vmbus_channel_message_header),
			  GFP_KERNEL);
768
	if (!msginfo)
769
		return -ENOMEM;
770

771
	init_completion(&msginfo->waitevent);
772

773
	msg = (struct vmbus_channel_message_header *)msginfo->msg;
774

775
	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
776 777


778
	ret = vmbus_post_msg(msg,
779 780
			       sizeof(struct vmbus_channel_message_header));
	if (ret != 0) {
781
		pr_err("Unable to request offers - %d\n", ret);
782

783 784
		goto cleanup;
	}
785

786
	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
787
	if (t == 0) {
788 789
		ret = -ETIMEDOUT;
		goto cleanup;
790 791 792 793
	}



794
cleanup:
795
	kfree(msginfo);
796 797 798 799

	return ret;
}

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 874 875 876 877 878 879 880 881 882
/*
 * 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);