3 * Copyright (c) 2009, Microsoft Corporation.
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.
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
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.
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
24 #include <linux/kernel.h>
28 #include "ring_buffer.h"
34 /* Amount of space to write to */
35 #define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
41 GetRingBufferAvailBytes()
44 Get number of bytes available to read and to write to
45 for the specified ring buffer
49 GetRingBufferAvailBytes(struct hv_ring_buffer_info
*rbi
, u32
*read
, u32
*write
)
51 u32 read_loc
, write_loc
;
53 /* Capture the read/write indices before they changed */
54 read_loc
= rbi
->RingBuffer
->ReadIndex
;
55 write_loc
= rbi
->RingBuffer
->WriteIndex
;
57 *write
= BYTES_AVAIL_TO_WRITE(read_loc
, write_loc
, rbi
->RingDataSize
);
58 *read
= rbi
->RingDataSize
- *write
;
64 GetNextWriteLocation()
67 Get the next write location for the specified ring buffer
71 GetNextWriteLocation(struct hv_ring_buffer_info
*RingInfo
)
73 u32 next
= RingInfo
->RingBuffer
->WriteIndex
;
75 /* ASSERT(next < RingInfo->RingDataSize); */
83 SetNextWriteLocation()
86 Set the next write location for the specified ring buffer
90 SetNextWriteLocation(struct hv_ring_buffer_info
*RingInfo
,
91 u32 NextWriteLocation
)
93 RingInfo
->RingBuffer
->WriteIndex
= NextWriteLocation
;
102 Get the next read location for the specified ring buffer
106 GetNextReadLocation(struct hv_ring_buffer_info
*RingInfo
)
108 u32 next
= RingInfo
->RingBuffer
->ReadIndex
;
110 /* ASSERT(next < RingInfo->RingDataSize); */
118 GetNextReadLocationWithOffset()
121 Get the next read location + offset for the specified ring buffer.
122 This allows the caller to skip
126 GetNextReadLocationWithOffset(struct hv_ring_buffer_info
*RingInfo
, u32 Offset
)
128 u32 next
= RingInfo
->RingBuffer
->ReadIndex
;
130 /* ASSERT(next < RingInfo->RingDataSize); */
132 next
%= RingInfo
->RingDataSize
;
140 SetNextReadLocation()
143 Set the next read location for the specified ring buffer
147 SetNextReadLocation(struct hv_ring_buffer_info
*RingInfo
, u32 NextReadLocation
)
149 RingInfo
->RingBuffer
->ReadIndex
= NextReadLocation
;
159 Get the start of the ring buffer
163 GetRingBuffer(struct hv_ring_buffer_info
*RingInfo
)
165 return (void *)RingInfo
->RingBuffer
->Buffer
;
175 Get the size of the ring buffer
179 GetRingBufferSize(struct hv_ring_buffer_info
*RingInfo
)
181 return RingInfo
->RingDataSize
;
187 GetRingBufferIndices()
190 Get the read and write indices as u64 of the specified ring buffer
194 GetRingBufferIndices(struct hv_ring_buffer_info
*RingInfo
)
196 return ((u64
)RingInfo
->RingBuffer
->WriteIndex
<< 32)
197 || RingInfo
->RingBuffer
->ReadIndex
;
207 Dump out to console the ring buffer info
210 void DumpRingInfo(struct hv_ring_buffer_info
*RingInfo
, char *Prefix
)
212 u32 bytesAvailToWrite
;
213 u32 bytesAvailToRead
;
215 GetRingBufferAvailBytes(RingInfo
,
221 "%s <<ringinfo %p buffer %p avail write %u "
222 "avail read %u read idx %u write idx %u>>",
225 RingInfo
->RingBuffer
->Buffer
,
228 RingInfo
->RingBuffer
->ReadIndex
,
229 RingInfo
->RingBuffer
->WriteIndex
);
233 /* Internal routines */
237 struct hv_ring_buffer_info
*RingInfo
,
238 u32 StartWriteOffset
,
244 struct hv_ring_buffer_info
*RingInfo
,
247 u32 StartReadOffset
);
254 RingBufferGetDebugInfo()
257 Get various debug metrics for the specified ring buffer
260 void RingBufferGetDebugInfo(struct hv_ring_buffer_info
*RingInfo
,
261 struct hv_ring_buffer_debug_info
*debug_info
)
263 u32 bytesAvailToWrite
;
264 u32 bytesAvailToRead
;
266 if (RingInfo
->RingBuffer
) {
267 GetRingBufferAvailBytes(RingInfo
,
271 debug_info
->BytesAvailToRead
= bytesAvailToRead
;
272 debug_info
->BytesAvailToWrite
= bytesAvailToWrite
;
273 debug_info
->CurrentReadIndex
= RingInfo
->RingBuffer
->ReadIndex
;
274 debug_info
->CurrentWriteIndex
= RingInfo
->RingBuffer
->WriteIndex
;
275 debug_info
->CurrentInterruptMask
= RingInfo
->RingBuffer
->InterruptMask
;
283 GetRingBufferInterruptMask()
286 Get the interrupt mask for the specified ring buffer
289 u32
GetRingBufferInterruptMask(struct hv_ring_buffer_info
*rbi
)
291 return rbi
->RingBuffer
->InterruptMask
;
300 Initialize the ring buffer
303 int RingBufferInit(struct hv_ring_buffer_info
*RingInfo
, void *Buffer
, u32 BufferLen
)
305 if (sizeof(struct hv_ring_buffer
) != PAGE_SIZE
)
308 memset(RingInfo
, 0, sizeof(struct hv_ring_buffer_info
));
310 RingInfo
->RingBuffer
= (struct hv_ring_buffer
*)Buffer
;
311 RingInfo
->RingBuffer
->ReadIndex
= RingInfo
->RingBuffer
->WriteIndex
= 0;
313 RingInfo
->RingSize
= BufferLen
;
314 RingInfo
->RingDataSize
= BufferLen
- sizeof(struct hv_ring_buffer
);
316 spin_lock_init(&RingInfo
->ring_lock
);
327 Cleanup the ring buffer
330 void RingBufferCleanup(struct hv_ring_buffer_info
*RingInfo
)
340 Write to the ring buffer
343 int RingBufferWrite(struct hv_ring_buffer_info
*OutRingInfo
,
344 struct scatterlist
*sglist
, u32 sgcount
)
347 u32 byteAvailToWrite
;
349 u32 totalBytesToWrite
= 0;
351 struct scatterlist
*sg
;
352 volatile u32 nextWriteLocation
;
356 for_each_sg(sglist
, sg
, sgcount
, i
)
358 totalBytesToWrite
+= sg
->length
;
361 totalBytesToWrite
+= sizeof(u64
);
363 spin_lock_irqsave(&OutRingInfo
->ring_lock
, flags
);
365 GetRingBufferAvailBytes(OutRingInfo
,
369 DPRINT_DBG(VMBUS
, "Writing %u bytes...", totalBytesToWrite
);
371 /* DumpRingInfo(OutRingInfo, "BEFORE "); */
373 /* If there is only room for the packet, assume it is full. */
374 /* Otherwise, the next time around, we think the ring buffer */
375 /* is empty since the read index == write index */
376 if (byteAvailToWrite
<= totalBytesToWrite
) {
378 "No more space left on outbound ring buffer "
379 "(needed %u, avail %u)",
383 spin_unlock_irqrestore(&OutRingInfo
->ring_lock
, flags
);
387 /* Write to the ring buffer */
388 nextWriteLocation
= GetNextWriteLocation(OutRingInfo
);
390 for_each_sg(sglist
, sg
, sgcount
, i
)
392 nextWriteLocation
= CopyToRingBuffer(OutRingInfo
,
398 /* Set previous packet start */
399 prevIndices
= GetRingBufferIndices(OutRingInfo
);
401 nextWriteLocation
= CopyToRingBuffer(OutRingInfo
,
406 /* Make sure we flush all writes before updating the writeIndex */
409 /* Now, update the write location */
410 SetNextWriteLocation(OutRingInfo
, nextWriteLocation
);
412 /* DumpRingInfo(OutRingInfo, "AFTER "); */
414 spin_unlock_irqrestore(&OutRingInfo
->ring_lock
, flags
);
425 Read without advancing the read index
428 int RingBufferPeek(struct hv_ring_buffer_info
*InRingInfo
, void *Buffer
, u32 BufferLen
)
430 u32 bytesAvailToWrite
;
431 u32 bytesAvailToRead
;
432 u32 nextReadLocation
= 0;
435 spin_lock_irqsave(&InRingInfo
->ring_lock
, flags
);
437 GetRingBufferAvailBytes(InRingInfo
,
441 /* Make sure there is something to read */
442 if (bytesAvailToRead
< BufferLen
) {
444 "got callback but not enough to read "
445 "<avail to read %d read size %d>!!",
449 spin_unlock_irqrestore(&InRingInfo
->ring_lock
, flags
);
454 /* Convert to byte offset */
455 nextReadLocation
= GetNextReadLocation(InRingInfo
);
457 nextReadLocation
= CopyFromRingBuffer(InRingInfo
,
462 spin_unlock_irqrestore(&InRingInfo
->ring_lock
, flags
);
474 Read and advance the read index
477 int RingBufferRead(struct hv_ring_buffer_info
*InRingInfo
, void *Buffer
,
478 u32 BufferLen
, u32 Offset
)
480 u32 bytesAvailToWrite
;
481 u32 bytesAvailToRead
;
482 u32 nextReadLocation
= 0;
489 spin_lock_irqsave(&InRingInfo
->ring_lock
, flags
);
491 GetRingBufferAvailBytes(InRingInfo
,
495 DPRINT_DBG(VMBUS
, "Reading %u bytes...", BufferLen
);
497 /* DumpRingInfo(InRingInfo, "BEFORE "); */
499 /* Make sure there is something to read */
500 if (bytesAvailToRead
< BufferLen
) {
502 "got callback but not enough to read "
503 "<avail to read %d read size %d>!!",
507 spin_unlock_irqrestore(&InRingInfo
->ring_lock
, flags
);
512 nextReadLocation
= GetNextReadLocationWithOffset(InRingInfo
, Offset
);
514 nextReadLocation
= CopyFromRingBuffer(InRingInfo
,
519 nextReadLocation
= CopyFromRingBuffer(InRingInfo
,
524 /* Make sure all reads are done before we update the read index since */
525 /* the writer may start writing to the read area once the read index */
529 /* Update the read index */
530 SetNextReadLocation(InRingInfo
, nextReadLocation
);
532 /* DumpRingInfo(InRingInfo, "AFTER "); */
534 spin_unlock_irqrestore(&InRingInfo
->ring_lock
, flags
);
546 Helper routine to copy from source to ring buffer.
547 Assume there is enough room. Handles wrap-around in dest case only!!
552 struct hv_ring_buffer_info
*RingInfo
,
553 u32 StartWriteOffset
,
557 void *ringBuffer
= GetRingBuffer(RingInfo
);
558 u32 ringBufferSize
= GetRingBufferSize(RingInfo
);
561 /* wrap-around detected! */
562 if (SrcLen
> ringBufferSize
- StartWriteOffset
) {
563 DPRINT_DBG(VMBUS
, "wrap-around detected!");
565 fragLen
= ringBufferSize
- StartWriteOffset
;
566 memcpy(ringBuffer
+ StartWriteOffset
, Src
, fragLen
);
567 memcpy(ringBuffer
, Src
+ fragLen
, SrcLen
- fragLen
);
569 memcpy(ringBuffer
+ StartWriteOffset
, Src
, SrcLen
);
571 StartWriteOffset
+= SrcLen
;
572 StartWriteOffset
%= ringBufferSize
;
574 return StartWriteOffset
;
584 Helper routine to copy to source from ring buffer.
585 Assume there is enough room. Handles wrap-around in src case only!!
590 struct hv_ring_buffer_info
*RingInfo
,
595 void *ringBuffer
= GetRingBuffer(RingInfo
);
596 u32 ringBufferSize
= GetRingBufferSize(RingInfo
);
600 /* wrap-around detected at the src */
601 if (DestLen
> ringBufferSize
- StartReadOffset
) {
602 DPRINT_DBG(VMBUS
, "src wrap-around detected!");
604 fragLen
= ringBufferSize
- StartReadOffset
;
606 memcpy(Dest
, ringBuffer
+ StartReadOffset
, fragLen
);
607 memcpy(Dest
+ fragLen
, ringBuffer
, DestLen
- fragLen
);
610 memcpy(Dest
, ringBuffer
+ StartReadOffset
, DestLen
);
613 StartReadOffset
+= DestLen
;
614 StartReadOffset
%= ringBufferSize
;
616 return StartReadOffset
;