hv.c revision 0a46618d58c90f93e8b8e9a18062d1691b70297e
1b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox/*
2b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * Copyright (c) 2009, Microsoft Corporation.
3b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *
4b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * This program is free software; you can redistribute it and/or modify it
5b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * under the terms and conditions of the GNU General Public License,
6b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * version 2, as published by the Free Software Foundation.
7b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *
8b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * This program is distributed in the hope it will be useful, but WITHOUT
9b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * more details.
12b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *
13b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * You should have received a copy of the GNU General Public License along with
14b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * Place - Suite 330, Boston, MA 02111-1307 USA.
16b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *
17b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * Authors:
18b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *   Haiyang Zhang <haiyangz@microsoft.com>
19b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *   Hank Janssen  <hjanssen@microsoft.com>
20b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox *
218de055350fbaa96b6563892c195a60be583faa9cMatthew Wilcox */
22b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23fd63e9ceeeae58cfe877c2d49d41c1bf7532303cMatthew Wilcox
24b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#include <linux/kernel.h>
25b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#include <linux/mm.h>
26b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#include <linux/slab.h>
275aff9382ddc8aac6eb0c70ffbb351652d71da69aMatthew Wilcox#include <linux/vmalloc.h>
28b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#include "hv_api.h"
29b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#include "logging.h"
30b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#include "vmbus_private.h"
31b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
321fa6aeadf18aeebd7a217d7a3a933856448375b6Matthew Wilcox/* The one and only */
33b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcoxstruct hv_context hv_context = {
34b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	.synic_initialized	= false,
35b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	.hypercall_page		= NULL,
36b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	.signal_event_param	= NULL,
37b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	.signal_event_buffer	= NULL,
38be7b62754e097adc0cb16c25c9ee86ee20de62fbMatthew Wilcox};
39c3bfe7176c035a0a2c70bc79180fb13a6c57142aMatthew Wilcox
40b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox/*
41b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * query_hypervisor_presence
42b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * - Query the cpuid for presense of windows hypervisor
435d0f6131a79adfa1fb51309c5f81a2a4ef879dd4Vishal Verma */
44797a796a13df6b84a4791e57306737059b5b2384Hitoshi Mitakestatic int query_hypervisor_presence(void)
45797a796a13df6b84a4791e57306737059b5b2384Hitoshi Mitake{
46b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int eax;
47b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int ebx;
48b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int ecx;
49b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int edx;
50e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox	unsigned int op;
51b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
52b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	eax = 0;
53b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	ebx = 0;
54b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	ecx = 0;
5558ffacb545f76fc2c65d1fbfa5acf5184a2a09e6Matthew Wilcox	edx = 0;
5658ffacb545f76fc2c65d1fbfa5acf5184a2a09e6Matthew Wilcox	op = HVCPUID_VERSION_FEATURES;
5758ffacb545f76fc2c65d1fbfa5acf5184a2a09e6Matthew Wilcox	cpuid(op, &eax, &ebx, &ecx, &edx);
581fa6aeadf18aeebd7a217d7a3a933856448375b6Matthew Wilcox
591fa6aeadf18aeebd7a217d7a3a933856448375b6Matthew Wilcox	return ecx & HV_PRESENT_BIT;
601fa6aeadf18aeebd7a217d7a3a933856448375b6Matthew Wilcox}
611fa6aeadf18aeebd7a217d7a3a933856448375b6Matthew Wilcox
62b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox/*
63b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * query_hypervisor_info - Get version info of the windows hypervisor
64b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox */
65b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcoxstatic int query_hypervisor_info(void)
66b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox{
67b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int eax;
68091b609258b8e01cc45b01a41ca5e496f674d989Matthew Wilcox	unsigned int ebx;
69b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int ecx;
70b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int edx;
71b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int max_leaf;
72b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	unsigned int op;
73b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
74b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	/*
751fa6aeadf18aeebd7a217d7a3a933856448375b6Matthew Wilcox	* Its assumed that this is called after confirming that Viridian
76b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	* is present. Query id and revision.
77b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	*/
78b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	eax = 0;
79b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	ebx = 0;
80b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	ecx = 0;
81b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	edx = 0;
82b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	op = HVCPUID_VENDOR_MAXFUNCTION;
83e9539f47525ecee05c9f22c3565885f3e9492c52Matthew Wilcox	cpuid(op, &eax, &ebx, &ecx, &edx);
84e9539f47525ecee05c9f22c3565885f3e9492c52Matthew Wilcox
85b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox/*	DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
86b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    (ebx & 0xFF),
87b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((ebx >> 8) & 0xFF),
88b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((ebx >> 16) & 0xFF),
89b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((ebx >> 24) & 0xFF),
90b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    (ecx & 0xFF),
91b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((ecx >> 8) & 0xFF),
92b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((ecx >> 16) & 0xFF),
93b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((ecx >> 24) & 0xFF),
94b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    (edx & 0xFF),
95b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((edx >> 8) & 0xFF),
96b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((edx >> 16) & 0xFF),
97b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		    ((edx >> 24) & 0xFF));
98f8ebf8409abfdaeeb8c847381629a2a8b8e3d816Vishal Verma*/
99b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	max_leaf = eax;
100b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox/*	eax = 0;
101b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	ebx = 0;
102b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	ecx = 0;
1036ecec74520d8a357726e6c12f99080dbe7b347ddKeith Busch	edx = 0;
104b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	op = HVCPUID_INTERFACE;
105b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	cpuid(op, &eax, &ebx, &ecx, &edx);
1065c1281a3bf5655ec1b90db495da3a2b77826ba88Matthew Wilcox
107c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
108c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox		    (eax & 0xFF),
109e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox		    ((eax >> 8) & 0xFF),
110c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox		    ((eax >> 16) & 0xFF),
111c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox		    ((eax >> 24) & 0xFF));
112e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox*/
113e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox
114e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox	if (max_leaf >= HVCPUID_VERSION) {
115e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox		eax = 0;
116e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox		ebx = 0;
117e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox		ecx = 0;
118e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox		edx = 0;
119e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox		op = HVCPUID_VERSION;
120b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		cpuid(op, &eax, &ebx, &ecx, &edx);
121714a7a22884b74862540bc84955274d86b2f6040Matthew Wilcox		pr_info("Hyper-V Host OS Build:%d-%d.%d-%d-%d.%d\n",
122714a7a22884b74862540bc84955274d86b2f6040Matthew Wilcox			    eax,
123714a7a22884b74862540bc84955274d86b2f6040Matthew Wilcox			    ebx >> 16,
124c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox			    ebx & 0xFFFF,
125b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			    ecx,
126b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			    edx >> 24,
127b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			    edx & 0xFFFFFF);
128b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	}
129b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	return max_leaf;
130b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox}
131184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox
132184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox/*
133184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox * do_hypercall- Invoke the specified hypercall
134b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox */
135c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcoxstatic u64 do_hypercall(u64 control, void *input, void *output)
136c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox{
137b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox#ifdef CONFIG_X86_64
138e6d15f79f997a98b3a69abbc462fc9041cc1a7b4Matthew Wilcox	u64 hv_status = 0;
139e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox	u64 input_address = (input) ? virt_to_phys(input) : 0;
140b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u64 output_address = (output) ? virt_to_phys(output) : 0;
141b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	volatile void *hypercall_page = hv_context.hypercall_page;
142b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
143b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	__asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
144b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	__asm__ __volatile__("call *%3" : "=a" (hv_status) :
145b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			     "c" (control), "d" (input_address),
146b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			     "m" (hypercall_page));
147b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
148c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	return hv_status;
149c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
150e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox#else
151b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
152b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 control_hi = control >> 32;
153b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 control_lo = control & 0xFFFFFFFF;
154b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 hv_status_hi = 1;
155c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	u32 hv_status_lo = 1;
156b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u64 input_address = (input) ? virt_to_phys(input) : 0;
157b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 input_address_hi = input_address >> 32;
158b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 input_address_lo = input_address & 0xFFFFFFFF;
159e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox	u64 output_address = (output) ? virt_to_phys(output) : 0;
160b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 output_address_hi = output_address >> 32;
161b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u32 output_address_lo = output_address & 0xFFFFFFFF;
162b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	volatile void *hypercall_page = hv_context.hypercall_page;
163c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
164c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
165d2d8703481f60d67f49e3177196cbe474b11377cMatthew Wilcox			      "=a"(hv_status_lo) : "d" (control_hi),
166d2d8703481f60d67f49e3177196cbe474b11377cMatthew Wilcox			      "a" (control_lo), "b" (input_address_hi),
167d2d8703481f60d67f49e3177196cbe474b11377cMatthew Wilcox			      "c" (input_address_lo), "D"(output_address_hi),
16800df5cb4eb927078850086f8becc3286a69ea12eMatthew Wilcox			      "S"(output_address_lo), "m" (hypercall_page));
169be7b62754e097adc0cb16c25c9ee86ee20de62fbMatthew Wilcox
1705c1281a3bf5655ec1b90db495da3a2b77826ba88Matthew Wilcox	return hv_status_lo | ((u64)hv_status_hi << 32);
171c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox#endif /* !x86_64 */
172c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox}
173c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
174c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox/*
175c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox * hv_init - Main initialization routine.
176c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox *
177c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox * This routine must be called before any other routines in here are called
1785c1281a3bf5655ec1b90db495da3a2b77826ba88Matthew Wilcox */
179c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcoxint hv_init(void)
180c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox{
181c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	int ret = 0;
182c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	int max_leaf;
183c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	union hv_x64_msr_hypercall_contents hypercall_msr;
1845c1281a3bf5655ec1b90db495da3a2b77826ba88Matthew Wilcox	void *virtaddr = NULL;
185c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
186c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
187c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	memset(hv_context.synic_message_page, 0,
188c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	       sizeof(void *) * MAX_NUM_CPUS);
189c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
1905c1281a3bf5655ec1b90db495da3a2b77826ba88Matthew Wilcox	if (!query_hypervisor_presence())
191c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox		goto Cleanup;
192c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
193184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox	max_leaf = query_hypervisor_info();
194184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox	/* HvQueryHypervisorFeatures(maxLeaf); */
195184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox
196c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	/*
197c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	 * We only support running on top of Hyper-V
198b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	 */
199c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	rdmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
200e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox
201b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	if (hv_context.guestid != 0)
202c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox		goto Cleanup;
203c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
20448e3d39816416b3bf03dee3a796c0c04427c1a31Matthew Wilcox	/* Write our OS info */
205c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
206859361a228258edf4821d9f5635825033eca78e8Keith Busch	hv_context.guestid = HV_LINUX_GUEST_ID;
207859361a228258edf4821d9f5635825033eca78e8Keith Busch
208c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	/* See if the hypercall page is already set */
209c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
210e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox
211b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	/*
212b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	* Allocate the hypercall page memory
213c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	* virtaddr = osd_page_alloc(1);
214b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	*/
215b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
216c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
217c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	if (!virtaddr)
2183c0cf138d7789feb3f335f6f1d24ad8fc8b3a23fMatthew Wilcox		goto Cleanup;
219c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
220e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox	hypercall_msr.enable = 1;
221c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
222c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr);
223c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
224c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox
225e85248e516c550382ba33ca325c272a0ca397e44Matthew Wilcox	/* Confirm that hypercall page did get setup. */
226c2f5b65020869215814df03c3941dac9436f99fbMatthew Wilcox	hypercall_msr.as_uint64 = 0;
2273c0cf138d7789feb3f335f6f1d24ad8fc8b3a23fMatthew Wilcox	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
2283c0cf138d7789feb3f335f6f1d24ad8fc8b3a23fMatthew Wilcox
2295d0f6131a79adfa1fb51309c5f81a2a4ef879dd4Vishal Verma	if (!hypercall_msr.enable)
230b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		goto Cleanup;
231040a93b52a9eee8177ebaf2ba0ee0f9f518d1bf8Matthew Wilcox
232b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.hypercall_page = virtaddr;
233b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
2345d0f6131a79adfa1fb51309c5f81a2a4ef879dd4Vishal Verma	/* Setup the global signal event param for the signal event hypercall */
235b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_buffer =
2361b23484bd012c078de2ea939249e2fb2e85a0a6eMatthew Wilcox			kmalloc(sizeof(struct hv_input_signal_event_buffer),
237b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox				GFP_KERNEL);
238b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	if (!hv_context.signal_event_buffer)
239b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		goto Cleanup;
240714a7a22884b74862540bc84955274d86b2f6040Matthew Wilcox
241b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_param =
242b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		(struct hv_input_signal_event *)
243b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			(ALIGN((unsigned long)
244b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox				  hv_context.signal_event_buffer,
245b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox				  HV_HYPERCALL_PARAM_ALIGN));
246b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_param->connectionid.asu32 = 0;
247b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_param->connectionid.u.id =
248b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox						VMBUS_EVENT_CONNECTION_ID;
249b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_param->flag_number = 0;
250b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_param->rsvdz = 0;
251b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
252b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	return ret;
253b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
254b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew WilcoxCleanup:
2557547881d0951384f9833ec3a80fac8f3f16f3b98Matthew Wilcox	if (virtaddr) {
256b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		if (hypercall_msr.enable) {
257b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			hypercall_msr.as_uint64 = 0;
258b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox			wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
259b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		}
260b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
261b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		vfree(virtaddr);
262eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	}
263e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	ret = -1;
264eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	return ret;
265e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews}
266e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
267eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox/*
268eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox * hv_cleanup - Cleanup routine.
269eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox *
270eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox * This routine is called normally during driver unloading or exiting.
271eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox */
272eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcoxvoid hv_cleanup(void)
273eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox{
274eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	union hv_x64_msr_hypercall_contents hypercall_msr;
275eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
276eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	kfree(hv_context.signal_event_buffer);
277b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	hv_context.signal_event_buffer = NULL;
278eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	hv_context.signal_event_param = NULL;
279eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
280b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	if (hv_context.hypercall_page) {
281eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		hypercall_msr.as_uint64 = 0;
282eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
283eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		vfree(hv_context.hypercall_page);
284eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		hv_context.hypercall_page = NULL;
285eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	}
286eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox}
287eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
288eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox/*
2892b1960341576bf51c01b12fefeb1cc53820923e7Keith Busch * hv_post_message - Post a message using the hypervisor message IPC.
2906198221fa0df0298513b35796f63f242ea97134eKeith Busch *
291eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox * This involves a hypercall.
292eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox */
293eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcoxu16 hv_post_message(union hv_connection_id connection_id,
294b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		  enum hv_message_type message_type,
295b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox		  void *payload, size_t payload_size)
2965d0f6131a79adfa1fb51309c5f81a2a4ef879dd4Vishal Verma{
297b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	struct aligned_input {
298eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		u64 alignment8;
299eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		struct hv_input_post_message msg;
300eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	};
301eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
302eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	struct hv_input_post_message *aligned_msg;
303eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	u16 status;
304eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	unsigned long addr;
305eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
306eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
307eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		return -1;
308eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
309eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
310eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	if (!addr)
311eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		return -1;
312b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
313b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	aligned_msg = (struct hv_input_post_message *)
3146198221fa0df0298513b35796f63f242ea97134eKeith Busch			(ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN));
3156198221fa0df0298513b35796f63f242ea97134eKeith Busch
3166198221fa0df0298513b35796f63f242ea97134eKeith Busch	aligned_msg->connectionid = connection_id;
3176198221fa0df0298513b35796f63f242ea97134eKeith Busch	aligned_msg->message_type = message_type;
3186198221fa0df0298513b35796f63f242ea97134eKeith Busch	aligned_msg->payload_size = payload_size;
3196198221fa0df0298513b35796f63f242ea97134eKeith Busch	memcpy((void *)aligned_msg->payload, payload, payload_size);
3206198221fa0df0298513b35796f63f242ea97134eKeith Busch
3216198221fa0df0298513b35796f63f242ea97134eKeith Busch	status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
3226198221fa0df0298513b35796f63f242ea97134eKeith Busch		& 0xFFFF;
3236198221fa0df0298513b35796f63f242ea97134eKeith Busch
3246198221fa0df0298513b35796f63f242ea97134eKeith Busch	kfree((void *)addr);
3256198221fa0df0298513b35796f63f242ea97134eKeith Busch
3266198221fa0df0298513b35796f63f242ea97134eKeith Busch	return status;
3276198221fa0df0298513b35796f63f242ea97134eKeith Busch}
3286198221fa0df0298513b35796f63f242ea97134eKeith Busch
3296198221fa0df0298513b35796f63f242ea97134eKeith Busch
3306198221fa0df0298513b35796f63f242ea97134eKeith Busch/*
3316198221fa0df0298513b35796f63f242ea97134eKeith Busch * hv_signal_event -
3326198221fa0df0298513b35796f63f242ea97134eKeith Busch * Signal an event on the specified connection using the hypervisor event IPC.
3336198221fa0df0298513b35796f63f242ea97134eKeith Busch *
3346198221fa0df0298513b35796f63f242ea97134eKeith Busch * This involves a hypercall.
3356198221fa0df0298513b35796f63f242ea97134eKeith Busch */
3366198221fa0df0298513b35796f63f242ea97134eKeith Buschu16 hv_signal_event(void)
3376198221fa0df0298513b35796f63f242ea97134eKeith Busch{
3385c1281a3bf5655ec1b90db495da3a2b77826ba88Matthew Wilcox	u16 status;
339b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox
340b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	status = do_hypercall(HVCALL_SIGNAL_EVENT,
341eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox			       hv_context.signal_event_param,
342eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox			       NULL) & 0xFFFF;
343b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	return status;
344b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox}
3459e59d091b0eb04f223ed037348e3d9e36f30e72bKeith Busch
3462b1960341576bf51c01b12fefeb1cc53820923e7Keith Busch/*
347b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox * hv_synic_init - Initialize the Synthethic Interrupt Controller.
3489e59d091b0eb04f223ed037348e3d9e36f30e72bKeith Busch *
3499e59d091b0eb04f223ed037348e3d9e36f30e72bKeith Busch * If it is already initialized by another entity (ie x2v shim), we need to
350eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox * retrieve the initialized message and event pages.  Otherwise, we create and
351427e97080196548557b288517537ab7eb48c309fKeith Busch * initialize the message and event pages.
3521ad2f8932a72bf375361727949ced2cb4e8cfcefMatthew Wilcox */
353427e97080196548557b288517537ab7eb48c309fKeith Buschvoid hv_synic_init(void *irqarg)
3541ad2f8932a72bf375361727949ced2cb4e8cfcefMatthew Wilcox{
355b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	u64 version;
356b60503ba432b16fc84442a84e29a7aad2c0c363dMatthew Wilcox	union hv_synic_simp simp;
357184d2944cb3b92a2e8e1733c59d1e531ad6e924aMatthew Wilcox	union hv_synic_siefp siefp;
3585d0f6131a79adfa1fb51309c5f81a2a4ef879dd4Vishal Verma	union hv_synic_sint shared_sint;
3595d0f6131a79adfa1fb51309c5f81a2a4ef879dd4Vishal Verma	union hv_synic_scontrol sctrl;
360ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
36199802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox	u32 irq_vector = *((u32 *)(irqarg));
362eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	int cpu = smp_processor_id();
363eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
364ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	if (!hv_context.hypercall_page)
365ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox		return;
366ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
367e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	/* Check the version */
368eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	rdmsrl(HV_X64_MSR_SVERSION, version);
369e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
370eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	hv_context.synic_message_page[cpu] =
371ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox		(void *)get_zeroed_page(GFP_ATOMIC);
372ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
373ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	if (hv_context.synic_message_page[cpu] == NULL) {
374ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox		pr_err("Unable to allocate SYNIC message page\n");
375eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox		goto Cleanup;
376ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	}
377ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
378ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	hv_context.synic_event_page[cpu] =
379ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox		(void *)get_zeroed_page(GFP_ATOMIC);
380ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
381ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	if (hv_context.synic_event_page[cpu] == NULL) {
382ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox		pr_err("Unable to allocate SYNIC event page\n");
383ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox		goto Cleanup;
384ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	}
385ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
386ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	/* Setup the Synic's message page */
387ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox	rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
388eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	simp.simp_enabled = 1;
389e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu])
390e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews		>> PAGE_SHIFT;
391e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
39299802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox	wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
39399802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox
394eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	/* Setup the Synic's event page */
39599802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox	rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
39699802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox	siefp.siefp_enabled = 1;
397eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu])
39899802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox		>> PAGE_SHIFT;
39999802a7aee2b3dd720e382c52b892cc6a8122b11Matthew Wilcox
400b77954cbddff28d55a36fad3c16f4daebb0f01dfMatthew Wilcox	wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
401b77954cbddff28d55a36fad3c16f4daebb0f01dfMatthew Wilcox
402b77954cbddff28d55a36fad3c16f4daebb0f01dfMatthew Wilcox	/* Setup the interception SINT. */
403eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	/* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
404eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	/*	  interceptionSint.as_uint64); */
405b77954cbddff28d55a36fad3c16f4daebb0f01dfMatthew Wilcox
406eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	/* Setup the shared SINT. */
407eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
408e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
409e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	shared_sint.as_uint64 = 0;
410e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	shared_sint.vector = irq_vector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
4117523d834dd1573610078eb1ac0933f6490232f90Matthew Wilcox	shared_sint.masked = false;
412e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	shared_sint.auto_eoi = true;
413b77954cbddff28d55a36fad3c16f4daebb0f01dfMatthew Wilcox
414eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
415eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox
416eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox	/* Enable the global synic bit */
4177523d834dd1573610078eb1ac0933f6490232f90Matthew Wilcox	rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
4187523d834dd1573610078eb1ac0933f6490232f90Matthew Wilcox	sctrl.enable = 1;
4197523d834dd1573610078eb1ac0933f6490232f90Matthew Wilcox
420e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
421e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
422e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	hv_context.synic_initialized = true;
423e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	return;
424e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
425e025344c56e08b155f43ea09647969286c78377cShane Michael MatthewsCleanup:
426e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	if (hv_context.synic_event_page[cpu])
427e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews		free_page((unsigned long)hv_context.synic_event_page[cpu]);
428e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews
429e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	if (hv_context.synic_message_page[cpu])
430e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews		free_page((unsigned long)hv_context.synic_message_page[cpu]);
431e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews	return;
432e025344c56e08b155f43ea09647969286c78377cShane Michael Matthews}
433ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox
434ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox/*
435eca18b2394a9387feeaf14cd884ddddd7a809d19Matthew Wilcox * hv_synic_cleanup - Cleanup routine for hv_synic_init().
436ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcox */
437ff22b54fda2078fc3cd1bcdcb7a5ce5d08fd6591Matthew Wilcoxvoid hv_synic_cleanup(void *arg)
438427e97080196548557b288517537ab7eb48c309fKeith Busch{
439427e97080196548557b288517537ab7eb48c309fKeith Busch	union hv_synic_sint shared_sint;
440427e97080196548557b288517537ab7eb48c309fKeith Busch	union hv_synic_simp simp;
441427e97080196548557b288517537ab7eb48c309fKeith Busch	union hv_synic_siefp siefp;
442427e97080196548557b288517537ab7eb48c309fKeith Busch	int cpu = smp_processor_id();
443427e97080196548557b288517537ab7eb48c309fKeith Busch
444427e97080196548557b288517537ab7eb48c309fKeith Busch	if (!hv_context.synic_initialized)
445427e97080196548557b288517537ab7eb48c309fKeith Busch		return;
446427e97080196548557b288517537ab7eb48c309fKeith Busch
447427e97080196548557b288517537ab7eb48c309fKeith Busch	rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
448427e97080196548557b288517537ab7eb48c309fKeith Busch
449427e97080196548557b288517537ab7eb48c309fKeith Busch	shared_sint.masked = 1;
450427e97080196548557b288517537ab7eb48c309fKeith Busch
451427e97080196548557b288517537ab7eb48c309fKeith Busch	/* Need to correctly cleanup in the case of SMP!!! */
452427e97080196548557b288517537ab7eb48c309fKeith Busch	/* Disable the interrupt */
453427e97080196548557b288517537ab7eb48c309fKeith Busch	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
4541b56749e541ad59068582f2a28297843e243b856Keith Busch
4551b56749e541ad59068582f2a28297843e243b856Keith Busch	rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
456427e97080196548557b288517537ab7eb48c309fKeith Busch	simp.simp_enabled = 0;
457427e97080196548557b288517537ab7eb48c309fKeith Busch	simp.base_simp_gpa = 0;
458427e97080196548557b288517537ab7eb48c309fKeith Busch
459427e97080196548557b288517537ab7eb48c309fKeith Busch	wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
460427e97080196548557b288517537ab7eb48c309fKeith Busch
461427e97080196548557b288517537ab7eb48c309fKeith Busch	rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
462427e97080196548557b288517537ab7eb48c309fKeith Busch	siefp.siefp_enabled = 0;
463427e97080196548557b288517537ab7eb48c309fKeith Busch	siefp.base_siefp_gpa = 0;
464427e97080196548557b288517537ab7eb48c309fKeith Busch
465427e97080196548557b288517537ab7eb48c309fKeith Busch	wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
466427e97080196548557b288517537ab7eb48c309fKeith Busch
467427e97080196548557b288517537ab7eb48c309fKeith Busch	free_page((unsigned long)hv_context.synic_message_page[cpu]);
468427e97080196548557b288517537ab7eb48c309fKeith Busch	free_page((unsigned long)hv_context.synic_event_page[cpu]);
469427e97080196548557b288517537ab7eb48c309fKeith Busch}
470427e97080196548557b288517537ab7eb48c309fKeith Busch