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