staging: hv: Remove all unneeded DPRINT from hv_utils
[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>
645954c5 26#include "logging.h"
8f078ca6 27#include "ring_buffer.h"
3e7ee490 28
3e7ee490 29
454f18a9
BP
30/* #defines */
31
32
33/* Amount of space to write to */
0686e4f4 34#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
3e7ee490
HJ
35
36
37/*++
38
39Name:
1ac58644 40 get_ringbuffer_availbytes()
3e7ee490
HJ
41
42Description:
43 Get number of bytes available to read and to write to
44 for the specified ring buffer
45
46--*/
47static inline void
1ac58644
HZ
48get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
49 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 */
82f8bd40
HZ
54 read_loc = rbi->ring_buffer->read_index;
55 write_loc = rbi->ring_buffer->write_index;
3e7ee490 56
82f8bd40
HZ
57 *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->ring_datasize);
58 *read = rbi->ring_datasize - *write;
3e7ee490
HJ
59}
60
61/*++
62
63Name:
1ac58644 64 get_next_write_location()
3e7ee490
HJ
65
66Description:
67 Get the next write location for the specified ring buffer
68
69--*/
4d643114 70static inline u32
1ac58644 71get_next_write_location(struct hv_ring_buffer_info *ring_info)
3e7ee490 72{
fc8c72eb 73 u32 next = ring_info->ring_buffer->write_index;
3e7ee490 74
fc8c72eb 75 /* ASSERT(next < ring_info->RingDataSize); */
3e7ee490
HJ
76
77 return next;
78}
79
80/*++
81
82Name:
1ac58644 83 set_next_write_location()
3e7ee490
HJ
84
85Description:
86 Set the next write location for the specified ring buffer
87
88--*/
89static inline void
1ac58644 90set_next_write_location(struct hv_ring_buffer_info *ring_info,
fc8c72eb 91 u32 next_write_location)
3e7ee490 92{
fc8c72eb 93 ring_info->ring_buffer->write_index = next_write_location;
3e7ee490
HJ
94}
95
96/*++
97
98Name:
1ac58644 99 get_next_read_location()
3e7ee490
HJ
100
101Description:
102 Get the next read location for the specified ring buffer
103
104--*/
4d643114 105static inline u32
1ac58644 106get_next_read_location(struct hv_ring_buffer_info *ring_info)
3e7ee490 107{
fc8c72eb 108 u32 next = ring_info->ring_buffer->read_index;
3e7ee490 109
fc8c72eb 110 /* ASSERT(next < ring_info->RingDataSize); */
3e7ee490
HJ
111
112 return next;
113}
114
115/*++
116
117Name:
1ac58644 118 get_next_readlocation_withoffset()
3e7ee490
HJ
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
1ac58644
HZ
126get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info,
127 u32 offset)
3e7ee490 128{
fc8c72eb 129 u32 next = ring_info->ring_buffer->read_index;
3e7ee490 130
fc8c72eb
HZ
131 /* ASSERT(next < ring_info->RingDataSize); */
132 next += offset;
133 next %= ring_info->ring_datasize;
3e7ee490
HJ
134
135 return next;
136}
137
138/*++
139
140Name:
1ac58644 141 set_next_read_location()
3e7ee490
HJ
142
143Description:
144 Set the next read location for the specified ring buffer
145
146--*/
147static inline void
1ac58644 148set_next_read_location(struct hv_ring_buffer_info *ring_info,
fc8c72eb 149 u32 next_read_location)
3e7ee490 150{
fc8c72eb 151 ring_info->ring_buffer->read_index = next_read_location;
3e7ee490
HJ
152}
153
154
155/*++
156
157Name:
1ac58644 158 get_ring_buffer()
3e7ee490
HJ
159
160Description:
161 Get the start of the ring buffer
162
163--*/
8282c400 164static inline void *
1ac58644 165get_ring_buffer(struct hv_ring_buffer_info *ring_info)
3e7ee490 166{
fc8c72eb 167 return (void *)ring_info->ring_buffer->buffer;
3e7ee490
HJ
168}
169
170
171/*++
172
173Name:
1ac58644 174 get_ring_buffersize()
3e7ee490
HJ
175
176Description:
177 Get the size of the ring buffer
178
179--*/
4d643114 180static inline u32
1ac58644 181get_ring_buffersize(struct hv_ring_buffer_info *ring_info)
3e7ee490 182{
fc8c72eb 183 return ring_info->ring_datasize;
3e7ee490
HJ
184}
185
186/*++
187
188Name:
1ac58644 189 get_ring_bufferindices()
3e7ee490
HJ
190
191Description:
59471438 192 Get the read and write indices as u64 of the specified ring buffer
3e7ee490
HJ
193
194--*/
59471438 195static inline u64
1ac58644 196get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
3e7ee490 197{
fc8c72eb 198 return (u64)ring_info->ring_buffer->write_index << 32;
3e7ee490
HJ
199}
200
201
202/*++
203
204Name:
1ac58644 205 dump_ring_info()
3e7ee490
HJ
206
207Description:
208 Dump out to console the ring buffer info
209
210--*/
1ac58644 211void dump_ring_info(struct hv_ring_buffer_info *ring_info, char *prefix)
3e7ee490 212{
fc8c72eb
HZ
213 u32 bytes_avail_towrite;
214 u32 bytes_avail_toread;
3e7ee490 215
1ac58644 216 get_ringbuffer_availbytes(ring_info,
fc8c72eb
HZ
217 &bytes_avail_toread,
218 &bytes_avail_towrite);
3e7ee490 219
4408f531
B
220 DPRINT(VMBUS,
221 DEBUG_RING_LVL,
222 "%s <<ringinfo %p buffer %p avail write %u "
223 "avail read %u read idx %u write idx %u>>",
fc8c72eb
HZ
224 prefix,
225 ring_info,
226 ring_info->ring_buffer->buffer,
227 bytes_avail_towrite,
228 bytes_avail_toread,
229 ring_info->ring_buffer->read_index,
230 ring_info->ring_buffer->write_index);
3e7ee490
HJ
231}
232
454f18a9
BP
233
234/* Internal routines */
235
4d643114 236static u32
1ac58644 237copyto_ringbuffer(
fc8c72eb
HZ
238 struct hv_ring_buffer_info *ring_info,
239 u32 start_write_offset,
240 void *src,
241 u32 srclen);
3e7ee490 242
4d643114 243static u32
1ac58644 244copyfrom_ringbuffer(
fc8c72eb
HZ
245 struct hv_ring_buffer_info *ring_info,
246 void *dest,
247 u32 destlen,
248 u32 start_read_offset);
3e7ee490
HJ
249
250
251
252/*++
253
254Name:
1ac58644 255 ringbuffer_get_debuginfo()
3e7ee490
HJ
256
257Description:
258 Get various debug metrics for the specified ring buffer
259
260--*/
1ac58644 261void ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
80682b7a 262 struct hv_ring_buffer_debug_info *debug_info)
3e7ee490 263{
fc8c72eb
HZ
264 u32 bytes_avail_towrite;
265 u32 bytes_avail_toread;
3e7ee490 266
fc8c72eb 267 if (ring_info->ring_buffer) {
1ac58644 268 get_ringbuffer_availbytes(ring_info,
fc8c72eb
HZ
269 &bytes_avail_toread,
270 &bytes_avail_towrite);
3e7ee490 271
fc8c72eb
HZ
272 debug_info->bytes_avail_toread = bytes_avail_toread;
273 debug_info->bytes_avail_towrite = bytes_avail_towrite;
82f8bd40 274 debug_info->current_read_index =
fc8c72eb 275 ring_info->ring_buffer->read_index;
82f8bd40 276 debug_info->current_write_index =
fc8c72eb 277 ring_info->ring_buffer->write_index;
82f8bd40 278 debug_info->current_interrupt_mask =
fc8c72eb 279 ring_info->ring_buffer->interrupt_mask;
3e7ee490
HJ
280 }
281}
282
283
284/*++
285
286Name:
1ac58644 287 get_ringbuffer_interrupt_mask()
3e7ee490
HJ
288
289Description:
290 Get the interrupt mask for the specified ring buffer
291
292--*/
1ac58644 293u32 get_ringbuffer_interrupt_mask(struct hv_ring_buffer_info *rbi)
3e7ee490 294{
82f8bd40 295 return rbi->ring_buffer->interrupt_mask;
3e7ee490
HJ
296}
297
298/*++
299
300Name:
1ac58644 301 ringbuffer_init()
3e7ee490
HJ
302
303Description:
304 Initialize the ring buffer
305
306--*/
1ac58644 307int ringbuffer_init(struct hv_ring_buffer_info *ring_info,
fc8c72eb 308 void *buffer, u32 buflen)
3e7ee490 309{
4a1b3acc 310 if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
3324fb40 311 return -EINVAL;
3e7ee490 312
fc8c72eb 313 memset(ring_info, 0, sizeof(struct hv_ring_buffer_info));
3e7ee490 314
fc8c72eb
HZ
315 ring_info->ring_buffer = (struct hv_ring_buffer *)buffer;
316 ring_info->ring_buffer->read_index =
317 ring_info->ring_buffer->write_index = 0;
3e7ee490 318
fc8c72eb
HZ
319 ring_info->ring_size = buflen;
320 ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
3e7ee490 321
fc8c72eb 322 spin_lock_init(&ring_info->ring_lock);
3e7ee490
HJ
323
324 return 0;
325}
326
327/*++
328
329Name:
1ac58644 330 ringbuffer_cleanup()
3e7ee490
HJ
331
332Description:
333 Cleanup the ring buffer
334
335--*/
1ac58644 336void ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
3e7ee490 337{
3e7ee490
HJ
338}
339
340/*++
341
342Name:
1ac58644 343 ringbuffer_write()
3e7ee490
HJ
344
345Description:
346 Write to the ring buffer
347
348--*/
1ac58644 349int ringbuffer_write(struct hv_ring_buffer_info *outring_info,
3523a805 350 struct scatterlist *sglist, u32 sgcount)
3e7ee490 351{
4408f531 352 int i = 0;
fc8c72eb
HZ
353 u32 bytes_avail_towrite;
354 u32 bytes_avail_toread;
355 u32 totalbytes_towrite = 0;
3e7ee490 356
b219b3f7 357 struct scatterlist *sg;
fc8c72eb
HZ
358 volatile u32 next_write_location;
359 u64 prev_indices = 0;
a98f96ee 360 unsigned long flags;
3e7ee490 361
b219b3f7 362 for_each_sg(sglist, sg, sgcount, i)
3e7ee490 363 {
fc8c72eb 364 totalbytes_towrite += sg->length;
3e7ee490
HJ
365 }
366
fc8c72eb 367 totalbytes_towrite += sizeof(u64);
3e7ee490 368
fc8c72eb 369 spin_lock_irqsave(&outring_info->ring_lock, flags);
3e7ee490 370
1ac58644 371 get_ringbuffer_availbytes(outring_info,
fc8c72eb
HZ
372 &bytes_avail_toread,
373 &bytes_avail_towrite);
3e7ee490 374
fc8c72eb 375 /* Dumpring_info(Outring_info, "BEFORE "); */
3e7ee490 376
4408f531
B
377 /* If there is only room for the packet, assume it is full. */
378 /* Otherwise, the next time around, we think the ring buffer */
454f18a9 379 /* is empty since the read index == write index */
fc8c72eb 380 if (bytes_avail_towrite <= totalbytes_towrite) {
fc8c72eb 381 spin_unlock_irqrestore(&outring_info->ring_lock, flags);
3e7ee490
HJ
382 return -1;
383 }
384
454f18a9 385 /* Write to the ring buffer */
1ac58644 386 next_write_location = get_next_write_location(outring_info);
3e7ee490 387
b219b3f7 388 for_each_sg(sglist, sg, sgcount, i)
3e7ee490 389 {
1ac58644 390 next_write_location = copyto_ringbuffer(outring_info,
fc8c72eb 391 next_write_location,
b219b3f7
NP
392 sg_virt(sg),
393 sg->length);
3e7ee490
HJ
394 }
395
454f18a9 396 /* Set previous packet start */
1ac58644 397 prev_indices = get_ring_bufferindices(outring_info);
3e7ee490 398
1ac58644 399 next_write_location = copyto_ringbuffer(outring_info,
fc8c72eb
HZ
400 next_write_location,
401 &prev_indices,
b219b3f7 402 sizeof(u64));
3e7ee490 403
454f18a9 404 /* Make sure we flush all writes before updating the writeIndex */
28b6ca9c 405 mb();
3e7ee490 406
454f18a9 407 /* Now, update the write location */
1ac58644 408 set_next_write_location(outring_info, next_write_location);
3e7ee490 409
fc8c72eb 410 /* Dumpring_info(Outring_info, "AFTER "); */
3e7ee490 411
fc8c72eb 412 spin_unlock_irqrestore(&outring_info->ring_lock, flags);
3e7ee490
HJ
413 return 0;
414}
415
416
417/*++
418
419Name:
1ac58644 420 ringbuffer_peek()
3e7ee490
HJ
421
422Description:
423 Read without advancing the read index
424
425--*/
1ac58644 426int ringbuffer_peek(struct hv_ring_buffer_info *Inring_info,
fc8c72eb 427 void *Buffer, u32 buflen)
3e7ee490 428{
fc8c72eb
HZ
429 u32 bytes_avail_towrite;
430 u32 bytes_avail_toread;
431 u32 next_read_location = 0;
a98f96ee 432 unsigned long flags;
3e7ee490 433
fc8c72eb 434 spin_lock_irqsave(&Inring_info->ring_lock, flags);
3e7ee490 435
1ac58644 436 get_ringbuffer_availbytes(Inring_info,
fc8c72eb
HZ
437 &bytes_avail_toread,
438 &bytes_avail_towrite);
3e7ee490 439
454f18a9 440 /* Make sure there is something to read */
fc8c72eb 441 if (bytes_avail_toread < buflen) {
4408f531
B
442 /* DPRINT_DBG(VMBUS,
443 "got callback but not enough to read "
444 "<avail to read %d read size %d>!!",
fc8c72eb 445 bytes_avail_toread,
4408f531 446 BufferLen); */
3e7ee490 447
fc8c72eb 448 spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
3e7ee490
HJ
449
450 return -1;
451 }
452
454f18a9 453 /* Convert to byte offset */
1ac58644 454 next_read_location = get_next_read_location(Inring_info);
3e7ee490 455
1ac58644 456 next_read_location = copyfrom_ringbuffer(Inring_info,
4408f531 457 Buffer,
fc8c72eb
HZ
458 buflen,
459 next_read_location);
3e7ee490 460
fc8c72eb 461 spin_unlock_irqrestore(&Inring_info->ring_lock, flags);
3e7ee490
HJ
462
463 return 0;
464}
465
466
467/*++
468
469Name:
1ac58644 470 ringbuffer_read()
3e7ee490
HJ
471
472Description:
473 Read and advance the read index
474
475--*/
1ac58644 476int ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer,
fc8c72eb 477 u32 buflen, u32 offset)
3e7ee490 478{
fc8c72eb
HZ
479 u32 bytes_avail_towrite;
480 u32 bytes_avail_toread;
481 u32 next_read_location = 0;
482 u64 prev_indices = 0;
a98f96ee 483 unsigned long flags;
3e7ee490 484
fc8c72eb 485 if (buflen <= 0)
a16e1485 486 return -EINVAL;
3e7ee490 487
fc8c72eb 488 spin_lock_irqsave(&inring_info->ring_lock, flags);
3e7ee490 489
1ac58644 490 get_ringbuffer_availbytes(inring_info,
fc8c72eb
HZ
491 &bytes_avail_toread,
492 &bytes_avail_towrite);
3e7ee490 493
fc8c72eb 494 /* Dumpring_info(Inring_info, "BEFORE "); */
3e7ee490 495
454f18a9 496 /* Make sure there is something to read */
fc8c72eb 497 if (bytes_avail_toread < buflen) {
fc8c72eb 498 spin_unlock_irqrestore(&inring_info->ring_lock, flags);
3e7ee490
HJ
499
500 return -1;
501 }
502
1ac58644
HZ
503 next_read_location =
504 get_next_readlocation_withoffset(inring_info, offset);
3e7ee490 505
1ac58644 506 next_read_location = copyfrom_ringbuffer(inring_info,
fc8c72eb
HZ
507 buffer,
508 buflen,
509 next_read_location);
3e7ee490 510
1ac58644 511 next_read_location = copyfrom_ringbuffer(inring_info,
fc8c72eb 512 &prev_indices,
4408f531 513 sizeof(u64),
fc8c72eb 514 next_read_location);
3e7ee490 515
454f18a9 516 /* Make sure all reads are done before we update the read index since */
4408f531
B
517 /* the writer may start writing to the read area once the read index */
518 /*is updated */
28b6ca9c 519 mb();
3e7ee490 520
454f18a9 521 /* Update the read index */
1ac58644 522 set_next_read_location(inring_info, next_read_location);
3e7ee490 523
fc8c72eb 524 /* Dumpring_info(Inring_info, "AFTER "); */
3e7ee490 525
fc8c72eb 526 spin_unlock_irqrestore(&inring_info->ring_lock, flags);
3e7ee490
HJ
527
528 return 0;
529}
530
531
532/*++
533
534Name:
1ac58644 535 copyto_ringbuffer()
3e7ee490
HJ
536
537Description:
538 Helper routine to copy from source to ring buffer.
539 Assume there is enough room. Handles wrap-around in dest case only!!
540
541--*/
bd1de709 542static u32
1ac58644 543copyto_ringbuffer(
fc8c72eb
HZ
544 struct hv_ring_buffer_info *ring_info,
545 u32 start_write_offset,
546 void *src,
547 u32 srclen)
3e7ee490 548{
1ac58644
HZ
549 void *ring_buffer = get_ring_buffer(ring_info);
550 u32 ring_buffer_size = get_ring_buffersize(ring_info);
fc8c72eb 551 u32 frag_len;
3e7ee490 552
4408f531 553 /* wrap-around detected! */
fc8c72eb 554 if (srclen > ring_buffer_size - start_write_offset) {
fc8c72eb
HZ
555 frag_len = ring_buffer_size - start_write_offset;
556 memcpy(ring_buffer + start_write_offset, src, frag_len);
557 memcpy(ring_buffer, src + frag_len, srclen - frag_len);
4408f531 558 } else
fc8c72eb 559 memcpy(ring_buffer + start_write_offset, src, srclen);
3e7ee490 560
fc8c72eb
HZ
561 start_write_offset += srclen;
562 start_write_offset %= ring_buffer_size;
3e7ee490 563
fc8c72eb 564 return start_write_offset;
3e7ee490
HJ
565}
566
567
568/*++
569
570Name:
1ac58644 571 copyfrom_ringbuffer()
3e7ee490
HJ
572
573Description:
574 Helper routine to copy to source from ring buffer.
575 Assume there is enough room. Handles wrap-around in src case only!!
576
577--*/
bd1de709 578static u32
1ac58644 579copyfrom_ringbuffer(
fc8c72eb
HZ
580 struct hv_ring_buffer_info *ring_info,
581 void *dest,
582 u32 destlen,
583 u32 start_read_offset)
3e7ee490 584{
1ac58644
HZ
585 void *ring_buffer = get_ring_buffer(ring_info);
586 u32 ring_buffer_size = get_ring_buffersize(ring_info);
3e7ee490 587
fc8c72eb 588 u32 frag_len;
3e7ee490 589
4408f531 590 /* wrap-around detected at the src */
fc8c72eb 591 if (destlen > ring_buffer_size - start_read_offset) {
fc8c72eb 592 frag_len = ring_buffer_size - start_read_offset;
3e7ee490 593
fc8c72eb
HZ
594 memcpy(dest, ring_buffer + start_read_offset, frag_len);
595 memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
4408f531
B
596 } else
597
fc8c72eb 598 memcpy(dest, ring_buffer + start_read_offset, destlen);
4408f531 599
3e7ee490 600
fc8c72eb
HZ
601 start_read_offset += destlen;
602 start_read_offset %= ring_buffer_size;
3e7ee490 603
fc8c72eb 604 return start_read_offset;
3e7ee490
HJ
605}
606
607
454f18a9 608/* eof */
This page took 0.2695 seconds and 5 git commands to generate.