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
165
net/vhost-vdpa.c
165
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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
struct iovec *out_cursor,
|
||||
struct iovec *in_cursor, uint8_t class,
|
||||
@ -671,11 +696,31 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s,
|
||||
.class = class,
|
||||
.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;
|
||||
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));
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can poll here since we've had BQL from the time
|
||||
* we sent the descriptor.
|
||||
*/
|
||||
return vhost_vdpa_net_svq_poll(s, 1);
|
||||
/* iterate the cursors */
|
||||
dummy_cursor_iov_cnt = 1;
|
||||
iov_discard_front(&out_cursor, &dummy_cursor_iov_cnt, cmd_size);
|
||||
dummy_cursor_iov_cnt = 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,
|
||||
@ -709,15 +756,12 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n,
|
||||
.iov_base = (void *)n->mac,
|
||||
.iov_len = sizeof(n->mac),
|
||||
};
|
||||
ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_MAC,
|
||||
VIRTIO_NET_CTRL_MAC_ADDR_SET,
|
||||
&data, 1);
|
||||
if (unlikely(dev_written < 0)) {
|
||||
return dev_written;
|
||||
}
|
||||
if (*s->status != VIRTIO_NET_OK) {
|
||||
return -EIO;
|
||||
ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_MAC,
|
||||
VIRTIO_NET_CTRL_MAC_ADDR_SET,
|
||||
&data, 1);
|
||||
if (unlikely(r < 0)) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,15 +806,12 @@ static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n,
|
||||
.iov_len = mul_macs_size,
|
||||
},
|
||||
};
|
||||
ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_MAC,
|
||||
VIRTIO_NET_CTRL_MAC_TABLE_SET,
|
||||
data, ARRAY_SIZE(data));
|
||||
if (unlikely(dev_written < 0)) {
|
||||
return dev_written;
|
||||
}
|
||||
if (*s->status != VIRTIO_NET_OK) {
|
||||
return -EIO;
|
||||
ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_MAC,
|
||||
VIRTIO_NET_CTRL_MAC_TABLE_SET,
|
||||
data, ARRAY_SIZE(data));
|
||||
if (unlikely(r < 0)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -782,7 +823,7 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s,
|
||||
struct iovec *in_cursor)
|
||||
{
|
||||
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)) {
|
||||
return 0;
|
||||
@ -793,15 +834,12 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s,
|
||||
.iov_base = &mq,
|
||||
.iov_len = sizeof(mq),
|
||||
};
|
||||
dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_MQ,
|
||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET,
|
||||
&data, 1);
|
||||
if (unlikely(dev_written < 0)) {
|
||||
return dev_written;
|
||||
}
|
||||
if (*s->status != VIRTIO_NET_OK) {
|
||||
return -EIO;
|
||||
r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_MQ,
|
||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET,
|
||||
&data, 1);
|
||||
if (unlikely(r < 0)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -813,7 +851,7 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s,
|
||||
struct iovec *in_cursor)
|
||||
{
|
||||
uint64_t offloads;
|
||||
ssize_t dev_written;
|
||||
ssize_t r;
|
||||
|
||||
if (!virtio_vdev_has_feature(&n->parent_obj,
|
||||
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
@ -841,15 +879,12 @@ static int vhost_vdpa_net_load_offloads(VhostVDPAState *s,
|
||||
.iov_base = &offloads,
|
||||
.iov_len = sizeof(offloads),
|
||||
};
|
||||
dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS,
|
||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET,
|
||||
&data, 1);
|
||||
if (unlikely(dev_written < 0)) {
|
||||
return dev_written;
|
||||
}
|
||||
if (*s->status != VIRTIO_NET_OK) {
|
||||
return -EIO;
|
||||
r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS,
|
||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET,
|
||||
&data, 1);
|
||||
if (unlikely(r < 0)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -865,16 +900,12 @@ static int vhost_vdpa_net_load_rx_mode(VhostVDPAState *s,
|
||||
.iov_base = &on,
|
||||
.iov_len = sizeof(on),
|
||||
};
|
||||
ssize_t dev_written;
|
||||
ssize_t r;
|
||||
|
||||
dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_RX,
|
||||
cmd, &data, 1);
|
||||
if (unlikely(dev_written < 0)) {
|
||||
return dev_written;
|
||||
}
|
||||
if (*s->status != VIRTIO_NET_OK) {
|
||||
return -EIO;
|
||||
r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_RX, cmd, &data, 1);
|
||||
if (unlikely(r < 0)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1031,15 +1062,12 @@ static int vhost_vdpa_net_load_single_vlan(VhostVDPAState *s,
|
||||
.iov_base = &vid,
|
||||
.iov_len = sizeof(vid),
|
||||
};
|
||||
ssize_t dev_written = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_VLAN,
|
||||
VIRTIO_NET_CTRL_VLAN_ADD,
|
||||
&data, 1);
|
||||
if (unlikely(dev_written < 0)) {
|
||||
return dev_written;
|
||||
}
|
||||
if (unlikely(*s->status != VIRTIO_NET_OK)) {
|
||||
return -EIO;
|
||||
ssize_t r = vhost_vdpa_net_load_cmd(s, out_cursor, in_cursor,
|
||||
VIRTIO_NET_CTRL_VLAN,
|
||||
VIRTIO_NET_CTRL_VLAN_ADD,
|
||||
&data, 1);
|
||||
if (unlikely(r < 0)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1106,6 +1134,17 @@ static int vhost_vdpa_net_cvq_load(NetClientState *nc)
|
||||
if (unlikely(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) {
|
||||
|
Loading…
Reference in New Issue
Block a user