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> | |
4983b39a | 26 | #include "osd.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: | |
41 | GetRingBufferAvailBytes() | |
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 | |
8a0e1c55 | 49 | GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, 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: | |
64 | GetNextWriteLocation() | |
65 | ||
66 | Description: | |
67 | Get the next write location for the specified ring buffer | |
68 | ||
69 | --*/ | |
4d643114 | 70 | static inline u32 |
fc8c72eb | 71 | GetNextWriteLocation(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: | |
83 | SetNextWriteLocation() | |
84 | ||
85 | Description: | |
86 | Set the next write location for the specified ring buffer | |
87 | ||
88 | --*/ | |
89 | static inline void | |
fc8c72eb HZ |
90 | SetNextWriteLocation(struct hv_ring_buffer_info *ring_info, |
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: | |
99 | GetNextReadLocation() | |
100 | ||
101 | Description: | |
102 | Get the next read location for the specified ring buffer | |
103 | ||
104 | --*/ | |
4d643114 | 105 | static inline u32 |
fc8c72eb | 106 | GetNextReadLocation(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: | |
118 | GetNextReadLocationWithOffset() | |
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 |
fc8c72eb | 126 | GetNextReadLocationWithOffset(struct hv_ring_buffer_info *ring_info, u32 offset) |
3e7ee490 | 127 | { |
fc8c72eb | 128 | u32 next = ring_info->ring_buffer->read_index; |
3e7ee490 | 129 | |
fc8c72eb HZ |
130 | /* ASSERT(next < ring_info->RingDataSize); */ |
131 | next += offset; | |
132 | next %= ring_info->ring_datasize; | |
3e7ee490 HJ |
133 | |
134 | return next; | |
135 | } | |
136 | ||
137 | /*++ | |
138 | ||
139 | Name: | |
140 | SetNextReadLocation() | |
141 | ||
142 | Description: | |
143 | Set the next read location for the specified ring buffer | |
144 | ||
145 | --*/ | |
146 | static inline void | |
fc8c72eb HZ |
147 | SetNextReadLocation(struct hv_ring_buffer_info *ring_info, |
148 | u32 next_read_location) | |
3e7ee490 | 149 | { |
fc8c72eb | 150 | ring_info->ring_buffer->read_index = next_read_location; |
3e7ee490 HJ |
151 | } |
152 | ||
153 | ||
154 | /*++ | |
155 | ||
156 | Name: | |
157 | GetRingBuffer() | |
158 | ||
159 | Description: | |
160 | Get the start of the ring buffer | |
161 | ||
162 | --*/ | |
8282c400 | 163 | static inline void * |
fc8c72eb | 164 | GetRingBuffer(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 165 | { |
fc8c72eb | 166 | return (void *)ring_info->ring_buffer->buffer; |
3e7ee490 HJ |
167 | } |
168 | ||
169 | ||
170 | /*++ | |
171 | ||
172 | Name: | |
173 | GetRingBufferSize() | |
174 | ||
175 | Description: | |
176 | Get the size of the ring buffer | |
177 | ||
178 | --*/ | |
4d643114 | 179 | static inline u32 |
fc8c72eb | 180 | GetRingBufferSize(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 181 | { |
fc8c72eb | 182 | return ring_info->ring_datasize; |
3e7ee490 HJ |
183 | } |
184 | ||
185 | /*++ | |
186 | ||
187 | Name: | |
188 | GetRingBufferIndices() | |
189 | ||
190 | Description: | |
59471438 | 191 | Get the read and write indices as u64 of the specified ring buffer |
3e7ee490 HJ |
192 | |
193 | --*/ | |
59471438 | 194 | static inline u64 |
fc8c72eb | 195 | GetRingBufferIndices(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 196 | { |
fc8c72eb | 197 | return (u64)ring_info->ring_buffer->write_index << 32; |
3e7ee490 HJ |
198 | } |
199 | ||
200 | ||
201 | /*++ | |
202 | ||
203 | Name: | |
fc8c72eb | 204 | Dumpring_info() |
3e7ee490 HJ |
205 | |
206 | Description: | |
207 | Dump out to console the ring buffer info | |
208 | ||
209 | --*/ | |
fc8c72eb | 210 | void Dumpring_info(struct hv_ring_buffer_info *ring_info, char *prefix) |
3e7ee490 | 211 | { |
fc8c72eb HZ |
212 | u32 bytes_avail_towrite; |
213 | u32 bytes_avail_toread; | |
3e7ee490 | 214 | |
fc8c72eb HZ |
215 | GetRingBufferAvailBytes(ring_info, |
216 | &bytes_avail_toread, | |
217 | &bytes_avail_towrite); | |
3e7ee490 | 218 | |
4408f531 B |
219 | DPRINT(VMBUS, |
220 | DEBUG_RING_LVL, | |
221 | "%s <<ringinfo %p buffer %p avail write %u " | |
222 | "avail read %u read idx %u write idx %u>>", | |
fc8c72eb HZ |
223 | prefix, |
224 | ring_info, | |
225 | ring_info->ring_buffer->buffer, | |
226 | bytes_avail_towrite, | |
227 | bytes_avail_toread, | |
228 | ring_info->ring_buffer->read_index, | |
229 | ring_info->ring_buffer->write_index); | |
3e7ee490 HJ |
230 | } |
231 | ||
454f18a9 BP |
232 | |
233 | /* Internal routines */ | |
234 | ||
4d643114 | 235 | static u32 |
3e7ee490 | 236 | CopyToRingBuffer( |
fc8c72eb HZ |
237 | struct hv_ring_buffer_info *ring_info, |
238 | u32 start_write_offset, | |
239 | void *src, | |
240 | u32 srclen); | |
3e7ee490 | 241 | |
4d643114 | 242 | static u32 |
3e7ee490 | 243 | CopyFromRingBuffer( |
fc8c72eb HZ |
244 | struct hv_ring_buffer_info *ring_info, |
245 | void *dest, | |
246 | u32 destlen, | |
247 | u32 start_read_offset); | |
3e7ee490 HJ |
248 | |
249 | ||
250 | ||
251 | /*++ | |
252 | ||
253 | Name: | |
254 | RingBufferGetDebugInfo() | |
255 | ||
256 | Description: | |
257 | Get various debug metrics for the specified ring buffer | |
258 | ||
259 | --*/ | |
fc8c72eb | 260 | void RingBufferGetDebugInfo(struct hv_ring_buffer_info *ring_info, |
80682b7a | 261 | struct hv_ring_buffer_debug_info *debug_info) |
3e7ee490 | 262 | { |
fc8c72eb HZ |
263 | u32 bytes_avail_towrite; |
264 | u32 bytes_avail_toread; | |
3e7ee490 | 265 | |
fc8c72eb HZ |
266 | if (ring_info->ring_buffer) { |
267 | GetRingBufferAvailBytes(ring_info, | |
268 | &bytes_avail_toread, | |
269 | &bytes_avail_towrite); | |
3e7ee490 | 270 | |
fc8c72eb HZ |
271 | debug_info->bytes_avail_toread = bytes_avail_toread; |
272 | debug_info->bytes_avail_towrite = bytes_avail_towrite; | |
82f8bd40 | 273 | debug_info->current_read_index = |
fc8c72eb | 274 | ring_info->ring_buffer->read_index; |
82f8bd40 | 275 | debug_info->current_write_index = |
fc8c72eb | 276 | ring_info->ring_buffer->write_index; |
82f8bd40 | 277 | debug_info->current_interrupt_mask = |
fc8c72eb | 278 | ring_info->ring_buffer->interrupt_mask; |
3e7ee490 HJ |
279 | } |
280 | } | |
281 | ||
282 | ||
283 | /*++ | |
284 | ||
285 | Name: | |
286 | GetRingBufferInterruptMask() | |
287 | ||
288 | Description: | |
289 | Get the interrupt mask for the specified ring buffer | |
290 | ||
291 | --*/ | |
8a0e1c55 | 292 | u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi) |
3e7ee490 | 293 | { |
82f8bd40 | 294 | return rbi->ring_buffer->interrupt_mask; |
3e7ee490 HJ |
295 | } |
296 | ||
297 | /*++ | |
298 | ||
299 | Name: | |
300 | RingBufferInit() | |
301 | ||
302 | Description: | |
303 | Initialize the ring buffer | |
304 | ||
305 | --*/ | |
fc8c72eb HZ |
306 | int RingBufferInit(struct hv_ring_buffer_info *ring_info, |
307 | void *buffer, u32 buflen) | |
3e7ee490 | 308 | { |
4a1b3acc | 309 | if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) |
3324fb40 | 310 | return -EINVAL; |
3e7ee490 | 311 | |
fc8c72eb | 312 | memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); |
3e7ee490 | 313 | |
fc8c72eb HZ |
314 | ring_info->ring_buffer = (struct hv_ring_buffer *)buffer; |
315 | ring_info->ring_buffer->read_index = | |
316 | ring_info->ring_buffer->write_index = 0; | |
3e7ee490 | 317 | |
fc8c72eb HZ |
318 | ring_info->ring_size = buflen; |
319 | ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); | |
3e7ee490 | 320 | |
fc8c72eb | 321 | spin_lock_init(&ring_info->ring_lock); |
3e7ee490 HJ |
322 | |
323 | return 0; | |
324 | } | |
325 | ||
326 | /*++ | |
327 | ||
328 | Name: | |
329 | RingBufferCleanup() | |
330 | ||
331 | Description: | |
332 | Cleanup the ring buffer | |
333 | ||
334 | --*/ | |
fc8c72eb | 335 | void RingBufferCleanup(struct hv_ring_buffer_info *ring_info) |
3e7ee490 | 336 | { |
3e7ee490 HJ |
337 | } |
338 | ||
339 | /*++ | |
340 | ||
341 | Name: | |
342 | RingBufferWrite() | |
343 | ||
344 | Description: | |
345 | Write to the ring buffer | |
346 | ||
347 | --*/ | |
fc8c72eb | 348 | int RingBufferWrite(struct hv_ring_buffer_info *outring_info, |
3523a805 | 349 | struct scatterlist *sglist, u32 sgcount) |
3e7ee490 | 350 | { |
4408f531 | 351 | int i = 0; |
fc8c72eb HZ |
352 | u32 bytes_avail_towrite; |
353 | u32 bytes_avail_toread; | |
354 | u32 totalbytes_towrite = 0; | |
3e7ee490 | 355 | |
b219b3f7 | 356 | struct scatterlist *sg; |
fc8c72eb HZ |
357 | volatile u32 next_write_location; |
358 | u64 prev_indices = 0; | |
a98f96ee | 359 | unsigned long flags; |
3e7ee490 | 360 | |
b219b3f7 | 361 | for_each_sg(sglist, sg, sgcount, i) |
3e7ee490 | 362 | { |
fc8c72eb | 363 | totalbytes_towrite += sg->length; |
3e7ee490 HJ |
364 | } |
365 | ||
fc8c72eb | 366 | totalbytes_towrite += sizeof(u64); |
3e7ee490 | 367 | |
fc8c72eb | 368 | spin_lock_irqsave(&outring_info->ring_lock, flags); |
3e7ee490 | 369 | |
fc8c72eb HZ |
370 | GetRingBufferAvailBytes(outring_info, |
371 | &bytes_avail_toread, | |
372 | &bytes_avail_towrite); | |
3e7ee490 | 373 | |
fc8c72eb | 374 | DPRINT_DBG(VMBUS, "Writing %u bytes...", totalbytes_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) { |
4408f531 B |
382 | DPRINT_DBG(VMBUS, |
383 | "No more space left on outbound ring buffer " | |
384 | "(needed %u, avail %u)", | |
fc8c72eb HZ |
385 | totalbytes_towrite, |
386 | bytes_avail_towrite); | |
3e7ee490 | 387 | |
fc8c72eb | 388 | spin_unlock_irqrestore(&outring_info->ring_lock, flags); |
3e7ee490 HJ |
389 | return -1; |
390 | } | |
391 | ||
454f18a9 | 392 | /* Write to the ring buffer */ |
fc8c72eb | 393 | next_write_location = GetNextWriteLocation(outring_info); |
3e7ee490 | 394 | |
b219b3f7 | 395 | for_each_sg(sglist, sg, sgcount, i) |
3e7ee490 | 396 | { |
fc8c72eb HZ |
397 | next_write_location = CopyToRingBuffer(outring_info, |
398 | next_write_location, | |
b219b3f7 NP |
399 | sg_virt(sg), |
400 | sg->length); | |
3e7ee490 HJ |
401 | } |
402 | ||
454f18a9 | 403 | /* Set previous packet start */ |
fc8c72eb | 404 | prev_indices = GetRingBufferIndices(outring_info); |
3e7ee490 | 405 | |
fc8c72eb HZ |
406 | next_write_location = CopyToRingBuffer(outring_info, |
407 | next_write_location, | |
408 | &prev_indices, | |
b219b3f7 | 409 | sizeof(u64)); |
3e7ee490 | 410 | |
454f18a9 | 411 | /* Make sure we flush all writes before updating the writeIndex */ |
28b6ca9c | 412 | mb(); |
3e7ee490 | 413 | |
454f18a9 | 414 | /* Now, update the write location */ |
fc8c72eb | 415 | SetNextWriteLocation(outring_info, next_write_location); |
3e7ee490 | 416 | |
fc8c72eb | 417 | /* Dumpring_info(Outring_info, "AFTER "); */ |
3e7ee490 | 418 | |
fc8c72eb | 419 | spin_unlock_irqrestore(&outring_info->ring_lock, flags); |
3e7ee490 HJ |
420 | return 0; |
421 | } | |
422 | ||
423 | ||
424 | /*++ | |
425 | ||
426 | Name: | |
427 | RingBufferPeek() | |
428 | ||
429 | Description: | |
430 | Read without advancing the read index | |
431 | ||
432 | --*/ | |
fc8c72eb HZ |
433 | int RingBufferPeek(struct hv_ring_buffer_info *Inring_info, |
434 | void *Buffer, u32 buflen) | |
3e7ee490 | 435 | { |
fc8c72eb HZ |
436 | u32 bytes_avail_towrite; |
437 | u32 bytes_avail_toread; | |
438 | u32 next_read_location = 0; | |
a98f96ee | 439 | unsigned long flags; |
3e7ee490 | 440 | |
fc8c72eb | 441 | spin_lock_irqsave(&Inring_info->ring_lock, flags); |
3e7ee490 | 442 | |
fc8c72eb HZ |
443 | GetRingBufferAvailBytes(Inring_info, |
444 | &bytes_avail_toread, | |
445 | &bytes_avail_towrite); | |
3e7ee490 | 446 | |
454f18a9 | 447 | /* Make sure there is something to read */ |
fc8c72eb | 448 | if (bytes_avail_toread < buflen) { |
4408f531 B |
449 | /* DPRINT_DBG(VMBUS, |
450 | "got callback but not enough to read " | |
451 | "<avail to read %d read size %d>!!", | |
fc8c72eb | 452 | bytes_avail_toread, |
4408f531 | 453 | BufferLen); */ |
3e7ee490 | 454 | |
fc8c72eb | 455 | spin_unlock_irqrestore(&Inring_info->ring_lock, flags); |
3e7ee490 HJ |
456 | |
457 | return -1; | |
458 | } | |
459 | ||
454f18a9 | 460 | /* Convert to byte offset */ |
fc8c72eb | 461 | next_read_location = GetNextReadLocation(Inring_info); |
3e7ee490 | 462 | |
fc8c72eb | 463 | next_read_location = CopyFromRingBuffer(Inring_info, |
4408f531 | 464 | Buffer, |
fc8c72eb HZ |
465 | buflen, |
466 | next_read_location); | |
3e7ee490 | 467 | |
fc8c72eb | 468 | spin_unlock_irqrestore(&Inring_info->ring_lock, flags); |
3e7ee490 HJ |
469 | |
470 | return 0; | |
471 | } | |
472 | ||
473 | ||
474 | /*++ | |
475 | ||
476 | Name: | |
477 | RingBufferRead() | |
478 | ||
479 | Description: | |
480 | Read and advance the read index | |
481 | ||
482 | --*/ | |
fc8c72eb HZ |
483 | int RingBufferRead(struct hv_ring_buffer_info *inring_info, void *buffer, |
484 | u32 buflen, u32 offset) | |
3e7ee490 | 485 | { |
fc8c72eb HZ |
486 | u32 bytes_avail_towrite; |
487 | u32 bytes_avail_toread; | |
488 | u32 next_read_location = 0; | |
489 | u64 prev_indices = 0; | |
a98f96ee | 490 | unsigned long flags; |
3e7ee490 | 491 | |
fc8c72eb | 492 | if (buflen <= 0) |
a16e1485 | 493 | return -EINVAL; |
3e7ee490 | 494 | |
fc8c72eb | 495 | spin_lock_irqsave(&inring_info->ring_lock, flags); |
3e7ee490 | 496 | |
fc8c72eb HZ |
497 | GetRingBufferAvailBytes(inring_info, |
498 | &bytes_avail_toread, | |
499 | &bytes_avail_towrite); | |
3e7ee490 | 500 | |
fc8c72eb | 501 | DPRINT_DBG(VMBUS, "Reading %u bytes...", buflen); |
3e7ee490 | 502 | |
fc8c72eb | 503 | /* Dumpring_info(Inring_info, "BEFORE "); */ |
3e7ee490 | 504 | |
454f18a9 | 505 | /* Make sure there is something to read */ |
fc8c72eb | 506 | if (bytes_avail_toread < buflen) { |
4408f531 B |
507 | DPRINT_DBG(VMBUS, |
508 | "got callback but not enough to read " | |
509 | "<avail to read %d read size %d>!!", | |
fc8c72eb HZ |
510 | bytes_avail_toread, |
511 | buflen); | |
3e7ee490 | 512 | |
fc8c72eb | 513 | spin_unlock_irqrestore(&inring_info->ring_lock, flags); |
3e7ee490 HJ |
514 | |
515 | return -1; | |
516 | } | |
517 | ||
fc8c72eb | 518 | next_read_location = GetNextReadLocationWithOffset(inring_info, offset); |
3e7ee490 | 519 | |
fc8c72eb HZ |
520 | next_read_location = CopyFromRingBuffer(inring_info, |
521 | buffer, | |
522 | buflen, | |
523 | next_read_location); | |
3e7ee490 | 524 | |
fc8c72eb HZ |
525 | next_read_location = CopyFromRingBuffer(inring_info, |
526 | &prev_indices, | |
4408f531 | 527 | sizeof(u64), |
fc8c72eb | 528 | next_read_location); |
3e7ee490 | 529 | |
454f18a9 | 530 | /* Make sure all reads are done before we update the read index since */ |
4408f531 B |
531 | /* the writer may start writing to the read area once the read index */ |
532 | /*is updated */ | |
28b6ca9c | 533 | mb(); |
3e7ee490 | 534 | |
454f18a9 | 535 | /* Update the read index */ |
fc8c72eb | 536 | SetNextReadLocation(inring_info, next_read_location); |
3e7ee490 | 537 | |
fc8c72eb | 538 | /* Dumpring_info(Inring_info, "AFTER "); */ |
3e7ee490 | 539 | |
fc8c72eb | 540 | spin_unlock_irqrestore(&inring_info->ring_lock, flags); |
3e7ee490 HJ |
541 | |
542 | return 0; | |
543 | } | |
544 | ||
545 | ||
546 | /*++ | |
547 | ||
548 | Name: | |
549 | CopyToRingBuffer() | |
550 | ||
551 | Description: | |
552 | Helper routine to copy from source to ring buffer. | |
553 | Assume there is enough room. Handles wrap-around in dest case only!! | |
554 | ||
555 | --*/ | |
bd1de709 | 556 | static u32 |
3e7ee490 | 557 | CopyToRingBuffer( |
fc8c72eb HZ |
558 | struct hv_ring_buffer_info *ring_info, |
559 | u32 start_write_offset, | |
560 | void *src, | |
561 | u32 srclen) | |
3e7ee490 | 562 | { |
fc8c72eb HZ |
563 | void *ring_buffer = GetRingBuffer(ring_info); |
564 | u32 ring_buffer_size = GetRingBufferSize(ring_info); | |
565 | u32 frag_len; | |
3e7ee490 | 566 | |
4408f531 | 567 | /* wrap-around detected! */ |
fc8c72eb | 568 | if (srclen > ring_buffer_size - start_write_offset) { |
3e7ee490 HJ |
569 | DPRINT_DBG(VMBUS, "wrap-around detected!"); |
570 | ||
fc8c72eb HZ |
571 | frag_len = ring_buffer_size - start_write_offset; |
572 | memcpy(ring_buffer + start_write_offset, src, frag_len); | |
573 | memcpy(ring_buffer, src + frag_len, srclen - frag_len); | |
4408f531 | 574 | } else |
fc8c72eb | 575 | memcpy(ring_buffer + start_write_offset, src, srclen); |
3e7ee490 | 576 | |
fc8c72eb HZ |
577 | start_write_offset += srclen; |
578 | start_write_offset %= ring_buffer_size; | |
3e7ee490 | 579 | |
fc8c72eb | 580 | return start_write_offset; |
3e7ee490 HJ |
581 | } |
582 | ||
583 | ||
584 | /*++ | |
585 | ||
586 | Name: | |
587 | CopyFromRingBuffer() | |
588 | ||
589 | Description: | |
590 | Helper routine to copy to source from ring buffer. | |
591 | Assume there is enough room. Handles wrap-around in src case only!! | |
592 | ||
593 | --*/ | |
bd1de709 | 594 | static u32 |
3e7ee490 | 595 | CopyFromRingBuffer( |
fc8c72eb HZ |
596 | struct hv_ring_buffer_info *ring_info, |
597 | void *dest, | |
598 | u32 destlen, | |
599 | u32 start_read_offset) | |
3e7ee490 | 600 | { |
fc8c72eb HZ |
601 | void *ring_buffer = GetRingBuffer(ring_info); |
602 | u32 ring_buffer_size = GetRingBufferSize(ring_info); | |
3e7ee490 | 603 | |
fc8c72eb | 604 | u32 frag_len; |
3e7ee490 | 605 | |
4408f531 | 606 | /* wrap-around detected at the src */ |
fc8c72eb | 607 | if (destlen > ring_buffer_size - start_read_offset) { |
3e7ee490 HJ |
608 | DPRINT_DBG(VMBUS, "src wrap-around detected!"); |
609 | ||
fc8c72eb | 610 | frag_len = ring_buffer_size - start_read_offset; |
3e7ee490 | 611 | |
fc8c72eb HZ |
612 | memcpy(dest, ring_buffer + start_read_offset, frag_len); |
613 | memcpy(dest + frag_len, ring_buffer, destlen - frag_len); | |
4408f531 B |
614 | } else |
615 | ||
fc8c72eb | 616 | memcpy(dest, ring_buffer + start_read_offset, destlen); |
4408f531 | 617 | |
3e7ee490 | 618 | |
fc8c72eb HZ |
619 | start_read_offset += destlen; |
620 | start_read_offset %= ring_buffer_size; | |
3e7ee490 | 621 | |
fc8c72eb | 622 | return start_read_offset; |
3e7ee490 HJ |
623 | } |
624 | ||
625 | ||
454f18a9 | 626 | /* eof */ |