Staging: hv: fix sparse function warnings
[linux-2.6/mini2440.git] / drivers / staging / hv / Connection.c
bloba2888cb467096e74243922a00c9573fa81a67a89
1 /*
3 * Copyright (c) 2009, Microsoft Corporation.
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.
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.
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.
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
25 #include "include/logging.h"
27 #include "VmbusPrivate.h"
29 /* Globals */
32 struct VMBUS_CONNECTION gVmbusConnection = {
33 .ConnectState = Disconnected,
34 .NextGpadlHandle = 0xE1E10,
38 /*++
40 Name:
41 VmbusConnect()
43 Description:
44 Sends a connect request on the partition service connection
46 --*/
47 static int
48 VmbusConnect(void)
50 int ret=0;
51 VMBUS_CHANNEL_MSGINFO *msgInfo=NULL;
52 VMBUS_CHANNEL_INITIATE_CONTACT *msg;
53 unsigned long flags;
55 DPRINT_ENTER(VMBUS);
57 /* Make sure we are not connecting or connected */
58 if (gVmbusConnection.ConnectState != Disconnected)
59 return -1;
61 /* Initialize the vmbus connection */
62 gVmbusConnection.ConnectState = Connecting;
63 gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ");
65 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
66 spin_lock_init(&gVmbusConnection.channelmsg_lock);
68 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
69 spin_lock_init(&gVmbusConnection.channel_lock);
72 * Setup the vmbus event connection for channel interrupt
73 * abstraction stuff
75 gVmbusConnection.InterruptPage = PageAlloc(1);
76 if (gVmbusConnection.InterruptPage == NULL)
78 ret = -1;
79 goto Cleanup;
82 gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
83 gVmbusConnection.SendInterruptPage = (void*)((unsigned long)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
85 /* Setup the monitor
86 * notification facility. The 1st page for parent->child and
87 * the 2nd page for child->parent
89 gVmbusConnection.MonitorPages = PageAlloc(2);
90 if (gVmbusConnection.MonitorPages == NULL)
92 ret = -1;
93 goto Cleanup;
96 msgInfo = kzalloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT), GFP_KERNEL);
97 if (msgInfo == NULL)
99 ret = -1;
100 goto Cleanup;
103 msgInfo->WaitEvent = WaitEventCreate();
104 msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
106 msg->Header.MessageType = ChannelMessageInitiateContact;
107 msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
108 msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage);
109 msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages);
110 msg->MonitorPage2 = GetPhysicalAddress((void *)((unsigned long)gVmbusConnection.MonitorPages + PAGE_SIZE));
113 * Add to list before we send the request since we may
114 * receive the response before returning from this routine
116 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
117 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
118 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
120 DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
121 msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
123 DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
125 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
126 if (ret != 0)
128 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
129 goto Cleanup;
132 /* Wait for the connection response */
133 WaitEventWait(msgInfo->WaitEvent);
135 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
137 /* Check if successful */
138 if (msgInfo->Response.VersionResponse.VersionSupported)
140 DPRINT_INFO(VMBUS, "Vmbus connected!!");
141 gVmbusConnection.ConnectState = Connected;
144 else
146 DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
147 ret = -1;
149 goto Cleanup;
153 WaitEventClose(msgInfo->WaitEvent);
154 kfree(msgInfo);
155 DPRINT_EXIT(VMBUS);
157 return 0;
159 Cleanup:
161 gVmbusConnection.ConnectState = Disconnected;
163 WorkQueueClose(gVmbusConnection.WorkQueue);
165 if (gVmbusConnection.InterruptPage)
167 PageFree(gVmbusConnection.InterruptPage, 1);
168 gVmbusConnection.InterruptPage = NULL;
171 if (gVmbusConnection.MonitorPages)
173 PageFree(gVmbusConnection.MonitorPages, 2);
174 gVmbusConnection.MonitorPages = NULL;
177 if (msgInfo)
179 if (msgInfo->WaitEvent)
180 WaitEventClose(msgInfo->WaitEvent);
182 kfree(msgInfo);
185 DPRINT_EXIT(VMBUS);
187 return ret;
191 /*++
193 Name:
194 VmbusDisconnect()
196 Description:
197 Sends a disconnect request on the partition service connection
199 --*/
200 static int
201 VmbusDisconnect(
202 void
205 int ret=0;
206 VMBUS_CHANNEL_UNLOAD *msg;
208 DPRINT_ENTER(VMBUS);
210 /* Make sure we are connected */
211 if (gVmbusConnection.ConnectState != Connected)
212 return -1;
214 msg = kzalloc(sizeof(VMBUS_CHANNEL_UNLOAD), GFP_KERNEL);
216 msg->MessageType = ChannelMessageUnload;
218 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
220 if (ret != 0)
222 goto Cleanup;
225 PageFree(gVmbusConnection.InterruptPage, 1);
227 /* TODO: iterate thru the msg list and free up */
229 WorkQueueClose(gVmbusConnection.WorkQueue);
231 gVmbusConnection.ConnectState = Disconnected;
233 DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
235 Cleanup:
236 if (msg)
238 kfree(msg);
241 DPRINT_EXIT(VMBUS);
243 return ret;
247 /*++
249 Name:
250 GetChannelFromRelId()
252 Description:
253 Get the channel object given its child relative id (ie channel id)
255 --*/
256 static VMBUS_CHANNEL*
257 GetChannelFromRelId(
258 u32 relId
261 VMBUS_CHANNEL* channel;
262 VMBUS_CHANNEL* foundChannel=NULL;
263 LIST_ENTRY* anchor;
264 LIST_ENTRY* curr;
265 unsigned long flags;
267 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
268 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
270 channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
272 if (channel->OfferMsg.ChildRelId == relId)
274 foundChannel = channel;
275 break;
278 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
280 return foundChannel;
285 /*++
287 Name:
288 VmbusProcessChannelEvent()
290 Description:
291 Process a channel event notification
293 --*/
294 static void
295 VmbusProcessChannelEvent(
296 void * context
299 VMBUS_CHANNEL* channel;
300 u32 relId = (u32)(unsigned long)context;
302 ASSERT(relId > 0);
305 * Find the channel based on this relid and invokes the
306 * channel callback to process the event
308 channel = GetChannelFromRelId(relId);
310 if (channel)
312 VmbusChannelOnChannelEvent(channel);
313 /* WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel); */
315 else
317 DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
322 /*++
324 Name:
325 VmbusOnEvents()
327 Description:
328 Handler for events
330 --*/
331 static void
332 VmbusOnEvents(
333 void
336 int dword;
337 /* int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes */
338 int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
339 int bit;
340 int relid;
341 u32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
342 /* VMBUS_CHANNEL_MESSAGE* receiveMsg; */
344 DPRINT_ENTER(VMBUS);
346 /* Check events */
347 if (recvInterruptPage)
349 for (dword = 0; dword < maxdword; dword++)
351 if (recvInterruptPage[dword])
353 for (bit = 0; bit < 32; bit++)
355 if (BitTestAndClear(&recvInterruptPage[dword], bit))
357 relid = (dword << 5) + bit;
359 DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
361 if (relid == 0) /* special case - vmbus channel protocol msg */
363 DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
365 continue; }
366 else
368 /* QueueWorkItem(VmbusProcessEvent, (void*)relid); */
369 /* ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); */
370 VmbusProcessChannelEvent((void*)(unsigned long)relid);
377 DPRINT_EXIT(VMBUS);
379 return;
382 /*++
384 Name:
385 VmbusPostMessage()
387 Description:
388 Send a msg on the vmbus's message connection
390 --*/
391 static int
392 VmbusPostMessage(
393 void * buffer,
394 size_t bufferLen
397 int ret=0;
398 HV_CONNECTION_ID connId;
401 connId.Asu32 =0;
402 connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
403 ret = HvPostMessage(
404 connId,
406 buffer,
407 bufferLen);
409 return ret;
412 /*++
414 Name:
415 VmbusSetEvent()
417 Description:
418 Send an event notification to the parent
420 --*/
421 static int
422 VmbusSetEvent(u32 childRelId)
424 int ret=0;
426 DPRINT_ENTER(VMBUS);
428 /* Each u32 represents 32 channels */
429 BitSet((u32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31);
430 ret = HvSignalEvent();
432 DPRINT_EXIT(VMBUS);
434 return ret;
437 /* EOF */