From 9988ce685676cebe0b14dc128f00e1ae9cd1a4fa Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 2 Sep 2016 05:58:20 -0700 Subject: Drivers: hv: ring_buffer: wrap around mappings for ring buffers Make it possible to always use a single memcpy() or to provide a direct link to a packet on the ring buffer by creating virtual mapping for two copies of the ring buffer with vmap(). Utilize currently empty hv_ringbuffer_cleanup() to do the unmap. While on it, replace sizeof(struct hv_ring_buffer) check in hv_ringbuffer_init() with BUILD_BUG_ON() as it is a compile time check. Signed-off-by: Vitaly Kuznetsov Tested-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/ring_buffer.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'drivers/hv/ring_buffer.c') diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index e3edcaee7ab3..7e21c2c82ad1 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "hyperv_vmbus.h" @@ -243,22 +245,46 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, /* Initialize the ring buffer. */ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, - void *buffer, u32 buflen) + struct page *pages, u32 page_cnt) { - if (sizeof(struct hv_ring_buffer) != PAGE_SIZE) - return -EINVAL; + int i; + struct page **pages_wraparound; + + BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); memset(ring_info, 0, sizeof(struct hv_ring_buffer_info)); - ring_info->ring_buffer = (struct hv_ring_buffer *)buffer; + /* + * First page holds struct hv_ring_buffer, do wraparound mapping for + * the rest. + */ + pages_wraparound = kzalloc(sizeof(struct page *) * (page_cnt * 2 - 1), + GFP_KERNEL); + if (!pages_wraparound) + return -ENOMEM; + + pages_wraparound[0] = pages; + for (i = 0; i < 2 * (page_cnt - 1); i++) + pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1]; + + ring_info->ring_buffer = (struct hv_ring_buffer *) + vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL); + + kfree(pages_wraparound); + + + if (!ring_info->ring_buffer) + return -ENOMEM; + ring_info->ring_buffer->read_index = ring_info->ring_buffer->write_index = 0; /* Set the feature bit for enabling flow control. */ ring_info->ring_buffer->feature_bits.value = 1; - ring_info->ring_size = buflen; - ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer); + ring_info->ring_size = page_cnt << PAGE_SHIFT; + ring_info->ring_datasize = ring_info->ring_size - + sizeof(struct hv_ring_buffer); spin_lock_init(&ring_info->ring_lock); @@ -268,6 +294,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, /* Cleanup the ring buffer. */ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) { + vunmap(ring_info->ring_buffer); } /* Write to the ring buffer. */ -- cgit v1.2.3-59-g8ed1b