vmbus: simplify hv_ringbuffer_read
With new iterator functions (and the double mapping) the ring buffer read function can be greatly simplified. Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
133d55cdb2
Коммит
4226ff69a3
|
@ -94,30 +94,6 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
|
||||||
ring_info->ring_buffer->write_index = next_write_location;
|
ring_info->ring_buffer->write_index = next_write_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the next read location for the specified ring buffer. */
|
|
||||||
static inline u32
|
|
||||||
hv_get_next_read_location(const struct hv_ring_buffer_info *ring_info)
|
|
||||||
{
|
|
||||||
return ring_info->ring_buffer->read_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the next read location + offset for the specified ring buffer.
|
|
||||||
* This allows the caller to skip.
|
|
||||||
*/
|
|
||||||
static inline u32
|
|
||||||
hv_get_next_readlocation_withoffset(const struct hv_ring_buffer_info *ring_info,
|
|
||||||
u32 offset)
|
|
||||||
{
|
|
||||||
u32 next = ring_info->ring_buffer->read_index;
|
|
||||||
|
|
||||||
next += offset;
|
|
||||||
if (next >= ring_info->ring_datasize)
|
|
||||||
next -= ring_info->ring_datasize;
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the next read location for the specified ring buffer. */
|
/* Set the next read location for the specified ring buffer. */
|
||||||
static inline void
|
static inline void
|
||||||
hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
|
hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
|
||||||
|
@ -141,29 +117,6 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
|
||||||
return (u64)ring_info->ring_buffer->write_index << 32;
|
return (u64)ring_info->ring_buffer->write_index << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper routine to copy to source from ring buffer.
|
|
||||||
* Assume there is enough room. Handles wrap-around in src case only!!
|
|
||||||
*/
|
|
||||||
static u32 hv_copyfrom_ringbuffer(
|
|
||||||
const struct hv_ring_buffer_info *ring_info,
|
|
||||||
void *dest,
|
|
||||||
u32 destlen,
|
|
||||||
u32 start_read_offset)
|
|
||||||
{
|
|
||||||
void *ring_buffer = hv_get_ring_buffer(ring_info);
|
|
||||||
u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
|
|
||||||
|
|
||||||
memcpy(dest, ring_buffer + start_read_offset, destlen);
|
|
||||||
|
|
||||||
start_read_offset += destlen;
|
|
||||||
if (start_read_offset >= ring_buffer_size)
|
|
||||||
start_read_offset -= ring_buffer_size;
|
|
||||||
|
|
||||||
return start_read_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper routine to copy from source to ring buffer.
|
* Helper routine to copy from source to ring buffer.
|
||||||
* Assume there is enough room. Handles wrap-around in dest case only!!
|
* Assume there is enough room. Handles wrap-around in dest case only!!
|
||||||
|
@ -334,33 +287,22 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
init_cached_read_index(struct hv_ring_buffer_info *rbi)
|
|
||||||
{
|
|
||||||
rbi->cached_read_index = rbi->ring_buffer->read_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hv_ringbuffer_read(struct vmbus_channel *channel,
|
int hv_ringbuffer_read(struct vmbus_channel *channel,
|
||||||
void *buffer, u32 buflen, u32 *buffer_actual_len,
|
void *buffer, u32 buflen, u32 *buffer_actual_len,
|
||||||
u64 *requestid, bool raw)
|
u64 *requestid, bool raw)
|
||||||
{
|
{
|
||||||
u32 bytes_avail_toread;
|
struct vmpacket_descriptor *desc;
|
||||||
u32 next_read_location;
|
u32 packetlen, offset;
|
||||||
u64 prev_indices = 0;
|
|
||||||
struct vmpacket_descriptor desc;
|
|
||||||
u32 offset;
|
|
||||||
u32 packetlen;
|
|
||||||
struct hv_ring_buffer_info *inring_info = &channel->inbound;
|
|
||||||
|
|
||||||
if (buflen <= 0)
|
if (unlikely(buflen == 0))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*buffer_actual_len = 0;
|
*buffer_actual_len = 0;
|
||||||
*requestid = 0;
|
*requestid = 0;
|
||||||
|
|
||||||
bytes_avail_toread = hv_get_bytes_to_read(inring_info);
|
|
||||||
/* Make sure there is something to read */
|
/* Make sure there is something to read */
|
||||||
if (bytes_avail_toread < sizeof(desc)) {
|
desc = hv_pkt_iter_first(channel);
|
||||||
|
if (desc == NULL) {
|
||||||
/*
|
/*
|
||||||
* No error is set when there is even no header, drivers are
|
* No error is set when there is even no header, drivers are
|
||||||
* supposed to analyze buffer_actual_len.
|
* supposed to analyze buffer_actual_len.
|
||||||
|
@ -368,48 +310,22 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_cached_read_index(inring_info);
|
offset = raw ? 0 : (desc->offset8 << 3);
|
||||||
|
packetlen = (desc->len8 << 3) - offset;
|
||||||
next_read_location = hv_get_next_read_location(inring_info);
|
|
||||||
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
|
|
||||||
sizeof(desc),
|
|
||||||
next_read_location);
|
|
||||||
|
|
||||||
offset = raw ? 0 : (desc.offset8 << 3);
|
|
||||||
packetlen = (desc.len8 << 3) - offset;
|
|
||||||
*buffer_actual_len = packetlen;
|
*buffer_actual_len = packetlen;
|
||||||
*requestid = desc.trans_id;
|
*requestid = desc->trans_id;
|
||||||
|
|
||||||
if (bytes_avail_toread < packetlen + offset)
|
if (unlikely(packetlen > buflen))
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
if (packetlen > buflen)
|
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
|
||||||
next_read_location =
|
/* since ring is double mapped, only one copy is necessary */
|
||||||
hv_get_next_readlocation_withoffset(inring_info, offset);
|
memcpy(buffer, (const char *)desc + offset, packetlen);
|
||||||
|
|
||||||
next_read_location = hv_copyfrom_ringbuffer(inring_info,
|
/* Advance ring index to next packet descriptor */
|
||||||
buffer,
|
__hv_pkt_iter_next(channel, desc);
|
||||||
packetlen,
|
|
||||||
next_read_location);
|
|
||||||
|
|
||||||
next_read_location = hv_copyfrom_ringbuffer(inring_info,
|
/* Notify host of update */
|
||||||
&prev_indices,
|
hv_pkt_iter_close(channel);
|
||||||
sizeof(u64),
|
|
||||||
next_read_location);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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_mb();
|
|
||||||
|
|
||||||
/* Update the read index */
|
|
||||||
hv_set_next_read_location(inring_info, next_read_location);
|
|
||||||
|
|
||||||
hv_signal_on_read(channel);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -442,7 +358,7 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
|
||||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||||
|
|
||||||
/* set state for later hv_signal_on_read() */
|
/* set state for later hv_signal_on_read() */
|
||||||
init_cached_read_index(rbi);
|
rbi->cached_read_index = rbi->ring_buffer->read_index;
|
||||||
|
|
||||||
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
|
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче