Staging: hv: cleanup coding style issues in RingBuffer.h
[deliverable/linux.git] / drivers / staging / hv / RingBuffer.c
CommitLineData
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
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
4d643114 47GetRingBufferAvailBytes(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
61Name:
62 GetNextWriteLocation()
63
64Description:
65 Get the next write location for the specified ring buffer
66
67--*/
4d643114 68static inline u32
3e7ee490
HJ
69GetNextWriteLocation(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
80Name:
81 SetNextWriteLocation()
82
83Description:
84 Set the next write location for the specified ring buffer
85
86--*/
87static inline void
4d643114 88SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, u32 NextWriteLocation)
3e7ee490
HJ
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--*/
4d643114 102static inline u32
3e7ee490
HJ
103GetNextReadLocation(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
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--*/
4d643114
GKH
122static inline u32
123GetNextReadLocationWithOffset(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
136Name:
137 SetNextReadLocation()
138
139Description:
140 Set the next read location for the specified ring buffer
141
142--*/
143static inline void
4d643114 144SetNextReadLocation(RING_BUFFER_INFO* RingInfo, u32 NextReadLocation)
3e7ee490
HJ
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--*/
8282c400 159static inline void *
3e7ee490
HJ
160GetRingBuffer(RING_BUFFER_INFO* RingInfo)
161{
8282c400 162 return (void *)RingInfo->RingBuffer->Buffer;
3e7ee490
HJ
163}
164
165
166/*++
167
168Name:
169 GetRingBufferSize()
170
171Description:
172 Get the size of the ring buffer
173
174--*/
4d643114 175static inline u32
3e7ee490
HJ
176GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
177{
178 return RingInfo->RingDataSize;
179}
180
181/*++
182
183Name:
184 GetRingBufferIndices()
185
186Description:
59471438 187 Get the read and write indices as u64 of the specified ring buffer
3e7ee490
HJ
188
189--*/
59471438 190static inline u64
3e7ee490
HJ
191GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
192{
59471438 193 return ((u64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
3e7ee490
HJ
194}
195
196
197/*++
198
199Name:
200 DumpRingInfo()
201
202Description:
203 Dump out to console the ring buffer info
204
205--*/
3523a805 206void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
3e7ee490 207{
4d643114
GKH
208 u32 bytesAvailToWrite;
209 u32 bytesAvailToRead;
3e7ee490
HJ
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
454f18a9
BP
223
224/* Internal routines */
225
4d643114 226static u32
3e7ee490
HJ
227CopyToRingBuffer(
228 RING_BUFFER_INFO *RingInfo,
4d643114 229 u32 StartWriteOffset,
8282c400 230 void * Src,
4d643114 231 u32 SrcLen);
3e7ee490 232
4d643114 233static u32
3e7ee490
HJ
234CopyFromRingBuffer(
235 RING_BUFFER_INFO *RingInfo,
8282c400 236 void * Dest,
4d643114
GKH
237 u32 DestLen,
238 u32 StartReadOffset);
3e7ee490
HJ
239
240
241
242/*++
243
244Name:
245 RingBufferGetDebugInfo()
246
247Description:
248 Get various debug metrics for the specified ring buffer
249
250--*/
3523a805
GKH
251void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
252 RING_BUFFER_DEBUG_INFO *DebugInfo)
3e7ee490 253{
4d643114
GKH
254 u32 bytesAvailToWrite;
255 u32 bytesAvailToRead;
3e7ee490
HJ
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--*/
3523a805 280u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *rbi)
3e7ee490
HJ
281{
282 return rbi->RingBuffer->InterruptMask;
283}
284
285/*++
286
287Name:
288 RingBufferInit()
289
290Description:
291 Initialize the ring buffer
292
293--*/
3523a805 294int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
3e7ee490
HJ
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
a98f96ee 306 spin_lock_init(&RingInfo->ring_lock);
3e7ee490
HJ
307
308 return 0;
309}
310
311/*++
312
313Name:
314 RingBufferCleanup()
315
316Description:
317 Cleanup the ring buffer
318
319--*/
3523a805 320void RingBufferCleanup(RING_BUFFER_INFO* RingInfo)
3e7ee490 321{
3e7ee490
HJ
322}
323
324/*++
325
326Name:
327 RingBufferWrite()
328
329Description:
330 Write to the ring buffer
331
332--*/
3523a805
GKH
333int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
334 struct scatterlist *sglist, u32 sgcount)
3e7ee490
HJ
335{
336 int i=0;
4d643114
GKH
337 u32 byteAvailToWrite;
338 u32 byteAvailToRead;
339 u32 totalBytesToWrite=0;
3e7ee490 340
b219b3f7 341 struct scatterlist *sg;
4d643114 342 volatile u32 nextWriteLocation;
59471438 343 u64 prevIndices=0;
a98f96ee 344 unsigned long flags;
3e7ee490
HJ
345
346 DPRINT_ENTER(VMBUS);
347
b219b3f7 348 for_each_sg(sglist, sg, sgcount, i)
3e7ee490 349 {
b219b3f7 350 totalBytesToWrite += sg->length;
3e7ee490
HJ
351 }
352
59471438 353 totalBytesToWrite += sizeof(u64);
3e7ee490 354
a98f96ee 355 spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
3e7ee490
HJ
356
357 GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
358
359 DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
360
454f18a9 361 /* DumpRingInfo(OutRingInfo, "BEFORE "); */
3e7ee490 362
454f18a9
BP
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 */
3e7ee490
HJ
365 if (byteAvailToWrite <= totalBytesToWrite)
366 {
367 DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
368
a98f96ee 369 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
3e7ee490
HJ
370
371 DPRINT_EXIT(VMBUS);
372
373 return -1;
374 }
375
454f18a9 376 /* Write to the ring buffer */
3e7ee490
HJ
377 nextWriteLocation = GetNextWriteLocation(OutRingInfo);
378
b219b3f7 379 for_each_sg(sglist, sg, sgcount, i)
3e7ee490 380 {
b219b3f7
NP
381 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
382 nextWriteLocation,
383 sg_virt(sg),
384 sg->length);
3e7ee490
HJ
385 }
386
454f18a9 387 /* Set previous packet start */
3e7ee490
HJ
388 prevIndices = GetRingBufferIndices(OutRingInfo);
389
390 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
b219b3f7
NP
391 nextWriteLocation,
392 &prevIndices,
393 sizeof(u64));
3e7ee490 394
454f18a9 395 /* Make sure we flush all writes before updating the writeIndex */
28b6ca9c 396 mb();
3e7ee490 397
454f18a9 398 /* Now, update the write location */
3e7ee490
HJ
399 SetNextWriteLocation(OutRingInfo, nextWriteLocation);
400
454f18a9 401 /* DumpRingInfo(OutRingInfo, "AFTER "); */
3e7ee490 402
a98f96ee 403 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
3e7ee490
HJ
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--*/
3523a805 420int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
3e7ee490 421{
4d643114
GKH
422 u32 bytesAvailToWrite;
423 u32 bytesAvailToRead;
424 u32 nextReadLocation=0;
a98f96ee 425 unsigned long flags;
3e7ee490 426
a98f96ee 427 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
428
429 GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
430
454f18a9 431 /* Make sure there is something to read */
3e7ee490
HJ
432 if (bytesAvailToRead < BufferLen )
433 {
454f18a9 434 /* DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); */
3e7ee490 435
a98f96ee 436 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
437
438 return -1;
439 }
440
454f18a9 441 /* Convert to byte offset */
3e7ee490
HJ
442 nextReadLocation = GetNextReadLocation(InRingInfo);
443
444 nextReadLocation = CopyFromRingBuffer(InRingInfo,
445 Buffer,
446 BufferLen,
447 nextReadLocation);
448
a98f96ee 449 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
450
451 return 0;
452}
453
454
455/*++
456
457Name:
458 RingBufferRead()
459
460Description:
461 Read and advance the read index
462
463--*/
3523a805
GKH
464int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
465 u32 BufferLen, u32 Offset)
3e7ee490 466{
4d643114
GKH
467 u32 bytesAvailToWrite;
468 u32 bytesAvailToRead;
469 u32 nextReadLocation=0;
59471438 470 u64 prevIndices=0;
a98f96ee 471 unsigned long flags;
3e7ee490
HJ
472
473 ASSERT(BufferLen > 0);
474
a98f96ee 475 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
476
477 GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
478
479 DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
480
454f18a9 481 /* DumpRingInfo(InRingInfo, "BEFORE "); */
3e7ee490 482
454f18a9 483 /* Make sure there is something to read */
3e7ee490
HJ
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
a98f96ee 488 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
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,
59471438 502 sizeof(u64),
3e7ee490
HJ
503 nextReadLocation);
504
454f18a9
BP
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 */
28b6ca9c 507 mb();
3e7ee490 508
454f18a9 509 /* Update the read index */
3e7ee490
HJ
510 SetNextReadLocation(InRingInfo, nextReadLocation);
511
454f18a9 512 /* DumpRingInfo(InRingInfo, "AFTER "); */
3e7ee490 513
a98f96ee 514 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
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--*/
bd1de709 530static u32
3e7ee490
HJ
531CopyToRingBuffer(
532 RING_BUFFER_INFO *RingInfo,
4d643114 533 u32 StartWriteOffset,
8282c400 534 void * Src,
4d643114 535 u32 SrcLen)
3e7ee490 536{
8282c400 537 void * ringBuffer=GetRingBuffer(RingInfo);
4d643114
GKH
538 u32 ringBufferSize=GetRingBufferSize(RingInfo);
539 u32 fragLen;
3e7ee490 540
454f18a9 541 if (SrcLen > ringBufferSize - StartWriteOffset) /* wrap-around detected! */
3e7ee490
HJ
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--*/
bd1de709 571static u32
3e7ee490
HJ
572CopyFromRingBuffer(
573 RING_BUFFER_INFO *RingInfo,
8282c400 574 void * Dest,
4d643114
GKH
575 u32 DestLen,
576 u32 StartReadOffset)
3e7ee490 577{
8282c400 578 void * ringBuffer=GetRingBuffer(RingInfo);
4d643114 579 u32 ringBufferSize=GetRingBufferSize(RingInfo);
3e7ee490 580
4d643114 581 u32 fragLen;
3e7ee490 582
454f18a9 583 if (DestLen > ringBufferSize - StartReadOffset) /* wrap-around detected at the src */
3e7ee490
HJ
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
454f18a9 604/* eof */
This page took 0.059353 seconds and 5 git commands to generate.