Blame view

drivers/hv/hv.c 10 KB
3e7ee4902   Hank Janssen   Staging: hv: add ...
1
  /*
3e7ee4902   Hank Janssen   Staging: hv: add ...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   * 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>
   *
   */
0a46618d5   Hank Janssen   staging: hv: Repl...
22
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
a0086dc51   Greg Kroah-Hartman   Staging: hv: remo...
23
24
  #include <linux/kernel.h>
  #include <linux/mm.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
b7c947f04   Bill Pemberton   Staging: hv: remo...
26
  #include <linux/vmalloc.h>
46a971913   Greg Kroah-Hartman   Staging: hv: move...
27
  #include <linux/hyperv.h>
83ba0c4f3   K. Y. Srinivasan   Drivers: hv: Clea...
28
  #include <linux/version.h>
db11f12a1   K. Y. Srinivasan   Drivers: hv: Mana...
29
  #include <linux/interrupt.h>
407dd1644   Greg Kroah-Hartman   Staging: hv: remo...
30
  #include <asm/hyperv.h>
0f2a6619e   K. Y. Srinivasan   Staging: hv: vmbu...
31
  #include "hyperv_vmbus.h"
3e7ee4902   Hank Janssen   Staging: hv: add ...
32

454f18a96   Bill Pemberton   Staging: hv: Remo...
33
  /* The one and only */
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
34
35
36
  struct hv_context hv_context = {
  	.synic_initialized	= false,
  	.hypercall_page		= NULL,
3e7ee4902   Hank Janssen   Staging: hv: add ...
37
  };
3e1895195   Hank Janssen   staging: hv: Corr...
38
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
39
   * query_hypervisor_info - Get version info of the windows hypervisor
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
40
   */
5fbebb2d2   K. Y. Srinivasan   Drivers: hv: Capt...
41
42
43
44
  unsigned int host_info_eax;
  unsigned int host_info_ebx;
  unsigned int host_info_ecx;
  unsigned int host_info_edx;
d44890c8d   Haiyang Zhang   staging: hv: Conv...
45
  static int query_hypervisor_info(void)
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
46
47
48
49
50
  {
  	unsigned int eax;
  	unsigned int ebx;
  	unsigned int ecx;
  	unsigned int edx;
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
51
  	unsigned int max_leaf;
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
52
  	unsigned int op;
3e7ee4902   Hank Janssen   Staging: hv: add ...
53

0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
54
55
56
57
58
59
60
61
  	/*
  	* Its assumed that this is called after confirming that Viridian
  	* is present. Query id and revision.
  	*/
  	eax = 0;
  	ebx = 0;
  	ecx = 0;
  	edx = 0;
f6feebe07   Haiyang Zhang   staging: hv: Conv...
62
  	op = HVCPUID_VENDOR_MAXFUNCTION;
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
63
  	cpuid(op, &eax, &ebx, &ecx, &edx);
3e7ee4902   Hank Janssen   Staging: hv: add ...
64

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
65
  	max_leaf = eax;
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
66

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
67
  	if (max_leaf >= HVCPUID_VERSION) {
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
68
69
70
71
  		eax = 0;
  		ebx = 0;
  		ecx = 0;
  		edx = 0;
f6feebe07   Haiyang Zhang   staging: hv: Conv...
72
  		op = HVCPUID_VERSION;
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
73
  		cpuid(op, &eax, &ebx, &ecx, &edx);
5fbebb2d2   K. Y. Srinivasan   Drivers: hv: Capt...
74
75
76
77
  		host_info_eax = eax;
  		host_info_ebx = ebx;
  		host_info_ecx = ecx;
  		host_info_edx = edx;
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
78
  	}
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
79
  	return max_leaf;
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
80
  }
3e7ee4902   Hank Janssen   Staging: hv: add ...
81

3e1895195   Hank Janssen   staging: hv: Corr...
82
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
83
   * do_hypercall- Invoke the specified hypercall
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
84
   */
d44890c8d   Haiyang Zhang   staging: hv: Conv...
85
  static u64 do_hypercall(u64 control, void *input, void *output)
3e7ee4902   Hank Janssen   Staging: hv: add ...
86
  {
530cf2070   Greg Kroah-Hartman   Staging: hv: use ...
87
  #ifdef CONFIG_X86_64
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
88
89
90
  	u64 hv_status = 0;
  	u64 input_address = (input) ? virt_to_phys(input) : 0;
  	u64 output_address = (output) ? virt_to_phys(output) : 0;
dec317fd6   K. Y. Srinivasan   Staging: hv: vmbu...
91
  	void *hypercall_page = hv_context.hypercall_page;
3e7ee4902   Hank Janssen   Staging: hv: add ...
92

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
93
94
95
96
  	__asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
  	__asm__ __volatile__("call *%3" : "=a" (hv_status) :
  			     "c" (control), "d" (input_address),
  			     "m" (hypercall_page));
3e7ee4902   Hank Janssen   Staging: hv: add ...
97

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
98
  	return hv_status;
3e7ee4902   Hank Janssen   Staging: hv: add ...
99
100
  
  #else
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
101
102
103
104
105
106
107
108
109
110
  	u32 control_hi = control >> 32;
  	u32 control_lo = control & 0xFFFFFFFF;
  	u32 hv_status_hi = 1;
  	u32 hv_status_lo = 1;
  	u64 input_address = (input) ? virt_to_phys(input) : 0;
  	u32 input_address_hi = input_address >> 32;
  	u32 input_address_lo = input_address & 0xFFFFFFFF;
  	u64 output_address = (output) ? virt_to_phys(output) : 0;
  	u32 output_address_hi = output_address >> 32;
  	u32 output_address_lo = output_address & 0xFFFFFFFF;
dec317fd6   K. Y. Srinivasan   Staging: hv: vmbu...
111
  	void *hypercall_page = hv_context.hypercall_page;
3e7ee4902   Hank Janssen   Staging: hv: add ...
112

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
113
114
115
116
117
  	__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
  			      "=a"(hv_status_lo) : "d" (control_hi),
  			      "a" (control_lo), "b" (input_address_hi),
  			      "c" (input_address_lo), "D"(output_address_hi),
  			      "S"(output_address_lo), "m" (hypercall_page));
3e7ee4902   Hank Janssen   Staging: hv: add ...
118

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
119
  	return hv_status_lo | ((u64)hv_status_hi << 32);
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
120
  #endif /* !x86_64 */
3e7ee4902   Hank Janssen   Staging: hv: add ...
121
  }
3e1895195   Hank Janssen   staging: hv: Corr...
122
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
123
   * hv_init - Main initialization routine.
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
124
125
126
   *
   * This routine must be called before any other routines in here are called
   */
d44890c8d   Haiyang Zhang   staging: hv: Conv...
127
  int hv_init(void)
3e7ee4902   Hank Janssen   Staging: hv: add ...
128
  {
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
129
130
131
  	int max_leaf;
  	union hv_x64_msr_hypercall_contents hypercall_msr;
  	void *virtaddr = NULL;
3e7ee4902   Hank Janssen   Staging: hv: add ...
132

14c1bf8a8   K. Y. Srinivasan   drivers: hv: Incr...
133
  	memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
134
  	memset(hv_context.synic_message_page, 0,
14c1bf8a8   K. Y. Srinivasan   drivers: hv: Incr...
135
  	       sizeof(void *) * NR_CPUS);
917ea427c   K. Y. Srinivasan   Drivers: hv: Setu...
136
137
  	memset(hv_context.vp_index, 0,
  	       sizeof(int) * NR_CPUS);
db11f12a1   K. Y. Srinivasan   Drivers: hv: Mana...
138
139
  	memset(hv_context.event_dpc, 0,
  	       sizeof(void *) * NR_CPUS);
3e7ee4902   Hank Janssen   Staging: hv: add ...
140

d44890c8d   Haiyang Zhang   staging: hv: Conv...
141
  	max_leaf = query_hypervisor_info();
3e7ee4902   Hank Janssen   Staging: hv: add ...
142

83ba0c4f3   K. Y. Srinivasan   Drivers: hv: Clea...
143
144
145
146
147
  	/*
  	 * Write our OS ID.
  	 */
  	hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
  	wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
148

454f18a96   Bill Pemberton   Staging: hv: Remo...
149
  	/* See if the hypercall page is already set */
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
150
  	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
151

df3493e0b   K. Y. Srinivasan   Staging: hv: Use ...
152
  	virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
3e7ee4902   Hank Janssen   Staging: hv: add ...
153

98e087022   Hank Janssen   staging: hv: Remo...
154
  	if (!virtaddr)
44939d37c   K. Y. Srinivasan   Staging: hv: Chan...
155
  		goto cleanup;
3e7ee4902   Hank Janssen   Staging: hv: add ...
156

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
157
  	hypercall_msr.enable = 1;
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
158

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
159
160
  	hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr);
  	wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
161
162
  
  	/* Confirm that hypercall page did get setup. */
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
163
164
  	hypercall_msr.as_uint64 = 0;
  	rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
165

98e087022   Hank Janssen   staging: hv: Remo...
166
  	if (!hypercall_msr.enable)
44939d37c   K. Y. Srinivasan   Staging: hv: Chan...
167
  		goto cleanup;
3e7ee4902   Hank Janssen   Staging: hv: add ...
168

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
169
  	hv_context.hypercall_page = virtaddr;
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
170

5433e0033   K. Y. Srinivasan   Staging: hv: vmbu...
171
  	return 0;
3e7ee4902   Hank Janssen   Staging: hv: add ...
172

44939d37c   K. Y. Srinivasan   Staging: hv: Chan...
173
  cleanup:
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
174
175
176
177
  	if (virtaddr) {
  		if (hypercall_msr.enable) {
  			hypercall_msr.as_uint64 = 0;
  			wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
178
  		}
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
179
  		vfree(virtaddr);
3e7ee4902   Hank Janssen   Staging: hv: add ...
180
  	}
5433e0033   K. Y. Srinivasan   Staging: hv: vmbu...
181
182
  
  	return -ENOTSUPP;
3e7ee4902   Hank Janssen   Staging: hv: add ...
183
  }
3e1895195   Hank Janssen   staging: hv: Corr...
184
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
185
   * hv_cleanup - Cleanup routine.
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
186
187
188
   *
   * This routine is called normally during driver unloading or exiting.
   */
d44890c8d   Haiyang Zhang   staging: hv: Conv...
189
  void hv_cleanup(void)
3e7ee4902   Hank Janssen   Staging: hv: add ...
190
  {
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
191
  	union hv_x64_msr_hypercall_contents hypercall_msr;
3e7ee4902   Hank Janssen   Staging: hv: add ...
192

93e5bd06a   K. Y. Srinivasan   Drivers: hv: Make...
193
194
  	/* Reset our OS id */
  	wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
195
  	if (hv_context.hypercall_page) {
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
196
197
  		hypercall_msr.as_uint64 = 0;
  		wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
198
199
  		vfree(hv_context.hypercall_page);
  		hv_context.hypercall_page = NULL;
3e7ee4902   Hank Janssen   Staging: hv: add ...
200
  	}
3e7ee4902   Hank Janssen   Staging: hv: add ...
201
  }
3e1895195   Hank Janssen   staging: hv: Corr...
202
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
203
   * hv_post_message - Post a message using the hypervisor message IPC.
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
204
205
206
   *
   * This involves a hypercall.
   */
415f0a02a   Dan Carpenter   hv: fix return ty...
207
  int hv_post_message(union hv_connection_id connection_id,
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
208
209
  		  enum hv_message_type message_type,
  		  void *payload, size_t payload_size)
3e7ee4902   Hank Janssen   Staging: hv: add ...
210
  {
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
211
  	struct aligned_input {
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
212
  		u64 alignment8;
cba4decdd   Greg Kroah-Hartman   Staging: hv: codi...
213
  		struct hv_input_post_message msg;
3e7ee4902   Hank Janssen   Staging: hv: add ...
214
  	};
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
215
  	struct hv_input_post_message *aligned_msg;
034469e63   Greg Kroah-Hartman   Staging: hv: codi...
216
  	u16 status;
c4b0bc948   Greg Kroah-Hartman   Staging: hv: remo...
217
  	unsigned long addr;
3e7ee4902   Hank Janssen   Staging: hv: add ...
218

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
219
  	if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
39594abcd   K. Y. Srinivasan   Staging: hv: vmbu...
220
  		return -EMSGSIZE;
3e7ee4902   Hank Janssen   Staging: hv: add ...
221

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
222
  	addr = (unsigned long)kmalloc(sizeof(struct aligned_input), GFP_ATOMIC);
3e7ee4902   Hank Janssen   Staging: hv: add ...
223
  	if (!addr)
39594abcd   K. Y. Srinivasan   Staging: hv: vmbu...
224
  		return -ENOMEM;
3e7ee4902   Hank Janssen   Staging: hv: add ...
225

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
226
  	aligned_msg = (struct hv_input_post_message *)
735096819   Uwe Kleine-König   staging/hv/osd: d...
227
  			(ALIGN(addr, HV_HYPERCALL_PARAM_ALIGN));
3e7ee4902   Hank Janssen   Staging: hv: add ...
228

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
229
230
231
232
  	aligned_msg->connectionid = connection_id;
  	aligned_msg->message_type = message_type;
  	aligned_msg->payload_size = payload_size;
  	memcpy((void *)aligned_msg->payload, payload, payload_size);
3e7ee4902   Hank Janssen   Staging: hv: add ...
233

d44890c8d   Haiyang Zhang   staging: hv: Conv...
234
235
  	status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL)
  		& 0xFFFF;
3e7ee4902   Hank Janssen   Staging: hv: add ...
236

0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
237
  	kfree((void *)addr);
3e7ee4902   Hank Janssen   Staging: hv: add ...
238
239
240
  
  	return status;
  }
3e1895195   Hank Janssen   staging: hv: Corr...
241
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
242
243
   * hv_signal_event -
   * Signal an event on the specified connection using the hypervisor event IPC.
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
244
245
246
   *
   * This involves a hypercall.
   */
1f42248d7   K. Y. Srinivasan   Drivers: hv: Chan...
247
  u16 hv_signal_event(void *con_id)
3e7ee4902   Hank Janssen   Staging: hv: add ...
248
  {
034469e63   Greg Kroah-Hartman   Staging: hv: codi...
249
  	u16 status;
3e7ee4902   Hank Janssen   Staging: hv: add ...
250

1f42248d7   K. Y. Srinivasan   Drivers: hv: Chan...
251
  	status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0xFFFF);
3e7ee4902   Hank Janssen   Staging: hv: add ...
252
253
  	return status;
  }
3e1895195   Hank Janssen   staging: hv: Corr...
254
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
255
   * hv_synic_init - Initialize the Synthethic Interrupt Controller.
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
256
257
258
259
260
   *
   * If it is already initialized by another entity (ie x2v shim), we need to
   * retrieve the initialized message and event pages.  Otherwise, we create and
   * initialize the message and event pages.
   */
302a3c0f2   K. Y. Srinivasan   Drivers: hv: vmbu...
261
  void hv_synic_init(void *arg)
3e7ee4902   Hank Janssen   Staging: hv: add ...
262
  {
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
263
  	u64 version;
eacb1b4d2   Greg Kroah-Hartman   Staging: hv: typd...
264
265
  	union hv_synic_simp simp;
  	union hv_synic_siefp siefp;
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
266
  	union hv_synic_sint shared_sint;
eacb1b4d2   Greg Kroah-Hartman   Staging: hv: typd...
267
  	union hv_synic_scontrol sctrl;
917ea427c   K. Y. Srinivasan   Drivers: hv: Setu...
268
  	u64 vp_index;
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
269

7692fd4d4   Greg Kroah-Hartman   Staging: hv: fix ...
270
  	int cpu = smp_processor_id();
3e7ee4902   Hank Janssen   Staging: hv: add ...
271

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
272
  	if (!hv_context.hypercall_page)
7692fd4d4   Greg Kroah-Hartman   Staging: hv: fix ...
273
  		return;
3e7ee4902   Hank Janssen   Staging: hv: add ...
274

454f18a96   Bill Pemberton   Staging: hv: Remo...
275
  	/* Check the version */
a51ed7d65   Greg Kroah-Hartman   Staging: hv: remo...
276
  	rdmsrl(HV_X64_MSR_SVERSION, version);
3e7ee4902   Hank Janssen   Staging: hv: add ...
277

333494842   Zhang Yanfei   driver: hv: remov...
278
279
  	hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct),
  					    GFP_ATOMIC);
db11f12a1   K. Y. Srinivasan   Drivers: hv: Mana...
280
281
282
283
284
285
  	if (hv_context.event_dpc[cpu] == NULL) {
  		pr_err("Unable to allocate event dpc
  ");
  		goto cleanup;
  	}
  	tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
286
287
  	hv_context.synic_message_page[cpu] =
  		(void *)get_zeroed_page(GFP_ATOMIC);
3e7ee4902   Hank Janssen   Staging: hv: add ...
288

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
289
  	if (hv_context.synic_message_page[cpu] == NULL) {
0a46618d5   Hank Janssen   staging: hv: Repl...
290
291
  		pr_err("Unable to allocate SYNIC message page
  ");
44939d37c   K. Y. Srinivasan   Staging: hv: Chan...
292
  		goto cleanup;
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
293
  	}
3e7ee4902   Hank Janssen   Staging: hv: add ...
294

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
295
296
  	hv_context.synic_event_page[cpu] =
  		(void *)get_zeroed_page(GFP_ATOMIC);
3e7ee4902   Hank Janssen   Staging: hv: add ...
297

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
298
  	if (hv_context.synic_event_page[cpu] == NULL) {
0a46618d5   Hank Janssen   staging: hv: Repl...
299
300
  		pr_err("Unable to allocate SYNIC event page
  ");
44939d37c   K. Y. Srinivasan   Staging: hv: Chan...
301
  		goto cleanup;
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
302
  	}
3e7ee4902   Hank Janssen   Staging: hv: add ...
303

a73e6b7c5   Hank Janssen   Staging: hv: Remo...
304
  	/* Setup the Synic's message page */
f6feebe07   Haiyang Zhang   staging: hv: Conv...
305
306
  	rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
  	simp.simp_enabled = 1;
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
307
  	simp.base_simp_gpa = virt_to_phys(hv_context.synic_message_page[cpu])
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
308
  		>> PAGE_SHIFT;
3e7ee4902   Hank Janssen   Staging: hv: add ...
309

f6feebe07   Haiyang Zhang   staging: hv: Conv...
310
  	wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
311

a73e6b7c5   Hank Janssen   Staging: hv: Remo...
312
  	/* Setup the Synic's event page */
f6feebe07   Haiyang Zhang   staging: hv: Conv...
313
314
  	rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
  	siefp.siefp_enabled = 1;
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
315
  	siefp.base_siefp_gpa = virt_to_phys(hv_context.synic_event_page[cpu])
a73e6b7c5   Hank Janssen   Staging: hv: Remo...
316
  		>> PAGE_SHIFT;
f6feebe07   Haiyang Zhang   staging: hv: Conv...
317
  	wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
318

0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
319
  	/* Setup the shared SINT. */
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
320
  	rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
321

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
322
  	shared_sint.as_uint64 = 0;
302a3c0f2   K. Y. Srinivasan   Drivers: hv: vmbu...
323
  	shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR;
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
324
  	shared_sint.masked = false;
b0209501d   K. Y. Srinivasan   Drivers: hv: Hand...
325
  	shared_sint.auto_eoi = true;
3e7ee4902   Hank Janssen   Staging: hv: add ...
326

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
327
  	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
328

454f18a96   Bill Pemberton   Staging: hv: Remo...
329
  	/* Enable the global synic bit */
f6feebe07   Haiyang Zhang   staging: hv: Conv...
330
331
  	rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
  	sctrl.enable = 1;
3e7ee4902   Hank Janssen   Staging: hv: add ...
332

f6feebe07   Haiyang Zhang   staging: hv: Conv...
333
  	wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
334

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
335
  	hv_context.synic_initialized = true;
917ea427c   K. Y. Srinivasan   Drivers: hv: Setu...
336
337
338
339
340
341
342
343
  
  	/*
  	 * Setup the mapping between Hyper-V's notion
  	 * of cpuid and Linux' notion of cpuid.
  	 * This array will be indexed using Linux cpuid.
  	 */
  	rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
  	hv_context.vp_index[cpu] = (u32)vp_index;
7692fd4d4   Greg Kroah-Hartman   Staging: hv: fix ...
344
  	return;
3e7ee4902   Hank Janssen   Staging: hv: add ...
345

44939d37c   K. Y. Srinivasan   Staging: hv: Chan...
346
  cleanup:
6a0aaa185   Haiyang Zhang   staging: hv: Conv...
347
  	if (hv_context.synic_event_page[cpu])
df3493e0b   K. Y. Srinivasan   Staging: hv: Use ...
348
  		free_page((unsigned long)hv_context.synic_event_page[cpu]);
3e7ee4902   Hank Janssen   Staging: hv: add ...
349

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
350
  	if (hv_context.synic_message_page[cpu])
df3493e0b   K. Y. Srinivasan   Staging: hv: Use ...
351
  		free_page((unsigned long)hv_context.synic_message_page[cpu]);
7692fd4d4   Greg Kroah-Hartman   Staging: hv: fix ...
352
  	return;
3e7ee4902   Hank Janssen   Staging: hv: add ...
353
  }
3e1895195   Hank Janssen   staging: hv: Corr...
354
  /*
d44890c8d   Haiyang Zhang   staging: hv: Conv...
355
   * hv_synic_cleanup - Cleanup routine for hv_synic_init().
0831ad041   Greg Kroah-Hartman   Staging: hv: fix ...
356
   */
d44890c8d   Haiyang Zhang   staging: hv: Conv...
357
  void hv_synic_cleanup(void *arg)
3e7ee4902   Hank Janssen   Staging: hv: add ...
358
  {
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
359
  	union hv_synic_sint shared_sint;
eacb1b4d2   Greg Kroah-Hartman   Staging: hv: typd...
360
361
  	union hv_synic_simp simp;
  	union hv_synic_siefp siefp;
7692fd4d4   Greg Kroah-Hartman   Staging: hv: fix ...
362
  	int cpu = smp_processor_id();
3e7ee4902   Hank Janssen   Staging: hv: add ...
363

6a0aaa185   Haiyang Zhang   staging: hv: Conv...
364
  	if (!hv_context.synic_initialized)
3e7ee4902   Hank Janssen   Staging: hv: add ...
365
  		return;
3e7ee4902   Hank Janssen   Staging: hv: add ...
366

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
367
  	rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
368

b8dfb264f   Haiyang Zhang   staging: hv: Conv...
369
  	shared_sint.masked = 1;
3e7ee4902   Hank Janssen   Staging: hv: add ...
370

7692fd4d4   Greg Kroah-Hartman   Staging: hv: fix ...
371
  	/* Need to correctly cleanup in the case of SMP!!! */
454f18a96   Bill Pemberton   Staging: hv: Remo...
372
  	/* Disable the interrupt */
b8dfb264f   Haiyang Zhang   staging: hv: Conv...
373
  	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
374

f6feebe07   Haiyang Zhang   staging: hv: Conv...
375
376
377
  	rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
  	simp.simp_enabled = 0;
  	simp.base_simp_gpa = 0;
3e7ee4902   Hank Janssen   Staging: hv: add ...
378

f6feebe07   Haiyang Zhang   staging: hv: Conv...
379
  	wrmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
380

f6feebe07   Haiyang Zhang   staging: hv: Conv...
381
382
383
  	rdmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
  	siefp.siefp_enabled = 0;
  	siefp.base_siefp_gpa = 0;
3e7ee4902   Hank Janssen   Staging: hv: add ...
384

f6feebe07   Haiyang Zhang   staging: hv: Conv...
385
  	wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64);
3e7ee4902   Hank Janssen   Staging: hv: add ...
386

df3493e0b   K. Y. Srinivasan   Staging: hv: Use ...
387
388
  	free_page((unsigned long)hv_context.synic_message_page[cpu]);
  	free_page((unsigned long)hv_context.synic_event_page[cpu]);
3e7ee4902   Hank Janssen   Staging: hv: add ...
389
  }