1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/kernel.h>
23#include <linux/mm.h>
24#include "osd.h"
25#include "logging.h"
26#include "VersionInfo.h"
27#include "VmbusPrivate.h"
28
29static const char *gDriverName = "vmbus";
30
31
32
33
34
35
36static const struct hv_guid gVmbusDeviceType = {
37 .data = {
38 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
39 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
40 }
41};
42
43
44static const struct hv_guid gVmbusDeviceId = {
45 .data = {
46 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
47 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
48 }
49};
50
51static struct hv_driver *gDriver;
52static struct hv_device *gDevice;
53
54
55
56
57static void VmbusGetChannelOffers(void)
58{
59 DPRINT_ENTER(VMBUS);
60 VmbusChannelRequestOffers();
61 DPRINT_EXIT(VMBUS);
62}
63
64
65
66
67static void VmbusGetChannelInterface(struct vmbus_channel_interface *Interface)
68{
69 GetChannelInterface(Interface);
70}
71
72
73
74
75static void VmbusGetChannelInfo(struct hv_device *DeviceObject,
76 struct hv_device_info *DeviceInfo)
77{
78 GetChannelInfo(DeviceObject, DeviceInfo);
79}
80
81
82
83
84struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
85 struct hv_guid *DeviceInstance,
86 void *Context)
87{
88 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
89
90 return vmbusDriver->OnChildDeviceCreate(DeviceType, DeviceInstance,
91 Context);
92}
93
94
95
96
97int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
98{
99 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
100
101 return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
102}
103
104
105
106
107void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
108{
109 struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
110
111 vmbusDriver->OnChildDeviceRemove(ChildDevice);
112}
113
114
115
116
117static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
118{
119 u32 *irqvector = AdditionalInfo;
120 int ret;
121
122 DPRINT_ENTER(VMBUS);
123
124 gDevice = dev;
125
126 memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
127 memcpy(&gDevice->deviceInstance, &gVmbusDeviceId,
128 sizeof(struct hv_guid));
129
130
131
132 ret = HvSynicInit(*irqvector);
133
134
135 ret = VmbusConnect();
136
137
138 DPRINT_EXIT(VMBUS);
139
140 return ret;
141}
142
143
144
145
146static int VmbusOnDeviceRemove(struct hv_device *dev)
147{
148 int ret = 0;
149
150 DPRINT_ENTER(VMBUS);
151 VmbusChannelReleaseUnattachedChannels();
152 VmbusDisconnect();
153 HvSynicCleanup();
154 DPRINT_EXIT(VMBUS);
155
156 return ret;
157}
158
159
160
161
162static void VmbusOnCleanup(struct hv_driver *drv)
163{
164
165
166 DPRINT_ENTER(VMBUS);
167 HvCleanup();
168 DPRINT_EXIT(VMBUS);
169}
170
171
172
173
174static void VmbusOnMsgDPC(struct hv_driver *drv)
175{
176 void *page_addr = gHvContext.synICMessagePage[0];
177 struct hv_message *msg = (struct hv_message *)page_addr +
178 VMBUS_MESSAGE_SINT;
179 struct hv_message *copied;
180
181 while (1) {
182 if (msg->Header.MessageType == HvMessageTypeNone) {
183
184 break;
185 } else {
186 copied = kmalloc(sizeof(*copied), GFP_ATOMIC);
187 if (copied == NULL)
188 continue;
189
190 memcpy(copied, msg, sizeof(*copied));
191 osd_schedule_callback(gVmbusConnection.WorkQueue,
192 VmbusOnChannelMessage,
193 (void *)copied);
194 }
195
196 msg->Header.MessageType = HvMessageTypeNone;
197
198
199
200
201
202
203
204
205 mb();
206
207 if (msg->Header.MessageFlags.MessagePending) {
208
209
210
211
212
213 wrmsrl(HV_X64_MSR_EOM, 0);
214 }
215 }
216}
217
218
219
220
221static void VmbusOnEventDPC(struct hv_driver *drv)
222{
223
224 VmbusOnEvents();
225}
226
227
228
229
230static int VmbusOnISR(struct hv_driver *drv)
231{
232 int ret = 0;
233 void *page_addr;
234 struct hv_message *msg;
235 union hv_synic_event_flags *event;
236
237 page_addr = gHvContext.synICMessagePage[0];
238 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
239
240 DPRINT_ENTER(VMBUS);
241
242
243 if (msg->Header.MessageType != HvMessageTypeNone) {
244 DPRINT_DBG(VMBUS, "received msg type %d size %d",
245 msg->Header.MessageType,
246 msg->Header.PayloadSize);
247 ret |= 0x1;
248 }
249
250
251 page_addr = gHvContext.synICEventPage[0];
252 event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
253
254
255 if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0])) {
256 DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
257 ret |= 0x2;
258 }
259
260 DPRINT_EXIT(VMBUS);
261 return ret;
262}
263
264
265
266
267int VmbusInitialize(struct hv_driver *drv)
268{
269 struct vmbus_driver *driver = (struct vmbus_driver *)drv;
270 int ret;
271
272 DPRINT_ENTER(VMBUS);
273
274 DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++",
275 VersionDate, VersionTime);
276 DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++",
277 VersionDesc);
278 DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
279 VMBUS_REVISION_NUMBER);
280 DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
281 VMBUS_MESSAGE_SINT);
282 DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, "
283 "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
284 sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER),
285 sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
286
287 drv->name = gDriverName;
288 memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
289
290
291 driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
292 driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
293 driver->Base.OnCleanup = VmbusOnCleanup;
294 driver->OnIsr = VmbusOnISR;
295 driver->OnMsgDpc = VmbusOnMsgDPC;
296 driver->OnEventDpc = VmbusOnEventDPC;
297 driver->GetChannelOffers = VmbusGetChannelOffers;
298 driver->GetChannelInterface = VmbusGetChannelInterface;
299 driver->GetChannelInfo = VmbusGetChannelInfo;
300
301
302 ret = HvInit();
303 if (ret != 0)
304 DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
305 ret);
306 gDriver = drv;
307
308 DPRINT_EXIT(VMBUS);
309
310 return ret;
311}
312