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