Blame view
drivers/hv/channel.c
25.7 KB
3e7ee4902 Staging: hv: add ... |
1 |
/* |
3e7ee4902 Staging: hv: add ... |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
* Copyright (c) 2009, Microsoft Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Authors: * Haiyang Zhang <haiyangz@microsoft.com> * Hank Janssen <hjanssen@microsoft.com> |
3e7ee4902 Staging: hv: add ... |
20 |
*/ |
0a46618d5 staging: hv: Repl... |
21 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
5654e9322 Staging: hv: remo... |
22 |
#include <linux/kernel.h> |
0c3b7b2f7 Staging: hv: Use ... |
23 24 |
#include <linux/sched.h> #include <linux/wait.h> |
a0086dc51 Staging: hv: remo... |
25 |
#include <linux/mm.h> |
5a0e3ad6a include cleanup: ... |
26 |
#include <linux/slab.h> |
c88c4e4c7 Staging: hv: Adde... |
27 |
#include <linux/module.h> |
46a971913 Staging: hv: move... |
28 |
#include <linux/hyperv.h> |
011a7c3cc Drivers: hv: vmbu... |
29 |
#include <linux/uio.h> |
63d55b2ae Drivers: hv: vmbu... |
30 |
#include <linux/interrupt.h> |
3f335ea21 Staging: hv: Incl... |
31 |
|
0f2a6619e Staging: hv: vmbu... |
32 |
#include "hyperv_vmbus.h" |
3e7ee4902 Staging: hv: add ... |
33 |
|
e3fe0bb65 Staging: hv: Remo... |
34 35 |
#define NUM_PAGES_SPANNED(addr, len) \ ((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT)) |
3e1895195 staging: hv: Corr... |
36 |
/* |
fff41b2e3 staging: hv: Rena... |
37 |
* vmbus_setevent- Trigger an event notification on the specified |
3e1895195 staging: hv: Corr... |
38 |
* channel. |
f4266e342 Staging: hv: codi... |
39 |
*/ |
e2fdf7841 Drivers: hv: vmbu... |
40 |
void vmbus_setevent(struct vmbus_channel *channel) |
3e7ee4902 Staging: hv: add ... |
41 |
{ |
39d70a4ab staging: hv: Remo... |
42 |
struct hv_monitor_page *monitorpage; |
3e7ee4902 Staging: hv: add ... |
43 |
|
3724287c0 Drivers: hv: vmbu... |
44 45 46 47 48 49 |
/* * For channels marked as in "low latency" mode * bypass the monitor page mechanism. */ if ((channel->offermsg.monitor_allocated) && (!channel->low_latency)) { |
454f18a96 Staging: hv: Remo... |
50 |
/* Each u32 represents 32 channels */ |
223565857 staging: hv: use ... |
51 |
sync_set_bit(channel->offermsg.child_relid & 31, |
da9fcb726 staging: hv: Conv... |
52 |
(unsigned long *) vmbus_connection.send_int_page + |
c50f7fb28 staging: hv: Conv... |
53 |
(channel->offermsg.child_relid >> 5)); |
3e7ee4902 Staging: hv: add ... |
54 |
|
8681db445 hv: make "monitor... |
55 56 |
/* Get the child to parent monitor page */ monitorpage = vmbus_connection.monitor_pages[1]; |
3e7ee4902 Staging: hv: add ... |
57 |
|
223565857 staging: hv: use ... |
58 |
sync_set_bit(channel->monitor_bit, |
f6feebe07 staging: hv: Conv... |
59 60 |
(unsigned long *)&monitorpage->trigger_group [channel->monitor_grp].pending); |
7c369f405 Staging: hv: remo... |
61 |
|
f4266e342 Staging: hv: codi... |
62 |
} else { |
21c3bef5d Drivers: hv: Chan... |
63 |
vmbus_set_event(channel); |
3e7ee4902 Staging: hv: add ... |
64 |
} |
3e7ee4902 Staging: hv: add ... |
65 |
} |
e2fdf7841 Drivers: hv: vmbu... |
66 |
EXPORT_SYMBOL_GPL(vmbus_setevent); |
3e7ee4902 Staging: hv: add ... |
67 |
|
3e1895195 staging: hv: Corr... |
68 |
/* |
fff41b2e3 staging: hv: Rena... |
69 |
* vmbus_open - Open the specified channel. |
f4266e342 Staging: hv: codi... |
70 |
*/ |
fff41b2e3 staging: hv: Rena... |
71 |
int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, |
39d70a4ab staging: hv: Remo... |
72 73 |
u32 recv_ringbuffer_size, void *userdata, u32 userdatalen, void (*onchannelcallback)(void *context), void *context) |
3e7ee4902 Staging: hv: add ... |
74 |
{ |
0987ff696 Staging: hv: vmbu... |
75 |
struct vmbus_channel_open_channel *open_msg; |
176fb9e3f Staging: hv: vmbu... |
76 |
struct vmbus_channel_msginfo *open_info = NULL; |
dd0813b6f Staging: hv: make... |
77 |
unsigned long flags; |
08a9513f7 hv: channel: matc... |
78 |
int ret, err = 0; |
294409d20 Drivers: hv: vmbu... |
79 |
struct page *page; |
3e7ee4902 Staging: hv: add ... |
80 |
|
98f531b10 Drivers: hv: clea... |
81 82 83 |
if (send_ringbuffer_size % PAGE_SIZE || recv_ringbuffer_size % PAGE_SIZE) return -EINVAL; |
67fae053b Drivers: hv: rena... |
84 |
spin_lock_irqsave(&newchannel->lock, flags); |
e68d2971d Drivers: hv: vmbu... |
85 86 87 |
if (newchannel->state == CHANNEL_OPEN_STATE) { newchannel->state = CHANNEL_OPENING_STATE; } else { |
67fae053b Drivers: hv: rena... |
88 |
spin_unlock_irqrestore(&newchannel->lock, flags); |
e68d2971d Drivers: hv: vmbu... |
89 90 |
return -EINVAL; } |
67fae053b Drivers: hv: rena... |
91 |
spin_unlock_irqrestore(&newchannel->lock, flags); |
e68d2971d Drivers: hv: vmbu... |
92 |
|
c50f7fb28 staging: hv: Conv... |
93 94 |
newchannel->onchannel_callback = onchannelcallback; newchannel->channel_callback_context = context; |
3e7ee4902 Staging: hv: add ... |
95 |
|
454f18a96 Staging: hv: Remo... |
96 |
/* Allocate the ring buffer */ |
294409d20 Drivers: hv: vmbu... |
97 98 99 100 101 102 |
page = alloc_pages_node(cpu_to_node(newchannel->target_cpu), GFP_KERNEL|__GFP_ZERO, get_order(send_ringbuffer_size + recv_ringbuffer_size)); if (!page) |
98f531b10 Drivers: hv: clea... |
103 104 105 |
page = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(send_ringbuffer_size + recv_ringbuffer_size)); |
df3493e0b Staging: hv: Use ... |
106 |
|
98f531b10 Drivers: hv: clea... |
107 |
if (!page) { |
ac0d12b7c hv: vmbus_open():... |
108 |
err = -ENOMEM; |
98f531b10 Drivers: hv: clea... |
109 |
goto error_set_chnstate; |
ac0d12b7c hv: vmbus_open():... |
110 |
} |
3e7ee4902 Staging: hv: add ... |
111 |
|
9988ce685 Drivers: hv: ring... |
112 |
newchannel->ringbuffer_pages = page_address(page); |
c50f7fb28 staging: hv: Conv... |
113 |
newchannel->ringbuffer_pagecount = (send_ringbuffer_size + |
39d70a4ab staging: hv: Remo... |
114 |
recv_ringbuffer_size) >> PAGE_SHIFT; |
3e7ee4902 Staging: hv: add ... |
115 |
|
9988ce685 Drivers: hv: ring... |
116 117 |
ret = hv_ringbuffer_init(&newchannel->outbound, page, send_ringbuffer_size >> PAGE_SHIFT); |
72a95cbcb Staging: hv: Rena... |
118 |
|
fd4dc88e4 staging: hv: Fix ... |
119 |
if (ret != 0) { |
3324fb405 staging: hv: chec... |
120 |
err = ret; |
98f531b10 Drivers: hv: clea... |
121 |
goto error_free_pages; |
3324fb405 staging: hv: chec... |
122 |
} |
9988ce685 Drivers: hv: ring... |
123 124 125 |
ret = hv_ringbuffer_init(&newchannel->inbound, &page[send_ringbuffer_size >> PAGE_SHIFT], recv_ringbuffer_size >> PAGE_SHIFT); |
fd4dc88e4 staging: hv: Fix ... |
126 |
if (ret != 0) { |
3324fb405 staging: hv: chec... |
127 |
err = ret; |
98f531b10 Drivers: hv: clea... |
128 |
goto error_free_pages; |
3324fb405 staging: hv: chec... |
129 |
} |
3e7ee4902 Staging: hv: add ... |
130 |
|
3e7ee4902 Staging: hv: add ... |
131 |
|
454f18a96 Staging: hv: Remo... |
132 |
/* Establish the gpadl for the ring buffer */ |
c50f7fb28 staging: hv: Conv... |
133 |
newchannel->ringbuffer_gpadlhandle = 0; |
3e7ee4902 Staging: hv: add ... |
134 |
|
fff41b2e3 staging: hv: Rena... |
135 |
ret = vmbus_establish_gpadl(newchannel, |
9988ce685 Drivers: hv: ring... |
136 137 138 139 |
page_address(page), send_ringbuffer_size + recv_ringbuffer_size, &newchannel->ringbuffer_gpadlhandle); |
b94ef345b Staging: hv: test... |
140 |
|
fd4dc88e4 staging: hv: Fix ... |
141 |
if (ret != 0) { |
b94ef345b Staging: hv: test... |
142 |
err = ret; |
98f531b10 Drivers: hv: clea... |
143 |
goto error_free_pages; |
b94ef345b Staging: hv: test... |
144 |
} |
f4266e342 Staging: hv: codi... |
145 |
|
454f18a96 Staging: hv: Remo... |
146 |
/* Create and init the channel open message */ |
176fb9e3f Staging: hv: vmbu... |
147 |
open_info = kmalloc(sizeof(*open_info) + |
f4266e342 Staging: hv: codi... |
148 149 |
sizeof(struct vmbus_channel_open_channel), GFP_KERNEL); |
176fb9e3f Staging: hv: vmbu... |
150 |
if (!open_info) { |
c3bf2e26b Staging: hv: remo... |
151 |
err = -ENOMEM; |
98f531b10 Drivers: hv: clea... |
152 |
goto error_free_gpadl; |
c3bf2e26b Staging: hv: remo... |
153 |
} |
3e7ee4902 Staging: hv: add ... |
154 |
|
176fb9e3f Staging: hv: vmbu... |
155 |
init_completion(&open_info->waitevent); |
3e7ee4902 Staging: hv: add ... |
156 |
|
176fb9e3f Staging: hv: vmbu... |
157 |
open_msg = (struct vmbus_channel_open_channel *)open_info->msg; |
0987ff696 Staging: hv: vmbu... |
158 159 160 161 162 |
open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL; open_msg->openid = newchannel->offermsg.child_relid; open_msg->child_relid = newchannel->offermsg.child_relid; open_msg->ringbuffer_gpadlhandle = newchannel->ringbuffer_gpadlhandle; open_msg->downstream_ringbuffer_pageoffset = send_ringbuffer_size >> |
f4266e342 Staging: hv: codi... |
163 |
PAGE_SHIFT; |
abbf3b2aa Drivers: hv: Add ... |
164 |
open_msg->target_vp = newchannel->target_vp; |
3e7ee4902 Staging: hv: add ... |
165 |
|
39d70a4ab staging: hv: Remo... |
166 |
if (userdatalen > MAX_USER_DEFINED_BYTES) { |
c827f944f Staging: hv: remo... |
167 |
err = -EINVAL; |
98f531b10 Drivers: hv: clea... |
168 |
goto error_free_gpadl; |
c827f944f Staging: hv: remo... |
169 |
} |
39d70a4ab staging: hv: Remo... |
170 |
if (userdatalen) |
0987ff696 Staging: hv: vmbu... |
171 |
memcpy(open_msg->userdata, userdata, userdatalen); |
3e7ee4902 Staging: hv: add ... |
172 |
|
15b2f6479 staging: hv: Conv... |
173 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
176fb9e3f Staging: hv: vmbu... |
174 |
list_add_tail(&open_info->msglistentry, |
da9fcb726 staging: hv: Conv... |
175 |
&vmbus_connection.chn_msg_list); |
15b2f6479 staging: hv: Conv... |
176 |
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
3e7ee4902 Staging: hv: add ... |
177 |
|
0987ff696 Staging: hv: vmbu... |
178 |
ret = vmbus_post_msg(open_msg, |
f4266e342 Staging: hv: codi... |
179 |
sizeof(struct vmbus_channel_open_channel)); |
98e087022 staging: hv: Remo... |
180 |
|
45d727cee Drivers: hv: vmbu... |
181 182 |
if (ret != 0) { err = ret; |
98f531b10 Drivers: hv: clea... |
183 |
goto error_clean_msglist; |
45d727cee Drivers: hv: vmbu... |
184 |
} |
3e7ee4902 Staging: hv: add ... |
185 |
|
396e287fa Drivers: hv: get ... |
186 |
wait_for_completion(&open_info->waitevent); |
0c3b7b2f7 Staging: hv: Use ... |
187 |
|
15b2f6479 staging: hv: Conv... |
188 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
176fb9e3f Staging: hv: vmbu... |
189 |
list_del(&open_info->msglistentry); |
15b2f6479 staging: hv: Conv... |
190 |
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
3e7ee4902 Staging: hv: add ... |
191 |
|
ffc151f3c Drivers: hv: vmbu... |
192 193 |
if (open_info->response.open_result.status) { err = -EAGAIN; |
98f531b10 Drivers: hv: clea... |
194 |
goto error_free_gpadl; |
ffc151f3c Drivers: hv: vmbu... |
195 |
} |
e68d2971d Drivers: hv: vmbu... |
196 |
|
ffc151f3c Drivers: hv: vmbu... |
197 |
newchannel->state = CHANNEL_OPENED_STATE; |
176fb9e3f Staging: hv: vmbu... |
198 |
kfree(open_info); |
ffc151f3c Drivers: hv: vmbu... |
199 |
return 0; |
c3bf2e26b Staging: hv: remo... |
200 |
|
98f531b10 Drivers: hv: clea... |
201 |
error_clean_msglist: |
139255024 Drivers: hv: Clea... |
202 203 204 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&open_info->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
98f531b10 Drivers: hv: clea... |
205 |
error_free_gpadl: |
40384e4bb Drivers: hv: vmbu... |
206 |
vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); |
98f531b10 Drivers: hv: clea... |
207 208 |
kfree(open_info); error_free_pages: |
9988ce685 Drivers: hv: ring... |
209 210 211 212 |
hv_ringbuffer_cleanup(&newchannel->outbound); hv_ringbuffer_cleanup(&newchannel->inbound); __free_pages(page, get_order(send_ringbuffer_size + recv_ringbuffer_size)); |
98f531b10 Drivers: hv: clea... |
213 |
error_set_chnstate: |
ac0d12b7c hv: vmbus_open():... |
214 |
newchannel->state = CHANNEL_OPEN_STATE; |
c3bf2e26b Staging: hv: remo... |
215 |
return err; |
3e7ee4902 Staging: hv: add ... |
216 |
} |
36ceadfc6 Staging: hv: chan... |
217 |
EXPORT_SYMBOL_GPL(vmbus_open); |
3e7ee4902 Staging: hv: add ... |
218 |
|
5c23a1a5c Drivers: hv: vmbu... |
219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
/* Used for Hyper-V Socket: a guest client's connect() to the host */ int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id, const uuid_le *shv_host_servie_id) { struct vmbus_channel_tl_connect_request conn_msg; memset(&conn_msg, 0, sizeof(conn_msg)); conn_msg.header.msgtype = CHANNELMSG_TL_CONNECT_REQUEST; conn_msg.guest_endpoint_id = *shv_guest_servie_id; conn_msg.host_service_id = *shv_host_servie_id; return vmbus_post_msg(&conn_msg, sizeof(conn_msg)); } EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request); |
3e1895195 staging: hv: Corr... |
233 |
/* |
fff41b2e3 staging: hv: Rena... |
234 |
* create_gpadl_header - Creates a gpadl for the specified buffer |
f4266e342 Staging: hv: codi... |
235 |
*/ |
fff41b2e3 staging: hv: Rena... |
236 |
static int create_gpadl_header(void *kbuffer, u32 size, |
4d6376329 Drivers: hv: get ... |
237 |
struct vmbus_channel_msginfo **msginfo) |
3e7ee4902 Staging: hv: add ... |
238 239 |
{ int i; |
39d70a4ab staging: hv: Remo... |
240 |
int pagecount; |
39d70a4ab staging: hv: Remo... |
241 242 243 244 245 |
struct vmbus_channel_gpadl_header *gpadl_header; struct vmbus_channel_gpadl_body *gpadl_body; struct vmbus_channel_msginfo *msgheader; struct vmbus_channel_msginfo *msgbody = NULL; u32 msgsize; |
3e7ee4902 Staging: hv: add ... |
246 |
|
39d70a4ab staging: hv: Remo... |
247 |
int pfnsum, pfncount, pfnleft, pfncurr, pfnsize; |
3e7ee4902 Staging: hv: add ... |
248 |
|
39d70a4ab staging: hv: Remo... |
249 |
pagecount = size >> PAGE_SHIFT; |
3e7ee4902 Staging: hv: add ... |
250 |
|
454f18a96 Staging: hv: Remo... |
251 |
/* do we need a gpadl body msg */ |
39d70a4ab staging: hv: Remo... |
252 |
pfnsize = MAX_SIZE_CHANNEL_MESSAGE - |
f4266e342 Staging: hv: codi... |
253 254 |
sizeof(struct vmbus_channel_gpadl_header) - sizeof(struct gpa_range); |
39d70a4ab staging: hv: Remo... |
255 |
pfncount = pfnsize / sizeof(u64); |
3e7ee4902 Staging: hv: add ... |
256 |
|
39d70a4ab staging: hv: Remo... |
257 |
if (pagecount > pfncount) { |
f4266e342 Staging: hv: codi... |
258 |
/* we need a gpadl body */ |
454f18a96 Staging: hv: Remo... |
259 |
/* fill in the header */ |
39d70a4ab staging: hv: Remo... |
260 |
msgsize = sizeof(struct vmbus_channel_msginfo) + |
f4266e342 Staging: hv: codi... |
261 |
sizeof(struct vmbus_channel_gpadl_header) + |
39d70a4ab staging: hv: Remo... |
262 263 264 |
sizeof(struct gpa_range) + pfncount * sizeof(u64); msgheader = kzalloc(msgsize, GFP_KERNEL); if (!msgheader) |
d1c250bb5 Staging: hv: remo... |
265 |
goto nomem; |
3e7ee4902 Staging: hv: add ... |
266 |
|
c50f7fb28 staging: hv: Conv... |
267 268 |
INIT_LIST_HEAD(&msgheader->submsglist); msgheader->msgsize = msgsize; |
3e7ee4902 Staging: hv: add ... |
269 |
|
39d70a4ab staging: hv: Remo... |
270 |
gpadl_header = (struct vmbus_channel_gpadl_header *) |
c50f7fb28 staging: hv: Conv... |
271 272 273 |
msgheader->msg; gpadl_header->rangecount = 1; gpadl_header->range_buflen = sizeof(struct gpa_range) + |
39d70a4ab staging: hv: Remo... |
274 |
pagecount * sizeof(u64); |
415f22871 staging: hv: Conv... |
275 276 |
gpadl_header->range[0].byte_offset = 0; gpadl_header->range[0].byte_count = size; |
39d70a4ab staging: hv: Remo... |
277 |
for (i = 0; i < pfncount; i++) |
b679ef73e hyperv: Add suppo... |
278 279 |
gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys( kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; |
39d70a4ab staging: hv: Remo... |
280 |
*msginfo = msgheader; |
3e7ee4902 Staging: hv: add ... |
281 |
|
39d70a4ab staging: hv: Remo... |
282 283 |
pfnsum = pfncount; pfnleft = pagecount - pfncount; |
3e7ee4902 Staging: hv: add ... |
284 |
|
454f18a96 Staging: hv: Remo... |
285 |
/* how many pfns can we fit */ |
39d70a4ab staging: hv: Remo... |
286 |
pfnsize = MAX_SIZE_CHANNEL_MESSAGE - |
f4266e342 Staging: hv: codi... |
287 |
sizeof(struct vmbus_channel_gpadl_body); |
39d70a4ab staging: hv: Remo... |
288 |
pfncount = pfnsize / sizeof(u64); |
3e7ee4902 Staging: hv: add ... |
289 |
|
454f18a96 Staging: hv: Remo... |
290 |
/* fill in the body */ |
39d70a4ab staging: hv: Remo... |
291 292 293 |
while (pfnleft) { if (pfnleft > pfncount) pfncurr = pfncount; |
3e7ee4902 Staging: hv: add ... |
294 |
else |
39d70a4ab staging: hv: Remo... |
295 |
pfncurr = pfnleft; |
3e7ee4902 Staging: hv: add ... |
296 |
|
39d70a4ab staging: hv: Remo... |
297 |
msgsize = sizeof(struct vmbus_channel_msginfo) + |
f4266e342 Staging: hv: codi... |
298 |
sizeof(struct vmbus_channel_gpadl_body) + |
39d70a4ab staging: hv: Remo... |
299 300 |
pfncurr * sizeof(u64); msgbody = kzalloc(msgsize, GFP_KERNEL); |
f38cf9ccd Staging: hv: vmbu... |
301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
if (!msgbody) { struct vmbus_channel_msginfo *pos = NULL; struct vmbus_channel_msginfo *tmp = NULL; /* * Free up all the allocated messages. */ list_for_each_entry_safe(pos, tmp, &msgheader->submsglist, msglistentry) { list_del(&pos->msglistentry); kfree(pos); } |
d1c250bb5 Staging: hv: remo... |
315 |
goto nomem; |
f38cf9ccd Staging: hv: vmbu... |
316 |
} |
c50f7fb28 staging: hv: Conv... |
317 |
msgbody->msgsize = msgsize; |
39d70a4ab staging: hv: Remo... |
318 |
gpadl_body = |
c50f7fb28 staging: hv: Conv... |
319 |
(struct vmbus_channel_gpadl_body *)msgbody->msg; |
f4266e342 Staging: hv: codi... |
320 321 |
/* |
f4266e342 Staging: hv: codi... |
322 323 |
* Gpadl is u32 and we are using a pointer which could * be 64-bit |
f27df643d Staging: hv: vmbu... |
324 325 |
* This is governed by the guest/host protocol and * so the hypervisor gurantees that this is ok. |
f4266e342 Staging: hv: codi... |
326 |
*/ |
39d70a4ab staging: hv: Remo... |
327 |
for (i = 0; i < pfncurr; i++) |
b679ef73e hyperv: Add suppo... |
328 329 330 |
gpadl_body->pfn[i] = slow_virt_to_phys( kbuffer + PAGE_SIZE * (pfnsum + i)) >> PAGE_SHIFT; |
3e7ee4902 Staging: hv: add ... |
331 |
|
454f18a96 Staging: hv: Remo... |
332 |
/* add to msg header */ |
c50f7fb28 staging: hv: Conv... |
333 334 |
list_add_tail(&msgbody->msglistentry, &msgheader->submsglist); |
39d70a4ab staging: hv: Remo... |
335 336 |
pfnsum += pfncurr; pfnleft -= pfncurr; |
3e7ee4902 Staging: hv: add ... |
337 |
} |
f4266e342 Staging: hv: codi... |
338 |
} else { |
454f18a96 Staging: hv: Remo... |
339 |
/* everything fits in a header */ |
39d70a4ab staging: hv: Remo... |
340 |
msgsize = sizeof(struct vmbus_channel_msginfo) + |
f4266e342 Staging: hv: codi... |
341 |
sizeof(struct vmbus_channel_gpadl_header) + |
39d70a4ab staging: hv: Remo... |
342 343 344 |
sizeof(struct gpa_range) + pagecount * sizeof(u64); msgheader = kzalloc(msgsize, GFP_KERNEL); if (msgheader == NULL) |
e3eb7cdd1 staging: hv: chec... |
345 |
goto nomem; |
4d6376329 Drivers: hv: get ... |
346 347 |
INIT_LIST_HEAD(&msgheader->submsglist); |
c50f7fb28 staging: hv: Conv... |
348 |
msgheader->msgsize = msgsize; |
39d70a4ab staging: hv: Remo... |
349 350 |
gpadl_header = (struct vmbus_channel_gpadl_header *) |
c50f7fb28 staging: hv: Conv... |
351 352 353 |
msgheader->msg; gpadl_header->rangecount = 1; gpadl_header->range_buflen = sizeof(struct gpa_range) + |
39d70a4ab staging: hv: Remo... |
354 |
pagecount * sizeof(u64); |
415f22871 staging: hv: Conv... |
355 356 |
gpadl_header->range[0].byte_offset = 0; gpadl_header->range[0].byte_count = size; |
39d70a4ab staging: hv: Remo... |
357 |
for (i = 0; i < pagecount; i++) |
b679ef73e hyperv: Add suppo... |
358 359 |
gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys( kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT; |
39d70a4ab staging: hv: Remo... |
360 361 |
*msginfo = msgheader; |
3e7ee4902 Staging: hv: add ... |
362 363 364 |
} return 0; |
d1c250bb5 Staging: hv: remo... |
365 |
nomem: |
39d70a4ab staging: hv: Remo... |
366 367 |
kfree(msgheader); kfree(msgbody); |
d1c250bb5 Staging: hv: remo... |
368 |
return -ENOMEM; |
3e7ee4902 Staging: hv: add ... |
369 |
} |
3e1895195 staging: hv: Corr... |
370 |
/* |
fff41b2e3 staging: hv: Rena... |
371 |
* vmbus_establish_gpadl - Estabish a GPADL for the specified buffer |
f4266e342 Staging: hv: codi... |
372 |
* |
39d70a4ab staging: hv: Remo... |
373 |
* @channel: a channel |
b679ef73e hyperv: Add suppo... |
374 |
* @kbuffer: from kmalloc or vmalloc |
39d70a4ab staging: hv: Remo... |
375 376 |
* @size: page-size multiple * @gpadl_handle: some funky thing |
f4266e342 Staging: hv: codi... |
377 |
*/ |
fff41b2e3 staging: hv: Rena... |
378 |
int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, |
39d70a4ab staging: hv: Remo... |
379 |
u32 size, u32 *gpadl_handle) |
3e7ee4902 Staging: hv: add ... |
380 |
{ |
39d70a4ab staging: hv: Remo... |
381 382 |
struct vmbus_channel_gpadl_header *gpadlmsg; struct vmbus_channel_gpadl_body *gpadl_body; |
39d70a4ab staging: hv: Remo... |
383 |
struct vmbus_channel_msginfo *msginfo = NULL; |
7cc80c980 Drivers: hv: don'... |
384 |
struct vmbus_channel_msginfo *submsginfo, *tmp; |
53af545b2 Staging: hv: remo... |
385 |
struct list_head *curr; |
39d70a4ab staging: hv: Remo... |
386 |
u32 next_gpadl_handle; |
dd0813b6f Staging: hv: make... |
387 |
unsigned long flags; |
c3bf2e26b Staging: hv: remo... |
388 |
int ret = 0; |
3e7ee4902 Staging: hv: add ... |
389 |
|
9f52a1630 Drivers: hv: vmbu... |
390 391 |
next_gpadl_handle = (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1); |
3e7ee4902 Staging: hv: add ... |
392 |
|
4d6376329 Drivers: hv: get ... |
393 |
ret = create_gpadl_header(kbuffer, size, &msginfo); |
c3bf2e26b Staging: hv: remo... |
394 395 |
if (ret) return ret; |
3e7ee4902 Staging: hv: add ... |
396 |
|
9568a1931 Staging: hv: Use ... |
397 |
init_completion(&msginfo->waitevent); |
c3bf2e26b Staging: hv: remo... |
398 |
|
c50f7fb28 staging: hv: Conv... |
399 400 401 402 |
gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg; gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER; gpadlmsg->child_relid = channel->offermsg.child_relid; gpadlmsg->gpadl = next_gpadl_handle; |
3e7ee4902 Staging: hv: add ... |
403 |
|
3e7ee4902 Staging: hv: add ... |
404 |
|
15b2f6479 staging: hv: Conv... |
405 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
c50f7fb28 staging: hv: Conv... |
406 |
list_add_tail(&msginfo->msglistentry, |
da9fcb726 staging: hv: Conv... |
407 |
&vmbus_connection.chn_msg_list); |
3e7ee4902 Staging: hv: add ... |
408 |
|
15b2f6479 staging: hv: Conv... |
409 |
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
3e7ee4902 Staging: hv: add ... |
410 |
|
c69776771 staging: hv: Conv... |
411 |
ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize - |
39d70a4ab staging: hv: Remo... |
412 |
sizeof(*msginfo)); |
98e087022 staging: hv: Remo... |
413 |
if (ret != 0) |
00d760b05 Staging: hv: vmbu... |
414 |
goto cleanup; |
3e7ee4902 Staging: hv: add ... |
415 |
|
4d6376329 Drivers: hv: get ... |
416 417 418 419 |
list_for_each(curr, &msginfo->submsglist) { submsginfo = (struct vmbus_channel_msginfo *)curr; gpadl_body = (struct vmbus_channel_gpadl_body *)submsginfo->msg; |
53af545b2 Staging: hv: remo... |
420 |
|
4d6376329 Drivers: hv: get ... |
421 422 423 |
gpadl_body->header.msgtype = CHANNELMSG_GPADL_BODY; gpadl_body->gpadl = next_gpadl_handle; |
3e7ee4902 Staging: hv: add ... |
424 |
|
4d6376329 Drivers: hv: get ... |
425 426 427 428 429 |
ret = vmbus_post_msg(gpadl_body, submsginfo->msgsize - sizeof(*submsginfo)); if (ret != 0) goto cleanup; |
3e7ee4902 Staging: hv: add ... |
430 |
|
3e7ee4902 Staging: hv: add ... |
431 |
} |
72c6b71c2 Drivers: hv: vmbu... |
432 |
wait_for_completion(&msginfo->waitevent); |
3e7ee4902 Staging: hv: add ... |
433 |
|
454f18a96 Staging: hv: Remo... |
434 |
/* At this point, we received the gpadl created msg */ |
c50f7fb28 staging: hv: Conv... |
435 |
*gpadl_handle = gpadlmsg->gpadl; |
3e7ee4902 Staging: hv: add ... |
436 |
|
00d760b05 Staging: hv: vmbu... |
437 |
cleanup: |
15b2f6479 staging: hv: Conv... |
438 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
c50f7fb28 staging: hv: Conv... |
439 |
list_del(&msginfo->msglistentry); |
15b2f6479 staging: hv: Conv... |
440 |
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
7cc80c980 Drivers: hv: don'... |
441 442 443 444 |
list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist, msglistentry) { kfree(submsginfo); } |
3e7ee4902 Staging: hv: add ... |
445 |
|
39d70a4ab staging: hv: Remo... |
446 |
kfree(msginfo); |
3e7ee4902 Staging: hv: add ... |
447 448 |
return ret; } |
98873724a Staging: hv: chan... |
449 |
EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); |
3e7ee4902 Staging: hv: add ... |
450 |
|
3e1895195 staging: hv: Corr... |
451 |
/* |
fff41b2e3 staging: hv: Rena... |
452 |
* vmbus_teardown_gpadl -Teardown the specified GPADL handle |
f4266e342 Staging: hv: codi... |
453 |
*/ |
fff41b2e3 staging: hv: Rena... |
454 |
int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) |
3e7ee4902 Staging: hv: add ... |
455 |
{ |
82250213d Staging: hv: type... |
456 |
struct vmbus_channel_gpadl_teardown *msg; |
aded7165f Staging: hv: clea... |
457 |
struct vmbus_channel_msginfo *info; |
dd0813b6f Staging: hv: make... |
458 |
unsigned long flags; |
66be65308 Drivers: hv: vmbu... |
459 |
int ret; |
3e7ee4902 Staging: hv: add ... |
460 |
|
f4266e342 Staging: hv: codi... |
461 462 |
info = kmalloc(sizeof(*info) + sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL); |
c3bf2e26b Staging: hv: remo... |
463 464 |
if (!info) return -ENOMEM; |
3e7ee4902 Staging: hv: add ... |
465 |
|
9568a1931 Staging: hv: Use ... |
466 |
init_completion(&info->waitevent); |
3e7ee4902 Staging: hv: add ... |
467 |
|
c50f7fb28 staging: hv: Conv... |
468 |
msg = (struct vmbus_channel_gpadl_teardown *)info->msg; |
3e7ee4902 Staging: hv: add ... |
469 |
|
c50f7fb28 staging: hv: Conv... |
470 471 472 |
msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN; msg->child_relid = channel->offermsg.child_relid; msg->gpadl = gpadl_handle; |
3e7ee4902 Staging: hv: add ... |
473 |
|
15b2f6479 staging: hv: Conv... |
474 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
c50f7fb28 staging: hv: Conv... |
475 |
list_add_tail(&info->msglistentry, |
da9fcb726 staging: hv: Conv... |
476 |
&vmbus_connection.chn_msg_list); |
15b2f6479 staging: hv: Conv... |
477 |
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
c69776771 staging: hv: Conv... |
478 |
ret = vmbus_post_msg(msg, |
f4266e342 Staging: hv: codi... |
479 |
sizeof(struct vmbus_channel_gpadl_teardown)); |
3e7ee4902 Staging: hv: add ... |
480 |
|
66be65308 Drivers: hv: vmbu... |
481 482 483 484 |
if (ret) goto post_msg_err; wait_for_completion(&info->waitevent); |
3e7ee4902 Staging: hv: add ... |
485 |
|
66be65308 Drivers: hv: vmbu... |
486 |
post_msg_err: |
15b2f6479 staging: hv: Conv... |
487 |
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); |
c50f7fb28 staging: hv: Conv... |
488 |
list_del(&info->msglistentry); |
15b2f6479 staging: hv: Conv... |
489 |
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
3e7ee4902 Staging: hv: add ... |
490 |
|
8c69f52ab Staging: hv: osd:... |
491 |
kfree(info); |
3e7ee4902 Staging: hv: add ... |
492 493 |
return ret; } |
18726d7a6 Staging: hv: chan... |
494 |
EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); |
3e7ee4902 Staging: hv: add ... |
495 |
|
d3ba720dd Drivers: hv: Elim... |
496 497 498 499 500 501 |
static void reset_channel_cb(void *arg) { struct vmbus_channel *channel = arg; channel->onchannel_callback = NULL; } |
98d731bb0 Drivers: hv: vmbu... |
502 |
static int vmbus_close_internal(struct vmbus_channel *channel) |
3e7ee4902 Staging: hv: add ... |
503 |
{ |
82250213d Staging: hv: type... |
504 |
struct vmbus_channel_close_channel *msg; |
f4266e342 Staging: hv: codi... |
505 |
int ret; |
3e7ee4902 Staging: hv: add ... |
506 |
|
63d55b2ae Drivers: hv: vmbu... |
507 508 509 510 511 512 513 514 515 |
/* * process_chn_event(), running in the tasklet, can race * with vmbus_close_internal() in the case of SMP guest, e.g., when * the former is accessing channel->inbound.ring_buffer, the latter * could be freeing the ring_buffer pages. * * To resolve the race, we can serialize them by disabling the * tasklet when the latter is running here. */ |
638fea33a Drivers: hv: vmbu... |
516 |
hv_event_tasklet_disable(channel); |
63d55b2ae Drivers: hv: vmbu... |
517 |
|
64b7faf90 Drivers: hv: vmbu... |
518 519 520 521 522 523 524 525 526 527 528 |
/* * In case a device driver's probe() fails (e.g., * util_probe() -> vmbus_open() returns -ENOMEM) and the device is * rescinded later (e.g., we dynamically disble an Integrated Service * in Hyper-V Manager), the driver's remove() invokes vmbus_close(): * here we should skip most of the below cleanup work. */ if (channel->state != CHANNEL_OPENED_STATE) { ret = -EINVAL; goto out; } |
e68d2971d Drivers: hv: vmbu... |
529 530 |
channel->state = CHANNEL_OPEN_STATE; channel->sc_creation_callback = NULL; |
454f18a96 Staging: hv: Remo... |
531 |
/* Stop callback and cancel the timer asap */ |
2115b5617 Drivers: hv: vmbu... |
532 533 |
if (channel->target_cpu != get_cpu()) { put_cpu(); |
d3ba720dd Drivers: hv: Elim... |
534 535 |
smp_call_function_single(channel->target_cpu, reset_channel_cb, channel, true); |
2115b5617 Drivers: hv: vmbu... |
536 |
} else { |
d3ba720dd Drivers: hv: Elim... |
537 |
reset_channel_cb(channel); |
2115b5617 Drivers: hv: vmbu... |
538 539 |
put_cpu(); } |
3e7ee4902 Staging: hv: add ... |
540 |
|
454f18a96 Staging: hv: Remo... |
541 |
/* Send a closing message */ |
3e7ee4902 Staging: hv: add ... |
542 |
|
e9a27a9f9 Staging: hv: vmbu... |
543 |
msg = &channel->close_msg.msg; |
3e7ee4902 Staging: hv: add ... |
544 |
|
c50f7fb28 staging: hv: Conv... |
545 546 |
msg->header.msgtype = CHANNELMSG_CLOSECHANNEL; msg->child_relid = channel->offermsg.child_relid; |
3e7ee4902 Staging: hv: add ... |
547 |
|
c69776771 staging: hv: Conv... |
548 |
ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_close_channel)); |
3e7ee4902 Staging: hv: add ... |
549 |
|
98d731bb0 Drivers: hv: vmbu... |
550 551 552 553 554 555 556 |
if (ret) { pr_err("Close failed: close post msg return is %d ", ret); /* * If we failed to post the close msg, * it is perhaps better to leak memory. */ |
63d55b2ae Drivers: hv: vmbu... |
557 |
goto out; |
98d731bb0 Drivers: hv: vmbu... |
558 |
} |
454f18a96 Staging: hv: Remo... |
559 |
/* Tear down the gpadl for the channel's ring buffer */ |
98d731bb0 Drivers: hv: vmbu... |
560 561 562 563 564 565 566 567 568 569 |
if (channel->ringbuffer_gpadlhandle) { ret = vmbus_teardown_gpadl(channel, channel->ringbuffer_gpadlhandle); if (ret) { pr_err("Close failed: teardown gpadl return %d ", ret); /* * If we failed to teardown gpadl, * it is perhaps better to leak memory. */ |
63d55b2ae Drivers: hv: vmbu... |
570 |
goto out; |
98d731bb0 Drivers: hv: vmbu... |
571 572 |
} } |
3e7ee4902 Staging: hv: add ... |
573 |
|
454f18a96 Staging: hv: Remo... |
574 |
/* Cleanup the ring buffers for this channel */ |
2dba688ba Staging: hv: Rena... |
575 576 |
hv_ringbuffer_cleanup(&channel->outbound); hv_ringbuffer_cleanup(&channel->inbound); |
3e7ee4902 Staging: hv: add ... |
577 |
|
df3493e0b Staging: hv: Use ... |
578 579 |
free_pages((unsigned long)channel->ringbuffer_pages, get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); |
3e7ee4902 Staging: hv: add ... |
580 |
|
63d55b2ae Drivers: hv: vmbu... |
581 |
out: |
638fea33a Drivers: hv: vmbu... |
582 |
hv_event_tasklet_enable(channel); |
63d55b2ae Drivers: hv: vmbu... |
583 |
|
98d731bb0 Drivers: hv: vmbu... |
584 |
return ret; |
3e7ee4902 Staging: hv: add ... |
585 |
} |
e68d2971d Drivers: hv: vmbu... |
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
/* * vmbus_close - Close the specified channel */ void vmbus_close(struct vmbus_channel *channel) { struct list_head *cur, *tmp; struct vmbus_channel *cur_channel; if (channel->primary_channel != NULL) { /* * We will only close sub-channels when * the primary is closed. */ return; } /* * Close all the sub-channels first and then close the * primary channel. */ list_for_each_safe(cur, tmp, &channel->sc_list) { cur_channel = list_entry(cur, struct vmbus_channel, sc_list); if (cur_channel->state != CHANNEL_OPENED_STATE) continue; vmbus_close_internal(cur_channel); } /* * Now close the primary. */ vmbus_close_internal(channel); } |
70bfa3078 Staging: hv: chan... |
617 |
EXPORT_SYMBOL_GPL(vmbus_close); |
3e7ee4902 Staging: hv: add ... |
618 |
|
e9395e3f8 Drivers: hv: vmbu... |
619 |
int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, |
39d70a4ab staging: hv: Remo... |
620 |
u32 bufferlen, u64 requestid, |
e9395e3f8 Drivers: hv: vmbu... |
621 |
enum vmbus_packet_type type, u32 flags, bool kick_q) |
3e7ee4902 Staging: hv: add ... |
622 |
{ |
8dc0a06ad Staging: hv: remo... |
623 |
struct vmpacket_descriptor desc; |
39d70a4ab staging: hv: Remo... |
624 |
u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen; |
735096819 staging/hv/osd: d... |
625 |
u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64)); |
011a7c3cc Drivers: hv: vmbu... |
626 |
struct kvec bufferlist[3]; |
39d70a4ab staging: hv: Remo... |
627 |
u64 aligned_data = 0; |
fe760e4d6 Drivers: hv: vmbu... |
628 |
bool lock = channel->acquire_ring_lock; |
b81658cf5 Drivers: hv: vmbu... |
629 |
int num_vecs = ((bufferlen != 0) ? 3 : 1); |
3e7ee4902 Staging: hv: add ... |
630 |
|
3e7ee4902 Staging: hv: add ... |
631 |
|
454f18a96 Staging: hv: Remo... |
632 |
/* Setup the descriptor */ |
415f22871 staging: hv: Conv... |
633 634 |
desc.type = type; /* VmbusPacketTypeDataInBand; */ desc.flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */ |
f4266e342 Staging: hv: codi... |
635 |
/* in 8-bytes granularity */ |
415f22871 staging: hv: Conv... |
636 637 638 |
desc.offset8 = sizeof(struct vmpacket_descriptor) >> 3; desc.len8 = (u16)(packetlen_aligned >> 3); desc.trans_id = requestid; |
3e7ee4902 Staging: hv: add ... |
639 |
|
011a7c3cc Drivers: hv: vmbu... |
640 641 642 643 644 645 |
bufferlist[0].iov_base = &desc; bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor); bufferlist[1].iov_base = buffer; bufferlist[1].iov_len = bufferlen; bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
3e7ee4902 Staging: hv: add ... |
646 |
|
e2fdf7841 Drivers: hv: vmbu... |
647 648 |
return hv_ringbuffer_write(channel, bufferlist, num_vecs, lock, kick_q); |
3e7ee4902 Staging: hv: add ... |
649 |
|
3e7ee4902 Staging: hv: add ... |
650 |
} |
e9395e3f8 Drivers: hv: vmbu... |
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
EXPORT_SYMBOL(vmbus_sendpacket_ctl); /** * vmbus_sendpacket() - Send the specified buffer on the given channel * @channel: Pointer to vmbus_channel structure. * @buffer: Pointer to the buffer you want to receive the data into. * @bufferlen: Maximum size of what the the buffer will hold * @requestid: Identifier of the request * @type: Type of packet that is being send e.g. negotiate, time * packet etc. * * Sends data in @buffer directly to hyper-v via the vmbus * This will send the data unparsed to hyper-v. * * Mainly used by Hyper-V drivers. */ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u64 requestid, enum vmbus_packet_type type, u32 flags) { return vmbus_sendpacket_ctl(channel, buffer, bufferlen, requestid, type, flags, true); } |
fff41b2e3 staging: hv: Rena... |
674 |
EXPORT_SYMBOL(vmbus_sendpacket); |
3e7ee4902 Staging: hv: add ... |
675 |
|
3e1895195 staging: hv: Corr... |
676 |
/* |
87e93d617 Drivers: hv: vmbu... |
677 678 679 680 681 |
* vmbus_sendpacket_pagebuffer_ctl - Send a range of single-page buffer * packets using a GPADL Direct packet type. This interface allows you * to control notifying the host. This will be useful for sending * batched data. Also the sender can control the send flags * explicitly. |
f4266e342 Staging: hv: codi... |
682 |
*/ |
87e93d617 Drivers: hv: vmbu... |
683 |
int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, |
39d70a4ab staging: hv: Remo... |
684 685 |
struct hv_page_buffer pagebuffers[], u32 pagecount, void *buffer, u32 bufferlen, |
87e93d617 Drivers: hv: vmbu... |
686 687 688 |
u64 requestid, u32 flags, bool kick_q) |
3e7ee4902 Staging: hv: add ... |
689 |
{ |
f4266e342 Staging: hv: codi... |
690 |
int i; |
430a8e9a3 staging: hv: Remo... |
691 |
struct vmbus_channel_packet_page_buffer desc; |
39d70a4ab staging: hv: Remo... |
692 693 694 |
u32 descsize; u32 packetlen; u32 packetlen_aligned; |
011a7c3cc Drivers: hv: vmbu... |
695 |
struct kvec bufferlist[3]; |
39d70a4ab staging: hv: Remo... |
696 |
u64 aligned_data = 0; |
fe760e4d6 Drivers: hv: vmbu... |
697 |
bool lock = channel->acquire_ring_lock; |
3e7ee4902 Staging: hv: add ... |
698 |
|
39d70a4ab staging: hv: Remo... |
699 |
if (pagecount > MAX_PAGE_BUFFER_COUNT) |
002b53ea5 Staging: hv: retu... |
700 |
return -EINVAL; |
3e7ee4902 Staging: hv: add ... |
701 |
|
3e7ee4902 Staging: hv: add ... |
702 |
|
f4266e342 Staging: hv: codi... |
703 |
/* |
430a8e9a3 staging: hv: Remo... |
704 |
* Adjust the size down since vmbus_channel_packet_page_buffer is the |
f4266e342 Staging: hv: codi... |
705 706 |
* largest size we support */ |
39d70a4ab staging: hv: Remo... |
707 708 |
descsize = sizeof(struct vmbus_channel_packet_page_buffer) - ((MAX_PAGE_BUFFER_COUNT - pagecount) * |
f4266e342 Staging: hv: codi... |
709 |
sizeof(struct hv_page_buffer)); |
39d70a4ab staging: hv: Remo... |
710 |
packetlen = descsize + bufferlen; |
735096819 staging/hv/osd: d... |
711 |
packetlen_aligned = ALIGN(packetlen, sizeof(u64)); |
3e7ee4902 Staging: hv: add ... |
712 |
|
454f18a96 Staging: hv: Remo... |
713 |
/* Setup the descriptor */ |
415f22871 staging: hv: Conv... |
714 |
desc.type = VM_PKT_DATA_USING_GPA_DIRECT; |
87e93d617 Drivers: hv: vmbu... |
715 |
desc.flags = flags; |
39d70a4ab staging: hv: Remo... |
716 717 718 719 720 721 |
desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ desc.length8 = (u16)(packetlen_aligned >> 3); desc.transactionid = requestid; desc.rangecount = pagecount; for (i = 0; i < pagecount; i++) { |
ca623ad35 staging: hv: Conv... |
722 723 724 |
desc.range[i].len = pagebuffers[i].len; desc.range[i].offset = pagebuffers[i].offset; desc.range[i].pfn = pagebuffers[i].pfn; |
3e7ee4902 Staging: hv: add ... |
725 |
} |
011a7c3cc Drivers: hv: vmbu... |
726 727 728 729 730 731 |
bufferlist[0].iov_base = &desc; bufferlist[0].iov_len = descsize; bufferlist[1].iov_base = buffer; bufferlist[1].iov_len = bufferlen; bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
3e7ee4902 Staging: hv: add ... |
732 |
|
e2fdf7841 Drivers: hv: vmbu... |
733 734 |
return hv_ringbuffer_write(channel, bufferlist, 3, lock, kick_q); |
3e7ee4902 Staging: hv: add ... |
735 |
} |
b3a19b36a Drivers: hv: vmbu... |
736 |
EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer_ctl); |
87e93d617 Drivers: hv: vmbu... |
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 |
/* * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer * packets using a GPADL Direct packet type. */ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, struct hv_page_buffer pagebuffers[], u32 pagecount, void *buffer, u32 bufferlen, u64 requestid) { u32 flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; return vmbus_sendpacket_pagebuffer_ctl(channel, pagebuffers, pagecount, buffer, bufferlen, requestid, flags, true); } |
713efeb4d Staging: hv: chan... |
753 |
EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); |
3e7ee4902 Staging: hv: add ... |
754 |
|
3e1895195 staging: hv: Corr... |
755 |
/* |
fff41b2e3 staging: hv: Rena... |
756 |
* vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet |
3e1895195 staging: hv: Corr... |
757 |
* using a GPADL Direct packet type. |
d61031ee8 Drivers: hv: vmbu... |
758 759 760 761 762 763 764 |
* The buffer includes the vmbus descriptor. */ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, struct vmbus_packet_mpb_array *desc, u32 desc_size, void *buffer, u32 bufferlen, u64 requestid) { |
d61031ee8 Drivers: hv: vmbu... |
765 766 767 768 |
u32 packetlen; u32 packetlen_aligned; struct kvec bufferlist[3]; u64 aligned_data = 0; |
fe760e4d6 Drivers: hv: vmbu... |
769 |
bool lock = channel->acquire_ring_lock; |
d61031ee8 Drivers: hv: vmbu... |
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 |
packetlen = desc_size + bufferlen; packetlen_aligned = ALIGN(packetlen, sizeof(u64)); /* Setup the descriptor */ desc->type = VM_PKT_DATA_USING_GPA_DIRECT; desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */ desc->length8 = (u16)(packetlen_aligned >> 3); desc->transactionid = requestid; desc->rangecount = 1; bufferlist[0].iov_base = desc; bufferlist[0].iov_len = desc_size; bufferlist[1].iov_base = buffer; bufferlist[1].iov_len = bufferlen; bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
e2fdf7841 Drivers: hv: vmbu... |
788 789 |
return hv_ringbuffer_write(channel, bufferlist, 3, lock, true); |
d61031ee8 Drivers: hv: vmbu... |
790 791 792 793 794 795 |
} EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc); /* * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet * using a GPADL Direct packet type. |
f4266e342 Staging: hv: codi... |
796 |
*/ |
fff41b2e3 staging: hv: Rena... |
797 |
int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, |
39d70a4ab staging: hv: Remo... |
798 799 |
struct hv_multipage_buffer *multi_pagebuffer, void *buffer, u32 bufferlen, u64 requestid) |
3e7ee4902 Staging: hv: add ... |
800 |
{ |
430a8e9a3 staging: hv: Remo... |
801 |
struct vmbus_channel_packet_multipage_buffer desc; |
39d70a4ab staging: hv: Remo... |
802 803 804 |
u32 descsize; u32 packetlen; u32 packetlen_aligned; |
011a7c3cc Drivers: hv: vmbu... |
805 |
struct kvec bufferlist[3]; |
39d70a4ab staging: hv: Remo... |
806 |
u64 aligned_data = 0; |
fe760e4d6 Drivers: hv: vmbu... |
807 |
bool lock = channel->acquire_ring_lock; |
ca623ad35 staging: hv: Conv... |
808 809 |
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset, multi_pagebuffer->len); |
3e7ee4902 Staging: hv: add ... |
810 |
|
24b8a406b hv: Remove unnece... |
811 |
if (pfncount > MAX_MULTIPAGE_BUFFER_COUNT) |
002b53ea5 Staging: hv: retu... |
812 |
return -EINVAL; |
3e7ee4902 Staging: hv: add ... |
813 |
|
f4266e342 Staging: hv: codi... |
814 |
/* |
430a8e9a3 staging: hv: Remo... |
815 |
* Adjust the size down since vmbus_channel_packet_multipage_buffer is |
f4266e342 Staging: hv: codi... |
816 817 |
* the largest size we support */ |
39d70a4ab staging: hv: Remo... |
818 819 |
descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) - ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) * |
f4266e342 Staging: hv: codi... |
820 |
sizeof(u64)); |
39d70a4ab staging: hv: Remo... |
821 |
packetlen = descsize + bufferlen; |
735096819 staging/hv/osd: d... |
822 |
packetlen_aligned = ALIGN(packetlen, sizeof(u64)); |
3e7ee4902 Staging: hv: add ... |
823 |
|
3e7ee4902 Staging: hv: add ... |
824 |
|
454f18a96 Staging: hv: Remo... |
825 |
/* Setup the descriptor */ |
415f22871 staging: hv: Conv... |
826 |
desc.type = VM_PKT_DATA_USING_GPA_DIRECT; |
430a8e9a3 staging: hv: Remo... |
827 |
desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; |
39d70a4ab staging: hv: Remo... |
828 829 830 |
desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ desc.length8 = (u16)(packetlen_aligned >> 3); desc.transactionid = requestid; |
430a8e9a3 staging: hv: Remo... |
831 |
desc.rangecount = 1; |
3e7ee4902 Staging: hv: add ... |
832 |
|
ca623ad35 staging: hv: Conv... |
833 834 |
desc.range.len = multi_pagebuffer->len; desc.range.offset = multi_pagebuffer->offset; |
3e7ee4902 Staging: hv: add ... |
835 |
|
ca623ad35 staging: hv: Conv... |
836 |
memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array, |
39d70a4ab staging: hv: Remo... |
837 |
pfncount * sizeof(u64)); |
3e7ee4902 Staging: hv: add ... |
838 |
|
011a7c3cc Drivers: hv: vmbu... |
839 840 841 842 843 844 |
bufferlist[0].iov_base = &desc; bufferlist[0].iov_len = descsize; bufferlist[1].iov_base = buffer; bufferlist[1].iov_len = bufferlen; bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); |
3e7ee4902 Staging: hv: add ... |
845 |
|
e2fdf7841 Drivers: hv: vmbu... |
846 847 |
return hv_ringbuffer_write(channel, bufferlist, 3, lock, true); |
3e7ee4902 Staging: hv: add ... |
848 |
} |
4cb106faf Staging: hv: chan... |
849 |
EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer); |
c88c4e4c7 Staging: hv: Adde... |
850 851 |
/** |
fff41b2e3 staging: hv: Rena... |
852 |
* vmbus_recvpacket() - Retrieve the user packet on the specified channel |
39d70a4ab staging: hv: Remo... |
853 854 855 856 857 |
* @channel: Pointer to vmbus_channel structure. * @buffer: Pointer to the buffer you want to receive the data into. * @bufferlen: Maximum size of what the the buffer will hold * @buffer_actual_len: The actual size of the data after it was received * @requestid: Identifier of the request |
c88c4e4c7 Staging: hv: Adde... |
858 859 860 861 862 |
* * Receives directly from the hyper-v vmbus and puts the data it received * into Buffer. This will receive the data unparsed from hyper-v. * * Mainly used by Hyper-V drivers. |
f4266e342 Staging: hv: codi... |
863 |
*/ |
667d37406 Drivers: hv: remo... |
864 865 866 867 |
static inline int __vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u32 *buffer_actual_len, u64 *requestid, bool raw) |
3e7ee4902 Staging: hv: add ... |
868 |
{ |
964dfbe3d Drivers: hv: vmbu... |
869 870 |
return hv_ringbuffer_read(channel, buffer, bufferlen, buffer_actual_len, requestid, raw); |
3e7ee4902 Staging: hv: add ... |
871 |
|
667d37406 Drivers: hv: remo... |
872 873 874 875 876 877 878 879 |
} int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u32 *buffer_actual_len, u64 *requestid) { return __vmbus_recvpacket(channel, buffer, bufferlen, buffer_actual_len, requestid, false); |
3e7ee4902 Staging: hv: add ... |
880 |
} |
fff41b2e3 staging: hv: Rena... |
881 |
EXPORT_SYMBOL(vmbus_recvpacket); |
3e7ee4902 Staging: hv: add ... |
882 |
|
3e1895195 staging: hv: Corr... |
883 |
/* |
fff41b2e3 staging: hv: Rena... |
884 |
* vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel |
f4266e342 Staging: hv: codi... |
885 |
*/ |
fff41b2e3 staging: hv: Rena... |
886 |
int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, |
39d70a4ab staging: hv: Remo... |
887 888 |
u32 bufferlen, u32 *buffer_actual_len, u64 *requestid) |
3e7ee4902 Staging: hv: add ... |
889 |
{ |
667d37406 Drivers: hv: remo... |
890 891 |
return __vmbus_recvpacket(channel, buffer, bufferlen, buffer_actual_len, requestid, true); |
3e7ee4902 Staging: hv: add ... |
892 |
} |
adaee6bd4 Staging: hv: chan... |
893 |
EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); |