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