hyeprv/vmbus: Rework prplist sending.

MFC after:	1 week
Sponsored by:	Microsoft OSTC
Differential Revision:	https://reviews.freebsd.org/D7175
This commit is contained in:
Sepherosa Ziehau 2016-07-15 06:40:59 +00:00
parent 7ff1939db0
commit 66e132bd0f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=302878
6 changed files with 92 additions and 141 deletions

View File

@ -82,18 +82,6 @@ typedef uint8_t hv_bool_uint8_t;
#define VMBUS_VERSION_MAJOR(ver) (((uint32_t)(ver)) >> 16)
#define VMBUS_VERSION_MINOR(ver) (((uint32_t)(ver)) & 0xffff)
#define HV_MAX_MULTIPAGE_BUFFER_COUNT 32
#define HV_ALIGN_UP(value, align) \
(((value) & (align-1)) ? \
(((value) + (align-1)) & ~(align-1) ) : (value))
#define HV_ALIGN_DOWN(value, align) ( (value) & ~(align-1) )
#define HV_NUM_PAGES_SPANNED(addr, len) \
((HV_ALIGN_UP(addr+len, PAGE_SIZE) - \
HV_ALIGN_DOWN(addr, PAGE_SIZE)) >> PAGE_SHIFT )
struct hyperv_guid {
uint8_t hv_guid[16];
} __packed;
@ -223,12 +211,6 @@ typedef struct {
uint8_t buffer[0]; /* doubles as interrupt mask */
} __packed hv_vmbus_ring_buffer;
typedef struct {
int length;
int offset;
uint64_t pfn_array[HV_MAX_MULTIPAGE_BUFFER_COUNT];
} __packed hv_vmbus_multipage_buffer;
typedef struct {
hv_vmbus_ring_buffer* ring_buffer;
struct mtx ring_lock;
@ -368,13 +350,6 @@ int hv_vmbus_channel_send_packet(
hv_vmbus_packet_type type,
uint32_t flags);
int hv_vmbus_channel_send_packet_multipagebuffer(
hv_vmbus_channel* channel,
hv_vmbus_multipage_buffer* multi_page_buffer,
void* buffer,
uint32_t buffer_len,
uint64_t request_id);
int hv_vmbus_channel_establish_gpadl(
hv_vmbus_channel* channel,
/* must be phys and virt contiguous */

View File

@ -31,6 +31,15 @@
#include <sys/param.h>
/*
* GPA stuffs.
*/
struct vmbus_gpa_range {
uint32_t gpa_len;
uint32_t gpa_ofs;
uint64_t gpa_page[0];
} __packed;
/* This is actually vmbus_gpa_range.gpa_page[1] */
struct vmbus_gpa {
uint32_t gpa_len;
@ -39,11 +48,15 @@ struct vmbus_gpa {
} __packed;
#define VMBUS_CHAN_SGLIST_MAX 32
#define VMBUS_CHAN_PRPLIST_MAX 32
struct hv_vmbus_channel;
int vmbus_chan_send_sglist(struct hv_vmbus_channel *chan,
struct vmbus_gpa sg[], int sglen, void *data, int dlen,
uint64_t xactid);
int vmbus_chan_send_prplist(struct hv_vmbus_channel *chan,
struct vmbus_gpa_range *prp, int prp_cnt, void *data, int dlen,
uint64_t xactid);
#endif /* !_VMBUS_H_ */

View File

@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/scsi_message.h>
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/vmbus.h>
#include "hv_vstorage.h"
#include "vmbus_if.h"
@ -100,7 +101,7 @@ struct hv_sgl_page_pool{
boolean_t is_init;
} g_hv_sgl_page_pool;
#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * HV_MAX_MULTIPAGE_BUFFER_COUNT
#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * VMBUS_CHAN_PRPLIST_MAX
enum storvsc_request_type {
WRITE_TYPE,
@ -108,10 +109,16 @@ enum storvsc_request_type {
UNKNOWN_TYPE
};
struct hvs_gpa_range {
struct vmbus_gpa_range gpa_range;
uint64_t gpa_page[VMBUS_CHAN_PRPLIST_MAX];
} __packed;
struct hv_storvsc_request {
LIST_ENTRY(hv_storvsc_request) link;
struct vstor_packet vstor_packet;
hv_vmbus_multipage_buffer data_buf;
int prp_cnt;
struct hvs_gpa_range prp_list;
void *sense_data;
uint8_t sense_info_len;
uint8_t retries;
@ -674,21 +681,18 @@ hv_storvsc_io_request(struct storvsc_softc *sc,
vstor_packet->u.vm_srb.sense_info_len = sense_buffer_size;
vstor_packet->u.vm_srb.transfer_len = request->data_buf.length;
vstor_packet->u.vm_srb.transfer_len =
request->prp_list.gpa_range.gpa_len;
vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
outgoing_channel = vmbus_select_outgoing_channel(sc->hs_chan);
mtx_unlock(&request->softc->hs_lock);
if (request->data_buf.length) {
ret = hv_vmbus_channel_send_packet_multipagebuffer(
outgoing_channel,
&request->data_buf,
vstor_packet,
VSTOR_PKT_SIZE,
(uint64_t)(uintptr_t)request);
if (request->prp_list.gpa_range.gpa_len) {
ret = vmbus_chan_send_prplist(outgoing_channel,
&request->prp_list.gpa_range, request->prp_cnt,
vstor_packet, VSTOR_PKT_SIZE, (uint64_t)(uintptr_t)request);
} else {
ret = hv_vmbus_channel_send_packet(
outgoing_channel,
@ -954,7 +958,7 @@ storvsc_attach(device_t dev)
/*
* Pre-create SG list, each SG list with
* HV_MAX_MULTIPAGE_BUFFER_COUNT segments, each
* VMBUS_CHAN_PRPLIST_MAX segments, each
* segment has one page buffer
*/
for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) {
@ -962,10 +966,10 @@ storvsc_attach(device_t dev)
M_DEVBUF, M_WAITOK|M_ZERO);
sgl_node->sgl_data =
sglist_alloc(HV_MAX_MULTIPAGE_BUFFER_COUNT,
sglist_alloc(VMBUS_CHAN_PRPLIST_MAX,
M_WAITOK|M_ZERO);
for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) {
for (j = 0; j < VMBUS_CHAN_PRPLIST_MAX; j++) {
tmp_buff = malloc(PAGE_SIZE,
M_DEVBUF, M_WAITOK|M_ZERO);
@ -1052,7 +1056,7 @@ storvsc_attach(device_t dev)
while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
LIST_REMOVE(sgl_node, link);
for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) {
for (j = 0; j < VMBUS_CHAN_PRPLIST_MAX; j++) {
if (NULL !=
(void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) {
free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
@ -1115,7 +1119,7 @@ storvsc_detach(device_t dev)
while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
LIST_REMOVE(sgl_node, link);
for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){
for (j = 0; j < VMBUS_CHAN_PRPLIST_MAX; j++){
if (NULL !=
(void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) {
free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
@ -1666,6 +1670,7 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
uint32_t pfn_num = 0;
uint32_t pfn;
uint64_t not_aligned_seg_bits = 0;
struct hvs_gpa_range *prplist;
/* refer to struct vmscsi_req for meanings of these two fields */
reqp->vstor_packet.u.vm_srb.port =
@ -1709,22 +1714,23 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
return (0);
}
reqp->data_buf.length = csio->dxfer_len;
prplist = &reqp->prp_list;
prplist->gpa_range.gpa_len = csio->dxfer_len;
switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
case CAM_DATA_VADDR:
{
bytes_to_copy = csio->dxfer_len;
phys_addr = vtophys(csio->data_ptr);
reqp->data_buf.offset = phys_addr & PAGE_MASK;
prplist->gpa_range.gpa_ofs = phys_addr & PAGE_MASK;
while (bytes_to_copy != 0) {
int bytes, page_offset;
phys_addr =
vtophys(&csio->data_ptr[reqp->data_buf.length -
vtophys(&csio->data_ptr[prplist->gpa_range.gpa_len -
bytes_to_copy]);
pfn = phys_addr >> PAGE_SHIFT;
reqp->data_buf.pfn_array[pfn_num] = pfn;
prplist->gpa_page[pfn_num] = pfn;
page_offset = phys_addr & PAGE_MASK;
bytes = min(PAGE_SIZE - page_offset, bytes_to_copy);
@ -1732,6 +1738,7 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
bytes_to_copy -= bytes;
pfn_num++;
}
reqp->prp_cnt = pfn_num;
break;
}
@ -1748,10 +1755,10 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
printf("Storvsc: get SG I/O operation, %d\n",
reqp->vstor_packet.u.vm_srb.data_in);
if (storvsc_sg_count > HV_MAX_MULTIPAGE_BUFFER_COUNT){
if (storvsc_sg_count > VMBUS_CHAN_PRPLIST_MAX){
printf("Storvsc: %d segments is too much, "
"only support %d segments\n",
storvsc_sg_count, HV_MAX_MULTIPAGE_BUFFER_COUNT);
storvsc_sg_count, VMBUS_CHAN_PRPLIST_MAX);
return (EINVAL);
}
@ -1804,10 +1811,10 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
phys_addr =
vtophys(storvsc_sglist[0].ds_addr);
}
reqp->data_buf.offset = phys_addr & PAGE_MASK;
prplist->gpa_range.gpa_ofs = phys_addr & PAGE_MASK;
pfn = phys_addr >> PAGE_SHIFT;
reqp->data_buf.pfn_array[0] = pfn;
prplist->gpa_page[0] = pfn;
for (i = 1; i < storvsc_sg_count; i++) {
if (reqp->not_aligned_seg_bits & (1 << i)) {
@ -1819,27 +1826,31 @@ create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
}
pfn = phys_addr >> PAGE_SHIFT;
reqp->data_buf.pfn_array[i] = pfn;
prplist->gpa_page[i] = pfn;
}
reqp->prp_cnt = i;
} else {
phys_addr = vtophys(storvsc_sglist[0].ds_addr);
reqp->data_buf.offset = phys_addr & PAGE_MASK;
prplist->gpa_range.gpa_ofs = phys_addr & PAGE_MASK;
for (i = 0; i < storvsc_sg_count; i++) {
phys_addr = vtophys(storvsc_sglist[i].ds_addr);
pfn = phys_addr >> PAGE_SHIFT;
reqp->data_buf.pfn_array[i] = pfn;
prplist->gpa_page[i] = pfn;
}
reqp->prp_cnt = i;
/* check the last segment cross boundary or not */
offset = phys_addr & PAGE_MASK;
if (offset) {
/* Add one more PRP entry */
phys_addr =
vtophys(storvsc_sglist[i-1].ds_addr +
PAGE_SIZE - offset);
pfn = phys_addr >> PAGE_SHIFT;
reqp->data_buf.pfn_array[i] = pfn;
prplist->gpa_page[i] = pfn;
reqp->prp_cnt++;
}
reqp->bounce_sgl_count = 0;

View File

@ -712,78 +712,46 @@ vmbus_chan_send_sglist(struct hv_vmbus_channel *chan,
return error;
}
/**
* @brief Send a multi-page buffer packet using a GPADL Direct packet type
*/
int
hv_vmbus_channel_send_packet_multipagebuffer(
hv_vmbus_channel* channel,
hv_vmbus_multipage_buffer* multi_page_buffer,
void* buffer,
uint32_t buffer_len,
uint64_t request_id)
vmbus_chan_send_prplist(struct hv_vmbus_channel *chan,
struct vmbus_gpa_range *prp, int prp_cnt, void *data, int dlen,
uint64_t xactid)
{
struct vmbus_chanpkt_prplist pkt;
int pktlen, pad_pktlen, hlen, error;
struct iovec iov[4];
boolean_t send_evt;
uint64_t pad = 0;
int ret = 0;
uint32_t desc_size;
boolean_t need_sig;
uint32_t packet_len;
uint32_t packet_len_aligned;
uint32_t pfn_count;
uint64_t aligned_data = 0;
struct iovec iov[3];
hv_vmbus_channel_packet_multipage_buffer desc;
KASSERT(prp_cnt < VMBUS_CHAN_PRPLIST_MAX,
("invalid prplist entry count %d", prp_cnt));
pfn_count =
HV_NUM_PAGES_SPANNED(
multi_page_buffer->offset,
multi_page_buffer->length);
hlen = __offsetof(struct vmbus_chanpkt_prplist,
cp_range[0].gpa_page[prp_cnt]);
pktlen = hlen + dlen;
pad_pktlen = roundup2(pktlen, VMBUS_CHANPKT_SIZE_ALIGN);
if ((pfn_count == 0) || (pfn_count > HV_MAX_MULTIPAGE_BUFFER_COUNT))
return (EINVAL);
/*
* Adjust the size down since hv_vmbus_channel_packet_multipage_buffer
* is the largest size we support
*/
desc_size =
sizeof(hv_vmbus_channel_packet_multipage_buffer) -
((HV_MAX_MULTIPAGE_BUFFER_COUNT - pfn_count) *
sizeof(uint64_t));
packet_len = desc_size + buffer_len;
packet_len_aligned = HV_ALIGN_UP(packet_len, sizeof(uint64_t));
pkt.cp_hdr.cph_type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT;
pkt.cp_hdr.cph_flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
pkt.cp_hdr.cph_data_ofs = hlen >> VMBUS_CHANPKT_SIZE_SHIFT;
pkt.cp_hdr.cph_len = pad_pktlen >> VMBUS_CHANPKT_SIZE_SHIFT;
pkt.cp_hdr.cph_xactid = xactid;
pkt.cp_rsvd = 0;
pkt.cp_range_cnt = 1;
/*
* Setup the descriptor
*/
desc.type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT;
desc.flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
desc.data_offset8 = desc_size >> 3; /* in 8-bytes granularity */
desc.length8 = (uint16_t) (packet_len_aligned >> 3);
desc.transaction_id = request_id;
desc.range_count = 1;
iov[0].iov_base = &pkt;
iov[0].iov_len = sizeof(pkt);
iov[1].iov_base = prp;
iov[1].iov_len = __offsetof(struct vmbus_gpa_range, gpa_page[prp_cnt]);
iov[2].iov_base = data;
iov[2].iov_len = dlen;
iov[3].iov_base = &pad;
iov[3].iov_len = pad_pktlen - pktlen;
desc.range.length = multi_page_buffer->length;
desc.range.offset = multi_page_buffer->offset;
memcpy(desc.range.pfn_array, multi_page_buffer->pfn_array,
pfn_count * sizeof(uint64_t));
iov[0].iov_base = &desc;
iov[0].iov_len = desc_size;
iov[1].iov_base = buffer;
iov[1].iov_len = buffer_len;
iov[2].iov_base = &aligned_data;
iov[2].iov_len = packet_len_aligned - packet_len;
ret = hv_ring_buffer_write(&channel->outbound, iov, 3, &need_sig);
/* TODO: We should determine if this is optional */
if (ret == 0 && need_sig)
vmbus_chan_send_event(channel);
return (ret);
error = hv_ring_buffer_write(&chan->outbound, iov, 4, &send_evt);
if (!error && send_evt)
vmbus_chan_send_event(chan);
return error;
}
/**

View File

@ -41,20 +41,6 @@
struct vmbus_softc;
/*
* The format must be the same as hv_vm_data_gpa_direct
*/
typedef struct hv_vmbus_channel_packet_multipage_buffer {
uint16_t type;
uint16_t data_offset8;
uint16_t length8;
uint16_t flags;
uint64_t transaction_id;
uint32_t reserved;
uint32_t range_count; /* Always 1 in this case */
hv_vmbus_multipage_buffer range;
} __packed hv_vmbus_channel_packet_multipage_buffer;
/*
* Private, VM Bus functions
*/

View File

@ -108,15 +108,6 @@ CTASSERT(sizeof(struct vmbus_mnf) == PAGE_SIZE);
#define VMBUS_CHAN_MAX_COMPAT 256
#define VMBUS_CHAN_MAX (VMBUS_EVTFLAG_LEN * VMBUS_EVTFLAGS_MAX)
/*
* GPA range.
*/
struct vmbus_gpa_range {
uint32_t gpa_len;
uint32_t gpa_ofs;
uint64_t gpa_page[];
} __packed;
/*
* Channel packets
*/
@ -143,6 +134,13 @@ struct vmbus_chanpkt_sglist {
struct vmbus_gpa cp_gpa[];
} __packed;
struct vmbus_chanpkt_prplist {
struct vmbus_chanpkt_hdr cp_hdr;
uint32_t cp_rsvd;
uint32_t cp_range_cnt;
struct vmbus_gpa_range cp_range[];
} __packed;
/*
* Channel messages
* - Embedded in vmbus_message.msg_data, e.g. response and notification.