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>
This commit is contained in:
stephen hemminger
2017-02-27 10:26:48 -08:00
committed by David S. Miller
parent 50698d80f8
commit f3dd3f4797
3 changed files with 139 additions and 97 deletions

View File

@@ -1504,14 +1504,6 @@ static inline void hv_signal_on_read(struct vmbus_channel *channel)
return;
}
static inline void
init_cached_read_index(struct vmbus_channel *channel)
{
struct hv_ring_buffer_info *rbi = &channel->inbound;
rbi->cached_read_index = rbi->ring_buffer->read_index;
}
/*
* Mask off host interrupt callback notifications
*/
@@ -1545,76 +1537,48 @@ static inline u32 hv_end_read(struct hv_ring_buffer_info *rbi)
/*
* An API to support in-place processing of incoming VMBUS packets.
*/
#define VMBUS_PKT_TRAILER 8
/* Get data payload associated with descriptor */
static inline void *hv_pkt_data(const struct vmpacket_descriptor *desc)
{
return (void *)((unsigned long)desc + (desc->offset8 << 3));
}
/* Get data size associated with descriptor */
static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc)
{
return (desc->len8 << 3) - (desc->offset8 << 3);
}
struct vmpacket_descriptor *
hv_pkt_iter_first(struct vmbus_channel *channel);
struct vmpacket_descriptor *
__hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *pkt);
void hv_pkt_iter_close(struct vmbus_channel *channel);
/*
* Get next packet descriptor from iterator
* If at end of list, return NULL and update host.
*/
static inline struct vmpacket_descriptor *
get_next_pkt_raw(struct vmbus_channel *channel)
hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *pkt)
{
struct hv_ring_buffer_info *ring_info = &channel->inbound;
u32 priv_read_loc = ring_info->priv_read_index;
void *ring_buffer = hv_get_ring_buffer(ring_info);
u32 dsize = ring_info->ring_datasize;
/*
* delta is the difference between what is available to read and
* what was already consumed in place. We commit read index after
* the whole batch is processed.
*/
u32 delta = priv_read_loc >= ring_info->ring_buffer->read_index ?
priv_read_loc - ring_info->ring_buffer->read_index :
(dsize - ring_info->ring_buffer->read_index) + priv_read_loc;
u32 bytes_avail_toread = (hv_get_bytes_to_read(ring_info) - delta);
struct vmpacket_descriptor *nxt;
if (bytes_avail_toread < sizeof(struct vmpacket_descriptor))
return NULL;
nxt = __hv_pkt_iter_next(channel, pkt);
if (!nxt)
hv_pkt_iter_close(channel);
return ring_buffer + priv_read_loc;
}
/*
* A helper function to step through packets "in-place"
* This API is to be called after each successful call
* get_next_pkt_raw().
*/
static inline void put_pkt_raw(struct vmbus_channel *channel,
struct vmpacket_descriptor *desc)
{
struct hv_ring_buffer_info *ring_info = &channel->inbound;
u32 packetlen = desc->len8 << 3;
u32 dsize = ring_info->ring_datasize;
/*
* Include the packet trailer.
*/
ring_info->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
ring_info->priv_read_index %= dsize;
}
/*
* This call commits the read index and potentially signals the host.
* Here is the pattern for using the "in-place" consumption APIs:
*
* init_cached_read_index();
*
* while (get_next_pkt_raw() {
* process the packet "in-place";
* put_pkt_raw();
* }
* if (packets processed in place)
* commit_rd_index();
*/
static inline void commit_rd_index(struct vmbus_channel *channel)
{
struct hv_ring_buffer_info *ring_info = &channel->inbound;
/*
* Make sure all reads are done before we update the read index since
* the writer may start writing to the read area once the read index
* is updated.
*/
virt_rmb();
ring_info->ring_buffer->read_index = ring_info->priv_read_index;
hv_signal_on_read(channel);
return nxt;
}
#define foreach_vmbus_pkt(pkt, channel) \
for (pkt = hv_pkt_iter_first(channel); pkt; \
pkt = hv_pkt_iter_next(channel, pkt))
#endif /* _HYPERV_H */