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 | --*/ | |
bd1de709 | 206 | static void |
3e7ee490 HJ |
207 | DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix) |
208 | { | |
4d643114 GKH |
209 | u32 bytesAvailToWrite; |
210 | u32 bytesAvailToRead; | |
3e7ee490 HJ |
211 | |
212 | GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
213 | ||
214 | DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>", | |
215 | Prefix, | |
216 | RingInfo, | |
217 | RingInfo->RingBuffer->Buffer, | |
218 | bytesAvailToWrite, | |
219 | bytesAvailToRead, | |
220 | RingInfo->RingBuffer->ReadIndex, | |
221 | RingInfo->RingBuffer->WriteIndex); | |
222 | } | |
223 | ||
454f18a9 BP |
224 | |
225 | /* Internal routines */ | |
226 | ||
4d643114 | 227 | static u32 |
3e7ee490 HJ |
228 | CopyToRingBuffer( |
229 | RING_BUFFER_INFO *RingInfo, | |
4d643114 | 230 | u32 StartWriteOffset, |
8282c400 | 231 | void * Src, |
4d643114 | 232 | u32 SrcLen); |
3e7ee490 | 233 | |
4d643114 | 234 | static u32 |
3e7ee490 HJ |
235 | CopyFromRingBuffer( |
236 | RING_BUFFER_INFO *RingInfo, | |
8282c400 | 237 | void * Dest, |
4d643114 GKH |
238 | u32 DestLen, |
239 | u32 StartReadOffset); | |
3e7ee490 HJ |
240 | |
241 | ||
242 | ||
243 | /*++ | |
244 | ||
245 | Name: | |
246 | RingBufferGetDebugInfo() | |
247 | ||
248 | Description: | |
249 | Get various debug metrics for the specified ring buffer | |
250 | ||
251 | --*/ | |
bd1de709 | 252 | static void |
3e7ee490 HJ |
253 | RingBufferGetDebugInfo( |
254 | RING_BUFFER_INFO *RingInfo, | |
255 | RING_BUFFER_DEBUG_INFO *DebugInfo | |
256 | ) | |
257 | { | |
4d643114 GKH |
258 | u32 bytesAvailToWrite; |
259 | u32 bytesAvailToRead; | |
3e7ee490 HJ |
260 | |
261 | if (RingInfo->RingBuffer) | |
262 | { | |
263 | GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
264 | ||
265 | DebugInfo->BytesAvailToRead = bytesAvailToRead; | |
266 | DebugInfo->BytesAvailToWrite = bytesAvailToWrite; | |
267 | DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; | |
268 | DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; | |
269 | ||
270 | DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; | |
271 | } | |
272 | } | |
273 | ||
274 | ||
275 | /*++ | |
276 | ||
277 | Name: | |
278 | GetRingBufferInterruptMask() | |
279 | ||
280 | Description: | |
281 | Get the interrupt mask for the specified ring buffer | |
282 | ||
283 | --*/ | |
bd1de709 | 284 | static u32 |
3e7ee490 HJ |
285 | GetRingBufferInterruptMask( |
286 | RING_BUFFER_INFO *rbi | |
287 | ) | |
288 | { | |
289 | return rbi->RingBuffer->InterruptMask; | |
290 | } | |
291 | ||
292 | /*++ | |
293 | ||
294 | Name: | |
295 | RingBufferInit() | |
296 | ||
297 | Description: | |
298 | Initialize the ring buffer | |
299 | ||
300 | --*/ | |
bd1de709 | 301 | static int |
3e7ee490 HJ |
302 | RingBufferInit( |
303 | RING_BUFFER_INFO *RingInfo, | |
e20f683b | 304 | void *Buffer, |
4d643114 | 305 | u32 BufferLen |
3e7ee490 HJ |
306 | ) |
307 | { | |
308 | ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE); | |
309 | ||
310 | memset(RingInfo, 0, sizeof(RING_BUFFER_INFO)); | |
311 | ||
312 | RingInfo->RingBuffer = (RING_BUFFER*)Buffer; | |
313 | RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0; | |
314 | ||
315 | RingInfo->RingSize = BufferLen; | |
316 | RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER); | |
317 | ||
a98f96ee | 318 | spin_lock_init(&RingInfo->ring_lock); |
3e7ee490 HJ |
319 | |
320 | return 0; | |
321 | } | |
322 | ||
323 | /*++ | |
324 | ||
325 | Name: | |
326 | RingBufferCleanup() | |
327 | ||
328 | Description: | |
329 | Cleanup the ring buffer | |
330 | ||
331 | --*/ | |
bd1de709 | 332 | static void |
3e7ee490 HJ |
333 | RingBufferCleanup( |
334 | RING_BUFFER_INFO* RingInfo | |
335 | ) | |
336 | { | |
3e7ee490 HJ |
337 | } |
338 | ||
339 | /*++ | |
340 | ||
341 | Name: | |
342 | RingBufferWrite() | |
343 | ||
344 | Description: | |
345 | Write to the ring buffer | |
346 | ||
347 | --*/ | |
bd1de709 | 348 | static int |
3e7ee490 HJ |
349 | RingBufferWrite( |
350 | RING_BUFFER_INFO* OutRingInfo, | |
351 | SG_BUFFER_LIST SgBuffers[], | |
4d643114 | 352 | u32 SgBufferCount |
3e7ee490 HJ |
353 | ) |
354 | { | |
355 | int i=0; | |
4d643114 GKH |
356 | u32 byteAvailToWrite; |
357 | u32 byteAvailToRead; | |
358 | u32 totalBytesToWrite=0; | |
3e7ee490 | 359 | |
4d643114 | 360 | volatile u32 nextWriteLocation; |
59471438 | 361 | u64 prevIndices=0; |
a98f96ee | 362 | unsigned long flags; |
3e7ee490 HJ |
363 | |
364 | DPRINT_ENTER(VMBUS); | |
365 | ||
366 | for (i=0; i < SgBufferCount; i++) | |
367 | { | |
368 | totalBytesToWrite += SgBuffers[i].Length; | |
369 | } | |
370 | ||
59471438 | 371 | totalBytesToWrite += sizeof(u64); |
3e7ee490 | 372 | |
a98f96ee | 373 | spin_lock_irqsave(&OutRingInfo->ring_lock, flags); |
3e7ee490 HJ |
374 | |
375 | GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); | |
376 | ||
377 | DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); | |
378 | ||
454f18a9 | 379 | /* DumpRingInfo(OutRingInfo, "BEFORE "); */ |
3e7ee490 | 380 | |
454f18a9 BP |
381 | /* If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer */ |
382 | /* is empty since the read index == write index */ | |
3e7ee490 HJ |
383 | if (byteAvailToWrite <= totalBytesToWrite) |
384 | { | |
385 | DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); | |
386 | ||
a98f96ee | 387 | spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); |
3e7ee490 HJ |
388 | |
389 | DPRINT_EXIT(VMBUS); | |
390 | ||
391 | return -1; | |
392 | } | |
393 | ||
454f18a9 | 394 | /* Write to the ring buffer */ |
3e7ee490 HJ |
395 | nextWriteLocation = GetNextWriteLocation(OutRingInfo); |
396 | ||
397 | for (i=0; i < SgBufferCount; i++) | |
398 | { | |
399 | nextWriteLocation = CopyToRingBuffer(OutRingInfo, | |
400 | nextWriteLocation, | |
401 | SgBuffers[i].Data, | |
402 | SgBuffers[i].Length); | |
403 | } | |
404 | ||
454f18a9 | 405 | /* Set previous packet start */ |
3e7ee490 HJ |
406 | prevIndices = GetRingBufferIndices(OutRingInfo); |
407 | ||
408 | nextWriteLocation = CopyToRingBuffer(OutRingInfo, | |
409 | nextWriteLocation, | |
410 | &prevIndices, | |
59471438 | 411 | sizeof(u64)); |
3e7ee490 | 412 | |
454f18a9 | 413 | /* Make sure we flush all writes before updating the writeIndex */ |
28b6ca9c | 414 | mb(); |
3e7ee490 | 415 | |
454f18a9 | 416 | /* Now, update the write location */ |
3e7ee490 HJ |
417 | SetNextWriteLocation(OutRingInfo, nextWriteLocation); |
418 | ||
454f18a9 | 419 | /* DumpRingInfo(OutRingInfo, "AFTER "); */ |
3e7ee490 | 420 | |
a98f96ee | 421 | spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); |
3e7ee490 HJ |
422 | |
423 | DPRINT_EXIT(VMBUS); | |
424 | ||
425 | return 0; | |
426 | } | |
427 | ||
428 | ||
429 | /*++ | |
430 | ||
431 | Name: | |
432 | RingBufferPeek() | |
433 | ||
434 | Description: | |
435 | Read without advancing the read index | |
436 | ||
437 | --*/ | |
bd1de709 | 438 | static int |
3e7ee490 HJ |
439 | RingBufferPeek( |
440 | RING_BUFFER_INFO* InRingInfo, | |
441 | void* Buffer, | |
4d643114 | 442 | u32 BufferLen |
3e7ee490 HJ |
443 | ) |
444 | { | |
4d643114 GKH |
445 | u32 bytesAvailToWrite; |
446 | u32 bytesAvailToRead; | |
447 | u32 nextReadLocation=0; | |
a98f96ee | 448 | unsigned long flags; |
3e7ee490 | 449 | |
a98f96ee | 450 | spin_lock_irqsave(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
451 | |
452 | GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
453 | ||
454f18a9 | 454 | /* Make sure there is something to read */ |
3e7ee490 HJ |
455 | if (bytesAvailToRead < BufferLen ) |
456 | { | |
454f18a9 | 457 | /* DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); */ |
3e7ee490 | 458 | |
a98f96ee | 459 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
460 | |
461 | return -1; | |
462 | } | |
463 | ||
454f18a9 | 464 | /* Convert to byte offset */ |
3e7ee490 HJ |
465 | nextReadLocation = GetNextReadLocation(InRingInfo); |
466 | ||
467 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
468 | Buffer, | |
469 | BufferLen, | |
470 | nextReadLocation); | |
471 | ||
a98f96ee | 472 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
473 | |
474 | return 0; | |
475 | } | |
476 | ||
477 | ||
478 | /*++ | |
479 | ||
480 | Name: | |
481 | RingBufferRead() | |
482 | ||
483 | Description: | |
484 | Read and advance the read index | |
485 | ||
486 | --*/ | |
bd1de709 | 487 | static int |
3e7ee490 HJ |
488 | RingBufferRead( |
489 | RING_BUFFER_INFO* InRingInfo, | |
8282c400 | 490 | void * Buffer, |
4d643114 GKH |
491 | u32 BufferLen, |
492 | u32 Offset | |
3e7ee490 HJ |
493 | ) |
494 | { | |
4d643114 GKH |
495 | u32 bytesAvailToWrite; |
496 | u32 bytesAvailToRead; | |
497 | u32 nextReadLocation=0; | |
59471438 | 498 | u64 prevIndices=0; |
a98f96ee | 499 | unsigned long flags; |
3e7ee490 HJ |
500 | |
501 | ASSERT(BufferLen > 0); | |
502 | ||
a98f96ee | 503 | spin_lock_irqsave(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
504 | |
505 | GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); | |
506 | ||
507 | DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); | |
508 | ||
454f18a9 | 509 | /* DumpRingInfo(InRingInfo, "BEFORE "); */ |
3e7ee490 | 510 | |
454f18a9 | 511 | /* Make sure there is something to read */ |
3e7ee490 HJ |
512 | if (bytesAvailToRead < BufferLen ) |
513 | { | |
514 | DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); | |
515 | ||
a98f96ee | 516 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
517 | |
518 | return -1; | |
519 | } | |
520 | ||
521 | nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); | |
522 | ||
523 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
524 | Buffer, | |
525 | BufferLen, | |
526 | nextReadLocation); | |
527 | ||
528 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
529 | &prevIndices, | |
59471438 | 530 | sizeof(u64), |
3e7ee490 HJ |
531 | nextReadLocation); |
532 | ||
454f18a9 BP |
533 | /* Make sure all reads are done before we update the read index since */ |
534 | /* the writer may start writing to the read area once the read index is updated */ | |
28b6ca9c | 535 | mb(); |
3e7ee490 | 536 | |
454f18a9 | 537 | /* Update the read index */ |
3e7ee490 HJ |
538 | SetNextReadLocation(InRingInfo, nextReadLocation); |
539 | ||
454f18a9 | 540 | /* DumpRingInfo(InRingInfo, "AFTER "); */ |
3e7ee490 | 541 | |
a98f96ee | 542 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
543 | |
544 | return 0; | |
545 | } | |
546 | ||
547 | ||
548 | /*++ | |
549 | ||
550 | Name: | |
551 | CopyToRingBuffer() | |
552 | ||
553 | Description: | |
554 | Helper routine to copy from source to ring buffer. | |
555 | Assume there is enough room. Handles wrap-around in dest case only!! | |
556 | ||
557 | --*/ | |
bd1de709 | 558 | static u32 |
3e7ee490 HJ |
559 | CopyToRingBuffer( |
560 | RING_BUFFER_INFO *RingInfo, | |
4d643114 | 561 | u32 StartWriteOffset, |
8282c400 | 562 | void * Src, |
4d643114 | 563 | u32 SrcLen) |
3e7ee490 | 564 | { |
8282c400 | 565 | void * ringBuffer=GetRingBuffer(RingInfo); |
4d643114 GKH |
566 | u32 ringBufferSize=GetRingBufferSize(RingInfo); |
567 | u32 fragLen; | |
3e7ee490 | 568 | |
454f18a9 | 569 | if (SrcLen > ringBufferSize - StartWriteOffset) /* wrap-around detected! */ |
3e7ee490 HJ |
570 | { |
571 | DPRINT_DBG(VMBUS, "wrap-around detected!"); | |
572 | ||
573 | fragLen = ringBufferSize - StartWriteOffset; | |
574 | memcpy(ringBuffer + StartWriteOffset, Src, fragLen); | |
575 | memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen); | |
576 | } | |
577 | else | |
578 | { | |
579 | memcpy(ringBuffer + StartWriteOffset, Src, SrcLen); | |
580 | } | |
581 | ||
582 | StartWriteOffset += SrcLen; | |
583 | StartWriteOffset %= ringBufferSize; | |
584 | ||
585 | return StartWriteOffset; | |
586 | } | |
587 | ||
588 | ||
589 | /*++ | |
590 | ||
591 | Name: | |
592 | CopyFromRingBuffer() | |
593 | ||
594 | Description: | |
595 | Helper routine to copy to source from ring buffer. | |
596 | Assume there is enough room. Handles wrap-around in src case only!! | |
597 | ||
598 | --*/ | |
bd1de709 | 599 | static u32 |
3e7ee490 HJ |
600 | CopyFromRingBuffer( |
601 | RING_BUFFER_INFO *RingInfo, | |
8282c400 | 602 | void * Dest, |
4d643114 GKH |
603 | u32 DestLen, |
604 | u32 StartReadOffset) | |
3e7ee490 | 605 | { |
8282c400 | 606 | void * ringBuffer=GetRingBuffer(RingInfo); |
4d643114 | 607 | u32 ringBufferSize=GetRingBufferSize(RingInfo); |
3e7ee490 | 608 | |
4d643114 | 609 | u32 fragLen; |
3e7ee490 | 610 | |
454f18a9 | 611 | if (DestLen > ringBufferSize - StartReadOffset) /* wrap-around detected at the src */ |
3e7ee490 HJ |
612 | { |
613 | DPRINT_DBG(VMBUS, "src wrap-around detected!"); | |
614 | ||
615 | fragLen = ringBufferSize - StartReadOffset; | |
616 | ||
617 | memcpy(Dest, ringBuffer + StartReadOffset, fragLen); | |
618 | memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen); | |
619 | } | |
620 | else | |
621 | { | |
622 | memcpy(Dest, ringBuffer + StartReadOffset, DestLen); | |
623 | } | |
624 | ||
625 | StartReadOffset += DestLen; | |
626 | StartReadOffset %= ringBufferSize; | |
627 | ||
628 | return StartReadOffset; | |
629 | } | |
630 | ||
631 | ||
454f18a9 | 632 | /* eof */ |