blob: 27004ade91a6424c54a6f1237574a7253b99321a [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
Hank Janssen3e7ee492009-07-13 16:02:34 -07002 * Copyright (c) 2009, Microsoft Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Authors:
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
Hank Janssen3e7ee492009-07-13 16:02:34 -070020 */
Greg Kroah-Hartman5654e932009-07-14 15:08:20 -070021#include <linux/kernel.h>
Greg Kroah-Hartmana0086dc2009-08-17 17:22:08 -070022#include <linux/mm.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Hank Janssenc88c4e42010-05-04 15:55:05 -070024#include <linux/module.h>
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070025#include "osd.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070026#include "logging.h"
Greg Kroah-Hartman72daf322010-05-05 22:45:25 -070027#include "vmbus_private.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070028
Bill Pemberton454f18a2009-07-27 16:47:24 -040029/* Internal routines */
Haiyang Zhangfff41b22010-10-07 11:40:08 -070030static int create_gpadl_header(
Haiyang Zhang39d70a42010-09-30 10:52:13 -070031 void *kbuffer, /* must be phys and virt contiguous */
32 u32 size, /* page-size multiple */
33 struct vmbus_channel_msginfo **msginfo,
34 u32 *messagecount);
Haiyang Zhangfff41b22010-10-07 11:40:08 -070035static void dump_vmbus_channel(struct vmbus_channel *channel);
36static void vmbus_setevent(struct vmbus_channel *channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -070037
38
39#if 0
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070040static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
Hank Janssen3e7ee492009-07-13 16:02:34 -070041{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070042 int i = 0;
43 int j = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -070044
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070045 DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
46 MonitorPage, MonitorPage->TriggerState);
Hank Janssen3e7ee492009-07-13 16:02:34 -070047
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070048 for (i = 0; i < 4; i++)
49 DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
50 MonitorPage->TriggerGroup[i].AsUINT64);
Hank Janssen3e7ee492009-07-13 16:02:34 -070051
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070052 for (i = 0; i < 4; i++) {
53 for (j = 0; j < 32; j++) {
54 DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
55 MonitorPage->Latency[i][j]);
Hank Janssen3e7ee492009-07-13 16:02:34 -070056 }
57 }
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070058 for (i = 0; i < 4; i++) {
59 for (j = 0; j < 32; j++) {
60 DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
61 MonitorPage->Parameter[i][j].ConnectionId.Asu32);
62 DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
63 MonitorPage->Parameter[i][j].FlagNumber);
Hank Janssen3e7ee492009-07-13 16:02:34 -070064 }
65 }
66}
67#endif
68
Hank Janssen3e189512010-03-04 22:11:00 +000069/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -070070 * vmbus_setevent- Trigger an event notification on the specified
Hank Janssen3e189512010-03-04 22:11:00 +000071 * channel.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070072 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -070073static void vmbus_setevent(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -070074{
Haiyang Zhang39d70a42010-09-30 10:52:13 -070075 struct hv_monitor_page *monitorpage;
Hank Janssen3e7ee492009-07-13 16:02:34 -070076
Haiyang Zhang39d70a42010-09-30 10:52:13 -070077 if (channel->OfferMsg.MonitorAllocated) {
Bill Pemberton454f18a2009-07-27 16:47:24 -040078 /* Each u32 represents 32 channels */
Haiyang Zhang39d70a42010-09-30 10:52:13 -070079 set_bit(channel->OfferMsg.ChildRelId & 31,
Bill Pemberton7c369f42009-07-29 17:00:11 -040080 (unsigned long *) gVmbusConnection.SendInterruptPage +
Haiyang Zhang39d70a42010-09-30 10:52:13 -070081 (channel->OfferMsg.ChildRelId >> 5));
Hank Janssen3e7ee492009-07-13 16:02:34 -070082
Haiyang Zhang39d70a42010-09-30 10:52:13 -070083 monitorpage = gVmbusConnection.MonitorPages;
84 monitorpage++; /* Get the child to parent monitor page */
Hank Janssen3e7ee492009-07-13 16:02:34 -070085
Haiyang Zhang39d70a42010-09-30 10:52:13 -070086 set_bit(channel->MonitorBit,
87 (unsigned long *)&monitorpage->TriggerGroup
88 [channel->MonitorGroup].Pending);
Bill Pemberton7c369f42009-07-29 17:00:11 -040089
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -070090 } else {
Haiyang Zhang39d70a42010-09-30 10:52:13 -070091 VmbusSetEvent(channel->OfferMsg.ChildRelId);
Hank Janssen3e7ee492009-07-13 16:02:34 -070092 }
Hank Janssen3e7ee492009-07-13 16:02:34 -070093}
94
95#if 0
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -070096static void VmbusChannelClearEvent(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -070097{
Greg Kroah-Hartmaneacb1b42009-08-20 12:11:26 -070098 struct hv_monitor_page *monitorPage;
Hank Janssen3e7ee492009-07-13 16:02:34 -070099
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700100 if (Channel->OfferMsg.MonitorAllocated) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400101 /* Each u32 represents 32 channels */
Bill Pemberton7c369f42009-07-29 17:00:11 -0400102 clear_bit(Channel->OfferMsg.ChildRelId & 31,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700103 (unsigned long *)gVmbusConnection.SendInterruptPage +
104 (Channel->OfferMsg.ChildRelId >> 5));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700105
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700106 monitorPage =
107 (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400108 monitorPage++; /* Get the child to parent monitor page */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700109
Bill Pemberton7c369f42009-07-29 17:00:11 -0400110 clear_bit(Channel->MonitorBit,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700111 (unsigned long *)&monitorPage->TriggerGroup
112 [Channel->MonitorGroup].Pending);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700113 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700114}
115
116#endif
Hank Janssen3e189512010-03-04 22:11:00 +0000117/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700118 * vmbus_get_debug_info -Retrieve various channel debug info
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700119 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700120void vmbus_get_debug_info(struct vmbus_channel *channel,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700121 struct vmbus_channel_debug_info *debuginfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700122{
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700123 struct hv_monitor_page *monitorpage;
124 u8 monitor_group = (u8)channel->OfferMsg.MonitorId / 32;
125 u8 monitor_offset = (u8)channel->OfferMsg.MonitorId % 32;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400126 /* u32 monitorBit = 1 << monitorOffset; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700127
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700128 debuginfo->RelId = channel->OfferMsg.ChildRelId;
129 debuginfo->State = channel->State;
130 memcpy(&debuginfo->InterfaceType,
131 &channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
132 memcpy(&debuginfo->InterfaceInstance,
133 &channel->OfferMsg.Offer.InterfaceInstance,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700134 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700135
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700136 monitorpage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700137
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700138 debuginfo->MonitorId = channel->OfferMsg.MonitorId;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700139
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700140 debuginfo->ServerMonitorPending =
141 monitorpage->TriggerGroup[monitor_group].Pending;
142 debuginfo->ServerMonitorLatency =
143 monitorpage->Latency[monitor_group][monitor_offset];
144 debuginfo->ServerMonitorConnectionId =
145 monitorpage->Parameter[monitor_group]
146 [monitor_offset].ConnectionId.u.Id;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700147
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700148 monitorpage++;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700149
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700150 debuginfo->ClientMonitorPending =
151 monitorpage->TriggerGroup[monitor_group].Pending;
152 debuginfo->ClientMonitorLatency =
153 monitorpage->Latency[monitor_group][monitor_offset];
154 debuginfo->ClientMonitorConnectionId =
155 monitorpage->Parameter[monitor_group]
156 [monitor_offset].ConnectionId.u.Id;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700157
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700158 RingBufferGetDebugInfo(&channel->Inbound, &debuginfo->Inbound);
159 RingBufferGetDebugInfo(&channel->Outbound, &debuginfo->Outbound);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700160}
161
Hank Janssen3e189512010-03-04 22:11:00 +0000162/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700163 * vmbus_open - Open the specified channel.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700164 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700165int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700166 u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
167 void (*onchannelcallback)(void *context), void *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700168{
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700169 struct vmbus_channel_open_channel *openMsg;
Bill Pembertonb94ef342010-05-05 15:27:37 -0400170 struct vmbus_channel_msginfo *openInfo = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700171 void *in, *out;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700172 unsigned long flags;
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400173 int ret, err = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700174
Bill Pemberton454f18a2009-07-27 16:47:24 -0400175 /* Aligned to page size */
Bill Pemberton0ace2472010-05-05 15:27:40 -0400176 /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
177 /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700178
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700179 newchannel->OnChannelCallback = onchannelcallback;
180 newchannel->ChannelCallbackContext = context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700181
Bill Pemberton454f18a2009-07-27 16:47:24 -0400182 /* Allocate the ring buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700183 out = osd_PageAlloc((send_ringbuffer_size + recv_ringbuffer_size)
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700184 >> PAGE_SHIFT);
Bill Pemberton7e052d92010-05-05 15:27:30 -0400185 if (!out)
186 return -ENOMEM;
187
Bill Pemberton0ace2472010-05-05 15:27:40 -0400188 /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700189
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700190 in = (void *)((unsigned long)out + send_ringbuffer_size);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700191
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700192 newchannel->RingBufferPages = out;
193 newchannel->RingBufferPageCount = (send_ringbuffer_size +
194 recv_ringbuffer_size) >> PAGE_SHIFT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700195
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700196 ret = RingBufferInit(&newchannel->Outbound, out, send_ringbuffer_size);
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000197 if (ret != 0) {
Bill Pemberton3324fb42010-05-05 15:27:49 -0400198 err = ret;
199 goto errorout;
200 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700201
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700202 ret = RingBufferInit(&newchannel->Inbound, in, recv_ringbuffer_size);
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000203 if (ret != 0) {
Bill Pemberton3324fb42010-05-05 15:27:49 -0400204 err = ret;
205 goto errorout;
206 }
207
Hank Janssen3e7ee492009-07-13 16:02:34 -0700208
Bill Pemberton454f18a2009-07-27 16:47:24 -0400209 /* Establish the gpadl for the ring buffer */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700210 DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700211 newchannel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700212
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700213 newchannel->RingBufferGpadlHandle = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700214
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700215 ret = vmbus_establish_gpadl(newchannel,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700216 newchannel->Outbound.RingBuffer,
217 send_ringbuffer_size +
218 recv_ringbuffer_size,
219 &newchannel->RingBufferGpadlHandle);
Bill Pembertonb94ef342010-05-05 15:27:37 -0400220
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000221 if (ret != 0) {
Bill Pembertonb94ef342010-05-05 15:27:37 -0400222 err = ret;
223 goto errorout;
224 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700225
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700226 DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
227 "size %d recv ring %p size %d, downstreamoffset %d>",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700228 newchannel, newchannel->OfferMsg.ChildRelId,
229 newchannel->RingBufferGpadlHandle,
230 newchannel->Outbound.RingBuffer,
231 newchannel->Outbound.RingSize,
232 newchannel->Inbound.RingBuffer,
233 newchannel->Inbound.RingSize,
234 send_ringbuffer_size);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700235
Bill Pemberton454f18a2009-07-27 16:47:24 -0400236 /* Create and init the channel open message */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700237 openInfo = kmalloc(sizeof(*openInfo) +
238 sizeof(struct vmbus_channel_open_channel),
239 GFP_KERNEL);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400240 if (!openInfo) {
241 err = -ENOMEM;
242 goto errorout;
243 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700244
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700245 openInfo->WaitEvent = osd_WaitEventCreate();
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400246 if (!openInfo->WaitEvent) {
247 err = -ENOMEM;
248 goto errorout;
249 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700250
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700251 openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700252 openMsg->Header.MessageType = ChannelMessageOpenChannel;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700253 openMsg->OpenId = newchannel->OfferMsg.ChildRelId; /* FIXME */
254 openMsg->ChildRelId = newchannel->OfferMsg.ChildRelId;
255 openMsg->RingBufferGpadlHandle = newchannel->RingBufferGpadlHandle;
256 openMsg->DownstreamRingBufferPageOffset = send_ringbuffer_size >>
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700257 PAGE_SHIFT;
258 openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700259
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700260 if (userdatalen > MAX_USER_DEFINED_BYTES) {
Bill Pembertonc827f942010-05-05 15:27:38 -0400261 err = -EINVAL;
262 goto errorout;
263 }
264
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700265 if (userdatalen)
266 memcpy(openMsg->UserData, userdata, userdatalen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700267
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700268 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400269 list_add_tail(&openInfo->MsgListEntry,
270 &gVmbusConnection.ChannelMsgList);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700271 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700272
273 DPRINT_DBG(VMBUS, "Sending channel open msg...");
274
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700275 ret = VmbusPostMessage(openMsg,
276 sizeof(struct vmbus_channel_open_channel));
277 if (ret != 0) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700278 DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
279 goto Cleanup;
280 }
281
Bill Pemberton454f18a2009-07-27 16:47:24 -0400282 /* FIXME: Need to time-out here */
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700283 osd_WaitEventWait(openInfo->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700284
285 if (openInfo->Response.OpenResult.Status == 0)
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700286 DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700287 else
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700288 DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700289 newchannel, openInfo->Response.OpenResult.Status);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700290
291Cleanup:
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700292 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400293 list_del(&openInfo->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700294 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700295
Bill Pemberton420beac2009-07-29 17:00:10 -0400296 kfree(openInfo->WaitEvent);
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700297 kfree(openInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700298 return 0;
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400299
300errorout:
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700301 RingBufferCleanup(&newchannel->Outbound);
302 RingBufferCleanup(&newchannel->Inbound);
303 osd_PageFree(out, (send_ringbuffer_size + recv_ringbuffer_size)
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400304 >> PAGE_SHIFT);
305 kfree(openInfo);
306 return err;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700307}
308
Hank Janssen3e189512010-03-04 22:11:00 +0000309/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700310 * dump_gpadl_body - Dump the gpadl body message to the console for
Hank Janssen3e189512010-03-04 22:11:00 +0000311 * debugging purposes.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700312 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700313static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700314{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700315 int i;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700316 int pfncount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700317
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700318 pfncount = (len - sizeof(struct vmbus_channel_gpadl_body)) /
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700319 sizeof(u64);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700320 DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", len, pfncount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700321
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700322 for (i = 0; i < pfncount; i++)
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700323 DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700324 i, gpadl->Pfn[i]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700325}
326
Hank Janssen3e189512010-03-04 22:11:00 +0000327/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700328 * dump_gpadl_header - Dump the gpadl header message to the console for
Hank Janssen3e189512010-03-04 22:11:00 +0000329 * debugging purposes.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700330 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700331static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700332{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700333 int i, j;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700334 int pagecount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700335
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700336 DPRINT_DBG(VMBUS,
337 "gpadl header - relid %d, range count %d, range buflen %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700338 gpadl->ChildRelId, gpadl->RangeCount, gpadl->RangeBufLen);
339 for (i = 0; i < gpadl->RangeCount; i++) {
340 pagecount = gpadl->Range[i].ByteCount >> PAGE_SHIFT;
341 pagecount = (pagecount > 26) ? 26 : pagecount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700342
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700343 DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700344 "page count %d", i, gpadl->Range[i].ByteCount,
345 gpadl->Range[i].ByteOffset, pagecount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700346
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700347 for (j = 0; j < pagecount; j++)
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700348 DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700349 gpadl->Range[i].PfnArray[j]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700350 }
351}
352
Hank Janssen3e189512010-03-04 22:11:00 +0000353/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700354 * create_gpadl_header - Creates a gpadl for the specified buffer
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700355 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700356static int create_gpadl_header(void *kbuffer, u32 size,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700357 struct vmbus_channel_msginfo **msginfo,
358 u32 *messagecount)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700359{
360 int i;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700361 int pagecount;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700362 unsigned long long pfn;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700363 struct vmbus_channel_gpadl_header *gpadl_header;
364 struct vmbus_channel_gpadl_body *gpadl_body;
365 struct vmbus_channel_msginfo *msgheader;
366 struct vmbus_channel_msginfo *msgbody = NULL;
367 u32 msgsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700368
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700369 int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700370
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700371 /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
Bill Pemberton0ace2472010-05-05 15:27:40 -0400372 /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700373
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700374 pagecount = size >> PAGE_SHIFT;
375 pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700376
Bill Pemberton454f18a2009-07-27 16:47:24 -0400377 /* do we need a gpadl body msg */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700378 pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700379 sizeof(struct vmbus_channel_gpadl_header) -
380 sizeof(struct gpa_range);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700381 pfncount = pfnsize / sizeof(u64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700382
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700383 if (pagecount > pfncount) {
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700384 /* we need a gpadl body */
Bill Pemberton454f18a2009-07-27 16:47:24 -0400385 /* fill in the header */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700386 msgsize = sizeof(struct vmbus_channel_msginfo) +
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700387 sizeof(struct vmbus_channel_gpadl_header) +
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700388 sizeof(struct gpa_range) + pfncount * sizeof(u64);
389 msgheader = kzalloc(msgsize, GFP_KERNEL);
390 if (!msgheader)
Bill Pembertond1c250b2010-05-05 15:27:35 -0400391 goto nomem;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700392
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700393 INIT_LIST_HEAD(&msgheader->SubMsgList);
394 msgheader->MessageSize = msgsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700395
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700396 gpadl_header = (struct vmbus_channel_gpadl_header *)
397 msgheader->Msg;
398 gpadl_header->RangeCount = 1;
399 gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
400 pagecount * sizeof(u64);
401 gpadl_header->Range[0].ByteOffset = 0;
402 gpadl_header->Range[0].ByteCount = size;
403 for (i = 0; i < pfncount; i++)
404 gpadl_header->Range[0].PfnArray[i] = pfn+i;
405 *msginfo = msgheader;
406 *messagecount = 1;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700407
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700408 pfnsum = pfncount;
409 pfnleft = pagecount - pfncount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700410
Bill Pemberton454f18a2009-07-27 16:47:24 -0400411 /* how many pfns can we fit */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700412 pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700413 sizeof(struct vmbus_channel_gpadl_body);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700414 pfncount = pfnsize / sizeof(u64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415
Bill Pemberton454f18a2009-07-27 16:47:24 -0400416 /* fill in the body */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700417 while (pfnleft) {
418 if (pfnleft > pfncount)
419 pfncurr = pfncount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700420 else
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700421 pfncurr = pfnleft;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700422
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700423 msgsize = sizeof(struct vmbus_channel_msginfo) +
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700424 sizeof(struct vmbus_channel_gpadl_body) +
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700425 pfncurr * sizeof(u64);
426 msgbody = kzalloc(msgsize, GFP_KERNEL);
Bill Pembertond1c250b2010-05-05 15:27:35 -0400427 /* FIXME: we probably need to more if this fails */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700428 if (!msgbody)
Bill Pembertond1c250b2010-05-05 15:27:35 -0400429 goto nomem;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700430 msgbody->MessageSize = msgsize;
431 (*messagecount)++;
432 gpadl_body =
433 (struct vmbus_channel_gpadl_body *)msgbody->Msg;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700434
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700435 /*
436 * FIXME:
437 * Gpadl is u32 and we are using a pointer which could
438 * be 64-bit
439 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700440 /* gpadl_body->Gpadl = kbuffer; */
441 for (i = 0; i < pfncurr; i++)
442 gpadl_body->Pfn[i] = pfn + pfnsum + i;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700443
Bill Pemberton454f18a2009-07-27 16:47:24 -0400444 /* add to msg header */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700445 list_add_tail(&msgbody->MsgListEntry,
446 &msgheader->SubMsgList);
447 pfnsum += pfncurr;
448 pfnleft -= pfncurr;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700449 }
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700450 } else {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400451 /* everything fits in a header */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700452 msgsize = sizeof(struct vmbus_channel_msginfo) +
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700453 sizeof(struct vmbus_channel_gpadl_header) +
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700454 sizeof(struct gpa_range) + pagecount * sizeof(u64);
455 msgheader = kzalloc(msgsize, GFP_KERNEL);
456 if (msgheader == NULL)
Kulikov Vasiliye3eb7cd2010-07-16 20:13:51 +0400457 goto nomem;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700458 msgheader->MessageSize = msgsize;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700459
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700460 gpadl_header = (struct vmbus_channel_gpadl_header *)
461 msgheader->Msg;
462 gpadl_header->RangeCount = 1;
463 gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
464 pagecount * sizeof(u64);
465 gpadl_header->Range[0].ByteOffset = 0;
466 gpadl_header->Range[0].ByteCount = size;
467 for (i = 0; i < pagecount; i++)
468 gpadl_header->Range[0].PfnArray[i] = pfn+i;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700469
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700470 *msginfo = msgheader;
471 *messagecount = 1;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700472 }
473
474 return 0;
Bill Pembertond1c250b2010-05-05 15:27:35 -0400475nomem:
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700476 kfree(msgheader);
477 kfree(msgbody);
Bill Pembertond1c250b2010-05-05 15:27:35 -0400478 return -ENOMEM;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700479}
480
Hank Janssen3e189512010-03-04 22:11:00 +0000481/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700482 * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700483 *
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700484 * @channel: a channel
485 * @kbuffer: from kmalloc
486 * @size: page-size multiple
487 * @gpadl_handle: some funky thing
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700488 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700489int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700490 u32 size, u32 *gpadl_handle)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700491{
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700492 struct vmbus_channel_gpadl_header *gpadlmsg;
493 struct vmbus_channel_gpadl_body *gpadl_body;
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700494 /* struct vmbus_channel_gpadl_created *gpadlCreated; */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700495 struct vmbus_channel_msginfo *msginfo = NULL;
496 struct vmbus_channel_msginfo *submsginfo;
497 u32 msgcount;
Bill Pemberton53af5452009-09-11 21:46:44 -0400498 struct list_head *curr;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700499 u32 next_gpadl_handle;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700500 unsigned long flags;
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400501 int ret = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700502
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700503 next_gpadl_handle = atomic_read(&gVmbusConnection.NextGpadlHandle);
Bill Pembertonf4888412009-07-29 17:00:12 -0400504 atomic_inc(&gVmbusConnection.NextGpadlHandle);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700505
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700506 ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400507 if (ret)
508 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700509
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700510 msginfo->WaitEvent = osd_WaitEventCreate();
511 if (!msginfo->WaitEvent) {
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400512 ret = -ENOMEM;
513 goto Cleanup;
514 }
515
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700516 gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->Msg;
517 gpadlmsg->Header.MessageType = ChannelMessageGpadlHeader;
518 gpadlmsg->ChildRelId = channel->OfferMsg.ChildRelId;
519 gpadlmsg->Gpadl = next_gpadl_handle;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700520
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700521 dump_gpadl_header(gpadlmsg);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700522
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700523 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700524 list_add_tail(&msginfo->MsgListEntry,
Bill Pemberton53af5452009-09-11 21:46:44 -0400525 &gVmbusConnection.ChannelMsgList);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700526
Bill Pemberton53af5452009-09-11 21:46:44 -0400527 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700528 DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700529 kbuffer, size, msgcount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700530
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700531 DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700532 msginfo->MessageSize - sizeof(*msginfo));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700533
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700534 ret = VmbusPostMessage(gpadlmsg, msginfo->MessageSize -
535 sizeof(*msginfo));
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700536 if (ret != 0) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700537 DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
538 goto Cleanup;
539 }
540
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700541 if (msgcount > 1) {
542 list_for_each(curr, &msginfo->SubMsgList) {
Bill Pemberton53af5452009-09-11 21:46:44 -0400543
544 /* FIXME: should this use list_entry() instead ? */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700545 submsginfo = (struct vmbus_channel_msginfo *)curr;
546 gpadl_body =
547 (struct vmbus_channel_gpadl_body *)submsginfo->Msg;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700548
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700549 gpadl_body->Header.MessageType =
550 ChannelMessageGpadlBody;
551 gpadl_body->Gpadl = next_gpadl_handle;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700552
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700553 DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700554 submsginfo->MessageSize -
555 sizeof(*submsginfo));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700556
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700557 dump_gpadl_body(gpadl_body, submsginfo->MessageSize -
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700558 sizeof(*submsginfo));
559 ret = VmbusPostMessage(gpadl_body,
560 submsginfo->MessageSize -
561 sizeof(*submsginfo));
Haiyang Zhangfd4dc882010-05-13 15:56:30 +0000562 if (ret != 0)
Bill Pemberton99259152010-05-05 15:27:36 -0400563 goto Cleanup;
564
Hank Janssen3e7ee492009-07-13 16:02:34 -0700565 }
566 }
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700567 osd_WaitEventWait(msginfo->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700568
Bill Pemberton454f18a2009-07-27 16:47:24 -0400569 /* At this point, we received the gpadl created msg */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700570 DPRINT_DBG(VMBUS, "Received GPADL created "
571 "(relid %d, status %d handle %x)",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700572 channel->OfferMsg.ChildRelId,
573 msginfo->Response.GpadlCreated.CreationStatus,
574 gpadlmsg->Gpadl);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700575
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700576 *gpadl_handle = gpadlmsg->Gpadl;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700577
578Cleanup:
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700579 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700580 list_del(&msginfo->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700581 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700582
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700583 kfree(msginfo->WaitEvent);
584 kfree(msginfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700585 return ret;
586}
587
Hank Janssen3e189512010-03-04 22:11:00 +0000588/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700589 * vmbus_teardown_gpadl -Teardown the specified GPADL handle
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700590 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700591int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700592{
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700593 struct vmbus_channel_gpadl_teardown *msg;
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -0700594 struct vmbus_channel_msginfo *info;
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700595 unsigned long flags;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700596 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700597
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700598 /* ASSERT(gpadl_handle != 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700599
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700600 info = kmalloc(sizeof(*info) +
601 sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400602 if (!info)
603 return -ENOMEM;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700604
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700605 info->WaitEvent = osd_WaitEventCreate();
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400606 if (!info->WaitEvent) {
607 kfree(info);
608 return -ENOMEM;
609 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700610
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700611 msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700612
613 msg->Header.MessageType = ChannelMessageGpadlTeardown;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700614 msg->ChildRelId = channel->OfferMsg.ChildRelId;
615 msg->Gpadl = gpadl_handle;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700616
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700617 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400618 list_add_tail(&info->MsgListEntry,
619 &gVmbusConnection.ChannelMsgList);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700620 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700621
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700622 ret = VmbusPostMessage(msg,
623 sizeof(struct vmbus_channel_gpadl_teardown));
624 if (ret != 0) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400625 /* TODO: */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700626 /* something... */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700627 }
628
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700629 osd_WaitEventWait(info->WaitEvent);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700630
Bill Pemberton454f18a2009-07-27 16:47:24 -0400631 /* Received a torndown response */
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700632 spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
Bill Pemberton53af5452009-09-11 21:46:44 -0400633 list_del(&info->MsgListEntry);
Greg Kroah-Hartmandd0813b2009-07-15 14:56:45 -0700634 spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700635
Bill Pemberton420beac2009-07-29 17:00:10 -0400636 kfree(info->WaitEvent);
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700637 kfree(info);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700638 return ret;
639}
Greg Kroah-Hartman18726d72010-10-21 08:39:59 -0700640EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700641
Hank Janssen3e189512010-03-04 22:11:00 +0000642/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700643 * vmbus_close - Close the specified channel
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700644 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700645void vmbus_close(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700646{
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700647 struct vmbus_channel_close_channel *msg;
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -0700648 struct vmbus_channel_msginfo *info;
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700649 unsigned long flags;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700650 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700651
Bill Pemberton454f18a2009-07-27 16:47:24 -0400652 /* Stop callback and cancel the timer asap */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700653 channel->OnChannelCallback = NULL;
654 del_timer_sync(&channel->poll_timer);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700655
Bill Pemberton454f18a2009-07-27 16:47:24 -0400656 /* Send a closing message */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700657 info = kmalloc(sizeof(*info) +
658 sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
Bill Pembertonc3bf2e22010-05-05 15:27:34 -0400659 /* FIXME: can't do anything other than return here because the
660 * function is void */
661 if (!info)
662 return;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700663
Greg Kroah-Hartmanbfc30aa2009-07-29 15:40:18 -0700664 /* info->waitEvent = osd_WaitEventCreate(); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700665
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700666 msg = (struct vmbus_channel_close_channel *)info->Msg;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700667 msg->Header.MessageType = ChannelMessageCloseChannel;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700668 msg->ChildRelId = channel->OfferMsg.ChildRelId;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700669
Greg Kroah-Hartman82250212009-08-26 15:16:04 -0700670 ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700671 if (ret != 0) {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400672 /* TODO: */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700673 /* something... */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700674 }
675
Bill Pemberton454f18a2009-07-27 16:47:24 -0400676 /* Tear down the gpadl for the channel's ring buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700677 if (channel->RingBufferGpadlHandle)
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700678 vmbus_teardown_gpadl(channel,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700679 channel->RingBufferGpadlHandle);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700680
Bill Pemberton454f18a2009-07-27 16:47:24 -0400681 /* TODO: Send a msg to release the childRelId */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700682
Bill Pemberton454f18a2009-07-27 16:47:24 -0400683 /* Cleanup the ring buffers for this channel */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700684 RingBufferCleanup(&channel->Outbound);
685 RingBufferCleanup(&channel->Inbound);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700686
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700687 osd_PageFree(channel->RingBufferPages, channel->RingBufferPageCount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700688
Greg Kroah-Hartman8c69f522009-07-15 12:48:29 -0700689 kfree(info);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700690
Bill Pemberton454f18a2009-07-27 16:47:24 -0400691 /*
692 * If we are closing the channel during an error path in
693 * opening the channel, don't free the channel since the
694 * caller will free the channel
695 */
696
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700697 if (channel->State == CHANNEL_OPEN_STATE) {
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700698 spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700699 list_del(&channel->ListEntry);
Greg Kroah-Hartman0f5e44c2009-07-15 14:57:16 -0700700 spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700701
Haiyang Zhange98cb272010-10-15 10:14:07 -0700702 free_channel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700703 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700704}
705
Hank Janssenc88c4e42010-05-04 15:55:05 -0700706/**
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700707 * vmbus_sendpacket() - Send the specified buffer on the given channel
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700708 * @channel: Pointer to vmbus_channel structure.
709 * @buffer: Pointer to the buffer you want to receive the data into.
710 * @bufferlen: Maximum size of what the the buffer will hold
711 * @requestid: Identifier of the request
712 * @type: Type of packet that is being send e.g. negotiate, time
Hank Janssenc88c4e42010-05-04 15:55:05 -0700713 * packet etc.
714 *
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700715 * Sends data in @buffer directly to hyper-v via the vmbus
Hank Janssenc88c4e42010-05-04 15:55:05 -0700716 * This will send the data unparsed to hyper-v.
717 *
718 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700719 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700720int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700721 u32 bufferlen, u64 requestid,
722 enum vmbus_packet_type type, u32 flags)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700723{
Greg Kroah-Hartman8dc0a062009-08-27 16:02:36 -0700724 struct vmpacket_descriptor desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700725 u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
726 u32 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
727 struct scatterlist bufferlist[3];
728 u64 aligned_data = 0;
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700729 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700730
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700731 DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700732 channel, buffer, bufferlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700733
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700734 dump_vmbus_channel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700735
Bill Pemberton0ace2472010-05-05 15:27:40 -0400736 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700737
Bill Pemberton454f18a2009-07-27 16:47:24 -0400738 /* Setup the descriptor */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700739 desc.Type = type; /* VmbusPacketTypeDataInBand; */
740 desc.Flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700741 /* in 8-bytes granularity */
742 desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700743 desc.Length8 = (u16)(packetlen_aligned >> 3);
744 desc.TransactionId = requestid;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700745
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700746 sg_init_table(bufferlist, 3);
747 sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
748 sg_set_buf(&bufferlist[1], buffer, bufferlen);
749 sg_set_buf(&bufferlist[2], &aligned_data,
750 packetlen_aligned - packetlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700751
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700752 ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700753
Bill Pemberton454f18a2009-07-27 16:47:24 -0400754 /* TODO: We should determine if this is optional */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700755 if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700756 vmbus_setevent(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700757
Hank Janssen3e7ee492009-07-13 16:02:34 -0700758 return ret;
759}
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700760EXPORT_SYMBOL(vmbus_sendpacket);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700761
Hank Janssen3e189512010-03-04 22:11:00 +0000762/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700763 * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer
Hank Janssen3e189512010-03-04 22:11:00 +0000764 * packets using a GPADL Direct packet type.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700765 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700766int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700767 struct hv_page_buffer pagebuffers[],
768 u32 pagecount, void *buffer, u32 bufferlen,
769 u64 requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700770{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700771 int ret;
772 int i;
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000773 struct vmbus_channel_packet_page_buffer desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700774 u32 descsize;
775 u32 packetlen;
776 u32 packetlen_aligned;
777 struct scatterlist bufferlist[3];
778 u64 aligned_data = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700779
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700780 if (pagecount > MAX_PAGE_BUFFER_COUNT)
Bill Pemberton002b53e2010-05-05 15:27:39 -0400781 return -EINVAL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700782
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700783 dump_vmbus_channel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700784
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700785 /*
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000786 * Adjust the size down since vmbus_channel_packet_page_buffer is the
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700787 * largest size we support
788 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700789 descsize = sizeof(struct vmbus_channel_packet_page_buffer) -
790 ((MAX_PAGE_BUFFER_COUNT - pagecount) *
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700791 sizeof(struct hv_page_buffer));
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700792 packetlen = descsize + bufferlen;
793 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700794
Bill Pemberton0ace2472010-05-05 15:27:40 -0400795 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700796
Bill Pemberton454f18a2009-07-27 16:47:24 -0400797 /* Setup the descriptor */
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000798 desc.type = VmbusPacketTypeDataUsingGpaDirect;
799 desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700800 desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
801 desc.length8 = (u16)(packetlen_aligned >> 3);
802 desc.transactionid = requestid;
803 desc.rangecount = pagecount;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700804
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700805 for (i = 0; i < pagecount; i++) {
806 desc.range[i].Length = pagebuffers[i].Length;
807 desc.range[i].Offset = pagebuffers[i].Offset;
808 desc.range[i].Pfn = pagebuffers[i].Pfn;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700809 }
810
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700811 sg_init_table(bufferlist, 3);
812 sg_set_buf(&bufferlist[0], &desc, descsize);
813 sg_set_buf(&bufferlist[1], buffer, bufferlen);
814 sg_set_buf(&bufferlist[2], &aligned_data,
815 packetlen_aligned - packetlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700816
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700817 ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700818
Bill Pemberton454f18a2009-07-27 16:47:24 -0400819 /* TODO: We should determine if this is optional */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700820 if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700821 vmbus_setevent(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700822
Hank Janssen3e7ee492009-07-13 16:02:34 -0700823 return ret;
824}
825
Hank Janssen3e189512010-03-04 22:11:00 +0000826/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700827 * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
Hank Janssen3e189512010-03-04 22:11:00 +0000828 * using a GPADL Direct packet type.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700829 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700830int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700831 struct hv_multipage_buffer *multi_pagebuffer,
832 void *buffer, u32 bufferlen, u64 requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700833{
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700834 int ret;
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000835 struct vmbus_channel_packet_multipage_buffer desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700836 u32 descsize;
837 u32 packetlen;
838 u32 packetlen_aligned;
839 struct scatterlist bufferlist[3];
840 u64 aligned_data = 0;
841 u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->Offset,
842 multi_pagebuffer->Length);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700843
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700844 dump_vmbus_channel(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700845
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700846 DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700847 multi_pagebuffer->Offset,
848 multi_pagebuffer->Length, pfncount);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700849
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700850 if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
Bill Pemberton002b53e2010-05-05 15:27:39 -0400851 return -EINVAL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700852
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700853 /*
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000854 * Adjust the size down since vmbus_channel_packet_multipage_buffer is
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700855 * the largest size we support
856 */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700857 descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) -
858 ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) *
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700859 sizeof(u64));
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700860 packetlen = descsize + bufferlen;
861 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700862
Bill Pemberton0ace2472010-05-05 15:27:40 -0400863 /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700864
Bill Pemberton454f18a2009-07-27 16:47:24 -0400865 /* Setup the descriptor */
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000866 desc.type = VmbusPacketTypeDataUsingGpaDirect;
867 desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700868 desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
869 desc.length8 = (u16)(packetlen_aligned >> 3);
870 desc.transactionid = requestid;
Haiyang Zhang430a8e92010-09-20 21:07:51 +0000871 desc.rangecount = 1;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700872
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700873 desc.range.Length = multi_pagebuffer->Length;
874 desc.range.Offset = multi_pagebuffer->Offset;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700875
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700876 memcpy(desc.range.PfnArray, multi_pagebuffer->PfnArray,
877 pfncount * sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700878
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700879 sg_init_table(bufferlist, 3);
880 sg_set_buf(&bufferlist[0], &desc, descsize);
881 sg_set_buf(&bufferlist[1], buffer, bufferlen);
882 sg_set_buf(&bufferlist[2], &aligned_data,
883 packetlen_aligned - packetlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700884
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700885 ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700886
Bill Pemberton454f18a2009-07-27 16:47:24 -0400887 /* TODO: We should determine if this is optional */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700888 if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700889 vmbus_setevent(channel);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700890
Hank Janssen3e7ee492009-07-13 16:02:34 -0700891 return ret;
892}
893
Hank Janssenc88c4e42010-05-04 15:55:05 -0700894
895/**
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700896 * vmbus_recvpacket() - Retrieve the user packet on the specified channel
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700897 * @channel: Pointer to vmbus_channel structure.
898 * @buffer: Pointer to the buffer you want to receive the data into.
899 * @bufferlen: Maximum size of what the the buffer will hold
900 * @buffer_actual_len: The actual size of the data after it was received
901 * @requestid: Identifier of the request
Hank Janssenc88c4e42010-05-04 15:55:05 -0700902 *
903 * Receives directly from the hyper-v vmbus and puts the data it received
904 * into Buffer. This will receive the data unparsed from hyper-v.
905 *
906 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700907 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700908int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700909 u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700910{
Greg Kroah-Hartman8dc0a062009-08-27 16:02:36 -0700911 struct vmpacket_descriptor desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700912 u32 packetlen;
913 u32 userlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700914 int ret;
Greg Kroah-Hartman54411c42009-07-15 14:48:32 -0700915 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700916
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700917 *buffer_actual_len = 0;
918 *requestid = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700919
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700920 spin_lock_irqsave(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700921
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700922 ret = RingBufferPeek(&channel->Inbound, &desc,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700923 sizeof(struct vmpacket_descriptor));
924 if (ret != 0) {
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700925 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700926
Bill Pemberton454f18a2009-07-27 16:47:24 -0400927 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700928 return 0;
929 }
930
Bill Pemberton454f18a2009-07-27 16:47:24 -0400931 /* VmbusChannelClearEvent(Channel); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700932
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700933 packetlen = desc.Length8 << 3;
934 userlen = packetlen - (desc.DataOffset8 << 3);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400935 /* ASSERT(userLen > 0); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700936
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700937 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
938 "flag %d tid %llx pktlen %d datalen %d> ",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700939 channel, channel->OfferMsg.ChildRelId, desc.Type,
940 desc.Flags, desc.TransactionId, packetlen, userlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700941
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700942 *buffer_actual_len = userlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700943
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700944 if (userlen > bufferlen) {
945 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700946
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700947 DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700948 bufferlen, userlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700949 return -1;
950 }
951
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700952 *requestid = desc.TransactionId;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700953
Bill Pemberton454f18a2009-07-27 16:47:24 -0400954 /* Copy over the packet to the user buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700955 ret = RingBufferRead(&channel->Inbound, buffer, userlen,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700956 (desc.DataOffset8 << 3));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700957
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700958 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700959
Hank Janssen3e7ee492009-07-13 16:02:34 -0700960 return 0;
961}
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700962EXPORT_SYMBOL(vmbus_recvpacket);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700963
Hank Janssen3e189512010-03-04 22:11:00 +0000964/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700965 * vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700966 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -0700967int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700968 u32 bufferlen, u32 *buffer_actual_len,
969 u64 *requestid)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700970{
Greg Kroah-Hartman8dc0a062009-08-27 16:02:36 -0700971 struct vmpacket_descriptor desc;
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700972 u32 packetlen;
973 u32 userlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700974 int ret;
Greg Kroah-Hartman54411c42009-07-15 14:48:32 -0700975 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700976
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700977 *buffer_actual_len = 0;
978 *requestid = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700979
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700980 spin_lock_irqsave(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700981
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700982 ret = RingBufferPeek(&channel->Inbound, &desc,
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700983 sizeof(struct vmpacket_descriptor));
984 if (ret != 0) {
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700985 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700986
Bill Pemberton454f18a2009-07-27 16:47:24 -0400987 /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700988 return 0;
989 }
990
Bill Pemberton454f18a2009-07-27 16:47:24 -0400991 /* VmbusChannelClearEvent(Channel); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700992
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700993 packetlen = desc.Length8 << 3;
994 userlen = packetlen - (desc.DataOffset8 << 3);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700995
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -0700996 DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
997 "flag %d tid %llx pktlen %d datalen %d> ",
Haiyang Zhang39d70a42010-09-30 10:52:13 -0700998 channel, channel->OfferMsg.ChildRelId, desc.Type,
999 desc.Flags, desc.TransactionId, packetlen, userlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001000
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001001 *buffer_actual_len = packetlen;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001002
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001003 if (packetlen > bufferlen) {
1004 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001005
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001006 DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001007 "got space for only %d bytes", packetlen, bufferlen);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001008 return -2;
1009 }
1010
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001011 *requestid = desc.TransactionId;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001012
Bill Pemberton454f18a2009-07-27 16:47:24 -04001013 /* Copy over the entire packet to the user buffer */
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001014 ret = RingBufferRead(&channel->Inbound, buffer, packetlen, 0);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001015
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001016 spin_unlock_irqrestore(&channel->inbound_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001017 return 0;
1018}
1019
Hank Janssen3e189512010-03-04 22:11:00 +00001020/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001021 * vmbus_onchannel_event - Channel event callback
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001022 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001023void vmbus_onchannel_event(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001024{
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001025 dump_vmbus_channel(channel);
Bill Pemberton0ace2472010-05-05 15:27:40 -04001026 /* ASSERT(Channel->OnChannelCallback); */
Haiyang Zhang5996b3d2009-11-20 16:29:17 +00001027
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001028 channel->OnChannelCallback(channel->ChannelCallbackContext);
Haiyang Zhang5996b3d2009-11-20 16:29:17 +00001029
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001030 mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100));
Hank Janssen3e7ee492009-07-13 16:02:34 -07001031}
1032
Hank Janssen3e189512010-03-04 22:11:00 +00001033/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001034 * vmbus_ontimer - Timer event callback
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001035 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001036void vmbus_ontimer(unsigned long data)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001037{
Greg Kroah-Hartmanaded71652009-08-18 15:21:19 -07001038 struct vmbus_channel *channel = (struct vmbus_channel *)data;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001039
Chris Nicholson0fa37b12010-02-20 20:36:23 +00001040 if (channel->OnChannelCallback)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001041 channel->OnChannelCallback(channel->ChannelCallbackContext);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001042}
1043
Hank Janssen3e189512010-03-04 22:11:00 +00001044/*
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001045 * dump_vmbus_channel- Dump vmbus channel info to the console
Greg Kroah-Hartmanf4266e32009-09-01 17:24:57 -07001046 */
Haiyang Zhangfff41b22010-10-07 11:40:08 -07001047static void dump_vmbus_channel(struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001048{
Haiyang Zhang39d70a42010-09-30 10:52:13 -07001049 DPRINT_DBG(VMBUS, "Channel (%d)", channel->OfferMsg.ChildRelId);
1050 DumpRingInfo(&channel->Outbound, "Outbound ");
1051 DumpRingInfo(&channel->Inbound, "Inbound ");
Hank Janssen3e7ee492009-07-13 16:02:34 -07001052}