blob: 77003bb191ecfe33369f8bbad8a4b29c8c279b23 [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
21 *
22 */
23
Bill Pembertonb7c947f2009-07-29 17:00:13 -040024#include <linux/vmalloc.h>
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -070025#include <asm/io.h>
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070026#include "include/logging.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070027#include "VmbusPrivate.h"
28
Bill Pemberton454f18a2009-07-27 16:47:24 -040029/* Globals */
Hank Janssen3e7ee492009-07-13 16:02:34 -070030
Bill Pemberton454f18a2009-07-27 16:47:24 -040031/* The one and only */
Hank Janssen3e7ee492009-07-13 16:02:34 -070032HV_CONTEXT gHvContext={
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -070033 .SynICInitialized = false,
Hank Janssen3e7ee492009-07-13 16:02:34 -070034 .HypercallPage = NULL,
35 .SignalEventParam = NULL,
36 .SignalEventBuffer = NULL,
37};
38
39
40/*++
41
42Name:
43 HvQueryHypervisorPresence()
44
45Description:
46 Query the cpuid for presense of windows hypervisor
47
48--*/
49static int
50HvQueryHypervisorPresence (
51 void
52 )
53{
54 unsigned int eax;
55 unsigned int ebx;
56 unsigned int ecx;
57 unsigned int edx;
58 unsigned int op;
59
60 eax = 0;
61 ebx = 0;
62 ecx = 0;
63 edx = 0;
64 op = HvCpuIdFunctionVersionAndFeatures;
Greg Kroah-Hartmanf931a702009-07-29 15:37:12 -070065 cpuid(op, &eax, &ebx, &ecx, &edx);
Hank Janssen3e7ee492009-07-13 16:02:34 -070066
67 return (ecx & HV_PRESENT_BIT);
68}
69
70
71/*++
72
73Name:
74 HvQueryHypervisorInfo()
75
76Description:
77 Get version info of the windows hypervisor
78
79--*/
80static int
81HvQueryHypervisorInfo (
82 void
83 )
84{
85 unsigned int eax;
86 unsigned int ebx;
87 unsigned int ecx;
88 unsigned int edx;
89 unsigned int maxLeaf;
90 unsigned int op;
91
Bill Pemberton454f18a2009-07-27 16:47:24 -040092 /*
93 * Its assumed that this is called after confirming that Viridian
94 * is present. Query id and revision.
95 */
96
Hank Janssen3e7ee492009-07-13 16:02:34 -070097
98 eax = 0;
99 ebx = 0;
100 ecx = 0;
101 edx = 0;
102 op = HvCpuIdFunctionHvVendorAndMaxFunction;
Greg Kroah-Hartmanf931a702009-07-29 15:37:12 -0700103 cpuid(op, &eax, &ebx, &ecx, &edx);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700104
105 DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
Bill Pemberton454f18a2009-07-27 16:47:24 -0400106 (ebx & 0xFF),
107 ((ebx >> 8) & 0xFF),
108 ((ebx >> 16) & 0xFF),
109 ((ebx >> 24) & 0xFF),
110 (ecx & 0xFF),
111 ((ecx >> 8) & 0xFF),
112 ((ecx >> 16) & 0xFF),
113 ((ecx >> 24) & 0xFF),
114 (edx & 0xFF),
115 ((edx >> 8) & 0xFF),
116 ((edx >> 16) & 0xFF),
117 ((edx >> 24) & 0xFF));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700118
119 maxLeaf = eax;
120 eax = 0;
121 ebx = 0;
122 ecx = 0;
123 edx = 0;
124 op = HvCpuIdFunctionHvInterface;
Greg Kroah-Hartmanf931a702009-07-29 15:37:12 -0700125 cpuid(op, &eax, &ebx, &ecx, &edx);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700126
127 DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
Bill Pemberton454f18a2009-07-27 16:47:24 -0400128 (eax & 0xFF),
129 ((eax >> 8) & 0xFF),
130 ((eax >> 16) & 0xFF),
131 ((eax >> 24) & 0xFF));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700132
133 if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400134 eax = 0;
135 ebx = 0;
136 ecx = 0;
137 edx = 0;
138 op = HvCpuIdFunctionMsHvVersion;
Greg Kroah-Hartmanf931a702009-07-29 15:37:12 -0700139 cpuid(op, &eax, &ebx, &ecx, &edx);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400140 DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
141 eax,
142 ebx >> 16,
143 ebx & 0xFFFF,
144 ecx,
145 edx >> 24,
146 edx & 0xFFFFFF);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700147 }
148 return maxLeaf;
149}
150
151
152/*++
153
154Name:
155 HvDoHypercall()
156
157Description:
158 Invoke the specified hypercall
159
160--*/
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700161static u64
Hank Janssen3e7ee492009-07-13 16:02:34 -0700162HvDoHypercall (
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700163 u64 Control,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700164 void* Input,
165 void* Output
166 )
167{
Greg Kroah-Hartman530cf202009-07-16 22:31:15 -0700168#ifdef CONFIG_X86_64
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700169 u64 hvStatus=0;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700170 u64 inputAddress = (Input)? virt_to_phys(Input) : 0;
171 u64 outputAddress = (Output)? virt_to_phys(Output) : 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700172 volatile void* hypercallPage = gHvContext.HypercallPage;
173
174 DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
175 Control,
176 inputAddress,
177 Input,
178 outputAddress,
179 Output,
180 hypercallPage);
181
182 __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
183 __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
184
185 DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
186
187 return hvStatus;
188
189#else
190
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700191 u32 controlHi = Control >> 32;
192 u32 controlLo = Control & 0xFFFFFFFF;
193 u32 hvStatusHi = 1;
194 u32 hvStatusLo = 1;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700195 u64 inputAddress = (Input) ? virt_to_phys(Input) : 0;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700196 u32 inputAddressHi = inputAddress >> 32;
197 u32 inputAddressLo = inputAddress & 0xFFFFFFFF;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700198 u64 outputAddress = (Output) ? virt_to_phys(Output) : 0;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700199 u32 outputAddressHi = outputAddress >> 32;
200 u32 outputAddressLo = outputAddress & 0xFFFFFFFF;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700201 volatile void* hypercallPage = gHvContext.HypercallPage;
202
203 DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
204 Control,
205 Input,
206 Output);
207
208 __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
209
210
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700211 DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((u64)hvStatusHi << 32));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700212
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700213 return (hvStatusLo | ((u64)hvStatusHi << 32));
Bill Pemberton454f18a2009-07-27 16:47:24 -0400214#endif /* x86_64 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700215}
216
217/*++
218
219Name:
220 HvInit()
221
222Description:
223 Main initialization routine. This routine must be called
224 before any other routines in here are called
225
226--*/
227static int
228HvInit (
229 void
230 )
231{
232 int ret=0;
233 int maxLeaf;
234 HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
Greg Kroah-Hartman949cada2009-07-29 09:06:51 -0700235 void *virtAddr = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700236
237 DPRINT_ENTER(VMBUS);
238
Bill Pemberton44f357f2009-07-28 13:46:26 -0400239 memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
240 memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700241
242 if (!HvQueryHypervisorPresence())
243 {
244 DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
245 goto Cleanup;
246 }
247
248 DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
249
250 maxLeaf = HvQueryHypervisorInfo();
Bill Pemberton454f18a2009-07-27 16:47:24 -0400251 /* HvQueryHypervisorFeatures(maxLeaf); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700252
Bill Pemberton454f18a2009-07-27 16:47:24 -0400253 /* Determine if we are running on xenlinux (ie x2v shim) or native linux */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700254 rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700255 if (gHvContext.GuestId == 0)
256 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400257 /* Write our OS info */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700258 wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700259
260 gHvContext.GuestId = HV_LINUX_GUEST_ID;
261 }
262
Bill Pemberton454f18a2009-07-27 16:47:24 -0400263 /* See if the hypercall page is already set */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700264 rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700265 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
266 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400267 /* Allocate the hypercall page memory */
Greg Kroah-Hartmanbfc30aae2009-07-29 15:40:18 -0700268 /* virtAddr = osd_PageAlloc(1); */
269 virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700270
271 if (!virtAddr)
272 {
273 DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
274 goto Cleanup;
275 }
276
277 hypercallMsr.Enable = 1;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700278 /* hypercallMsr.GuestPhysicalAddress = virt_to_phys(virtAddr) >> PAGE_SHIFT; */
279 hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700280 wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700281
Bill Pemberton454f18a2009-07-27 16:47:24 -0400282 /* Confirm that hypercall page did get setup. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700283 hypercallMsr.AsUINT64 = 0;
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700284 rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700285 if (!hypercallMsr.Enable)
286 {
287 DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
288 goto Cleanup;
289 }
290
291 gHvContext.HypercallPage = virtAddr;
292 }
293 else
294 {
295 DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
296 goto Cleanup;
297 }
298
Greg Kroah-Hartman2701f682009-07-16 12:36:37 -0700299 DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
300 gHvContext.HypercallPage,
301 (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700302
Bill Pemberton454f18a2009-07-27 16:47:24 -0400303 /* Setup the global signal event param for the signal event hypercall */
Greg Kroah-Hartmane40d37c2009-07-15 12:47:22 -0700304 gHvContext.SignalEventBuffer = kmalloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700305 if (!gHvContext.SignalEventBuffer)
306 {
307 goto Cleanup;
308 }
309
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700310 gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((unsigned long)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN));
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700311 gHvContext.SignalEventParam->ConnectionId.Asu32 = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700312 gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID;
313 gHvContext.SignalEventParam->FlagNumber = 0;
314 gHvContext.SignalEventParam->RsvdZ = 0;
315
Bill Pemberton454f18a2009-07-27 16:47:24 -0400316 /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700317
318 DPRINT_EXIT(VMBUS);
319
320 return ret;
321
322Cleanup:
323 if (virtAddr)
324 {
325 if (hypercallMsr.Enable)
326 {
327 hypercallMsr.AsUINT64 = 0;
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700328 wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700329 }
330
Bill Pembertonb7c947f2009-07-29 17:00:13 -0400331 vfree(virtAddr);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700332 }
333 ret = -1;
334 DPRINT_EXIT(VMBUS);
335
336 return ret;
337}
338
339
340/*++
341
342Name:
343 HvCleanup()
344
345Description:
346 Cleanup routine. This routine is called normally during driver unloading or exiting.
347
348--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700349static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700350HvCleanup (
351 void
352 )
353{
354 HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
355
356 DPRINT_ENTER(VMBUS);
357
358 if (gHvContext.SignalEventBuffer)
359 {
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700360 kfree(gHvContext.SignalEventBuffer);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700361 gHvContext.SignalEventBuffer = NULL;
362 gHvContext.SignalEventParam = NULL;
363 }
364
365 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
366 {
367 if (gHvContext.HypercallPage)
368 {
369 hypercallMsr.AsUINT64 = 0;
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700370 wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
Bill Pembertonb7c947f2009-07-29 17:00:13 -0400371 vfree(gHvContext.HypercallPage);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700372 gHvContext.HypercallPage = NULL;
373 }
374 }
375
376 DPRINT_EXIT(VMBUS);
377
378}
379
380
381/*++
382
383Name:
384 HvPostMessage()
385
386Description:
387 Post a message using the hypervisor message IPC. This
388 involves a hypercall.
389
390--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700391static HV_STATUS
Hank Janssen3e7ee492009-07-13 16:02:34 -0700392HvPostMessage(
393 HV_CONNECTION_ID connectionId,
394 HV_MESSAGE_TYPE messageType,
Greg Kroah-Hartman8282c402009-07-14 15:06:28 -0700395 void * payload,
Greg Kroah-Hartman45635d92009-07-14 15:14:20 -0700396 size_t payloadSize
Hank Janssen3e7ee492009-07-13 16:02:34 -0700397 )
398{
399 struct alignedInput {
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700400 u64 alignment8;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700401 HV_INPUT_POST_MESSAGE msg;
402 };
403
404 PHV_INPUT_POST_MESSAGE alignedMsg;
405 HV_STATUS status;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700406 unsigned long addr;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700407
408 if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
409 {
410 return -1;
411 }
412
Greg Kroah-Hartman0a72f3c2009-07-15 12:48:01 -0700413 addr = (unsigned long)kmalloc(sizeof(struct alignedInput), GFP_ATOMIC);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700414
415 if (!addr)
416 {
417 return -1;
418 }
419
420 alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
421
422 alignedMsg->ConnectionId = connectionId;
423 alignedMsg->MessageType = messageType;
424 alignedMsg->PayloadSize = payloadSize;
425 memcpy((void*)alignedMsg->Payload, payload, payloadSize);
426
Greg Kroah-Hartman949cada2009-07-29 09:06:51 -0700427 status = HvDoHypercall(HvCallPostMessage, alignedMsg, NULL) & 0xFFFF;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700428
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700429 kfree((void*)addr);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700430
431 return status;
432}
433
434
435/*++
436
437Name:
438 HvSignalEvent()
439
440Description:
441 Signal an event on the specified connection using the hypervisor event IPC. This
442 involves a hypercall.
443
444--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700445static HV_STATUS
Greg Kroah-Hartman12772902009-07-29 09:05:33 -0700446HvSignalEvent(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700447{
448 HV_STATUS status;
449
Greg Kroah-Hartman949cada2009-07-29 09:06:51 -0700450 status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, NULL) & 0xFFFF;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700451
452 return status;
453}
454
455
456/*++
457
458Name:
459 HvSynicInit()
460
461Description:
462 Initialize the Synthethic Interrupt Controller. If it is already initialized by
463 another entity (ie x2v shim), we need to retrieve the initialized message and event pages.
464 Otherwise, we create and initialize the message and event pages.
465
466--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700467static int
Hank Janssen3e7ee492009-07-13 16:02:34 -0700468HvSynicInit (
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700469 u32 irqVector
Hank Janssen3e7ee492009-07-13 16:02:34 -0700470 )
471{
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700472 u64 version;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700473 HV_SYNIC_SIMP simp;
474 HV_SYNIC_SIEFP siefp;
475 HV_SYNIC_SINT sharedSint;
476 HV_SYNIC_SCONTROL sctrl;
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700477 u64 guestID;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700478 int ret=0;
479
480 DPRINT_ENTER(VMBUS);
481
482 if (!gHvContext.HypercallPage)
483 {
484 DPRINT_EXIT(VMBUS);
485 return ret;
486 }
487
Bill Pemberton454f18a2009-07-27 16:47:24 -0400488 /* Check the version */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700489 rdmsrl(HV_X64_MSR_SVERSION, version);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700490
491 DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
492
Bill Pemberton454f18a2009-07-27 16:47:24 -0400493 /* TODO: Handle SMP */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700494 if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
495 {
496 DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
497
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700498 rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
499 rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700500
501 DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
502
Bill Pemberton454f18a2009-07-27 16:47:24 -0400503 /* Determine if we are running on xenlinux (ie x2v shim) or native linux */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700504 rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700505 if (guestID == HV_LINUX_GUEST_ID)
506 {
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700507 gHvContext.synICMessagePage[0] = phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT);
508 gHvContext.synICEventPage[0] = phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700509 }
510 else
511 {
512 DPRINT_ERR(VMBUS, "unknown guest id!!");
513 goto Cleanup;
514 }
515 DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
516 }
517 else
518 {
Greg Kroah-Hartmanbfc30aae2009-07-29 15:40:18 -0700519 gHvContext.synICMessagePage[0] = osd_PageAlloc(1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700520 if (gHvContext.synICMessagePage[0] == NULL)
521 {
522 DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
523 goto Cleanup;
524 }
525
Greg Kroah-Hartmanbfc30aae2009-07-29 15:40:18 -0700526 gHvContext.synICEventPage[0] = osd_PageAlloc(1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700527 if (gHvContext.synICEventPage[0] == NULL)
528 {
529 DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
530 goto Cleanup;
531 }
532
Bill Pemberton454f18a2009-07-27 16:47:24 -0400533 /* Setup the Synic's message page */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700534 rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700535 simp.SimpEnabled = 1;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700536 simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700537
538 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
539
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700540 wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700541
Bill Pemberton454f18a2009-07-27 16:47:24 -0400542 /* Setup the Synic's event page */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700543 rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700544 siefp.SiefpEnabled = 1;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700545 siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700546
547 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
548
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700549 wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700550 }
Bill Pemberton454f18a2009-07-27 16:47:24 -0400551 /* Setup the interception SINT. */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700552 /* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
Bill Pemberton454f18a2009-07-27 16:47:24 -0400553 /* interceptionSint.AsUINT64); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700554
Bill Pemberton454f18a2009-07-27 16:47:24 -0400555 /* Setup the shared SINT. */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700556 rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700557
558 sharedSint.AsUINT64 = 0;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400559 sharedSint.Vector = irqVector; /* HV_SHARED_SINT_IDT_VECTOR + 0x20; */
560 sharedSint.Masked = false;
561 sharedSint.AutoEoi = true;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700562
563 DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
564
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700565 wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700566
Bill Pemberton454f18a2009-07-27 16:47:24 -0400567 /* Enable the global synic bit */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700568 rdmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700569 sctrl.Enable = 1;
570
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700571 wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700572
Greg Kroah-Hartman0e727612009-07-15 12:46:44 -0700573 gHvContext.SynICInitialized = true;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700574
575 DPRINT_EXIT(VMBUS);
576
577 return ret;
578
579Cleanup:
580 ret = -1;
581
582 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
583 {
584 if (gHvContext.synICEventPage[0])
585 {
Greg Kroah-Hartmanbfc30aae2009-07-29 15:40:18 -0700586 osd_PageFree(gHvContext.synICEventPage[0],1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700587 }
588
589 if (gHvContext.synICMessagePage[0])
590 {
Greg Kroah-Hartmanbfc30aae2009-07-29 15:40:18 -0700591 osd_PageFree(gHvContext.synICMessagePage[0], 1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700592 }
593 }
594
595 DPRINT_EXIT(VMBUS);
596
597 return ret;
598
599}
600
601/*++
602
603Name:
604 HvSynicCleanup()
605
606Description:
607 Cleanup routine for HvSynicInit().
608
609--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700610static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700611HvSynicCleanup(
Greg Kroah-Hartmane20f6832009-07-14 15:07:21 -0700612 void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700613 )
614{
615 HV_SYNIC_SINT sharedSint;
616 HV_SYNIC_SIMP simp;
617 HV_SYNIC_SIEFP siefp;
618
619 DPRINT_ENTER(VMBUS);
620
621 if (!gHvContext.SynICInitialized)
622 {
623 DPRINT_EXIT(VMBUS);
624 return;
625 }
626
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700627 rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700628
629 sharedSint.Masked = 1;
630
Bill Pemberton454f18a2009-07-27 16:47:24 -0400631 /* Disable the interrupt */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700632 wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700633
Bill Pemberton454f18a2009-07-27 16:47:24 -0400634 /*
635 * Disable and free the resources only if we are running as
636 * native linux since in xenlinux, we are sharing the
637 * resources with the x2v shim
638 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700639 if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
640 {
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700641 rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700642 simp.SimpEnabled = 0;
643 simp.BaseSimpGpa = 0;
644
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700645 wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700646
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700647 rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700648 siefp.SiefpEnabled = 0;
649 siefp.BaseSiefpGpa = 0;
650
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700651 wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700652
Greg Kroah-Hartmanbfc30aae2009-07-29 15:40:18 -0700653 osd_PageFree(gHvContext.synICMessagePage[0], 1);
654 osd_PageFree(gHvContext.synICEventPage[0], 1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700655 }
656
657 DPRINT_EXIT(VMBUS);
658}
659
660
Bill Pemberton454f18a2009-07-27 16:47:24 -0400661/* eof */