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