blob: 17bc7626f70a71d991aa2bdc9c50a960657e4f90 [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
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
Greg Kroah-Hartmana0086dc2009-08-17 17:22:08 -070024#include <linux/kernel.h>
25#include <linux/mm.h>
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070026#include "osd.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070027#include "logging.h"
Greg Kroah-Hartman8f078ca2010-05-05 22:22:35 -070028#include "ring_buffer.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070029
Hank Janssen3e7ee492009-07-13 16:02:34 -070030
Bill Pemberton454f18a2009-07-27 16:47:24 -040031/* #defines */
32
33
34/* Amount of space to write to */
Lars Lindley0686e4f2010-03-11 23:51:23 +010035#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
Hank Janssen3e7ee492009-07-13 16:02:34 -070036
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
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -070049GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write)
Hank Janssen3e7ee492009-07-13 16:02:34 -070050{
C. Bartlett4408f532010-02-03 15:34:27 +000051 u32 read_loc, write_loc;
Hank Janssen3e7ee492009-07-13 16:02:34 -070052
Bill Pemberton454f18a2009-07-27 16:47:24 -040053 /* Capture the read/write indices before they changed */
Hank Janssen3e7ee492009-07-13 16:02:34 -070054 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--*/
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -070070static inline u32
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -070071GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -070072{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -070073 u32 next = RingInfo->RingBuffer->WriteIndex;
Hank Janssen3e7ee492009-07-13 16:02:34 -070074
Bill Pemberton1bbdd7a2010-05-05 15:27:48 -040075 /* ASSERT(next < RingInfo->RingDataSize); */
Hank Janssen3e7ee492009-07-13 16:02:34 -070076
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
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -070090SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo,
91 u32 NextWriteLocation)
Hank Janssen3e7ee492009-07-13 16:02:34 -070092{
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--*/
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700105static inline u32
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700106GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700107{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700108 u32 next = RingInfo->RingBuffer->ReadIndex;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700109
Bill Pemberton1bbdd7a2010-05-05 15:27:48 -0400110 /* ASSERT(next < RingInfo->RingDataSize); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700111
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--*/
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700125static inline u32
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700126GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700127{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700128 u32 next = RingInfo->RingBuffer->ReadIndex;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700129
Bill Pemberton1bbdd7a2010-05-05 15:27:48 -0400130 /* ASSERT(next < RingInfo->RingDataSize); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700131 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
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700147SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700148{
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--*/
Greg Kroah-Hartman8282c402009-07-14 15:06:28 -0700162static inline void *
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700163GetRingBuffer(struct hv_ring_buffer_info *RingInfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700164{
Greg Kroah-Hartman8282c402009-07-14 15:06:28 -0700165 return (void *)RingInfo->RingBuffer->Buffer;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700166}
167
168
169/*++
170
171Name:
172 GetRingBufferSize()
173
174Description:
175 Get the size of the ring buffer
176
177--*/
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700178static inline u32
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700179GetRingBufferSize(struct hv_ring_buffer_info *RingInfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700180{
181 return RingInfo->RingDataSize;
182}
183
184/*++
185
186Name:
187 GetRingBufferIndices()
188
189Description:
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700190 Get the read and write indices as u64 of the specified ring buffer
Hank Janssen3e7ee492009-07-13 16:02:34 -0700191
192--*/
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700193static inline u64
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700194GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700195{
C. Bartlett4408f532010-02-03 15:34:27 +0000196 return ((u64)RingInfo->RingBuffer->WriteIndex << 32)
197 || RingInfo->RingBuffer->ReadIndex;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700198}
199
200
201/*++
202
203Name:
204 DumpRingInfo()
205
206Description:
207 Dump out to console the ring buffer info
208
209--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700210void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700211{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700212 u32 bytesAvailToWrite;
213 u32 bytesAvailToRead;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700214
C. Bartlett4408f532010-02-03 15:34:27 +0000215 GetRingBufferAvailBytes(RingInfo,
216 &bytesAvailToRead,
217 &bytesAvailToWrite);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700218
C. Bartlett4408f532010-02-03 15:34:27 +0000219 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>>",
Hank Janssen3e7ee492009-07-13 16:02:34 -0700223 Prefix,
224 RingInfo,
225 RingInfo->RingBuffer->Buffer,
226 bytesAvailToWrite,
227 bytesAvailToRead,
228 RingInfo->RingBuffer->ReadIndex,
229 RingInfo->RingBuffer->WriteIndex);
230}
231
Bill Pemberton454f18a2009-07-27 16:47:24 -0400232
233/* Internal routines */
234
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700235static u32
Hank Janssen3e7ee492009-07-13 16:02:34 -0700236CopyToRingBuffer(
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700237 struct hv_ring_buffer_info *RingInfo,
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700238 u32 StartWriteOffset,
C. Bartlett4408f532010-02-03 15:34:27 +0000239 void *Src,
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700240 u32 SrcLen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700241
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700242static u32
Hank Janssen3e7ee492009-07-13 16:02:34 -0700243CopyFromRingBuffer(
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700244 struct hv_ring_buffer_info *RingInfo,
C. Bartlett4408f532010-02-03 15:34:27 +0000245 void *Dest,
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700246 u32 DestLen,
247 u32 StartReadOffset);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700248
249
250
251/*++
252
253Name:
254 RingBufferGetDebugInfo()
255
256Description:
257 Get various debug metrics for the specified ring buffer
258
259--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700260void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
Greg Kroah-Hartman80682b72010-07-27 11:37:32 -0700261 struct hv_ring_buffer_debug_info *debug_info)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700262{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700263 u32 bytesAvailToWrite;
264 u32 bytesAvailToRead;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700265
C. Bartlett4408f532010-02-03 15:34:27 +0000266 if (RingInfo->RingBuffer) {
267 GetRingBufferAvailBytes(RingInfo,
268 &bytesAvailToRead,
269 &bytesAvailToWrite);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700270
Greg Kroah-Hartman80682b72010-07-27 11:37:32 -0700271 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;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700276 }
277}
278
279
280/*++
281
282Name:
283 GetRingBufferInterruptMask()
284
285Description:
286 Get the interrupt mask for the specified ring buffer
287
288--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700289u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700290{
291 return rbi->RingBuffer->InterruptMask;
292}
293
294/*++
295
296Name:
297 RingBufferInit()
298
299Description:
300 Initialize the ring buffer
301
302--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700303int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700304{
Greg Kroah-Hartman4a1b3ac2010-07-27 11:47:08 -0700305 if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
Bill Pemberton3324fb42010-05-05 15:27:49 -0400306 return -EINVAL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700307
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700308 memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700309
Greg Kroah-Hartman4a1b3ac2010-07-27 11:47:08 -0700310 RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700311 RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
312
313 RingInfo->RingSize = BufferLen;
Greg Kroah-Hartman4a1b3ac2010-07-27 11:47:08 -0700314 RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700315
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700316 spin_lock_init(&RingInfo->ring_lock);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700317
318 return 0;
319}
320
321/*++
322
323Name:
324 RingBufferCleanup()
325
326Description:
327 Cleanup the ring buffer
328
329--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700330void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700331{
Hank Janssen3e7ee492009-07-13 16:02:34 -0700332}
333
334/*++
335
336Name:
337 RingBufferWrite()
338
339Description:
340 Write to the ring buffer
341
342--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700343int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
Greg Kroah-Hartman3523a802009-08-17 17:22:08 -0700344 struct scatterlist *sglist, u32 sgcount)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700345{
C. Bartlett4408f532010-02-03 15:34:27 +0000346 int i = 0;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700347 u32 byteAvailToWrite;
348 u32 byteAvailToRead;
C. Bartlett4408f532010-02-03 15:34:27 +0000349 u32 totalBytesToWrite = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700350
Nicolas Palixb219b3f2009-07-30 17:37:23 +0200351 struct scatterlist *sg;
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700352 volatile u32 nextWriteLocation;
C. Bartlett4408f532010-02-03 15:34:27 +0000353 u64 prevIndices = 0;
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700354 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700355
Nicolas Palixb219b3f2009-07-30 17:37:23 +0200356 for_each_sg(sglist, sg, sgcount, i)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700357 {
Nicolas Palixb219b3f2009-07-30 17:37:23 +0200358 totalBytesToWrite += sg->length;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700359 }
360
Greg Kroah-Hartman59471432009-07-14 15:10:26 -0700361 totalBytesToWrite += sizeof(u64);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700362
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700363 spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700364
C. Bartlett4408f532010-02-03 15:34:27 +0000365 GetRingBufferAvailBytes(OutRingInfo,
366 &byteAvailToRead,
367 &byteAvailToWrite);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700368
369 DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
370
Bill Pemberton454f18a2009-07-27 16:47:24 -0400371 /* DumpRingInfo(OutRingInfo, "BEFORE "); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700372
C. Bartlett4408f532010-02-03 15:34:27 +0000373 /* If there is only room for the packet, assume it is full. */
374 /* Otherwise, the next time around, we think the ring buffer */
Bill Pemberton454f18a2009-07-27 16:47:24 -0400375 /* is empty since the read index == write index */
C. Bartlett4408f532010-02-03 15:34:27 +0000376 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);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700382
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700383 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700384 return -1;
385 }
386
Bill Pemberton454f18a2009-07-27 16:47:24 -0400387 /* Write to the ring buffer */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700388 nextWriteLocation = GetNextWriteLocation(OutRingInfo);
389
Nicolas Palixb219b3f2009-07-30 17:37:23 +0200390 for_each_sg(sglist, sg, sgcount, i)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700391 {
Nicolas Palixb219b3f2009-07-30 17:37:23 +0200392 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
393 nextWriteLocation,
394 sg_virt(sg),
395 sg->length);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700396 }
397
Bill Pemberton454f18a2009-07-27 16:47:24 -0400398 /* Set previous packet start */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700399 prevIndices = GetRingBufferIndices(OutRingInfo);
400
401 nextWriteLocation = CopyToRingBuffer(OutRingInfo,
Nicolas Palixb219b3f2009-07-30 17:37:23 +0200402 nextWriteLocation,
403 &prevIndices,
404 sizeof(u64));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700405
Bill Pemberton454f18a2009-07-27 16:47:24 -0400406 /* Make sure we flush all writes before updating the writeIndex */
Greg Kroah-Hartman28b6ca92009-07-16 12:34:20 -0700407 mb();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700408
Bill Pemberton454f18a2009-07-27 16:47:24 -0400409 /* Now, update the write location */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700410 SetNextWriteLocation(OutRingInfo, nextWriteLocation);
411
Bill Pemberton454f18a2009-07-27 16:47:24 -0400412 /* DumpRingInfo(OutRingInfo, "AFTER "); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700413
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700414 spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415 return 0;
416}
417
418
419/*++
420
421Name:
422 RingBufferPeek()
423
424Description:
425 Read without advancing the read index
426
427--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700428int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700429{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700430 u32 bytesAvailToWrite;
431 u32 bytesAvailToRead;
C. Bartlett4408f532010-02-03 15:34:27 +0000432 u32 nextReadLocation = 0;
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700433 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700434
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700435 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700436
C. Bartlett4408f532010-02-03 15:34:27 +0000437 GetRingBufferAvailBytes(InRingInfo,
438 &bytesAvailToRead,
439 &bytesAvailToWrite);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700440
Bill Pemberton454f18a2009-07-27 16:47:24 -0400441 /* Make sure there is something to read */
C. Bartlett4408f532010-02-03 15:34:27 +0000442 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); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700448
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700449 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700450
451 return -1;
452 }
453
Bill Pemberton454f18a2009-07-27 16:47:24 -0400454 /* Convert to byte offset */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700455 nextReadLocation = GetNextReadLocation(InRingInfo);
456
457 nextReadLocation = CopyFromRingBuffer(InRingInfo,
C. Bartlett4408f532010-02-03 15:34:27 +0000458 Buffer,
459 BufferLen,
460 nextReadLocation);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700461
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700462 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700463
464 return 0;
465}
466
467
468/*++
469
470Name:
471 RingBufferRead()
472
473Description:
474 Read and advance the read index
475
476--*/
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700477int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
Greg Kroah-Hartman3523a802009-08-17 17:22:08 -0700478 u32 BufferLen, u32 Offset)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700479{
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700480 u32 bytesAvailToWrite;
481 u32 bytesAvailToRead;
C. Bartlett4408f532010-02-03 15:34:27 +0000482 u32 nextReadLocation = 0;
483 u64 prevIndices = 0;
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700484 unsigned long flags;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700485
Bill Pembertona16e1482010-05-05 15:27:50 -0400486 if (BufferLen <= 0)
487 return -EINVAL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700488
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700489 spin_lock_irqsave(&InRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700490
C. Bartlett4408f532010-02-03 15:34:27 +0000491 GetRingBufferAvailBytes(InRingInfo,
492 &bytesAvailToRead,
493 &bytesAvailToWrite);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700494
495 DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
496
Bill Pemberton454f18a2009-07-27 16:47:24 -0400497 /* DumpRingInfo(InRingInfo, "BEFORE "); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700498
Bill Pemberton454f18a2009-07-27 16:47:24 -0400499 /* Make sure there is something to read */
C. Bartlett4408f532010-02-03 15:34:27 +0000500 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);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700506
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700507 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700508
509 return -1;
510 }
511
512 nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
513
514 nextReadLocation = CopyFromRingBuffer(InRingInfo,
C. Bartlett4408f532010-02-03 15:34:27 +0000515 Buffer,
516 BufferLen,
517 nextReadLocation);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700518
519 nextReadLocation = CopyFromRingBuffer(InRingInfo,
C. Bartlett4408f532010-02-03 15:34:27 +0000520 &prevIndices,
521 sizeof(u64),
522 nextReadLocation);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700523
Bill Pemberton454f18a2009-07-27 16:47:24 -0400524 /* Make sure all reads are done before we update the read index since */
C. Bartlett4408f532010-02-03 15:34:27 +0000525 /* the writer may start writing to the read area once the read index */
526 /*is updated */
Greg Kroah-Hartman28b6ca92009-07-16 12:34:20 -0700527 mb();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700528
Bill Pemberton454f18a2009-07-27 16:47:24 -0400529 /* Update the read index */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700530 SetNextReadLocation(InRingInfo, nextReadLocation);
531
Bill Pemberton454f18a2009-07-27 16:47:24 -0400532 /* DumpRingInfo(InRingInfo, "AFTER "); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700533
Greg Kroah-Hartmana98f96e2009-07-15 14:55:14 -0700534 spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700535
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--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700550static u32
Hank Janssen3e7ee492009-07-13 16:02:34 -0700551CopyToRingBuffer(
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700552 struct hv_ring_buffer_info *RingInfo,
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700553 u32 StartWriteOffset,
C. Bartlett4408f532010-02-03 15:34:27 +0000554 void *Src,
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700555 u32 SrcLen)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700556{
C. Bartlett4408f532010-02-03 15:34:27 +0000557 void *ringBuffer = GetRingBuffer(RingInfo);
558 u32 ringBufferSize = GetRingBufferSize(RingInfo);
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700559 u32 fragLen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700560
C. Bartlett4408f532010-02-03 15:34:27 +0000561 /* wrap-around detected! */
562 if (SrcLen > ringBufferSize - StartWriteOffset) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700563 DPRINT_DBG(VMBUS, "wrap-around detected!");
564
565 fragLen = ringBufferSize - StartWriteOffset;
566 memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
567 memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
C. Bartlett4408f532010-02-03 15:34:27 +0000568 } else
Hank Janssen3e7ee492009-07-13 16:02:34 -0700569 memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700570
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--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700588static u32
Hank Janssen3e7ee492009-07-13 16:02:34 -0700589CopyFromRingBuffer(
Greg Kroah-Hartman8a0e1c52010-07-27 11:43:11 -0700590 struct hv_ring_buffer_info *RingInfo,
C. Bartlett4408f532010-02-03 15:34:27 +0000591 void *Dest,
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700592 u32 DestLen,
593 u32 StartReadOffset)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700594{
C. Bartlett4408f532010-02-03 15:34:27 +0000595 void *ringBuffer = GetRingBuffer(RingInfo);
596 u32 ringBufferSize = GetRingBufferSize(RingInfo);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700597
Greg Kroah-Hartman4d643112009-07-14 15:09:36 -0700598 u32 fragLen;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700599
C. Bartlett4408f532010-02-03 15:34:27 +0000600 /* wrap-around detected at the src */
601 if (DestLen > ringBufferSize - StartReadOffset) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700602 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);
C. Bartlett4408f532010-02-03 15:34:27 +0000608 } else
609
Hank Janssen3e7ee492009-07-13 16:02:34 -0700610 memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
C. Bartlett4408f532010-02-03 15:34:27 +0000611
Hank Janssen3e7ee492009-07-13 16:02:34 -0700612
613 StartReadOffset += DestLen;
614 StartReadOffset %= ringBufferSize;
615
616 return StartReadOffset;
617}
618
619
Bill Pemberton454f18a2009-07-27 16:47:24 -0400620/* eof */