mirror of https://github.com/xemu-project/xemu.git
vdpa: Send cvq state load commands in parallel
This patch enables sending CVQ state load commands in parallel at device startup by following steps: * Refactor vhost_vdpa_net_load_cmd() to iterate through the control commands shadow buffers. This allows different CVQ state load commands to use their own unique buffers. * Delay the polling and checking of buffers until either the SVQ is full or control commands shadow buffers are full. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1578 Signed-off-by: Hawkins Jiawei <yin31149@gmail.com> Acked-by: Eugenio Pérez <eperezma@redhat.com> Message-Id: <9350f32278e39f7bce297b8f2d82dac27c6f8c9a.1697165821.git.yin31149@gmail.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
99d6a32469
commit
acec5f685c
135
net/vhost-vdpa.c
135
net/vhost-vdpa.c
|
@ -661,6 +661,31 @@ static void vhost_vdpa_net_load_cursor_reset(VhostVDPAState *s,
|
||||||
in_cursor->iov_len = vhost_vdpa_net_cvq_cmd_page_len();
|
in_cursor->iov_len = vhost_vdpa_net_cvq_cmd_page_len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Poll SVQ for multiple pending control commands and check the device's ack.
|
||||||
|
*
|
||||||
|
* Caller should hold the BQL when invoking this function.
|
||||||
|
*
|
||||||
|
* @s: The VhostVDPAState
|
||||||
|
* @len: The length of the pending status shadow buffer
|
||||||
|
*/
|
||||||
|
static ssize_t vhost_vdpa_net_svq_flush(VhostVDPAState *s, size_t len)
|
||||||
|
{
|
||||||
|
/* device uses a one-byte length ack for each control command */
|
||||||
|
ssize_t dev_written = vhost_vdpa_net_svq_poll(s, len);
|
||||||
|
if (unlikely(dev_written != len)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check the device's ack */
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
if (s->status[i] != VIRTIO_NET_OK) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s,
|
static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s,
|
||||||
struct iovec *out_cursor,
|
struct iovec *out_cursor,
|
||||||
struct iovec *in_cursor, uint8_t class,
|
struct iovec *in_cursor, uint8_t class,
|
||||||
|
@ -671,11 +696,31 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s,
|
||||||
.class = class,
|
.class = class,
|
||||||
.cmd = cmd,
|
.cmd = cmd,
|
||||||
};
|
};
|
||||||
size_t data_size = iov_size(data_sg, data_num);
|
size_t data_size = iov_size(data_sg, data_num), cmd_size;
|
||||||
struct iovec out, in;
|
struct iovec out, in;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
|
unsigned dummy_cursor_iov_cnt;
|
||||||
|
VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0);
|
||||||
|
|
||||||
assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl));
|
assert(data_size < vhost_vdpa_net_cvq_cmd_page_len() - sizeof(ctrl));
|
||||||
|
cmd_size = sizeof(ctrl) + data_size;
|
||||||
|
if (vhost_svq_available_slots(svq) < 2 ||
|
||||||
|
iov_size(out_cursor, 1) < cmd_size) {
|
||||||
|
/*
|
||||||
|
* It is time to flush all pending control commands if SVQ is full
|
||||||
|
* or control commands shadow buffers are full.
|
||||||
|
*
|
||||||
|
* We can poll here since we've had BQL from the time
|
||||||
|
* we sent the descriptor.
|
||||||
|
*/
|
||||||
|
r = vhost_vdpa_net_svq_flush(s, in_cursor->iov_base -
|
||||||
|
(void *)s->status);
|
||||||
|
if (unlikely(r < 0)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
vhost_vdpa_net_load_cursor_reset(s, out_cursor, in_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
/* pack the CVQ command header */
|
/* pack the CVQ command header */
|
||||||
iov_from_buf(out_cursor, 1, 0, &ctrl, sizeof(ctrl));
|
iov_from_buf(out_cursor, 1, 0, &ctrl, sizeof(ctrl));
|
||||||
|
@ -684,7 +729,7 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s,
|
||||||
out_cursor->iov_base + sizeof(ctrl), data_size);
|
out_cursor->iov_base + sizeof(ctrl), data_size);
|
||||||
|
|
||||||
/* extract the required buffer from the cursor for output */
|
/* extract the required buffer from the cursor for output */
|
||||||
iov_copy(&out, 1, out_cursor, 1, 0, sizeof(ctrl) + data_size);
|
iov_copy(&out, 1, out_cursor, 1, 0, cmd_size);
|
||||||
/* extract the required buffer from the cursor for input */
|
/* extract the required buffer from the cursor for input */
|
||||||
iov_copy(&in, 1, in_cursor, 1, 0, sizeof(*s->status));
|
iov_copy(&in, 1, in_cursor, 1, 0, sizeof(*s->status));
|
||||||
|
|
||||||
|
@ -693,11 +738,13 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* iterate the cursors */
|
||||||
* We can poll here since we've had BQL from the time
|
dummy_cursor_iov_cnt = 1;
|
||||||
* we sent the descriptor.
|
iov_discard_front(&out_cursor, &dummy_cursor_iov_cnt, cmd_size);
|
||||||
*/
|
dummy_cursor_iov_cnt = 1;
|
||||||
return vhost_vdpa_net_svq_poll(s, 1);
|
iov_discard_front(&in_cursor, &dummy_cursor_iov_cnt, sizeof(*s->status));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n,
|
static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n,
|
||||||
|
@ -709,15 +756,12 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n,
|
||||||
.iov_base = (void *)n->mac,
|
.iov_base = (void *)n->mac,
|
||||||
.iov_len = sizeof(n->mac),
|
.iov_len = sizeof(n->mac),
|
||||||
};
|
};
|
||||||
ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||||
VIRTIO_NET_CTRL_MAC,
|
VIRTIO_NET_CTRL_MAC,
|
||||||
VIRTIO_NET_CTRL_MAC_ADDR_SET,
|
VIRTIO_NET_CTRL_MAC_ADDR_SET,
|
||||||
&data, 1);
|
&data, 1);
|
||||||
if (unlikely(dev_written < 0)) {
|
if (unlikely(r < 0)) {
|
||||||
return dev_written;
|
return r;
|
||||||
}
|
|
||||||
if (*s->status != VIRTIO_NET_OK) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,15 +806,12 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n,
|
||||||
.iov_len = mul_macs_size,
|
.iov_len = mul_macs_size,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||||
VIRTIO_NET_CTRL_MAC,
|
VIRTIO_NET_CTRL_MAC,
|
||||||
VIRTIO_NET_CTRL_MAC_TABLE_SET,
|
VIRTIO_NET_CTRL_MAC_TABLE_SET,
|
||||||
data, ARRAY_SIZE(data));
|
data, ARRAY_SIZE(data));
|
||||||
if (unlikely(dev_written < 0)) {
|
if (unlikely(r < 0)) {
|
||||||
return dev_written;
|
return r;
|
||||||
}
|
|
||||||
if (*s->status != VIRTIO_NET_OK) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -782,7 +823,7 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s,
|
||||||
struct iovec *in_cursor)
|
struct iovec *in_cursor)
|
||||||
{
|
{
|
||||||
struct virtio_net_ctrl_mq mq;
|
struct virtio_net_ctrl_mq mq;
|
||||||
ssize_t dev_written;
|
ssize_t r;
|
||||||
|
|
||||||
if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_MQ)) {
|
if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_MQ)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -793,15 +834,12 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s,
|
||||||
.iov_base = &mq,
|
.iov_base = &mq,
|
||||||
.iov_len = sizeof(mq),
|
.iov_len = sizeof(mq),
|
||||||
};
|
};
|
||||||
dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||||
VIRTIO_NET_CTRL_MQ,
|
VIRTIO_NET_CTRL_MQ,
|
||||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET,
|
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET,
|
||||||
&data, 1);
|
&data, 1);
|
||||||
if (unlikely(dev_written < 0)) {
|
if (unlikely(r < 0)) {
|
||||||
return dev_written;
|
return r;
|
||||||
}
|
|
||||||
if (*s->status != VIRTIO_NET_OK) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -813,7 +851,7 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s,
|
||||||
struct iovec *in_cursor)
|
struct iovec *in_cursor)
|
||||||
{
|
{
|
||||||
uint64_t offloads;
|
uint64_t offloads;
|
||||||
ssize_t dev_written;
|
ssize_t r;
|
||||||
|
|
||||||
if (!virtio_vdev_has_feature(&n->parent_obj,
|
if (!virtio_vdev_has_feature(&n->parent_obj,
|
||||||
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||||
|
@ -841,15 +879,12 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s,
|
||||||
.iov_base = &offloads,
|
.iov_base = &offloads,
|
||||||
.iov_len = sizeof(offloads),
|
.iov_len = sizeof(offloads),
|
||||||
};
|
};
|
||||||
dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS,
|
VIRTIO_NET_CTRL_GUEST_OFFLOADS,
|
||||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET,
|
VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET,
|
||||||
&data, 1);
|
&data, 1);
|
||||||
if (unlikely(dev_written < 0)) {
|
if (unlikely(r < 0)) {
|
||||||
return dev_written;
|
return r;
|
||||||
}
|
|
||||||
if (*s->status != VIRTIO_NET_OK) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -865,16 +900,12 @@ static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s,
|
||||||
.iov_base = &on,
|
.iov_base = &on,
|
||||||
.iov_len = sizeof(on),
|
.iov_len = sizeof(on),
|
||||||
};
|
};
|
||||||
ssize_t dev_written;
|
ssize_t r;
|
||||||
|
|
||||||
dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||||
VIRTIO_NET_CTRL_RX,
|
VIRTIO_NET_CTRL_RX, cmd, &data, 1);
|
||||||
cmd, &data, 1);
|
if (unlikely(r < 0)) {
|
||||||
if (unlikely(dev_written < 0)) {
|
return r;
|
||||||
return dev_written;
|
|
||||||
}
|
|
||||||
if (*s->status != VIRTIO_NET_OK) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1031,15 +1062,12 @@ static int vhost_vdpa_net_load_single_vlan(VhostVDPAState *s,
|
||||||
.iov_base = &vid,
|
.iov_base = &vid,
|
||||||
.iov_len = sizeof(vid),
|
.iov_len = sizeof(vid),
|
||||||
};
|
};
|
||||||
ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||||
VIRTIO_NET_CTRL_VLAN,
|
VIRTIO_NET_CTRL_VLAN,
|
||||||
VIRTIO_NET_CTRL_VLAN_ADD,
|
VIRTIO_NET_CTRL_VLAN_ADD,
|
||||||
&data, 1);
|
&data, 1);
|
||||||
if (unlikely(dev_written < 0)) {
|
if (unlikely(r < 0)) {
|
||||||
return dev_written;
|
return r;
|
||||||
}
|
|
||||||
if (unlikely(*s->status != VIRTIO_NET_OK)) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1106,6 +1134,17 @@ static int vhost_vdpa_net_cvq_load(NetClientState *nc)
|
||||||
if (unlikely(r)) {
|
if (unlikely(r)) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to poll and check all pending device's used buffers.
|
||||||
|
*
|
||||||
|
* We can poll here since we've had BQL from the time
|
||||||
|
* we sent the descriptor.
|
||||||
|
*/
|
||||||
|
r = vhost_vdpa_net_svq_flush(s, in_cursor.iov_base - (void *)s->status);
|
||||||
|
if (unlikely(r)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < v->dev->vq_index; ++i) {
|
for (int i = 0; i < v->dev->vq_index; ++i) {
|
||||||
|
|
Loading…
Reference in New Issue