diff options
author | stephen hemminger <stephen@networkplumber.org> | 2017-02-27 13:26:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-03-06 20:13:13 -0500 |
commit | f3dd3f4797652c311df9c074436d420f1ad3566e (patch) | |
tree | 029e7602f0594a5b805828c33c40448cdb58623f /drivers/hv | |
parent | 50698d80f8bb1db989b7b9fa433f588fade5e382 (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.c | 94 |
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 | ||
341 | static inline void | ||
342 | init_cached_read_index(struct hv_ring_buffer_info *rbi) | ||
343 | { | ||
344 | rbi->cached_read_index = rbi->ring_buffer->read_index; | ||
345 | } | ||
346 | |||
339 | int hv_ringbuffer_read(struct vmbus_channel *channel, | 347 | int 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 | */ | ||
430 | static 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 | */ | ||
446 | struct 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 | } | ||
458 | EXPORT_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 | */ | ||
466 | struct 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 | } | ||
485 | EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); | ||
486 | |||
487 | /* | ||
488 | * Update host ring buffer after iterating over packets. | ||
489 | */ | ||
490 | void 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 | } | ||
504 | EXPORT_SYMBOL_GPL(hv_pkt_iter_close); | ||