Staging: comedi: poc: fix coding style issues
[safe/jmp/linux-2.6] / drivers / staging / hv / RingBuffer.c
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 #include <linux/kernel.h>
25 #include <linux/mm.h>
26 #include "osd.h"
27 #include "logging.h"
28 #include "RingBuffer.h"
29
30
31 /* #defines */
32
33
34 /* Amount of space to write to */
35 #define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
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
49 GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, u32 *read, u32 *write)
50 {
51         u32 read_loc,write_loc;
52
53         /* Capture the read/write indices before they changed */
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 --*/
70 static inline u32
71 GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
72 {
73         u32 next = RingInfo->RingBuffer->WriteIndex;
74
75         ASSERT(next < RingInfo->RingDataSize);
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
90 SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, u32 NextWriteLocation)
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 --*/
104 static inline u32
105 GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
106 {
107         u32 next = RingInfo->RingBuffer->ReadIndex;
108
109         ASSERT(next < RingInfo->RingDataSize);
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 --*/
124 static inline u32
125 GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, u32 Offset)
126 {
127         u32 next = RingInfo->RingBuffer->ReadIndex;
128
129         ASSERT(next < RingInfo->RingDataSize);
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
146 SetNextReadLocation(RING_BUFFER_INFO* RingInfo, u32 NextReadLocation)
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 --*/
161 static inline void *
162 GetRingBuffer(RING_BUFFER_INFO* RingInfo)
163 {
164         return (void *)RingInfo->RingBuffer->Buffer;
165 }
166
167
168 /*++
169
170 Name:
171         GetRingBufferSize()
172
173 Description:
174         Get the size of the ring buffer
175
176 --*/
177 static inline u32
178 GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
179 {
180         return RingInfo->RingDataSize;
181 }
182
183 /*++
184
185 Name:
186         GetRingBufferIndices()
187
188 Description:
189         Get the read and write indices as u64 of the specified ring buffer
190
191 --*/
192 static inline u64
193 GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
194 {
195         return ((u64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
196 }
197
198
199 /*++
200
201 Name:
202         DumpRingInfo()
203
204 Description:
205         Dump out to console the ring buffer info
206
207 --*/
208 void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
209 {
210         u32 bytesAvailToWrite;
211         u32 bytesAvailToRead;
212
213         GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
214
215         DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
216                 Prefix,
217                 RingInfo,
218                 RingInfo->RingBuffer->Buffer,
219                 bytesAvailToWrite,
220                 bytesAvailToRead,
221                 RingInfo->RingBuffer->ReadIndex,
222                 RingInfo->RingBuffer->WriteIndex);
223 }
224
225
226 /* Internal routines */
227
228 static u32
229 CopyToRingBuffer(
230         RING_BUFFER_INFO        *RingInfo,
231         u32                             StartWriteOffset,
232         void *                          Src,
233         u32                             SrcLen);
234
235 static u32
236 CopyFromRingBuffer(
237         RING_BUFFER_INFO        *RingInfo,
238         void *                          Dest,
239         u32                             DestLen,
240         u32                             StartReadOffset);
241
242
243
244 /*++
245
246 Name:
247         RingBufferGetDebugInfo()
248
249 Description:
250         Get various debug metrics for the specified ring buffer
251
252 --*/
253 void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
254                             RING_BUFFER_DEBUG_INFO *DebugInfo)
255 {
256         u32 bytesAvailToWrite;
257         u32 bytesAvailToRead;
258
259         if (RingInfo->RingBuffer)
260         {
261                 GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
262
263                 DebugInfo->BytesAvailToRead = bytesAvailToRead;
264                 DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
265                 DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
266                 DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
267
268                 DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
269         }
270 }
271
272
273 /*++
274
275 Name:
276         GetRingBufferInterruptMask()
277
278 Description:
279         Get the interrupt mask for the specified ring buffer
280
281 --*/
282 u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *rbi)
283 {
284         return rbi->RingBuffer->InterruptMask;
285 }
286
287 /*++
288
289 Name:
290         RingBufferInit()
291
292 Description:
293         Initialize the ring buffer
294
295 --*/
296 int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
297 {
298         ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE);
299
300         memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
301
302         RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
303         RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
304
305         RingInfo->RingSize = BufferLen;
306         RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
307
308         spin_lock_init(&RingInfo->ring_lock);
309
310         return 0;
311 }
312
313 /*++
314
315 Name:
316         RingBufferCleanup()
317
318 Description:
319         Cleanup the ring buffer
320
321 --*/
322 void RingBufferCleanup(RING_BUFFER_INFO* RingInfo)
323 {
324 }
325
326 /*++
327
328 Name:
329         RingBufferWrite()
330
331 Description:
332         Write to the ring buffer
333
334 --*/
335 int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
336                     struct scatterlist *sglist, u32 sgcount)
337 {
338         int i=0;
339         u32 byteAvailToWrite;
340         u32 byteAvailToRead;
341         u32 totalBytesToWrite=0;
342
343         struct scatterlist *sg;
344         volatile u32 nextWriteLocation;
345         u64 prevIndices=0;
346         unsigned long flags;
347
348         DPRINT_ENTER(VMBUS);
349
350         for_each_sg(sglist, sg, sgcount, i)
351         {
352                 totalBytesToWrite += sg->length;
353         }
354
355         totalBytesToWrite += sizeof(u64);
356
357         spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
358
359         GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
360
361         DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
362
363         /* DumpRingInfo(OutRingInfo, "BEFORE "); */
364
365         /* If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer */
366         /* is empty since the read index == write index */
367         if (byteAvailToWrite <= totalBytesToWrite)
368         {
369                 DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
370
371                 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
372
373                 DPRINT_EXIT(VMBUS);
374
375                 return -1;
376         }
377
378         /* Write to the ring buffer */
379         nextWriteLocation = GetNextWriteLocation(OutRingInfo);
380
381         for_each_sg(sglist, sg, sgcount, i)
382         {
383                 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
384                                                      nextWriteLocation,
385                                                      sg_virt(sg),
386                                                      sg->length);
387         }
388
389         /* Set previous packet start */
390         prevIndices = GetRingBufferIndices(OutRingInfo);
391
392         nextWriteLocation = CopyToRingBuffer(OutRingInfo,
393                                              nextWriteLocation,
394                                              &prevIndices,
395                                              sizeof(u64));
396
397         /* Make sure we flush all writes before updating the writeIndex */
398         mb();
399
400         /* Now, update the write location */
401         SetNextWriteLocation(OutRingInfo, nextWriteLocation);
402
403         /* DumpRingInfo(OutRingInfo, "AFTER "); */
404
405         spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
406
407         DPRINT_EXIT(VMBUS);
408
409         return 0;
410 }
411
412
413 /*++
414
415 Name:
416         RingBufferPeek()
417
418 Description:
419         Read without advancing the read index
420
421 --*/
422 int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
423 {
424         u32 bytesAvailToWrite;
425         u32 bytesAvailToRead;
426         u32 nextReadLocation=0;
427         unsigned long flags;
428
429         spin_lock_irqsave(&InRingInfo->ring_lock, flags);
430
431         GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
432
433         /* Make sure there is something to read */
434         if (bytesAvailToRead < BufferLen )
435         {
436                 /* DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); */
437
438                 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
439
440                 return -1;
441         }
442
443         /* Convert to byte offset */
444         nextReadLocation = GetNextReadLocation(InRingInfo);
445
446         nextReadLocation = CopyFromRingBuffer(InRingInfo,
447                                                                                         Buffer,
448                                                                                         BufferLen,
449                                                                                         nextReadLocation);
450
451         spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
452
453         return 0;
454 }
455
456
457 /*++
458
459 Name:
460         RingBufferRead()
461
462 Description:
463         Read and advance the read index
464
465 --*/
466 int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
467                    u32 BufferLen, u32 Offset)
468 {
469         u32 bytesAvailToWrite;
470         u32 bytesAvailToRead;
471         u32 nextReadLocation=0;
472         u64 prevIndices=0;
473         unsigned long flags;
474
475         ASSERT(BufferLen > 0);
476
477         spin_lock_irqsave(&InRingInfo->ring_lock, flags);
478
479         GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
480
481         DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
482
483         /* DumpRingInfo(InRingInfo, "BEFORE "); */
484
485         /* Make sure there is something to read */
486         if (bytesAvailToRead < BufferLen )
487         {
488                 DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
489
490                 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
491
492                 return -1;
493         }
494
495         nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
496
497         nextReadLocation = CopyFromRingBuffer(InRingInfo,
498                                                                                         Buffer,
499                                                                                         BufferLen,
500                                                                                         nextReadLocation);
501
502         nextReadLocation = CopyFromRingBuffer(InRingInfo,
503                                                                                         &prevIndices,
504                                                                                         sizeof(u64),
505                                                                                         nextReadLocation);
506
507         /* Make sure all reads are done before we update the read index since */
508         /* the writer may start writing to the read area once the read index is updated */
509         mb();
510
511         /* Update the read index */
512         SetNextReadLocation(InRingInfo, nextReadLocation);
513
514         /* DumpRingInfo(InRingInfo, "AFTER "); */
515
516         spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
517
518         return 0;
519 }
520
521
522 /*++
523
524 Name:
525         CopyToRingBuffer()
526
527 Description:
528         Helper routine to copy from source to ring buffer.
529         Assume there is enough room. Handles wrap-around in dest case only!!
530
531 --*/
532 static u32
533 CopyToRingBuffer(
534         RING_BUFFER_INFO        *RingInfo,
535         u32                             StartWriteOffset,
536         void *                          Src,
537         u32                             SrcLen)
538 {
539         void * ringBuffer=GetRingBuffer(RingInfo);
540         u32 ringBufferSize=GetRingBufferSize(RingInfo);
541         u32 fragLen;
542
543         if (SrcLen > ringBufferSize - StartWriteOffset) /* wrap-around detected! */
544         {
545                 DPRINT_DBG(VMBUS, "wrap-around detected!");
546
547                 fragLen = ringBufferSize - StartWriteOffset;
548                 memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
549                 memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
550         }
551         else
552         {
553                 memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
554         }
555
556         StartWriteOffset += SrcLen;
557         StartWriteOffset %= ringBufferSize;
558
559         return StartWriteOffset;
560 }
561
562
563 /*++
564
565 Name:
566         CopyFromRingBuffer()
567
568 Description:
569         Helper routine to copy to source from ring buffer.
570         Assume there is enough room. Handles wrap-around in src case only!!
571
572 --*/
573 static u32
574 CopyFromRingBuffer(
575         RING_BUFFER_INFO        *RingInfo,
576         void *                          Dest,
577         u32                             DestLen,
578         u32                             StartReadOffset)
579 {
580         void * ringBuffer=GetRingBuffer(RingInfo);
581         u32 ringBufferSize=GetRingBufferSize(RingInfo);
582
583         u32 fragLen;
584
585         if (DestLen > ringBufferSize - StartReadOffset) /* wrap-around detected at the src */
586         {
587                 DPRINT_DBG(VMBUS, "src wrap-around detected!");
588
589                 fragLen = ringBufferSize - StartReadOffset;
590
591                 memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
592                 memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
593         }
594         else
595         {
596                 memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
597         }
598
599         StartReadOffset += DestLen;
600         StartReadOffset %= ringBufferSize;
601
602         return StartReadOffset;
603 }
604
605
606 /* eof */