]>
Commit | Line | Data |
---|---|---|
3e7ee490 HJ |
1 | /* |
2 | * | |
3 | * Copyright (c) 2009, Microsoft Corporation. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | |
17 | * | |
18 | * Authors: | |
19 | * Haiyang Zhang <[email protected]> | |
20 | * Hank Janssen <[email protected]> | |
21 | * | |
22 | */ | |
0a46618d | 23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
3e7ee490 | 24 | |
a0086dc5 GKH |
25 | #include <linux/kernel.h> |
26 | #include <linux/mm.h> | |
645954c5 | 27 | #include "logging.h" |
8f078ca6 | 28 | #include "ring_buffer.h" |
3e7ee490 | 29 | |
3e7ee490 | 30 | |
454f18a9 BP |
31 | /* #defines */ |
32 | ||
33 | ||
34 | /* Amount of space to write to */ | |
0686e4f4 | 35 | #define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w)) |
3e7ee490 HJ |
36 | |
37 | ||
38 | /*++ | |
39 | ||
40 | Name: | |
1ac58644 | 41 | get_ringbuffer_availbytes() |
3e7ee490 HJ |
42 | |
43 | Description: | |
44 | Get number of bytes available to read and to write to | |
45 | for the specified ring buffer | |
46 | ||
47 | --*/ | |
48 | static inline void | |
1ac58644 HZ |
49 | get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, |
50 | u32 *read, u32 *write) | |
3e7ee490 | 51 | { |
4408f531 | 52 | u32 read_loc, write_loc; |
3e7ee490 | 53 | |
454f18a9 | 54 | /* Capture the read/write indices before they changed */ |
82f8bd40 HZ |
55 | read_loc = rbi->ring_buffer->read_index; |
56 | write_loc = rbi->ring_buffer->write_index; | |
3e7ee490 | 57 | |
82f8bd40 HZ |
58 | *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->ring_datasize); |
59 | *read = rbi->ring_datasize - *write; | |
3e7ee490 HJ |
60 | } |
61 | ||
62 | /*++ | |
63 | ||
64 | Name: | |
1ac58644 | 65 | get_next_write_location() |
3e7ee490 HJ |
66 | |
67 | Description: | |
68 | Get the next write location for the specified ring buffer | |
69 | ||
70 | --*/ | |
4d643114 | 71 | static inline u32 |
1ac58644 | 72 | get_next_write_location(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 73 | { |
fc8c72eb | 74 | u32 next = ring_info->ring_buffer->write_index; |
3e7ee490 | 75 | |
fc8c72eb | 76 | /* ASSERT(next < ring_info->RingDataSize); */ |
3e7ee490 HJ |
77 | |
78 | return next; | |
79 | } | |
80 | ||
81 | /*++ | |
82 | ||
83 | Name: | |
1ac58644 | 84 | set_next_write_location() |
3e7ee490 HJ |
85 | |
86 | Description: | |
87 | Set the next write location for the specified ring buffer | |
88 | ||
89 | --*/ | |
90 | static inline void | |
1ac58644 | 91 | set_next_write_location(struct hv_ring_buffer_info *ring_info, |
fc8c72eb | 92 | u32 next_write_location) |
3e7ee490 | 93 | { |
fc8c72eb | 94 | ring_info->ring_buffer->write_index = next_write_location; |
3e7ee490 HJ |
95 | } |
96 | ||
97 | /*++ | |
98 | ||
99 | Name: | |
1ac58644 | 100 | get_next_read_location() |
3e7ee490 HJ |
101 | |
102 | Description: | |
103 | Get the next read location for the specified ring buffer | |
104 | ||
105 | --*/ | |
4d643114 | 106 | static inline u32 |
1ac58644 | 107 | get_next_read_location(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 108 | { |
fc8c72eb | 109 | u32 next = ring_info->ring_buffer->read_index; |
3e7ee490 | 110 | |
fc8c72eb | 111 | /* ASSERT(next < ring_info->RingDataSize); */ |
3e7ee490 HJ |
112 | |
113 | return next; | |
114 | } | |
115 | ||
116 | /*++ | |
117 | ||
118 | Name: | |
1ac58644 | 119 | get_next_readlocation_withoffset() |
3e7ee490 HJ |
120 | |
121 | Description: | |
122 | Get the next read location + offset for the specified ring buffer. | |
123 | This allows the caller to skip | |
124 | ||
125 | --*/ | |
4d643114 | 126 | static inline u32 |
1ac58644 HZ |
127 | get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info, |
128 | u32 offset) | |
3e7ee490 | 129 | { |
fc8c72eb | 130 | u32 next = ring_info->ring_buffer->read_index; |
3e7ee490 | 131 | |
fc8c72eb HZ |
132 | /* ASSERT(next < ring_info->RingDataSize); */ |
133 | next += offset; | |
134 | next %= ring_info->ring_datasize; | |
3e7ee490 HJ |
135 | |
136 | return next; | |
137 | } | |
138 | ||
139 | /*++ | |
140 | ||
141 | Name: | |
1ac58644 | 142 | set_next_read_location() |
3e7ee490 HJ |
143 | |
144 | Description: | |
145 | Set the next read location for the specified ring buffer | |
146 | ||
147 | --*/ | |
148 | static inline void | |
1ac58644 | 149 | set_next_read_location(struct hv_ring_buffer_info *ring_info, |
fc8c72eb | 150 | u32 next_read_location) |
3e7ee490 | 151 | { |
fc8c72eb | 152 | ring_info->ring_buffer->read_index = next_read_location; |
3e7ee490 HJ |
153 | } |
154 | ||
155 | ||
156 | /*++ | |
157 | ||
158 | Name: | |
1ac58644 | 159 | get_ring_buffer() |
3e7ee490 HJ |
160 | |
161 | Description: | |
162 | Get the start of the ring buffer | |
163 | ||
164 | --*/ | |
8282c400 | 165 | static inline void * |
1ac58644 | 166 | get_ring_buffer(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 167 | { |
fc8c72eb | 168 | return (void *)ring_info->ring_buffer->buffer; |
3e7ee490 HJ |
169 | } |
170 | ||
171 | ||
172 | /*++ | |
173 | ||
174 | Name: | |
1ac58644 | 175 | get_ring_buffersize() |
3e7ee490 HJ |
176 | |
177 | Description: | |
178 | Get the size of the ring buffer | |
179 | ||
180 | --*/ | |
4d643114 | 181 | static inline u32 |
1ac58644 | 182 | get_ring_buffersize(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 183 | { |
fc8c72eb | 184 | return ring_info->ring_datasize; |
3e7ee490 HJ |
185 | } |
186 | ||
187 | /*++ | |
188 | ||
189 | Name: | |
1ac58644 | 190 | get_ring_bufferindices() |
3e7ee490 HJ |
191 | |
192 | Description: | |
59471438 | 193 | Get the read and write indices as u64 of the specified ring buffer |
3e7ee490 HJ |
194 | |
195 | --*/ | |
59471438 | 196 | static inline u64 |
1ac58644 | 197 | get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 198 | { |
fc8c72eb | 199 | return (u64)ring_info->ring_buffer->write_index << 32; |
3e7ee490 HJ |
200 | } |
201 | ||
202 | ||
203 | /*++ | |
204 | ||
205 | Name: | |
1ac58644 | 206 | dump_ring_info() |
3e7ee490 HJ |
207 | |
208 | Description: | |
209 | Dump out to console the ring buffer info | |
210 | ||
211 | --*/ | |
1ac58644 | 212 | void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix) |
3e7ee490 | 213 | { |
fc8c72eb HZ |
214 | u32 bytes_avail_towrite; |
215 | u32 bytes_avail_toread; | |
3e7ee490 | 216 | |
1ac58644 | 217 | get_ringbuffer_availbytes(ring_info, |
fc8c72eb HZ |
218 | &bytes_avail_toread, |
219 | &bytes_avail_towrite); | |
3e7ee490 | 220 | |
4408f531 B |
221 | DPRINT(VMBUS, |
222 | DEBUG_RING_LVL, | |
223 | "%s <<ringinfo %p buffer %p avail write %u " | |
224 | "avail read %u read idx %u write idx %u>>", | |
fc8c72eb HZ |
225 | prefix, |
226 | ring_info, | |
227 | ring_info->ring_buffer->buffer, | |
228 | bytes_avail_towrite, | |
229 | bytes_avail_toread, | |
230 | ring_info->ring_buffer->read_index, | |
231 | ring_info->ring_buffer->write_index); | |
3e7ee490 HJ |
232 | } |
233 | ||
454f18a9 BP |
234 | |
235 | /* Internal routines */ | |
236 | ||
4d643114 | 237 | static u32 |
1ac58644 | 238 | copyto_ringbuffer( |
fc8c72eb HZ |
239 | struct hv_ring_buffer_info *ring_info, |
240 | u32 start_write_offset, | |
241 | void *src, | |
242 | u32 srclen); | |
3e7ee490 | 243 | |
4d643114 | 244 | static u32 |
1ac58644 | 245 | copyfrom_ringbuffer( |
fc8c72eb HZ |
246 | struct hv_ring_buffer_info *ring_info, |
247 | void *dest, | |
248 | u32 destlen, | |
249 | u32 start_read_offset); | |
3e7ee490 HJ |
250 | |
251 | ||
252 | ||
253 | /*++ | |
254 | ||
255 | Name: | |
1ac58644 | 256 | ringbuffer_get_debuginfo() |
3e7ee490 HJ |
257 | |
258 | Description: | |
259 | Get various debug metrics for the specified ring buffer | |
260 | ||
261 | --*/ | |
1ac58644 | 262 | void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, |
80682b7a | 263 | struct hv_ring_buffer_debug_info *debug_info) |
3e7ee490 | 264 | { |
fc8c72eb HZ |
265 | u32 bytes_avail_towrite; |
266 | u32 bytes_avail_toread; | |
3e7ee490 | 267 | |
fc8c72eb | 268 | if (ring_info->ring_buffer) { |
1ac58644 | 269 | get_ringbuffer_availbytes(ring_info, |
fc8c72eb HZ |
270 | &bytes_avail_toread, |
271 | &bytes_avail_towrite); | |
3e7ee490 | 272 | |
fc8c72eb HZ |
273 | debug_info->bytes_avail_toread = bytes_avail_toread; |
274 | debug_info->bytes_avail_towrite = bytes_avail_towrite; | |
82f8bd40 | 275 | debug_info->current_read_index = |
fc8c72eb | 276 | ring_info->ring_buffer->read_index; |
82f8bd40 | 277 | debug_info->current_write_index = |
fc8c72eb | 278 | ring_info->ring_buffer->write_index; |
82f8bd40 | 279 | debug_info->current_interrupt_mask = |
fc8c72eb | 280 | ring_info->ring_buffer->interrupt_mask; |
3e7ee490 HJ |
281 | } |
282 | } | |
283 | ||
284 | ||
285 | /*++ | |
286 | ||
287 | Name: | |
1ac58644 | 288 | get_ringbuffer_interrupt_mask() |
3e7ee490 HJ |
289 | |
290 | Description: | |
291 | Get the interrupt mask for the specified ring buffer | |
292 | ||
293 | --*/ | |
1ac58644 | 294 | u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi) |
3e7ee490 | 295 | { |
82f8bd40 | 296 | return rbi->ring_buffer->interrupt_mask; |
3e7ee490 HJ |
297 | } |
298 | ||
299 | /*++ | |
300 | ||
301 | Name: | |
1ac58644 | 302 | ringbuffer_init() |
3e7ee490 HJ |
303 | |
304 | Description: | |
305 | Initialize the ring buffer | |
306 | ||
307 | --*/ | |
1ac58644 | 308 | int ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
fc8c72eb | 309 | void *buffer, u32 buflen) |
3e7ee490 | 310 | { |
4a1b3acc | 311 | if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) |
3324fb40 | 312 | return -EINVAL; |
3e7ee490 | 313 | |
fc8c72eb | 314 | memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); |
3e7ee490 | 315 | |
fc8c72eb HZ |
316 | ring_info->ring_buffer = (struct hv_ring_buffer *)buffer; |
317 | ring_info->ring_buffer->read_index = | |
318 | ring_info->ring_buffer->write_index = 0; | |
3e7ee490 | 319 | |
fc8c72eb HZ |
320 | ring_info->ring_size = buflen; |
321 | ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); | |
3e7ee490 | 322 | |
fc8c72eb | 323 | spin_lock_init(&ring_info->ring_lock); |
3e7ee490 HJ |
324 | |
325 | return 0; | |
326 | } | |
327 | ||
328 | /*++ | |
329 | ||
330 | Name: | |
1ac58644 | 331 | ringbuffer_cleanup() |
3e7ee490 HJ |
332 | |
333 | Description: | |
334 | Cleanup the ring buffer | |
335 | ||
336 | --*/ | |
1ac58644 | 337 | void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 338 | { |
3e7ee490 HJ |
339 | } |
340 | ||
341 | /*++ | |
342 | ||
343 | Name: | |
1ac58644 | 344 | ringbuffer_write() |
3e7ee490 HJ |
345 | |
346 | Description: | |
347 | Write to the ring buffer | |
348 | ||
349 | --*/ | |
1ac58644 | 350 | int ringbuffer_write(struct hv_ring_buffer_info *outring_info, |
3523a805 | 351 | struct scatterlist *sglist, u32 sgcount) |
3e7ee490 | 352 | { |
4408f531 | 353 | int i = 0; |
fc8c72eb HZ |
354 | u32 bytes_avail_towrite; |
355 | u32 bytes_avail_toread; | |
356 | u32 totalbytes_towrite = 0; | |
3e7ee490 | 357 | |
b219b3f7 | 358 | struct scatterlist *sg; |
fc8c72eb HZ |
359 | volatile u32 next_write_location; |
360 | u64 prev_indices = 0; | |
a98f96ee | 361 | unsigned long flags; |
3e7ee490 | 362 | |
b219b3f7 | 363 | for_each_sg(sglist, sg, sgcount, i) |
3e7ee490 | 364 | { |
fc8c72eb | 365 | totalbytes_towrite += sg->length; |
3e7ee490 HJ |
366 | } |
367 | ||
fc8c72eb | 368 | totalbytes_towrite += sizeof(u64); |
3e7ee490 | 369 | |
fc8c72eb | 370 | spin_lock_irqsave(&outring_info->ring_lock, flags); |
3e7ee490 | 371 | |
1ac58644 | 372 | get_ringbuffer_availbytes(outring_info, |
fc8c72eb HZ |
373 | &bytes_avail_toread, |
374 | &bytes_avail_towrite); | |
3e7ee490 | 375 | |
fc8c72eb | 376 | /* Dumpring_info(Outring_info, "BEFORE "); */ |
3e7ee490 | 377 | |
4408f531 B |
378 | /* If there is only room for the packet, assume it is full. */ |
379 | /* Otherwise, the next time around, we think the ring buffer */ | |
454f18a9 | 380 | /* is empty since the read index == write index */ |
fc8c72eb | 381 | if (bytes_avail_towrite <= totalbytes_towrite) { |
fc8c72eb | 382 | spin_unlock_irqrestore(&outring_info->ring_lock, flags); |
3e7ee490 HJ |
383 | return -1; |
384 | } | |
385 | ||
454f18a9 | 386 | /* Write to the ring buffer */ |
1ac58644 | 387 | next_write_location = get_next_write_location(outring_info); |
3e7ee490 | 388 | |
b219b3f7 | 389 | for_each_sg(sglist, sg, sgcount, i) |
3e7ee490 | 390 | { |
1ac58644 | 391 | next_write_location = copyto_ringbuffer(outring_info, |
fc8c72eb | 392 | next_write_location, |
b219b3f7 NP |
393 | sg_virt(sg), |
394 | sg->length); | |
3e7ee490 HJ |
395 | } |
396 | ||
454f18a9 | 397 | /* Set previous packet start */ |
1ac58644 | 398 | prev_indices = get_ring_bufferindices(outring_info); |
3e7ee490 | 399 | |
1ac58644 | 400 | next_write_location = copyto_ringbuffer(outring_info, |
fc8c72eb HZ |
401 | next_write_location, |
402 | &prev_indices, | |
b219b3f7 | 403 | sizeof(u64)); |
3e7ee490 | 404 | |
454f18a9 | 405 | /* Make sure we flush all writes before updating the writeIndex */ |
28b6ca9c | 406 | mb(); |
3e7ee490 | 407 | |
454f18a9 | 408 | /* Now, update the write location */ |
1ac58644 | 409 | set_next_write_location(outring_info, next_write_location); |
3e7ee490 | 410 | |
fc8c72eb | 411 | /* Dumpring_info(Outring_info, "AFTER "); */ |
3e7ee490 | 412 | |
fc8c72eb | 413 | spin_unlock_irqrestore(&outring_info->ring_lock, flags); |
3e7ee490 HJ |
414 | return 0; |
415 | } | |
416 | ||
417 | ||
418 | /*++ | |
419 | ||
420 | Name: | |
1ac58644 | 421 | ringbuffer_peek() |
3e7ee490 HJ |
422 | |
423 | Description: | |
424 | Read without advancing the read index | |
425 | ||
426 | --*/ | |
1ac58644 | 427 | int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info, |
fc8c72eb | 428 | void *Buffer, u32 buflen) |
3e7ee490 | 429 | { |
fc8c72eb HZ |
430 | u32 bytes_avail_towrite; |
431 | u32 bytes_avail_toread; | |
432 | u32 next_read_location = 0; | |
a98f96ee | 433 | unsigned long flags; |
3e7ee490 | 434 | |
fc8c72eb | 435 | spin_lock_irqsave(&Inring_info->ring_lock, flags); |
3e7ee490 | 436 | |
1ac58644 | 437 | get_ringbuffer_availbytes(Inring_info, |
fc8c72eb HZ |
438 | &bytes_avail_toread, |
439 | &bytes_avail_towrite); | |
3e7ee490 | 440 | |
454f18a9 | 441 | /* Make sure there is something to read */ |
fc8c72eb | 442 | if (bytes_avail_toread < buflen) { |
4408f531 B |
443 | /* DPRINT_DBG(VMBUS, |
444 | "got callback but not enough to read " | |
445 | "<avail to read %d read size %d>!!", | |
fc8c72eb | 446 | bytes_avail_toread, |
4408f531 | 447 | BufferLen); */ |
3e7ee490 | 448 | |
fc8c72eb | 449 | spin_unlock_irqrestore(&Inring_info->ring_lock, flags); |
3e7ee490 HJ |
450 | |
451 | return -1; | |
452 | } | |
453 | ||
454f18a9 | 454 | /* Convert to byte offset */ |
1ac58644 | 455 | next_read_location = get_next_read_location(Inring_info); |
3e7ee490 | 456 | |
1ac58644 | 457 | next_read_location = copyfrom_ringbuffer(Inring_info, |
4408f531 | 458 | Buffer, |
fc8c72eb HZ |
459 | buflen, |
460 | next_read_location); | |
3e7ee490 | 461 | |
fc8c72eb | 462 | spin_unlock_irqrestore(&Inring_info->ring_lock, flags); |
3e7ee490 HJ |
463 | |
464 | return 0; | |
465 | } | |
466 | ||
467 | ||
468 | /*++ | |
469 | ||
470 | Name: | |
1ac58644 | 471 | ringbuffer_read() |
3e7ee490 HJ |
472 | |
473 | Description: | |
474 | Read and advance the read index | |
475 | ||
476 | --*/ | |
1ac58644 | 477 | int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, |
fc8c72eb | 478 | u32 buflen, u32 offset) |
3e7ee490 | 479 | { |
fc8c72eb HZ |
480 | u32 bytes_avail_towrite; |
481 | u32 bytes_avail_toread; | |
482 | u32 next_read_location = 0; | |
483 | u64 prev_indices = 0; | |
a98f96ee | 484 | unsigned long flags; |
3e7ee490 | 485 | |
fc8c72eb | 486 | if (buflen <= 0) |
a16e1485 | 487 | return -EINVAL; |
3e7ee490 | 488 | |
fc8c72eb | 489 | spin_lock_irqsave(&inring_info->ring_lock, flags); |
3e7ee490 | 490 | |
1ac58644 | 491 | get_ringbuffer_availbytes(inring_info, |
fc8c72eb HZ |
492 | &bytes_avail_toread, |
493 | &bytes_avail_towrite); | |
3e7ee490 | 494 | |
fc8c72eb | 495 | /* Dumpring_info(Inring_info, "BEFORE "); */ |
3e7ee490 | 496 | |
454f18a9 | 497 | /* Make sure there is something to read */ |
fc8c72eb | 498 | if (bytes_avail_toread < buflen) { |
fc8c72eb | 499 | spin_unlock_irqrestore(&inring_info->ring_lock, flags); |
3e7ee490 HJ |
500 | |
501 | return -1; | |
502 | } | |
503 | ||
1ac58644 HZ |
504 | next_read_location = |
505 | get_next_readlocation_withoffset(inring_info, offset); | |
3e7ee490 | 506 | |
1ac58644 | 507 | next_read_location = copyfrom_ringbuffer(inring_info, |
fc8c72eb HZ |
508 | buffer, |
509 | buflen, | |
510 | next_read_location); | |
3e7ee490 | 511 | |
1ac58644 | 512 | next_read_location = copyfrom_ringbuffer(inring_info, |
fc8c72eb | 513 | &prev_indices, |
4408f531 | 514 | sizeof(u64), |
fc8c72eb | 515 | next_read_location); |
3e7ee490 | 516 | |
454f18a9 | 517 | /* Make sure all reads are done before we update the read index since */ |
4408f531 B |
518 | /* the writer may start writing to the read area once the read index */ |
519 | /*is updated */ | |
28b6ca9c | 520 | mb(); |
3e7ee490 | 521 | |
454f18a9 | 522 | /* Update the read index */ |
1ac58644 | 523 | set_next_read_location(inring_info, next_read_location); |
3e7ee490 | 524 | |
fc8c72eb | 525 | /* Dumpring_info(Inring_info, "AFTER "); */ |
3e7ee490 | 526 | |
fc8c72eb | 527 | spin_unlock_irqrestore(&inring_info->ring_lock, flags); |
3e7ee490 HJ |
528 | |
529 | return 0; | |
530 | } | |
531 | ||
532 | ||
533 | /*++ | |
534 | ||
535 | Name: | |
1ac58644 | 536 | copyto_ringbuffer() |
3e7ee490 HJ |
537 | |
538 | Description: | |
539 | Helper routine to copy from source to ring buffer. | |
540 | Assume there is enough room. Handles wrap-around in dest case only!! | |
541 | ||
542 | --*/ | |
bd1de709 | 543 | static u32 |
1ac58644 | 544 | copyto_ringbuffer( |
fc8c72eb HZ |
545 | struct hv_ring_buffer_info *ring_info, |
546 | u32 start_write_offset, | |
547 | void *src, | |
548 | u32 srclen) | |
3e7ee490 | 549 | { |
1ac58644 HZ |
550 | void *ring_buffer = get_ring_buffer(ring_info); |
551 | u32 ring_buffer_size = get_ring_buffersize(ring_info); | |
fc8c72eb | 552 | u32 frag_len; |
3e7ee490 | 553 | |
4408f531 | 554 | /* wrap-around detected! */ |
fc8c72eb | 555 | if (srclen > ring_buffer_size - start_write_offset) { |
fc8c72eb HZ |
556 | frag_len = ring_buffer_size - start_write_offset; |
557 | memcpy(ring_buffer + start_write_offset, src, frag_len); | |
558 | memcpy(ring_buffer, src + frag_len, srclen - frag_len); | |
4408f531 | 559 | } else |
fc8c72eb | 560 | memcpy(ring_buffer + start_write_offset, src, srclen); |
3e7ee490 | 561 | |
fc8c72eb HZ |
562 | start_write_offset += srclen; |
563 | start_write_offset %= ring_buffer_size; | |
3e7ee490 | 564 | |
fc8c72eb | 565 | return start_write_offset; |
3e7ee490 HJ |
566 | } |
567 | ||
568 | ||
569 | /*++ | |
570 | ||
571 | Name: | |
1ac58644 | 572 | copyfrom_ringbuffer() |
3e7ee490 HJ |
573 | |
574 | Description: | |
575 | Helper routine to copy to source from ring buffer. | |
576 | Assume there is enough room. Handles wrap-around in src case only!! | |
577 | ||
578 | --*/ | |
bd1de709 | 579 | static u32 |
1ac58644 | 580 | copyfrom_ringbuffer( |
fc8c72eb HZ |
581 | struct hv_ring_buffer_info *ring_info, |
582 | void *dest, | |
583 | u32 destlen, | |
584 | u32 start_read_offset) | |
3e7ee490 | 585 | { |
1ac58644 HZ |
586 | void *ring_buffer = get_ring_buffer(ring_info); |
587 | u32 ring_buffer_size = get_ring_buffersize(ring_info); | |
3e7ee490 | 588 | |
fc8c72eb | 589 | u32 frag_len; |
3e7ee490 | 590 | |
4408f531 | 591 | /* wrap-around detected at the src */ |
fc8c72eb | 592 | if (destlen > ring_buffer_size - start_read_offset) { |
fc8c72eb | 593 | frag_len = ring_buffer_size - start_read_offset; |
3e7ee490 | 594 | |
fc8c72eb HZ |
595 | memcpy(dest, ring_buffer + start_read_offset, frag_len); |
596 | memcpy(dest + frag_len, ring_buffer, destlen - frag_len); | |
4408f531 B |
597 | } else |
598 | ||
fc8c72eb | 599 | memcpy(dest, ring_buffer + start_read_offset, destlen); |
4408f531 | 600 | |
3e7ee490 | 601 | |
fc8c72eb HZ |
602 | start_read_offset += destlen; |
603 | start_read_offset %= ring_buffer_size; | |
3e7ee490 | 604 | |
fc8c72eb | 605 | return start_read_offset; |
3e7ee490 HJ |
606 | } |
607 | ||
608 | ||
454f18a9 | 609 | /* eof */ |