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