xref: /openbmc/linux/drivers/hv/channel_mgmt.c (revision 95e9fd10)
1 /*
2  * Copyright (c) 2009, Microsoft Corporation.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15  * Place - Suite 330, Boston, MA 02111-1307 USA.
16  *
17  * Authors:
18  *   Haiyang Zhang <haiyangz@microsoft.com>
19  *   Hank Janssen  <hjanssen@microsoft.com>
20  */
21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #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  * @icmsghdrp: Pointer to msg header structure
44  * @icmsg_negotiate: Pointer to negotiate message structure
45  * @buf: Raw buffer channel data
46  *
47  * @icmsghdrp is of type &struct icmsg_hdr.
48  * @negop is of type &struct icmsg_negotiate.
49  * Set up and fill in default negotiate response message.
50  *
51  * The max_fw_version specifies the maximum framework version that
52  * we can support and max _srv_version specifies the maximum service
53  * version we can support. A special value MAX_SRV_VER can be
54  * specified to indicate that we can handle the maximum version
55  * exposed by the host.
56  *
57  * Mainly used by Hyper-V drivers.
58  */
59 void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
60 				struct icmsg_negotiate *negop, u8 *buf,
61 				int max_fw_version, int max_srv_version)
62 {
63 	int icframe_vercnt;
64 	int icmsg_vercnt;
65 	int i;
66 
67 	icmsghdrp->icmsgsize = 0x10;
68 
69 	negop = (struct icmsg_negotiate *)&buf[
70 		sizeof(struct vmbuspipe_hdr) +
71 		sizeof(struct icmsg_hdr)];
72 
73 	icframe_vercnt = negop->icframe_vercnt;
74 	icmsg_vercnt = negop->icmsg_vercnt;
75 
76 	/*
77 	 * Select the framework version number we will
78 	 * support.
79 	 */
80 
81 	for (i = 0; i < negop->icframe_vercnt; i++) {
82 		if (negop->icversion_data[i].major <= max_fw_version)
83 			icframe_vercnt = negop->icversion_data[i].major;
84 	}
85 
86 	for (i = negop->icframe_vercnt;
87 		 (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
88 		if (negop->icversion_data[i].major <= max_srv_version)
89 			icmsg_vercnt = negop->icversion_data[i].major;
90 	}
91 
92 	/*
93 	 * Respond with the maximum framework and service
94 	 * version numbers we can support.
95 	 */
96 	negop->icframe_vercnt = 1;
97 	negop->icmsg_vercnt = 1;
98 	negop->icversion_data[0].major = icframe_vercnt;
99 	negop->icversion_data[0].minor = 0;
100 	negop->icversion_data[1].major = icmsg_vercnt;
101 	negop->icversion_data[1].minor = 0;
102 }
103 
104 EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
105 
106 /*
107  * alloc_channel - Allocate and initialize a vmbus channel object
108  */
109 static struct vmbus_channel *alloc_channel(void)
110 {
111 	struct vmbus_channel *channel;
112 
113 	channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
114 	if (!channel)
115 		return NULL;
116 
117 	spin_lock_init(&channel->inbound_lock);
118 
119 	channel->controlwq = create_workqueue("hv_vmbus_ctl");
120 	if (!channel->controlwq) {
121 		kfree(channel);
122 		return NULL;
123 	}
124 
125 	return channel;
126 }
127 
128 /*
129  * release_hannel - Release the vmbus channel object itself
130  */
131 static void release_channel(struct work_struct *work)
132 {
133 	struct vmbus_channel *channel = container_of(work,
134 						     struct vmbus_channel,
135 						     work);
136 
137 	destroy_workqueue(channel->controlwq);
138 
139 	kfree(channel);
140 }
141 
142 /*
143  * free_channel - Release the resources used by the vmbus channel object
144  */
145 static void free_channel(struct vmbus_channel *channel)
146 {
147 
148 	/*
149 	 * We have to release the channel's workqueue/thread in the vmbus's
150 	 * workqueue/thread context
151 	 * ie we can't destroy ourselves.
152 	 */
153 	INIT_WORK(&channel->work, release_channel);
154 	queue_work(vmbus_connection.work_queue, &channel->work);
155 }
156 
157 
158 
159 /*
160  * vmbus_process_rescind_offer -
161  * Rescind the offer by initiating a device removal
162  */
163 static void vmbus_process_rescind_offer(struct work_struct *work)
164 {
165 	struct vmbus_channel *channel = container_of(work,
166 						     struct vmbus_channel,
167 						     work);
168 
169 	vmbus_device_unregister(channel->device_obj);
170 }
171 
172 void vmbus_free_channels(void)
173 {
174 	struct vmbus_channel *channel;
175 
176 	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
177 		vmbus_device_unregister(channel->device_obj);
178 		kfree(channel->device_obj);
179 		free_channel(channel);
180 	}
181 }
182 
183 /*
184  * vmbus_process_offer - Process the offer by creating a channel/device
185  * associated with this offer
186  */
187 static void vmbus_process_offer(struct work_struct *work)
188 {
189 	struct vmbus_channel *newchannel = container_of(work,
190 							struct vmbus_channel,
191 							work);
192 	struct vmbus_channel *channel;
193 	bool fnew = true;
194 	int ret;
195 	unsigned long flags;
196 
197 	/* The next possible work is rescind handling */
198 	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
199 
200 	/* Make sure this is a new offer */
201 	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
202 
203 	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
204 		if (!uuid_le_cmp(channel->offermsg.offer.if_type,
205 			newchannel->offermsg.offer.if_type) &&
206 			!uuid_le_cmp(channel->offermsg.offer.if_instance,
207 				newchannel->offermsg.offer.if_instance)) {
208 			fnew = false;
209 			break;
210 		}
211 	}
212 
213 	if (fnew)
214 		list_add_tail(&newchannel->listentry,
215 			      &vmbus_connection.chn_list);
216 
217 	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
218 
219 	if (!fnew) {
220 		free_channel(newchannel);
221 		return;
222 	}
223 
224 	/*
225 	 * Start the process of binding this offer to the driver
226 	 * We need to set the DeviceObject field before calling
227 	 * vmbus_child_dev_add()
228 	 */
229 	newchannel->device_obj = vmbus_device_create(
230 		&newchannel->offermsg.offer.if_type,
231 		&newchannel->offermsg.offer.if_instance,
232 		newchannel);
233 
234 	/*
235 	 * Add the new device to the bus. This will kick off device-driver
236 	 * binding which eventually invokes the device driver's AddDevice()
237 	 * method.
238 	 */
239 	ret = vmbus_device_register(newchannel->device_obj);
240 	if (ret != 0) {
241 		pr_err("unable to add child device object (relid %d)\n",
242 			   newchannel->offermsg.child_relid);
243 
244 		spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
245 		list_del(&newchannel->listentry);
246 		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
247 		kfree(newchannel->device_obj);
248 
249 		free_channel(newchannel);
250 	} else {
251 		/*
252 		 * This state is used to indicate a successful open
253 		 * so that when we do close the channel normally, we
254 		 * can cleanup properly
255 		 */
256 		newchannel->state = CHANNEL_OPEN_STATE;
257 	}
258 }
259 
260 /*
261  * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
262  *
263  */
264 static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
265 {
266 	struct vmbus_channel_offer_channel *offer;
267 	struct vmbus_channel *newchannel;
268 	uuid_le *guidtype;
269 	uuid_le *guidinstance;
270 
271 	offer = (struct vmbus_channel_offer_channel *)hdr;
272 
273 	guidtype = &offer->offer.if_type;
274 	guidinstance = &offer->offer.if_instance;
275 
276 	/* Allocate the channel object and save this offer. */
277 	newchannel = alloc_channel();
278 	if (!newchannel) {
279 		pr_err("Unable to allocate channel object\n");
280 		return;
281 	}
282 
283 	memcpy(&newchannel->offermsg, offer,
284 	       sizeof(struct vmbus_channel_offer_channel));
285 	newchannel->monitor_grp = (u8)offer->monitorid / 32;
286 	newchannel->monitor_bit = (u8)offer->monitorid % 32;
287 
288 	INIT_WORK(&newchannel->work, vmbus_process_offer);
289 	queue_work(newchannel->controlwq, &newchannel->work);
290 }
291 
292 /*
293  * vmbus_onoffer_rescind - Rescind offer handler.
294  *
295  * We queue a work item to process this offer synchronously
296  */
297 static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
298 {
299 	struct vmbus_channel_rescind_offer *rescind;
300 	struct vmbus_channel *channel;
301 
302 	rescind = (struct vmbus_channel_rescind_offer *)hdr;
303 	channel = relid2channel(rescind->child_relid);
304 
305 	if (channel == NULL)
306 		/* Just return here, no channel found */
307 		return;
308 
309 	/* work is initialized for vmbus_process_rescind_offer() from
310 	 * vmbus_process_offer() where the channel got created */
311 	queue_work(channel->controlwq, &channel->work);
312 }
313 
314 /*
315  * vmbus_onoffers_delivered -
316  * This is invoked when all offers have been delivered.
317  *
318  * Nothing to do here.
319  */
320 static void vmbus_onoffers_delivered(
321 			struct vmbus_channel_message_header *hdr)
322 {
323 }
324 
325 /*
326  * vmbus_onopen_result - Open result handler.
327  *
328  * This is invoked when we received a response to our channel open request.
329  * Find the matching request, copy the response and signal the requesting
330  * thread.
331  */
332 static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
333 {
334 	struct vmbus_channel_open_result *result;
335 	struct vmbus_channel_msginfo *msginfo;
336 	struct vmbus_channel_message_header *requestheader;
337 	struct vmbus_channel_open_channel *openmsg;
338 	unsigned long flags;
339 
340 	result = (struct vmbus_channel_open_result *)hdr;
341 
342 	/*
343 	 * Find the open msg, copy the result and signal/unblock the wait event
344 	 */
345 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
346 
347 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
348 				msglistentry) {
349 		requestheader =
350 			(struct vmbus_channel_message_header *)msginfo->msg;
351 
352 		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
353 			openmsg =
354 			(struct vmbus_channel_open_channel *)msginfo->msg;
355 			if (openmsg->child_relid == result->child_relid &&
356 			    openmsg->openid == result->openid) {
357 				memcpy(&msginfo->response.open_result,
358 				       result,
359 				       sizeof(
360 					struct vmbus_channel_open_result));
361 				complete(&msginfo->waitevent);
362 				break;
363 			}
364 		}
365 	}
366 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
367 }
368 
369 /*
370  * vmbus_ongpadl_created - GPADL created handler.
371  *
372  * This is invoked when we received a response to our gpadl create request.
373  * Find the matching request, copy the response and signal the requesting
374  * thread.
375  */
376 static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
377 {
378 	struct vmbus_channel_gpadl_created *gpadlcreated;
379 	struct vmbus_channel_msginfo *msginfo;
380 	struct vmbus_channel_message_header *requestheader;
381 	struct vmbus_channel_gpadl_header *gpadlheader;
382 	unsigned long flags;
383 
384 	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
385 
386 	/*
387 	 * Find the establish msg, copy the result and signal/unblock the wait
388 	 * event
389 	 */
390 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
391 
392 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
393 				msglistentry) {
394 		requestheader =
395 			(struct vmbus_channel_message_header *)msginfo->msg;
396 
397 		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
398 			gpadlheader =
399 			(struct vmbus_channel_gpadl_header *)requestheader;
400 
401 			if ((gpadlcreated->child_relid ==
402 			     gpadlheader->child_relid) &&
403 			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
404 				memcpy(&msginfo->response.gpadl_created,
405 				       gpadlcreated,
406 				       sizeof(
407 					struct vmbus_channel_gpadl_created));
408 				complete(&msginfo->waitevent);
409 				break;
410 			}
411 		}
412 	}
413 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
414 }
415 
416 /*
417  * vmbus_ongpadl_torndown - GPADL torndown handler.
418  *
419  * This is invoked when we received a response to our gpadl teardown request.
420  * Find the matching request, copy the response and signal the requesting
421  * thread.
422  */
423 static void vmbus_ongpadl_torndown(
424 			struct vmbus_channel_message_header *hdr)
425 {
426 	struct vmbus_channel_gpadl_torndown *gpadl_torndown;
427 	struct vmbus_channel_msginfo *msginfo;
428 	struct vmbus_channel_message_header *requestheader;
429 	struct vmbus_channel_gpadl_teardown *gpadl_teardown;
430 	unsigned long flags;
431 
432 	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
433 
434 	/*
435 	 * Find the open msg, copy the result and signal/unblock the wait event
436 	 */
437 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
438 
439 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
440 				msglistentry) {
441 		requestheader =
442 			(struct vmbus_channel_message_header *)msginfo->msg;
443 
444 		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
445 			gpadl_teardown =
446 			(struct vmbus_channel_gpadl_teardown *)requestheader;
447 
448 			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
449 				memcpy(&msginfo->response.gpadl_torndown,
450 				       gpadl_torndown,
451 				       sizeof(
452 					struct vmbus_channel_gpadl_torndown));
453 				complete(&msginfo->waitevent);
454 				break;
455 			}
456 		}
457 	}
458 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
459 }
460 
461 /*
462  * vmbus_onversion_response - Version response handler
463  *
464  * This is invoked when we received a response to our initiate contact request.
465  * Find the matching request, copy the response and signal the requesting
466  * thread.
467  */
468 static void vmbus_onversion_response(
469 		struct vmbus_channel_message_header *hdr)
470 {
471 	struct vmbus_channel_msginfo *msginfo;
472 	struct vmbus_channel_message_header *requestheader;
473 	struct vmbus_channel_initiate_contact *initiate;
474 	struct vmbus_channel_version_response *version_response;
475 	unsigned long flags;
476 
477 	version_response = (struct vmbus_channel_version_response *)hdr;
478 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
479 
480 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
481 				msglistentry) {
482 		requestheader =
483 			(struct vmbus_channel_message_header *)msginfo->msg;
484 
485 		if (requestheader->msgtype ==
486 		    CHANNELMSG_INITIATE_CONTACT) {
487 			initiate =
488 			(struct vmbus_channel_initiate_contact *)requestheader;
489 			memcpy(&msginfo->response.version_response,
490 			      version_response,
491 			      sizeof(struct vmbus_channel_version_response));
492 			complete(&msginfo->waitevent);
493 		}
494 	}
495 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
496 }
497 
498 /* Channel message dispatch table */
499 static struct vmbus_channel_message_table_entry
500 	channel_message_table[CHANNELMSG_COUNT] = {
501 	{CHANNELMSG_INVALID,			NULL},
502 	{CHANNELMSG_OFFERCHANNEL,		vmbus_onoffer},
503 	{CHANNELMSG_RESCIND_CHANNELOFFER,	vmbus_onoffer_rescind},
504 	{CHANNELMSG_REQUESTOFFERS,		NULL},
505 	{CHANNELMSG_ALLOFFERS_DELIVERED,	vmbus_onoffers_delivered},
506 	{CHANNELMSG_OPENCHANNEL,		NULL},
507 	{CHANNELMSG_OPENCHANNEL_RESULT,	vmbus_onopen_result},
508 	{CHANNELMSG_CLOSECHANNEL,		NULL},
509 	{CHANNELMSG_GPADL_HEADER,		NULL},
510 	{CHANNELMSG_GPADL_BODY,		NULL},
511 	{CHANNELMSG_GPADL_CREATED,		vmbus_ongpadl_created},
512 	{CHANNELMSG_GPADL_TEARDOWN,		NULL},
513 	{CHANNELMSG_GPADL_TORNDOWN,		vmbus_ongpadl_torndown},
514 	{CHANNELMSG_RELID_RELEASED,		NULL},
515 	{CHANNELMSG_INITIATE_CONTACT,		NULL},
516 	{CHANNELMSG_VERSION_RESPONSE,		vmbus_onversion_response},
517 	{CHANNELMSG_UNLOAD,			NULL},
518 };
519 
520 /*
521  * vmbus_onmessage - Handler for channel protocol messages.
522  *
523  * This is invoked in the vmbus worker thread context.
524  */
525 void vmbus_onmessage(void *context)
526 {
527 	struct hv_message *msg = context;
528 	struct vmbus_channel_message_header *hdr;
529 	int size;
530 
531 	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
532 	size = msg->header.payload_size;
533 
534 	if (hdr->msgtype >= CHANNELMSG_COUNT) {
535 		pr_err("Received invalid channel message type %d size %d\n",
536 			   hdr->msgtype, size);
537 		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
538 				     (unsigned char *)msg->u.payload, size);
539 		return;
540 	}
541 
542 	if (channel_message_table[hdr->msgtype].message_handler)
543 		channel_message_table[hdr->msgtype].message_handler(hdr);
544 	else
545 		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
546 }
547 
548 /*
549  * vmbus_request_offers - Send a request to get all our pending offers.
550  */
551 int vmbus_request_offers(void)
552 {
553 	struct vmbus_channel_message_header *msg;
554 	struct vmbus_channel_msginfo *msginfo;
555 	int ret, t;
556 
557 	msginfo = kmalloc(sizeof(*msginfo) +
558 			  sizeof(struct vmbus_channel_message_header),
559 			  GFP_KERNEL);
560 	if (!msginfo)
561 		return -ENOMEM;
562 
563 	init_completion(&msginfo->waitevent);
564 
565 	msg = (struct vmbus_channel_message_header *)msginfo->msg;
566 
567 	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
568 
569 
570 	ret = vmbus_post_msg(msg,
571 			       sizeof(struct vmbus_channel_message_header));
572 	if (ret != 0) {
573 		pr_err("Unable to request offers - %d\n", ret);
574 
575 		goto cleanup;
576 	}
577 
578 	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
579 	if (t == 0) {
580 		ret = -ETIMEDOUT;
581 		goto cleanup;
582 	}
583 
584 
585 
586 cleanup:
587 	kfree(msginfo);
588 
589 	return ret;
590 }
591 
592 /* eof */
593