Staging: hv: Transform PDEVICE_OBJECT and DEVICE_OBJECT typedefs into their correspon...
[deliverable/linux.git] / drivers / staging / hv / Vmbus.c
CommitLineData
3e7ee490
HJ
1/*
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
5654e932 24#include <linux/kernel.h>
0ffa63b0 25#include <linux/mm.h>
09d50ff8 26#include "include/logging.h"
3e7ee490
HJ
27#include "VersionInfo.h"
28#include "VmbusPrivate.h"
29
454f18a9
BP
30
31/* Globals */
32
3e7ee490
HJ
33static const char* gDriverName="vmbus";
34
454f18a9
BP
35/* Windows vmbus does not defined this.
36 * We defined this to be consistent with other devices
37 */
38/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
3e7ee490
HJ
39static const GUID gVmbusDeviceType={
40 .Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85}
41};
42
454f18a9 43/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
3e7ee490
HJ
44static const GUID gVmbusDeviceId={
45 .Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5}
46};
47
454f18a9 48static DRIVER_OBJECT* gDriver; /* vmbus driver object */
3d3b5518 49static struct hv_device* gDevice; /* vmbus root device */
454f18a9
BP
50
51
3e7ee490 52
454f18a9 53/* Internal routines */
3e7ee490 54
3e7ee490
HJ
55
56static void
57VmbusGetChannelInterface(
58 VMBUS_CHANNEL_INTERFACE *Interface
59 );
60
61static void
62VmbusGetChannelInfo(
3d3b5518 63 struct hv_device *DeviceObject,
3e7ee490
HJ
64 DEVICE_INFO *DeviceInfo
65 );
66
67static void
68VmbusGetChannelOffers(
69 void
70 );
71
72static int
73VmbusOnDeviceAdd(
3d3b5518 74 struct hv_device *Device,
3e7ee490
HJ
75 void *AdditionalInfo
76 );
77
78static int
79VmbusOnDeviceRemove(
3d3b5518 80 struct hv_device *dev
3e7ee490
HJ
81 );
82
83static void
84VmbusOnCleanup(
85 DRIVER_OBJECT* drv
86 );
87
88static int
89VmbusOnISR(
90 DRIVER_OBJECT* drv
91 );
92
93static void
94VmbusOnMsgDPC(
95 DRIVER_OBJECT* drv
96 );
97
98static void
99VmbusOnEventDPC(
100 DRIVER_OBJECT* drv
101 );
102
103/*++;
104
105Name:
106 VmbusInitialize()
107
108Description:
109 Main entry point
110
111--*/
112int
113VmbusInitialize(
114 DRIVER_OBJECT* drv
115 )
116{
117 VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
118 int ret=0;
119
120 DPRINT_ENTER(VMBUS);
121
122 DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
123 DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
124
125 DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
126 DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
127
226408a4 128 DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%ld, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%ld",
3fcc523a 129 sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
3e7ee490
HJ
130
131 drv->name = gDriverName;
132 memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID));
133
454f18a9 134 /* Setup dispatch table */
3e7ee490
HJ
135 driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
136 driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
137 driver->Base.OnCleanup = VmbusOnCleanup;
138 driver->OnIsr = VmbusOnISR;
139 driver->OnMsgDpc = VmbusOnMsgDPC;
140 driver->OnEventDpc = VmbusOnEventDPC;
141 driver->GetChannelOffers = VmbusGetChannelOffers;
142 driver->GetChannelInterface = VmbusGetChannelInterface;
143 driver->GetChannelInfo = VmbusGetChannelInfo;
144
454f18a9 145 /* Hypervisor initialization...setup hypercall page..etc */
3e7ee490
HJ
146 ret = HvInit();
147 if (ret != 0)
148 {
149 DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
150 }
151
152 gDriver = drv;
153
154 DPRINT_EXIT(VMBUS);
155
156 return ret;
157}
158
159
160/*++;
161
162Name:
163 VmbusGetChannelOffers()
164
165Description:
166 Retrieve the channel offers from the parent partition
167
168--*/
169
170static void
171VmbusGetChannelOffers(void)
172{
173 DPRINT_ENTER(VMBUS);
174 VmbusChannelRequestOffers();
175 DPRINT_EXIT(VMBUS);
176}
177
178
179/*++;
180
181Name:
182 VmbusGetChannelInterface()
183
184Description:
185 Get the channel interface
186
187--*/
188static void
189VmbusGetChannelInterface(
190 VMBUS_CHANNEL_INTERFACE *Interface
191 )
192{
193 GetChannelInterface(Interface);
194}
195
196
197/*++;
198
199Name:
200 VmbusGetChannelInterface()
201
202Description:
203 Get the device info for the specified device object
204
205--*/
206static void
207VmbusGetChannelInfo(
3d3b5518 208 struct hv_device *DeviceObject,
3e7ee490
HJ
209 DEVICE_INFO *DeviceInfo
210 )
211{
212 GetChannelInfo(DeviceObject, DeviceInfo);
213}
214
215
216
217/*++
218
219Name:
220 VmbusCreateChildDevice()
221
222Description:
223 Creates the child device on the bus that represents the channel offer
224
225--*/
226
3d3b5518 227struct hv_device*
3e7ee490
HJ
228VmbusChildDeviceCreate(
229 GUID DeviceType,
230 GUID DeviceInstance,
231 void *Context)
232{
233 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
234
235 return vmbusDriver->OnChildDeviceCreate(
236 DeviceType,
237 DeviceInstance,
238 Context);
239}
240
241
242/*++
243
244Name:
245 VmbusChildDeviceAdd()
246
247Description:
248 Registers the child device with the vmbus
249
250--*/
251int
252VmbusChildDeviceAdd(
3d3b5518 253 struct hv_device *ChildDevice)
3e7ee490
HJ
254{
255 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
256
257 return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
258}
259
260
261/*++
262
263Name:
264 VmbusChildDeviceRemove()
265
266Description:
267 Unregisters the child device from the vmbus
268
269--*/
270void
271VmbusChildDeviceRemove(
3d3b5518 272 struct hv_device *ChildDevice)
3e7ee490
HJ
273{
274 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
275
276 vmbusDriver->OnChildDeviceRemove(ChildDevice);
277}
278
279/*++
280
281Name:
282 VmbusChildDeviceDestroy()
283
284Description:
285 Release the child device from the vmbus
286
287--*/
454f18a9
BP
288
289/* **************
290void
291VmbusChildDeviceDestroy(
3d3b5518 292struct hv_device *ChildDevice
454f18a9
BP
293)
294{
295VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
296
297vmbusDriver->OnChildDeviceDestroy(ChildDevice);
298}
299************* */
3e7ee490
HJ
300
301/*++
302
303Name:
304 VmbusOnDeviceAdd()
305
306Description:
307 Callback when the root bus device is added
308
309--*/
310static int
311VmbusOnDeviceAdd(
3d3b5518 312 struct hv_device *dev,
3e7ee490
HJ
313 void *AdditionalInfo
314 )
315{
4d643114 316 u32 *irqvector = (u32*) AdditionalInfo;
3e7ee490
HJ
317 int ret=0;
318
319 DPRINT_ENTER(VMBUS);
320
321 gDevice = dev;
322
323 memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID));
324 memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID));
325
454f18a9
BP
326 /* strcpy(dev->name, "vmbus"); */
327 /* SynIC setup... */
3e7ee490
HJ
328 ret = HvSynicInit(*irqvector);
329
454f18a9 330 /* Connect to VMBus in the root partition */
3e7ee490
HJ
331 ret = VmbusConnect();
332
454f18a9 333 /* VmbusSendEvent(device->localPortId+1); */
3e7ee490
HJ
334 DPRINT_EXIT(VMBUS);
335
336 return ret;
337}
338
339
340/*++
341
342Name:
343 VmbusOnDeviceRemove()
344
345Description:
346 Callback when the root bus device is removed
347
348--*/
349int VmbusOnDeviceRemove(
3d3b5518 350 struct hv_device *dev
3e7ee490
HJ
351 )
352{
353 int ret=0;
354
355 DPRINT_ENTER(VMBUS);
356
357 VmbusChannelReleaseUnattachedChannels();
358
359 VmbusDisconnect();
360
361 HvSynicCleanup();
362
363 DPRINT_EXIT(VMBUS);
364
365 return ret;
366}
367
368
369/*++
370
371Name:
372 VmbusOnCleanup()
373
374Description:
375 Perform any cleanup when the driver is removed
376
377--*/
378void
379VmbusOnCleanup(
380 DRIVER_OBJECT* drv
381 )
382{
454f18a9 383 /* VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; */
3e7ee490
HJ
384
385 DPRINT_ENTER(VMBUS);
386
387 HvCleanup();
388
389 DPRINT_EXIT(VMBUS);
390}
391
392
393/*++
394
395Name:
396 VmbusOnMsgDPC()
397
398Description:
399 DPC routine to handle messages from the hypervisior
400
401--*/
402void
403VmbusOnMsgDPC(
404 DRIVER_OBJECT* drv
405 )
406{
407 void *page_addr = gHvContext.synICMessagePage[0];
408
409 HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
410 HV_MESSAGE *copied;
411 while (1)
412 {
454f18a9 413 if (msg->Header.MessageType == HvMessageTypeNone) /* no msg */
3e7ee490
HJ
414 {
415 break;
416 }
417 else
418 {
0a72f3cf 419 copied = kmalloc(sizeof(HV_MESSAGE), GFP_ATOMIC);
3e7ee490
HJ
420 if (copied == NULL)
421 {
422 continue;
423 }
424
425 memcpy(copied, msg, sizeof(HV_MESSAGE));
426 WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied);
427 }
428
429 msg->Header.MessageType = HvMessageTypeNone;
430
454f18a9
BP
431 /*
432 * Make sure the write to MessageType (ie set to
433 * HvMessageTypeNone) happens before we read the
434 * MessagePending and EOMing. Otherwise, the EOMing
435 * will not deliver any more messages since there is
436 * no empty slot
437 */
28b6ca9c 438 mb();
3e7ee490
HJ
439
440 if (msg->Header.MessageFlags.MessagePending)
441 {
454f18a9
BP
442 /*
443 * This will cause message queue rescan to
444 * possibly deliver another msg from the
445 * hypervisor
446 */
3e7ee490
HJ
447 WriteMsr(HV_X64_MSR_EOM, 0);
448 }
449 }
450}
451
452/*++
453
454Name:
455 VmbusOnEventDPC()
456
457Description:
458 DPC routine to handle events from the hypervisior
459
460--*/
461void
462VmbusOnEventDPC(
463 DRIVER_OBJECT* drv
464 )
465{
454f18a9 466 /* TODO: Process any events */
3e7ee490
HJ
467 VmbusOnEvents();
468}
469
470
471/*++
472
473Name:
474 VmbusOnISR()
475
476Description:
477 ISR routine
478
479--*/
480int
481VmbusOnISR(
482 DRIVER_OBJECT* drv
483 )
484{
454f18a9 485 /* VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; */
3e7ee490
HJ
486
487 int ret=0;
454f18a9 488 /* struct page* page; */
3e7ee490
HJ
489 void *page_addr;
490 HV_MESSAGE* msg;
491 HV_SYNIC_EVENT_FLAGS* event;
492
454f18a9
BP
493 /* page = SynICMessagePage[0]; */
494 /* page_addr = page_address(page); */
3e7ee490
HJ
495 page_addr = gHvContext.synICMessagePage[0];
496 msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
497
498 DPRINT_ENTER(VMBUS);
499
454f18a9 500 /* Check if there are actual msgs to be process */
3e7ee490
HJ
501 if (msg->Header.MessageType != HvMessageTypeNone)
502 {
503 DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
504 ret |= 0x1;
505 }
506
454f18a9 507 /* TODO: Check if there are events to be process */
3e7ee490
HJ
508 page_addr = gHvContext.synICEventPage[0];
509 event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT;
510
454f18a9 511 /* Since we are a child, we only need to check bit 0 */
3e7ee490
HJ
512 if (BitTestAndClear(&event->Flags32[0], 0))
513 {
514 DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
515 ret |= 0x2;
516 }
517
518 DPRINT_EXIT(VMBUS);
519 return ret;
520}
521
454f18a9 522/* eof */
This page took 0.056879 seconds and 5 git commands to generate.