blob: 7b480f0de5b05ebce2c49d64a7a9c599f25a50cf [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
24
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070025#include "include/logging.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070026
27#include "VmbusPrivate.h"
28
Bill Pemberton454f18a2009-07-27 16:47:24 -040029/* Globals */
Hank Janssen3e7ee492009-07-13 16:02:34 -070030
31
Bill Pemberton662e66b2009-07-27 16:47:42 -040032struct VMBUS_CONNECTION gVmbusConnection = {
Hank Janssen3e7ee492009-07-13 16:02:34 -070033 .ConnectState = Disconnected,
34 .NextGpadlHandle = 0xE1E10,
35};
36
37
38/*++
39
40Name:
41 VmbusConnect()
42
43Description:
44 Sends a connect request on the partition service connection
45
46--*/
47int
48VmbusConnect(
49 )
50{
51 int ret=0;
52 VMBUS_CHANNEL_MSGINFO *msgInfo=NULL;
53 VMBUS_CHANNEL_INITIATE_CONTACT *msg;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -070054 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -070055
56 DPRINT_ENTER(VMBUS);
57
Bill Pemberton454f18a2009-07-27 16:47:24 -040058 /* Make sure we are not connecting or connected */
Hank Janssen3e7ee492009-07-13 16:02:34 -070059 if (gVmbusConnection.ConnectState != Disconnected)
60 return -1;
61
Bill Pemberton454f18a2009-07-27 16:47:24 -040062 /* Initialize the vmbus connection */
Hank Janssen3e7ee492009-07-13 16:02:34 -070063 gVmbusConnection.ConnectState = Connecting;
64 gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ");
65
66 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -070067 spin_lock_init(&gVmbusConnection.channelmsg_lock);
Hank Janssen3e7ee492009-07-13 16:02:34 -070068
69 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -070070 spin_lock_init(&gVmbusConnection.channel_lock);
Hank Janssen3e7ee492009-07-13 16:02:34 -070071
Bill Pemberton454f18a2009-07-27 16:47:24 -040072 /*
73 * Setup the vmbus event connection for channel interrupt
74 * abstraction stuff
75 */
Hank Janssen3e7ee492009-07-13 16:02:34 -070076 gVmbusConnection.InterruptPage = PageAlloc(1);
77 if (gVmbusConnection.InterruptPage == NULL)
78 {
79 ret = -1;
80 goto Cleanup;
81 }
82
83 gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -070084 gVmbusConnection.SendInterruptPage = (void*)((unsigned long)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
Hank Janssen3e7ee492009-07-13 16:02:34 -070085
Bill Pemberton454f18a2009-07-27 16:47:24 -040086 /* Setup the monitor
87 * notification facility. The 1st page for parent->child and
88 * the 2nd page for child->parent
89 */
Hank Janssen3e7ee492009-07-13 16:02:34 -070090 gVmbusConnection.MonitorPages = PageAlloc(2);
91 if (gVmbusConnection.MonitorPages == NULL)
92 {
93 ret = -1;
94 goto Cleanup;
95 }
96
Greg Kroah-Hartmane276a3a2009-07-15 12:47:43 -070097 msgInfo = kzalloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -070098 if (msgInfo == NULL)
99 {
100 ret = -1;
101 goto Cleanup;
102 }
103
104 msgInfo->WaitEvent = WaitEventCreate();
105 msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
106
107 msg->Header.MessageType = ChannelMessageInitiateContact;
108 msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
109 msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage);
110 msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages);
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700111 msg->MonitorPage2 = GetPhysicalAddress((void *)((unsigned long)gVmbusConnection.MonitorPages + PAGE_SIZE));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700112
Bill Pemberton454f18a2009-07-27 16:47:24 -0400113 /*
114 * Add to list before we send the request since we may
115 * receive the response before returning from this routine
116 */
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700117 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700118 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700119 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700120
121 DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
122 msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
123
124 DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
125
126 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
127 if (ret != 0)
128 {
129 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
130 goto Cleanup;
131 }
132
Bill Pemberton454f18a2009-07-27 16:47:24 -0400133 /* Wait for the connection response */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700134 WaitEventWait(msgInfo->WaitEvent);
135
136 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
137
Bill Pemberton454f18a2009-07-27 16:47:24 -0400138 /* Check if successful */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700139 if (msgInfo->Response.VersionResponse.VersionSupported)
140 {
141 DPRINT_INFO(VMBUS, "Vmbus connected!!");
142 gVmbusConnection.ConnectState = Connected;
143
144 }
145 else
146 {
147 DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
148 ret = -1;
149
150 goto Cleanup;
151 }
152
153
154 WaitEventClose(msgInfo->WaitEvent);
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700155 kfree(msgInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700156 DPRINT_EXIT(VMBUS);
157
158 return 0;
159
160Cleanup:
161
162 gVmbusConnection.ConnectState = Disconnected;
163
164 WorkQueueClose(gVmbusConnection.WorkQueue);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700165
166 if (gVmbusConnection.InterruptPage)
167 {
168 PageFree(gVmbusConnection.InterruptPage, 1);
169 gVmbusConnection.InterruptPage = NULL;
170 }
171
172 if (gVmbusConnection.MonitorPages)
173 {
174 PageFree(gVmbusConnection.MonitorPages, 2);
175 gVmbusConnection.MonitorPages = NULL;
176 }
177
178 if (msgInfo)
179 {
180 if (msgInfo->WaitEvent)
181 WaitEventClose(msgInfo->WaitEvent);
182
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700183 kfree(msgInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700184 }
185
186 DPRINT_EXIT(VMBUS);
187
188 return ret;
189}
190
191
192/*++
193
194Name:
195 VmbusDisconnect()
196
197Description:
198 Sends a disconnect request on the partition service connection
199
200--*/
201int
202VmbusDisconnect(
Greg Kroah-Hartmane20f6832009-07-14 15:07:21 -0700203 void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700204 )
205{
206 int ret=0;
207 VMBUS_CHANNEL_UNLOAD *msg;
208
209 DPRINT_ENTER(VMBUS);
210
Bill Pemberton454f18a2009-07-27 16:47:24 -0400211 /* Make sure we are connected */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700212 if (gVmbusConnection.ConnectState != Connected)
213 return -1;
214
Greg Kroah-Hartmane276a3a2009-07-15 12:47:43 -0700215 msg = kzalloc(sizeof(VMBUS_CHANNEL_UNLOAD), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700216
217 msg->MessageType = ChannelMessageUnload;
218
219 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
220
221 if (ret != 0)
222 {
223 goto Cleanup;
224 }
225
226 PageFree(gVmbusConnection.InterruptPage, 1);
227
Bill Pemberton454f18a2009-07-27 16:47:24 -0400228 /* TODO: iterate thru the msg list and free up */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700229
Hank Janssen3e7ee492009-07-13 16:02:34 -0700230 WorkQueueClose(gVmbusConnection.WorkQueue);
231
232 gVmbusConnection.ConnectState = Disconnected;
233
234 DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
235
236Cleanup:
237 if (msg)
238 {
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700239 kfree(msg);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700240 }
241
242 DPRINT_EXIT(VMBUS);
243
244 return ret;
245}
246
247
248/*++
249
250Name:
251 GetChannelFromRelId()
252
253Description:
254 Get the channel object given its child relative id (ie channel id)
255
256--*/
257VMBUS_CHANNEL*
258GetChannelFromRelId(
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700259 u32 relId
Hank Janssen3e7ee492009-07-13 16:02:34 -0700260 )
261{
262 VMBUS_CHANNEL* channel;
263 VMBUS_CHANNEL* foundChannel=NULL;
264 LIST_ENTRY* anchor;
265 LIST_ENTRY* curr;
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700266 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700267
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700268 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700269 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
270 {
271 channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
272
273 if (channel->OfferMsg.ChildRelId == relId)
274 {
275 foundChannel = channel;
276 break;
277 }
278 }
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700279 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700280
281 return foundChannel;
282}
283
284
285
286/*++
287
288Name:
289 VmbusProcessChannelEvent()
290
291Description:
292 Process a channel event notification
293
294--*/
295static void
296VmbusProcessChannelEvent(
Greg Kroah-Hartman8282c402009-07-14 15:06:28 -0700297 void * context
Hank Janssen3e7ee492009-07-13 16:02:34 -0700298 )
299{
300 VMBUS_CHANNEL* channel;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700301 u32 relId = (u32)(unsigned long)context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700302
303 ASSERT(relId > 0);
304
Bill Pemberton454f18a2009-07-27 16:47:24 -0400305 /*
306 * Find the channel based on this relid and invokes the
307 * channel callback to process the event
308 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700309 channel = GetChannelFromRelId(relId);
310
311 if (channel)
312 {
313 VmbusChannelOnChannelEvent(channel);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400314 /* WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700315 }
316 else
317 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400318 DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700319 }
320}
321
322
323/*++
324
325Name:
326 VmbusOnEvents()
327
328Description:
329 Handler for events
330
331--*/
Greg Kroah-Hartmane20f6832009-07-14 15:07:21 -0700332void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700333VmbusOnEvents(
Greg Kroah-Hartmane20f6832009-07-14 15:07:21 -0700334 void
Hank Janssen3e7ee492009-07-13 16:02:34 -0700335 )
336{
337 int dword;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400338 /* int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700339 int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
340 int bit;
341 int relid;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700342 u32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400343 /* VMBUS_CHANNEL_MESSAGE* receiveMsg; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700344
345 DPRINT_ENTER(VMBUS);
346
Bill Pemberton454f18a2009-07-27 16:47:24 -0400347 /* Check events */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700348 if (recvInterruptPage)
349 {
350 for (dword = 0; dword < maxdword; dword++)
351 {
352 if (recvInterruptPage[dword])
353 {
354 for (bit = 0; bit < 32; bit++)
355 {
356 if (BitTestAndClear(&recvInterruptPage[dword], bit))
357 {
358 relid = (dword << 5) + bit;
359
360 DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
361
Bill Pemberton454f18a2009-07-27 16:47:24 -0400362 if (relid == 0) /* special case - vmbus channel protocol msg */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700363 {
364 DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
365
366 continue; }
367 else
368 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400369 /* QueueWorkItem(VmbusProcessEvent, (void*)relid); */
370 /* ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); */
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700371 VmbusProcessChannelEvent((void*)(unsigned long)relid);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700372 }
373 }
374 }
375 }
376 }
377 }
378 DPRINT_EXIT(VMBUS);
379
380 return;
381}
382
383/*++
384
385Name:
386 VmbusPostMessage()
387
388Description:
389 Send a msg on the vmbus's message connection
390
391--*/
392int
393VmbusPostMessage(
Greg Kroah-Hartman8282c402009-07-14 15:06:28 -0700394 void * buffer,
Greg Kroah-Hartman45635d92009-07-14 15:14:20 -0700395 size_t bufferLen
Hank Janssen3e7ee492009-07-13 16:02:34 -0700396 )
397{
398 int ret=0;
399 HV_CONNECTION_ID connId;
400
401
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700402 connId.Asu32 =0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700403 connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
404 ret = HvPostMessage(
405 connId,
406 1,
407 buffer,
408 bufferLen);
409
410 return ret;
411}
412
413/*++
414
415Name:
416 VmbusSetEvent()
417
418Description:
419 Send an event notification to the parent
420
421--*/
422int
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700423VmbusSetEvent(u32 childRelId)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700424{
425 int ret=0;
426
427 DPRINT_ENTER(VMBUS);
428
Bill Pemberton454f18a2009-07-27 16:47:24 -0400429 /* Each u32 represents 32 channels */
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700430 BitSet((u32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700431 ret = HvSignalEvent();
432
433 DPRINT_EXIT(VMBUS);
434
435 return ret;
436}
437
Bill Pemberton454f18a2009-07-27 16:47:24 -0400438/* EOF */