summaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorstephen hemminger <stephen@networkplumber.org>2017-02-27 13:26:48 -0500
committerDavid S. Miller <davem@davemloft.net>2017-03-06 20:13:13 -0500
commitf3dd3f4797652c311df9c074436d420f1ad3566e (patch)
tree029e7602f0594a5b805828c33c40448cdb58623f /drivers/hv
parent50698d80f8bb1db989b7b9fa433f588fade5e382 (diff)
vmbus: introduce in-place packet iterator
This is mostly just a refactoring of previous functions (get_pkt_next_raw, put_pkt_raw and commit_rd_index) to make it easier to use for other drivers and NAPI. Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/hv')
-rw-r--r--drivers/hv/ring_buffer.c94
1 files changed, 93 insertions, 1 deletions
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index 87799e81af97..c3f1a9e33cef 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -32,6 +32,8 @@
32 32
33#include "hyperv_vmbus.h" 33#include "hyperv_vmbus.h"
34 34
35#define VMBUS_PKT_TRAILER 8
36
35/* 37/*
36 * When we write to the ring buffer, check if the host needs to 38 * When we write to the ring buffer, check if the host needs to
37 * be signaled. Here is the details of this protocol: 39 * be signaled. Here is the details of this protocol:
@@ -336,6 +338,12 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
336 return 0; 338 return 0;
337} 339}
338 340
341static inline void
342init_cached_read_index(struct hv_ring_buffer_info *rbi)
343{
344 rbi->cached_read_index = rbi->ring_buffer->read_index;
345}
346
339int hv_ringbuffer_read(struct vmbus_channel *channel, 347int hv_ringbuffer_read(struct vmbus_channel *channel,
340 void *buffer, u32 buflen, u32 *buffer_actual_len, 348 void *buffer, u32 buflen, u32 *buffer_actual_len,
341 u64 *requestid, bool raw) 349 u64 *requestid, bool raw)
@@ -366,7 +374,8 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
366 return ret; 374 return ret;
367 } 375 }
368 376
369 init_cached_read_index(channel); 377 init_cached_read_index(inring_info);
378
370 next_read_location = hv_get_next_read_location(inring_info); 379 next_read_location = hv_get_next_read_location(inring_info);
371 next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc, 380 next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
372 sizeof(desc), 381 sizeof(desc),
@@ -410,3 +419,86 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
410 419
411 return ret; 420 return ret;
412} 421}
422
423/*
424 * Determine number of bytes available in ring buffer after
425 * the current iterator (priv_read_index) location.
426 *
427 * This is similar to hv_get_bytes_to_read but with private
428 * read index instead.
429 */
430static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
431{
432 u32 priv_read_loc = rbi->priv_read_index;
433 u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
434
435 if (write_loc >= priv_read_loc)
436 return write_loc - priv_read_loc;
437 else
438 return (rbi->ring_datasize - priv_read_loc) + write_loc;
439}
440
441/*
442 * Get first vmbus packet from ring buffer after read_index
443 *
444 * If ring buffer is empty, returns NULL and no other action needed.
445 */
446struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
447{
448 struct hv_ring_buffer_info *rbi = &channel->inbound;
449
450 /* set state for later hv_signal_on_read() */
451 init_cached_read_index(rbi);
452
453 if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
454 return NULL;
455
456 return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
457}
458EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
459
460/*
461 * Get next vmbus packet from ring buffer.
462 *
463 * Advances the current location (priv_read_index) and checks for more
464 * data. If the end of the ring buffer is reached, then return NULL.
465 */
466struct vmpacket_descriptor *
467__hv_pkt_iter_next(struct vmbus_channel *channel,
468 const struct vmpacket_descriptor *desc)
469{
470 struct hv_ring_buffer_info *rbi = &channel->inbound;
471 u32 packetlen = desc->len8 << 3;
472 u32 dsize = rbi->ring_datasize;
473
474 /* bump offset to next potential packet */
475 rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
476 if (rbi->priv_read_index >= dsize)
477 rbi->priv_read_index -= dsize;
478
479 /* more data? */
480 if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
481 return NULL;
482 else
483 return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
484}
485EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
486
487/*
488 * Update host ring buffer after iterating over packets.
489 */
490void hv_pkt_iter_close(struct vmbus_channel *channel)
491{
492 struct hv_ring_buffer_info *rbi = &channel->inbound;
493
494 /*
495 * Make sure all reads are done before we update the read index since
496 * the writer may start writing to the read area once the read index
497 * is updated.
498 */
499 virt_rmb();
500 rbi->ring_buffer->read_index = rbi->priv_read_index;
501
502 hv_signal_on_read(channel);
503}
504EXPORT_SYMBOL_GPL(hv_pkt_iter_close);