Drivers: hv: vmbus: Cleanup the packet send path
The current channel code is using scatterlist abstraction to pass data to the ringbuffer API on the send path. This causes unnecessary translations between virtual and physical addresses. Fix this. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
90f3453585
commit
011a7c3cc3
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/hyperv.h>
|
#include <linux/hyperv.h>
|
||||||
|
#include <linux/uio.h>
|
||||||
|
|
||||||
#include "hyperv_vmbus.h"
|
#include "hyperv_vmbus.h"
|
||||||
|
|
||||||
|
@ -554,14 +555,14 @@ EXPORT_SYMBOL_GPL(vmbus_close);
|
||||||
*
|
*
|
||||||
* Mainly used by Hyper-V drivers.
|
* Mainly used by Hyper-V drivers.
|
||||||
*/
|
*/
|
||||||
int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
|
int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
|
||||||
u32 bufferlen, u64 requestid,
|
u32 bufferlen, u64 requestid,
|
||||||
enum vmbus_packet_type type, u32 flags)
|
enum vmbus_packet_type type, u32 flags)
|
||||||
{
|
{
|
||||||
struct vmpacket_descriptor desc;
|
struct vmpacket_descriptor desc;
|
||||||
u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
|
u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
|
||||||
u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
|
u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
|
||||||
struct scatterlist bufferlist[3];
|
struct kvec bufferlist[3];
|
||||||
u64 aligned_data = 0;
|
u64 aligned_data = 0;
|
||||||
int ret;
|
int ret;
|
||||||
bool signal = false;
|
bool signal = false;
|
||||||
|
@ -575,11 +576,12 @@ int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
|
||||||
desc.len8 = (u16)(packetlen_aligned >> 3);
|
desc.len8 = (u16)(packetlen_aligned >> 3);
|
||||||
desc.trans_id = requestid;
|
desc.trans_id = requestid;
|
||||||
|
|
||||||
sg_init_table(bufferlist, 3);
|
bufferlist[0].iov_base = &desc;
|
||||||
sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
|
bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor);
|
||||||
sg_set_buf(&bufferlist[1], buffer, bufferlen);
|
bufferlist[1].iov_base = buffer;
|
||||||
sg_set_buf(&bufferlist[2], &aligned_data,
|
bufferlist[1].iov_len = bufferlen;
|
||||||
packetlen_aligned - packetlen);
|
bufferlist[2].iov_base = &aligned_data;
|
||||||
|
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
|
||||||
|
|
||||||
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
|
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
|
||||||
|
|
||||||
|
@ -605,7 +607,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
|
||||||
u32 descsize;
|
u32 descsize;
|
||||||
u32 packetlen;
|
u32 packetlen;
|
||||||
u32 packetlen_aligned;
|
u32 packetlen_aligned;
|
||||||
struct scatterlist bufferlist[3];
|
struct kvec bufferlist[3];
|
||||||
u64 aligned_data = 0;
|
u64 aligned_data = 0;
|
||||||
bool signal = false;
|
bool signal = false;
|
||||||
|
|
||||||
|
@ -637,11 +639,12 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
|
||||||
desc.range[i].pfn = pagebuffers[i].pfn;
|
desc.range[i].pfn = pagebuffers[i].pfn;
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_init_table(bufferlist, 3);
|
bufferlist[0].iov_base = &desc;
|
||||||
sg_set_buf(&bufferlist[0], &desc, descsize);
|
bufferlist[0].iov_len = descsize;
|
||||||
sg_set_buf(&bufferlist[1], buffer, bufferlen);
|
bufferlist[1].iov_base = buffer;
|
||||||
sg_set_buf(&bufferlist[2], &aligned_data,
|
bufferlist[1].iov_len = bufferlen;
|
||||||
packetlen_aligned - packetlen);
|
bufferlist[2].iov_base = &aligned_data;
|
||||||
|
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
|
||||||
|
|
||||||
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
|
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
|
||||||
|
|
||||||
|
@ -665,7 +668,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
|
||||||
u32 descsize;
|
u32 descsize;
|
||||||
u32 packetlen;
|
u32 packetlen;
|
||||||
u32 packetlen_aligned;
|
u32 packetlen_aligned;
|
||||||
struct scatterlist bufferlist[3];
|
struct kvec bufferlist[3];
|
||||||
u64 aligned_data = 0;
|
u64 aligned_data = 0;
|
||||||
bool signal = false;
|
bool signal = false;
|
||||||
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
|
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
|
||||||
|
@ -700,11 +703,12 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
|
||||||
memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
|
memcpy(desc.range.pfn_array, multi_pagebuffer->pfn_array,
|
||||||
pfncount * sizeof(u64));
|
pfncount * sizeof(u64));
|
||||||
|
|
||||||
sg_init_table(bufferlist, 3);
|
bufferlist[0].iov_base = &desc;
|
||||||
sg_set_buf(&bufferlist[0], &desc, descsize);
|
bufferlist[0].iov_len = descsize;
|
||||||
sg_set_buf(&bufferlist[1], buffer, bufferlen);
|
bufferlist[1].iov_base = buffer;
|
||||||
sg_set_buf(&bufferlist[2], &aligned_data,
|
bufferlist[1].iov_len = bufferlen;
|
||||||
packetlen_aligned - packetlen);
|
bufferlist[2].iov_base = &aligned_data;
|
||||||
|
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
|
||||||
|
|
||||||
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
|
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
|
||||||
|
|
||||||
|
|
|
@ -559,8 +559,8 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
|
||||||
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
|
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
|
||||||
|
|
||||||
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
|
int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
|
||||||
struct scatterlist *sglist,
|
struct kvec *kv_list,
|
||||||
u32 sgcount, bool *signal);
|
u32 kv_count, bool *signal);
|
||||||
|
|
||||||
int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
|
int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer,
|
||||||
u32 buflen);
|
u32 buflen);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/hyperv.h>
|
#include <linux/hyperv.h>
|
||||||
|
#include <linux/uio.h>
|
||||||
|
|
||||||
#include "hyperv_vmbus.h"
|
#include "hyperv_vmbus.h"
|
||||||
|
|
||||||
|
@ -387,23 +388,20 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
|
int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
|
||||||
struct scatterlist *sglist, u32 sgcount, bool *signal)
|
struct kvec *kv_list, u32 kv_count, bool *signal)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
u32 bytes_avail_towrite;
|
u32 bytes_avail_towrite;
|
||||||
u32 bytes_avail_toread;
|
u32 bytes_avail_toread;
|
||||||
u32 totalbytes_towrite = 0;
|
u32 totalbytes_towrite = 0;
|
||||||
|
|
||||||
struct scatterlist *sg;
|
|
||||||
u32 next_write_location;
|
u32 next_write_location;
|
||||||
u32 old_write;
|
u32 old_write;
|
||||||
u64 prev_indices = 0;
|
u64 prev_indices = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
for_each_sg(sglist, sg, sgcount, i)
|
for (i = 0; i < kv_count; i++)
|
||||||
{
|
totalbytes_towrite += kv_list[i].iov_len;
|
||||||
totalbytes_towrite += sg->length;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalbytes_towrite += sizeof(u64);
|
totalbytes_towrite += sizeof(u64);
|
||||||
|
|
||||||
|
@ -427,12 +425,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
|
||||||
|
|
||||||
old_write = next_write_location;
|
old_write = next_write_location;
|
||||||
|
|
||||||
for_each_sg(sglist, sg, sgcount, i)
|
for (i = 0; i < kv_count; i++) {
|
||||||
{
|
|
||||||
next_write_location = hv_copyto_ringbuffer(outring_info,
|
next_write_location = hv_copyto_ringbuffer(outring_info,
|
||||||
next_write_location,
|
next_write_location,
|
||||||
sg_virt(sg),
|
kv_list[i].iov_base,
|
||||||
sg->length);
|
kv_list[i].iov_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set previous packet start */
|
/* Set previous packet start */
|
||||||
|
|
|
@ -802,7 +802,7 @@ extern int vmbus_open(struct vmbus_channel *channel,
|
||||||
extern void vmbus_close(struct vmbus_channel *channel);
|
extern void vmbus_close(struct vmbus_channel *channel);
|
||||||
|
|
||||||
extern int vmbus_sendpacket(struct vmbus_channel *channel,
|
extern int vmbus_sendpacket(struct vmbus_channel *channel,
|
||||||
const void *buffer,
|
void *buffer,
|
||||||
u32 bufferLen,
|
u32 bufferLen,
|
||||||
u64 requestid,
|
u64 requestid,
|
||||||
enum vmbus_packet_type type,
|
enum vmbus_packet_type type,
|
||||||
|
|
Loading…
Reference in New Issue