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 */ |
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 |
8a0e1c55 | 71 | GetNextWriteLocation(struct hv_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 | |
8a0e1c55 GKH |
90 | SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo, |
91 | u32 NextWriteLocation) | |
3e7ee490 HJ |
92 | { |
93 | RingInfo->RingBuffer->WriteIndex = NextWriteLocation; | |
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 |
8a0e1c55 | 106 | GetNextReadLocation(struct hv_ring_buffer_info *RingInfo) |
3e7ee490 | 107 | { |
4d643114 | 108 | u32 next = RingInfo->RingBuffer->ReadIndex; |
3e7ee490 | 109 | |
1bbdd7a5 | 110 | /* ASSERT(next < RingInfo->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 |
8a0e1c55 | 126 | GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset) |
3e7ee490 | 127 | { |
4d643114 | 128 | u32 next = RingInfo->RingBuffer->ReadIndex; |
3e7ee490 | 129 | |
1bbdd7a5 | 130 | /* ASSERT(next < RingInfo->RingDataSize); */ |
3e7ee490 HJ |
131 | next += Offset; |
132 | next %= RingInfo->RingDataSize; | |
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 | |
8a0e1c55 | 147 | SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation) |
3e7ee490 HJ |
148 | { |
149 | RingInfo->RingBuffer->ReadIndex = NextReadLocation; | |
150 | } | |
151 | ||
152 | ||
153 | /*++ | |
154 | ||
155 | Name: | |
156 | GetRingBuffer() | |
157 | ||
158 | Description: | |
159 | Get the start of the ring buffer | |
160 | ||
161 | --*/ | |
8282c400 | 162 | static inline void * |
8a0e1c55 | 163 | GetRingBuffer(struct hv_ring_buffer_info *RingInfo) |
3e7ee490 | 164 | { |
8282c400 | 165 | return (void *)RingInfo->RingBuffer->Buffer; |
3e7ee490 HJ |
166 | } |
167 | ||
168 | ||
169 | /*++ | |
170 | ||
171 | Name: | |
172 | GetRingBufferSize() | |
173 | ||
174 | Description: | |
175 | Get the size of the ring buffer | |
176 | ||
177 | --*/ | |
4d643114 | 178 | static inline u32 |
8a0e1c55 | 179 | GetRingBufferSize(struct hv_ring_buffer_info *RingInfo) |
3e7ee490 HJ |
180 | { |
181 | return RingInfo->RingDataSize; | |
182 | } | |
183 | ||
184 | /*++ | |
185 | ||
186 | Name: | |
187 | GetRingBufferIndices() | |
188 | ||
189 | Description: | |
59471438 | 190 | Get the read and write indices as u64 of the specified ring buffer |
3e7ee490 HJ |
191 | |
192 | --*/ | |
59471438 | 193 | static inline u64 |
8a0e1c55 | 194 | GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo) |
3e7ee490 | 195 | { |
e5fa721d | 196 | return (u64)RingInfo->RingBuffer->WriteIndex << 32; |
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 | --*/ | |
8a0e1c55 | 209 | void DumpRingInfo(struct hv_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 | 235 | CopyToRingBuffer( |
8a0e1c55 | 236 | struct hv_ring_buffer_info *RingInfo, |
4d643114 | 237 | u32 StartWriteOffset, |
4408f531 | 238 | void *Src, |
4d643114 | 239 | u32 SrcLen); |
3e7ee490 | 240 | |
4d643114 | 241 | static u32 |
3e7ee490 | 242 | CopyFromRingBuffer( |
8a0e1c55 | 243 | struct hv_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 | --*/ | |
8a0e1c55 | 259 | void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo, |
80682b7a | 260 | struct hv_ring_buffer_debug_info *debug_info) |
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 | 269 | |
80682b7a GKH |
270 | debug_info->BytesAvailToRead = bytesAvailToRead; |
271 | debug_info->BytesAvailToWrite = bytesAvailToWrite; | |
272 | debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; | |
273 | debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; | |
274 | debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; | |
3e7ee490 HJ |
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 | --*/ | |
8a0e1c55 | 288 | u32 GetRingBufferInterruptMask(struct hv_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 | --*/ | |
8a0e1c55 | 302 | int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen) |
3e7ee490 | 303 | { |
4a1b3acc | 304 | if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) |
3324fb40 | 305 | return -EINVAL; |
3e7ee490 | 306 | |
8a0e1c55 | 307 | memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info)); |
3e7ee490 | 308 | |
4a1b3acc | 309 | RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer; |
3e7ee490 HJ |
310 | RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0; |
311 | ||
312 | RingInfo->RingSize = BufferLen; | |
4a1b3acc | 313 | RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer); |
3e7ee490 | 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 | --*/ | |
8a0e1c55 | 329 | void RingBufferCleanup(struct hv_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 | --*/ | |
8a0e1c55 | 342 | int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo, |
3523a805 | 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 | 354 | |
b219b3f7 | 355 | for_each_sg(sglist, sg, sgcount, i) |
3e7ee490 | 356 | { |
b219b3f7 | 357 | totalBytesToWrite += sg->length; |
3e7ee490 HJ |
358 | } |
359 | ||
59471438 | 360 | totalBytesToWrite += sizeof(u64); |
3e7ee490 | 361 | |
a98f96ee | 362 | spin_lock_irqsave(&OutRingInfo->ring_lock, flags); |
3e7ee490 | 363 | |
4408f531 B |
364 | GetRingBufferAvailBytes(OutRingInfo, |
365 | &byteAvailToRead, | |
366 | &byteAvailToWrite); | |
3e7ee490 HJ |
367 | |
368 | DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); | |
369 | ||
454f18a9 | 370 | /* DumpRingInfo(OutRingInfo, "BEFORE "); */ |
3e7ee490 | 371 | |
4408f531 B |
372 | /* If there is only room for the packet, assume it is full. */ |
373 | /* Otherwise, the next time around, we think the ring buffer */ | |
454f18a9 | 374 | /* is empty since the read index == write index */ |
4408f531 B |
375 | if (byteAvailToWrite <= totalBytesToWrite) { |
376 | DPRINT_DBG(VMBUS, | |
377 | "No more space left on outbound ring buffer " | |
378 | "(needed %u, avail %u)", | |
379 | totalBytesToWrite, | |
380 | byteAvailToWrite); | |
3e7ee490 | 381 | |
a98f96ee | 382 | spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); |
3e7ee490 HJ |
383 | return -1; |
384 | } | |
385 | ||
454f18a9 | 386 | /* Write to the ring buffer */ |
3e7ee490 HJ |
387 | nextWriteLocation = GetNextWriteLocation(OutRingInfo); |
388 | ||
b219b3f7 | 389 | for_each_sg(sglist, sg, sgcount, i) |
3e7ee490 | 390 | { |
b219b3f7 NP |
391 | nextWriteLocation = CopyToRingBuffer(OutRingInfo, |
392 | nextWriteLocation, | |
393 | sg_virt(sg), | |
394 | sg->length); | |
3e7ee490 HJ |
395 | } |
396 | ||
454f18a9 | 397 | /* Set previous packet start */ |
3e7ee490 HJ |
398 | prevIndices = GetRingBufferIndices(OutRingInfo); |
399 | ||
400 | nextWriteLocation = CopyToRingBuffer(OutRingInfo, | |
b219b3f7 NP |
401 | nextWriteLocation, |
402 | &prevIndices, | |
403 | sizeof(u64)); | |
3e7ee490 | 404 | |
454f18a9 | 405 | /* Make sure we flush all writes before updating the writeIndex */ |
28b6ca9c | 406 | mb(); |
3e7ee490 | 407 | |
454f18a9 | 408 | /* Now, update the write location */ |
3e7ee490 HJ |
409 | SetNextWriteLocation(OutRingInfo, nextWriteLocation); |
410 | ||
454f18a9 | 411 | /* DumpRingInfo(OutRingInfo, "AFTER "); */ |
3e7ee490 | 412 | |
a98f96ee | 413 | spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); |
3e7ee490 HJ |
414 | return 0; |
415 | } | |
416 | ||
417 | ||
418 | /*++ | |
419 | ||
420 | Name: | |
421 | RingBufferPeek() | |
422 | ||
423 | Description: | |
424 | Read without advancing the read index | |
425 | ||
426 | --*/ | |
8a0e1c55 | 427 | int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen) |
3e7ee490 | 428 | { |
4d643114 GKH |
429 | u32 bytesAvailToWrite; |
430 | u32 bytesAvailToRead; | |
4408f531 | 431 | u32 nextReadLocation = 0; |
a98f96ee | 432 | unsigned long flags; |
3e7ee490 | 433 | |
a98f96ee | 434 | spin_lock_irqsave(&InRingInfo->ring_lock, flags); |
3e7ee490 | 435 | |
4408f531 B |
436 | GetRingBufferAvailBytes(InRingInfo, |
437 | &bytesAvailToRead, | |
438 | &bytesAvailToWrite); | |
3e7ee490 | 439 | |
454f18a9 | 440 | /* Make sure there is something to read */ |
4408f531 B |
441 | if (bytesAvailToRead < BufferLen) { |
442 | /* DPRINT_DBG(VMBUS, | |
443 | "got callback but not enough to read " | |
444 | "<avail to read %d read size %d>!!", | |
445 | bytesAvailToRead, | |
446 | BufferLen); */ | |
3e7ee490 | 447 | |
a98f96ee | 448 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
449 | |
450 | return -1; | |
451 | } | |
452 | ||
454f18a9 | 453 | /* Convert to byte offset */ |
3e7ee490 HJ |
454 | nextReadLocation = GetNextReadLocation(InRingInfo); |
455 | ||
456 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
4408f531 B |
457 | Buffer, |
458 | BufferLen, | |
459 | nextReadLocation); | |
3e7ee490 | 460 | |
a98f96ee | 461 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
462 | |
463 | return 0; | |
464 | } | |
465 | ||
466 | ||
467 | /*++ | |
468 | ||
469 | Name: | |
470 | RingBufferRead() | |
471 | ||
472 | Description: | |
473 | Read and advance the read index | |
474 | ||
475 | --*/ | |
8a0e1c55 | 476 | int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer, |
3523a805 | 477 | u32 BufferLen, u32 Offset) |
3e7ee490 | 478 | { |
4d643114 GKH |
479 | u32 bytesAvailToWrite; |
480 | u32 bytesAvailToRead; | |
4408f531 B |
481 | u32 nextReadLocation = 0; |
482 | u64 prevIndices = 0; | |
a98f96ee | 483 | unsigned long flags; |
3e7ee490 | 484 | |
a16e1485 BP |
485 | if (BufferLen <= 0) |
486 | return -EINVAL; | |
3e7ee490 | 487 | |
a98f96ee | 488 | spin_lock_irqsave(&InRingInfo->ring_lock, flags); |
3e7ee490 | 489 | |
4408f531 B |
490 | GetRingBufferAvailBytes(InRingInfo, |
491 | &bytesAvailToRead, | |
492 | &bytesAvailToWrite); | |
3e7ee490 HJ |
493 | |
494 | DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); | |
495 | ||
454f18a9 | 496 | /* DumpRingInfo(InRingInfo, "BEFORE "); */ |
3e7ee490 | 497 | |
454f18a9 | 498 | /* Make sure there is something to read */ |
4408f531 B |
499 | if (bytesAvailToRead < BufferLen) { |
500 | DPRINT_DBG(VMBUS, | |
501 | "got callback but not enough to read " | |
502 | "<avail to read %d read size %d>!!", | |
503 | bytesAvailToRead, | |
504 | BufferLen); | |
3e7ee490 | 505 | |
a98f96ee | 506 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
507 | |
508 | return -1; | |
509 | } | |
510 | ||
511 | nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); | |
512 | ||
513 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
4408f531 B |
514 | Buffer, |
515 | BufferLen, | |
516 | nextReadLocation); | |
3e7ee490 HJ |
517 | |
518 | nextReadLocation = CopyFromRingBuffer(InRingInfo, | |
4408f531 B |
519 | &prevIndices, |
520 | sizeof(u64), | |
521 | nextReadLocation); | |
3e7ee490 | 522 | |
454f18a9 | 523 | /* Make sure all reads are done before we update the read index since */ |
4408f531 B |
524 | /* the writer may start writing to the read area once the read index */ |
525 | /*is updated */ | |
28b6ca9c | 526 | mb(); |
3e7ee490 | 527 | |
454f18a9 | 528 | /* Update the read index */ |
3e7ee490 HJ |
529 | SetNextReadLocation(InRingInfo, nextReadLocation); |
530 | ||
454f18a9 | 531 | /* DumpRingInfo(InRingInfo, "AFTER "); */ |
3e7ee490 | 532 | |
a98f96ee | 533 | spin_unlock_irqrestore(&InRingInfo->ring_lock, flags); |
3e7ee490 HJ |
534 | |
535 | return 0; | |
536 | } | |
537 | ||
538 | ||
539 | /*++ | |
540 | ||
541 | Name: | |
542 | CopyToRingBuffer() | |
543 | ||
544 | Description: | |
545 | Helper routine to copy from source to ring buffer. | |
546 | Assume there is enough room. Handles wrap-around in dest case only!! | |
547 | ||
548 | --*/ | |
bd1de709 | 549 | static u32 |
3e7ee490 | 550 | CopyToRingBuffer( |
8a0e1c55 | 551 | struct hv_ring_buffer_info *RingInfo, |
4d643114 | 552 | u32 StartWriteOffset, |
4408f531 | 553 | void *Src, |
4d643114 | 554 | u32 SrcLen) |
3e7ee490 | 555 | { |
4408f531 B |
556 | void *ringBuffer = GetRingBuffer(RingInfo); |
557 | u32 ringBufferSize = GetRingBufferSize(RingInfo); | |
4d643114 | 558 | u32 fragLen; |
3e7ee490 | 559 | |
4408f531 B |
560 | /* wrap-around detected! */ |
561 | if (SrcLen > ringBufferSize - StartWriteOffset) { | |
3e7ee490 HJ |
562 | DPRINT_DBG(VMBUS, "wrap-around detected!"); |
563 | ||
564 | fragLen = ringBufferSize - StartWriteOffset; | |
565 | memcpy(ringBuffer + StartWriteOffset, Src, fragLen); | |
566 | memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen); | |
4408f531 | 567 | } else |
3e7ee490 | 568 | memcpy(ringBuffer + StartWriteOffset, Src, SrcLen); |
3e7ee490 HJ |
569 | |
570 | StartWriteOffset += SrcLen; | |
571 | StartWriteOffset %= ringBufferSize; | |
572 | ||
573 | return StartWriteOffset; | |
574 | } | |
575 | ||
576 | ||
577 | /*++ | |
578 | ||
579 | Name: | |
580 | CopyFromRingBuffer() | |
581 | ||
582 | Description: | |
583 | Helper routine to copy to source from ring buffer. | |
584 | Assume there is enough room. Handles wrap-around in src case only!! | |
585 | ||
586 | --*/ | |
bd1de709 | 587 | static u32 |
3e7ee490 | 588 | CopyFromRingBuffer( |
8a0e1c55 | 589 | struct hv_ring_buffer_info *RingInfo, |
4408f531 | 590 | void *Dest, |
4d643114 GKH |
591 | u32 DestLen, |
592 | u32 StartReadOffset) | |
3e7ee490 | 593 | { |
4408f531 B |
594 | void *ringBuffer = GetRingBuffer(RingInfo); |
595 | u32 ringBufferSize = GetRingBufferSize(RingInfo); | |
3e7ee490 | 596 | |
4d643114 | 597 | u32 fragLen; |
3e7ee490 | 598 | |
4408f531 B |
599 | /* wrap-around detected at the src */ |
600 | if (DestLen > ringBufferSize - StartReadOffset) { | |
3e7ee490 HJ |
601 | DPRINT_DBG(VMBUS, "src wrap-around detected!"); |
602 | ||
603 | fragLen = ringBufferSize - StartReadOffset; | |
604 | ||
605 | memcpy(Dest, ringBuffer + StartReadOffset, fragLen); | |
606 | memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen); | |
4408f531 B |
607 | } else |
608 | ||
3e7ee490 | 609 | memcpy(Dest, ringBuffer + StartReadOffset, DestLen); |
4408f531 | 610 | |
3e7ee490 HJ |
611 | |
612 | StartReadOffset += DestLen; | |
613 | StartReadOffset %= ringBufferSize; | |
614 | ||
615 | return StartReadOffset; | |
616 | } | |
617 | ||
618 | ||
454f18a9 | 619 | /* eof */ |