Staging: hv: cleanup coding style issues in RingBuffer.h
[deliverable/linux.git] / drivers / staging / hv / RingBuffer.c
... / ...
CommitLineData
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
25#include "include/logging.h"
26#include "RingBuffer.h"
27
28
29/* #defines */
30
31
32/* Amount of space to write to */
33#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
34
35
36/*++
37
38Name:
39 GetRingBufferAvailBytes()
40
41Description:
42 Get number of bytes available to read and to write to
43 for the specified ring buffer
44
45--*/
46static inline void
47GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, u32 *read, u32 *write)
48{
49 u32 read_loc,write_loc;
50
51 /* Capture the read/write indices before they changed */
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
61Name:
62 GetNextWriteLocation()
63
64Description:
65 Get the next write location for the specified ring buffer
66
67--*/
68static inline u32
69GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
70{
71 u32 next = RingInfo->RingBuffer->WriteIndex;
72
73 ASSERT(next < RingInfo->RingDataSize);
74
75 return next;
76}
77
78/*++
79
80Name:
81 SetNextWriteLocation()
82
83Description:
84 Set the next write location for the specified ring buffer
85
86--*/
87static inline void
88SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, u32 NextWriteLocation)
89{
90 RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
91}
92
93/*++
94
95Name:
96 GetNextReadLocation()
97
98Description:
99 Get the next read location for the specified ring buffer
100
101--*/
102static inline u32
103GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
104{
105 u32 next = RingInfo->RingBuffer->ReadIndex;
106
107 ASSERT(next < RingInfo->RingDataSize);
108
109 return next;
110}
111
112/*++
113
114Name:
115 GetNextReadLocationWithOffset()
116
117Description:
118 Get the next read location + offset for the specified ring buffer.
119 This allows the caller to skip
120
121--*/
122static inline u32
123GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, u32 Offset)
124{
125 u32 next = RingInfo->RingBuffer->ReadIndex;
126
127 ASSERT(next < RingInfo->RingDataSize);
128 next += Offset;
129 next %= RingInfo->RingDataSize;
130
131 return next;
132}
133
134/*++
135
136Name:
137 SetNextReadLocation()
138
139Description:
140 Set the next read location for the specified ring buffer
141
142--*/
143static inline void
144SetNextReadLocation(RING_BUFFER_INFO* RingInfo, u32 NextReadLocation)
145{
146 RingInfo->RingBuffer->ReadIndex = NextReadLocation;
147}
148
149
150/*++
151
152Name:
153 GetRingBuffer()
154
155Description:
156 Get the start of the ring buffer
157
158--*/
159static inline void *
160GetRingBuffer(RING_BUFFER_INFO* RingInfo)
161{
162 return (void *)RingInfo->RingBuffer->Buffer;
163}
164
165
166/*++
167
168Name:
169 GetRingBufferSize()
170
171Description:
172 Get the size of the ring buffer
173
174--*/
175static inline u32
176GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
177{
178 return RingInfo->RingDataSize;
179}
180
181/*++
182
183Name:
184 GetRingBufferIndices()
185
186Description:
187 Get the read and write indices as u64 of the specified ring buffer
188
189--*/
190static inline u64
191GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
192{
193 return ((u64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
194}
195
196
197/*++
198
199Name:
200 DumpRingInfo()
201
202Description:
203 Dump out to console the ring buffer info
204
205--*/
206void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
207{
208 u32 bytesAvailToWrite;
209 u32 bytesAvailToRead;
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
223
224/* Internal routines */
225
226static u32
227CopyToRingBuffer(
228 RING_BUFFER_INFO *RingInfo,
229 u32 StartWriteOffset,
230 void * Src,
231 u32 SrcLen);
232
233static u32
234CopyFromRingBuffer(
235 RING_BUFFER_INFO *RingInfo,
236 void * Dest,
237 u32 DestLen,
238 u32 StartReadOffset);
239
240
241
242/*++
243
244Name:
245 RingBufferGetDebugInfo()
246
247Description:
248 Get various debug metrics for the specified ring buffer
249
250--*/
251void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
252 RING_BUFFER_DEBUG_INFO *DebugInfo)
253{
254 u32 bytesAvailToWrite;
255 u32 bytesAvailToRead;
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
273Name:
274 GetRingBufferInterruptMask()
275
276Description:
277 Get the interrupt mask for the specified ring buffer
278
279--*/
280u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *rbi)
281{
282 return rbi->RingBuffer->InterruptMask;
283}
284
285/*++
286
287Name:
288 RingBufferInit()
289
290Description:
291 Initialize the ring buffer
292
293--*/
294int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
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
306 spin_lock_init(&RingInfo->ring_lock);
307
308 return 0;
309}
310
311/*++
312
313Name:
314 RingBufferCleanup()
315
316Description:
317 Cleanup the ring buffer
318
319--*/
320void RingBufferCleanup(RING_BUFFER_INFO* RingInfo)
321{
322}
323
324/*++
325
326Name:
327 RingBufferWrite()
328
329Description:
330 Write to the ring buffer
331
332--*/
333int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
334 struct scatterlist *sglist, u32 sgcount)
335{
336 int i=0;
337 u32 byteAvailToWrite;
338 u32 byteAvailToRead;
339 u32 totalBytesToWrite=0;
340
341 struct scatterlist *sg;
342 volatile u32 nextWriteLocation;
343 u64 prevIndices=0;
344 unsigned long flags;
345
346 DPRINT_ENTER(VMBUS);
347
348 for_each_sg(sglist, sg, sgcount, i)
349 {
350 totalBytesToWrite += sg->length;
351 }
352
353 totalBytesToWrite += sizeof(u64);
354
355 spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
356
357 GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
358
359 DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
360
361 /* DumpRingInfo(OutRingInfo, "BEFORE "); */
362
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 */
365 if (byteAvailToWrite <= totalBytesToWrite)
366 {
367 DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
368
369 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
370
371 DPRINT_EXIT(VMBUS);
372
373 return -1;
374 }
375
376 /* Write to the ring buffer */
377 nextWriteLocation = GetNextWriteLocation(OutRingInfo);
378
379 for_each_sg(sglist, sg, sgcount, i)
380 {
381 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
382 nextWriteLocation,
383 sg_virt(sg),
384 sg->length);
385 }
386
387 /* Set previous packet start */
388 prevIndices = GetRingBufferIndices(OutRingInfo);
389
390 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
391 nextWriteLocation,
392 &prevIndices,
393 sizeof(u64));
394
395 /* Make sure we flush all writes before updating the writeIndex */
396 mb();
397
398 /* Now, update the write location */
399 SetNextWriteLocation(OutRingInfo, nextWriteLocation);
400
401 /* DumpRingInfo(OutRingInfo, "AFTER "); */
402
403 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
404
405 DPRINT_EXIT(VMBUS);
406
407 return 0;
408}
409
410
411/*++
412
413Name:
414 RingBufferPeek()
415
416Description:
417 Read without advancing the read index
418
419--*/
420int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
421{
422 u32 bytesAvailToWrite;
423 u32 bytesAvailToRead;
424 u32 nextReadLocation=0;
425 unsigned long flags;
426
427 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
428
429 GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
430
431 /* Make sure there is something to read */
432 if (bytesAvailToRead < BufferLen )
433 {
434 /* DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); */
435
436 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
437
438 return -1;
439 }
440
441 /* Convert to byte offset */
442 nextReadLocation = GetNextReadLocation(InRingInfo);
443
444 nextReadLocation = CopyFromRingBuffer(InRingInfo,
445 Buffer,
446 BufferLen,
447 nextReadLocation);
448
449 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
450
451 return 0;
452}
453
454
455/*++
456
457Name:
458 RingBufferRead()
459
460Description:
461 Read and advance the read index
462
463--*/
464int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
465 u32 BufferLen, u32 Offset)
466{
467 u32 bytesAvailToWrite;
468 u32 bytesAvailToRead;
469 u32 nextReadLocation=0;
470 u64 prevIndices=0;
471 unsigned long flags;
472
473 ASSERT(BufferLen > 0);
474
475 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
476
477 GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
478
479 DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
480
481 /* DumpRingInfo(InRingInfo, "BEFORE "); */
482
483 /* Make sure there is something to read */
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
488 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
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,
502 sizeof(u64),
503 nextReadLocation);
504
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 */
507 mb();
508
509 /* Update the read index */
510 SetNextReadLocation(InRingInfo, nextReadLocation);
511
512 /* DumpRingInfo(InRingInfo, "AFTER "); */
513
514 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
515
516 return 0;
517}
518
519
520/*++
521
522Name:
523 CopyToRingBuffer()
524
525Description:
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--*/
530static u32
531CopyToRingBuffer(
532 RING_BUFFER_INFO *RingInfo,
533 u32 StartWriteOffset,
534 void * Src,
535 u32 SrcLen)
536{
537 void * ringBuffer=GetRingBuffer(RingInfo);
538 u32 ringBufferSize=GetRingBufferSize(RingInfo);
539 u32 fragLen;
540
541 if (SrcLen > ringBufferSize - StartWriteOffset) /* wrap-around detected! */
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
563Name:
564 CopyFromRingBuffer()
565
566Description:
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--*/
571static u32
572CopyFromRingBuffer(
573 RING_BUFFER_INFO *RingInfo,
574 void * Dest,
575 u32 DestLen,
576 u32 StartReadOffset)
577{
578 void * ringBuffer=GetRingBuffer(RingInfo);
579 u32 ringBufferSize=GetRingBufferSize(RingInfo);
580
581 u32 fragLen;
582
583 if (DestLen > ringBufferSize - StartReadOffset) /* wrap-around detected at the src */
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
604/* eof */
This page took 0.025909 seconds and 5 git commands to generate.