channel_mgmt.c 23.6 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 222 223 224 225 226 227
	struct device *dev;

	if (channel->device_obj) {
		dev = get_device(&channel->device_obj->device);
		if (dev) {
			vmbus_device_unregister(channel->device_obj);
			put_device(dev);
		}
	}
228

229 230 231 232 233
	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));

234 235
	if (channel->target_cpu != get_cpu()) {
		put_cpu();
236 237
		smp_call_function_single(channel->target_cpu,
					 percpu_channel_deq, channel, true);
238
	} else {
239
		percpu_channel_deq(channel);
240 241
		put_cpu();
	}
242

243 244 245 246 247 248 249
	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);
250
		list_del(&channel->sc_list);
251 252
		spin_unlock_irqrestore(&primary_channel->sc_lock, flags);
	}
253
	free_channel(channel);
254
}
255

256 257 258 259 260 261 262 263 264 265 266
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);
	}
}

267
/*
268
 * vmbus_process_offer - Process the offer by creating a channel/device
269
 * associated with this offer
270
 */
271
static void vmbus_process_offer(struct work_struct *work)
272
{
273 274 275
	struct vmbus_channel *newchannel = container_of(work,
							struct vmbus_channel,
							work);
276
	struct vmbus_channel *channel;
277
	bool fnew = true;
278
	bool enq = false;
279
	int ret;
280
	unsigned long flags;
281

282 283 284
	/* The next possible work is rescind handling */
	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);

285
	/* Make sure this is a new offer */
286
	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
287

288
	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
289 290 291 292
		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)) {
293
			fnew = false;
294 295 296 297
			break;
		}
	}

298
	if (fnew) {
299
		list_add_tail(&newchannel->listentry,
300
			      &vmbus_connection.chn_list);
301 302
		enq = true;
	}
303

304
	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
305

306
	if (enq) {
307 308
		if (newchannel->target_cpu != get_cpu()) {
			put_cpu();
309 310 311
			smp_call_function_single(newchannel->target_cpu,
						 percpu_channel_enq,
						 newchannel, true);
312
		} else {
313
			percpu_channel_enq(newchannel);
314 315
			put_cpu();
		}
316
	}
317
	if (!fnew) {
318 319 320 321 322 323 324 325 326 327 328
		/*
		 * 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);
329

330 331
			if (newchannel->target_cpu != get_cpu()) {
				put_cpu();
332 333 334
				smp_call_function_single(newchannel->target_cpu,
							 percpu_channel_enq,
							 newchannel, true);
335
			} else {
336
				percpu_channel_enq(newchannel);
337 338
				put_cpu();
			}
339

340 341 342 343 344 345 346
			newchannel->state = CHANNEL_OPEN_STATE;
			if (channel->sc_creation_callback != NULL)
				channel->sc_creation_callback(newchannel);

			return;
		}

347
		free_channel(newchannel);
348 349 350
		return;
	}

351 352 353 354 355 356 357
	/*
	 * 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;

358 359 360
	/*
	 * Start the process of binding this offer to the driver
	 * We need to set the DeviceObject field before calling
361
	 * vmbus_child_dev_add()
362
	 */
363
	newchannel->device_obj = vmbus_device_create(
364 365
		&newchannel->offermsg.offer.if_type,
		&newchannel->offermsg.offer.if_instance,
366
		newchannel);
367

368 369 370 371 372
	/*
	 * Add the new device to the bus. This will kick off device-driver
	 * binding which eventually invokes the device driver's AddDevice()
	 * method.
	 */
373
	ret = vmbus_device_register(newchannel->device_obj);
374
	if (ret != 0) {
375
		pr_err("unable to add child device object (relid %d)\n",
376
			   newchannel->offermsg.child_relid);
377

378
		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
379
		list_del(&newchannel->listentry);
380
		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
K
K. Y. Srinivasan 已提交
381
		kfree(newchannel->device_obj);
382

383
		free_channel(newchannel);
384 385 386
	}
}

387 388 389 390 391 392 393 394
enum {
	IDE = 0,
	SCSI,
	NIC,
	MAX_PERF_CHN,
};

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


/*
 * 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.
 */
423
static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid)
424 425 426 427 428 429 430
{
	u32 cur_cpu;
	int i;
	bool perf_chn = false;
	u32 max_cpus = num_online_cpus();

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

454
/*
455
 * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
456 457
 *
 */
458
static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
459
{
460
	struct vmbus_channel_offer_channel *offer;
461
	struct vmbus_channel *newchannel;
462

463
	offer = (struct vmbus_channel_offer_channel *)hdr;
464

465
	/* Allocate the channel object and save this offer. */
466
	newchannel = alloc_channel();
467
	if (!newchannel) {
468
		pr_err("Unable to allocate channel object\n");
469 470 471
		return;
	}

472 473 474 475 476 477 478
	/*
	 * 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;

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
	/*
	 * 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;
	}

499
	init_vp_index(newchannel, &offer->offer.if_type);
500

501
	memcpy(&newchannel->offermsg, offer,
502
	       sizeof(struct vmbus_channel_offer_channel));
503 504
	newchannel->monitor_grp = (u8)offer->monitorid / 32;
	newchannel->monitor_bit = (u8)offer->monitorid % 32;
505

506 507
	INIT_WORK(&newchannel->work, vmbus_process_offer);
	queue_work(newchannel->controlwq, &newchannel->work);
508 509
}

510
/*
511
 * vmbus_onoffer_rescind - Rescind offer handler.
512 513 514
 *
 * We queue a work item to process this offer synchronously
 */
515
static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
516
{
517
	struct vmbus_channel_rescind_offer *rescind;
518
	struct vmbus_channel *channel;
519

520
	rescind = (struct vmbus_channel_rescind_offer *)hdr;
521
	channel = relid2channel(rescind->child_relid);
522 523 524

	if (channel == NULL)
		/* Just return here, no channel found */
525 526
		return;

527 528
	channel->rescind = true;

529 530 531
	/* work is initialized for vmbus_process_rescind_offer() from
	 * vmbus_process_offer() where the channel got created */
	queue_work(channel->controlwq, &channel->work);
532 533
}

534
/*
535 536
 * vmbus_onoffers_delivered -
 * This is invoked when all offers have been delivered.
537 538 539
 *
 * Nothing to do here.
 */
540
static void vmbus_onoffers_delivered(
541
			struct vmbus_channel_message_header *hdr)
542 543 544
{
}

545
/*
546
 * vmbus_onopen_result - Open result handler.
547 548 549 550 551
 *
 * 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.
 */
552
static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
553
{
554
	struct vmbus_channel_open_result *result;
555 556 557
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_open_channel *openmsg;
558
	unsigned long flags;
559

560
	result = (struct vmbus_channel_open_result *)hdr;
561

562 563 564
	/*
	 * Find the open msg, copy the result and signal/unblock the wait event
	 */
565
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
566

567 568
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
569
		requestheader =
570
			(struct vmbus_channel_message_header *)msginfo->msg;
571

572
		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
573
			openmsg =
574 575 576 577
			(struct vmbus_channel_open_channel *)msginfo->msg;
			if (openmsg->child_relid == result->child_relid &&
			    openmsg->openid == result->openid) {
				memcpy(&msginfo->response.open_result,
578
				       result,
579 580 581
				       sizeof(
					struct vmbus_channel_open_result));
				complete(&msginfo->waitevent);
582 583 584 585
				break;
			}
		}
	}
586
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
587 588
}

589
/*
590
 * vmbus_ongpadl_created - GPADL created handler.
591 592 593 594 595
 *
 * 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.
 */
596
static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
597
{
598 599 600 601
	struct vmbus_channel_gpadl_created *gpadlcreated;
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_gpadl_header *gpadlheader;
602
	unsigned long flags;
603

604
	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
605

606 607 608 609
	/*
	 * Find the establish msg, copy the result and signal/unblock the wait
	 * event
	 */
610
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
611

612 613
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
614
		requestheader =
615
			(struct vmbus_channel_message_header *)msginfo->msg;
616

617
		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
618 619 620
			gpadlheader =
			(struct vmbus_channel_gpadl_header *)requestheader;

621 622 623 624
			if ((gpadlcreated->child_relid ==
			     gpadlheader->child_relid) &&
			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
				memcpy(&msginfo->response.gpadl_created,
625
				       gpadlcreated,
626 627 628
				       sizeof(
					struct vmbus_channel_gpadl_created));
				complete(&msginfo->waitevent);
629 630 631 632
				break;
			}
		}
	}
633
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
634 635
}

636
/*
637
 * vmbus_ongpadl_torndown - GPADL torndown handler.
638 639 640 641 642
 *
 * 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.
 */
643
static void vmbus_ongpadl_torndown(
644
			struct vmbus_channel_message_header *hdr)
645
{
646 647 648 649
	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;
650
	unsigned long flags;
651

652
	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
653 654 655 656

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

659 660
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
661
		requestheader =
662
			(struct vmbus_channel_message_header *)msginfo->msg;
663

664
		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
665 666
			gpadl_teardown =
			(struct vmbus_channel_gpadl_teardown *)requestheader;
667

668 669
			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
				memcpy(&msginfo->response.gpadl_torndown,
670
				       gpadl_torndown,
671 672 673
				       sizeof(
					struct vmbus_channel_gpadl_torndown));
				complete(&msginfo->waitevent);
674 675 676 677
				break;
			}
		}
	}
678
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
679 680
}

681
/*
682
 * vmbus_onversion_response - Version response handler
683 684 685 686 687
 *
 * 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.
 */
688
static void vmbus_onversion_response(
689
		struct vmbus_channel_message_header *hdr)
690
{
691 692 693
	struct vmbus_channel_msginfo *msginfo;
	struct vmbus_channel_message_header *requestheader;
	struct vmbus_channel_version_response *version_response;
694
	unsigned long flags;
695

696
	version_response = (struct vmbus_channel_version_response *)hdr;
697
	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
698

699 700
	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
				msglistentry) {
701
		requestheader =
702
			(struct vmbus_channel_message_header *)msginfo->msg;
703

704 705 706
		if (requestheader->msgtype ==
		    CHANNELMSG_INITIATE_CONTACT) {
			memcpy(&msginfo->response.version_response,
707
			      version_response,
708
			      sizeof(struct vmbus_channel_version_response));
709
			complete(&msginfo->waitevent);
710 711
		}
	}
712
	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
713 714
}

715 716
/* Channel message dispatch table */
static struct vmbus_channel_message_table_entry
717
	channel_message_table[CHANNELMSG_COUNT] = {
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
	{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},
735 736
};

737
/*
738
 * vmbus_onmessage - Handler for channel protocol messages.
739 740 741
 *
 * This is invoked in the vmbus worker thread context.
 */
742
void vmbus_onmessage(void *context)
743
{
744
	struct hv_message *msg = context;
745
	struct vmbus_channel_message_header *hdr;
746 747
	int size;

748 749
	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
	size = msg->header.payload_size;
750

751
	if (hdr->msgtype >= CHANNELMSG_COUNT) {
752
		pr_err("Received invalid channel message type %d size %d\n",
753
			   hdr->msgtype, size);
754
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
755
				     (unsigned char *)msg->u.payload, size);
756 757 758
		return;
	}

759 760
	if (channel_message_table[hdr->msgtype].message_handler)
		channel_message_table[hdr->msgtype].message_handler(hdr);
761
	else
762
		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
763 764
}

765
/*
766
 * vmbus_request_offers - Send a request to get all our pending offers.
767
 */
768
int vmbus_request_offers(void)
769
{
770
	struct vmbus_channel_message_header *msg;
771
	struct vmbus_channel_msginfo *msginfo;
772
	int ret, t;
773

774
	msginfo = kmalloc(sizeof(*msginfo) +
775 776
			  sizeof(struct vmbus_channel_message_header),
			  GFP_KERNEL);
777
	if (!msginfo)
778
		return -ENOMEM;
779

780
	init_completion(&msginfo->waitevent);
781

782
	msg = (struct vmbus_channel_message_header *)msginfo->msg;
783

784
	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
785 786


787
	ret = vmbus_post_msg(msg,
788 789
			       sizeof(struct vmbus_channel_message_header));
	if (ret != 0) {
790
		pr_err("Unable to request offers - %d\n", ret);
791

792 793
		goto cleanup;
	}
794

795
	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
796
	if (t == 0) {
797 798
		ret = -ETIMEDOUT;
		goto cleanup;
799 800 801 802
	}



803
cleanup:
804
	kfree(msginfo);
805 806 807 808

	return ret;
}

809 810 811 812 813 814 815 816 817
/*
 * 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;
818
	int cur_cpu;
819 820 821 822 823 824 825
	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;

826 827
	cur_cpu = hv_context.vp_index[get_cpu()];
	put_cpu();
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 883 884 885 886 887 888 889 890 891 892 893
	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);