xref: /openbmc/linux/drivers/hv/channel_mgmt.c (revision b6bec26c)
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 
269 	offer = (struct vmbus_channel_offer_channel *)hdr;
270 
271 	/* Allocate the channel object and save this offer. */
272 	newchannel = alloc_channel();
273 	if (!newchannel) {
274 		pr_err("Unable to allocate channel object\n");
275 		return;
276 	}
277 
278 	memcpy(&newchannel->offermsg, offer,
279 	       sizeof(struct vmbus_channel_offer_channel));
280 	newchannel->monitor_grp = (u8)offer->monitorid / 32;
281 	newchannel->monitor_bit = (u8)offer->monitorid % 32;
282 
283 	INIT_WORK(&newchannel->work, vmbus_process_offer);
284 	queue_work(newchannel->controlwq, &newchannel->work);
285 }
286 
287 /*
288  * vmbus_onoffer_rescind - Rescind offer handler.
289  *
290  * We queue a work item to process this offer synchronously
291  */
292 static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
293 {
294 	struct vmbus_channel_rescind_offer *rescind;
295 	struct vmbus_channel *channel;
296 
297 	rescind = (struct vmbus_channel_rescind_offer *)hdr;
298 	channel = relid2channel(rescind->child_relid);
299 
300 	if (channel == NULL)
301 		/* Just return here, no channel found */
302 		return;
303 
304 	/* work is initialized for vmbus_process_rescind_offer() from
305 	 * vmbus_process_offer() where the channel got created */
306 	queue_work(channel->controlwq, &channel->work);
307 }
308 
309 /*
310  * vmbus_onoffers_delivered -
311  * This is invoked when all offers have been delivered.
312  *
313  * Nothing to do here.
314  */
315 static void vmbus_onoffers_delivered(
316 			struct vmbus_channel_message_header *hdr)
317 {
318 }
319 
320 /*
321  * vmbus_onopen_result - Open result handler.
322  *
323  * This is invoked when we received a response to our channel open request.
324  * Find the matching request, copy the response and signal the requesting
325  * thread.
326  */
327 static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
328 {
329 	struct vmbus_channel_open_result *result;
330 	struct vmbus_channel_msginfo *msginfo;
331 	struct vmbus_channel_message_header *requestheader;
332 	struct vmbus_channel_open_channel *openmsg;
333 	unsigned long flags;
334 
335 	result = (struct vmbus_channel_open_result *)hdr;
336 
337 	/*
338 	 * Find the open msg, copy the result and signal/unblock the wait event
339 	 */
340 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
341 
342 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
343 				msglistentry) {
344 		requestheader =
345 			(struct vmbus_channel_message_header *)msginfo->msg;
346 
347 		if (requestheader->msgtype == CHANNELMSG_OPENCHANNEL) {
348 			openmsg =
349 			(struct vmbus_channel_open_channel *)msginfo->msg;
350 			if (openmsg->child_relid == result->child_relid &&
351 			    openmsg->openid == result->openid) {
352 				memcpy(&msginfo->response.open_result,
353 				       result,
354 				       sizeof(
355 					struct vmbus_channel_open_result));
356 				complete(&msginfo->waitevent);
357 				break;
358 			}
359 		}
360 	}
361 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
362 }
363 
364 /*
365  * vmbus_ongpadl_created - GPADL created handler.
366  *
367  * This is invoked when we received a response to our gpadl create request.
368  * Find the matching request, copy the response and signal the requesting
369  * thread.
370  */
371 static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
372 {
373 	struct vmbus_channel_gpadl_created *gpadlcreated;
374 	struct vmbus_channel_msginfo *msginfo;
375 	struct vmbus_channel_message_header *requestheader;
376 	struct vmbus_channel_gpadl_header *gpadlheader;
377 	unsigned long flags;
378 
379 	gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
380 
381 	/*
382 	 * Find the establish msg, copy the result and signal/unblock the wait
383 	 * event
384 	 */
385 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
386 
387 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
388 				msglistentry) {
389 		requestheader =
390 			(struct vmbus_channel_message_header *)msginfo->msg;
391 
392 		if (requestheader->msgtype == CHANNELMSG_GPADL_HEADER) {
393 			gpadlheader =
394 			(struct vmbus_channel_gpadl_header *)requestheader;
395 
396 			if ((gpadlcreated->child_relid ==
397 			     gpadlheader->child_relid) &&
398 			    (gpadlcreated->gpadl == gpadlheader->gpadl)) {
399 				memcpy(&msginfo->response.gpadl_created,
400 				       gpadlcreated,
401 				       sizeof(
402 					struct vmbus_channel_gpadl_created));
403 				complete(&msginfo->waitevent);
404 				break;
405 			}
406 		}
407 	}
408 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
409 }
410 
411 /*
412  * vmbus_ongpadl_torndown - GPADL torndown handler.
413  *
414  * This is invoked when we received a response to our gpadl teardown request.
415  * Find the matching request, copy the response and signal the requesting
416  * thread.
417  */
418 static void vmbus_ongpadl_torndown(
419 			struct vmbus_channel_message_header *hdr)
420 {
421 	struct vmbus_channel_gpadl_torndown *gpadl_torndown;
422 	struct vmbus_channel_msginfo *msginfo;
423 	struct vmbus_channel_message_header *requestheader;
424 	struct vmbus_channel_gpadl_teardown *gpadl_teardown;
425 	unsigned long flags;
426 
427 	gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
428 
429 	/*
430 	 * Find the open msg, copy the result and signal/unblock the wait event
431 	 */
432 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
433 
434 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
435 				msglistentry) {
436 		requestheader =
437 			(struct vmbus_channel_message_header *)msginfo->msg;
438 
439 		if (requestheader->msgtype == CHANNELMSG_GPADL_TEARDOWN) {
440 			gpadl_teardown =
441 			(struct vmbus_channel_gpadl_teardown *)requestheader;
442 
443 			if (gpadl_torndown->gpadl == gpadl_teardown->gpadl) {
444 				memcpy(&msginfo->response.gpadl_torndown,
445 				       gpadl_torndown,
446 				       sizeof(
447 					struct vmbus_channel_gpadl_torndown));
448 				complete(&msginfo->waitevent);
449 				break;
450 			}
451 		}
452 	}
453 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
454 }
455 
456 /*
457  * vmbus_onversion_response - Version response handler
458  *
459  * This is invoked when we received a response to our initiate contact request.
460  * Find the matching request, copy the response and signal the requesting
461  * thread.
462  */
463 static void vmbus_onversion_response(
464 		struct vmbus_channel_message_header *hdr)
465 {
466 	struct vmbus_channel_msginfo *msginfo;
467 	struct vmbus_channel_message_header *requestheader;
468 	struct vmbus_channel_version_response *version_response;
469 	unsigned long flags;
470 
471 	version_response = (struct vmbus_channel_version_response *)hdr;
472 	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
473 
474 	list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
475 				msglistentry) {
476 		requestheader =
477 			(struct vmbus_channel_message_header *)msginfo->msg;
478 
479 		if (requestheader->msgtype ==
480 		    CHANNELMSG_INITIATE_CONTACT) {
481 			memcpy(&msginfo->response.version_response,
482 			      version_response,
483 			      sizeof(struct vmbus_channel_version_response));
484 			complete(&msginfo->waitevent);
485 		}
486 	}
487 	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
488 }
489 
490 /* Channel message dispatch table */
491 static struct vmbus_channel_message_table_entry
492 	channel_message_table[CHANNELMSG_COUNT] = {
493 	{CHANNELMSG_INVALID,			NULL},
494 	{CHANNELMSG_OFFERCHANNEL,		vmbus_onoffer},
495 	{CHANNELMSG_RESCIND_CHANNELOFFER,	vmbus_onoffer_rescind},
496 	{CHANNELMSG_REQUESTOFFERS,		NULL},
497 	{CHANNELMSG_ALLOFFERS_DELIVERED,	vmbus_onoffers_delivered},
498 	{CHANNELMSG_OPENCHANNEL,		NULL},
499 	{CHANNELMSG_OPENCHANNEL_RESULT,	vmbus_onopen_result},
500 	{CHANNELMSG_CLOSECHANNEL,		NULL},
501 	{CHANNELMSG_GPADL_HEADER,		NULL},
502 	{CHANNELMSG_GPADL_BODY,		NULL},
503 	{CHANNELMSG_GPADL_CREATED,		vmbus_ongpadl_created},
504 	{CHANNELMSG_GPADL_TEARDOWN,		NULL},
505 	{CHANNELMSG_GPADL_TORNDOWN,		vmbus_ongpadl_torndown},
506 	{CHANNELMSG_RELID_RELEASED,		NULL},
507 	{CHANNELMSG_INITIATE_CONTACT,		NULL},
508 	{CHANNELMSG_VERSION_RESPONSE,		vmbus_onversion_response},
509 	{CHANNELMSG_UNLOAD,			NULL},
510 };
511 
512 /*
513  * vmbus_onmessage - Handler for channel protocol messages.
514  *
515  * This is invoked in the vmbus worker thread context.
516  */
517 void vmbus_onmessage(void *context)
518 {
519 	struct hv_message *msg = context;
520 	struct vmbus_channel_message_header *hdr;
521 	int size;
522 
523 	hdr = (struct vmbus_channel_message_header *)msg->u.payload;
524 	size = msg->header.payload_size;
525 
526 	if (hdr->msgtype >= CHANNELMSG_COUNT) {
527 		pr_err("Received invalid channel message type %d size %d\n",
528 			   hdr->msgtype, size);
529 		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
530 				     (unsigned char *)msg->u.payload, size);
531 		return;
532 	}
533 
534 	if (channel_message_table[hdr->msgtype].message_handler)
535 		channel_message_table[hdr->msgtype].message_handler(hdr);
536 	else
537 		pr_err("Unhandled channel message type %d\n", hdr->msgtype);
538 }
539 
540 /*
541  * vmbus_request_offers - Send a request to get all our pending offers.
542  */
543 int vmbus_request_offers(void)
544 {
545 	struct vmbus_channel_message_header *msg;
546 	struct vmbus_channel_msginfo *msginfo;
547 	int ret, t;
548 
549 	msginfo = kmalloc(sizeof(*msginfo) +
550 			  sizeof(struct vmbus_channel_message_header),
551 			  GFP_KERNEL);
552 	if (!msginfo)
553 		return -ENOMEM;
554 
555 	init_completion(&msginfo->waitevent);
556 
557 	msg = (struct vmbus_channel_message_header *)msginfo->msg;
558 
559 	msg->msgtype = CHANNELMSG_REQUESTOFFERS;
560 
561 
562 	ret = vmbus_post_msg(msg,
563 			       sizeof(struct vmbus_channel_message_header));
564 	if (ret != 0) {
565 		pr_err("Unable to request offers - %d\n", ret);
566 
567 		goto cleanup;
568 	}
569 
570 	t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
571 	if (t == 0) {
572 		ret = -ETIMEDOUT;
573 		goto cleanup;
574 	}
575 
576 
577 
578 cleanup:
579 	kfree(msginfo);
580 
581 	return ret;
582 }
583 
584 /* eof */
585