Staging: hv: clean up typedefs in ChannelMgmt.h
[linux-2.6/mini2440.git] / drivers / staging / hv / Connection.c
blob6b726894b31bebd44901e84dba72ebcf2f48e9a1
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 <linux/kernel.h>
26 #include <linux/mm.h>
27 #include <linux/vmalloc.h>
28 #include "include/logging.h"
29 #include "VmbusPrivate.h"
31 /* Globals */
34 struct VMBUS_CONNECTION gVmbusConnection = {
35 .ConnectState = Disconnected,
36 .NextGpadlHandle = ATOMIC_INIT(0xE1E10),
40 /*++
42 Name:
43 VmbusConnect()
45 Description:
46 Sends a connect request on the partition service connection
48 --*/
49 int VmbusConnect(void)
51 int ret=0;
52 struct vmbus_channel_msginfo *msgInfo = NULL;
53 VMBUS_CHANNEL_INITIATE_CONTACT *msg;
54 unsigned long flags;
56 DPRINT_ENTER(VMBUS);
58 /* Make sure we are not connecting or connected */
59 if (gVmbusConnection.ConnectState != Disconnected)
60 return -1;
62 /* Initialize the vmbus connection */
63 gVmbusConnection.ConnectState = Connecting;
64 gVmbusConnection.WorkQueue = create_workqueue("hv_vmbus_con");
65 if (!gVmbusConnection.WorkQueue)
67 ret = -1;
68 goto Cleanup;
71 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
72 spin_lock_init(&gVmbusConnection.channelmsg_lock);
74 INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
75 spin_lock_init(&gVmbusConnection.channel_lock);
78 * Setup the vmbus event connection for channel interrupt
79 * abstraction stuff
81 gVmbusConnection.InterruptPage = osd_PageAlloc(1);
82 if (gVmbusConnection.InterruptPage == NULL)
84 ret = -1;
85 goto Cleanup;
88 gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
89 gVmbusConnection.SendInterruptPage = (void*)((unsigned long)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
91 /* Setup the monitor
92 * notification facility. The 1st page for parent->child and
93 * the 2nd page for child->parent
95 gVmbusConnection.MonitorPages = osd_PageAlloc(2);
96 if (gVmbusConnection.MonitorPages == NULL)
98 ret = -1;
99 goto Cleanup;
102 msgInfo = kzalloc(sizeof(*msgInfo) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT), GFP_KERNEL);
103 if (msgInfo == NULL)
105 ret = -1;
106 goto Cleanup;
109 msgInfo->WaitEvent = osd_WaitEventCreate();
110 msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
112 msg->Header.MessageType = ChannelMessageInitiateContact;
113 msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
114 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));
119 * Add to list before we send the request since we may
120 * receive the response before returning from this routine
122 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
123 INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
124 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
126 DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
127 msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
129 DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
131 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
132 if (ret != 0)
134 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
135 goto Cleanup;
138 /* Wait for the connection response */
139 osd_WaitEventWait(msgInfo->WaitEvent);
141 REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
143 /* Check if successful */
144 if (msgInfo->Response.VersionResponse.VersionSupported)
146 DPRINT_INFO(VMBUS, "Vmbus connected!!");
147 gVmbusConnection.ConnectState = Connected;
150 else
152 DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
153 ret = -1;
155 goto Cleanup;
159 kfree(msgInfo->WaitEvent);
160 kfree(msgInfo);
161 DPRINT_EXIT(VMBUS);
163 return 0;
165 Cleanup:
167 gVmbusConnection.ConnectState = Disconnected;
169 if (gVmbusConnection.WorkQueue)
170 destroy_workqueue(gVmbusConnection.WorkQueue);
172 if (gVmbusConnection.InterruptPage)
174 osd_PageFree(gVmbusConnection.InterruptPage, 1);
175 gVmbusConnection.InterruptPage = NULL;
178 if (gVmbusConnection.MonitorPages)
180 osd_PageFree(gVmbusConnection.MonitorPages, 2);
181 gVmbusConnection.MonitorPages = NULL;
184 if (msgInfo)
186 if (msgInfo->WaitEvent)
187 kfree(msgInfo->WaitEvent);
189 kfree(msgInfo);
192 DPRINT_EXIT(VMBUS);
194 return ret;
198 /*++
200 Name:
201 VmbusDisconnect()
203 Description:
204 Sends a disconnect request on the partition service connection
206 --*/
207 int VmbusDisconnect(void)
209 int ret=0;
210 VMBUS_CHANNEL_UNLOAD *msg;
212 DPRINT_ENTER(VMBUS);
214 /* Make sure we are connected */
215 if (gVmbusConnection.ConnectState != Connected)
216 return -1;
218 msg = kzalloc(sizeof(VMBUS_CHANNEL_UNLOAD), GFP_KERNEL);
220 msg->MessageType = ChannelMessageUnload;
222 ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
224 if (ret != 0)
226 goto Cleanup;
229 osd_PageFree(gVmbusConnection.InterruptPage, 1);
231 /* TODO: iterate thru the msg list and free up */
233 destroy_workqueue(gVmbusConnection.WorkQueue);
235 gVmbusConnection.ConnectState = Disconnected;
237 DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
239 Cleanup:
240 if (msg)
242 kfree(msg);
245 DPRINT_EXIT(VMBUS);
247 return ret;
251 /*++
253 Name:
254 GetChannelFromRelId()
256 Description:
257 Get the channel object given its child relative id (ie channel id)
259 --*/
260 struct vmbus_channel *GetChannelFromRelId(u32 relId)
262 struct vmbus_channel *channel;
263 struct vmbus_channel *foundChannel = NULL;
264 LIST_ENTRY* anchor;
265 LIST_ENTRY* curr;
266 unsigned long flags;
268 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
269 ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
271 channel = CONTAINING_RECORD(curr, struct vmbus_channel, ListEntry);
273 if (channel->OfferMsg.ChildRelId == relId)
275 foundChannel = channel;
276 break;
279 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
281 return foundChannel;
286 /*++
288 Name:
289 VmbusProcessChannelEvent()
291 Description:
292 Process a channel event notification
294 --*/
295 static void
296 VmbusProcessChannelEvent(
297 void * context
300 struct vmbus_channel *channel;
301 u32 relId = (u32)(unsigned long)context;
303 ASSERT(relId > 0);
306 * Find the channel based on this relid and invokes the
307 * channel callback to process the event
309 channel = GetChannelFromRelId(relId);
311 if (channel)
313 VmbusChannelOnChannelEvent(channel);
314 /* WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel); */
316 else
318 DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
323 /*++
325 Name:
326 VmbusOnEvents()
328 Description:
329 Handler for events
331 --*/
332 void VmbusOnEvents(void)
334 int dword;
335 /* int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes */
336 int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
337 int bit;
338 int relid;
339 u32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
340 /* VMBUS_CHANNEL_MESSAGE* receiveMsg; */
342 DPRINT_ENTER(VMBUS);
344 /* Check events */
345 if (recvInterruptPage)
347 for (dword = 0; dword < maxdword; dword++)
349 if (recvInterruptPage[dword])
351 for (bit = 0; bit < 32; bit++)
353 if (test_and_clear_bit(bit, (unsigned long *) &recvInterruptPage[dword]))
355 relid = (dword << 5) + bit;
357 DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
359 if (relid == 0) /* special case - vmbus channel protocol msg */
361 DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
363 continue; }
364 else
366 /* QueueWorkItem(VmbusProcessEvent, (void*)relid); */
367 /* ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); */
368 VmbusProcessChannelEvent((void*)(unsigned long)relid);
375 DPRINT_EXIT(VMBUS);
377 return;
380 /*++
382 Name:
383 VmbusPostMessage()
385 Description:
386 Send a msg on the vmbus's message connection
388 --*/
389 int VmbusPostMessage(void *buffer, size_t bufferLen)
391 int ret=0;
392 HV_CONNECTION_ID connId;
395 connId.Asu32 =0;
396 connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
397 ret = HvPostMessage(
398 connId,
400 buffer,
401 bufferLen);
403 return ret;
406 /*++
408 Name:
409 VmbusSetEvent()
411 Description:
412 Send an event notification to the parent
414 --*/
415 int VmbusSetEvent(u32 childRelId)
417 int ret=0;
419 DPRINT_ENTER(VMBUS);
421 /* Each u32 represents 32 channels */
422 set_bit(childRelId & 31,
423 (unsigned long *) gVmbusConnection.SendInterruptPage + (childRelId >> 5));
425 ret = HvSignalEvent();
427 DPRINT_EXIT(VMBUS);
429 return ret;
432 /* EOF */