staging: hv: check return value of RingBufferInit()
[linux-2.6-block.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
a0086dc5
GKH
24#include <linux/kernel.h>
25#include <linux/mm.h>
4983b39a 26#include "osd.h"
645954c5 27#include "logging.h"
3e7ee490
HJ
28#include "RingBuffer.h"
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
40Name:
41 GetRingBufferAvailBytes()
42
43Description:
44 Get number of bytes available to read and to write to
45 for the specified ring buffer
46
47--*/
48static inline void
4d643114 49GetRingBufferAvailBytes(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
63Name:
64 GetNextWriteLocation()
65
66Description:
67 Get the next write location for the specified ring buffer
68
69--*/
4d643114 70static inline u32
4408f531 71GetNextWriteLocation(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
82Name:
83 SetNextWriteLocation()
84
85Description:
86 Set the next write location for the specified ring buffer
87
88--*/
89static inline void
4408f531 90SetNextWriteLocation(RING_BUFFER_INFO *RingInfo, u32 NextWriteLocation)
3e7ee490
HJ
91{
92 RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
93}
94
95/*++
96
97Name:
98 GetNextReadLocation()
99
100Description:
101 Get the next read location for the specified ring buffer
102
103--*/
4d643114 104static inline u32
4408f531 105GetNextReadLocation(RING_BUFFER_INFO *RingInfo)
3e7ee490 106{
4d643114 107 u32 next = RingInfo->RingBuffer->ReadIndex;
3e7ee490 108
1bbdd7a5 109 /* ASSERT(next < RingInfo->RingDataSize); */
3e7ee490
HJ
110
111 return next;
112}
113
114/*++
115
116Name:
117 GetNextReadLocationWithOffset()
118
119Description:
120 Get the next read location + offset for the specified ring buffer.
121 This allows the caller to skip
122
123--*/
4d643114 124static inline u32
4408f531 125GetNextReadLocationWithOffset(RING_BUFFER_INFO *RingInfo, u32 Offset)
3e7ee490 126{
4d643114 127 u32 next = RingInfo->RingBuffer->ReadIndex;
3e7ee490 128
1bbdd7a5 129 /* ASSERT(next < RingInfo->RingDataSize); */
3e7ee490
HJ
130 next += Offset;
131 next %= RingInfo->RingDataSize;
132
133 return next;
134}
135
136/*++
137
138Name:
139 SetNextReadLocation()
140
141Description:
142 Set the next read location for the specified ring buffer
143
144--*/
145static inline void
4408f531 146SetNextReadLocation(RING_BUFFER_INFO *RingInfo, u32 NextReadLocation)
3e7ee490
HJ
147{
148 RingInfo->RingBuffer->ReadIndex = NextReadLocation;
149}
150
151
152/*++
153
154Name:
155 GetRingBuffer()
156
157Description:
158 Get the start of the ring buffer
159
160--*/
8282c400 161static inline void *
4408f531 162GetRingBuffer(RING_BUFFER_INFO *RingInfo)
3e7ee490 163{
8282c400 164 return (void *)RingInfo->RingBuffer->Buffer;
3e7ee490
HJ
165}
166
167
168/*++
169
170Name:
171 GetRingBufferSize()
172
173Description:
174 Get the size of the ring buffer
175
176--*/
4d643114 177static inline u32
4408f531 178GetRingBufferSize(RING_BUFFER_INFO *RingInfo)
3e7ee490
HJ
179{
180 return RingInfo->RingDataSize;
181}
182
183/*++
184
185Name:
186 GetRingBufferIndices()
187
188Description:
59471438 189 Get the read and write indices as u64 of the specified ring buffer
3e7ee490
HJ
190
191--*/
59471438 192static inline u64
4408f531 193GetRingBufferIndices(RING_BUFFER_INFO *RingInfo)
3e7ee490 194{
4408f531
B
195 return ((u64)RingInfo->RingBuffer->WriteIndex << 32)
196 || RingInfo->RingBuffer->ReadIndex;
3e7ee490
HJ
197}
198
199
200/*++
201
202Name:
203 DumpRingInfo()
204
205Description:
206 Dump out to console the ring buffer info
207
208--*/
3523a805 209void DumpRingInfo(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 234static u32
3e7ee490
HJ
235CopyToRingBuffer(
236 RING_BUFFER_INFO *RingInfo,
4d643114 237 u32 StartWriteOffset,
4408f531 238 void *Src,
4d643114 239 u32 SrcLen);
3e7ee490 240
4d643114 241static u32
3e7ee490
HJ
242CopyFromRingBuffer(
243 RING_BUFFER_INFO *RingInfo,
4408f531 244 void *Dest,
4d643114
GKH
245 u32 DestLen,
246 u32 StartReadOffset);
3e7ee490
HJ
247
248
249
250/*++
251
252Name:
253 RingBufferGetDebugInfo()
254
255Description:
256 Get various debug metrics for the specified ring buffer
257
258--*/
3523a805
GKH
259void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
260 RING_BUFFER_DEBUG_INFO *DebugInfo)
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
HJ
269
270 DebugInfo->BytesAvailToRead = bytesAvailToRead;
271 DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
272 DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
273 DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
3e7ee490
HJ
274 DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
275 }
276}
277
278
279/*++
280
281Name:
282 GetRingBufferInterruptMask()
283
284Description:
285 Get the interrupt mask for the specified ring buffer
286
287--*/
3523a805 288u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *rbi)
3e7ee490
HJ
289{
290 return rbi->RingBuffer->InterruptMask;
291}
292
293/*++
294
295Name:
296 RingBufferInit()
297
298Description:
299 Initialize the ring buffer
300
301--*/
3523a805 302int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
3e7ee490 303{
3324fb40
BP
304 if (sizeof(RING_BUFFER) != PAGE_SIZE)
305 return -EINVAL;
3e7ee490
HJ
306
307 memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
308
4408f531 309 RingInfo->RingBuffer = (RING_BUFFER *)Buffer;
3e7ee490
HJ
310 RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
311
312 RingInfo->RingSize = BufferLen;
313 RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
314
a98f96ee 315 spin_lock_init(&RingInfo->ring_lock);
3e7ee490
HJ
316
317 return 0;
318}
319
320/*++
321
322Name:
323 RingBufferCleanup()
324
325Description:
326 Cleanup the ring buffer
327
328--*/
4408f531 329void RingBufferCleanup(RING_BUFFER_INFO *RingInfo)
3e7ee490 330{
3e7ee490
HJ
331}
332
333/*++
334
335Name:
336 RingBufferWrite()
337
338Description:
339 Write to the ring buffer
340
341--*/
3523a805
GKH
342int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
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
HJ
354
355 DPRINT_ENTER(VMBUS);
356
b219b3f7 357 for_each_sg(sglist, sg, sgcount, i)
3e7ee490 358 {
b219b3f7 359 totalBytesToWrite += sg->length;
3e7ee490
HJ
360 }
361
59471438 362 totalBytesToWrite += sizeof(u64);
3e7ee490 363
a98f96ee 364 spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
3e7ee490 365
4408f531
B
366 GetRingBufferAvailBytes(OutRingInfo,
367 &byteAvailToRead,
368 &byteAvailToWrite);
3e7ee490
HJ
369
370 DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
371
454f18a9 372 /* DumpRingInfo(OutRingInfo, "BEFORE "); */
3e7ee490 373
4408f531
B
374 /* If there is only room for the packet, assume it is full. */
375 /* Otherwise, the next time around, we think the ring buffer */
454f18a9 376 /* is empty since the read index == write index */
4408f531
B
377 if (byteAvailToWrite <= totalBytesToWrite) {
378 DPRINT_DBG(VMBUS,
379 "No more space left on outbound ring buffer "
380 "(needed %u, avail %u)",
381 totalBytesToWrite,
382 byteAvailToWrite);
3e7ee490 383
a98f96ee 384 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
3e7ee490
HJ
385
386 DPRINT_EXIT(VMBUS);
387
388 return -1;
389 }
390
454f18a9 391 /* Write to the ring buffer */
3e7ee490
HJ
392 nextWriteLocation = GetNextWriteLocation(OutRingInfo);
393
b219b3f7 394 for_each_sg(sglist, sg, sgcount, i)
3e7ee490 395 {
b219b3f7
NP
396 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
397 nextWriteLocation,
398 sg_virt(sg),
399 sg->length);
3e7ee490
HJ
400 }
401
454f18a9 402 /* Set previous packet start */
3e7ee490
HJ
403 prevIndices = GetRingBufferIndices(OutRingInfo);
404
405 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
b219b3f7
NP
406 nextWriteLocation,
407 &prevIndices,
408 sizeof(u64));
3e7ee490 409
454f18a9 410 /* Make sure we flush all writes before updating the writeIndex */
28b6ca9c 411 mb();
3e7ee490 412
454f18a9 413 /* Now, update the write location */
3e7ee490
HJ
414 SetNextWriteLocation(OutRingInfo, nextWriteLocation);
415
454f18a9 416 /* DumpRingInfo(OutRingInfo, "AFTER "); */
3e7ee490 417
a98f96ee 418 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
3e7ee490
HJ
419
420 DPRINT_EXIT(VMBUS);
421
422 return 0;
423}
424
425
426/*++
427
428Name:
429 RingBufferPeek()
430
431Description:
432 Read without advancing the read index
433
434--*/
3523a805 435int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
3e7ee490 436{
4d643114
GKH
437 u32 bytesAvailToWrite;
438 u32 bytesAvailToRead;
4408f531 439 u32 nextReadLocation = 0;
a98f96ee 440 unsigned long flags;
3e7ee490 441
a98f96ee 442 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
3e7ee490 443
4408f531
B
444 GetRingBufferAvailBytes(InRingInfo,
445 &bytesAvailToRead,
446 &bytesAvailToWrite);
3e7ee490 447
454f18a9 448 /* Make sure there is something to read */
4408f531
B
449 if (bytesAvailToRead < BufferLen) {
450 /* DPRINT_DBG(VMBUS,
451 "got callback but not enough to read "
452 "<avail to read %d read size %d>!!",
453 bytesAvailToRead,
454 BufferLen); */
3e7ee490 455
a98f96ee 456 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
457
458 return -1;
459 }
460
454f18a9 461 /* Convert to byte offset */
3e7ee490
HJ
462 nextReadLocation = GetNextReadLocation(InRingInfo);
463
464 nextReadLocation = CopyFromRingBuffer(InRingInfo,
4408f531
B
465 Buffer,
466 BufferLen,
467 nextReadLocation);
3e7ee490 468
a98f96ee 469 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
470
471 return 0;
472}
473
474
475/*++
476
477Name:
478 RingBufferRead()
479
480Description:
481 Read and advance the read index
482
483--*/
3523a805
GKH
484int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
485 u32 BufferLen, u32 Offset)
3e7ee490 486{
4d643114
GKH
487 u32 bytesAvailToWrite;
488 u32 bytesAvailToRead;
4408f531
B
489 u32 nextReadLocation = 0;
490 u64 prevIndices = 0;
a98f96ee 491 unsigned long flags;
3e7ee490
HJ
492
493 ASSERT(BufferLen > 0);
494
a98f96ee 495 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
3e7ee490 496
4408f531
B
497 GetRingBufferAvailBytes(InRingInfo,
498 &bytesAvailToRead,
499 &bytesAvailToWrite);
3e7ee490
HJ
500
501 DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
502
454f18a9 503 /* DumpRingInfo(InRingInfo, "BEFORE "); */
3e7ee490 504
454f18a9 505 /* Make sure there is something to read */
4408f531
B
506 if (bytesAvailToRead < BufferLen) {
507 DPRINT_DBG(VMBUS,
508 "got callback but not enough to read "
509 "<avail to read %d read size %d>!!",
510 bytesAvailToRead,
511 BufferLen);
3e7ee490 512
a98f96ee 513 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
514
515 return -1;
516 }
517
518 nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
519
520 nextReadLocation = CopyFromRingBuffer(InRingInfo,
4408f531
B
521 Buffer,
522 BufferLen,
523 nextReadLocation);
3e7ee490
HJ
524
525 nextReadLocation = CopyFromRingBuffer(InRingInfo,
4408f531
B
526 &prevIndices,
527 sizeof(u64),
528 nextReadLocation);
3e7ee490 529
454f18a9 530 /* Make sure all reads are done before we update the read index since */
4408f531
B
531 /* the writer may start writing to the read area once the read index */
532 /*is updated */
28b6ca9c 533 mb();
3e7ee490 534
454f18a9 535 /* Update the read index */
3e7ee490
HJ
536 SetNextReadLocation(InRingInfo, nextReadLocation);
537
454f18a9 538 /* DumpRingInfo(InRingInfo, "AFTER "); */
3e7ee490 539
a98f96ee 540 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
3e7ee490
HJ
541
542 return 0;
543}
544
545
546/*++
547
548Name:
549 CopyToRingBuffer()
550
551Description:
552 Helper routine to copy from source to ring buffer.
553 Assume there is enough room. Handles wrap-around in dest case only!!
554
555--*/
bd1de709 556static u32
3e7ee490
HJ
557CopyToRingBuffer(
558 RING_BUFFER_INFO *RingInfo,
4d643114 559 u32 StartWriteOffset,
4408f531 560 void *Src,
4d643114 561 u32 SrcLen)
3e7ee490 562{
4408f531
B
563 void *ringBuffer = GetRingBuffer(RingInfo);
564 u32 ringBufferSize = GetRingBufferSize(RingInfo);
4d643114 565 u32 fragLen;
3e7ee490 566
4408f531
B
567 /* wrap-around detected! */
568 if (SrcLen > ringBufferSize - StartWriteOffset) {
3e7ee490
HJ
569 DPRINT_DBG(VMBUS, "wrap-around detected!");
570
571 fragLen = ringBufferSize - StartWriteOffset;
572 memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
573 memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
4408f531 574 } else
3e7ee490 575 memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
3e7ee490
HJ
576
577 StartWriteOffset += SrcLen;
578 StartWriteOffset %= ringBufferSize;
579
580 return StartWriteOffset;
581}
582
583
584/*++
585
586Name:
587 CopyFromRingBuffer()
588
589Description:
590 Helper routine to copy to source from ring buffer.
591 Assume there is enough room. Handles wrap-around in src case only!!
592
593--*/
bd1de709 594static u32
3e7ee490
HJ
595CopyFromRingBuffer(
596 RING_BUFFER_INFO *RingInfo,
4408f531 597 void *Dest,
4d643114
GKH
598 u32 DestLen,
599 u32 StartReadOffset)
3e7ee490 600{
4408f531
B
601 void *ringBuffer = GetRingBuffer(RingInfo);
602 u32 ringBufferSize = GetRingBufferSize(RingInfo);
3e7ee490 603
4d643114 604 u32 fragLen;
3e7ee490 605
4408f531
B
606 /* wrap-around detected at the src */
607 if (DestLen > ringBufferSize - StartReadOffset) {
3e7ee490
HJ
608 DPRINT_DBG(VMBUS, "src wrap-around detected!");
609
610 fragLen = ringBufferSize - StartReadOffset;
611
612 memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
613 memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
4408f531
B
614 } else
615
3e7ee490 616 memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
4408f531 617
3e7ee490
HJ
618
619 StartReadOffset += DestLen;
620 StartReadOffset %= ringBufferSize;
621
622 return StartReadOffset;
623}
624
625
454f18a9 626/* eof */