blob: 01aa669006ae0c1bde7f13eb2cf6d20dbc2a6352 [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-Hartmana0086dc2009-08-17 17:22:08 -070025#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/vmalloc.h>
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070028#include "include/logging.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070029#include "VmbusPrivate.h"
30
Bill Pemberton454f18a2009-07-27 16:47:24 -040031/* Globals */
Hank Janssen3e7ee492009-07-13 16:02:34 -070032
33
Bill Pemberton662e66b2009-07-27 16:47:42 -040034struct VMBUS_CONNECTION gVmbusConnection = {
Hank Janssen3e7ee492009-07-13 16:02:34 -070035 .ConnectState = Disconnected,
Bill Pembertonf4888412009-07-29 17:00:12 -040036 .NextGpadlHandle = ATOMIC_INIT(0xE1E10),
Hank Janssen3e7ee492009-07-13 16:02:34 -070037};
38
39
40/*++
41
42Name:
43 VmbusConnect()
44
45Description:
46 Sends a connect request on the partition service connection
47
48--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -070049int VmbusConnect(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -070050{
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;
Bill Pembertonde65a382009-07-29 17:00:09 -040064 gVmbusConnection.WorkQueue = create_workqueue("hv_vmbus_con");
65 if (!gVmbusConnection.WorkQueue)
66 {
67 ret = -1;
68 goto Cleanup;
69 }
Hank Janssen3e7ee492009-07-13 16:02:34 -070070
71 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -070072 spin_lock_init(&gVmbusConnection.channelmsg_lock);
Hank Janssen3e7ee492009-07-13 16:02:34 -070073
74 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -070075 spin_lock_init(&gVmbusConnection.channel_lock);
Hank Janssen3e7ee492009-07-13 16:02:34 -070076
Bill Pemberton454f18a2009-07-27 16:47:24 -040077 /*
78 * Setup the vmbus event connection for channel interrupt
79 * abstraction stuff
80 */
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -070081 gVmbusConnection.InterruptPage = osd_PageAlloc(1);
Hank Janssen3e7ee492009-07-13 16:02:34 -070082 if (gVmbusConnection.InterruptPage == NULL)
83 {
84 ret = -1;
85 goto Cleanup;
86 }
87
88 gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -070089 gVmbusConnection.SendInterruptPage = (void*)((unsigned long)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
Hank Janssen3e7ee492009-07-13 16:02:34 -070090
Bill Pemberton454f18a2009-07-27 16:47:24 -040091 /* Setup the monitor
92 * notification facility. The 1st page for parent->child and
93 * the 2nd page for child->parent
94 */
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -070095 gVmbusConnection.MonitorPages = osd_PageAlloc(2);
Hank Janssen3e7ee492009-07-13 16:02:34 -070096 if (gVmbusConnection.MonitorPages == NULL)
97 {
98 ret = -1;
99 goto Cleanup;
100 }
101
Greg Kroah-Hartmane276a3a2009-07-15 12:47:43 -0700102 msgInfo = kzalloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700103 if (msgInfo == NULL)
104 {
105 ret = -1;
106 goto Cleanup;
107 }
108
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700109 msgInfo->WaitEvent = osd_WaitEventCreate();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700110 msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
111
112 msg->Header.MessageType = ChannelMessageInitiateContact;
113 msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
Greg Kroah-Hartmanfa56d362009-07-29 15:39:27 -0700114 msg->InterruptPage = virt_to_phys(gVmbusConnection.InterruptPage);
115 msg->MonitorPage1 = virt_to_phys(gVmbusConnection.MonitorPages);
116 msg->MonitorPage2 = virt_to_phys((void *)((unsigned long)gVmbusConnection.MonitorPages + PAGE_SIZE));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700117
Bill Pemberton454f18a2009-07-27 16:47:24 -0400118 /*
119 * Add to list before we send the request since we may
120 * receive the response before returning from this routine
121 */
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700122 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700123 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700124 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700125
126 DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
127 msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
128
129 DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
130
131 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
132 if (ret != 0)
133 {
134 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
135 goto Cleanup;
136 }
137
Bill Pemberton454f18a2009-07-27 16:47:24 -0400138 /* Wait for the connection response */
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700139 osd_WaitEventWait(msgInfo->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700140
141 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
142
Bill Pemberton454f18a2009-07-27 16:47:24 -0400143 /* Check if successful */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700144 if (msgInfo->Response.VersionResponse.VersionSupported)
145 {
146 DPRINT_INFO(VMBUS, "Vmbus connected!!");
147 gVmbusConnection.ConnectState = Connected;
148
149 }
150 else
151 {
152 DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
153 ret = -1;
154
155 goto Cleanup;
156 }
157
158
Bill Pemberton420beac2009-07-29 17:00:10 -0400159 kfree(msgInfo->WaitEvent);
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700160 kfree(msgInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700161 DPRINT_EXIT(VMBUS);
162
163 return 0;
164
165Cleanup:
166
167 gVmbusConnection.ConnectState = Disconnected;
168
Bill Pembertonde65a382009-07-29 17:00:09 -0400169 if (gVmbusConnection.WorkQueue)
170 destroy_workqueue(gVmbusConnection.WorkQueue);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700171
172 if (gVmbusConnection.InterruptPage)
173 {
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700174 osd_PageFree(gVmbusConnection.InterruptPage, 1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700175 gVmbusConnection.InterruptPage = NULL;
176 }
177
178 if (gVmbusConnection.MonitorPages)
179 {
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700180 osd_PageFree(gVmbusConnection.MonitorPages, 2);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700181 gVmbusConnection.MonitorPages = NULL;
182 }
183
184 if (msgInfo)
185 {
186 if (msgInfo->WaitEvent)
Bill Pemberton420beac2009-07-29 17:00:10 -0400187 kfree(msgInfo->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700188
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700189 kfree(msgInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700190 }
191
192 DPRINT_EXIT(VMBUS);
193
194 return ret;
195}
196
197
198/*++
199
200Name:
201 VmbusDisconnect()
202
203Description:
204 Sends a disconnect request on the partition service connection
205
206--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700207int VmbusDisconnect(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700208{
209 int ret=0;
210 VMBUS_CHANNEL_UNLOAD *msg;
211
212 DPRINT_ENTER(VMBUS);
213
Bill Pemberton454f18a2009-07-27 16:47:24 -0400214 /* Make sure we are connected */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700215 if (gVmbusConnection.ConnectState != Connected)
216 return -1;
217
Greg Kroah-Hartmane276a3a2009-07-15 12:47:43 -0700218 msg = kzalloc(sizeof(VMBUS_CHANNEL_UNLOAD), GFP_KERNEL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700219
220 msg->MessageType = ChannelMessageUnload;
221
222 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
223
224 if (ret != 0)
225 {
226 goto Cleanup;
227 }
228
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700229 osd_PageFree(gVmbusConnection.InterruptPage, 1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700230
Bill Pemberton454f18a2009-07-27 16:47:24 -0400231 /* TODO: iterate thru the msg list and free up */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700232
Bill Pembertonde65a382009-07-29 17:00:09 -0400233 destroy_workqueue(gVmbusConnection.WorkQueue);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700234
235 gVmbusConnection.ConnectState = Disconnected;
236
237 DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
238
239Cleanup:
240 if (msg)
241 {
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700242 kfree(msg);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700243 }
244
245 DPRINT_EXIT(VMBUS);
246
247 return ret;
248}
249
250
251/*++
252
253Name:
254 GetChannelFromRelId()
255
256Description:
257 Get the channel object given its child relative id (ie channel id)
258
259--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700260VMBUS_CHANNEL *GetChannelFromRelId(u32 relId)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700261{
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-Hartman8282c4002009-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-Hartmanf346fdc2009-08-17 17:23:00 -0700332void VmbusOnEvents(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700333{
334 int dword;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400335 /* int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700336 int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
337 int bit;
338 int relid;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700339 u32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400340 /* VMBUS_CHANNEL_MESSAGE* receiveMsg; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700341
342 DPRINT_ENTER(VMBUS);
343
Bill Pemberton454f18a2009-07-27 16:47:24 -0400344 /* Check events */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700345 if (recvInterruptPage)
346 {
347 for (dword = 0; dword < maxdword; dword++)
348 {
349 if (recvInterruptPage[dword])
350 {
351 for (bit = 0; bit < 32; bit++)
352 {
Bill Pemberton7c369f42009-07-29 17:00:11 -0400353 if (test_and_clear_bit(bit, (unsigned long *) &recvInterruptPage[dword]))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700354 {
355 relid = (dword << 5) + bit;
356
357 DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
358
Bill Pemberton454f18a2009-07-27 16:47:24 -0400359 if (relid == 0) /* special case - vmbus channel protocol msg */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700360 {
361 DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
362
363 continue; }
364 else
365 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400366 /* QueueWorkItem(VmbusProcessEvent, (void*)relid); */
367 /* ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); */
Greg Kroah-Hartmanc4b0bc92009-07-14 15:12:46 -0700368 VmbusProcessChannelEvent((void*)(unsigned long)relid);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700369 }
370 }
371 }
372 }
373 }
374 }
375 DPRINT_EXIT(VMBUS);
376
377 return;
378}
379
380/*++
381
382Name:
383 VmbusPostMessage()
384
385Description:
386 Send a msg on the vmbus's message connection
387
388--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700389int VmbusPostMessage(void *buffer, size_t bufferLen)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700390{
391 int ret=0;
392 HV_CONNECTION_ID connId;
393
394
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700395 connId.Asu32 =0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700396 connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
397 ret = HvPostMessage(
398 connId,
399 1,
400 buffer,
401 bufferLen);
402
403 return ret;
404}
405
406/*++
407
408Name:
409 VmbusSetEvent()
410
411Description:
412 Send an event notification to the parent
413
414--*/
Greg Kroah-Hartmanf346fdc2009-08-17 17:23:00 -0700415int VmbusSetEvent(u32 childRelId)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700416{
417 int ret=0;
418
419 DPRINT_ENTER(VMBUS);
420
Bill Pemberton454f18a2009-07-27 16:47:24 -0400421 /* Each u32 represents 32 channels */
Bill Pemberton7c369f42009-07-29 17:00:11 -0400422 set_bit(childRelId & 31,
423 (unsigned long *) gVmbusConnection.SendInterruptPage + (childRelId >> 5));
424
Hank Janssen3e7ee492009-07-13 16:02:34 -0700425 ret = HvSignalEvent();
426
427 DPRINT_EXIT(VMBUS);
428
429 return ret;
430}
431
Bill Pemberton454f18a2009-07-27 16:47:24 -0400432/* EOF */