]> Pileus Git - ~andy/linux/blob - drivers/staging/hv/Vmbus.c
Staging: hv: remove include/HvHalApi.h
[~andy/linux] / drivers / staging / hv / Vmbus.c
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
24 #include <linux/kernel.h>
25 #include <linux/mm.h>
26 #include "osd.h"
27 #include "include/logging.h"
28 #include "VersionInfo.h"
29 #include "VmbusPrivate.h"
30
31
32 /* Globals */
33
34 static const char* gDriverName="vmbus";
35
36 /* Windows vmbus does not defined this.
37  * We defined this to be consistent with other devices
38  */
39 /* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
40 static 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         }
45 };
46
47 /* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
48 static 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         }
53 };
54
55 static struct hv_driver *gDriver; /* vmbus driver object */
56 static struct hv_device* gDevice; /* vmbus root device */
57
58
59
60 /* Internal routines */
61
62
63 static void
64 VmbusGetChannelInterface(
65         VMBUS_CHANNEL_INTERFACE *Interface
66         );
67
68 static void
69 VmbusGetChannelInfo(
70         struct hv_device *DeviceObject,
71         DEVICE_INFO             *DeviceInfo
72         );
73
74 static void
75 VmbusGetChannelOffers(
76         void
77         );
78
79 static int
80 VmbusOnDeviceAdd(
81         struct hv_device *Device,
82         void                    *AdditionalInfo
83         );
84
85 static int
86 VmbusOnDeviceRemove(
87         struct hv_device *dev
88         );
89
90 static void
91 VmbusOnCleanup(
92         struct hv_driver *drv
93         );
94
95 static int
96 VmbusOnISR(
97         struct hv_driver *drv
98         );
99
100 static void
101 VmbusOnMsgDPC(
102         struct hv_driver *drv
103         );
104
105 static void
106 VmbusOnEventDPC(
107         struct hv_driver *drv
108         );
109
110 /*++;
111
112 Name:
113         VmbusInitialize()
114
115 Description:
116         Main entry point
117
118 --*/
119 int
120 VmbusInitialize(
121         struct hv_driver *drv
122         )
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
135         DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
136                 sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
137
138         drv->name = gDriverName;
139         memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
140
141         /* Setup dispatch table */
142         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
152         /* Hypervisor initialization...setup hypercall page..etc */
153         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
169 Name:
170         VmbusGetChannelOffers()
171
172 Description:
173         Retrieve the channel offers from the parent partition
174
175 --*/
176
177 static void
178 VmbusGetChannelOffers(void)
179 {
180         DPRINT_ENTER(VMBUS);
181         VmbusChannelRequestOffers();
182         DPRINT_EXIT(VMBUS);
183 }
184
185
186 /*++;
187
188 Name:
189         VmbusGetChannelInterface()
190
191 Description:
192         Get the channel interface
193
194 --*/
195 static void
196 VmbusGetChannelInterface(
197         VMBUS_CHANNEL_INTERFACE *Interface
198         )
199 {
200         GetChannelInterface(Interface);
201 }
202
203
204 /*++;
205
206 Name:
207         VmbusGetChannelInterface()
208
209 Description:
210         Get the device info for the specified device object
211
212 --*/
213 static void
214 VmbusGetChannelInfo(
215         struct hv_device *DeviceObject,
216         DEVICE_INFO             *DeviceInfo
217         )
218 {
219         GetChannelInfo(DeviceObject, DeviceInfo);
220 }
221
222
223
224 /*++
225
226 Name:
227         VmbusCreateChildDevice()
228
229 Description:
230         Creates the child device on the bus that represents the channel offer
231
232 --*/
233
234 struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
235                                          struct hv_guid *DeviceInstance,
236                                          void *Context)
237 {
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
249 Name:
250         VmbusChildDeviceAdd()
251
252 Description:
253         Registers the child device with the vmbus
254
255 --*/
256 int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
257 {
258         VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
259
260         return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
261 }
262
263
264 /*++
265
266 Name:
267         VmbusChildDeviceRemove()
268
269 Description:
270         Unregisters the child device from the vmbus
271
272 --*/
273 void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
274 {
275         VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
276
277         vmbusDriver->OnChildDeviceRemove(ChildDevice);
278 }
279
280 /*++
281
282 Name:
283         VmbusChildDeviceDestroy()
284
285 Description:
286         Release the child device from the vmbus
287
288 --*/
289
290 /* **************
291 void
292 VmbusChildDeviceDestroy(
293 struct hv_device  *ChildDevice
294 )
295 {
296 VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
297
298 vmbusDriver->OnChildDeviceDestroy(ChildDevice);
299 }
300 ************* */
301
302 /*++
303
304 Name:
305         VmbusOnDeviceAdd()
306
307 Description:
308         Callback when the root bus device is added
309
310 --*/
311 static int
312 VmbusOnDeviceAdd(
313         struct hv_device *dev,
314         void                    *AdditionalInfo
315         )
316 {
317         u32 *irqvector = (u32*) AdditionalInfo;
318         int ret=0;
319
320         DPRINT_ENTER(VMBUS);
321
322         gDevice = dev;
323
324         memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
325         memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(struct hv_guid));
326
327         /* strcpy(dev->name, "vmbus"); */
328         /* SynIC setup... */
329         ret = HvSynicInit(*irqvector);
330
331         /* Connect to VMBus in the root partition */
332         ret = VmbusConnect();
333
334         /* VmbusSendEvent(device->localPortId+1); */
335         DPRINT_EXIT(VMBUS);
336
337         return ret;
338 }
339
340
341 /*++
342
343 Name:
344         VmbusOnDeviceRemove()
345
346 Description:
347         Callback when the root bus device is removed
348
349 --*/
350 static int VmbusOnDeviceRemove(
351         struct hv_device *dev
352         )
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
372 Name:
373         VmbusOnCleanup()
374
375 Description:
376         Perform any cleanup when the driver is removed
377
378 --*/
379 static void
380 VmbusOnCleanup(
381         struct hv_driver *drv
382         )
383 {
384         /* VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; */
385
386         DPRINT_ENTER(VMBUS);
387
388         HvCleanup();
389
390         DPRINT_EXIT(VMBUS);
391 }
392
393
394 /*++
395
396 Name:
397         VmbusOnMsgDPC()
398
399 Description:
400         DPC routine to handle messages from the hypervisior
401
402 --*/
403 static void
404 VmbusOnMsgDPC(
405         struct hv_driver *drv
406         )
407 {
408         void *page_addr = gHvContext.synICMessagePage[0];
409
410         HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
411         HV_MESSAGE *copied;
412         while (1)
413         {
414                 if (msg->Header.MessageType == HvMessageTypeNone) /* no msg */
415                 {
416                         break;
417                 }
418                 else
419                 {
420                         copied = kmalloc(sizeof(HV_MESSAGE), GFP_ATOMIC);
421                         if (copied == NULL)
422                         {
423                                 continue;
424                         }
425
426                         memcpy(copied, msg, sizeof(HV_MESSAGE));
427                         osd_schedule_callback(gVmbusConnection.WorkQueue,
428                                               VmbusOnChannelMessage,
429                                               (void *)copied);
430                 }
431
432                 msg->Header.MessageType = HvMessageTypeNone;
433
434                 /*
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                  */
441                 mb();
442
443                 if (msg->Header.MessageFlags.MessagePending)
444                 {
445                         /*
446                          * This will cause message queue rescan to
447                          * possibly deliver another msg from the
448                          * hypervisor
449                          */
450                         wrmsrl(HV_X64_MSR_EOM, 0);
451                 }
452         }
453 }
454
455 /*++
456
457 Name:
458         VmbusOnEventDPC()
459
460 Description:
461         DPC routine to handle events from the hypervisior
462
463 --*/
464 static void
465 VmbusOnEventDPC(
466         struct hv_driver* drv
467         )
468 {
469         /* TODO: Process any events */
470         VmbusOnEvents();
471 }
472
473
474 /*++
475
476 Name:
477         VmbusOnISR()
478
479 Description:
480         ISR routine
481
482 --*/
483 static int
484 VmbusOnISR(
485         struct hv_driver *drv
486         )
487 {
488         /* VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; */
489
490         int ret=0;
491         /* struct page* page; */
492         void *page_addr;
493         HV_MESSAGE* msg;
494         HV_SYNIC_EVENT_FLAGS* event;
495
496         /* page = SynICMessagePage[0]; */
497         /* page_addr = page_address(page); */
498         page_addr = gHvContext.synICMessagePage[0];
499         msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
500
501         DPRINT_ENTER(VMBUS);
502
503         /* Check if there are actual msgs to be process */
504         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
510         /* TODO: Check if there are events to be process */
511         page_addr = gHvContext.synICEventPage[0];
512         event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT;
513
514         /* Since we are a child, we only need to check bit 0 */
515         if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0]))
516         {
517                 DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
518                 ret |= 0x2;
519         }
520
521         DPRINT_EXIT(VMBUS);
522         return ret;
523 }
524
525 /* eof */