blob: e39cea1434a6edf91eb1b047d34b01bbacba6f7b [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
63static void
64VmbusGetChannelInterface(
65 VMBUS_CHANNEL_INTERFACE *Interface
66 );
67
68static void
69VmbusGetChannelInfo(
Nicolas Palix3d3b5512009-07-28 17:32:53 +020070 struct hv_device *DeviceObject,
Hank Janssen3e7ee492009-07-13 16:02:34 -070071 DEVICE_INFO *DeviceInfo
72 );
73
74static void
75VmbusGetChannelOffers(
76 void
77 );
78
79static int
80VmbusOnDeviceAdd(
Nicolas Palix3d3b5512009-07-28 17:32:53 +020081 struct hv_device *Device,
Hank Janssen3e7ee492009-07-13 16:02:34 -070082 void *AdditionalInfo
83 );
84
85static int
86VmbusOnDeviceRemove(
Nicolas Palix3d3b5512009-07-28 17:32:53 +020087 struct hv_device *dev
Hank Janssen3e7ee492009-07-13 16:02:34 -070088 );
89
90static void
91VmbusOnCleanup(
Nicolas Palix775ef252009-07-29 14:09:45 +020092 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -070093 );
94
95static int
96VmbusOnISR(
Nicolas Palix775ef252009-07-29 14:09:45 +020097 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -070098 );
99
100static void
101VmbusOnMsgDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200102 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700103 );
104
105static void
106VmbusOnEventDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200107 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700108 );
109
110/*++;
111
112Name:
113 VmbusInitialize()
114
115Description:
116 Main entry point
117
118--*/
119int
120VmbusInitialize(
Nicolas Palix775ef252009-07-29 14:09:45 +0200121 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700122 )
123{
124 VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
125 int ret=0;
126
127 DPRINT_ENTER(VMBUS);
128
129 DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
130 DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
131
132 DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
133 DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
134
Greg Kroah-Hartmanb7d7ae62009-07-28 16:18:05 -0700135 DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
Bill Pemberton3fcc5232009-07-27 16:47:40 -0400136 sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700137
138 drv->name = gDriverName;
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700139 memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700140
Bill Pemberton454f18a2009-07-27 16:47:24 -0400141 /* Setup dispatch table */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700142 driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
143 driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
144 driver->Base.OnCleanup = VmbusOnCleanup;
145 driver->OnIsr = VmbusOnISR;
146 driver->OnMsgDpc = VmbusOnMsgDPC;
147 driver->OnEventDpc = VmbusOnEventDPC;
148 driver->GetChannelOffers = VmbusGetChannelOffers;
149 driver->GetChannelInterface = VmbusGetChannelInterface;
150 driver->GetChannelInfo = VmbusGetChannelInfo;
151
Bill Pemberton454f18a2009-07-27 16:47:24 -0400152 /* Hypervisor initialization...setup hypercall page..etc */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700153 ret = HvInit();
154 if (ret != 0)
155 {
156 DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
157 }
158
159 gDriver = drv;
160
161 DPRINT_EXIT(VMBUS);
162
163 return ret;
164}
165
166
167/*++;
168
169Name:
170 VmbusGetChannelOffers()
171
172Description:
173 Retrieve the channel offers from the parent partition
174
175--*/
176
177static void
178VmbusGetChannelOffers(void)
179{
180 DPRINT_ENTER(VMBUS);
181 VmbusChannelRequestOffers();
182 DPRINT_EXIT(VMBUS);
183}
184
185
186/*++;
187
188Name:
189 VmbusGetChannelInterface()
190
191Description:
192 Get the channel interface
193
194--*/
195static void
196VmbusGetChannelInterface(
197 VMBUS_CHANNEL_INTERFACE *Interface
198 )
199{
200 GetChannelInterface(Interface);
201}
202
203
204/*++;
205
206Name:
207 VmbusGetChannelInterface()
208
209Description:
210 Get the device info for the specified device object
211
212--*/
213static void
214VmbusGetChannelInfo(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200215 struct hv_device *DeviceObject,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700216 DEVICE_INFO *DeviceInfo
217 )
218{
219 GetChannelInfo(DeviceObject, DeviceInfo);
220}
221
222
223
224/*++
225
226Name:
227 VmbusCreateChildDevice()
228
229Description:
230 Creates the child device on the bus that represents the channel offer
231
232--*/
233
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700234struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
235 struct hv_guid *DeviceInstance,
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700236 void *Context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700237{
238 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
239
240 return vmbusDriver->OnChildDeviceCreate(
241 DeviceType,
242 DeviceInstance,
243 Context);
244}
245
246
247/*++
248
249Name:
250 VmbusChildDeviceAdd()
251
252Description:
253 Registers the child device with the vmbus
254
255--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700256int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700257{
258 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
259
260 return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
261}
262
263
264/*++
265
266Name:
267 VmbusChildDeviceRemove()
268
269Description:
270 Unregisters the child device from the vmbus
271
272--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700273void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700274{
275 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
276
277 vmbusDriver->OnChildDeviceRemove(ChildDevice);
278}
279
280/*++
281
282Name:
283 VmbusChildDeviceDestroy()
284
285Description:
286 Release the child device from the vmbus
287
288--*/
Bill Pemberton454f18a2009-07-27 16:47:24 -0400289
290/* **************
291void
292VmbusChildDeviceDestroy(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200293struct hv_device *ChildDevice
Bill Pemberton454f18a2009-07-27 16:47:24 -0400294)
295{
296VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
297
298vmbusDriver->OnChildDeviceDestroy(ChildDevice);
299}
300************* */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700301
302/*++
303
304Name:
305 VmbusOnDeviceAdd()
306
307Description:
308 Callback when the root bus device is added
309
310--*/
311static int
312VmbusOnDeviceAdd(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200313 struct hv_device *dev,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700314 void *AdditionalInfo
315 )
316{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700317 u32 *irqvector = (u32*) AdditionalInfo;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700318 int ret=0;
319
320 DPRINT_ENTER(VMBUS);
321
322 gDevice = dev;
323
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700324 memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
325 memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700326
Bill Pemberton454f18a2009-07-27 16:47:24 -0400327 /* strcpy(dev->name, "vmbus"); */
328 /* SynIC setup... */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700329 ret = HvSynicInit(*irqvector);
330
Bill Pemberton454f18a2009-07-27 16:47:24 -0400331 /* Connect to VMBus in the root partition */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700332 ret = VmbusConnect();
333
Bill Pemberton454f18a2009-07-27 16:47:24 -0400334 /* VmbusSendEvent(device->localPortId+1); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700335 DPRINT_EXIT(VMBUS);
336
337 return ret;
338}
339
340
341/*++
342
343Name:
344 VmbusOnDeviceRemove()
345
346Description:
347 Callback when the root bus device is removed
348
349--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700350static int VmbusOnDeviceRemove(
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200351 struct hv_device *dev
Hank Janssen3e7ee492009-07-13 16:02:34 -0700352 )
353{
354 int ret=0;
355
356 DPRINT_ENTER(VMBUS);
357
358 VmbusChannelReleaseUnattachedChannels();
359
360 VmbusDisconnect();
361
362 HvSynicCleanup();
363
364 DPRINT_EXIT(VMBUS);
365
366 return ret;
367}
368
369
370/*++
371
372Name:
373 VmbusOnCleanup()
374
375Description:
376 Perform any cleanup when the driver is removed
377
378--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700379static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700380VmbusOnCleanup(
Nicolas Palix775ef252009-07-29 14:09:45 +0200381 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700382 )
383{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400384 /* VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700385
386 DPRINT_ENTER(VMBUS);
387
388 HvCleanup();
389
390 DPRINT_EXIT(VMBUS);
391}
392
393
394/*++
395
396Name:
397 VmbusOnMsgDPC()
398
399Description:
400 DPC routine to handle messages from the hypervisior
401
402--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700403static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700404VmbusOnMsgDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200405 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700406 )
407{
408 void *page_addr = gHvContext.synICMessagePage[0];
409
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700410 struct hv_message *msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
411 struct hv_message *copied;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700412 while (1)
413 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400414 if (msg->Header.MessageType == HvMessageTypeNone) /* no msg */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415 {
416 break;
417 }
418 else
419 {
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700420 copied = kmalloc(sizeof(*copied), GFP_ATOMIC);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700421 if (copied == NULL)
422 {
423 continue;
424 }
425
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700426 memcpy(copied, msg, sizeof(*copied));
Bill Pembertonde65a382009-07-29 17:00:09 -0400427 osd_schedule_callback(gVmbusConnection.WorkQueue,
428 VmbusOnChannelMessage,
429 (void *)copied);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700430 }
431
432 msg->Header.MessageType = HvMessageTypeNone;
433
Bill Pemberton454f18a2009-07-27 16:47:24 -0400434 /*
435 * Make sure the write to MessageType (ie set to
436 * HvMessageTypeNone) happens before we read the
437 * MessagePending and EOMing. Otherwise, the EOMing
438 * will not deliver any more messages since there is
439 * no empty slot
440 */
Greg Kroah-Hartman28b6ca92009-07-16 12:34:20 -0700441 mb();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700442
443 if (msg->Header.MessageFlags.MessagePending)
444 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400445 /*
446 * This will cause message queue rescan to
447 * possibly deliver another msg from the
448 * hypervisor
449 */
Greg Kroah-Hartmana51ed7d2009-08-17 17:20:02 -0700450 wrmsrl(HV_X64_MSR_EOM, 0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700451 }
452 }
453}
454
455/*++
456
457Name:
458 VmbusOnEventDPC()
459
460Description:
461 DPC routine to handle events from the hypervisior
462
463--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700464static void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700465VmbusOnEventDPC(
Nicolas Palix775ef252009-07-29 14:09:45 +0200466 struct hv_driver* drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700467 )
468{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400469 /* TODO: Process any events */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700470 VmbusOnEvents();
471}
472
473
474/*++
475
476Name:
477 VmbusOnISR()
478
479Description:
480 ISR routine
481
482--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700483static int
Hank Janssen3e7ee492009-07-13 16:02:34 -0700484VmbusOnISR(
Nicolas Palix775ef252009-07-29 14:09:45 +0200485 struct hv_driver *drv
Hank Janssen3e7ee492009-07-13 16:02:34 -0700486 )
487{
Bill Pemberton454f18a2009-07-27 16:47:24 -0400488 /* VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700489
490 int ret=0;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400491 /* struct page* page; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700492 void *page_addr;
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700493 struct hv_message *msg;
494 union hv_synic_event_flags *event;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700495
Bill Pemberton454f18a2009-07-27 16:47:24 -0400496 /* page = SynICMessagePage[0]; */
497 /* page_addr = page_address(page); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700498 page_addr = gHvContext.synICMessagePage[0];
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700499 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700500
501 DPRINT_ENTER(VMBUS);
502
Bill Pemberton454f18a2009-07-27 16:47:24 -0400503 /* Check if there are actual msgs to be process */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700504 if (msg->Header.MessageType != HvMessageTypeNone)
505 {
506 DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
507 ret |= 0x1;
508 }
509
Bill Pemberton454f18a2009-07-27 16:47:24 -0400510 /* TODO: Check if there are events to be process */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700511 page_addr = gHvContext.synICEventPage[0];
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -0700512 event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700513
Bill Pemberton454f18a2009-07-27 16:47:24 -0400514 /* Since we are a child, we only need to check bit 0 */
Bill Pemberton7c369f42009-07-29 17:00:11 -0400515 if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0]))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700516 {
517 DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
518 ret |= 0x2;
519 }
520
521 DPRINT_EXIT(VMBUS);
522 return ret;
523}
524
Bill Pemberton454f18a2009-07-27 16:47:24 -0400525/* eof */