blob: b3004cb9b6c9ae7fa42858898ee0aa4808c05d05 [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
Greg Kroah-Hartman5654e932009-07-14 15:08:20 -070024#include <linux/kernel.h>
Greg Kroah-Hartman0ffa63b2009-07-15 11:06:01 -070025#include <linux/mm.h>
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070026#include "osd.h"
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070027#include "include/logging.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070028#include "VersionInfo.h"
29#include "VmbusPrivate.h"
30
Bill Pemberton454f18a2009-07-27 16:47:24 -040031
32/* Globals */
33
Hank Janssen3e7ee492009-07-13 16:02:34 -070034static const char* gDriverName="vmbus";
35
Bill Pemberton454f18a2009-07-27 16:47:24 -040036/* Windows vmbus does not defined this.
37 * We defined this to be consistent with other devices
38 */
39/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -070040static const struct hv_guid gVmbusDeviceType = {
41 .data = {
42 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
43 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
44 }
Hank Janssen3e7ee492009-07-13 16:02:34 -070045};
46
Bill Pemberton454f18a2009-07-27 16:47:24 -040047/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -070048static const struct hv_guid gVmbusDeviceId = {
49 .data = {
50 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
51 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
52 }
Hank Janssen3e7ee492009-07-13 16:02:34 -070053};
54
Nicolas Palix775ef252009-07-29 14:09:45 +020055static struct hv_driver *gDriver; /* vmbus driver object */
Nicolas Palix3d3b5512009-07-28 17:32:53 +020056static struct hv_device* gDevice; /* vmbus root device */
Hank Janssen3e7ee492009-07-13 16:02:34 -070057
58
Bill Pemberton454f18a2009-07-27 16:47:24 -040059
60/* Internal routines */
61
Hank Janssen3e7ee492009-07-13 16:02:34 -070062
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -070063static void VmbusGetChannelInterface(struct vmbus_channel_interface *Interface);
Hank Janssen3e7ee492009-07-13 16:02:34 -070064
65static void
66VmbusGetChannelInfo(
Nicolas Palix3d3b5512009-07-28 17:32:53 +020067 struct hv_device *DeviceObject,
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -070068 struct hv_device_info *DeviceInfo
Hank Janssen3e7ee492009-07-13 16:02:34 -070069 );
70
71static void
72VmbusGetChannelOffers(
73 void
74 );
75
76static int
77VmbusOnDeviceAdd(
Nicolas Palix3d3b5512009-07-28 17:32:53 +020078 struct hv_device *Device,
Hank Janssen3e7ee492009-07-13 16:02:34 -070079 void *AdditionalInfo
80 );
81
82static int
83VmbusOnDeviceRemove(
Nicolas Palix3d3b5512009-07-28 17:32:53 +020084 struct hv_device *dev
Hank Janssen3e7ee492009-07-13 16:02:34 -070085 );
86
87static void
88VmbusOnCleanup(
Nicolas Palix775ef252009-07-29 14:09:45 +020089 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -070090 );
91
92static int
93VmbusOnISR(
Nicolas Palix775ef252009-07-29 14:09:45 +020094 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -070095 );
96
97static void
98VmbusOnMsgDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +020099 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700100 );
101
102static void
103VmbusOnEventDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200104 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700105 );
106
107/*++;
108
109Name:
110 VmbusInitialize()
111
112Description:
113 Main entry point
114
115--*/
116int
117VmbusInitialize(
Nicolas Palix775ef252009-07-29 14:09:45 +0200118 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700119 )
120{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700121 struct vmbus_driver *driver = (struct vmbus_driver *)drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700122 int ret=0;
123
124 DPRINT_ENTER(VMBUS);
125
126 DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
127 DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
128
129 DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
130 DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
131
Greg Kroah-Hartmanb7d7ae62009-07-28 16:18:05 -0700132 DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
Bill Pemberton3fcc5232009-07-27 16:47:40 -0400133 sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700134
135 drv->name = gDriverName;
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700136 memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700137
Bill Pemberton454f18a2009-07-27 16:47:24 -0400138 /* Setup dispatch table */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700139 driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
140 driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
141 driver->Base.OnCleanup = VmbusOnCleanup;
142 driver->OnIsr = VmbusOnISR;
143 driver->OnMsgDpc = VmbusOnMsgDPC;
144 driver->OnEventDpc = VmbusOnEventDPC;
145 driver->GetChannelOffers = VmbusGetChannelOffers;
146 driver->GetChannelInterface = VmbusGetChannelInterface;
147 driver->GetChannelInfo = VmbusGetChannelInfo;
148
Bill Pemberton454f18a2009-07-27 16:47:24 -0400149 /* Hypervisor initialization...setup hypercall page..etc */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700150 ret = HvInit();
151 if (ret != 0)
152 {
153 DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
154 }
155
156 gDriver = drv;
157
158 DPRINT_EXIT(VMBUS);
159
160 return ret;
161}
162
163
164/*++;
165
166Name:
167 VmbusGetChannelOffers()
168
169Description:
170 Retrieve the channel offers from the parent partition
171
172--*/
173
174static void
175VmbusGetChannelOffers(void)
176{
177 DPRINT_ENTER(VMBUS);
178 VmbusChannelRequestOffers();
179 DPRINT_EXIT(VMBUS);
180}
181
182
183/*++;
184
185Name:
186 VmbusGetChannelInterface()
187
188Description:
189 Get the channel interface
190
191--*/
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700192static void VmbusGetChannelInterface(struct vmbus_channel_interface *Interface)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700193{
194 GetChannelInterface(Interface);
195}
196
197
198/*++;
199
200Name:
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700201 VmbusGetChannelInfo()
Hank Janssen3e7ee492009-07-13 16:02:34 -0700202
203Description:
204 Get the device info for the specified device object
205
206--*/
207static void
208VmbusGetChannelInfo(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200209 struct hv_device *DeviceObject,
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700210 struct hv_device_info *DeviceInfo
Hank Janssen3e7ee492009-07-13 16:02:34 -0700211 )
212{
213 GetChannelInfo(DeviceObject, DeviceInfo);
214}
215
216
217
218/*++
219
220Name:
221 VmbusCreateChildDevice()
222
223Description:
224 Creates the child device on the bus that represents the channel offer
225
226--*/
227
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700228struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
229 struct hv_guid *DeviceInstance,
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700230 void *Context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700231{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700232 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700233
234 return vmbusDriver->OnChildDeviceCreate(
235 DeviceType,
236 DeviceInstance,
237 Context);
238}
239
240
241/*++
242
243Name:
244 VmbusChildDeviceAdd()
245
246Description:
247 Registers the child device with the vmbus
248
249--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700250int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700251{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700252 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700253
254 return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
255}
256
257
258/*++
259
260Name:
261 VmbusChildDeviceRemove()
262
263Description:
264 Unregisters the child device from the vmbus
265
266--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700267void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700268{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700269 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700270
271 vmbusDriver->OnChildDeviceRemove(ChildDevice);
272}
273
274/*++
275
276Name:
277 VmbusChildDeviceDestroy()
278
279Description:
280 Release the child device from the vmbus
281
282--*/
Bill Pemberton454f18a2009-07-27 16:47:24 -0400283
284/* **************
285void
286VmbusChildDeviceDestroy(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200287struct hv_device *ChildDevice
Bill Pemberton454f18a2009-07-27 16:47:24 -0400288)
289{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700290 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400291
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700292 vmbusDriver->OnChildDeviceDestroy(ChildDevice);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400293}
294************* */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700295
296/*++
297
298Name:
299 VmbusOnDeviceAdd()
300
301Description:
302 Callback when the root bus device is added
303
304--*/
305static int
306VmbusOnDeviceAdd(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200307 struct hv_device *dev,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700308 void *AdditionalInfo
309 )
310{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700311 u32 *irqvector = (u32*) AdditionalInfo;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700312 int ret=0;
313
314 DPRINT_ENTER(VMBUS);
315
316 gDevice = dev;
317
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700318 memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
319 memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700320
Bill Pemberton454f18a2009-07-27 16:47:24 -0400321 /* strcpy(dev->name, "vmbus"); */
322 /* SynIC setup... */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700323 ret = HvSynicInit(*irqvector);
324
Bill Pemberton454f18a2009-07-27 16:47:24 -0400325 /* Connect to VMBus in the root partition */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700326 ret = VmbusConnect();
327
Bill Pemberton454f18a2009-07-27 16:47:24 -0400328 /* VmbusSendEvent(device->localPortId+1); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700329 DPRINT_EXIT(VMBUS);
330
331 return ret;
332}
333
334
335/*++
336
337Name:
338 VmbusOnDeviceRemove()
339
340Description:
341 Callback when the root bus device is removed
342
343--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700344static int VmbusOnDeviceRemove(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200345 struct hv_device *dev
Hank Janssen3e7ee492009-07-13 16:02:34 -0700346 )
347{
348 int ret=0;
349
350 DPRINT_ENTER(VMBUS);
351
352 VmbusChannelReleaseUnattachedChannels();
353
354 VmbusDisconnect();
355
356 HvSynicCleanup();
357
358 DPRINT_EXIT(VMBUS);
359
360 return ret;
361}
362
363
364/*++
365
366Name:
367 VmbusOnCleanup()
368
369Description:
370 Perform any cleanup when the driver is removed
371
372--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700373static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700374VmbusOnCleanup(
Nicolas Palix775ef252009-07-29 14:09:45 +0200375 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700376 )
377{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700378 /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700379
380 DPRINT_ENTER(VMBUS);
381
382 HvCleanup();
383
384 DPRINT_EXIT(VMBUS);
385}
386
387
388/*++
389
390Name:
391 VmbusOnMsgDPC()
392
393Description:
394 DPC routine to handle messages from the hypervisior
395
396--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700397static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700398VmbusOnMsgDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200399 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700400 )
401{
402 void *page_addr = gHvContext.synICMessagePage[0];
403
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700404 struct hv_message *msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
405 struct hv_message *copied;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700406 while (1)
407 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400408 if (msg->Header.MessageType == HvMessageTypeNone) /* no msg */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700409 {
410 break;
411 }
412 else
413 {
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700414 copied = kmalloc(sizeof(*copied), GFP_ATOMIC);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415 if (copied == NULL)
416 {
417 continue;
418 }
419
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700420 memcpy(copied, msg, sizeof(*copied));
Bill Pembertonde65a382009-07-29 17:00:09 -0400421 osd_schedule_callback(gVmbusConnection.WorkQueue,
422 VmbusOnChannelMessage,
423 (void *)copied);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700424 }
425
426 msg->Header.MessageType = HvMessageTypeNone;
427
Bill Pemberton454f18a2009-07-27 16:47:24 -0400428 /*
429 * Make sure the write to MessageType (ie set to
430 * HvMessageTypeNone) happens before we read the
431 * MessagePending and EOMing. Otherwise, the EOMing
432 * will not deliver any more messages since there is
433 * no empty slot
434 */
Greg Kroah-Hartman28b6ca92009-07-16 12:34:20 -0700435 mb();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700436
437 if (msg->Header.MessageFlags.MessagePending)
438 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400439 /*
440 * This will cause message queue rescan to
441 * possibly deliver another msg from the
442 * hypervisor
443 */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700444 wrmsrl(HV_X64_MSR_EOM, 0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700445 }
446 }
447}
448
449/*++
450
451Name:
452 VmbusOnEventDPC()
453
454Description:
455 DPC routine to handle events from the hypervisior
456
457--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700458static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700459VmbusOnEventDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200460 struct hv_driver* drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700461 )
462{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400463 /* TODO: Process any events */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700464 VmbusOnEvents();
465}
466
467
468/*++
469
470Name:
471 VmbusOnISR()
472
473Description:
474 ISR routine
475
476--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700477static int
Hank Janssen3e7ee492009-07-13 16:02:34 -0700478VmbusOnISR(
Nicolas Palix775ef252009-07-29 14:09:45 +0200479 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700480 )
481{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700482 /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700483
484 int ret=0;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400485 /* struct page* page; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700486 void *page_addr;
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700487 struct hv_message *msg;
488 union hv_synic_event_flags *event;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700489
Bill Pemberton454f18a2009-07-27 16:47:24 -0400490 /* page = SynICMessagePage[0]; */
491 /* page_addr = page_address(page); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700492 page_addr = gHvContext.synICMessagePage[0];
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700493 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700494
495 DPRINT_ENTER(VMBUS);
496
Bill Pemberton454f18a2009-07-27 16:47:24 -0400497 /* Check if there are actual msgs to be process */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700498 if (msg->Header.MessageType != HvMessageTypeNone)
499 {
500 DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
501 ret |= 0x1;
502 }
503
Bill Pemberton454f18a2009-07-27 16:47:24 -0400504 /* TODO: Check if there are events to be process */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700505 page_addr = gHvContext.synICEventPage[0];
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700506 event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700507
Bill Pemberton454f18a2009-07-27 16:47:24 -0400508 /* Since we are a child, we only need to check bit 0 */
Bill Pemberton7c369f42009-07-29 17:00:11 -0400509 if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0]))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700510 {
511 DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
512 ret |= 0x2;
513 }
514
515 DPRINT_EXIT(VMBUS);
516 return ret;
517}
518
Bill Pemberton454f18a2009-07-27 16:47:24 -0400519/* eof */