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