1
The following changes since commit 7d3660e79830a069f1848bb4fa1cdf8f666424fb:
1
The following changes since commit 352998df1c53b366413690d95b35f76d0721ebed:
2
2
3
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging (2020-06-12 23:06:22 +0100)
3
Merge tag 'i2c-20220314' of https://github.com/philmd/qemu into staging (2022-03-14 14:39:33 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
https://github.com/jasowang/qemu.git tags/net-pull-request
7
https://github.com/jasowang/qemu.git tags/net-pull-request
8
8
9
for you to fetch changes up to 955aab203f932b8a7c23ff9c58ba036997cb3ed8:
9
for you to fetch changes up to 12a195fa343aae2ead1301ce04727bd0ae25eb15:
10
10
11
net: Drop the NetLegacy structure, always use Netdev instead (2020-06-16 14:40:40 +0800)
11
vdpa: Expose VHOST_F_LOG_ALL on SVQ (2022-03-15 13:57:44 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
Changes since V2:
16
- fix 32bit build errros
17
15
----------------------------------------------------------------
18
----------------------------------------------------------------
16
Derek Su (1):
19
Eugenio Pérez (14):
17
colo-compare: Fix memory leak in packet_enqueue()
20
vhost: Add VhostShadowVirtqueue
18
21
vhost: Add Shadow VirtQueue kick forwarding capabilities
19
Helge Deller (1):
22
vhost: Add Shadow VirtQueue call forwarding capabilities
20
Fix tulip breakage
23
vhost: Add vhost_svq_valid_features to shadow vq
24
virtio: Add vhost_svq_get_vring_addr
25
vdpa: adapt vhost_ops callbacks to svq
26
vhost: Shadow virtqueue buffers forwarding
27
util: Add iova_tree_alloc_map
28
util: add iova_tree_find_iova
29
vhost: Add VhostIOVATree
30
vdpa: Add custom IOTLB translations to SVQ
31
vdpa: Adapt vhost_vdpa_get_vring_base to SVQ
32
vdpa: Never set log_base addr if SVQ is enabled
33
vdpa: Expose VHOST_F_LOG_ALL on SVQ
21
34
22
Jason Wang (1):
35
Jason Wang (1):
23
net: use peer when purging queue in qemu_flush_or_purge_queue_packets()
36
virtio-net: fix map leaking on error during receive
24
37
25
Lukas Straub (6):
38
hw/net/virtio-net.c | 1 +
26
net/colo-compare.c: Create event_bh with the right AioContext
39
hw/virtio/meson.build | 2 +-
27
chardev/char.c: Use qemu_co_sleep_ns if in coroutine
40
hw/virtio/vhost-iova-tree.c | 110 +++++++
28
net/colo-compare.c: Fix deadlock in compare_chr_send
41
hw/virtio/vhost-iova-tree.h | 27 ++
29
net/colo-compare.c: Only hexdump packets if tracing is enabled
42
hw/virtio/vhost-shadow-virtqueue.c | 636 +++++++++++++++++++++++++++++++++++++
30
net/colo-compare.c: Check that colo-compare is active
43
hw/virtio/vhost-shadow-virtqueue.h | 87 +++++
31
net/colo-compare.c: Correct ordering in complete and finalize
44
hw/virtio/vhost-vdpa.c | 522 +++++++++++++++++++++++++++++-
32
45
include/hw/virtio/vhost-vdpa.h | 8 +
33
Philippe Mathieu-Daudé (3):
46
include/qemu/iova-tree.h | 38 ++-
34
hw/net/tulip: Fix 'Descriptor Error' definition
47
util/iova-tree.c | 170 ++++++++++
35
hw/net/tulip: Log descriptor overflows
48
10 files changed, 1584 insertions(+), 17 deletions(-)
36
hw/net/e1000e: Do not abort() on invalid PSRCTL register value
49
create mode 100644 hw/virtio/vhost-iova-tree.c
37
50
create mode 100644 hw/virtio/vhost-iova-tree.h
38
Sai Pavan Boddu (11):
51
create mode 100644 hw/virtio/vhost-shadow-virtqueue.c
39
net: cadence_gem: Fix debug statements
52
create mode 100644 hw/virtio/vhost-shadow-virtqueue.h
40
net: cadence_gem: Fix the queue address update during wrap around
41
net: cadence_gem: Fix irq update w.r.t queue
42
net: cadence_gem: Define access permission for interrupt registers
43
net: cadence_gem: Set ISR according to queue in use
44
net: cadence_gem: Move tx/rx packet buffert to CadenceGEMState
45
net: cadence_gem: Fix up code style
46
net: cadence_gem: Add support for jumbo frames
47
net: cadnece_gem: Update irq_read_clear field of designcfg_debug1 reg
48
net: cadence_gem: Update the reset value for interrupt mask register
49
net: cadence_gem: TX_LAST bit should be set by guest
50
51
Thomas Huth (2):
52
net: Drop the legacy "name" parameter from the -net option
53
net: Drop the NetLegacy structure, always use Netdev instead
54
55
Tong Ho (1):
56
net: cadence_gem: Fix RX address filtering
57
58
Yuri Benditovich (7):
59
virtio-net: implement RSS configuration command
60
virtio-net: implement RX RSS processing
61
tap: allow extended virtio header with hash info
62
virtio-net: reference implementation of hash report
63
vmstate.h: provide VMSTATE_VARRAY_UINT16_ALLOC macro
64
virtio-net: add migration support for RSS and hash report
65
virtio-net: align RSC fields with updated virtio-net header
66
67
chardev/char.c | 7 +-
68
docs/system/deprecated.rst | 15 +-
69
hw/net/cadence_gem.c | 458 +++++++++++++++++++++++------------------
70
hw/net/e1000e_core.c | 10 +-
71
hw/net/trace-events | 3 +
72
hw/net/tulip.c | 12 +-
73
hw/net/tulip.h | 2 +-
74
hw/net/virtio-net.c | 387 ++++++++++++++++++++++++++++++----
75
include/hw/net/cadence_gem.h | 6 +
76
include/hw/virtio/virtio-net.h | 16 ++
77
include/migration/vmstate.h | 10 +
78
net/colo-compare.c | 277 ++++++++++++++++++-------
79
net/colo.c | 7 +
80
net/colo.h | 1 +
81
net/net.c | 89 ++------
82
net/tap.c | 3 +-
83
net/trace-events | 1 +
84
qapi/net.json | 49 -----
85
18 files changed, 904 insertions(+), 449 deletions(-)
86
53
87
54
88
55
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
Commit bedd7e93d0196 ("virtio-net: fix use after unmap/free for sg")
2
tries to fix the use after free of the sg by caching the virtqueue
3
elements in an array and unmap them at once after receiving the
4
packets, But it forgot to unmap the cached elements on error which
5
will lead to leaking of mapping and other unexpected results.
2
6
3
Save and restore RSS/hash report configuration.
7
Fixing this by detaching the cached elements on error. This addresses
8
CVE-2022-26353.
4
9
5
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
10
Reported-by: Victor Tom <vv474172261@gmail.com>
11
Cc: qemu-stable@nongnu.org
12
Fixes: CVE-2022-26353
13
Fixes: bedd7e93d0196 ("virtio-net: fix use after unmap/free for sg")
14
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
16
---
8
hw/net/virtio-net.c | 37 +++++++++++++++++++++++++++++++++++++
17
hw/net/virtio-net.c | 1 +
9
1 file changed, 37 insertions(+)
18
1 file changed, 1 insertion(+)
10
19
11
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
20
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
12
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/net/virtio-net.c
22
--- a/hw/net/virtio-net.c
14
+++ b/hw/net/virtio-net.c
23
+++ b/hw/net/virtio-net.c
15
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
24
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
16
}
25
26
err:
27
for (j = 0; j < i; j++) {
28
+ virtqueue_detach_element(q->rx_vq, elems[j], lens[j]);
29
g_free(elems[j]);
17
}
30
}
18
31
19
+ if (n->rss_data.enabled) {
20
+ trace_virtio_net_rss_enable(n->rss_data.hash_types,
21
+ n->rss_data.indirections_len,
22
+ sizeof(n->rss_data.key));
23
+ } else {
24
+ trace_virtio_net_rss_disable();
25
+ }
26
return 0;
27
}
28
29
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_virtio_net_has_vnet = {
30
},
31
};
32
33
+static bool virtio_net_rss_needed(void *opaque)
34
+{
35
+ return VIRTIO_NET(opaque)->rss_data.enabled;
36
+}
37
+
38
+static const VMStateDescription vmstate_virtio_net_rss = {
39
+ .name = "virtio-net-device/rss",
40
+ .version_id = 1,
41
+ .minimum_version_id = 1,
42
+ .needed = virtio_net_rss_needed,
43
+ .fields = (VMStateField[]) {
44
+ VMSTATE_BOOL(rss_data.enabled, VirtIONet),
45
+ VMSTATE_BOOL(rss_data.redirect, VirtIONet),
46
+ VMSTATE_BOOL(rss_data.populate_hash, VirtIONet),
47
+ VMSTATE_UINT32(rss_data.hash_types, VirtIONet),
48
+ VMSTATE_UINT16(rss_data.indirections_len, VirtIONet),
49
+ VMSTATE_UINT16(rss_data.default_queue, VirtIONet),
50
+ VMSTATE_UINT8_ARRAY(rss_data.key, VirtIONet,
51
+ VIRTIO_NET_RSS_MAX_KEY_SIZE),
52
+ VMSTATE_VARRAY_UINT16_ALLOC(rss_data.indirections_table, VirtIONet,
53
+ rss_data.indirections_len, 0,
54
+ vmstate_info_uint16, uint16_t),
55
+ VMSTATE_END_OF_LIST()
56
+ },
57
+};
58
+
59
static const VMStateDescription vmstate_virtio_net_device = {
60
.name = "virtio-net-device",
61
.version_id = VIRTIO_NET_VM_VERSION,
62
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_virtio_net_device = {
63
has_ctrl_guest_offloads),
64
VMSTATE_END_OF_LIST()
65
},
66
+ .subsections = (const VMStateDescription * []) {
67
+ &vmstate_virtio_net_rss,
68
+ NULL
69
+ }
70
};
71
72
static NetClientInfo net_virtio_info = {
73
--
32
--
74
2.5.0
33
2.7.4
75
76
diff view generated by jsdifflib
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Set ISR according to queue in use, added interrupt support for
3
Vhost shadow virtqueue (SVQ) is an intermediate jump for virtqueue
4
all queues.
4
notifications and buffers, allowing qemu to track them. While qemu is
5
forwarding the buffers and virtqueue changes, it is able to commit the
6
memory it's being dirtied, the same way regular qemu's VirtIO devices
7
do.
5
8
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
9
This commit only exposes basic SVQ allocation and free. Next patches of
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
the series add functionality like notifications and buffers forwarding.
11
12
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
13
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
15
---
10
hw/net/cadence_gem.c | 27 +++++++++++++++++----------
16
hw/virtio/meson.build | 2 +-
11
1 file changed, 17 insertions(+), 10 deletions(-)
17
hw/virtio/vhost-shadow-virtqueue.c | 62 ++++++++++++++++++++++++++++++++++++++
18
hw/virtio/vhost-shadow-virtqueue.h | 28 +++++++++++++++++
19
3 files changed, 91 insertions(+), 1 deletion(-)
20
create mode 100644 hw/virtio/vhost-shadow-virtqueue.c
21
create mode 100644 hw/virtio/vhost-shadow-virtqueue.h
12
22
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
23
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
25
--- a/hw/virtio/meson.build
16
+++ b/hw/net/cadence_gem.c
26
+++ b/hw/virtio/meson.build
17
@@ -XXX,XX +XXX,XX @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx)
27
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c'))
18
/* The broadcast MAC address: 0xFFFFFFFFFFFF */
28
19
static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
29
virtio_ss = ss.source_set()
20
30
virtio_ss.add(files('virtio.c'))
21
+static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag)
31
-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c'))
32
+virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c'))
33
virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c'))
34
virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c'))
35
virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c'))
36
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
37
new file mode 100644
38
index XXXXXXX..XXXXXXX
39
--- /dev/null
40
+++ b/hw/virtio/vhost-shadow-virtqueue.c
41
@@ -XXX,XX +XXX,XX @@
42
+/*
43
+ * vhost shadow virtqueue
44
+ *
45
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
46
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
47
+ *
48
+ * SPDX-License-Identifier: GPL-2.0-or-later
49
+ */
50
+
51
+#include "qemu/osdep.h"
52
+#include "hw/virtio/vhost-shadow-virtqueue.h"
53
+
54
+#include "qemu/error-report.h"
55
+
56
+/**
57
+ * Creates vhost shadow virtqueue, and instructs the vhost device to use the
58
+ * shadow methods and file descriptors.
59
+ *
60
+ * Returns the new virtqueue or NULL.
61
+ *
62
+ * In case of error, reason is reported through error_report.
63
+ */
64
+VhostShadowVirtqueue *vhost_svq_new(void)
22
+{
65
+{
23
+ if (q == 0) {
66
+ g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1);
24
+ s->regs[GEM_ISR] |= flag & ~(s->regs[GEM_IMR]);
67
+ int r;
25
+ } else {
68
+
26
+ s->regs[GEM_INT_Q1_STATUS + q - 1] |= flag &
69
+ r = event_notifier_init(&svq->hdev_kick, 0);
27
+ ~(s->regs[GEM_INT_Q1_MASK + q - 1]);
70
+ if (r != 0) {
71
+ error_report("Couldn't create kick event notifier: %s (%d)",
72
+ g_strerror(errno), errno);
73
+ goto err_init_hdev_kick;
28
+ }
74
+ }
75
+
76
+ r = event_notifier_init(&svq->hdev_call, 0);
77
+ if (r != 0) {
78
+ error_report("Couldn't create call event notifier: %s (%d)",
79
+ g_strerror(errno), errno);
80
+ goto err_init_hdev_call;
81
+ }
82
+
83
+ return g_steal_pointer(&svq);
84
+
85
+err_init_hdev_call:
86
+ event_notifier_cleanup(&svq->hdev_kick);
87
+
88
+err_init_hdev_kick:
89
+ return NULL;
29
+}
90
+}
30
+
91
+
31
/*
92
+/**
32
* gem_init_register_masks:
93
+ * Free the resources of the shadow virtqueue.
33
* One time initialization.
94
+ *
34
@@ -XXX,XX +XXX,XX @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
95
+ * @pvq: gpointer to SVQ so it can be used by autofree functions.
35
if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
96
+ */
36
DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr);
97
+void vhost_svq_free(gpointer pvq)
37
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
98
+{
38
- s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
99
+ VhostShadowVirtqueue *vq = pvq;
39
+ gem_set_isr(s, q, GEM_INT_RXUSED);
100
+ event_notifier_cleanup(&vq->hdev_kick);
40
/* Handle interrupt consequences */
101
+ event_notifier_cleanup(&vq->hdev_call);
41
gem_update_int_status(s);
102
+ g_free(vq);
42
}
103
+}
43
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
104
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
44
gem_receive_updatestats(s, buf, size);
105
new file mode 100644
45
106
index XXXXXXX..XXXXXXX
46
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
107
--- /dev/null
47
- s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]);
108
+++ b/hw/virtio/vhost-shadow-virtqueue.h
48
+ gem_set_isr(s, q, GEM_INT_RXCMPL);
109
@@ -XXX,XX +XXX,XX @@
49
110
+/*
50
/* Handle interrupt consequences */
111
+ * vhost shadow virtqueue
51
gem_update_int_status(s);
112
+ *
52
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
113
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
53
DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);
114
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
54
115
+ *
55
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
116
+ * SPDX-License-Identifier: GPL-2.0-or-later
56
- s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
117
+ */
57
-
118
+
58
- /* Update queue interrupt status */
119
+#ifndef VHOST_SHADOW_VIRTQUEUE_H
59
- if (s->num_priority_queues > 1) {
120
+#define VHOST_SHADOW_VIRTQUEUE_H
60
- s->regs[GEM_INT_Q1_STATUS + q] |=
121
+
61
- GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]);
122
+#include "qemu/event_notifier.h"
62
- }
123
+
63
+ gem_set_isr(s, q, GEM_INT_TXCMPL);
124
+/* Shadow virtqueue to relay notifications */
64
125
+typedef struct VhostShadowVirtqueue {
65
/* Handle interrupt consequences */
126
+ /* Shadow kick notifier, sent to vhost */
66
gem_update_int_status(s);
127
+ EventNotifier hdev_kick;
67
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
128
+ /* Shadow call notifier, sent to vhost */
68
129
+ EventNotifier hdev_call;
69
if (tx_desc_get_used(desc)) {
130
+} VhostShadowVirtqueue;
70
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED;
131
+
71
- s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
132
+VhostShadowVirtqueue *vhost_svq_new(void);
72
+ /* IRQ TXUSED is defined only for queue 0 */
133
+
73
+ if (q == 0) {
134
+void vhost_svq_free(gpointer vq);
74
+ gem_set_isr(s, 0, GEM_INT_TXUSED);
135
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
75
+ }
136
+
76
gem_update_int_status(s);
137
+#endif
77
}
78
}
79
--
138
--
80
2.5.0
139
2.7.4
81
140
82
141
diff view generated by jsdifflib
1
From: Lukas Straub <lukasstraub2@web.de>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
In colo_compare_complete, insert CompareState into net_compares
3
At this mode no buffer forwarding will be performed in SVQ mode: Qemu
4
only after everything has been initialized.
4
will just forward the guest's kicks to the device.
5
In colo_compare_finalize, remove CompareState from net_compares
5
6
before anything is deinitialized.
6
Host memory notifiers regions are left out for simplicity, and they will
7
7
not be addressed in this series.
8
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
8
9
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
12
---
13
net/colo-compare.c | 45 +++++++++++++++++++++++----------------------
13
hw/virtio/vhost-shadow-virtqueue.c | 55 ++++++++++++++
14
1 file changed, 23 insertions(+), 22 deletions(-)
14
hw/virtio/vhost-shadow-virtqueue.h | 14 ++++
15
15
hw/virtio/vhost-vdpa.c | 144 ++++++++++++++++++++++++++++++++++++-
16
diff --git a/net/colo-compare.c b/net/colo-compare.c
16
include/hw/virtio/vhost-vdpa.h | 4 ++
17
4 files changed, 215 insertions(+), 2 deletions(-)
18
19
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/net/colo-compare.c
21
--- a/hw/virtio/vhost-shadow-virtqueue.c
19
+++ b/net/colo-compare.c
22
+++ b/hw/virtio/vhost-shadow-virtqueue.c
20
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
23
@@ -XXX,XX +XXX,XX @@
21
s->vnet_hdr);
24
#include "hw/virtio/vhost-shadow-virtqueue.h"
25
26
#include "qemu/error-report.h"
27
+#include "qemu/main-loop.h"
28
+#include "linux-headers/linux/vhost.h"
29
+
30
+/**
31
+ * Forward guest notifications.
32
+ *
33
+ * @n: guest kick event notifier, the one that guest set to notify svq.
34
+ */
35
+static void vhost_handle_guest_kick(EventNotifier *n)
36
+{
37
+ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick);
38
+ event_notifier_test_and_clear(n);
39
+ event_notifier_set(&svq->hdev_kick);
40
+}
41
+
42
+/**
43
+ * Set a new file descriptor for the guest to kick the SVQ and notify for avail
44
+ *
45
+ * @svq: The svq
46
+ * @svq_kick_fd: The svq kick fd
47
+ *
48
+ * Note that the SVQ will never close the old file descriptor.
49
+ */
50
+void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
51
+{
52
+ EventNotifier *svq_kick = &svq->svq_kick;
53
+ bool poll_stop = VHOST_FILE_UNBIND != event_notifier_get_fd(svq_kick);
54
+ bool poll_start = svq_kick_fd != VHOST_FILE_UNBIND;
55
+
56
+ if (poll_stop) {
57
+ event_notifier_set_handler(svq_kick, NULL);
58
+ }
59
+
60
+ /*
61
+ * event_notifier_set_handler already checks for guest's notifications if
62
+ * they arrive at the new file descriptor in the switch, so there is no
63
+ * need to explicitly check for them.
64
+ */
65
+ if (poll_start) {
66
+ event_notifier_init_fd(svq_kick, svq_kick_fd);
67
+ event_notifier_set(svq_kick);
68
+ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick);
69
+ }
70
+}
71
+
72
+/**
73
+ * Stop the shadow virtqueue operation.
74
+ * @svq: Shadow Virtqueue
75
+ */
76
+void vhost_svq_stop(VhostShadowVirtqueue *svq)
77
+{
78
+ event_notifier_set_handler(&svq->svq_kick, NULL);
79
+}
80
81
/**
82
* Creates vhost shadow virtqueue, and instructs the vhost device to use the
83
@@ -XXX,XX +XXX,XX @@ VhostShadowVirtqueue *vhost_svq_new(void)
84
goto err_init_hdev_call;
22
}
85
}
23
86
24
- qemu_mutex_lock(&colo_compare_mutex);
87
+ event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
25
- if (!colo_compare_active) {
88
return g_steal_pointer(&svq);
26
- qemu_mutex_init(&event_mtx);
89
27
- qemu_cond_init(&event_complete_cond);
90
err_init_hdev_call:
28
- colo_compare_active = true;
91
@@ -XXX,XX +XXX,XX @@ err_init_hdev_kick:
29
- }
92
void vhost_svq_free(gpointer pvq)
30
- QTAILQ_INSERT_TAIL(&net_compares, s, next);
93
{
31
- qemu_mutex_unlock(&colo_compare_mutex);
94
VhostShadowVirtqueue *vq = pvq;
32
-
95
+ vhost_svq_stop(vq);
33
s->out_sendco.s = s;
96
event_notifier_cleanup(&vq->hdev_kick);
34
s->out_sendco.chr = &s->chr_out;
97
event_notifier_cleanup(&vq->hdev_call);
35
s->out_sendco.notify_remote_frame = false;
98
g_free(vq);
36
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
99
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
37
connection_destroy);
100
index XXXXXXX..XXXXXXX 100644
38
101
--- a/hw/virtio/vhost-shadow-virtqueue.h
39
colo_compare_iothread(s);
102
+++ b/hw/virtio/vhost-shadow-virtqueue.h
40
+
103
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
41
+ qemu_mutex_lock(&colo_compare_mutex);
104
EventNotifier hdev_kick;
42
+ if (!colo_compare_active) {
105
/* Shadow call notifier, sent to vhost */
43
+ qemu_mutex_init(&event_mtx);
106
EventNotifier hdev_call;
44
+ qemu_cond_init(&event_complete_cond);
107
+
45
+ colo_compare_active = true;
108
+ /*
46
+ }
109
+ * Borrowed virtqueue's guest to host notifier. To borrow it in this event
47
+ QTAILQ_INSERT_TAIL(&net_compares, s, next);
110
+ * notifier allows to recover the VhostShadowVirtqueue from the event loop
48
+ qemu_mutex_unlock(&colo_compare_mutex);
111
+ * easily. If we use the VirtQueue's one, we don't have an easy way to
49
+
112
+ * retrieve VhostShadowVirtqueue.
113
+ *
114
+ * So shadow virtqueue must not clean it, or we would lose VirtQueue one.
115
+ */
116
+ EventNotifier svq_kick;
117
} VhostShadowVirtqueue;
118
119
+void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
120
+
121
+void vhost_svq_stop(VhostShadowVirtqueue *svq);
122
+
123
VhostShadowVirtqueue *vhost_svq_new(void);
124
125
void vhost_svq_free(gpointer vq);
126
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/hw/virtio/vhost-vdpa.c
129
+++ b/hw/virtio/vhost-vdpa.c
130
@@ -XXX,XX +XXX,XX @@
131
#include "hw/virtio/vhost.h"
132
#include "hw/virtio/vhost-backend.h"
133
#include "hw/virtio/virtio-net.h"
134
+#include "hw/virtio/vhost-shadow-virtqueue.h"
135
#include "hw/virtio/vhost-vdpa.h"
136
#include "exec/address-spaces.h"
137
#include "qemu/main-loop.h"
138
#include "cpu.h"
139
#include "trace.h"
140
#include "qemu-common.h"
141
+#include "qapi/error.h"
142
143
/*
144
* Return one past the end of the end of section. Be careful with uint64_t
145
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev)
146
return v->index != 0;
147
}
148
149
+static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
150
+ Error **errp)
151
+{
152
+ g_autoptr(GPtrArray) shadow_vqs = NULL;
153
+
154
+ if (!v->shadow_vqs_enabled) {
155
+ return 0;
156
+ }
157
+
158
+ shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
159
+ for (unsigned n = 0; n < hdev->nvqs; ++n) {
160
+ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();
161
+
162
+ if (unlikely(!svq)) {
163
+ error_setg(errp, "Cannot create svq %u", n);
164
+ return -1;
165
+ }
166
+ g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq));
167
+ }
168
+
169
+ v->shadow_vqs = g_steal_pointer(&shadow_vqs);
170
+ return 0;
171
+}
172
+
173
static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
174
{
175
struct vhost_vdpa *v;
176
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
177
dev->opaque = opaque ;
178
v->listener = vhost_vdpa_memory_listener;
179
v->msg_type = VHOST_IOTLB_MSG_V2;
180
+ ret = vhost_vdpa_init_svq(dev, v, errp);
181
+ if (ret) {
182
+ goto err;
183
+ }
184
185
vhost_vdpa_get_iova_range(v);
186
187
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
188
VIRTIO_CONFIG_S_DRIVER);
189
190
return 0;
191
+
192
+err:
193
+ ram_block_discard_disable(false);
194
+ return ret;
195
}
196
197
static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev,
198
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n)
199
200
static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev)
201
{
202
+ struct vhost_vdpa *v = dev->opaque;
203
int i;
204
205
+ if (v->shadow_vqs_enabled) {
206
+ /* FIXME SVQ is not compatible with host notifiers mr */
207
+ return;
208
+ }
209
+
210
for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) {
211
if (vhost_vdpa_host_notifier_init(dev, i)) {
212
goto err;
213
@@ -XXX,XX +XXX,XX @@ err:
50
return;
214
return;
51
}
215
}
52
216
53
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
217
+static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev)
54
CompareState *s = COLO_COMPARE(obj);
218
+{
55
CompareState *tmp = NULL;
219
+ struct vhost_vdpa *v = dev->opaque;
56
220
+ size_t idx;
57
- qemu_chr_fe_deinit(&s->chr_pri_in, false);
221
+
58
- qemu_chr_fe_deinit(&s->chr_sec_in, false);
222
+ if (!v->shadow_vqs) {
59
- qemu_chr_fe_deinit(&s->chr_out, false);
223
+ return;
60
- if (s->notify_dev) {
224
+ }
61
- qemu_chr_fe_deinit(&s->chr_notify_dev, false);
225
+
62
- }
226
+ for (idx = 0; idx < v->shadow_vqs->len; ++idx) {
63
-
227
+ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx));
64
- if (s->iothread) {
228
+ }
65
- colo_compare_timer_del(s);
229
+ g_ptr_array_free(v->shadow_vqs, true);
66
- }
230
+}
67
-
231
+
68
- qemu_bh_delete(s->event_bh);
232
static int vhost_vdpa_cleanup(struct vhost_dev *dev)
69
-
233
{
70
qemu_mutex_lock(&colo_compare_mutex);
234
struct vhost_vdpa *v;
71
QTAILQ_FOREACH(tmp, &net_compares, next) {
235
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev)
72
if (tmp == s) {
236
trace_vhost_vdpa_cleanup(dev, v);
73
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
237
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
74
}
238
memory_listener_unregister(&v->listener);
75
qemu_mutex_unlock(&colo_compare_mutex);
239
+ vhost_vdpa_svq_cleanup(dev);
76
240
77
+ qemu_chr_fe_deinit(&s->chr_pri_in, false);
241
dev->opaque = NULL;
78
+ qemu_chr_fe_deinit(&s->chr_sec_in, false);
242
ram_block_discard_disable(false);
79
+ qemu_chr_fe_deinit(&s->chr_out, false);
243
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
80
+ if (s->notify_dev) {
244
return ret;
81
+ qemu_chr_fe_deinit(&s->chr_notify_dev, false);
245
}
82
+ }
246
83
+
247
+static void vhost_vdpa_reset_svq(struct vhost_vdpa *v)
84
+ if (s->iothread) {
248
+{
85
+ colo_compare_timer_del(s);
249
+ if (!v->shadow_vqs_enabled) {
86
+ }
250
+ return;
87
+
251
+ }
88
+ qemu_bh_delete(s->event_bh);
252
+
89
+
253
+ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {
90
AioContext *ctx = iothread_get_aio_context(s->iothread);
254
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
91
aio_context_acquire(ctx);
255
+ vhost_svq_stop(svq);
92
AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
256
+ }
257
+}
258
+
259
static int vhost_vdpa_reset_device(struct vhost_dev *dev)
260
{
261
+ struct vhost_vdpa *v = dev->opaque;
262
int ret;
263
uint8_t status = 0;
264
265
+ vhost_vdpa_reset_svq(v);
266
+
267
ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
268
trace_vhost_vdpa_reset_device(dev, status);
269
return ret;
270
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config,
271
return ret;
272
}
273
274
+static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
275
+ struct vhost_vring_file *file)
276
+{
277
+ trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd);
278
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
279
+}
280
+
281
+/**
282
+ * Set the shadow virtqueue descriptors to the device
283
+ *
284
+ * @dev: The vhost device model
285
+ * @svq: The shadow virtqueue
286
+ * @idx: The index of the virtqueue in the vhost device
287
+ * @errp: Error
288
+ */
289
+static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
290
+ VhostShadowVirtqueue *svq, unsigned idx,
291
+ Error **errp)
292
+{
293
+ struct vhost_vring_file file = {
294
+ .index = dev->vq_index + idx,
295
+ };
296
+ const EventNotifier *event_notifier = &svq->hdev_kick;
297
+ int r;
298
+
299
+ file.fd = event_notifier_get_fd(event_notifier);
300
+ r = vhost_vdpa_set_vring_dev_kick(dev, &file);
301
+ if (unlikely(r != 0)) {
302
+ error_setg_errno(errp, -r, "Can't set device kick fd");
303
+ }
304
+
305
+ return r == 0;
306
+}
307
+
308
+static bool vhost_vdpa_svqs_start(struct vhost_dev *dev)
309
+{
310
+ struct vhost_vdpa *v = dev->opaque;
311
+ Error *err = NULL;
312
+ unsigned i;
313
+
314
+ if (!v->shadow_vqs) {
315
+ return true;
316
+ }
317
+
318
+ for (i = 0; i < v->shadow_vqs->len; ++i) {
319
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
320
+ bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err);
321
+ if (unlikely(!ok)) {
322
+ error_reportf_err(err, "Cannot setup SVQ %u: ", i);
323
+ return false;
324
+ }
325
+ }
326
+
327
+ return true;
328
+}
329
+
330
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
331
{
332
struct vhost_vdpa *v = dev->opaque;
333
+ bool ok;
334
trace_vhost_vdpa_dev_start(dev, started);
335
336
if (started) {
337
vhost_vdpa_host_notifiers_init(dev);
338
+ ok = vhost_vdpa_svqs_start(dev);
339
+ if (unlikely(!ok)) {
340
+ return -1;
341
+ }
342
vhost_vdpa_set_vring_ready(dev);
343
} else {
344
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
345
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
346
static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev,
347
struct vhost_vring_file *file)
348
{
349
- trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd);
350
- return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
351
+ struct vhost_vdpa *v = dev->opaque;
352
+ int vdpa_idx = file->index - dev->vq_index;
353
+
354
+ if (v->shadow_vqs_enabled) {
355
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx);
356
+ vhost_svq_set_svq_kick_fd(svq, file->fd);
357
+ return 0;
358
+ } else {
359
+ return vhost_vdpa_set_vring_dev_kick(dev, file);
360
+ }
361
}
362
363
static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
364
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
365
index XXXXXXX..XXXXXXX 100644
366
--- a/include/hw/virtio/vhost-vdpa.h
367
+++ b/include/hw/virtio/vhost-vdpa.h
368
@@ -XXX,XX +XXX,XX @@
369
#ifndef HW_VIRTIO_VHOST_VDPA_H
370
#define HW_VIRTIO_VHOST_VDPA_H
371
372
+#include <gmodule.h>
373
+
374
#include "hw/virtio/virtio.h"
375
#include "standard-headers/linux/vhost_types.h"
376
377
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
378
bool iotlb_batch_begin_sent;
379
MemoryListener listener;
380
struct vhost_vdpa_iova_range iova_range;
381
+ bool shadow_vqs_enabled;
382
+ GPtrArray *shadow_vqs;
383
struct vhost_dev *dev;
384
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
385
} VhostVDPA;
93
--
386
--
94
2.5.0
387
2.7.4
95
388
96
389
diff view generated by jsdifflib
1
From: Lukas Straub <lukasstraub2@web.de>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
The chr_out chardev is connected to a filter-redirector
3
This will make qemu aware of the device used buffers, allowing it to
4
running in the main loop. qemu_chr_fe_write_all might block
4
write the guest memory with its contents if needed.
5
here in compare_chr_send if the (socket-)buffer is full.
6
If another filter-redirector in the main loop want's to
7
send data to chr_pri_in it might also block if the buffer
8
is full. This leads to a deadlock because both event loops
9
get blocked.
10
5
11
Fix this by converting compare_chr_send to a coroutine and
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
12
putting the packets in a send queue.
7
Acked-by: Michael S. Tsirkin <mst@redhat.com>
13
14
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
15
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
16
Tested-by: Zhang Chen <chen.zhang@intel.com>
17
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
18
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
19
---
9
---
20
net/colo-compare.c | 193 ++++++++++++++++++++++++++++++++++++++++-------------
10
hw/virtio/vhost-shadow-virtqueue.c | 38 ++++++++++++++++++++++++++++++++++++++
21
net/colo.c | 7 ++
11
hw/virtio/vhost-shadow-virtqueue.h | 4 ++++
22
net/colo.h | 1 +
12
hw/virtio/vhost-vdpa.c | 31 +++++++++++++++++++++++++++++--
23
3 files changed, 156 insertions(+), 45 deletions(-)
13
3 files changed, 71 insertions(+), 2 deletions(-)
24
14
25
diff --git a/net/colo-compare.c b/net/colo-compare.c
15
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
26
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
27
--- a/net/colo-compare.c
17
--- a/hw/virtio/vhost-shadow-virtqueue.c
28
+++ b/net/colo-compare.c
18
+++ b/hw/virtio/vhost-shadow-virtqueue.c
29
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ static void vhost_handle_guest_kick(EventNotifier *n)
30
#include "migration/migration.h"
31
#include "util.h"
32
33
+#include "block/aio-wait.h"
34
+#include "qemu/coroutine.h"
35
+
36
#define TYPE_COLO_COMPARE "colo-compare"
37
#define COLO_COMPARE(obj) \
38
OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE)
39
@@ -XXX,XX +XXX,XX @@ static int event_unhandled_count;
40
* |packet | |packet + |packet | |packet +
41
* +--------+ +--------+ +--------+ +--------+
42
*/
43
+
44
+typedef struct SendCo {
45
+ Coroutine *co;
46
+ struct CompareState *s;
47
+ CharBackend *chr;
48
+ GQueue send_list;
49
+ bool notify_remote_frame;
50
+ bool done;
51
+ int ret;
52
+} SendCo;
53
+
54
+typedef struct SendEntry {
55
+ uint32_t size;
56
+ uint32_t vnet_hdr_len;
57
+ uint8_t *buf;
58
+} SendEntry;
59
+
60
typedef struct CompareState {
61
Object parent;
62
63
@@ -XXX,XX +XXX,XX @@ typedef struct CompareState {
64
SocketReadState pri_rs;
65
SocketReadState sec_rs;
66
SocketReadState notify_rs;
67
+ SendCo out_sendco;
68
+ SendCo notify_sendco;
69
bool vnet_hdr;
70
uint32_t compare_timeout;
71
uint32_t expired_scan_cycle;
72
@@ -XXX,XX +XXX,XX @@ enum {
73
74
75
static int compare_chr_send(CompareState *s,
76
- const uint8_t *buf,
77
+ uint8_t *buf,
78
uint32_t size,
79
uint32_t vnet_hdr_len,
80
- bool notify_remote_frame);
81
+ bool notify_remote_frame,
82
+ bool zero_copy);
83
84
static bool packet_matches_str(const char *str,
85
const uint8_t *buf,
86
@@ -XXX,XX +XXX,XX @@ static void notify_remote_frame(CompareState *s)
87
char msg[] = "DO_CHECKPOINT";
88
int ret = 0;
89
90
- ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
91
+ ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
92
if (ret < 0) {
93
error_report("Notify Xen COLO-frame failed");
94
}
95
@@ -XXX,XX +XXX,XX @@ static void colo_release_primary_pkt(CompareState *s, Packet *pkt)
96
pkt->data,
97
pkt->size,
98
pkt->vnet_hdr_len,
99
- false);
100
+ false,
101
+ true);
102
if (ret < 0) {
103
error_report("colo send primary packet failed");
104
}
105
trace_colo_compare_main("packet same and release packet");
106
- packet_destroy(pkt, NULL);
107
+ packet_destroy_partial(pkt, NULL);
108
}
20
}
109
21
110
/*
22
/**
111
@@ -XXX,XX +XXX,XX @@ static void colo_compare_connection(void *opaque, void *user_data)
23
+ * Forward vhost notifications
112
}
24
+ *
113
}
25
+ * @n: hdev call event notifier, the one that device set to notify svq.
114
26
+ */
115
-static int compare_chr_send(CompareState *s,
27
+static void vhost_svq_handle_call(EventNotifier *n)
116
- const uint8_t *buf,
28
+{
117
- uint32_t size,
29
+ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue,
118
- uint32_t vnet_hdr_len,
30
+ hdev_call);
119
- bool notify_remote_frame)
31
+ event_notifier_test_and_clear(n);
120
+static void coroutine_fn _compare_chr_send(void *opaque)
32
+ event_notifier_set(&svq->svq_call);
121
{
122
+ SendCo *sendco = opaque;
123
+ CompareState *s = sendco->s;
124
int ret = 0;
125
- uint32_t len = htonl(size);
126
127
- if (!size) {
128
- return 0;
129
- }
130
+ while (!g_queue_is_empty(&sendco->send_list)) {
131
+ SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
132
+ uint32_t len = htonl(entry->size);
133
134
- if (notify_remote_frame) {
135
- ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
136
- (uint8_t *)&len,
137
- sizeof(len));
138
- } else {
139
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
140
- }
141
+ ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len));
142
143
- if (ret != sizeof(len)) {
144
- goto err;
145
- }
146
+ if (ret != sizeof(len)) {
147
+ g_free(entry->buf);
148
+ g_slice_free(SendEntry, entry);
149
+ goto err;
150
+ }
151
152
- if (s->vnet_hdr) {
153
- /*
154
- * We send vnet header len make other module(like filter-redirector)
155
- * know how to parse net packet correctly.
156
- */
157
- len = htonl(vnet_hdr_len);
158
+ if (!sendco->notify_remote_frame && s->vnet_hdr) {
159
+ /*
160
+ * We send vnet header len make other module(like filter-redirector)
161
+ * know how to parse net packet correctly.
162
+ */
163
+ len = htonl(entry->vnet_hdr_len);
164
165
- if (!notify_remote_frame) {
166
- ret = qemu_chr_fe_write_all(&s->chr_out,
167
+ ret = qemu_chr_fe_write_all(sendco->chr,
168
(uint8_t *)&len,
169
sizeof(len));
170
+
171
+ if (ret != sizeof(len)) {
172
+ g_free(entry->buf);
173
+ g_slice_free(SendEntry, entry);
174
+ goto err;
175
+ }
176
}
177
178
- if (ret != sizeof(len)) {
179
+ ret = qemu_chr_fe_write_all(sendco->chr,
180
+ (uint8_t *)entry->buf,
181
+ entry->size);
182
+
183
+ if (ret != entry->size) {
184
+ g_free(entry->buf);
185
+ g_slice_free(SendEntry, entry);
186
goto err;
187
}
188
+
189
+ g_free(entry->buf);
190
+ g_slice_free(SendEntry, entry);
191
}
192
193
+ sendco->ret = 0;
194
+ goto out;
195
+
196
+err:
197
+ while (!g_queue_is_empty(&sendco->send_list)) {
198
+ SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
199
+ g_free(entry->buf);
200
+ g_slice_free(SendEntry, entry);
201
+ }
202
+ sendco->ret = ret < 0 ? ret : -EIO;
203
+out:
204
+ sendco->co = NULL;
205
+ sendco->done = true;
206
+ aio_wait_kick();
207
+}
33
+}
208
+
34
+
209
+static int compare_chr_send(CompareState *s,
35
+/**
210
+ uint8_t *buf,
36
+ * Set the call notifier for the SVQ to call the guest
211
+ uint32_t size,
37
+ *
212
+ uint32_t vnet_hdr_len,
38
+ * @svq: Shadow virtqueue
213
+ bool notify_remote_frame,
39
+ * @call_fd: call notifier
214
+ bool zero_copy)
40
+ *
41
+ * Called on BQL context.
42
+ */
43
+void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd)
215
+{
44
+{
216
+ SendCo *sendco;
45
+ if (call_fd == VHOST_FILE_UNBIND) {
217
+ SendEntry *entry;
46
+ /*
47
+ * Fail event_notifier_set if called handling device call.
48
+ *
49
+ * SVQ still needs device notifications, since it needs to keep
50
+ * forwarding used buffers even with the unbind.
51
+ */
52
+ memset(&svq->svq_call, 0, sizeof(svq->svq_call));
53
+ } else {
54
+ event_notifier_init_fd(&svq->svq_call, call_fd);
55
+ }
56
+}
218
+
57
+
219
if (notify_remote_frame) {
58
+/**
220
- ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
59
* Set a new file descriptor for the guest to kick the SVQ and notify for avail
221
- (uint8_t *)buf,
60
*
222
- size);
61
* @svq: The svq
223
+ sendco = &s->notify_sendco;
62
@@ -XXX,XX +XXX,XX @@ VhostShadowVirtqueue *vhost_svq_new(void)
224
} else {
225
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
226
+ sendco = &s->out_sendco;
227
}
63
}
228
64
229
- if (ret != size) {
65
event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
230
- goto err;
66
+ event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call);
231
+ if (!size) {
67
return g_steal_pointer(&svq);
232
+ return 0;
68
233
}
69
err_init_hdev_call:
234
70
@@ -XXX,XX +XXX,XX @@ void vhost_svq_free(gpointer pvq)
235
- return 0;
71
VhostShadowVirtqueue *vq = pvq;
236
+ entry = g_slice_new(SendEntry);
72
vhost_svq_stop(vq);
237
+ entry->size = size;
73
event_notifier_cleanup(&vq->hdev_kick);
238
+ entry->vnet_hdr_len = vnet_hdr_len;
74
+ event_notifier_set_handler(&vq->hdev_call, NULL);
239
+ if (zero_copy) {
75
event_notifier_cleanup(&vq->hdev_call);
240
+ entry->buf = buf;
76
g_free(vq);
241
+ } else {
77
}
242
+ entry->buf = g_malloc(size);
78
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
243
+ memcpy(entry->buf, buf, size);
79
index XXXXXXX..XXXXXXX 100644
244
+ }
80
--- a/hw/virtio/vhost-shadow-virtqueue.h
245
+ g_queue_push_head(&sendco->send_list, entry);
81
+++ b/hw/virtio/vhost-shadow-virtqueue.h
82
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
83
* So shadow virtqueue must not clean it, or we would lose VirtQueue one.
84
*/
85
EventNotifier svq_kick;
246
+
86
+
247
+ if (sendco->done) {
87
+ /* Guest's call notifier, where the SVQ calls guest. */
248
+ sendco->co = qemu_coroutine_create(_compare_chr_send, sendco);
88
+ EventNotifier svq_call;
249
+ sendco->done = false;
89
} VhostShadowVirtqueue;
250
+ qemu_coroutine_enter(sendco->co);
90
251
+ if (sendco->done) {
91
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
252
+ /* report early errors */
92
+void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
253
+ return sendco->ret;
93
254
+ }
94
void vhost_svq_stop(VhostShadowVirtqueue *svq);
255
+ }
95
256
96
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
257
-err:
97
index XXXXXXX..XXXXXXX 100644
258
- return ret < 0 ? ret : -EIO;
98
--- a/hw/virtio/vhost-vdpa.c
259
+ /* assume success */
99
+++ b/hw/virtio/vhost-vdpa.c
260
+ return 0;
100
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
101
return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
261
}
102
}
262
103
263
static int compare_chr_can_read(void *opaque)
104
+static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev,
264
@@ -XXX,XX +XXX,XX @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
105
+ struct vhost_vring_file *file)
265
pri_rs->buf,
106
+{
266
pri_rs->packet_len,
107
+ trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd);
267
pri_rs->vnet_hdr_len,
108
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
268
+ false,
109
+}
269
false);
270
} else {
271
/* compare packet in the specified connection */
272
@@ -XXX,XX +XXX,XX @@ static void compare_notify_rs_finalize(SocketReadState *notify_rs)
273
if (packet_matches_str("COLO_USERSPACE_PROXY_INIT",
274
notify_rs->buf,
275
notify_rs->packet_len)) {
276
- ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
277
+ ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
278
if (ret < 0) {
279
error_report("Notify Xen COLO-frame INIT failed");
280
}
281
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
282
283
QTAILQ_INSERT_TAIL(&net_compares, s, next);
284
285
+ s->out_sendco.s = s;
286
+ s->out_sendco.chr = &s->chr_out;
287
+ s->out_sendco.notify_remote_frame = false;
288
+ s->out_sendco.done = true;
289
+ g_queue_init(&s->out_sendco.send_list);
290
+
110
+
291
+ if (s->notify_dev) {
111
/**
292
+ s->notify_sendco.s = s;
112
* Set the shadow virtqueue descriptors to the device
293
+ s->notify_sendco.chr = &s->chr_notify_dev;
113
*
294
+ s->notify_sendco.notify_remote_frame = true;
114
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
295
+ s->notify_sendco.done = true;
115
* @svq: The shadow virtqueue
296
+ g_queue_init(&s->notify_sendco.send_list);
116
* @idx: The index of the virtqueue in the vhost device
117
* @errp: Error
118
+ *
119
+ * Note that this function does not rewind kick file descriptor if cannot set
120
+ * call one.
121
*/
122
static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
123
VhostShadowVirtqueue *svq, unsigned idx,
124
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
125
r = vhost_vdpa_set_vring_dev_kick(dev, &file);
126
if (unlikely(r != 0)) {
127
error_setg_errno(errp, -r, "Can't set device kick fd");
128
+ return false;
297
+ }
129
+ }
298
+
130
+
299
g_queue_init(&s->conn_list);
131
+ event_notifier = &svq->hdev_call;
300
132
+ file.fd = event_notifier_get_fd(event_notifier);
301
qemu_mutex_init(&event_mtx);
133
+ r = vhost_vdpa_set_vring_dev_call(dev, &file);
302
@@ -XXX,XX +XXX,XX @@ static void colo_flush_packets(void *opaque, void *user_data)
134
+ if (unlikely(r != 0)) {
303
pkt->data,
135
+ error_setg_errno(errp, -r, "Can't set device call fd");
304
pkt->size,
305
pkt->vnet_hdr_len,
306
- false);
307
- packet_destroy(pkt, NULL);
308
+ false,
309
+ true);
310
+ packet_destroy_partial(pkt, NULL);
311
}
136
}
312
while (!g_queue_is_empty(&conn->secondary_list)) {
137
313
pkt = g_queue_pop_head(&conn->secondary_list);
138
return r == 0;
314
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
139
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev,
315
}
140
static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
316
}
141
struct vhost_vring_file *file)
317
142
{
318
+ AioContext *ctx = iothread_get_aio_context(s->iothread);
143
- trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd);
319
+ aio_context_acquire(ctx);
144
- return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
320
+ AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
145
+ struct vhost_vdpa *v = dev->opaque;
321
+ if (s->notify_dev) {
146
+
322
+ AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
147
+ if (v->shadow_vqs_enabled) {
148
+ int vdpa_idx = file->index - dev->vq_index;
149
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx);
150
+
151
+ vhost_svq_set_svq_call_fd(svq, file->fd);
152
+ return 0;
153
+ } else {
154
+ return vhost_vdpa_set_vring_dev_call(dev, file);
323
+ }
155
+ }
324
+ aio_context_release(ctx);
325
+
326
/* Release all unhandled packets after compare thead exited */
327
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
328
+ AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
329
330
g_queue_clear(&s->conn_list);
331
+ g_queue_clear(&s->out_sendco.send_list);
332
+ if (s->notify_dev) {
333
+ g_queue_clear(&s->notify_sendco.send_list);
334
+ }
335
336
if (s->connection_track_table) {
337
g_hash_table_destroy(s->connection_track_table);
338
diff --git a/net/colo.c b/net/colo.c
339
index XXXXXXX..XXXXXXX 100644
340
--- a/net/colo.c
341
+++ b/net/colo.c
342
@@ -XXX,XX +XXX,XX @@ void packet_destroy(void *opaque, void *user_data)
343
g_slice_free(Packet, pkt);
344
}
156
}
345
157
346
+void packet_destroy_partial(void *opaque, void *user_data)
158
static int vhost_vdpa_get_features(struct vhost_dev *dev,
347
+{
348
+ Packet *pkt = opaque;
349
+
350
+ g_slice_free(Packet, pkt);
351
+}
352
+
353
/*
354
* Clear hashtable, stop this hash growing really huge
355
*/
356
diff --git a/net/colo.h b/net/colo.h
357
index XXXXXXX..XXXXXXX 100644
358
--- a/net/colo.h
359
+++ b/net/colo.h
360
@@ -XXX,XX +XXX,XX @@ bool connection_has_tracked(GHashTable *connection_track_table,
361
void connection_hashtable_reset(GHashTable *connection_track_table);
362
Packet *packet_new(const void *data, int size, int vnet_hdr_len);
363
void packet_destroy(void *opaque, void *user_data);
364
+void packet_destroy_partial(void *opaque, void *user_data);
365
366
#endif /* NET_COLO_H */
367
--
159
--
368
2.5.0
160
2.7.4
369
161
370
162
diff view generated by jsdifflib
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Add a property "jumbo-max-len", which sets default value of jumbo frames
3
This allows SVQ to negotiate features with the guest and the device. For
4
up to 16,383 bytes. Add Frame length checks for standard and jumbo
4
the device, SVQ is a driver. While this function bypasses all
5
frames.
5
non-transport features, it needs to disable the features that SVQ does
6
not support when forwarding buffers. This includes packed vq layout,
7
indirect descriptors or event idx.
6
8
7
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
9
Future changes can add support to offer more features to the guest,
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
since the use of VirtQueue gives this for free. This is left out at the
11
moment for simplicity.
12
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
14
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
16
---
11
hw/net/cadence_gem.c | 51 +++++++++++++++++++++++++++++++++++++++-----
17
hw/virtio/vhost-shadow-virtqueue.c | 44 ++++++++++++++++++++++++++++++++++++++
12
include/hw/net/cadence_gem.h | 4 +++-
18
hw/virtio/vhost-shadow-virtqueue.h | 2 ++
13
2 files changed, 49 insertions(+), 6 deletions(-)
19
hw/virtio/vhost-vdpa.c | 15 +++++++++++++
20
3 files changed, 61 insertions(+)
14
21
15
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
22
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/cadence_gem.c
24
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/hw/net/cadence_gem.c
25
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@
20
#define GEM_TXPAUSE (0x0000003C / 4) /* TX Pause Time reg */
27
#include "hw/virtio/vhost-shadow-virtqueue.h"
21
#define GEM_TXPARTIALSF (0x00000040 / 4) /* TX Partial Store and Forward */
28
22
#define GEM_RXPARTIALSF (0x00000044 / 4) /* RX Partial Store and Forward */
29
#include "qemu/error-report.h"
23
+#define GEM_JUMBO_MAX_LEN (0x00000048 / 4) /* Max Jumbo Frame Size */
30
+#include "qapi/error.h"
24
#define GEM_HASHLO (0x00000080 / 4) /* Hash Low address reg */
31
#include "qemu/main-loop.h"
25
#define GEM_HASHHI (0x00000084 / 4) /* Hash High address reg */
32
#include "linux-headers/linux/vhost.h"
26
#define GEM_SPADDR1LO (0x00000088 / 4) /* Specific addr 1 low reg */
33
27
@@ -XXX,XX +XXX,XX @@
34
/**
28
#define GEM_NWCFG_LERR_DISC 0x00010000 /* Discard RX frames with len err */
35
+ * Validate the transport device features that both guests can use with the SVQ
29
#define GEM_NWCFG_BUFF_OFST_M 0x0000C000 /* Receive buffer offset mask */
36
+ * and SVQs can use with the device.
30
#define GEM_NWCFG_BUFF_OFST_S 14 /* Receive buffer offset shift */
37
+ *
31
+#define GEM_NWCFG_RCV_1538 0x00000100 /* Receive 1538 bytes frame */
38
+ * @dev_features: The features
32
#define GEM_NWCFG_UCAST_HASH 0x00000080 /* accept unicast if hash match */
39
+ * @errp: Error pointer
33
#define GEM_NWCFG_MCAST_HASH 0x00000040 /* accept multicast if hash match */
40
+ */
34
#define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */
41
+bool vhost_svq_valid_features(uint64_t features, Error **errp)
35
#define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */
36
+#define GEM_NWCFG_JUMBO_FRAME 0x00000008 /* Jumbo Frames enable */
37
38
#define GEM_DMACFG_ADDR_64B (1U << 30)
39
#define GEM_DMACFG_TX_BD_EXT (1U << 29)
40
@@ -XXX,XX +XXX,XX @@
41
42
/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
43
#define GEM_INT_TXCMPL 0x00000080 /* Transmit Complete */
44
+#define GEM_INT_AMBA_ERR 0x00000040
45
#define GEM_INT_TXUSED 0x00000008
46
#define GEM_INT_RXUSED 0x00000004
47
#define GEM_INT_RXCMPL 0x00000002
48
@@ -XXX,XX +XXX,XX @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx)
49
/* The broadcast MAC address: 0xFFFFFFFFFFFF */
50
static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
51
52
+static uint32_t gem_get_max_buf_len(CadenceGEMState *s, bool tx)
53
+{
42
+{
54
+ uint32_t size;
43
+ bool ok = true;
55
+ if (s->regs[GEM_NWCFG] & GEM_NWCFG_JUMBO_FRAME) {
44
+ uint64_t svq_features = features;
56
+ size = s->regs[GEM_JUMBO_MAX_LEN];
45
+
57
+ if (size > s->jumbo_max_len) {
46
+ for (uint64_t b = VIRTIO_TRANSPORT_F_START; b <= VIRTIO_TRANSPORT_F_END;
58
+ size = s->jumbo_max_len;
47
+ ++b) {
59
+ qemu_log_mask(LOG_GUEST_ERROR, "GEM_JUMBO_MAX_LEN reg cannot be"
48
+ switch (b) {
60
+ " greater than 0x%" PRIx32 "\n", s->jumbo_max_len);
49
+ case VIRTIO_F_ANY_LAYOUT:
50
+ continue;
51
+
52
+ case VIRTIO_F_ACCESS_PLATFORM:
53
+ /* SVQ trust in the host's IOMMU to translate addresses */
54
+ case VIRTIO_F_VERSION_1:
55
+ /* SVQ trust that the guest vring is little endian */
56
+ if (!(svq_features & BIT_ULL(b))) {
57
+ svq_features |= BIT_ULL(b);
58
+ ok = false;
59
+ }
60
+ continue;
61
+
62
+ default:
63
+ if (svq_features & BIT_ULL(b)) {
64
+ svq_features &= ~BIT_ULL(b);
65
+ ok = false;
66
+ }
61
+ }
67
+ }
62
+ } else if (tx) {
63
+ size = 1518;
64
+ } else {
65
+ size = s->regs[GEM_NWCFG] & GEM_NWCFG_RCV_1538 ? 1538 : 1518;
66
+ }
68
+ }
67
+ return size;
69
+
70
+ if (!ok) {
71
+ error_setg(errp, "SVQ Invalid device feature flags, offer: 0x%"PRIx64
72
+ ", ok: 0x%"PRIx64, features, svq_features);
73
+ }
74
+ return ok;
68
+}
75
+}
69
+
76
+
70
static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag)
77
+/**
78
* Forward guest notifications.
79
*
80
* @n: guest kick event notifier, the one that guest set to notify svq.
81
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
82
index XXXXXXX..XXXXXXX 100644
83
--- a/hw/virtio/vhost-shadow-virtqueue.h
84
+++ b/hw/virtio/vhost-shadow-virtqueue.h
85
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
86
EventNotifier svq_call;
87
} VhostShadowVirtqueue;
88
89
+bool vhost_svq_valid_features(uint64_t features, Error **errp);
90
+
91
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
92
void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
93
94
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/hw/virtio/vhost-vdpa.c
97
+++ b/hw/virtio/vhost-vdpa.c
98
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
99
Error **errp)
71
{
100
{
72
if (q == 0) {
101
g_autoptr(GPtrArray) shadow_vqs = NULL;
73
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
102
+ uint64_t dev_features, svq_features;
74
/* Find which queue we are targeting */
103
+ int r;
75
q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
104
+ bool ok;
76
105
77
+ if (size > gem_get_max_buf_len(s, false)) {
106
if (!v->shadow_vqs_enabled) {
78
+ qemu_log_mask(LOG_GUEST_ERROR, "rx frame too long\n");
107
return 0;
79
+ gem_set_isr(s, q, GEM_INT_AMBA_ERR);
108
}
109
110
+ r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features);
111
+ if (r != 0) {
112
+ error_setg_errno(errp, -r, "Can't get vdpa device features");
113
+ return r;
114
+ }
115
+
116
+ svq_features = dev_features;
117
+ ok = vhost_svq_valid_features(svq_features, errp);
118
+ if (unlikely(!ok)) {
80
+ return -1;
119
+ return -1;
81
+ }
120
+ }
82
+
121
+
83
while (bytes_to_copy) {
122
shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
84
hwaddr desc_addr;
123
for (unsigned n = 0; n < hdev->nvqs; ++n) {
85
124
g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();
86
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
87
break;
88
}
89
90
- if (tx_desc_get_length(desc) > MAX_FRAME_SIZE -
91
+ if (tx_desc_get_length(desc) > gem_get_max_buf_len(s, true) -
92
(p - s->tx_packet)) {
93
- DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \
94
- " too large: size 0x%x space 0x%zx\n",
95
+ qemu_log_mask(LOG_GUEST_ERROR, "TX descriptor @ 0x%" \
96
+ HWADDR_PRIx " too large: size 0x%x space 0x%zx\n",
97
packet_desc_addr, tx_desc_get_length(desc),
98
- MAX_FRAME_SIZE - (p - s->tx_packet));
99
+ gem_get_max_buf_len(s, true) - (p - s->tx_packet));
100
+ gem_set_isr(s, q, GEM_INT_AMBA_ERR);
101
break;
102
}
103
104
@@ -XXX,XX +XXX,XX @@ static void gem_reset(DeviceState *d)
105
s->regs[GEM_RXPARTIALSF] = 0x000003ff;
106
s->regs[GEM_MODID] = s->revision;
107
s->regs[GEM_DESCONF] = 0x02500111;
108
- s->regs[GEM_DESCONF2] = 0x2ab13fff;
109
+ s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
110
s->regs[GEM_DESCONF5] = 0x002f2045;
111
s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
112
+ s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len;
113
114
if (s->num_priority_queues > 1) {
115
queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1);
116
@@ -XXX,XX +XXX,XX @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
117
s->regs[GEM_IMR] &= ~val;
118
gem_update_int_status(s);
119
break;
120
+ case GEM_JUMBO_MAX_LEN:
121
+ s->regs[GEM_JUMBO_MAX_LEN] = val & MAX_JUMBO_FRAME_SIZE_MASK;
122
+ break;
123
case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE:
124
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
125
gem_update_int_status(s);
126
@@ -XXX,XX +XXX,XX @@ static void gem_realize(DeviceState *dev, Error **errp)
127
128
s->nic = qemu_new_nic(&net_gem_info, &s->conf,
129
object_get_typename(OBJECT(dev)), dev->id, s);
130
+
131
+ if (s->jumbo_max_len > MAX_FRAME_SIZE) {
132
+ error_setg(errp, "jumbo-max-len is greater than %d",
133
+ MAX_FRAME_SIZE);
134
+ return;
135
+ }
136
}
137
138
static void gem_init(Object *obj)
139
@@ -XXX,XX +XXX,XX @@ static Property gem_properties[] = {
140
num_type1_screeners, 4),
141
DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState,
142
num_type2_screeners, 4),
143
+ DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState,
144
+ jumbo_max_len, 10240),
145
DEFINE_PROP_END_OF_LIST(),
146
};
147
148
diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h
149
index XXXXXXX..XXXXXXX 100644
150
--- a/include/hw/net/cadence_gem.h
151
+++ b/include/hw/net/cadence_gem.h
152
@@ -XXX,XX +XXX,XX @@
153
#define MAX_TYPE1_SCREENERS 16
154
#define MAX_TYPE2_SCREENERS 16
155
156
-#define MAX_FRAME_SIZE 2048
157
+#define MAX_JUMBO_FRAME_SIZE_MASK 0x3FFF
158
+#define MAX_FRAME_SIZE MAX_JUMBO_FRAME_SIZE_MASK
159
160
typedef struct CadenceGEMState {
161
/*< private >*/
162
@@ -XXX,XX +XXX,XX @@ typedef struct CadenceGEMState {
163
uint8_t num_type1_screeners;
164
uint8_t num_type2_screeners;
165
uint32_t revision;
166
+ uint16_t jumbo_max_len;
167
168
/* GEM registers backing store */
169
uint32_t regs[CADENCE_GEM_MAXREG];
170
--
125
--
171
2.5.0
126
2.7.4
172
127
173
128
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Similar to VMSTATE_VARRAY_UINT32_ALLOC, but the size is
3
It reports the shadow virtqueue address from qemu virtual address space.
4
16-bit field.
5
4
6
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
5
Since this will be different from the guest's vaddr, but the device can
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
access it, SVQ takes special care about its alignment & lack of garbage
7
data. It assumes that IOMMU will work in host_page_size ranges for that.
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
12
---
10
include/migration/vmstate.h | 10 ++++++++++
13
hw/virtio/vhost-shadow-virtqueue.c | 29 +++++++++++++++++++++++++++++
11
1 file changed, 10 insertions(+)
14
hw/virtio/vhost-shadow-virtqueue.h | 9 +++++++++
15
2 files changed, 38 insertions(+)
12
16
13
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
17
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/include/migration/vmstate.h
19
--- a/hw/virtio/vhost-shadow-virtqueue.c
16
+++ b/include/migration/vmstate.h
20
+++ b/hw/virtio/vhost-shadow-virtqueue.c
17
@@ -XXX,XX +XXX,XX @@ extern const VMStateInfo vmstate_info_qlist;
21
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd)
18
.offset = vmstate_offset_pointer(_state, _field, _type), \
19
}
22
}
20
23
21
+#define VMSTATE_VARRAY_UINT16_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
24
/**
22
+ .name = (stringify(_field)), \
25
+ * Get the shadow vq vring address.
23
+ .version_id = (_version), \
26
+ * @svq: Shadow virtqueue
24
+ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
27
+ * @addr: Destination to store address
25
+ .info = &(_info), \
28
+ */
26
+ .size = sizeof(_type), \
29
+void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
27
+ .flags = VMS_VARRAY_UINT16 | VMS_POINTER | VMS_ALLOC, \
30
+ struct vhost_vring_addr *addr)
28
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
31
+{
32
+ addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc;
33
+ addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail;
34
+ addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used;
29
+}
35
+}
30
+
36
+
31
#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
37
+size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq)
32
.name = (stringify(_field)), \
38
+{
33
.version_id = (_version), \
39
+ size_t desc_size = sizeof(vring_desc_t) * svq->vring.num;
40
+ size_t avail_size = offsetof(vring_avail_t, ring) +
41
+ sizeof(uint16_t) * svq->vring.num;
42
+
43
+ return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size);
44
+}
45
+
46
+size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq)
47
+{
48
+ size_t used_size = offsetof(vring_used_t, ring) +
49
+ sizeof(vring_used_elem_t) * svq->vring.num;
50
+ return ROUND_UP(used_size, qemu_real_host_page_size);
51
+}
52
+
53
+/**
54
* Set a new file descriptor for the guest to kick the SVQ and notify for avail
55
*
56
* @svq: The svq
57
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
58
index XXXXXXX..XXXXXXX 100644
59
--- a/hw/virtio/vhost-shadow-virtqueue.h
60
+++ b/hw/virtio/vhost-shadow-virtqueue.h
61
@@ -XXX,XX +XXX,XX @@
62
#define VHOST_SHADOW_VIRTQUEUE_H
63
64
#include "qemu/event_notifier.h"
65
+#include "hw/virtio/virtio.h"
66
+#include "standard-headers/linux/vhost_types.h"
67
68
/* Shadow virtqueue to relay notifications */
69
typedef struct VhostShadowVirtqueue {
70
+ /* Shadow vring */
71
+ struct vring vring;
72
+
73
/* Shadow kick notifier, sent to vhost */
74
EventNotifier hdev_kick;
75
/* Shadow call notifier, sent to vhost */
76
@@ -XXX,XX +XXX,XX @@ bool vhost_svq_valid_features(uint64_t features, Error **errp);
77
78
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
79
void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
80
+void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
81
+ struct vhost_vring_addr *addr);
82
+size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq);
83
+size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq);
84
85
void vhost_svq_stop(VhostShadowVirtqueue *svq);
86
34
--
87
--
35
2.5.0
88
2.7.4
36
89
37
90
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
If VIRTIO_NET_F_RSS negotiated and RSS is enabled, process
3
First half of the buffers forwarding part, preparing vhost-vdpa
4
incoming packets, calculate packet's hash and place the
4
callbacks to SVQ to offer it. QEMU cannot enable it at this moment, so
5
packet into respective RX virtqueue.
5
this is effectively dead code at the moment, but it helps to reduce
6
patch size.
6
7
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
11
---
10
hw/net/virtio-net.c | 88 +++++++++++++++++++++++++++++++++++++++++-
12
hw/virtio/vhost-vdpa.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
11
include/hw/virtio/virtio-net.h | 1 +
13
1 file changed, 41 insertions(+), 7 deletions(-)
12
2 files changed, 87 insertions(+), 2 deletions(-)
13
14
14
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
15
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/virtio-net.c
17
--- a/hw/virtio/vhost-vdpa.c
17
+++ b/hw/net/virtio-net.c
18
+++ b/hw/virtio/vhost-vdpa.c
18
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config,
19
#include "trace.h"
20
return ret;
20
#include "monitor/qdev.h"
21
}
21
#include "hw/pci/pci.h"
22
22
+#include "net_rx_pkt.h"
23
+static int vhost_vdpa_set_dev_vring_base(struct vhost_dev *dev,
23
24
+ struct vhost_vring_state *ring)
24
#define VIRTIO_NET_VM_VERSION 11
25
26
@@ -XXX,XX +XXX,XX @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
27
return 0;
28
}
29
30
+static uint8_t virtio_net_get_hash_type(bool isip4,
31
+ bool isip6,
32
+ bool isudp,
33
+ bool istcp,
34
+ uint32_t types)
35
+{
25
+{
36
+ if (isip4) {
26
+ trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num);
37
+ if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) {
27
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring);
38
+ return NetPktRssIpV4Tcp;
39
+ }
40
+ if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) {
41
+ return NetPktRssIpV4Udp;
42
+ }
43
+ if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
44
+ return NetPktRssIpV4;
45
+ }
46
+ } else if (isip6) {
47
+ uint32_t mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
48
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
49
+
50
+ if (istcp && (types & mask)) {
51
+ return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ?
52
+ NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp;
53
+ }
54
+ mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
55
+ if (isudp && (types & mask)) {
56
+ return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ?
57
+ NetPktRssIpV6UdpEx : NetPktRssIpV6Udp;
58
+ }
59
+ mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6;
60
+ if (types & mask) {
61
+ return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ?
62
+ NetPktRssIpV6Ex : NetPktRssIpV6;
63
+ }
64
+ }
65
+ return 0xff;
66
+}
28
+}
67
+
29
+
68
+static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
30
static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
69
+ size_t size)
31
struct vhost_vring_file *file)
32
{
33
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev,
34
return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
35
}
36
37
+static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev,
38
+ struct vhost_vring_addr *addr)
70
+{
39
+{
71
+ VirtIONet *n = qemu_get_nic_opaque(nc);
40
+ trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags,
72
+ unsigned int index = nc->queue_index, new_index;
41
+ addr->desc_user_addr, addr->used_user_addr,
73
+ struct NetRxPkt *pkt = n->rx_pkt;
42
+ addr->avail_user_addr,
74
+ uint8_t net_hash_type;
43
+ addr->log_guest_addr);
75
+ uint32_t hash;
76
+ bool isip4, isip6, isudp, istcp;
77
+
44
+
78
+ net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
45
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr);
79
+ size - n->host_hdr_len);
46
+
80
+ net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
47
+}
81
+ if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) {
48
+
82
+ istcp = isudp = false;
49
/**
83
+ }
50
* Set the shadow virtqueue descriptors to the device
84
+ if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) {
51
*
85
+ istcp = isudp = false;
52
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
86
+ }
53
static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev,
87
+ net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp,
54
struct vhost_vring_addr *addr)
88
+ n->rss_data.hash_types);
55
{
89
+ if (net_hash_type > NetPktRssIpV6UdpEx) {
56
- trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags,
90
+ return n->rss_data.default_queue;
57
- addr->desc_user_addr, addr->used_user_addr,
58
- addr->avail_user_addr,
59
- addr->log_guest_addr);
60
- return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr);
61
+ struct vhost_vdpa *v = dev->opaque;
62
+
63
+ if (v->shadow_vqs_enabled) {
64
+ /*
65
+ * Device vring addr was set at device start. SVQ base is handled by
66
+ * VirtQueue code.
67
+ */
68
+ return 0;
91
+ }
69
+ }
92
+
70
+
93
+ hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key);
71
+ return vhost_vdpa_set_vring_dev_addr(dev, addr);
94
+ new_index = hash & (n->rss_data.indirections_len - 1);
72
}
95
+ new_index = n->rss_data.indirections_table[new_index];
73
96
+ if (index == new_index) {
74
static int vhost_vdpa_set_vring_num(struct vhost_dev *dev,
97
+ return -1;
75
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_num(struct vhost_dev *dev,
98
+ }
76
static int vhost_vdpa_set_vring_base(struct vhost_dev *dev,
99
+ return new_index;
77
struct vhost_vring_state *ring)
100
+}
78
{
79
- trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num);
80
- return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring);
81
+ struct vhost_vdpa *v = dev->opaque;
101
+
82
+
102
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
83
+ if (v->shadow_vqs_enabled) {
103
- size_t size)
84
+ /*
104
+ size_t size, bool no_rss)
85
+ * Device vring base was set at device start. SVQ base is handled by
105
{
86
+ * VirtQueue code.
106
VirtIONet *n = qemu_get_nic_opaque(nc);
87
+ */
107
VirtIONetQueue *q = virtio_net_get_subqueue(nc);
88
+ return 0;
108
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
109
return -1;
110
}
111
112
+ if (!no_rss && n->rss_data.enabled) {
113
+ int index = virtio_net_process_rss(nc, buf, size);
114
+ if (index >= 0) {
115
+ NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
116
+ return virtio_net_receive_rcu(nc2, buf, size, true);
117
+ }
118
+ }
89
+ }
119
+
90
+
120
/* hdr_len refers to the header we supply to the guest */
91
+ return vhost_vdpa_set_dev_vring_base(dev, ring);
121
if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
122
return 0;
123
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,
124
{
125
RCU_READ_LOCK_GUARD();
126
127
- return virtio_net_receive_rcu(nc, buf, size);
128
+ return virtio_net_receive_rcu(nc, buf, size, false);
129
}
92
}
130
93
131
static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
94
static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
132
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
133
134
QTAILQ_INIT(&n->rsc_chains);
135
n->qdev = dev;
136
+
137
+ net_rx_pkt_init(&n->rx_pkt, false);
138
}
139
140
static void virtio_net_device_unrealize(DeviceState *dev)
141
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
142
qemu_del_nic(n->nic);
143
virtio_net_rsc_cleanup(n);
144
g_free(n->rss_data.indirections_table);
145
+ net_rx_pkt_uninit(n->rx_pkt);
146
virtio_cleanup(vdev);
147
}
148
149
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
150
index XXXXXXX..XXXXXXX 100644
151
--- a/include/hw/virtio/virtio-net.h
152
+++ b/include/hw/virtio/virtio-net.h
153
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
154
DeviceListener primary_listener;
155
Notifier migration_state;
156
VirtioNetRssData rss_data;
157
+ struct NetRxPkt *rx_pkt;
158
};
159
160
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
161
--
95
--
162
2.5.0
96
2.7.4
163
97
164
98
diff view generated by jsdifflib
1
From: Lukas Straub <lukasstraub2@web.de>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
If the colo-compare object is removed before failover and a
3
Initial version of shadow virtqueue that actually forward buffers. There
4
checkpoint happens, qemu crashes because it tries to lock
4
is no iommu support at the moment, and that will be addressed in future
5
the destroyed event_mtx in colo_notify_compares_event.
5
patches of this series. Since all vhost-vdpa devices use forced IOMMU,
6
6
this means that SVQ is not usable at this point of the series on any
7
Fix this by checking if everything is initialized by
7
device.
8
introducing a new variable colo_compare_active which
8
9
is protected by a new mutex colo_compare_mutex. The new mutex
9
For simplicity it only supports modern devices, that expects vring
10
also protects against concurrent access of the net_compares
10
in little endian, with split ring and no event idx or indirect
11
list and makes sure that colo_notify_compares_event isn't
11
descriptors. Support for them will not be added in this series.
12
active while we destroy event_mtx and event_complete_cond.
12
13
13
It reuses the VirtQueue code for the device part. The driver part is
14
With this it also is again possible to use colo without
14
based on Linux's virtio_ring driver, but with stripped functionality
15
colo-compare (periodic mode) and to use multiple colo-compare
15
and optimizations so it's easier to review.
16
for multiple network interfaces.
16
17
17
However, forwarding buffers have some particular pieces: One of the most
18
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
18
unexpected ones is that a guest's buffer can expand through more than
19
Tested-by: Lukas Straub <lukasstraub2@web.de>
19
one descriptor in SVQ. While this is handled gracefully by qemu's
20
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
20
emulated virtio devices, it may cause unexpected SVQ queue full. This
21
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
21
patch also solves it by checking for this condition at both guest's
22
kicks and device's calls. The code may be more elegant in the future if
23
SVQ code runs in its own iocontext.
24
25
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
26
Acked-by: Michael S. Tsirkin <mst@redhat.com>
22
Signed-off-by: Jason Wang <jasowang@redhat.com>
27
Signed-off-by: Jason Wang <jasowang@redhat.com>
23
---
28
---
24
net/colo-compare.c | 35 +++++++++++++++++++++++++++++------
29
hw/virtio/vhost-shadow-virtqueue.c | 352 ++++++++++++++++++++++++++++++++++++-
25
1 file changed, 29 insertions(+), 6 deletions(-)
30
hw/virtio/vhost-shadow-virtqueue.h | 26 +++
26
31
hw/virtio/vhost-vdpa.c | 155 +++++++++++++++-
27
diff --git a/net/colo-compare.c b/net/colo-compare.c
32
3 files changed, 522 insertions(+), 11 deletions(-)
33
34
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
28
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
29
--- a/net/colo-compare.c
36
--- a/hw/virtio/vhost-shadow-virtqueue.c
30
+++ b/net/colo-compare.c
37
+++ b/hw/virtio/vhost-shadow-virtqueue.c
31
@@ -XXX,XX +XXX,XX @@ static NotifierList colo_compare_notifiers =
38
@@ -XXX,XX +XXX,XX @@
32
#define REGULAR_PACKET_CHECK_MS 3000
39
#include "qemu/error-report.h"
33
#define DEFAULT_TIME_OUT_MS 3000
40
#include "qapi/error.h"
34
41
#include "qemu/main-loop.h"
35
+static QemuMutex colo_compare_mutex;
42
+#include "qemu/log.h"
36
+static bool colo_compare_active;
43
+#include "qemu/memalign.h"
37
static QemuMutex event_mtx;
44
#include "linux-headers/linux/vhost.h"
38
static QemuCond event_complete_cond;
45
39
static int event_unhandled_count;
46
/**
40
@@ -XXX,XX +XXX,XX @@ static void check_old_packet_regular(void *opaque)
47
@@ -XXX,XX +XXX,XX @@ bool vhost_svq_valid_features(uint64_t features, Error **errp)
41
void colo_notify_compares_event(void *opaque, int event, Error **errp)
48
}
49
50
/**
51
- * Forward guest notifications.
52
+ * Number of descriptors that the SVQ can make available from the guest.
53
+ *
54
+ * @svq: The svq
55
+ */
56
+static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
57
+{
58
+ return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx);
59
+}
60
+
61
+static void vhost_vring_write_descs(VhostShadowVirtqueue *svq,
62
+ const struct iovec *iovec, size_t num,
63
+ bool more_descs, bool write)
64
+{
65
+ uint16_t i = svq->free_head, last = svq->free_head;
66
+ unsigned n;
67
+ uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0;
68
+ vring_desc_t *descs = svq->vring.desc;
69
+
70
+ if (num == 0) {
71
+ return;
72
+ }
73
+
74
+ for (n = 0; n < num; n++) {
75
+ if (more_descs || (n + 1 < num)) {
76
+ descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT);
77
+ } else {
78
+ descs[i].flags = flags;
79
+ }
80
+ descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base);
81
+ descs[i].len = cpu_to_le32(iovec[n].iov_len);
82
+
83
+ last = i;
84
+ i = cpu_to_le16(descs[i].next);
85
+ }
86
+
87
+ svq->free_head = le16_to_cpu(descs[last].next);
88
+}
89
+
90
+static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
91
+ VirtQueueElement *elem, unsigned *head)
92
+{
93
+ unsigned avail_idx;
94
+ vring_avail_t *avail = svq->vring.avail;
95
+
96
+ *head = svq->free_head;
97
+
98
+ /* We need some descriptors here */
99
+ if (unlikely(!elem->out_num && !elem->in_num)) {
100
+ qemu_log_mask(LOG_GUEST_ERROR,
101
+ "Guest provided element with no descriptors");
102
+ return false;
103
+ }
104
+
105
+ vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0,
106
+ false);
107
+ vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true);
108
+
109
+ /*
110
+ * Put the entry in the available array (but don't update avail->idx until
111
+ * they do sync).
112
+ */
113
+ avail_idx = svq->shadow_avail_idx & (svq->vring.num - 1);
114
+ avail->ring[avail_idx] = cpu_to_le16(*head);
115
+ svq->shadow_avail_idx++;
116
+
117
+ /* Update the avail index after write the descriptor */
118
+ smp_wmb();
119
+ avail->idx = cpu_to_le16(svq->shadow_avail_idx);
120
+
121
+ return true;
122
+}
123
+
124
+static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem)
125
+{
126
+ unsigned qemu_head;
127
+ bool ok = vhost_svq_add_split(svq, elem, &qemu_head);
128
+ if (unlikely(!ok)) {
129
+ return false;
130
+ }
131
+
132
+ svq->ring_id_maps[qemu_head] = elem;
133
+ return true;
134
+}
135
+
136
+static void vhost_svq_kick(VhostShadowVirtqueue *svq)
137
+{
138
+ /*
139
+ * We need to expose the available array entries before checking the used
140
+ * flags
141
+ */
142
+ smp_mb();
143
+ if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) {
144
+ return;
145
+ }
146
+
147
+ event_notifier_set(&svq->hdev_kick);
148
+}
149
+
150
+/**
151
+ * Forward available buffers.
152
+ *
153
+ * @svq: Shadow VirtQueue
154
+ *
155
+ * Note that this function does not guarantee that all guest's available
156
+ * buffers are available to the device in SVQ avail ring. The guest may have
157
+ * exposed a GPA / GIOVA contiguous buffer, but it may not be contiguous in
158
+ * qemu vaddr.
159
+ *
160
+ * If that happens, guest's kick notifications will be disabled until the
161
+ * device uses some buffers.
162
+ */
163
+static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq)
164
+{
165
+ /* Clear event notifier */
166
+ event_notifier_test_and_clear(&svq->svq_kick);
167
+
168
+ /* Forward to the device as many available buffers as possible */
169
+ do {
170
+ virtio_queue_set_notification(svq->vq, false);
171
+
172
+ while (true) {
173
+ VirtQueueElement *elem;
174
+ bool ok;
175
+
176
+ if (svq->next_guest_avail_elem) {
177
+ elem = g_steal_pointer(&svq->next_guest_avail_elem);
178
+ } else {
179
+ elem = virtqueue_pop(svq->vq, sizeof(*elem));
180
+ }
181
+
182
+ if (!elem) {
183
+ break;
184
+ }
185
+
186
+ if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) {
187
+ /*
188
+ * This condition is possible since a contiguous buffer in GPA
189
+ * does not imply a contiguous buffer in qemu's VA
190
+ * scatter-gather segments. If that happens, the buffer exposed
191
+ * to the device needs to be a chain of descriptors at this
192
+ * moment.
193
+ *
194
+ * SVQ cannot hold more available buffers if we are here:
195
+ * queue the current guest descriptor and ignore further kicks
196
+ * until some elements are used.
197
+ */
198
+ svq->next_guest_avail_elem = elem;
199
+ return;
200
+ }
201
+
202
+ ok = vhost_svq_add(svq, elem);
203
+ if (unlikely(!ok)) {
204
+ /* VQ is broken, just return and ignore any other kicks */
205
+ return;
206
+ }
207
+ vhost_svq_kick(svq);
208
+ }
209
+
210
+ virtio_queue_set_notification(svq->vq, true);
211
+ } while (!virtio_queue_empty(svq->vq));
212
+}
213
+
214
+/**
215
+ * Handle guest's kick.
216
*
217
* @n: guest kick event notifier, the one that guest set to notify svq.
218
*/
219
-static void vhost_handle_guest_kick(EventNotifier *n)
220
+static void vhost_handle_guest_kick_notifier(EventNotifier *n)
42
{
221
{
43
CompareState *s;
222
VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick);
44
+ qemu_mutex_lock(&colo_compare_mutex);
223
event_notifier_test_and_clear(n);
45
+
224
- event_notifier_set(&svq->hdev_kick);
46
+ if (!colo_compare_active) {
225
+ vhost_handle_guest_kick(svq);
47
+ qemu_mutex_unlock(&colo_compare_mutex);
226
+}
227
+
228
+static bool vhost_svq_more_used(VhostShadowVirtqueue *svq)
229
+{
230
+ if (svq->last_used_idx != svq->shadow_used_idx) {
231
+ return true;
232
+ }
233
+
234
+ svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx);
235
+
236
+ return svq->last_used_idx != svq->shadow_used_idx;
237
}
238
239
/**
240
- * Forward vhost notifications
241
+ * Enable vhost device calls after disable them.
242
+ *
243
+ * @svq: The svq
244
+ *
245
+ * It returns false if there are pending used buffers from the vhost device,
246
+ * avoiding the possible races between SVQ checking for more work and enabling
247
+ * callbacks. True if SVQ used vring has no more pending buffers.
248
+ */
249
+static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq)
250
+{
251
+ svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
252
+ /* Make sure the flag is written before the read of used_idx */
253
+ smp_mb();
254
+ return !vhost_svq_more_used(svq);
255
+}
256
+
257
+static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq)
258
+{
259
+ svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
260
+}
261
+
262
+static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
263
+ uint32_t *len)
264
+{
265
+ vring_desc_t *descs = svq->vring.desc;
266
+ const vring_used_t *used = svq->vring.used;
267
+ vring_used_elem_t used_elem;
268
+ uint16_t last_used;
269
+
270
+ if (!vhost_svq_more_used(svq)) {
271
+ return NULL;
272
+ }
273
+
274
+ /* Only get used array entries after they have been exposed by dev */
275
+ smp_rmb();
276
+ last_used = svq->last_used_idx & (svq->vring.num - 1);
277
+ used_elem.id = le32_to_cpu(used->ring[last_used].id);
278
+ used_elem.len = le32_to_cpu(used->ring[last_used].len);
279
+
280
+ svq->last_used_idx++;
281
+ if (unlikely(used_elem.id >= svq->vring.num)) {
282
+ qemu_log_mask(LOG_GUEST_ERROR, "Device %s says index %u is used",
283
+ svq->vdev->name, used_elem.id);
284
+ return NULL;
285
+ }
286
+
287
+ if (unlikely(!svq->ring_id_maps[used_elem.id])) {
288
+ qemu_log_mask(LOG_GUEST_ERROR,
289
+ "Device %s says index %u is used, but it was not available",
290
+ svq->vdev->name, used_elem.id);
291
+ return NULL;
292
+ }
293
+
294
+ descs[used_elem.id].next = svq->free_head;
295
+ svq->free_head = used_elem.id;
296
+
297
+ *len = used_elem.len;
298
+ return g_steal_pointer(&svq->ring_id_maps[used_elem.id]);
299
+}
300
+
301
+static void vhost_svq_flush(VhostShadowVirtqueue *svq,
302
+ bool check_for_avail_queue)
303
+{
304
+ VirtQueue *vq = svq->vq;
305
+
306
+ /* Forward as many used buffers as possible. */
307
+ do {
308
+ unsigned i = 0;
309
+
310
+ vhost_svq_disable_notification(svq);
311
+ while (true) {
312
+ uint32_t len;
313
+ g_autofree VirtQueueElement *elem = vhost_svq_get_buf(svq, &len);
314
+ if (!elem) {
315
+ break;
316
+ }
317
+
318
+ if (unlikely(i >= svq->vring.num)) {
319
+ qemu_log_mask(LOG_GUEST_ERROR,
320
+ "More than %u used buffers obtained in a %u size SVQ",
321
+ i, svq->vring.num);
322
+ virtqueue_fill(vq, elem, len, i);
323
+ virtqueue_flush(vq, i);
324
+ return;
325
+ }
326
+ virtqueue_fill(vq, elem, len, i++);
327
+ }
328
+
329
+ virtqueue_flush(vq, i);
330
+ event_notifier_set(&svq->svq_call);
331
+
332
+ if (check_for_avail_queue && svq->next_guest_avail_elem) {
333
+ /*
334
+ * Avail ring was full when vhost_svq_flush was called, so it's a
335
+ * good moment to make more descriptors available if possible.
336
+ */
337
+ vhost_handle_guest_kick(svq);
338
+ }
339
+ } while (!vhost_svq_enable_notification(svq));
340
+}
341
+
342
+/**
343
+ * Forward used buffers.
344
*
345
* @n: hdev call event notifier, the one that device set to notify svq.
346
+ *
347
+ * Note that we are not making any buffers available in the loop, there is no
348
+ * way that it runs more than virtqueue size times.
349
*/
350
static void vhost_svq_handle_call(EventNotifier *n)
351
{
352
VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue,
353
hdev_call);
354
event_notifier_test_and_clear(n);
355
- event_notifier_set(&svq->svq_call);
356
+ vhost_svq_flush(svq, true);
357
}
358
359
/**
360
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
361
if (poll_start) {
362
event_notifier_init_fd(svq_kick, svq_kick_fd);
363
event_notifier_set(svq_kick);
364
- event_notifier_set_handler(svq_kick, vhost_handle_guest_kick);
365
+ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier);
366
+ }
367
+}
368
+
369
+/**
370
+ * Start the shadow virtqueue operation.
371
+ *
372
+ * @svq: Shadow Virtqueue
373
+ * @vdev: VirtIO device
374
+ * @vq: Virtqueue to shadow
375
+ */
376
+void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
377
+ VirtQueue *vq)
378
+{
379
+ size_t desc_size, driver_size, device_size;
380
+
381
+ svq->next_guest_avail_elem = NULL;
382
+ svq->shadow_avail_idx = 0;
383
+ svq->shadow_used_idx = 0;
384
+ svq->last_used_idx = 0;
385
+ svq->vdev = vdev;
386
+ svq->vq = vq;
387
+
388
+ svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq));
389
+ driver_size = vhost_svq_driver_area_size(svq);
390
+ device_size = vhost_svq_device_area_size(svq);
391
+ svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size);
392
+ desc_size = sizeof(vring_desc_t) * svq->vring.num;
393
+ svq->vring.avail = (void *)((char *)svq->vring.desc + desc_size);
394
+ memset(svq->vring.desc, 0, driver_size);
395
+ svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size);
396
+ memset(svq->vring.used, 0, device_size);
397
+ svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num);
398
+ for (unsigned i = 0; i < svq->vring.num - 1; i++) {
399
+ svq->vring.desc[i].next = cpu_to_le16(i + 1);
400
}
401
}
402
403
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
404
void vhost_svq_stop(VhostShadowVirtqueue *svq)
405
{
406
event_notifier_set_handler(&svq->svq_kick, NULL);
407
+ g_autofree VirtQueueElement *next_avail_elem = NULL;
408
+
409
+ if (!svq->vq) {
48
+ return;
410
+ return;
49
+ }
411
+ }
50
412
+
51
qemu_mutex_lock(&event_mtx);
413
+ /* Send all pending used descriptors to guest */
52
QTAILQ_FOREACH(s, &net_compares, next) {
414
+ vhost_svq_flush(svq, false);
53
@@ -XXX,XX +XXX,XX @@ void colo_notify_compares_event(void *opaque, int event, Error **errp)
415
+
416
+ for (unsigned i = 0; i < svq->vring.num; ++i) {
417
+ g_autofree VirtQueueElement *elem = NULL;
418
+ elem = g_steal_pointer(&svq->ring_id_maps[i]);
419
+ if (elem) {
420
+ virtqueue_detach_element(svq->vq, elem, 0);
421
+ }
422
+ }
423
+
424
+ next_avail_elem = g_steal_pointer(&svq->next_guest_avail_elem);
425
+ if (next_avail_elem) {
426
+ virtqueue_detach_element(svq->vq, next_avail_elem, 0);
427
+ }
428
+ svq->vq = NULL;
429
+ g_free(svq->ring_id_maps);
430
+ qemu_vfree(svq->vring.desc);
431
+ qemu_vfree(svq->vring.used);
432
}
433
434
/**
435
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
436
index XXXXXXX..XXXXXXX 100644
437
--- a/hw/virtio/vhost-shadow-virtqueue.h
438
+++ b/hw/virtio/vhost-shadow-virtqueue.h
439
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
440
441
/* Guest's call notifier, where the SVQ calls guest. */
442
EventNotifier svq_call;
443
+
444
+ /* Virtio queue shadowing */
445
+ VirtQueue *vq;
446
+
447
+ /* Virtio device */
448
+ VirtIODevice *vdev;
449
+
450
+ /* Map for use the guest's descriptors */
451
+ VirtQueueElement **ring_id_maps;
452
+
453
+ /* Next VirtQueue element that guest made available */
454
+ VirtQueueElement *next_guest_avail_elem;
455
+
456
+ /* Next head to expose to the device */
457
+ uint16_t shadow_avail_idx;
458
+
459
+ /* Next free descriptor */
460
+ uint16_t free_head;
461
+
462
+ /* Last seen used idx */
463
+ uint16_t shadow_used_idx;
464
+
465
+ /* Next head to consume from the device */
466
+ uint16_t last_used_idx;
467
} VhostShadowVirtqueue;
468
469
bool vhost_svq_valid_features(uint64_t features, Error **errp);
470
@@ -XXX,XX +XXX,XX @@ void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
471
size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq);
472
size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq);
473
474
+void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
475
+ VirtQueue *vq);
476
void vhost_svq_stop(VhostShadowVirtqueue *svq);
477
478
VhostShadowVirtqueue *vhost_svq_new(void);
479
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
480
index XXXXXXX..XXXXXXX 100644
481
--- a/hw/virtio/vhost-vdpa.c
482
+++ b/hw/virtio/vhost-vdpa.c
483
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev,
484
* Note that this function does not rewind kick file descriptor if cannot set
485
* call one.
486
*/
487
-static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
488
- VhostShadowVirtqueue *svq, unsigned idx,
489
- Error **errp)
490
+static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
491
+ VhostShadowVirtqueue *svq, unsigned idx,
492
+ Error **errp)
493
{
494
struct vhost_vring_file file = {
495
.index = dev->vq_index + idx,
496
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
497
r = vhost_vdpa_set_vring_dev_kick(dev, &file);
498
if (unlikely(r != 0)) {
499
error_setg_errno(errp, -r, "Can't set device kick fd");
500
- return false;
501
+ return r;
54
}
502
}
55
503
56
qemu_mutex_unlock(&event_mtx);
504
event_notifier = &svq->hdev_call;
57
+ qemu_mutex_unlock(&colo_compare_mutex);
505
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
506
error_setg_errno(errp, -r, "Can't set device call fd");
507
}
508
509
+ return r;
510
+}
511
+
512
+/**
513
+ * Unmap a SVQ area in the device
514
+ */
515
+static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova,
516
+ hwaddr size)
517
+{
518
+ int r;
519
+
520
+ size = ROUND_UP(size, qemu_real_host_page_size);
521
+ r = vhost_vdpa_dma_unmap(v, iova, size);
522
+ return r == 0;
523
+}
524
+
525
+static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
526
+ const VhostShadowVirtqueue *svq)
527
+{
528
+ struct vhost_vdpa *v = dev->opaque;
529
+ struct vhost_vring_addr svq_addr;
530
+ size_t device_size = vhost_svq_device_area_size(svq);
531
+ size_t driver_size = vhost_svq_driver_area_size(svq);
532
+ bool ok;
533
+
534
+ vhost_svq_get_vring_addr(svq, &svq_addr);
535
+
536
+ ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size);
537
+ if (unlikely(!ok)) {
538
+ return false;
539
+ }
540
+
541
+ return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size);
542
+}
543
+
544
+/**
545
+ * Map the shadow virtqueue rings in the device
546
+ *
547
+ * @dev: The vhost device
548
+ * @svq: The shadow virtqueue
549
+ * @addr: Assigned IOVA addresses
550
+ * @errp: Error pointer
551
+ */
552
+static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
553
+ const VhostShadowVirtqueue *svq,
554
+ struct vhost_vring_addr *addr,
555
+ Error **errp)
556
+{
557
+ struct vhost_vdpa *v = dev->opaque;
558
+ size_t device_size = vhost_svq_device_area_size(svq);
559
+ size_t driver_size = vhost_svq_driver_area_size(svq);
560
+ int r;
561
+
562
+ ERRP_GUARD();
563
+ vhost_svq_get_vring_addr(svq, addr);
564
+
565
+ r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size,
566
+ (void *)(uintptr_t)addr->desc_user_addr, true);
567
+ if (unlikely(r != 0)) {
568
+ error_setg_errno(errp, -r, "Cannot create vq driver region: ");
569
+ return false;
570
+ }
571
+
572
+ r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size,
573
+ (void *)(intptr_t)addr->used_user_addr, false);
574
+ if (unlikely(r != 0)) {
575
+ error_setg_errno(errp, -r, "Cannot create vq device region: ");
576
+ }
577
+
578
+ return r == 0;
579
+}
580
+
581
+static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
582
+ VhostShadowVirtqueue *svq, unsigned idx,
583
+ Error **errp)
584
+{
585
+ uint16_t vq_index = dev->vq_index + idx;
586
+ struct vhost_vring_state s = {
587
+ .index = vq_index,
588
+ };
589
+ int r;
590
+
591
+ r = vhost_vdpa_set_dev_vring_base(dev, &s);
592
+ if (unlikely(r)) {
593
+ error_setg_errno(errp, -r, "Cannot set vring base");
594
+ return false;
595
+ }
596
+
597
+ r = vhost_vdpa_svq_set_fds(dev, svq, idx, errp);
598
return r == 0;
58
}
599
}
59
600
60
static void colo_compare_timer_init(CompareState *s)
601
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev)
61
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
62
s->vnet_hdr);
63
}
602
}
64
603
65
+ qemu_mutex_lock(&colo_compare_mutex);
604
for (i = 0; i < v->shadow_vqs->len; ++i) {
66
+ if (!colo_compare_active) {
605
+ VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i);
67
+ qemu_mutex_init(&event_mtx);
606
VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
68
+ qemu_cond_init(&event_complete_cond);
607
+ struct vhost_vring_addr addr = {
69
+ colo_compare_active = true;
608
+ .index = i,
70
+ }
609
+ };
71
QTAILQ_INSERT_TAIL(&net_compares, s, next);
610
+ int r;
72
+ qemu_mutex_unlock(&colo_compare_mutex);
611
bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err);
73
612
if (unlikely(!ok)) {
74
s->out_sendco.s = s;
613
- error_reportf_err(err, "Cannot setup SVQ %u: ", i);
75
s->out_sendco.chr = &s->chr_out;
614
+ goto err;
76
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
615
+ }
77
616
+
78
g_queue_init(&s->conn_list);
617
+ vhost_svq_start(svq, dev->vdev, vq);
79
618
+ ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err);
80
- qemu_mutex_init(&event_mtx);
619
+ if (unlikely(!ok)) {
81
- qemu_cond_init(&event_complete_cond);
620
+ goto err_map;
82
-
621
+ }
83
s->connection_track_table = g_hash_table_new_full(connection_key_hash,
622
+
84
connection_key_equal,
623
+ /* Override vring GPA set by vhost subsystem */
85
g_free,
624
+ r = vhost_vdpa_set_vring_dev_addr(dev, &addr);
86
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
625
+ if (unlikely(r != 0)) {
87
626
+ error_setg_errno(&err, -r, "Cannot set device address");
88
qemu_bh_delete(s->event_bh);
627
+ goto err_set_addr;
89
628
+ }
90
+ qemu_mutex_lock(&colo_compare_mutex);
629
+ }
91
QTAILQ_FOREACH(tmp, &net_compares, next) {
630
+
92
if (tmp == s) {
631
+ return true;
93
QTAILQ_REMOVE(&net_compares, s, next);
632
+
94
break;
633
+err_set_addr:
634
+ vhost_vdpa_svq_unmap_rings(dev, g_ptr_array_index(v->shadow_vqs, i));
635
+
636
+err_map:
637
+ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, i));
638
+
639
+err:
640
+ error_reportf_err(err, "Cannot setup SVQ %u: ", i);
641
+ for (unsigned j = 0; j < i; ++j) {
642
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, j);
643
+ vhost_vdpa_svq_unmap_rings(dev, svq);
644
+ vhost_svq_stop(svq);
645
+ }
646
+
647
+ return false;
648
+}
649
+
650
+static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev)
651
+{
652
+ struct vhost_vdpa *v = dev->opaque;
653
+
654
+ if (!v->shadow_vqs) {
655
+ return true;
656
+ }
657
+
658
+ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {
659
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
660
+ bool ok = vhost_vdpa_svq_unmap_rings(dev, svq);
661
+ if (unlikely(!ok)) {
662
return false;
95
}
663
}
96
}
664
}
97
+ if (QTAILQ_EMPTY(&net_compares)) {
665
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
98
+ colo_compare_active = false;
666
}
99
+ qemu_mutex_destroy(&event_mtx);
667
vhost_vdpa_set_vring_ready(dev);
100
+ qemu_cond_destroy(&event_complete_cond);
668
} else {
101
+ }
669
+ ok = vhost_vdpa_svqs_stop(dev);
102
+ qemu_mutex_unlock(&colo_compare_mutex);
670
+ if (unlikely(!ok)) {
103
671
+ return -1;
104
AioContext *ctx = iothread_get_aio_context(s->iothread);
672
+ }
105
aio_context_acquire(ctx);
673
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
106
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
107
object_unref(OBJECT(s->iothread));
108
}
674
}
109
675
110
- qemu_mutex_destroy(&event_mtx);
111
- qemu_cond_destroy(&event_complete_cond);
112
-
113
g_free(s->pri_indev);
114
g_free(s->sec_indev);
115
g_free(s->outdev);
116
g_free(s->notify_dev);
117
}
118
119
+static void __attribute__((__constructor__)) colo_compare_init_globals(void)
120
+{
121
+ colo_compare_active = false;
122
+ qemu_mutex_init(&colo_compare_mutex);
123
+}
124
+
125
static const TypeInfo colo_compare_info = {
126
.name = TYPE_COLO_COMPARE,
127
.parent = TYPE_OBJECT,
128
--
676
--
129
2.5.0
677
2.7.4
130
678
131
679
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Now that the "name" parameter is gone, there is hardly any difference
3
This iova tree function allows it to look for a hole in allocated
4
between NetLegacy and Netdev anymore, so we can drop NetLegacy and always
4
regions and return a totally new translation for a given translated
5
use Netdev to simplify the code quite a bit.
5
address.
6
6
7
The only two differences that were really left between Netdev and NetLegacy:
7
It's usage is mainly to allow devices to access qemu address space,
8
8
remapping guest's one into a new iova space where qemu can add chunks of
9
1) NetLegacy does not allow a "hubport" type. We can continue to block
9
addresses.
10
this with a simple check in net_client_init1() for this type.
10
11
11
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
12
2) The "id" parameter was optional in NetLegacy (and an internal id
12
Reviewed-by: Peter Xu <peterx@redhat.com>
13
was chosen via assign_name() during initialization), but it is mandatory
13
Acked-by: Michael S. Tsirkin <mst@redhat.com>
14
for Netdev. To avoid that the visitor code bails out here, we have to
15
add an internal id to the QemuOpts already earlier now.
16
17
Signed-off-by: Thomas Huth <thuth@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
20
---
15
---
21
net/net.c | 77 ++++++++++-------------------------------------------------
16
include/qemu/iova-tree.h | 18 +++++++
22
qapi/net.json | 46 -----------------------------------
17
util/iova-tree.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++
23
2 files changed, 13 insertions(+), 110 deletions(-)
18
2 files changed, 154 insertions(+)
24
19
25
diff --git a/net/net.c b/net/net.c
20
diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
26
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
27
--- a/net/net.c
22
--- a/include/qemu/iova-tree.h
28
+++ b/net/net.c
23
+++ b/include/qemu/iova-tree.h
29
@@ -XXX,XX +XXX,XX @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
24
@@ -XXX,XX +XXX,XX @@
25
#define IOVA_OK (0)
26
#define IOVA_ERR_INVALID (-1) /* Invalid parameters */
27
#define IOVA_ERR_OVERLAP (-2) /* IOVA range overlapped */
28
+#define IOVA_ERR_NOMEM (-3) /* Cannot allocate */
29
30
typedef struct IOVATree IOVATree;
31
typedef struct DMAMap {
32
@@ -XXX,XX +XXX,XX @@ const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova);
33
void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator);
34
35
/**
36
+ * iova_tree_alloc_map:
37
+ *
38
+ * @tree: the iova tree to allocate from
39
+ * @map: the new map (as translated addr & size) to allocate in the iova region
40
+ * @iova_begin: the minimum address of the allocation
41
+ * @iova_end: the maximum addressable direction of the allocation
42
+ *
43
+ * Allocates a new region of a given size, between iova_min and iova_max.
44
+ *
45
+ * Return: Same as iova_tree_insert, but cannot overlap and can return error if
46
+ * iova tree is out of free contiguous range. The caller gets the assigned iova
47
+ * in map->iova.
48
+ */
49
+int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin,
50
+ hwaddr iova_end);
51
+
52
+/**
53
* iova_tree_destroy:
54
*
55
* @tree: the iova tree to destroy
56
diff --git a/util/iova-tree.c b/util/iova-tree.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/util/iova-tree.c
59
+++ b/util/iova-tree.c
60
@@ -XXX,XX +XXX,XX @@ struct IOVATree {
61
GTree *tree;
30
};
62
};
31
63
32
64
+/* Args to pass to iova_tree_alloc foreach function. */
33
-static int net_client_init1(const void *object, bool is_netdev, Error **errp)
65
+struct IOVATreeAllocArgs {
34
+static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp)
66
+ /* Size of the desired allocation */
67
+ size_t new_size;
68
+
69
+ /* The minimum address allowed in the allocation */
70
+ hwaddr iova_begin;
71
+
72
+ /* Map at the left of the hole, can be NULL if "this" is first one */
73
+ const DMAMap *prev;
74
+
75
+ /* Map at the right of the hole, can be NULL if "prev" is the last one */
76
+ const DMAMap *this;
77
+
78
+ /* If found, we fill in the IOVA here */
79
+ hwaddr iova_result;
80
+
81
+ /* Whether have we found a valid IOVA */
82
+ bool iova_found;
83
+};
84
+
85
+/**
86
+ * Iterate args to the next hole
87
+ *
88
+ * @args: The alloc arguments
89
+ * @next: The next mapping in the tree. Can be NULL to signal the last one
90
+ */
91
+static void iova_tree_alloc_args_iterate(struct IOVATreeAllocArgs *args,
92
+ const DMAMap *next)
93
+{
94
+ args->prev = args->this;
95
+ args->this = next;
96
+}
97
+
98
static int iova_tree_compare(gconstpointer a, gconstpointer b, gpointer data)
35
{
99
{
36
- Netdev legacy = {0};
100
const DMAMap *m1 = a, *m2 = b;
37
- const Netdev *netdev;
101
@@ -XXX,XX +XXX,XX @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map)
38
NetClientState *peer = NULL;
102
return IOVA_OK;
39
103
}
40
if (is_netdev) {
104
41
- netdev = object;
105
+/**
42
-
106
+ * Try to find an unallocated IOVA range between prev and this elements.
43
if (netdev->type == NET_CLIENT_DRIVER_NIC ||
107
+ *
44
!net_client_init_fun[netdev->type]) {
108
+ * @args: Arguments to allocation
45
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
109
+ *
46
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
110
+ * Cases:
47
return -1;
111
+ *
48
}
112
+ * (1) !prev, !this: No entries allocated, always succeed
49
} else {
113
+ *
50
- const NetLegacy *net = object;
114
+ * (2) !prev, this: We're iterating at the 1st element.
51
- const NetLegacyOptions *opts = net->opts;
115
+ *
52
- legacy.id = net->id;
116
+ * (3) prev, !this: We're iterating at the last element.
53
- netdev = &legacy;
117
+ *
54
-
118
+ * (4) prev, this: this is the most common case, we'll try to find a hole
55
- /* Map the old options to the new flat type */
119
+ * between "prev" and "this" mapping.
56
- switch (opts->type) {
120
+ *
57
- case NET_LEGACY_OPTIONS_TYPE_NONE:
121
+ * Note that this function assumes the last valid iova is HWADDR_MAX, but it
58
+ if (netdev->type == NET_CLIENT_DRIVER_NONE) {
122
+ * searches linearly so it's easy to discard the result if it's not the case.
59
return 0; /* nothing to do */
123
+ */
60
- case NET_LEGACY_OPTIONS_TYPE_NIC:
124
+static void iova_tree_alloc_map_in_hole(struct IOVATreeAllocArgs *args)
61
- legacy.type = NET_CLIENT_DRIVER_NIC;
125
+{
62
- legacy.u.nic = opts->u.nic;
126
+ const DMAMap *prev = args->prev, *this = args->this;
63
- break;
127
+ uint64_t hole_start, hole_last;
64
- case NET_LEGACY_OPTIONS_TYPE_USER:
128
+
65
- legacy.type = NET_CLIENT_DRIVER_USER;
129
+ if (this && this->iova + this->size < args->iova_begin) {
66
- legacy.u.user = opts->u.user;
130
+ return;
67
- break;
131
+ }
68
- case NET_LEGACY_OPTIONS_TYPE_TAP:
132
+
69
- legacy.type = NET_CLIENT_DRIVER_TAP;
133
+ hole_start = MAX(prev ? prev->iova + prev->size + 1 : 0, args->iova_begin);
70
- legacy.u.tap = opts->u.tap;
134
+ hole_last = this ? this->iova : HWADDR_MAX;
71
- break;
135
+
72
- case NET_LEGACY_OPTIONS_TYPE_L2TPV3:
136
+ if (hole_last - hole_start > args->new_size) {
73
- legacy.type = NET_CLIENT_DRIVER_L2TPV3;
137
+ args->iova_result = hole_start;
74
- legacy.u.l2tpv3 = opts->u.l2tpv3;
138
+ args->iova_found = true;
75
- break;
139
+ }
76
- case NET_LEGACY_OPTIONS_TYPE_SOCKET:
140
+}
77
- legacy.type = NET_CLIENT_DRIVER_SOCKET;
141
+
78
- legacy.u.socket = opts->u.socket;
142
+/**
79
- break;
143
+ * Foreach dma node in the tree, compare if there is a hole with its previous
80
- case NET_LEGACY_OPTIONS_TYPE_VDE:
144
+ * node (or minimum iova address allowed) and the node.
81
- legacy.type = NET_CLIENT_DRIVER_VDE;
145
+ *
82
- legacy.u.vde = opts->u.vde;
146
+ * @key: Node iterating
83
- break;
147
+ * @value: Node iterating
84
- case NET_LEGACY_OPTIONS_TYPE_BRIDGE:
148
+ * @pargs: Struct to communicate with the outside world
85
- legacy.type = NET_CLIENT_DRIVER_BRIDGE;
149
+ *
86
- legacy.u.bridge = opts->u.bridge;
150
+ * Return: false to keep iterating, true if needs break.
87
- break;
151
+ */
88
- case NET_LEGACY_OPTIONS_TYPE_NETMAP:
152
+static gboolean iova_tree_alloc_traverse(gpointer key, gpointer value,
89
- legacy.type = NET_CLIENT_DRIVER_NETMAP;
153
+ gpointer pargs)
90
- legacy.u.netmap = opts->u.netmap;
154
+{
91
- break;
155
+ struct IOVATreeAllocArgs *args = pargs;
92
- case NET_LEGACY_OPTIONS_TYPE_VHOST_USER:
156
+ DMAMap *node = value;
93
- legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
157
+
94
- legacy.u.vhost_user = opts->u.vhost_user;
158
+ assert(key == value);
95
- break;
159
+
96
- default:
160
+ iova_tree_alloc_args_iterate(args, node);
97
- abort();
161
+ iova_tree_alloc_map_in_hole(args);
98
}
162
+ return args->iova_found;
99
-
163
+}
100
- if (!net_client_init_fun[netdev->type]) {
164
+
101
+ if (netdev->type == NET_CLIENT_DRIVER_HUBPORT ||
165
+int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin,
102
+ !net_client_init_fun[netdev->type]) {
166
+ hwaddr iova_last)
103
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
167
+{
104
"a net backend type (maybe it is not compiled "
168
+ struct IOVATreeAllocArgs args = {
105
"into this binary)");
169
+ .new_size = map->size,
106
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
170
+ .iova_begin = iova_begin,
107
171
+ };
108
/* Do not add to a hub if it's a nic with a netdev= parameter. */
172
+
109
if (netdev->type != NET_CLIENT_DRIVER_NIC ||
173
+ if (unlikely(iova_last < iova_begin)) {
110
- !opts->u.nic.has_netdev) {
174
+ return IOVA_ERR_INVALID;
111
+ !netdev->u.nic.has_netdev) {
175
+ }
112
peer = net_hub_add_port(0, NULL, NULL);
176
+
113
}
177
+ /*
114
}
178
+ * Find a valid hole for the mapping
115
@@ -XXX,XX +XXX,XX @@ static void show_netdevs(void)
179
+ *
116
static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
180
+ * Assuming low iova_begin, so no need to do a binary search to
181
+ * locate the first node.
182
+ *
183
+ * TODO: Replace all this with g_tree_node_first/next/last when available
184
+ * (from glib since 2.68). To do it with g_tree_foreach complicates the
185
+ * code a lot.
186
+ *
187
+ */
188
+ g_tree_foreach(tree->tree, iova_tree_alloc_traverse, &args);
189
+ if (!args.iova_found) {
190
+ /*
191
+ * Either tree is empty or the last hole is still not checked.
192
+ * g_tree_foreach does not compare (last, iova_last] range, so we check
193
+ * it here.
194
+ */
195
+ iova_tree_alloc_args_iterate(&args, NULL);
196
+ iova_tree_alloc_map_in_hole(&args);
197
+ }
198
+
199
+ if (!args.iova_found || args.iova_result + map->size > iova_last) {
200
+ return IOVA_ERR_NOMEM;
201
+ }
202
+
203
+ map->iova = args.iova_result;
204
+ return iova_tree_insert(tree, map);
205
+}
206
+
207
void iova_tree_destroy(IOVATree *tree)
117
{
208
{
118
gchar **substrings = NULL;
209
g_tree_destroy(tree->tree);
119
- void *object = NULL;
120
+ Netdev *object = NULL;
121
Error *err = NULL;
122
int ret = -1;
123
Visitor *v = opts_visitor_new(opts);
124
@@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
125
}
126
}
127
128
- if (is_netdev) {
129
- visit_type_Netdev(v, NULL, (Netdev **)&object, &err);
130
- } else {
131
- visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err);
132
+ /* Create an ID for -net if the user did not specify one */
133
+ if (!is_netdev && !qemu_opts_id(opts)) {
134
+ static int idx;
135
+ qemu_opts_set_id(opts, g_strdup_printf("__org.qemu.net%i", idx++));
136
}
137
138
+ visit_type_Netdev(v, NULL, &object, &err);
139
+
140
if (!err) {
141
ret = net_client_init1(object, is_netdev, &err);
142
}
143
144
- if (is_netdev) {
145
- qapi_free_Netdev(object);
146
- } else {
147
- qapi_free_NetLegacy(object);
148
- }
149
+ qapi_free_Netdev(object);
150
151
out:
152
error_propagate(errp, err);
153
diff --git a/qapi/net.json b/qapi/net.json
154
index XXXXXXX..XXXXXXX 100644
155
--- a/qapi/net.json
156
+++ b/qapi/net.json
157
@@ -XXX,XX +XXX,XX @@
158
'vhost-user': 'NetdevVhostUserOptions' } }
159
160
##
161
-# @NetLegacy:
162
-#
163
-# Captures the configuration of a network device; legacy.
164
-#
165
-# @id: identifier for monitor commands
166
-#
167
-# @opts: device type specific properties (legacy)
168
-#
169
-# Since: 1.2
170
-##
171
-{ 'struct': 'NetLegacy',
172
- 'data': {
173
- '*id': 'str',
174
- 'opts': 'NetLegacyOptions' } }
175
-
176
-##
177
-# @NetLegacyOptionsType:
178
-#
179
-# Since: 1.2
180
-##
181
-{ 'enum': 'NetLegacyOptionsType',
182
- 'data': ['none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde',
183
- 'bridge', 'netmap', 'vhost-user'] }
184
-
185
-##
186
-# @NetLegacyOptions:
187
-#
188
-# Like Netdev, but for use only by the legacy command line options
189
-#
190
-# Since: 1.2
191
-##
192
-{ 'union': 'NetLegacyOptions',
193
- 'base': { 'type': 'NetLegacyOptionsType' },
194
- 'discriminator': 'type',
195
- 'data': {
196
- 'nic': 'NetLegacyNicOptions',
197
- 'user': 'NetdevUserOptions',
198
- 'tap': 'NetdevTapOptions',
199
- 'l2tpv3': 'NetdevL2TPv3Options',
200
- 'socket': 'NetdevSocketOptions',
201
- 'vde': 'NetdevVdeOptions',
202
- 'bridge': 'NetdevBridgeOptions',
203
- 'netmap': 'NetdevNetmapOptions',
204
- 'vhost-user': 'NetdevVhostUserOptions' } }
205
-
206
-##
207
# @NetFilterDirection:
208
#
209
# Indicates whether a netfilter is attached to a netdev's transmit queue or
210
--
210
--
211
2.5.0
211
2.7.4
212
212
213
213
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Optionally report RSS feature.
3
This function does the reverse operation of iova_tree_find: To look for
4
Handle RSS configuration command and keep RSS parameters
4
a mapping that match a translated address so we can do the reverse.
5
in virtio-net device context.
6
5
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
This have linear complexity instead of logarithmic, but it supports
7
overlapping HVA. Future developments could reduce it.
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
12
---
10
hw/net/trace-events | 3 +
13
include/qemu/iova-tree.h | 20 +++++++++++++++++++-
11
hw/net/virtio-net.c | 167 ++++++++++++++++++++++++++++++++++++++---
14
util/iova-tree.c | 34 ++++++++++++++++++++++++++++++++++
12
include/hw/virtio/virtio-net.h | 13 ++++
15
2 files changed, 53 insertions(+), 1 deletion(-)
13
3 files changed, 174 insertions(+), 9 deletions(-)
14
16
15
diff --git a/hw/net/trace-events b/hw/net/trace-events
17
diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/trace-events
19
--- a/include/qemu/iova-tree.h
18
+++ b/hw/net/trace-events
20
+++ b/include/qemu/iova-tree.h
19
@@ -XXX,XX +XXX,XX @@ virtio_net_announce_notify(void) ""
21
@@ -XXX,XX +XXX,XX @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map);
20
virtio_net_announce_timer(int round) "%d"
22
* @tree: the iova tree to search from
21
virtio_net_handle_announce(int round) "%d"
23
* @map: the mapping to search
22
virtio_net_post_load_device(void)
24
*
23
+virtio_net_rss_disable(void)
25
- * Search for a mapping in the iova tree that overlaps with the
24
+virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x"
26
+ * Search for a mapping in the iova tree that iova overlaps with the
25
+virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d"
27
* mapping range specified. Only the first found mapping will be
26
28
* returned.
27
# tulip.c
29
*
28
tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
30
@@ -XXX,XX +XXX,XX @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map);
29
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
31
const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map);
32
33
/**
34
+ * iova_tree_find_iova:
35
+ *
36
+ * @tree: the iova tree to search from
37
+ * @map: the mapping to search
38
+ *
39
+ * Search for a mapping in the iova tree that translated_addr overlaps with the
40
+ * mapping range specified. Only the first found mapping will be
41
+ * returned.
42
+ *
43
+ * Return: DMAMap pointer if found, or NULL if not found. Note that
44
+ * the returned DMAMap pointer is maintained internally. User should
45
+ * only read the content but never modify or free the content. Also,
46
+ * user is responsible to make sure the pointer is valid (say, no
47
+ * concurrent deletion in progress).
48
+ */
49
+const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map);
50
+
51
+/**
52
* iova_tree_find_address:
53
*
54
* @tree: the iova tree to search from
55
diff --git a/util/iova-tree.c b/util/iova-tree.c
30
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
31
--- a/hw/net/virtio-net.c
57
--- a/util/iova-tree.c
32
+++ b/hw/net/virtio-net.c
58
+++ b/util/iova-tree.c
33
@@ -XXX,XX +XXX,XX @@
59
@@ -XXX,XX +XXX,XX @@ struct IOVATreeAllocArgs {
34
tso/gso/gro 'off'. */
60
bool iova_found;
35
#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000
61
};
36
62
37
+#define VIRTIO_NET_RSS_SUPPORTED_HASHES (VIRTIO_NET_RSS_HASH_TYPE_IPv4 | \
63
+typedef struct IOVATreeFindIOVAArgs {
38
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv4 | \
64
+ const DMAMap *needle;
39
+ VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | \
65
+ const DMAMap *result;
40
+ VIRTIO_NET_RSS_HASH_TYPE_IPv6 | \
66
+} IOVATreeFindIOVAArgs;
41
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv6 | \
42
+ VIRTIO_NET_RSS_HASH_TYPE_UDPv6 | \
43
+ VIRTIO_NET_RSS_HASH_TYPE_IP_EX | \
44
+ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
45
+ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
46
+
67
+
47
/* temporary until standard header include it */
68
/**
48
#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
69
* Iterate args to the next hole
49
70
*
50
@@ -XXX,XX +XXX,XX @@ static VirtIOFeature feature_sizes[] = {
71
@@ -XXX,XX +XXX,XX @@ const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map)
51
.end = endof(struct virtio_net_config, mtu)},
72
return g_tree_lookup(tree->tree, map);
52
{.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX,
53
.end = endof(struct virtio_net_config, duplex)},
54
+ {.flags = 1ULL << VIRTIO_NET_F_RSS,
55
+ .end = endof(struct virtio_net_config, supported_hash_types)},
56
{}
57
};
58
59
@@ -XXX,XX +XXX,XX @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
60
memcpy(netcfg.mac, n->mac, ETH_ALEN);
61
virtio_stl_p(vdev, &netcfg.speed, n->net_conf.speed);
62
netcfg.duplex = n->net_conf.duplex;
63
+ netcfg.rss_max_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
64
+ virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length,
65
+ VIRTIO_NET_RSS_MAX_TABLE_LEN);
66
+ virtio_stl_p(vdev, &netcfg.supported_hash_types,
67
+ VIRTIO_NET_RSS_SUPPORTED_HASHES);
68
memcpy(config, &netcfg, n->config_size);
69
}
73
}
70
74
71
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
75
+static gboolean iova_tree_find_address_iterator(gpointer key, gpointer value,
72
return features;
76
+ gpointer data)
73
}
74
75
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
76
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
77
vdev->backend_features = features;
78
79
@@ -XXX,XX +XXX,XX @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
80
}
81
82
virtio_net_set_multiqueue(n,
83
+ virtio_has_feature(features, VIRTIO_NET_F_RSS) ||
84
virtio_has_feature(features, VIRTIO_NET_F_MQ));
85
86
virtio_net_set_mrg_rx_bufs(n,
87
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
88
}
89
}
90
91
+static void virtio_net_disable_rss(VirtIONet *n)
92
+{
77
+{
93
+ if (n->rss_data.enabled) {
78
+ const DMAMap *map = key;
94
+ trace_virtio_net_rss_disable();
79
+ IOVATreeFindIOVAArgs *args = data;
80
+ const DMAMap *needle;
81
+
82
+ g_assert(key == value);
83
+
84
+ needle = args->needle;
85
+ if (map->translated_addr + map->size < needle->translated_addr ||
86
+ needle->translated_addr + needle->size < map->translated_addr) {
87
+ return false;
95
+ }
88
+ }
96
+ n->rss_data.enabled = false;
89
+
90
+ args->result = map;
91
+ return true;
97
+}
92
+}
98
+
93
+
99
+static uint16_t virtio_net_handle_rss(VirtIONet *n,
94
+const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map)
100
+ struct iovec *iov, unsigned int iov_cnt)
101
+{
95
+{
102
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
96
+ IOVATreeFindIOVAArgs args = {
103
+ struct virtio_net_rss_config cfg;
97
+ .needle = map,
104
+ size_t s, offset = 0, size_get;
98
+ };
105
+ uint16_t queues, i;
106
+ struct {
107
+ uint16_t us;
108
+ uint8_t b;
109
+ } QEMU_PACKED temp;
110
+ const char *err_msg = "";
111
+ uint32_t err_value = 0;
112
+
99
+
113
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {
100
+ g_tree_foreach(tree->tree, iova_tree_find_address_iterator, &args);
114
+ err_msg = "RSS is not negotiated";
101
+ return args.result;
115
+ goto error;
116
+ }
117
+ size_get = offsetof(struct virtio_net_rss_config, indirection_table);
118
+ s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get);
119
+ if (s != size_get) {
120
+ err_msg = "Short command buffer";
121
+ err_value = (uint32_t)s;
122
+ goto error;
123
+ }
124
+ n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
125
+ n->rss_data.indirections_len =
126
+ virtio_lduw_p(vdev, &cfg.indirection_table_mask);
127
+ n->rss_data.indirections_len++;
128
+ if (!is_power_of_2(n->rss_data.indirections_len)) {
129
+ err_msg = "Invalid size of indirection table";
130
+ err_value = n->rss_data.indirections_len;
131
+ goto error;
132
+ }
133
+ if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
134
+ err_msg = "Too large indirection table";
135
+ err_value = n->rss_data.indirections_len;
136
+ goto error;
137
+ }
138
+ n->rss_data.default_queue =
139
+ virtio_lduw_p(vdev, &cfg.unclassified_queue);
140
+ if (n->rss_data.default_queue >= n->max_queues) {
141
+ err_msg = "Invalid default queue";
142
+ err_value = n->rss_data.default_queue;
143
+ goto error;
144
+ }
145
+ offset += size_get;
146
+ size_get = sizeof(uint16_t) * n->rss_data.indirections_len;
147
+ g_free(n->rss_data.indirections_table);
148
+ n->rss_data.indirections_table = g_malloc(size_get);
149
+ if (!n->rss_data.indirections_table) {
150
+ err_msg = "Can't allocate indirections table";
151
+ err_value = n->rss_data.indirections_len;
152
+ goto error;
153
+ }
154
+ s = iov_to_buf(iov, iov_cnt, offset,
155
+ n->rss_data.indirections_table, size_get);
156
+ if (s != size_get) {
157
+ err_msg = "Short indirection table buffer";
158
+ err_value = (uint32_t)s;
159
+ goto error;
160
+ }
161
+ for (i = 0; i < n->rss_data.indirections_len; ++i) {
162
+ uint16_t val = n->rss_data.indirections_table[i];
163
+ n->rss_data.indirections_table[i] = virtio_lduw_p(vdev, &val);
164
+ }
165
+ offset += size_get;
166
+ size_get = sizeof(temp);
167
+ s = iov_to_buf(iov, iov_cnt, offset, &temp, size_get);
168
+ if (s != size_get) {
169
+ err_msg = "Can't get queues";
170
+ err_value = (uint32_t)s;
171
+ goto error;
172
+ }
173
+ queues = virtio_lduw_p(vdev, &temp.us);
174
+ if (queues == 0 || queues > n->max_queues) {
175
+ err_msg = "Invalid number of queues";
176
+ err_value = queues;
177
+ goto error;
178
+ }
179
+ if (temp.b > VIRTIO_NET_RSS_MAX_KEY_SIZE) {
180
+ err_msg = "Invalid key size";
181
+ err_value = temp.b;
182
+ goto error;
183
+ }
184
+ if (!temp.b && n->rss_data.hash_types) {
185
+ err_msg = "No key provided";
186
+ err_value = 0;
187
+ goto error;
188
+ }
189
+ if (!temp.b && !n->rss_data.hash_types) {
190
+ virtio_net_disable_rss(n);
191
+ return queues;
192
+ }
193
+ offset += size_get;
194
+ size_get = temp.b;
195
+ s = iov_to_buf(iov, iov_cnt, offset, n->rss_data.key, size_get);
196
+ if (s != size_get) {
197
+ err_msg = "Can get key buffer";
198
+ err_value = (uint32_t)s;
199
+ goto error;
200
+ }
201
+ n->rss_data.enabled = true;
202
+ trace_virtio_net_rss_enable(n->rss_data.hash_types,
203
+ n->rss_data.indirections_len,
204
+ temp.b);
205
+ return queues;
206
+error:
207
+ trace_virtio_net_rss_error(err_msg, err_value);
208
+ virtio_net_disable_rss(n);
209
+ return 0;
210
+}
102
+}
211
+
103
+
212
static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
104
const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova)
213
struct iovec *iov, unsigned int iov_cnt)
214
{
105
{
215
VirtIODevice *vdev = VIRTIO_DEVICE(n);
106
const DMAMap map = { .iova = iova, .size = 0 };
216
- struct virtio_net_ctrl_mq mq;
217
- size_t s;
218
uint16_t queues;
219
220
- s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
221
- if (s != sizeof(mq)) {
222
- return VIRTIO_NET_ERR;
223
- }
224
+ virtio_net_disable_rss(n);
225
+ if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
226
+ queues = virtio_net_handle_rss(n, iov, iov_cnt);
227
+ } else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
228
+ struct virtio_net_ctrl_mq mq;
229
+ size_t s;
230
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ)) {
231
+ return VIRTIO_NET_ERR;
232
+ }
233
+ s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
234
+ if (s != sizeof(mq)) {
235
+ return VIRTIO_NET_ERR;
236
+ }
237
+ queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs);
238
239
- if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
240
+ } else {
241
return VIRTIO_NET_ERR;
242
}
243
244
- queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs);
245
-
246
if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
247
queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
248
queues > n->max_queues ||
249
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
250
g_free(n->vqs);
251
qemu_del_nic(n->nic);
252
virtio_net_rsc_cleanup(n);
253
+ g_free(n->rss_data.indirections_table);
254
virtio_cleanup(vdev);
255
}
256
257
@@ -XXX,XX +XXX,XX @@ static Property virtio_net_properties[] = {
258
DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features,
259
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
260
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
261
+ DEFINE_PROP_BIT64("rss", VirtIONet, host_features,
262
+ VIRTIO_NET_F_RSS, false),
263
DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
264
VIRTIO_NET_F_RSC_EXT, false),
265
DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
266
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
267
index XXXXXXX..XXXXXXX 100644
268
--- a/include/hw/virtio/virtio-net.h
269
+++ b/include/hw/virtio/virtio-net.h
270
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
271
/* Maximum packet size we can receive from tap device: header + 64k */
272
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB))
273
274
+#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
275
+#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
276
+
277
+typedef struct VirtioNetRssData {
278
+ bool enabled;
279
+ uint32_t hash_types;
280
+ uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
281
+ uint16_t indirections_len;
282
+ uint16_t *indirections_table;
283
+ uint16_t default_queue;
284
+} VirtioNetRssData;
285
+
286
typedef struct VirtIONetQueue {
287
VirtQueue *rx_vq;
288
VirtQueue *tx_vq;
289
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
290
bool failover;
291
DeviceListener primary_listener;
292
Notifier migration_state;
293
+ VirtioNetRssData rss_data;
294
};
295
296
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
297
--
107
--
298
2.5.0
108
2.7.4
299
109
300
110
diff view generated by jsdifflib
Deleted patch
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
1
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
4
Signed-off-by: Jason Wang <jasowang@redhat.com>
5
---
6
net/tap.c | 3 ++-
7
1 file changed, 2 insertions(+), 1 deletion(-)
8
9
diff --git a/net/tap.c b/net/tap.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/net/tap.c
12
+++ b/net/tap.c
13
@@ -XXX,XX +XXX,XX @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
14
15
assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
16
assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
17
- len == sizeof(struct virtio_net_hdr));
18
+ len == sizeof(struct virtio_net_hdr) ||
19
+ len == sizeof(struct virtio_net_hdr_v1_hash));
20
21
tap_fd_set_vnet_hdr_len(s->fd, len);
22
s->host_vnet_hdr_len = len;
23
--
24
2.5.0
25
26
diff view generated by jsdifflib
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
During wrap around and reset, queues are pointing to initial base
3
This tree is able to look for a translated address from an IOVA address.
4
address of queue 0, irrespective of what queue we are dealing with.
5
Fix it by assigning proper base address every time.
6
4
7
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
5
At first glance it is similar to util/iova-tree. However, SVQ working on
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
6
devices with limited IOVA space need more capabilities, like allocating
7
IOVA chunks or performing reverse translations (qemu addresses to iova).
8
9
The allocation capability, as "assign a free IOVA address to this chunk
10
of memory in qemu's address space" allows shadow virtqueue to create a
11
new address space that is not restricted by guest's addressable one, so
12
we can allocate shadow vqs vrings outside of it.
13
14
It duplicates the tree so it can search efficiently in both directions,
15
and it will signal overlap if iova or the translated address is present
16
in any tree.
17
18
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
19
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
20
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
21
---
11
hw/net/cadence_gem.c | 37 +++++++++++++++++++++++++++++++++----
22
hw/virtio/meson.build | 2 +-
12
1 file changed, 33 insertions(+), 4 deletions(-)
23
hw/virtio/vhost-iova-tree.c | 110 ++++++++++++++++++++++++++++++++++++++++++++
24
hw/virtio/vhost-iova-tree.h | 27 +++++++++++
25
3 files changed, 138 insertions(+), 1 deletion(-)
26
create mode 100644 hw/virtio/vhost-iova-tree.c
27
create mode 100644 hw/virtio/vhost-iova-tree.h
13
28
14
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
29
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
15
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/cadence_gem.c
31
--- a/hw/virtio/meson.build
17
+++ b/hw/net/cadence_gem.c
32
+++ b/hw/virtio/meson.build
18
@@ -XXX,XX +XXX,XX @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
33
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c'))
19
return 0;
34
20
}
35
virtio_ss = ss.source_set()
21
36
virtio_ss.add(files('virtio.c'))
22
+static uint32_t gem_get_queue_base_addr(CadenceGEMState *s, bool tx, int q)
37
-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c'))
38
+virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c', 'vhost-iova-tree.c'))
39
virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c'))
40
virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c'))
41
virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c'))
42
diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c
43
new file mode 100644
44
index XXXXXXX..XXXXXXX
45
--- /dev/null
46
+++ b/hw/virtio/vhost-iova-tree.c
47
@@ -XXX,XX +XXX,XX @@
48
+/*
49
+ * vhost software live migration iova tree
50
+ *
51
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
52
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
53
+ *
54
+ * SPDX-License-Identifier: GPL-2.0-or-later
55
+ */
56
+
57
+#include "qemu/osdep.h"
58
+#include "qemu/iova-tree.h"
59
+#include "vhost-iova-tree.h"
60
+
61
+#define iova_min_addr qemu_real_host_page_size
62
+
63
+/**
64
+ * VhostIOVATree, able to:
65
+ * - Translate iova address
66
+ * - Reverse translate iova address (from translated to iova)
67
+ * - Allocate IOVA regions for translated range (linear operation)
68
+ */
69
+struct VhostIOVATree {
70
+ /* First addressable iova address in the device */
71
+ uint64_t iova_first;
72
+
73
+ /* Last addressable iova address in the device */
74
+ uint64_t iova_last;
75
+
76
+ /* IOVA address to qemu memory maps. */
77
+ IOVATree *iova_taddr_map;
78
+};
79
+
80
+/**
81
+ * Create a new IOVA tree
82
+ *
83
+ * Returns the new IOVA tree
84
+ */
85
+VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
23
+{
86
+{
24
+ uint32_t base_addr = 0;
87
+ VhostIOVATree *tree = g_new(VhostIOVATree, 1);
25
+
88
+
26
+ switch (q) {
89
+ /* Some devices do not like 0 addresses */
27
+ case 0:
90
+ tree->iova_first = MAX(iova_first, iova_min_addr);
28
+ base_addr = s->regs[tx ? GEM_TXQBASE : GEM_RXQBASE];
91
+ tree->iova_last = iova_last;
29
+ break;
30
+ case 1 ... (MAX_PRIORITY_QUEUES - 1):
31
+ base_addr = s->regs[(tx ? GEM_TRANSMIT_Q1_PTR :
32
+ GEM_RECEIVE_Q1_PTR) + q - 1];
33
+ break;
34
+ default:
35
+ g_assert_not_reached();
36
+ };
37
+
92
+
38
+ return base_addr;
93
+ tree->iova_taddr_map = iova_tree_new();
94
+ return tree;
39
+}
95
+}
40
+
96
+
41
+static inline uint32_t gem_get_tx_queue_base_addr(CadenceGEMState *s, int q)
97
+/**
98
+ * Delete an iova tree
99
+ */
100
+void vhost_iova_tree_delete(VhostIOVATree *iova_tree)
42
+{
101
+{
43
+ return gem_get_queue_base_addr(s, true, q);
102
+ iova_tree_destroy(iova_tree->iova_taddr_map);
103
+ g_free(iova_tree);
44
+}
104
+}
45
+
105
+
46
+static inline uint32_t gem_get_rx_queue_base_addr(CadenceGEMState *s, int q)
106
+/**
107
+ * Find the IOVA address stored from a memory address
108
+ *
109
+ * @tree: The iova tree
110
+ * @map: The map with the memory address
111
+ *
112
+ * Return the stored mapping, or NULL if not found.
113
+ */
114
+const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree,
115
+ const DMAMap *map)
47
+{
116
+{
48
+ return gem_get_queue_base_addr(s, false, q);
117
+ return iova_tree_find_iova(tree->iova_taddr_map, map);
49
+}
118
+}
50
+
119
+
51
static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q)
120
+/**
52
{
121
+ * Allocate a new mapping
53
hwaddr desc_addr = 0;
122
+ *
54
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
123
+ * @tree: The iova tree
55
/* Next descriptor */
124
+ * @map: The iova map
56
if (rx_desc_get_wrap(s->rx_desc[q])) {
125
+ *
57
DB_PRINT("wrapping RX descriptor list\n");
126
+ * Returns:
58
- s->rx_desc_addr[q] = s->regs[GEM_RXQBASE];
127
+ * - IOVA_OK if the map fits in the container
59
+ s->rx_desc_addr[q] = gem_get_rx_queue_base_addr(s, q);
128
+ * - IOVA_ERR_INVALID if the map does not make sense (like size overflow)
60
} else {
129
+ * - IOVA_ERR_NOMEM if tree cannot allocate more space.
61
DB_PRINT("incrementing RX descriptor list\n");
130
+ *
62
s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true);
131
+ * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK.
63
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
132
+ */
64
sizeof(desc_first));
133
+int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map)
65
/* Advance the hardware current descriptor past this packet */
134
+{
66
if (tx_desc_get_wrap(desc)) {
135
+ /* Some vhost devices do not like addr 0. Skip first page */
67
- s->tx_desc_addr[q] = s->regs[GEM_TXQBASE];
136
+ hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size;
68
+ s->tx_desc_addr[q] = gem_get_tx_queue_base_addr(s, q);
137
+
69
} else {
138
+ if (map->translated_addr + map->size < map->translated_addr ||
70
s->tx_desc_addr[q] = packet_desc_addr +
139
+ map->perm == IOMMU_NONE) {
71
4 * gem_get_desc_len(s, false);
140
+ return IOVA_ERR_INVALID;
72
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
141
+ }
73
} else {
142
+
74
packet_desc_addr = 0;
143
+ /* Allocate a node in IOVA address */
75
}
144
+ return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first,
76
- packet_desc_addr |= s->regs[GEM_TXQBASE];
145
+ tree->iova_last);
77
+ packet_desc_addr |= gem_get_tx_queue_base_addr(s, q);
146
+}
78
} else {
147
+
79
packet_desc_addr += 4 * gem_get_desc_len(s, false);
148
+/**
80
}
149
+ * Remove existing mappings from iova tree
81
@@ -XXX,XX +XXX,XX @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
150
+ *
82
if (!(val & GEM_NWCTRL_TXENA)) {
151
+ * @iova_tree: The vhost iova tree
83
/* Reset to start of Q when transmit disabled. */
152
+ * @map: The map to remove
84
for (i = 0; i < s->num_priority_queues; i++) {
153
+ */
85
- s->tx_desc_addr[i] = s->regs[GEM_TXQBASE];
154
+void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map)
86
+ s->tx_desc_addr[i] = gem_get_tx_queue_base_addr(s, i);
155
+{
87
}
156
+ iova_tree_remove(iova_tree->iova_taddr_map, map);
88
}
157
+}
89
if (gem_can_receive(qemu_get_queue(s->nic))) {
158
diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h
159
new file mode 100644
160
index XXXXXXX..XXXXXXX
161
--- /dev/null
162
+++ b/hw/virtio/vhost-iova-tree.h
163
@@ -XXX,XX +XXX,XX @@
164
+/*
165
+ * vhost software live migration iova tree
166
+ *
167
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
168
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
169
+ *
170
+ * SPDX-License-Identifier: GPL-2.0-or-later
171
+ */
172
+
173
+#ifndef HW_VIRTIO_VHOST_IOVA_TREE_H
174
+#define HW_VIRTIO_VHOST_IOVA_TREE_H
175
+
176
+#include "qemu/iova-tree.h"
177
+#include "exec/memory.h"
178
+
179
+typedef struct VhostIOVATree VhostIOVATree;
180
+
181
+VhostIOVATree *vhost_iova_tree_new(uint64_t iova_first, uint64_t iova_last);
182
+void vhost_iova_tree_delete(VhostIOVATree *iova_tree);
183
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete);
184
+
185
+const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree,
186
+ const DMAMap *map);
187
+int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map);
188
+void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map);
189
+
190
+#endif
90
--
191
--
91
2.5.0
192
2.7.4
92
193
93
194
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Suggest VIRTIO_NET_F_HASH_REPORT if specified in device
3
Use translations added in VhostIOVATree in SVQ.
4
parameters.
4
5
If the VIRTIO_NET_F_HASH_REPORT is set,
5
Only introduce usage here, not allocation and deallocation. As with
6
the device extends configuration space. If the feature
6
previous patches, we use the dead code paths of shadow_vqs_enabled to
7
is negotiated, the packet layout is extended to
7
avoid commiting too many changes at once. These are impossible to take
8
accomodate the hash information. In this case deliver
8
at the moment.
9
packet's hash value and report type in virtio header
9
10
extension.
10
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
11
Use for configuration the same procedure as already
11
Acked-by: Michael S. Tsirkin <mst@redhat.com>
12
used for RSS. We add two fields in rss_data that
13
controls what the device does with the calculated hash
14
if rss_data.enabled is set. If field 'populate' is set
15
the hash is set in the packet, if field 'redirect' is
16
set the hash is used to decide the queue to place the
17
packet to.
18
19
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
20
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
21
---
13
---
22
hw/net/virtio-net.c | 99 +++++++++++++++++++++++++++++++++---------
14
hw/virtio/vhost-shadow-virtqueue.c | 86 +++++++++++++++++++++++---
23
include/hw/virtio/virtio-net.h | 2 +
15
hw/virtio/vhost-shadow-virtqueue.h | 6 +-
24
2 files changed, 81 insertions(+), 20 deletions(-)
16
hw/virtio/vhost-vdpa.c | 122 +++++++++++++++++++++++++++++++------
25
17
include/hw/virtio/vhost-vdpa.h | 3 +
26
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
18
4 files changed, 187 insertions(+), 30 deletions(-)
19
20
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
27
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/net/virtio-net.c
22
--- a/hw/virtio/vhost-shadow-virtqueue.c
29
+++ b/hw/net/virtio-net.c
23
+++ b/hw/virtio/vhost-shadow-virtqueue.c
30
@@ -XXX,XX +XXX,XX @@ static VirtIOFeature feature_sizes[] = {
24
@@ -XXX,XX +XXX,XX @@ static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
31
.end = endof(struct virtio_net_config, mtu)},
25
return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx);
32
{.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX,
33
.end = endof(struct virtio_net_config, duplex)},
34
- {.flags = 1ULL << VIRTIO_NET_F_RSS,
35
+ {.flags = (1ULL << VIRTIO_NET_F_RSS) | (1ULL << VIRTIO_NET_F_HASH_REPORT),
36
.end = endof(struct virtio_net_config, supported_hash_types)},
37
{}
38
};
39
@@ -XXX,XX +XXX,XX @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
40
netcfg.duplex = n->net_conf.duplex;
41
netcfg.rss_max_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
42
virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length,
43
- VIRTIO_NET_RSS_MAX_TABLE_LEN);
44
+ virtio_host_has_feature(vdev, VIRTIO_NET_F_RSS) ?
45
+ VIRTIO_NET_RSS_MAX_TABLE_LEN : 1);
46
virtio_stl_p(vdev, &netcfg.supported_hash_types,
47
VIRTIO_NET_RSS_SUPPORTED_HASHES);
48
memcpy(config, &netcfg, n->config_size);
49
@@ -XXX,XX +XXX,XX @@ static int peer_has_ufo(VirtIONet *n)
50
}
26
}
51
27
52
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
28
-static void vhost_vring_write_descs(VhostShadowVirtqueue *svq,
53
- int version_1)
29
+/**
54
+ int version_1, int hash_report)
30
+ * Translate addresses between the qemu's virtual address and the SVQ IOVA
55
{
31
+ *
56
int i;
32
+ * @svq: Shadow VirtQueue
57
NetClientState *nc;
33
+ * @vaddr: Translated IOVA addresses
58
@@ -XXX,XX +XXX,XX @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
34
+ * @iovec: Source qemu's VA addresses
59
n->mergeable_rx_bufs = mergeable_rx_bufs;
35
+ * @num: Length of iovec and minimum length of vaddr
60
36
+ */
61
if (version_1) {
37
+static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
62
- n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
38
+ hwaddr *addrs, const struct iovec *iovec,
63
+ n->guest_hdr_len = hash_report ?
39
+ size_t num)
64
+ sizeof(struct virtio_net_hdr_v1_hash) :
40
+{
65
+ sizeof(struct virtio_net_hdr_mrg_rxbuf);
41
+ if (num == 0) {
66
+ n->rss_data.populate_hash = !!hash_report;
42
+ return true;
67
} else {
43
+ }
68
n->guest_hdr_len = n->mergeable_rx_bufs ?
44
+
69
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
45
+ for (size_t i = 0; i < num; ++i) {
70
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
46
+ DMAMap needle = {
71
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4);
47
+ .translated_addr = (hwaddr)(uintptr_t)iovec[i].iov_base,
72
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6);
48
+ .size = iovec[i].iov_len,
73
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN);
49
+ };
74
+
50
+ Int128 needle_last, map_last;
75
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
51
+ size_t off;
52
+
53
+ const DMAMap *map = vhost_iova_tree_find_iova(svq->iova_tree, &needle);
54
+ /*
55
+ * Map cannot be NULL since iova map contains all guest space and
56
+ * qemu already has a physical address mapped
57
+ */
58
+ if (unlikely(!map)) {
59
+ qemu_log_mask(LOG_GUEST_ERROR,
60
+ "Invalid address 0x%"HWADDR_PRIx" given by guest",
61
+ needle.translated_addr);
62
+ return false;
63
+ }
64
+
65
+ off = needle.translated_addr - map->translated_addr;
66
+ addrs[i] = map->iova + off;
67
+
68
+ needle_last = int128_add(int128_make64(needle.translated_addr),
69
+ int128_make64(iovec[i].iov_len));
70
+ map_last = int128_make64(map->translated_addr + map->size);
71
+ if (unlikely(int128_gt(needle_last, map_last))) {
72
+ qemu_log_mask(LOG_GUEST_ERROR,
73
+ "Guest buffer expands over iova range");
74
+ return false;
75
+ }
76
+ }
77
+
78
+ return true;
79
+}
80
+
81
+static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
82
const struct iovec *iovec, size_t num,
83
bool more_descs, bool write)
84
{
85
@@ -XXX,XX +XXX,XX @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq,
86
} else {
87
descs[i].flags = flags;
88
}
89
- descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base);
90
+ descs[i].addr = cpu_to_le64(sg[n]);
91
descs[i].len = cpu_to_le32(iovec[n].iov_len);
92
93
last = i;
94
@@ -XXX,XX +XXX,XX @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
95
{
96
unsigned avail_idx;
97
vring_avail_t *avail = svq->vring.avail;
98
+ bool ok;
99
+ g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num));
100
101
*head = svq->free_head;
102
103
@@ -XXX,XX +XXX,XX @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
104
return false;
76
}
105
}
77
106
78
if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
107
- vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0,
79
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
108
- false);
109
- vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true);
110
+ ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num);
111
+ if (unlikely(!ok)) {
112
+ return false;
113
+ }
114
+ vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num,
115
+ elem->in_num > 0, false);
116
+
117
+
118
+ ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num);
119
+ if (unlikely(!ok)) {
120
+ return false;
121
+ }
122
+
123
+ vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true);
124
125
/*
126
* Put the entry in the available array (but don't update avail->idx until
127
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd)
128
void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
129
struct vhost_vring_addr *addr)
130
{
131
- addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc;
132
- addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail;
133
- addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used;
134
+ addr->desc_user_addr = (uint64_t)(uintptr_t)svq->vring.desc;
135
+ addr->avail_user_addr = (uint64_t)(uintptr_t)svq->vring.avail;
136
+ addr->used_user_addr = (uint64_t)(uintptr_t)svq->vring.used;
137
}
138
139
size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq)
140
@@ -XXX,XX +XXX,XX @@ void vhost_svq_stop(VhostShadowVirtqueue *svq)
141
* Creates vhost shadow virtqueue, and instructs the vhost device to use the
142
* shadow methods and file descriptors.
143
*
144
+ * @iova_tree: Tree to perform descriptors translations
145
+ *
146
* Returns the new virtqueue or NULL.
147
*
148
* In case of error, reason is reported through error_report.
149
*/
150
-VhostShadowVirtqueue *vhost_svq_new(void)
151
+VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree)
152
{
153
g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1);
154
int r;
155
@@ -XXX,XX +XXX,XX @@ VhostShadowVirtqueue *vhost_svq_new(void)
156
157
event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
158
event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call);
159
+ svq->iova_tree = iova_tree;
160
return g_steal_pointer(&svq);
161
162
err_init_hdev_call:
163
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
164
index XXXXXXX..XXXXXXX 100644
165
--- a/hw/virtio/vhost-shadow-virtqueue.h
166
+++ b/hw/virtio/vhost-shadow-virtqueue.h
167
@@ -XXX,XX +XXX,XX @@
168
#include "qemu/event_notifier.h"
169
#include "hw/virtio/virtio.h"
170
#include "standard-headers/linux/vhost_types.h"
171
+#include "hw/virtio/vhost-iova-tree.h"
172
173
/* Shadow virtqueue to relay notifications */
174
typedef struct VhostShadowVirtqueue {
175
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
176
/* Virtio device */
177
VirtIODevice *vdev;
178
179
+ /* IOVA mapping */
180
+ VhostIOVATree *iova_tree;
181
+
182
/* Map for use the guest's descriptors */
183
VirtQueueElement **ring_id_maps;
184
185
@@ -XXX,XX +XXX,XX @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
186
VirtQueue *vq);
187
void vhost_svq_stop(VhostShadowVirtqueue *svq);
188
189
-VhostShadowVirtqueue *vhost_svq_new(void);
190
+VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree);
191
192
void vhost_svq_free(gpointer vq);
193
G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
194
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
195
index XXXXXXX..XXXXXXX 100644
196
--- a/hw/virtio/vhost-vdpa.c
197
+++ b/hw/virtio/vhost-vdpa.c
198
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
199
vaddr, section->readonly);
200
201
llsize = int128_sub(llend, int128_make64(iova));
202
+ if (v->shadow_vqs_enabled) {
203
+ DMAMap mem_region = {
204
+ .translated_addr = (hwaddr)(uintptr_t)vaddr,
205
+ .size = int128_get64(llsize) - 1,
206
+ .perm = IOMMU_ACCESS_FLAG(true, section->readonly),
207
+ };
208
+
209
+ int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region);
210
+ if (unlikely(r != IOVA_OK)) {
211
+ error_report("Can't allocate a mapping (%d)", r);
212
+ goto fail;
213
+ }
214
+
215
+ iova = mem_region.iova;
216
+ }
217
218
vhost_vdpa_iotlb_batch_begin_once(v);
219
ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize),
220
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
221
222
llsize = int128_sub(llend, int128_make64(iova));
223
224
+ if (v->shadow_vqs_enabled) {
225
+ const DMAMap *result;
226
+ const void *vaddr = memory_region_get_ram_ptr(section->mr) +
227
+ section->offset_within_region +
228
+ (iova - section->offset_within_address_space);
229
+ DMAMap mem_region = {
230
+ .translated_addr = (hwaddr)(uintptr_t)vaddr,
231
+ .size = int128_get64(llsize) - 1,
232
+ };
233
+
234
+ result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region);
235
+ iova = result->iova;
236
+ vhost_iova_tree_remove(v->iova_tree, &mem_region);
237
+ }
238
vhost_vdpa_iotlb_batch_begin_once(v);
239
ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize));
240
if (ret) {
241
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
242
243
shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
244
for (unsigned n = 0; n < hdev->nvqs; ++n) {
245
- g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();
246
+ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree);
247
248
if (unlikely(!svq)) {
249
error_setg(errp, "Cannot create svq %u", n);
250
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
251
/**
252
* Unmap a SVQ area in the device
253
*/
254
-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova,
255
- hwaddr size)
256
+static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
257
+ const DMAMap *needle)
258
{
259
+ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle);
260
+ hwaddr size;
261
int r;
262
263
- size = ROUND_UP(size, qemu_real_host_page_size);
264
- r = vhost_vdpa_dma_unmap(v, iova, size);
265
+ if (unlikely(!result)) {
266
+ error_report("Unable to find SVQ address to unmap");
267
+ return false;
268
+ }
269
+
270
+ size = ROUND_UP(result->size, qemu_real_host_page_size);
271
+ r = vhost_vdpa_dma_unmap(v, result->iova, size);
272
return r == 0;
273
}
274
275
static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
276
const VhostShadowVirtqueue *svq)
277
{
278
+ DMAMap needle = {};
279
struct vhost_vdpa *v = dev->opaque;
280
struct vhost_vring_addr svq_addr;
281
- size_t device_size = vhost_svq_device_area_size(svq);
282
- size_t driver_size = vhost_svq_driver_area_size(svq);
283
bool ok;
284
285
vhost_svq_get_vring_addr(svq, &svq_addr);
286
287
- ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size);
288
+ needle.translated_addr = svq_addr.desc_user_addr;
289
+ ok = vhost_vdpa_svq_unmap_ring(v, &needle);
290
if (unlikely(!ok)) {
291
return false;
80
}
292
}
81
293
82
virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
294
- return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size);
83
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
295
+ needle.translated_addr = svq_addr.used_user_addr;
84
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
296
+ return vhost_vdpa_svq_unmap_ring(v, &needle);
85
vdev->backend_features = features;
297
+}
86
298
+
87
@@ -XXX,XX +XXX,XX @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
299
+/**
88
virtio_has_feature(features,
300
+ * Map the SVQ area in the device
89
VIRTIO_NET_F_MRG_RXBUF),
301
+ *
90
virtio_has_feature(features,
302
+ * @v: Vhost-vdpa device
91
- VIRTIO_F_VERSION_1));
303
+ * @needle: The area to search iova
92
+ VIRTIO_F_VERSION_1),
304
+ * @errorp: Error pointer
93
+ virtio_has_feature(features,
305
+ */
94
+ VIRTIO_NET_F_HASH_REPORT));
306
+static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle,
95
307
+ Error **errp)
96
n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
308
+{
97
virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4);
309
+ int r;
98
n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
310
+
99
virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6);
311
+ r = vhost_iova_tree_map_alloc(v->iova_tree, needle);
100
+ n->rss_data.redirect = virtio_has_feature(features, VIRTIO_NET_F_RSS);
312
+ if (unlikely(r != IOVA_OK)) {
101
313
+ error_setg(errp, "Cannot allocate iova (%d)", r);
102
if (n->has_vnet_hdr) {
314
+ return false;
103
n->curr_guest_offloads =
315
+ }
104
@@ -XXX,XX +XXX,XX @@ static void virtio_net_disable_rss(VirtIONet *n)
316
+
317
+ r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1,
318
+ (void *)(uintptr_t)needle->translated_addr,
319
+ needle->perm == IOMMU_RO);
320
+ if (unlikely(r != 0)) {
321
+ error_setg_errno(errp, -r, "Cannot map region to device");
322
+ vhost_iova_tree_remove(v->iova_tree, needle);
323
+ }
324
+
325
+ return r == 0;
105
}
326
}
106
327
107
static uint16_t virtio_net_handle_rss(VirtIONet *n,
328
/**
108
- struct iovec *iov, unsigned int iov_cnt)
329
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
109
+ struct iovec *iov,
330
struct vhost_vring_addr *addr,
110
+ unsigned int iov_cnt,
331
Error **errp)
111
+ bool do_rss)
332
{
112
{
333
+ DMAMap device_region, driver_region;
113
VirtIODevice *vdev = VIRTIO_DEVICE(n);
334
+ struct vhost_vring_addr svq_addr;
114
struct virtio_net_rss_config cfg;
335
struct vhost_vdpa *v = dev->opaque;
115
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
336
size_t device_size = vhost_svq_device_area_size(svq);
116
const char *err_msg = "";
337
size_t driver_size = vhost_svq_driver_area_size(svq);
117
uint32_t err_value = 0;
338
- int r;
118
339
+ size_t avail_offset;
119
- if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {
340
+ bool ok;
120
+ if (do_rss && !virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {
341
121
err_msg = "RSS is not negotiated";
342
ERRP_GUARD();
122
goto error;
343
- vhost_svq_get_vring_addr(svq, addr);
344
+ vhost_svq_get_vring_addr(svq, &svq_addr);
345
346
- r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size,
347
- (void *)(uintptr_t)addr->desc_user_addr, true);
348
- if (unlikely(r != 0)) {
349
- error_setg_errno(errp, -r, "Cannot create vq driver region: ");
350
+ driver_region = (DMAMap) {
351
+ .translated_addr = svq_addr.desc_user_addr,
352
+ .size = driver_size - 1,
353
+ .perm = IOMMU_RO,
354
+ };
355
+ ok = vhost_vdpa_svq_map_ring(v, &driver_region, errp);
356
+ if (unlikely(!ok)) {
357
+ error_prepend(errp, "Cannot create vq driver region: ");
358
return false;
123
}
359
}
124
+ if (!do_rss && !virtio_vdev_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
360
+ addr->desc_user_addr = driver_region.iova;
125
+ err_msg = "Hash report is not negotiated";
361
+ avail_offset = svq_addr.avail_user_addr - svq_addr.desc_user_addr;
126
+ goto error;
362
+ addr->avail_user_addr = driver_region.iova + avail_offset;
127
+ }
363
128
size_get = offsetof(struct virtio_net_rss_config, indirection_table);
364
- r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size,
129
s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get);
365
- (void *)(intptr_t)addr->used_user_addr, false);
130
if (s != size_get) {
366
- if (unlikely(r != 0)) {
131
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
367
- error_setg_errno(errp, -r, "Cannot create vq device region: ");
132
n->rss_data.indirections_len =
368
+ device_region = (DMAMap) {
133
virtio_lduw_p(vdev, &cfg.indirection_table_mask);
369
+ .translated_addr = svq_addr.used_user_addr,
134
n->rss_data.indirections_len++;
370
+ .size = device_size - 1,
135
+ if (!do_rss) {
371
+ .perm = IOMMU_RW,
136
+ n->rss_data.indirections_len = 1;
372
+ };
137
+ }
373
+ ok = vhost_vdpa_svq_map_ring(v, &device_region, errp);
138
if (!is_power_of_2(n->rss_data.indirections_len)) {
374
+ if (unlikely(!ok)) {
139
err_msg = "Invalid size of indirection table";
375
+ error_prepend(errp, "Cannot create vq device region: ");
140
err_value = n->rss_data.indirections_len;
376
+ vhost_vdpa_svq_unmap_ring(v, &driver_region);
141
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
142
err_value = n->rss_data.indirections_len;
143
goto error;
144
}
377
}
145
- n->rss_data.default_queue =
378
+ addr->used_user_addr = device_region.iova;
146
- virtio_lduw_p(vdev, &cfg.unclassified_queue);
379
147
+ n->rss_data.default_queue = do_rss ?
380
- return r == 0;
148
+ virtio_lduw_p(vdev, &cfg.unclassified_queue) : 0;
381
+ return ok;
149
if (n->rss_data.default_queue >= n->max_queues) {
150
err_msg = "Invalid default queue";
151
err_value = n->rss_data.default_queue;
152
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
153
err_value = (uint32_t)s;
154
goto error;
155
}
156
- queues = virtio_lduw_p(vdev, &temp.us);
157
+ queues = do_rss ? virtio_lduw_p(vdev, &temp.us) : n->curr_queues;
158
if (queues == 0 || queues > n->max_queues) {
159
err_msg = "Invalid number of queues";
160
err_value = queues;
161
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
162
uint16_t queues;
163
164
virtio_net_disable_rss(n);
165
+ if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) {
166
+ queues = virtio_net_handle_rss(n, iov, iov_cnt, false);
167
+ return queues ? VIRTIO_NET_OK : VIRTIO_NET_ERR;
168
+ }
169
if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
170
- queues = virtio_net_handle_rss(n, iov, iov_cnt);
171
+ queues = virtio_net_handle_rss(n, iov, iov_cnt, true);
172
} else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
173
struct virtio_net_ctrl_mq mq;
174
size_t s;
175
@@ -XXX,XX +XXX,XX @@ static uint8_t virtio_net_get_hash_type(bool isip4,
176
return 0xff;
177
}
382
}
178
383
179
+static void virtio_set_packet_hash(const uint8_t *buf, uint8_t report,
384
static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
180
+ uint32_t hash)
385
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
181
+{
182
+ struct virtio_net_hdr_v1_hash *hdr = (void *)buf;
183
+ hdr->hash_value = hash;
184
+ hdr->hash_report = report;
185
+}
186
+
187
static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
188
size_t size)
189
{
190
VirtIONet *n = qemu_get_nic_opaque(nc);
191
- unsigned int index = nc->queue_index, new_index;
192
+ unsigned int index = nc->queue_index, new_index = index;
193
struct NetRxPkt *pkt = n->rx_pkt;
194
uint8_t net_hash_type;
195
uint32_t hash;
196
bool isip4, isip6, isudp, istcp;
197
+ static const uint8_t reports[NetPktRssIpV6UdpEx + 1] = {
198
+ VIRTIO_NET_HASH_REPORT_IPv4,
199
+ VIRTIO_NET_HASH_REPORT_TCPv4,
200
+ VIRTIO_NET_HASH_REPORT_TCPv6,
201
+ VIRTIO_NET_HASH_REPORT_IPv6,
202
+ VIRTIO_NET_HASH_REPORT_IPv6_EX,
203
+ VIRTIO_NET_HASH_REPORT_TCPv6_EX,
204
+ VIRTIO_NET_HASH_REPORT_UDPv4,
205
+ VIRTIO_NET_HASH_REPORT_UDPv6,
206
+ VIRTIO_NET_HASH_REPORT_UDPv6_EX
207
+ };
208
209
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
210
size - n->host_hdr_len);
211
@@ -XXX,XX +XXX,XX @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
212
net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp,
213
n->rss_data.hash_types);
214
if (net_hash_type > NetPktRssIpV6UdpEx) {
215
- return n->rss_data.default_queue;
216
+ if (n->rss_data.populate_hash) {
217
+ virtio_set_packet_hash(buf, VIRTIO_NET_HASH_REPORT_NONE, 0);
218
+ }
219
+ return n->rss_data.redirect ? n->rss_data.default_queue : -1;
220
}
221
222
hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key);
223
- new_index = hash & (n->rss_data.indirections_len - 1);
224
- new_index = n->rss_data.indirections_table[new_index];
225
- if (index == new_index) {
226
- return -1;
227
+
228
+ if (n->rss_data.populate_hash) {
229
+ virtio_set_packet_hash(buf, reports[net_hash_type], hash);
230
}
231
- return new_index;
232
+
233
+ if (n->rss_data.redirect) {
234
+ new_index = hash & (n->rss_data.indirections_len - 1);
235
+ new_index = n->rss_data.indirections_table[new_index];
236
+ }
237
+
238
+ return (index == new_index) ? -1 : new_index;
239
}
240
241
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
242
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
243
}
244
245
receive_header(n, sg, elem->in_num, buf, size);
246
+ if (n->rss_data.populate_hash) {
247
+ offset = sizeof(mhdr);
248
+ iov_from_buf(sg, elem->in_num, offset,
249
+ buf + offset, n->host_hdr_len - sizeof(mhdr));
250
+ }
251
offset = n->host_hdr_len;
252
total += n->guest_hdr_len;
253
guest_offset = n->guest_hdr_len;
254
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
255
trace_virtio_net_post_load_device();
256
virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs,
257
virtio_vdev_has_feature(vdev,
258
- VIRTIO_F_VERSION_1));
259
+ VIRTIO_F_VERSION_1),
260
+ virtio_vdev_has_feature(vdev,
261
+ VIRTIO_NET_F_HASH_REPORT));
262
263
/* MAC_TABLE_ENTRIES may be different from the saved image */
264
if (n->mac_table.in_use > MAC_TABLE_ENTRIES) {
265
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
266
267
n->vqs[0].tx_waiting = 0;
268
n->tx_burst = n->net_conf.txburst;
269
- virtio_net_set_mrg_rx_bufs(n, 0, 0);
270
+ virtio_net_set_mrg_rx_bufs(n, 0, 0, 0);
271
n->promisc = 1; /* for compatibility */
272
273
n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
274
@@ -XXX,XX +XXX,XX @@ static Property virtio_net_properties[] = {
275
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
276
DEFINE_PROP_BIT64("rss", VirtIONet, host_features,
277
VIRTIO_NET_F_RSS, false),
278
+ DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
279
+ VIRTIO_NET_F_HASH_REPORT, false),
280
DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
281
VIRTIO_NET_F_RSC_EXT, false),
282
DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
283
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
284
index XXXXXXX..XXXXXXX 100644
386
index XXXXXXX..XXXXXXX 100644
285
--- a/include/hw/virtio/virtio-net.h
387
--- a/include/hw/virtio/vhost-vdpa.h
286
+++ b/include/hw/virtio/virtio-net.h
388
+++ b/include/hw/virtio/vhost-vdpa.h
287
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
389
@@ -XXX,XX +XXX,XX @@
288
390
289
typedef struct VirtioNetRssData {
391
#include <gmodule.h>
290
bool enabled;
392
291
+ bool redirect;
393
+#include "hw/virtio/vhost-iova-tree.h"
292
+ bool populate_hash;
394
#include "hw/virtio/virtio.h"
293
uint32_t hash_types;
395
#include "standard-headers/linux/vhost_types.h"
294
uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
396
295
uint16_t indirections_len;
397
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
398
MemoryListener listener;
399
struct vhost_vdpa_iova_range iova_range;
400
bool shadow_vqs_enabled;
401
+ /* IOVA mapping used by the Shadow Virtqueue */
402
+ VhostIOVATree *iova_tree;
403
GPtrArray *shadow_vqs;
404
struct vhost_dev *dev;
405
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
296
--
406
--
297
2.5.0
407
2.7.4
298
408
299
409
diff view generated by jsdifflib
Deleted patch
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
1
3
Removal of duplicated RSC definitions. Changing names of the
4
fields to ones defined in the Linux header.
5
6
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/virtio-net.c | 28 ++++------------------------
10
1 file changed, 4 insertions(+), 24 deletions(-)
11
12
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/virtio-net.c
15
+++ b/hw/net/virtio-net.c
16
@@ -XXX,XX +XXX,XX @@
17
VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
18
VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
19
20
-/* temporary until standard header include it */
21
-#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
22
-
23
-#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */
24
-#define VIRTIO_NET_F_RSC_EXT 61
25
-
26
-#endif
27
-
28
-static inline __virtio16 *virtio_net_rsc_ext_num_packets(
29
- struct virtio_net_hdr *hdr)
30
-{
31
- return &hdr->csum_start;
32
-}
33
-
34
-static inline __virtio16 *virtio_net_rsc_ext_num_dupacks(
35
- struct virtio_net_hdr *hdr)
36
-{
37
- return &hdr->csum_offset;
38
-}
39
-
40
static VirtIOFeature feature_sizes[] = {
41
{.flags = 1ULL << VIRTIO_NET_F_MAC,
42
.end = endof(struct virtio_net_config, mac)},
43
@@ -XXX,XX +XXX,XX @@ static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain,
44
VirtioNetRscSeg *seg)
45
{
46
int ret;
47
- struct virtio_net_hdr *h;
48
+ struct virtio_net_hdr_v1 *h;
49
50
- h = (struct virtio_net_hdr *)seg->buf;
51
+ h = (struct virtio_net_hdr_v1 *)seg->buf;
52
h->flags = 0;
53
h->gso_type = VIRTIO_NET_HDR_GSO_NONE;
54
55
if (seg->is_coalesced) {
56
- *virtio_net_rsc_ext_num_packets(h) = seg->packets;
57
- *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack;
58
+ h->rsc.segments = seg->packets;
59
+ h->rsc.dup_acks = seg->dup_ack;
60
h->flags = VIRTIO_NET_HDR_F_RSC_INFO;
61
if (chain->proto == ETH_P_IP) {
62
h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
63
--
64
2.5.0
65
66
diff view generated by jsdifflib
Deleted patch
1
From: Helge Deller <deller@gmx.de>
2
1
3
The tulip network driver in a qemu-system-hppa emulation is broken in
4
the sense that bigger network packages aren't received any longer and
5
thus even running e.g. "apt update" inside the VM fails.
6
7
The breakage was introduced by commit 8ffb7265af ("check frame size and
8
r/w data length") which added checks to prevent accesses outside of the
9
rx/tx buffers.
10
11
But the new checks were implemented wrong. The variable rx_frame_len
12
counts backwards, from rx_frame_size down to zero, and the variable len
13
is never bigger than rx_frame_len, so accesses just can't happen and the
14
checks are unnecessary.
15
On the contrary the checks now prevented bigger packages to be moved
16
into the rx buffers.
17
18
This patch reverts the wrong checks and were sucessfully tested with a
19
qemu-system-hppa emulation.
20
21
Fixes: 8ffb7265af ("check frame size and r/w data length")
22
Buglink: https://bugs.launchpad.net/bugs/1874539
23
Signed-off-by: Helge Deller <deller@gmx.de>
24
Signed-off-by: Jason Wang <jasowang@redhat.com>
25
---
26
hw/net/tulip.c | 6 ------
27
1 file changed, 6 deletions(-)
28
29
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/hw/net/tulip.c
32
+++ b/hw/net/tulip.c
33
@@ -XXX,XX +XXX,XX @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
34
len = s->rx_frame_len;
35
}
36
37
- if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
38
- return;
39
- }
40
pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
41
(s->rx_frame_size - s->rx_frame_len), len);
42
s->rx_frame_len -= len;
43
@@ -XXX,XX +XXX,XX @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
44
len = s->rx_frame_len;
45
}
46
47
- if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
48
- return;
49
- }
50
pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
51
(s->rx_frame_size - s->rx_frame_len), len);
52
s->rx_frame_len -= len;
53
--
54
2.5.0
55
56
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
Bit #14 is "DE" for 'Descriptor Error':
4
5
When set, indicates a frame truncation caused by a frame
6
that does not fit within the current descriptor buffers,
7
and that the 21143 does not own the next descriptor.
8
9
[Table 4-1. RDES0 Bit Fields Description]
10
11
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
hw/net/tulip.h | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/hw/net/tulip.h b/hw/net/tulip.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/net/tulip.h
20
+++ b/hw/net/tulip.h
21
@@ -XXX,XX +XXX,XX @@
22
#define RDES0_RF BIT(11)
23
#define RDES0_DT_SHIFT 12
24
#define RDES0_DT_MASK 3
25
-#define RDES0_LE BIT(14)
26
+#define RDES0_DE BIT(14)
27
#define RDES0_ES BIT(15)
28
#define RDES0_FL_SHIFT 16
29
#define RDES0_FL_MASK 0x3fff
30
--
31
2.5.0
32
33
diff view generated by jsdifflib
Deleted patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
1
3
Log with GUEST_ERROR what the guest is doing wrong.
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
8
hw/net/tulip.c | 6 ++++++
9
1 file changed, 6 insertions(+)
10
11
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/net/tulip.c
14
+++ b/hw/net/tulip.c
15
@@ -XXX,XX +XXX,XX @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
16
int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
17
18
if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) {
19
+ qemu_log_mask(LOG_GUEST_ERROR,
20
+ "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
21
+ __func__, s->tx_frame_len, len1, sizeof(s->tx_frame));
22
return -1;
23
}
24
if (len1) {
25
@@ -XXX,XX +XXX,XX @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
26
}
27
28
if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) {
29
+ qemu_log_mask(LOG_GUEST_ERROR,
30
+ "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
31
+ __func__, s->tx_frame_len, len2, sizeof(s->tx_frame));
32
return -1;
33
}
34
if (len2) {
35
--
36
2.5.0
37
38
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Enabling debug breaks the build, Fix them and make debug statements
4
always compilable. Fix few statements to use sized integer casting.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 27 +++++++++++++--------------
11
1 file changed, 13 insertions(+), 14 deletions(-)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@
18
#include "sysemu/dma.h"
19
#include "net/checksum.h"
20
21
-#ifdef CADENCE_GEM_ERR_DEBUG
22
-#define DB_PRINT(...) do { \
23
- fprintf(stderr, ": %s: ", __func__); \
24
- fprintf(stderr, ## __VA_ARGS__); \
25
- } while (0)
26
-#else
27
- #define DB_PRINT(...)
28
-#endif
29
+#define CADENCE_GEM_ERR_DEBUG 0
30
+#define DB_PRINT(...) do {\
31
+ if (CADENCE_GEM_ERR_DEBUG) { \
32
+ qemu_log(": %s: ", __func__); \
33
+ qemu_log(__VA_ARGS__); \
34
+ } \
35
+} while (0)
36
37
#define GEM_NWCTRL (0x00000000/4) /* Network Control reg */
38
#define GEM_NWCFG (0x00000004/4) /* Network Config reg */
39
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
40
size += 4;
41
}
42
43
- DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
44
+ DB_PRINT("config bufsize: %u packet size: %zd\n", rxbufsize, size);
45
46
/* Find which queue we are targeting */
47
q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
48
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
49
return -1;
50
}
51
52
- DB_PRINT("copy %u bytes to 0x%" PRIx64 "\n",
53
- MIN(bytes_to_copy, rxbufsize),
54
- rx_desc_get_buffer(s, s->rx_desc[q]));
55
+ DB_PRINT("copy %" PRIu32 " bytes to 0x%" PRIx64 "\n",
56
+ MIN(bytes_to_copy, rxbufsize),
57
+ rx_desc_get_buffer(s, s->rx_desc[q]));
58
59
/* Copy packet data to emulated DMA buffer */
60
address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) +
61
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
62
*/
63
if ((tx_desc_get_buffer(s, desc) == 0) ||
64
(tx_desc_get_length(desc) == 0)) {
65
- DB_PRINT("Invalid TX descriptor @ 0x%x\n",
66
- (unsigned)packet_desc_addr);
67
+ DB_PRINT("Invalid TX descriptor @ 0x%" HWADDR_PRIx "\n",
68
+ packet_desc_addr);
69
break;
70
}
71
72
--
73
2.5.0
74
75
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Set irq's specific to a queue, present implementation is setting q1 irq
4
based on q0 status.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 25 +++----------------------
11
1 file changed, 3 insertions(+), 22 deletions(-)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@ static void gem_update_int_status(CadenceGEMState *s)
18
{
19
int i;
20
21
- if (!s->regs[GEM_ISR]) {
22
- /* ISR isn't set, clear all the interrupts */
23
- for (i = 0; i < s->num_priority_queues; ++i) {
24
- qemu_set_irq(s->irq[i], 0);
25
- }
26
- return;
27
- }
28
+ qemu_set_irq(s->irq[0], !!s->regs[GEM_ISR]);
29
30
- /* If we get here we know s->regs[GEM_ISR] is set, so we don't need to
31
- * check it again.
32
- */
33
- if (s->num_priority_queues == 1) {
34
- /* No priority queues, just trigger the interrupt */
35
- DB_PRINT("asserting int.\n");
36
- qemu_set_irq(s->irq[0], 1);
37
- return;
38
- }
39
-
40
- for (i = 0; i < s->num_priority_queues; ++i) {
41
- if (s->regs[GEM_INT_Q1_STATUS + i]) {
42
- DB_PRINT("asserting int. (q=%d)\n", i);
43
- qemu_set_irq(s->irq[i], 1);
44
- }
45
+ for (i = 1; i < s->num_priority_queues; ++i) {
46
+ qemu_set_irq(s->irq[i], !!s->regs[GEM_INT_Q1_STATUS + i - 1]);
47
}
48
}
49
50
--
51
2.5.0
52
53
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Q1 to Q7 ISR's are clear-on-read, IER/IDR registers
4
are write-only, mask reg are read-only.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 14 ++++++++++++++
11
1 file changed, 14 insertions(+)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
18
*/
19
static void gem_init_register_masks(CadenceGEMState *s)
20
{
21
+ unsigned int i;
22
/* Mask of register bits which are read only */
23
memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
24
s->regs_ro[GEM_NWCTRL] = 0xFFF80000;
25
@@ -XXX,XX +XXX,XX @@ static void gem_init_register_masks(CadenceGEMState *s)
26
s->regs_ro[GEM_ISR] = 0xFFFFFFFF;
27
s->regs_ro[GEM_IMR] = 0xFFFFFFFF;
28
s->regs_ro[GEM_MODID] = 0xFFFFFFFF;
29
+ for (i = 0; i < s->num_priority_queues; i++) {
30
+ s->regs_ro[GEM_INT_Q1_STATUS + i] = 0xFFFFFFFF;
31
+ s->regs_ro[GEM_INT_Q1_ENABLE + i] = 0xFFFFF319;
32
+ s->regs_ro[GEM_INT_Q1_DISABLE + i] = 0xFFFFF319;
33
+ s->regs_ro[GEM_INT_Q1_MASK + i] = 0xFFFFFFFF;
34
+ }
35
36
/* Mask of register bits which are clear on read */
37
memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc));
38
s->regs_rtc[GEM_ISR] = 0xFFFFFFFF;
39
+ for (i = 0; i < s->num_priority_queues; i++) {
40
+ s->regs_rtc[GEM_INT_Q1_STATUS + i] = 0x00000CE6;
41
+ }
42
43
/* Mask of register bits which are write 1 to clear */
44
memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c));
45
@@ -XXX,XX +XXX,XX @@ static void gem_init_register_masks(CadenceGEMState *s)
46
s->regs_wo[GEM_NWCTRL] = 0x00073E60;
47
s->regs_wo[GEM_IER] = 0x07FFFFFF;
48
s->regs_wo[GEM_IDR] = 0x07FFFFFF;
49
+ for (i = 0; i < s->num_priority_queues; i++) {
50
+ s->regs_wo[GEM_INT_Q1_ENABLE + i] = 0x00000CE6;
51
+ s->regs_wo[GEM_INT_Q1_DISABLE + i] = 0x00000CE6;
52
+ }
53
}
54
55
/*
56
--
57
2.5.0
58
59
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Moving this buffers to CadenceGEMState, as their size will be increased
4
more when JUMBO frames support is added.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 38 +++++++++++++++++---------------------
11
include/hw/net/cadence_gem.h | 4 ++++
12
2 files changed, 21 insertions(+), 21 deletions(-)
13
14
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/cadence_gem.c
17
+++ b/hw/net/cadence_gem.c
18
@@ -XXX,XX +XXX,XX @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
19
*/
20
static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
21
{
22
- CadenceGEMState *s;
23
+ CadenceGEMState *s = qemu_get_nic_opaque(nc);
24
unsigned rxbufsize, bytes_to_copy;
25
unsigned rxbuf_offset;
26
- uint8_t rxbuf[2048];
27
uint8_t *rxbuf_ptr;
28
bool first_desc = true;
29
int maf;
30
int q = 0;
31
32
- s = qemu_get_nic_opaque(nc);
33
-
34
/* Is this destination MAC address "for us" ? */
35
maf = gem_mac_address_filter(s, buf);
36
if (maf == GEM_RX_REJECT) {
37
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
38
} else {
39
unsigned crc_val;
40
41
- if (size > sizeof(rxbuf) - sizeof(crc_val)) {
42
- size = sizeof(rxbuf) - sizeof(crc_val);
43
+ if (size > MAX_FRAME_SIZE - sizeof(crc_val)) {
44
+ size = MAX_FRAME_SIZE - sizeof(crc_val);
45
}
46
bytes_to_copy = size;
47
/* The application wants the FCS field, which QEMU does not provide.
48
* We must try and calculate one.
49
*/
50
51
- memcpy(rxbuf, buf, size);
52
- memset(rxbuf + size, 0, sizeof(rxbuf) - size);
53
- rxbuf_ptr = rxbuf;
54
- crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
55
- memcpy(rxbuf + size, &crc_val, sizeof(crc_val));
56
+ memcpy(s->rx_packet, buf, size);
57
+ memset(s->rx_packet + size, 0, MAX_FRAME_SIZE - size);
58
+ rxbuf_ptr = s->rx_packet;
59
+ crc_val = cpu_to_le32(crc32(0, s->rx_packet, MAX(size, 60)));
60
+ memcpy(s->rx_packet + size, &crc_val, sizeof(crc_val));
61
62
bytes_to_copy += 4;
63
size += 4;
64
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
65
{
66
uint32_t desc[DESC_MAX_NUM_WORDS];
67
hwaddr packet_desc_addr;
68
- uint8_t tx_packet[2048];
69
uint8_t *p;
70
unsigned total_bytes;
71
int q = 0;
72
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
73
* Packets scattered across multiple descriptors are gathered to this
74
* one contiguous buffer first.
75
*/
76
- p = tx_packet;
77
+ p = s->tx_packet;
78
total_bytes = 0;
79
80
for (q = s->num_priority_queues - 1; q >= 0; q--) {
81
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
82
break;
83
}
84
85
- if (tx_desc_get_length(desc) > sizeof(tx_packet) -
86
- (p - tx_packet)) {
87
+ if (tx_desc_get_length(desc) > MAX_FRAME_SIZE -
88
+ (p - s->tx_packet)) {
89
DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \
90
" too large: size 0x%x space 0x%zx\n",
91
packet_desc_addr, tx_desc_get_length(desc),
92
- sizeof(tx_packet) - (p - tx_packet));
93
+ MAX_FRAME_SIZE - (p - s->tx_packet));
94
break;
95
}
96
97
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
98
99
/* Is checksum offload enabled? */
100
if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) {
101
- net_checksum_calculate(tx_packet, total_bytes);
102
+ net_checksum_calculate(s->tx_packet, total_bytes);
103
}
104
105
/* Update MAC statistics */
106
- gem_transmit_updatestats(s, tx_packet, total_bytes);
107
+ gem_transmit_updatestats(s, s->tx_packet, total_bytes);
108
109
/* Send the packet somewhere */
110
if (s->phy_loop || (s->regs[GEM_NWCTRL] &
111
GEM_NWCTRL_LOCALLOOP)) {
112
- gem_receive(qemu_get_queue(s->nic), tx_packet,
113
+ gem_receive(qemu_get_queue(s->nic), s->tx_packet,
114
total_bytes);
115
} else {
116
- qemu_send_packet(qemu_get_queue(s->nic), tx_packet,
117
+ qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet,
118
total_bytes);
119
}
120
121
/* Prepare for next packet */
122
- p = tx_packet;
123
+ p = s->tx_packet;
124
total_bytes = 0;
125
}
126
127
diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h
128
index XXXXXXX..XXXXXXX 100644
129
--- a/include/hw/net/cadence_gem.h
130
+++ b/include/hw/net/cadence_gem.h
131
@@ -XXX,XX +XXX,XX @@
132
#define MAX_TYPE1_SCREENERS 16
133
#define MAX_TYPE2_SCREENERS 16
134
135
+#define MAX_FRAME_SIZE 2048
136
+
137
typedef struct CadenceGEMState {
138
/*< private >*/
139
SysBusDevice parent_obj;
140
@@ -XXX,XX +XXX,XX @@ typedef struct CadenceGEMState {
141
142
uint8_t can_rx_state; /* Debug only */
143
144
+ uint8_t tx_packet[MAX_FRAME_SIZE];
145
+ uint8_t rx_packet[MAX_FRAME_SIZE];
146
uint32_t rx_desc[MAX_PRIORITY_QUEUES][DESC_MAX_NUM_WORDS];
147
148
bool sar_active[4];
149
--
150
2.5.0
151
152
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Fix the code style for register definitions.
4
5
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/cadence_gem.c | 204 ++++++++++++++++++++++++++-------------------------
10
1 file changed, 103 insertions(+), 101 deletions(-)
11
12
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/cadence_gem.c
15
+++ b/hw/net/cadence_gem.c
16
@@ -XXX,XX +XXX,XX @@
17
} \
18
} while (0)
19
20
-#define GEM_NWCTRL (0x00000000/4) /* Network Control reg */
21
-#define GEM_NWCFG (0x00000004/4) /* Network Config reg */
22
-#define GEM_NWSTATUS (0x00000008/4) /* Network Status reg */
23
-#define GEM_USERIO (0x0000000C/4) /* User IO reg */
24
-#define GEM_DMACFG (0x00000010/4) /* DMA Control reg */
25
-#define GEM_TXSTATUS (0x00000014/4) /* TX Status reg */
26
-#define GEM_RXQBASE (0x00000018/4) /* RX Q Base address reg */
27
-#define GEM_TXQBASE (0x0000001C/4) /* TX Q Base address reg */
28
-#define GEM_RXSTATUS (0x00000020/4) /* RX Status reg */
29
-#define GEM_ISR (0x00000024/4) /* Interrupt Status reg */
30
-#define GEM_IER (0x00000028/4) /* Interrupt Enable reg */
31
-#define GEM_IDR (0x0000002C/4) /* Interrupt Disable reg */
32
-#define GEM_IMR (0x00000030/4) /* Interrupt Mask reg */
33
-#define GEM_PHYMNTNC (0x00000034/4) /* Phy Maintenance reg */
34
-#define GEM_RXPAUSE (0x00000038/4) /* RX Pause Time reg */
35
-#define GEM_TXPAUSE (0x0000003C/4) /* TX Pause Time reg */
36
-#define GEM_TXPARTIALSF (0x00000040/4) /* TX Partial Store and Forward */
37
-#define GEM_RXPARTIALSF (0x00000044/4) /* RX Partial Store and Forward */
38
-#define GEM_HASHLO (0x00000080/4) /* Hash Low address reg */
39
-#define GEM_HASHHI (0x00000084/4) /* Hash High address reg */
40
-#define GEM_SPADDR1LO (0x00000088/4) /* Specific addr 1 low reg */
41
-#define GEM_SPADDR1HI (0x0000008C/4) /* Specific addr 1 high reg */
42
-#define GEM_SPADDR2LO (0x00000090/4) /* Specific addr 2 low reg */
43
-#define GEM_SPADDR2HI (0x00000094/4) /* Specific addr 2 high reg */
44
-#define GEM_SPADDR3LO (0x00000098/4) /* Specific addr 3 low reg */
45
-#define GEM_SPADDR3HI (0x0000009C/4) /* Specific addr 3 high reg */
46
-#define GEM_SPADDR4LO (0x000000A0/4) /* Specific addr 4 low reg */
47
-#define GEM_SPADDR4HI (0x000000A4/4) /* Specific addr 4 high reg */
48
-#define GEM_TIDMATCH1 (0x000000A8/4) /* Type ID1 Match reg */
49
-#define GEM_TIDMATCH2 (0x000000AC/4) /* Type ID2 Match reg */
50
-#define GEM_TIDMATCH3 (0x000000B0/4) /* Type ID3 Match reg */
51
-#define GEM_TIDMATCH4 (0x000000B4/4) /* Type ID4 Match reg */
52
-#define GEM_WOLAN (0x000000B8/4) /* Wake on LAN reg */
53
-#define GEM_IPGSTRETCH (0x000000BC/4) /* IPG Stretch reg */
54
-#define GEM_SVLAN (0x000000C0/4) /* Stacked VLAN reg */
55
-#define GEM_MODID (0x000000FC/4) /* Module ID reg */
56
-#define GEM_OCTTXLO (0x00000100/4) /* Octects transmitted Low reg */
57
-#define GEM_OCTTXHI (0x00000104/4) /* Octects transmitted High reg */
58
-#define GEM_TXCNT (0x00000108/4) /* Error-free Frames transmitted */
59
-#define GEM_TXBCNT (0x0000010C/4) /* Error-free Broadcast Frames */
60
-#define GEM_TXMCNT (0x00000110/4) /* Error-free Multicast Frame */
61
-#define GEM_TXPAUSECNT (0x00000114/4) /* Pause Frames Transmitted */
62
-#define GEM_TX64CNT (0x00000118/4) /* Error-free 64 TX */
63
-#define GEM_TX65CNT (0x0000011C/4) /* Error-free 65-127 TX */
64
-#define GEM_TX128CNT (0x00000120/4) /* Error-free 128-255 TX */
65
-#define GEM_TX256CNT (0x00000124/4) /* Error-free 256-511 */
66
-#define GEM_TX512CNT (0x00000128/4) /* Error-free 512-1023 TX */
67
-#define GEM_TX1024CNT (0x0000012C/4) /* Error-free 1024-1518 TX */
68
-#define GEM_TX1519CNT (0x00000130/4) /* Error-free larger than 1519 TX */
69
-#define GEM_TXURUNCNT (0x00000134/4) /* TX under run error counter */
70
-#define GEM_SINGLECOLLCNT (0x00000138/4) /* Single Collision Frames */
71
-#define GEM_MULTCOLLCNT (0x0000013C/4) /* Multiple Collision Frames */
72
-#define GEM_EXCESSCOLLCNT (0x00000140/4) /* Excessive Collision Frames */
73
-#define GEM_LATECOLLCNT (0x00000144/4) /* Late Collision Frames */
74
-#define GEM_DEFERTXCNT (0x00000148/4) /* Deferred Transmission Frames */
75
-#define GEM_CSENSECNT (0x0000014C/4) /* Carrier Sense Error Counter */
76
-#define GEM_OCTRXLO (0x00000150/4) /* Octects Received register Low */
77
-#define GEM_OCTRXHI (0x00000154/4) /* Octects Received register High */
78
-#define GEM_RXCNT (0x00000158/4) /* Error-free Frames Received */
79
-#define GEM_RXBROADCNT (0x0000015C/4) /* Error-free Broadcast Frames RX */
80
-#define GEM_RXMULTICNT (0x00000160/4) /* Error-free Multicast Frames RX */
81
-#define GEM_RXPAUSECNT (0x00000164/4) /* Pause Frames Received Counter */
82
-#define GEM_RX64CNT (0x00000168/4) /* Error-free 64 byte Frames RX */
83
-#define GEM_RX65CNT (0x0000016C/4) /* Error-free 65-127B Frames RX */
84
-#define GEM_RX128CNT (0x00000170/4) /* Error-free 128-255B Frames RX */
85
-#define GEM_RX256CNT (0x00000174/4) /* Error-free 256-512B Frames RX */
86
-#define GEM_RX512CNT (0x00000178/4) /* Error-free 512-1023B Frames RX */
87
-#define GEM_RX1024CNT (0x0000017C/4) /* Error-free 1024-1518B Frames RX */
88
-#define GEM_RX1519CNT (0x00000180/4) /* Error-free 1519-max Frames RX */
89
-#define GEM_RXUNDERCNT (0x00000184/4) /* Undersize Frames Received */
90
-#define GEM_RXOVERCNT (0x00000188/4) /* Oversize Frames Received */
91
-#define GEM_RXJABCNT (0x0000018C/4) /* Jabbers Received Counter */
92
-#define GEM_RXFCSCNT (0x00000190/4) /* Frame Check seq. Error Counter */
93
-#define GEM_RXLENERRCNT (0x00000194/4) /* Length Field Error Counter */
94
-#define GEM_RXSYMERRCNT (0x00000198/4) /* Symbol Error Counter */
95
-#define GEM_RXALIGNERRCNT (0x0000019C/4) /* Alignment Error Counter */
96
-#define GEM_RXRSCERRCNT (0x000001A0/4) /* Receive Resource Error Counter */
97
-#define GEM_RXORUNCNT (0x000001A4/4) /* Receive Overrun Counter */
98
-#define GEM_RXIPCSERRCNT (0x000001A8/4) /* IP header Checksum Error Counter */
99
-#define GEM_RXTCPCCNT (0x000001AC/4) /* TCP Checksum Error Counter */
100
-#define GEM_RXUDPCCNT (0x000001B0/4) /* UDP Checksum Error Counter */
101
-
102
-#define GEM_1588S (0x000001D0/4) /* 1588 Timer Seconds */
103
-#define GEM_1588NS (0x000001D4/4) /* 1588 Timer Nanoseconds */
104
-#define GEM_1588ADJ (0x000001D8/4) /* 1588 Timer Adjust */
105
-#define GEM_1588INC (0x000001DC/4) /* 1588 Timer Increment */
106
-#define GEM_PTPETXS (0x000001E0/4) /* PTP Event Frame Transmitted (s) */
107
-#define GEM_PTPETXNS (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */
108
-#define GEM_PTPERXS (0x000001E8/4) /* PTP Event Frame Received (s) */
109
-#define GEM_PTPERXNS (0x000001EC/4) /* PTP Event Frame Received (ns) */
110
-#define GEM_PTPPTXS (0x000001E0/4) /* PTP Peer Frame Transmitted (s) */
111
-#define GEM_PTPPTXNS (0x000001E4/4) /* PTP Peer Frame Transmitted (ns) */
112
-#define GEM_PTPPRXS (0x000001E8/4) /* PTP Peer Frame Received (s) */
113
-#define GEM_PTPPRXNS (0x000001EC/4) /* PTP Peer Frame Received (ns) */
114
+#define GEM_NWCTRL (0x00000000 / 4) /* Network Control reg */
115
+#define GEM_NWCFG (0x00000004 / 4) /* Network Config reg */
116
+#define GEM_NWSTATUS (0x00000008 / 4) /* Network Status reg */
117
+#define GEM_USERIO (0x0000000C / 4) /* User IO reg */
118
+#define GEM_DMACFG (0x00000010 / 4) /* DMA Control reg */
119
+#define GEM_TXSTATUS (0x00000014 / 4) /* TX Status reg */
120
+#define GEM_RXQBASE (0x00000018 / 4) /* RX Q Base address reg */
121
+#define GEM_TXQBASE (0x0000001C / 4) /* TX Q Base address reg */
122
+#define GEM_RXSTATUS (0x00000020 / 4) /* RX Status reg */
123
+#define GEM_ISR (0x00000024 / 4) /* Interrupt Status reg */
124
+#define GEM_IER (0x00000028 / 4) /* Interrupt Enable reg */
125
+#define GEM_IDR (0x0000002C / 4) /* Interrupt Disable reg */
126
+#define GEM_IMR (0x00000030 / 4) /* Interrupt Mask reg */
127
+#define GEM_PHYMNTNC (0x00000034 / 4) /* Phy Maintenance reg */
128
+#define GEM_RXPAUSE (0x00000038 / 4) /* RX Pause Time reg */
129
+#define GEM_TXPAUSE (0x0000003C / 4) /* TX Pause Time reg */
130
+#define GEM_TXPARTIALSF (0x00000040 / 4) /* TX Partial Store and Forward */
131
+#define GEM_RXPARTIALSF (0x00000044 / 4) /* RX Partial Store and Forward */
132
+#define GEM_HASHLO (0x00000080 / 4) /* Hash Low address reg */
133
+#define GEM_HASHHI (0x00000084 / 4) /* Hash High address reg */
134
+#define GEM_SPADDR1LO (0x00000088 / 4) /* Specific addr 1 low reg */
135
+#define GEM_SPADDR1HI (0x0000008C / 4) /* Specific addr 1 high reg */
136
+#define GEM_SPADDR2LO (0x00000090 / 4) /* Specific addr 2 low reg */
137
+#define GEM_SPADDR2HI (0x00000094 / 4) /* Specific addr 2 high reg */
138
+#define GEM_SPADDR3LO (0x00000098 / 4) /* Specific addr 3 low reg */
139
+#define GEM_SPADDR3HI (0x0000009C / 4) /* Specific addr 3 high reg */
140
+#define GEM_SPADDR4LO (0x000000A0 / 4) /* Specific addr 4 low reg */
141
+#define GEM_SPADDR4HI (0x000000A4 / 4) /* Specific addr 4 high reg */
142
+#define GEM_TIDMATCH1 (0x000000A8 / 4) /* Type ID1 Match reg */
143
+#define GEM_TIDMATCH2 (0x000000AC / 4) /* Type ID2 Match reg */
144
+#define GEM_TIDMATCH3 (0x000000B0 / 4) /* Type ID3 Match reg */
145
+#define GEM_TIDMATCH4 (0x000000B4 / 4) /* Type ID4 Match reg */
146
+#define GEM_WOLAN (0x000000B8 / 4) /* Wake on LAN reg */
147
+#define GEM_IPGSTRETCH (0x000000BC / 4) /* IPG Stretch reg */
148
+#define GEM_SVLAN (0x000000C0 / 4) /* Stacked VLAN reg */
149
+#define GEM_MODID (0x000000FC / 4) /* Module ID reg */
150
+#define GEM_OCTTXLO (0x00000100 / 4) /* Octects transmitted Low reg */
151
+#define GEM_OCTTXHI (0x00000104 / 4) /* Octects transmitted High reg */
152
+#define GEM_TXCNT (0x00000108 / 4) /* Error-free Frames transmitted */
153
+#define GEM_TXBCNT (0x0000010C / 4) /* Error-free Broadcast Frames */
154
+#define GEM_TXMCNT (0x00000110 / 4) /* Error-free Multicast Frame */
155
+#define GEM_TXPAUSECNT (0x00000114 / 4) /* Pause Frames Transmitted */
156
+#define GEM_TX64CNT (0x00000118 / 4) /* Error-free 64 TX */
157
+#define GEM_TX65CNT (0x0000011C / 4) /* Error-free 65-127 TX */
158
+#define GEM_TX128CNT (0x00000120 / 4) /* Error-free 128-255 TX */
159
+#define GEM_TX256CNT (0x00000124 / 4) /* Error-free 256-511 */
160
+#define GEM_TX512CNT (0x00000128 / 4) /* Error-free 512-1023 TX */
161
+#define GEM_TX1024CNT (0x0000012C / 4) /* Error-free 1024-1518 TX */
162
+#define GEM_TX1519CNT (0x00000130 / 4) /* Error-free larger than 1519 TX */
163
+#define GEM_TXURUNCNT (0x00000134 / 4) /* TX under run error counter */
164
+#define GEM_SINGLECOLLCNT (0x00000138 / 4) /* Single Collision Frames */
165
+#define GEM_MULTCOLLCNT (0x0000013C / 4) /* Multiple Collision Frames */
166
+#define GEM_EXCESSCOLLCNT (0x00000140 / 4) /* Excessive Collision Frames */
167
+#define GEM_LATECOLLCNT (0x00000144 / 4) /* Late Collision Frames */
168
+#define GEM_DEFERTXCNT (0x00000148 / 4) /* Deferred Transmission Frames */
169
+#define GEM_CSENSECNT (0x0000014C / 4) /* Carrier Sense Error Counter */
170
+#define GEM_OCTRXLO (0x00000150 / 4) /* Octects Received register Low */
171
+#define GEM_OCTRXHI (0x00000154 / 4) /* Octects Received register High */
172
+#define GEM_RXCNT (0x00000158 / 4) /* Error-free Frames Received */
173
+#define GEM_RXBROADCNT (0x0000015C / 4) /* Error-free Broadcast Frames RX */
174
+#define GEM_RXMULTICNT (0x00000160 / 4) /* Error-free Multicast Frames RX */
175
+#define GEM_RXPAUSECNT (0x00000164 / 4) /* Pause Frames Received Counter */
176
+#define GEM_RX64CNT (0x00000168 / 4) /* Error-free 64 byte Frames RX */
177
+#define GEM_RX65CNT (0x0000016C / 4) /* Error-free 65-127B Frames RX */
178
+#define GEM_RX128CNT (0x00000170 / 4) /* Error-free 128-255B Frames RX */
179
+#define GEM_RX256CNT (0x00000174 / 4) /* Error-free 256-512B Frames RX */
180
+#define GEM_RX512CNT (0x00000178 / 4) /* Error-free 512-1023B Frames RX */
181
+#define GEM_RX1024CNT (0x0000017C / 4) /* Error-free 1024-1518B Frames RX */
182
+#define GEM_RX1519CNT (0x00000180 / 4) /* Error-free 1519-max Frames RX */
183
+#define GEM_RXUNDERCNT (0x00000184 / 4) /* Undersize Frames Received */
184
+#define GEM_RXOVERCNT (0x00000188 / 4) /* Oversize Frames Received */
185
+#define GEM_RXJABCNT (0x0000018C / 4) /* Jabbers Received Counter */
186
+#define GEM_RXFCSCNT (0x00000190 / 4) /* Frame Check seq. Error Counter */
187
+#define GEM_RXLENERRCNT (0x00000194 / 4) /* Length Field Error Counter */
188
+#define GEM_RXSYMERRCNT (0x00000198 / 4) /* Symbol Error Counter */
189
+#define GEM_RXALIGNERRCNT (0x0000019C / 4) /* Alignment Error Counter */
190
+#define GEM_RXRSCERRCNT (0x000001A0 / 4) /* Receive Resource Error Counter */
191
+#define GEM_RXORUNCNT (0x000001A4 / 4) /* Receive Overrun Counter */
192
+#define GEM_RXIPCSERRCNT (0x000001A8 / 4) /* IP header Checksum Err Counter */
193
+#define GEM_RXTCPCCNT (0x000001AC / 4) /* TCP Checksum Error Counter */
194
+#define GEM_RXUDPCCNT (0x000001B0 / 4) /* UDP Checksum Error Counter */
195
+
196
+#define GEM_1588S (0x000001D0 / 4) /* 1588 Timer Seconds */
197
+#define GEM_1588NS (0x000001D4 / 4) /* 1588 Timer Nanoseconds */
198
+#define GEM_1588ADJ (0x000001D8 / 4) /* 1588 Timer Adjust */
199
+#define GEM_1588INC (0x000001DC / 4) /* 1588 Timer Increment */
200
+#define GEM_PTPETXS (0x000001E0 / 4) /* PTP Event Frame Transmitted (s) */
201
+#define GEM_PTPETXNS (0x000001E4 / 4) /*
202
+ * PTP Event Frame Transmitted (ns)
203
+ */
204
+#define GEM_PTPERXS (0x000001E8 / 4) /* PTP Event Frame Received (s) */
205
+#define GEM_PTPERXNS (0x000001EC / 4) /* PTP Event Frame Received (ns) */
206
+#define GEM_PTPPTXS (0x000001E0 / 4) /* PTP Peer Frame Transmitted (s) */
207
+#define GEM_PTPPTXNS (0x000001E4 / 4) /* PTP Peer Frame Transmitted (ns) */
208
+#define GEM_PTPPRXS (0x000001E8 / 4) /* PTP Peer Frame Received (s) */
209
+#define GEM_PTPPRXNS (0x000001EC / 4) /* PTP Peer Frame Received (ns) */
210
211
/* Design Configuration Registers */
212
-#define GEM_DESCONF (0x00000280/4)
213
-#define GEM_DESCONF2 (0x00000284/4)
214
-#define GEM_DESCONF3 (0x00000288/4)
215
-#define GEM_DESCONF4 (0x0000028C/4)
216
-#define GEM_DESCONF5 (0x00000290/4)
217
-#define GEM_DESCONF6 (0x00000294/4)
218
+#define GEM_DESCONF (0x00000280 / 4)
219
+#define GEM_DESCONF2 (0x00000284 / 4)
220
+#define GEM_DESCONF3 (0x00000288 / 4)
221
+#define GEM_DESCONF4 (0x0000028C / 4)
222
+#define GEM_DESCONF5 (0x00000290 / 4)
223
+#define GEM_DESCONF6 (0x00000294 / 4)
224
#define GEM_DESCONF6_64B_MASK (1U << 23)
225
-#define GEM_DESCONF7 (0x00000298/4)
226
+#define GEM_DESCONF7 (0x00000298 / 4)
227
228
#define GEM_INT_Q1_STATUS (0x00000400 / 4)
229
#define GEM_INT_Q1_MASK (0x00000640 / 4)
230
--
231
2.5.0
232
233
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Advertise support of clear-on-read for ISR registers.
4
5
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/cadence_gem.c | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/cadence_gem.c
15
+++ b/hw/net/cadence_gem.c
16
@@ -XXX,XX +XXX,XX @@ static void gem_reset(DeviceState *d)
17
s->regs[GEM_TXPARTIALSF] = 0x000003ff;
18
s->regs[GEM_RXPARTIALSF] = 0x000003ff;
19
s->regs[GEM_MODID] = s->revision;
20
- s->regs[GEM_DESCONF] = 0x02500111;
21
+ s->regs[GEM_DESCONF] = 0x02D00111;
22
s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
23
s->regs[GEM_DESCONF5] = 0x002f2045;
24
s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
25
--
26
2.5.0
27
28
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
Mask all interrupt on reset.
4
5
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/cadence_gem.c | 1 +
10
1 file changed, 1 insertion(+)
11
12
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/cadence_gem.c
15
+++ b/hw/net/cadence_gem.c
16
@@ -XXX,XX +XXX,XX @@ static void gem_reset(DeviceState *d)
17
s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
18
s->regs[GEM_DESCONF5] = 0x002f2045;
19
s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
20
+ s->regs[GEM_INT_Q1_MASK] = 0x00000CE6;
21
s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len;
22
23
if (s->num_priority_queues > 1) {
24
--
25
2.5.0
26
27
diff view generated by jsdifflib
Deleted patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
1
3
TX_LAST bit should not be set by hardware, its set by guest to inform
4
the last bd of the frame.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
hw/net/cadence_gem.c | 6 ------
12
1 file changed, 6 deletions(-)
13
14
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/cadence_gem.c
17
+++ b/hw/net/cadence_gem.c
18
@@ -XXX,XX +XXX,XX @@ static inline unsigned tx_desc_get_last(uint32_t *desc)
19
return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
20
}
21
22
-static inline void tx_desc_set_last(uint32_t *desc)
23
-{
24
- desc[1] |= DESC_1_TX_LAST;
25
-}
26
-
27
static inline unsigned tx_desc_get_length(uint32_t *desc)
28
{
29
return desc[1] & DESC_1_LENGTH;
30
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
31
32
/* read next descriptor */
33
if (tx_desc_get_wrap(desc)) {
34
- tx_desc_set_last(desc);
35
36
if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
37
packet_desc_addr = s->regs[GEM_TBQPH];
38
--
39
2.5.0
40
41
diff view generated by jsdifflib
Deleted patch
1
From: Tong Ho <tong.ho@xilinx.com>
2
1
3
Two defects are fixed:
4
5
1/ Detection of multicast frames
6
2/ Treating drop of mis-addressed frames as non-error
7
8
Signed-off-by: Tong Ho <tong.ho@xilinx.com>
9
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
11
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
hw/net/cadence_gem.c | 26 +++++++++++---------------
15
1 file changed, 11 insertions(+), 15 deletions(-)
16
17
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/net/cadence_gem.c
20
+++ b/hw/net/cadence_gem.c
21
@@ -XXX,XX +XXX,XX @@
22
#include "qemu/module.h"
23
#include "sysemu/dma.h"
24
#include "net/checksum.h"
25
+#include "net/eth.h"
26
27
#define CADENCE_GEM_ERR_DEBUG 0
28
#define DB_PRINT(...) do {\
29
@@ -XXX,XX +XXX,XX @@ static unsigned calc_mac_hash(const uint8_t *mac)
30
static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
31
{
32
uint8_t *gem_spaddr;
33
- int i;
34
+ int i, is_mc;
35
36
/* Promiscuous mode? */
37
if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) {
38
@@ -XXX,XX +XXX,XX @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
39
}
40
41
/* Accept packets -w- hash match? */
42
- if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
43
- (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
44
+ is_mc = is_multicast_ether_addr(packet);
45
+ if ((is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
46
+ (!is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
47
+ uint64_t buckets;
48
unsigned hash_index;
49
50
hash_index = calc_mac_hash(packet);
51
- if (hash_index < 32) {
52
- if (s->regs[GEM_HASHLO] & (1<<hash_index)) {
53
- return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
54
- GEM_RX_UNICAST_HASH_ACCEPT;
55
- }
56
- } else {
57
- hash_index -= 32;
58
- if (s->regs[GEM_HASHHI] & (1<<hash_index)) {
59
- return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
60
- GEM_RX_UNICAST_HASH_ACCEPT;
61
- }
62
+ buckets = ((uint64_t)s->regs[GEM_HASHHI] << 32) | s->regs[GEM_HASHLO];
63
+ if ((buckets >> hash_index) & 1) {
64
+ return is_mc ? GEM_RX_MULTICAST_HASH_ACCEPT
65
+ : GEM_RX_UNICAST_HASH_ACCEPT;
66
}
67
}
68
69
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
70
/* Is this destination MAC address "for us" ? */
71
maf = gem_mac_address_filter(s, buf);
72
if (maf == GEM_RX_REJECT) {
73
- return -1;
74
+ return size; /* no, drop siliently b/c it's not an error */
75
}
76
77
/* Discard packets with receive length error enabled ? */
78
--
79
2.5.0
80
81
diff view generated by jsdifflib
Deleted patch
1
The sender of packet will be checked in the qemu_net_queue_purge() but
2
we use NetClientState not its peer when trying to purge the incoming
3
queue in qemu_flush_or_purge_packets(). This will trigger the assert
4
in virtio_net_reset since we can't pass the sender check:
5
1
6
hw/net/virtio-net.c:533: void virtio_net_reset(VirtIODevice *): Assertion
7
`!virtio_net_get_subqueue(nc)->async_tx.elem' failed.
8
#9 0x55a33fa31b78 in virtio_net_reset hw/net/virtio-net.c:533:13
9
#10 0x55a33fc88412 in virtio_reset hw/virtio/virtio.c:1919:9
10
#11 0x55a341d82764 in virtio_bus_reset hw/virtio/virtio-bus.c:95:9
11
#12 0x55a341dba2de in virtio_pci_reset hw/virtio/virtio-pci.c:1824:5
12
#13 0x55a341db3e02 in virtio_pci_common_write hw/virtio/virtio-pci.c:1252:13
13
#14 0x55a33f62117b in memory_region_write_accessor memory.c:496:5
14
#15 0x55a33f6205e4 in access_with_adjusted_size memory.c:557:18
15
#16 0x55a33f61e177 in memory_region_dispatch_write memory.c:1488:16
16
17
Reproducer:
18
https://www.mail-archive.com/qemu-devel@nongnu.org/msg701914.html
19
20
Fix by using the peer.
21
22
Reported-by: "Alexander Bulekov" <alxndr@bu.edu>
23
Acked-by: Alexander Bulekov <alxndr@bu.edu>
24
Fixes: ca77d85e1dbf9 ("net: complete all queued packets on VM stop")
25
Cc: qemu-stable@nongnu.org
26
Signed-off-by: Jason Wang <jasowang@redhat.com>
27
---
28
net/net.c | 2 +-
29
1 file changed, 1 insertion(+), 1 deletion(-)
30
31
diff --git a/net/net.c b/net/net.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/net/net.c
34
+++ b/net/net.c
35
@@ -XXX,XX +XXX,XX @@ void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
36
qemu_notify_event();
37
} else if (purge) {
38
/* Unable to empty the queue, purge remaining packets */
39
- qemu_net_queue_purge(nc->incoming_queue, nc);
40
+ qemu_net_queue_purge(nc->incoming_queue, nc->peer);
41
}
42
}
43
44
--
45
2.5.0
46
47
diff view generated by jsdifflib
1
From: Derek Su <dereksu@qnap.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
The patch is to fix the "pkt" memory leak in packet_enqueue().
3
This is needed to achieve migration, so the destination can restore its
4
The allocated "pkt" needs to be freed if the colo compare
4
index.
5
primary or secondary queue is too big.
6
5
7
Replace the error_report of full queue with a trace event.
6
Setting base as last used idx, so destination will see as available all
7
the entries that the device did not use, including the in-flight
8
processing ones.
8
9
9
Signed-off-by: Derek Su <dereksu@qnap.com>
10
This is ok for networking, but other kinds of devices might have
10
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
11
problems with these retransmissions.
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
12
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
14
Acked-by: Michael S. Tsirkin <mst@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
16
---
15
net/colo-compare.c | 23 +++++++++++++++--------
17
hw/virtio/vhost-vdpa.c | 17 +++++++++++++++++
16
net/trace-events | 1 +
18
1 file changed, 17 insertions(+)
17
2 files changed, 16 insertions(+), 8 deletions(-)
18
19
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
20
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
20
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
22
--- a/hw/virtio/vhost-vdpa.c
22
+++ b/net/colo-compare.c
23
+++ b/hw/virtio/vhost-vdpa.c
23
@@ -XXX,XX +XXX,XX @@ enum {
24
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev,
24
SECONDARY_IN,
25
static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
25
};
26
struct vhost_vring_state *ring)
26
27
{
27
+static const char *colo_mode[] = {
28
+ struct vhost_vdpa *v = dev->opaque;
28
+ [PRIMARY_IN] = "primary",
29
int ret;
29
+ [SECONDARY_IN] = "secondary",
30
30
+};
31
+ if (v->shadow_vqs_enabled) {
31
32
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs,
32
static int compare_chr_send(CompareState *s,
33
+ ring->index);
33
uint8_t *buf,
34
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
35
ConnectionKey key;
36
Packet *pkt = NULL;
37
Connection *conn;
38
+ int ret;
39
40
if (mode == PRIMARY_IN) {
41
pkt = packet_new(s->pri_rs.buf,
42
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
43
}
44
45
if (mode == PRIMARY_IN) {
46
- if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
47
- error_report("colo compare primary queue size too big,"
48
- "drop packet");
49
- }
50
+ ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack);
51
} else {
52
- if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) {
53
- error_report("colo compare secondary queue size too big,"
54
- "drop packet");
55
- }
56
+ ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack);
57
}
58
+
34
+
59
+ if (!ret) {
35
+ /*
60
+ trace_colo_compare_drop_packet(colo_mode[mode],
36
+ * Setting base as last used idx, so destination will see as available
61
+ "queue size too big, drop packet");
37
+ * all the entries that the device did not use, including the in-flight
62
+ packet_destroy(pkt, NULL);
38
+ * processing ones.
63
+ pkt = NULL;
39
+ *
40
+ * TODO: This is ok for networking, but other kinds of devices might
41
+ * have problems with these retransmissions.
42
+ */
43
+ ring->num = svq->last_used_idx;
44
+ return 0;
64
+ }
45
+ }
65
+
46
+
66
*con = conn;
47
ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring);
67
48
trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num);
68
return 0;
49
return ret;
69
diff --git a/net/trace-events b/net/trace-events
70
index XXXXXXX..XXXXXXX 100644
71
--- a/net/trace-events
72
+++ b/net/trace-events
73
@@ -XXX,XX +XXX,XX @@ colo_proxy_main(const char *chr) ": %s"
74
75
# colo-compare.c
76
colo_compare_main(const char *chr) ": %s"
77
+colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s"
78
colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d"
79
colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d"
80
colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s"
81
--
50
--
82
2.5.0
51
2.7.4
83
52
84
53
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
libFuzzer found using 'qemu-system-i386 -M q35':
3
Setting the log address would make the device start reporting invalid
4
dirty memory because the SVQ vrings are located in qemu's memory.
4
5
5
qemu: hardware error: e1000e: PSRCTL.BSIZE0 cannot be zero
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
6
CPU #0:
7
Acked-by: Michael S. Tsirkin <mst@redhat.com>
7
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
8
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
9
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
10
ES =0000 00000000 0000ffff 00009300
11
CS =f000 ffff0000 0000ffff 00009b00
12
SS =0000 00000000 0000ffff 00009300
13
DS =0000 00000000 0000ffff 00009300
14
FS =0000 00000000 0000ffff 00009300
15
GS =0000 00000000 0000ffff 00009300
16
LDT=0000 00000000 0000ffff 00008200
17
TR =0000 00000000 0000ffff 00008b00
18
GDT= 00000000 0000ffff
19
IDT= 00000000 0000ffff
20
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
21
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
22
DR6=ffff0ff0 DR7=00000400
23
EFER=0000000000000000
24
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
25
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
26
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
27
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
28
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
29
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
30
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
31
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
32
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
33
==1988== ERROR: libFuzzer: deadly signal
34
#6 0x7fae4d3ea894 in __GI_abort (/lib64/libc.so.6+0x22894)
35
#7 0x563f4cc59a1d in hw_error (qemu-fuzz-i386+0xe8ca1d)
36
#8 0x563f4d7c93f2 in e1000e_set_psrctl (qemu-fuzz-i386+0x19fc3f2)
37
#9 0x563f4d7b798f in e1000e_core_write (qemu-fuzz-i386+0x19ea98f)
38
#10 0x563f4d7afc46 in e1000e_mmio_write (qemu-fuzz-i386+0x19e2c46)
39
#11 0x563f4cc9a0a7 in memory_region_write_accessor (qemu-fuzz-i386+0xecd0a7)
40
#12 0x563f4cc99c13 in access_with_adjusted_size (qemu-fuzz-i386+0xeccc13)
41
#13 0x563f4cc987b4 in memory_region_dispatch_write (qemu-fuzz-i386+0xecb7b4)
42
43
It simply sent the following 2 I/O command to the e1000e
44
PCI BAR #2 I/O region:
45
46
writew 0x0100 0x0c00 # RCTL = E1000_RCTL_DTYP_MASK
47
writeb 0x2170 0x00 # PSRCTL = 0
48
49
2813 static void
50
2814 e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
51
2815 {
52
2816 if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
53
2817
54
2818 if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
55
2819 hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero");
56
2820 }
57
58
Instead of calling hw_error() which abort the process (it is
59
meant for CPU fatal error condition, not for device logging),
60
log the invalid request with qemu_log_mask(LOG_GUEST_ERROR)
61
and return, ignoring the request.
62
63
Cc: qemu-stable@nongnu.org
64
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
65
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
66
---
9
---
67
hw/net/e1000e_core.c | 10 +++++++---
10
hw/virtio/vhost-vdpa.c | 3 ++-
68
1 file changed, 7 insertions(+), 3 deletions(-)
11
1 file changed, 2 insertions(+), 1 deletion(-)
69
12
70
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
13
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
71
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
72
--- a/hw/net/e1000e_core.c
15
--- a/hw/virtio/vhost-vdpa.c
73
+++ b/hw/net/e1000e_core.c
16
+++ b/hw/virtio/vhost-vdpa.c
74
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
75
*/
18
static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
76
19
struct vhost_log *log)
77
#include "qemu/osdep.h"
20
{
78
+#include "qemu/log.h"
21
- if (vhost_vdpa_one_time_request(dev)) {
79
#include "net/net.h"
22
+ struct vhost_vdpa *v = dev->opaque;
80
#include "net/tap.h"
23
+ if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) {
81
-#include "hw/hw.h"
24
return 0;
82
#include "hw/pci/msi.h"
83
#include "hw/pci/msix.h"
84
#include "sysemu/runstate.h"
85
@@ -XXX,XX +XXX,XX @@ e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
86
if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
87
88
if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
89
- hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero");
90
+ qemu_log_mask(LOG_GUEST_ERROR,
91
+ "e1000e: PSRCTL.BSIZE0 cannot be zero");
92
+ return;
93
}
94
95
if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
96
- hw_error("e1000e: PSRCTL.BSIZE1 cannot be zero");
97
+ qemu_log_mask(LOG_GUEST_ERROR,
98
+ "e1000e: PSRCTL.BSIZE1 cannot be zero");
99
+ return;
100
}
101
}
25
}
102
26
103
--
27
--
104
2.5.0
28
2.7.4
105
29
106
30
diff view generated by jsdifflib
1
From: Lukas Straub <lukasstraub2@web.de>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
qemu_bh_new will set the bh to be executed in the main
3
SVQ is able to log the dirty bits by itself, so let's use it to not
4
loop. This causes crashes as colo_compare_handle_event assumes
4
block migration.
5
that it has exclusive access the queues, which are also
6
concurrently accessed in the iothread.
7
5
8
Create the bh with the AioContext of the iothread to fulfill
6
Also, ignore set and clear of VHOST_F_LOG_ALL on set_features if SVQ is
9
these assumptions and fix the crashes. This is safe, because
7
enabled. Even if the device supports it, the reports would be nonsense
10
the bh already takes the appropriate locks.
8
because SVQ memory is in the qemu region.
11
9
12
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
10
The log region is still allocated. Future changes might skip that, but
13
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
11
this series is already long enough.
14
Reviewed-by: Derek Su <dereksu@qnap.com>
12
15
Tested-by: Derek Su <dereksu@qnap.com>
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
16
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
14
Acked-by: Michael S. Tsirkin <mst@redhat.com>
17
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
18
---
16
---
19
net/colo-compare.c | 3 ++-
17
hw/virtio/vhost-vdpa.c | 39 +++++++++++++++++++++++++++++++++++----
20
1 file changed, 2 insertions(+), 1 deletion(-)
18
include/hw/virtio/vhost-vdpa.h | 1 +
19
2 files changed, 36 insertions(+), 4 deletions(-)
21
20
22
diff --git a/net/colo-compare.c b/net/colo-compare.c
21
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
23
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
24
--- a/net/colo-compare.c
23
--- a/hw/virtio/vhost-vdpa.c
25
+++ b/net/colo-compare.c
24
+++ b/hw/virtio/vhost-vdpa.c
26
@@ -XXX,XX +XXX,XX @@ static void colo_compare_handle_event(void *opaque)
25
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev)
27
26
return v->index != 0;
28
static void colo_compare_iothread(CompareState *s)
27
}
28
29
+static int vhost_vdpa_get_dev_features(struct vhost_dev *dev,
30
+ uint64_t *features)
31
+{
32
+ int ret;
33
+
34
+ ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features);
35
+ trace_vhost_vdpa_get_features(dev, *features);
36
+ return ret;
37
+}
38
+
39
static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
40
Error **errp)
29
{
41
{
30
+ AioContext *ctx = iothread_get_aio_context(s->iothread);
42
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
31
object_ref(OBJECT(s->iothread));
43
return 0;
32
s->worker_context = iothread_get_g_main_context(s->iothread);
33
34
@@ -XXX,XX +XXX,XX @@ static void colo_compare_iothread(CompareState *s)
35
}
44
}
36
45
37
colo_compare_timer_init(s);
46
- r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features);
38
- s->event_bh = qemu_bh_new(colo_compare_handle_event, s);
47
+ r = vhost_vdpa_get_dev_features(hdev, &dev_features);
39
+ s->event_bh = aio_bh_new(ctx, colo_compare_handle_event, s);
48
if (r != 0) {
49
error_setg_errno(errp, -r, "Can't get vdpa device features");
50
return r;
51
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev,
52
static int vhost_vdpa_set_features(struct vhost_dev *dev,
53
uint64_t features)
54
{
55
+ struct vhost_vdpa *v = dev->opaque;
56
int ret;
57
58
if (vhost_vdpa_one_time_request(dev)) {
59
return 0;
60
}
61
62
+ if (v->shadow_vqs_enabled) {
63
+ if ((v->acked_features ^ features) == BIT_ULL(VHOST_F_LOG_ALL)) {
64
+ /*
65
+ * QEMU is just trying to enable or disable logging. SVQ handles
66
+ * this sepparately, so no need to forward this.
67
+ */
68
+ v->acked_features = features;
69
+ return 0;
70
+ }
71
+
72
+ v->acked_features = features;
73
+
74
+ /* We must not ack _F_LOG if SVQ is enabled */
75
+ features &= ~BIT_ULL(VHOST_F_LOG_ALL);
76
+ }
77
+
78
trace_vhost_vdpa_set_features(dev, features);
79
ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features);
80
if (ret) {
81
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
82
static int vhost_vdpa_get_features(struct vhost_dev *dev,
83
uint64_t *features)
84
{
85
- int ret;
86
+ struct vhost_vdpa *v = dev->opaque;
87
+ int ret = vhost_vdpa_get_dev_features(dev, features);
88
+
89
+ if (ret == 0 && v->shadow_vqs_enabled) {
90
+ /* Add SVQ logging capabilities */
91
+ *features |= BIT_ULL(VHOST_F_LOG_ALL);
92
+ }
93
94
- ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features);
95
- trace_vhost_vdpa_get_features(dev, *features);
96
return ret;
40
}
97
}
41
98
42
static char *compare_get_pri_indev(Object *obj, Error **errp)
99
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
100
index XXXXXXX..XXXXXXX 100644
101
--- a/include/hw/virtio/vhost-vdpa.h
102
+++ b/include/hw/virtio/vhost-vdpa.h
103
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
104
bool iotlb_batch_begin_sent;
105
MemoryListener listener;
106
struct vhost_vdpa_iova_range iova_range;
107
+ uint64_t acked_features;
108
bool shadow_vqs_enabled;
109
/* IOVA mapping used by the Shadow Virtqueue */
110
VhostIOVATree *iova_tree;
43
--
111
--
44
2.5.0
112
2.7.4
45
113
46
114
diff view generated by jsdifflib
Deleted patch
1
From: Lukas Straub <lukasstraub2@web.de>
2
1
3
To be able to convert compare_chr_send to a coroutine in the
4
next commit, use qemu_co_sleep_ns if in coroutine.
5
6
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
chardev/char.c | 7 ++++++-
14
1 file changed, 6 insertions(+), 1 deletion(-)
15
16
diff --git a/chardev/char.c b/chardev/char.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/chardev/char.c
19
+++ b/chardev/char.c
20
@@ -XXX,XX +XXX,XX @@
21
#include "qemu/module.h"
22
#include "qemu/option.h"
23
#include "qemu/id.h"
24
+#include "qemu/coroutine.h"
25
26
#include "chardev/char-mux.h"
27
28
@@ -XXX,XX +XXX,XX @@ static int qemu_chr_write_buffer(Chardev *s,
29
retry:
30
res = cc->chr_write(s, buf + *offset, len - *offset);
31
if (res < 0 && errno == EAGAIN && write_all) {
32
- g_usleep(100);
33
+ if (qemu_in_coroutine()) {
34
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
35
+ } else {
36
+ g_usleep(100);
37
+ }
38
goto retry;
39
}
40
41
--
42
2.5.0
43
44
diff view generated by jsdifflib
Deleted patch
1
From: Lukas Straub <lukasstraub2@web.de>
2
1
3
Else the log will be flooded if there is a lot of network
4
traffic.
5
6
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
7
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/colo-compare.c | 10 ++++++----
14
1 file changed, 6 insertions(+), 4 deletions(-)
15
16
diff --git a/net/colo-compare.c b/net/colo-compare.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/colo-compare.c
19
+++ b/net/colo-compare.c
20
@@ -XXX,XX +XXX,XX @@ sec:
21
g_queue_push_head(&conn->primary_list, ppkt);
22
g_queue_push_head(&conn->secondary_list, spkt);
23
24
- qemu_hexdump((char *)ppkt->data, stderr,
25
- "colo-compare ppkt", ppkt->size);
26
- qemu_hexdump((char *)spkt->data, stderr,
27
- "colo-compare spkt", spkt->size);
28
+ if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
29
+ qemu_hexdump((char *)ppkt->data, stderr,
30
+ "colo-compare ppkt", ppkt->size);
31
+ qemu_hexdump((char *)spkt->data, stderr,
32
+ "colo-compare spkt", spkt->size);
33
+ }
34
35
colo_compare_inconsistency_notify(s);
36
}
37
--
38
2.5.0
39
40
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
It's been deprecated since QEMU v3.1, so it's time to finally
4
remove it. The "id" parameter can simply be used instead.
5
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
docs/system/deprecated.rst | 15 +++++++++------
11
net/net.c | 10 +---------
12
qapi/net.json | 3 ---
13
3 files changed, 10 insertions(+), 18 deletions(-)
14
15
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
16
index XXXXXXX..XXXXXXX 100644
17
--- a/docs/system/deprecated.rst
18
+++ b/docs/system/deprecated.rst
19
@@ -XXX,XX +XXX,XX @@ The 'file' driver for drives is no longer appropriate for character or host
20
devices and will only accept regular files (S_IFREG). The correct driver
21
for these file types is 'host_cdrom' or 'host_device' as appropriate.
22
23
-``-net ...,name=``\ *name* (since 3.1)
24
-''''''''''''''''''''''''''''''''''''''
25
-
26
-The ``name`` parameter of the ``-net`` option is a synonym
27
-for the ``id`` parameter, which should now be used instead.
28
-
29
``-smp`` (invalid topologies) (since 3.1)
30
'''''''''''''''''''''''''''''''''''''''''
31
32
@@ -XXX,XX +XXX,XX @@ What follows is a record of recently removed, formerly deprecated
33
features that serves as a record for users who have encountered
34
trouble after a recent upgrade.
35
36
+System emulator command line arguments
37
+--------------------------------------
38
+
39
+``-net ...,name=``\ *name* (removed in 5.1)
40
+'''''''''''''''''''''''''''''''''''''''''''
41
+
42
+The ``name`` parameter of the ``-net`` option was a synonym
43
+for the ``id`` parameter, which should now be used instead.
44
+
45
QEMU Machine Protocol (QMP) commands
46
------------------------------------
47
48
diff --git a/net/net.c b/net/net.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/net/net.c
51
+++ b/net/net.c
52
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
53
{
54
Netdev legacy = {0};
55
const Netdev *netdev;
56
- const char *name;
57
NetClientState *peer = NULL;
58
59
if (is_netdev) {
60
netdev = object;
61
- name = netdev->id;
62
63
if (netdev->type == NET_CLIENT_DRIVER_NIC ||
64
!net_client_init_fun[netdev->type]) {
65
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
66
const NetLegacyOptions *opts = net->opts;
67
legacy.id = net->id;
68
netdev = &legacy;
69
- /* missing optional values have been initialized to "all bits zero" */
70
- name = net->has_id ? net->id : net->name;
71
-
72
- if (net->has_name) {
73
- warn_report("The 'name' parameter is deprecated, use 'id' instead");
74
- }
75
76
/* Map the old options to the new flat type */
77
switch (opts->type) {
78
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
79
}
80
}
81
82
- if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) {
83
+ if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) {
84
/* FIXME drop when all init functions store an Error */
85
if (errp && !*errp) {
86
error_setg(errp, QERR_DEVICE_INIT_FAILED,
87
diff --git a/qapi/net.json b/qapi/net.json
88
index XXXXXXX..XXXXXXX 100644
89
--- a/qapi/net.json
90
+++ b/qapi/net.json
91
@@ -XXX,XX +XXX,XX @@
92
#
93
# @id: identifier for monitor commands
94
#
95
-# @name: identifier for monitor commands, ignored if @id is present
96
-#
97
# @opts: device type specific properties (legacy)
98
#
99
# Since: 1.2
100
@@ -XXX,XX +XXX,XX @@
101
{ 'struct': 'NetLegacy',
102
'data': {
103
'*id': 'str',
104
- '*name': 'str',
105
'opts': 'NetLegacyOptions' } }
106
107
##
108
--
109
2.5.0
110
111
diff view generated by jsdifflib