1
The following changes since commit 187f35512106501fe9a11057f4d8705431e0026d:
1
The following changes since commit 23895cbd82be95428e90168b12e925d0d3ca2f06:
2
2
3
Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-next-251019-3' into staging (2019-10-26 10:13:48 +0100)
3
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20201123.0' into staging (2020-11-23 18:51:13 +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 5af982a47cf6b6cd9beb872e5a9b940e43df5bf9:
9
for you to fetch changes up to 9925990d01a92564af55f6f69d0f5f59b47609b1:
10
10
11
COLO-compare: Fix incorrect `if` logic (2019-10-28 14:28:31 +0800)
11
net: Use correct default-path macro for downscript (2020-11-24 10:40:17 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
----------------------------------------------------------------
15
----------------------------------------------------------------
16
Fan Yang (1):
16
Keqian Zhu (1):
17
COLO-compare: Fix incorrect `if` logic
17
net: Use correct default-path macro for downscript
18
18
19
Michael S. Tsirkin (1):
19
Paolo Bonzini (1):
20
virtio: new post_load hook
20
net: do not exit on "netdev_add help" monitor command
21
21
22
Mikhail Sennikovsky (1):
22
Prasad J Pandit (1):
23
virtio-net: prevent offloads reset on migration
23
hw/net/e1000e: advance desc_offset in case of null descriptor
24
24
25
Sven Schnelle (1):
25
Yuri Benditovich (1):
26
net: add tulip (dec21143) driver
26
net: purge queued rx packets on queue deletion
27
27
28
MAINTAINERS | 6 +
28
yuanjungong (1):
29
hw/net/Kconfig | 5 +
29
tap: fix a memory leak
30
hw/net/Makefile.objs | 1 +
30
31
hw/net/trace-events | 14 +
31
hw/net/e1000e_core.c | 8 +++---
32
hw/net/tulip.c | 1029 ++++++++++++++++++++++++++++++++++++++++
32
include/net/net.h | 1 +
33
hw/net/tulip.h | 267 +++++++++++
33
monitor/hmp-cmds.c | 6 ++++
34
hw/net/virtio-net.c | 27 +-
34
net/net.c | 80 +++++++++++++++++++++++++++-------------------------
35
hw/virtio/virtio.c | 7 +
35
net/tap.c | 5 +++-
36
include/hw/pci/pci_ids.h | 1 +
36
5 files changed, 57 insertions(+), 43 deletions(-)
37
include/hw/virtio/virtio-net.h | 2 +
38
include/hw/virtio/virtio.h | 6 +
39
net/colo-compare.c | 6 +-
40
12 files changed, 1365 insertions(+), 6 deletions(-)
41
create mode 100644 hw/net/tulip.c
42
create mode 100644 hw/net/tulip.h
43
37
44
38
45
diff view generated by jsdifflib
New patch
1
From: Prasad J Pandit <pjp@fedoraproject.org>
1
2
3
While receiving packets via e1000e_write_packet_to_guest() routine,
4
'desc_offset' is advanced only when RX descriptor is processed. And
5
RX descriptor is not processed if it has NULL buffer address.
6
This may lead to an infinite loop condition. Increament 'desc_offset'
7
to process next descriptor in the ring to avoid infinite loop.
8
9
Reported-by: Cheol-woo Myung <330cjfdn@gmail.com>
10
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
hw/net/e1000e_core.c | 8 ++++----
14
1 file changed, 4 insertions(+), 4 deletions(-)
15
16
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/net/e1000e_core.c
19
+++ b/hw/net/e1000e_core.c
20
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
21
(const char *) &fcs_pad, e1000x_fcs_len(core->mac));
22
}
23
}
24
- desc_offset += desc_size;
25
- if (desc_offset >= total_size) {
26
- is_last = true;
27
- }
28
} else { /* as per intel docs; skip descriptors with null buf addr */
29
trace_e1000e_rx_null_descriptor();
30
}
31
+ desc_offset += desc_size;
32
+ if (desc_offset >= total_size) {
33
+ is_last = true;
34
+ }
35
36
e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL,
37
rss_info, do_ps ? ps_hdr_len : 0, &bastate.written);
38
--
39
2.7.4
40
41
diff view generated by jsdifflib
1
From: "Michael S. Tsirkin" <mst@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Post load hook in virtio vmsd is called early while device is processed,
3
"netdev_add help" is causing QEMU to exit because the code that
4
and when VirtIODevice core isn't fully initialized. Most device
4
invokes show_netdevs is shared between CLI and HMP processing.
5
specific code isn't ready to deal with a device in such state, and
5
Move the check to the callers so that exit(0) remains only
6
behaves weirdly.
6
in the CLI flow.
7
7
8
Add a new post_load hook in a device class instead. Devices should use
8
"netdev_add help" is not fixed by this patch; that is left for
9
this unless they specifically want to verify the migration stream as
9
later work.
10
it's processed, e.g. for bounds checking.
11
10
12
Cc: qemu-stable@nongnu.org
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
13
Suggested-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
14
Cc: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
15
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
16
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
17
---
13
---
18
hw/virtio/virtio.c | 7 +++++++
14
include/net/net.h | 1 +
19
include/hw/virtio/virtio.h | 6 ++++++
15
monitor/hmp-cmds.c | 6 +++++
20
2 files changed, 13 insertions(+)
16
net/net.c | 68 +++++++++++++++++++++++++++---------------------------
17
3 files changed, 41 insertions(+), 34 deletions(-)
21
18
22
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
19
diff --git a/include/net/net.h b/include/net/net.h
23
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
24
--- a/hw/virtio/virtio.c
21
--- a/include/net/net.h
25
+++ b/hw/virtio/virtio.c
22
+++ b/include/net/net.h
26
@@ -XXX,XX +XXX,XX @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
23
@@ -XXX,XX +XXX,XX @@ extern const char *host_net_devices[];
27
}
24
28
rcu_read_unlock();
25
/* from net.c */
29
26
int net_client_parse(QemuOptsList *opts_list, const char *str);
30
+ if (vdc->post_load) {
27
+void show_netdevs(void);
31
+ ret = vdc->post_load(vdev);
28
int net_init_clients(Error **errp);
32
+ if (ret) {
29
void net_check_clients(void);
33
+ return ret;
30
void net_cleanup(void);
34
+ }
31
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/monitor/hmp-cmds.c
34
+++ b/monitor/hmp-cmds.c
35
@@ -XXX,XX +XXX,XX @@
36
#include "qemu/option.h"
37
#include "qemu/timer.h"
38
#include "qemu/sockets.h"
39
+#include "qemu/help_option.h"
40
#include "monitor/monitor-internal.h"
41
#include "qapi/error.h"
42
#include "qapi/clone-visitor.h"
43
@@ -XXX,XX +XXX,XX @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict)
44
{
45
Error *err = NULL;
46
QemuOpts *opts;
47
+ const char *type = qdict_get_try_str(qdict, "type");
48
49
+ if (type && is_help_option(type)) {
50
+ show_netdevs();
51
+ return;
35
+ }
52
+ }
36
+
53
opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &err);
54
if (err) {
55
goto out;
56
diff --git a/net/net.c b/net/net.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/net/net.c
59
+++ b/net/net.c
60
@@ -XXX,XX +XXX,XX @@
61
#include "qemu/config-file.h"
62
#include "qemu/ctype.h"
63
#include "qemu/iov.h"
64
+#include "qemu/qemu-print.h"
65
#include "qemu/main-loop.h"
66
#include "qemu/option.h"
67
#include "qapi/error.h"
68
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp)
37
return 0;
69
return 0;
38
}
70
}
39
71
40
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
72
-static void show_netdevs(void)
41
index XXXXXXX..XXXXXXX 100644
73
+void show_netdevs(void)
42
--- a/include/hw/virtio/virtio.h
74
{
43
+++ b/include/hw/virtio/virtio.h
75
int idx;
44
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioDeviceClass {
76
const char *available_netdevs[] = {
45
*/
77
@@ -XXX,XX +XXX,XX @@ static void show_netdevs(void)
46
void (*save)(VirtIODevice *vdev, QEMUFile *f);
78
#endif
47
int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id);
79
};
48
+ /* Post load hook in vmsd is called early while device is processed, and
80
49
+ * when VirtIODevice isn't fully initialized. Devices should use this instead,
81
- printf("Available netdev backend types:\n");
50
+ * unless they specifically want to verify the migration stream as it's
82
+ qemu_printf("Available netdev backend types:\n");
51
+ * processed, e.g. for bounds checking.
83
for (idx = 0; idx < ARRAY_SIZE(available_netdevs); idx++) {
52
+ */
84
- puts(available_netdevs[idx]);
53
+ int (*post_load)(VirtIODevice *vdev);
85
+ qemu_printf("%s\n", available_netdevs[idx]);
54
const VMStateDescription *vmsd;
86
}
55
} VirtioDeviceClass;
87
}
88
89
@@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
90
int ret = -1;
91
Visitor *v = opts_visitor_new(opts);
92
93
- const char *type = qemu_opt_get(opts, "type");
94
-
95
- if (is_netdev && type && is_help_option(type)) {
96
- show_netdevs();
97
- exit(0);
98
- } else {
99
- /* Parse convenience option format ip6-net=fec0::0[/64] */
100
- const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
101
+ /* Parse convenience option format ip6-net=fec0::0[/64] */
102
+ const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
103
104
- if (ip6_net) {
105
- char *prefix_addr;
106
- unsigned long prefix_len = 64; /* Default 64bit prefix length. */
107
+ if (ip6_net) {
108
+ char *prefix_addr;
109
+ unsigned long prefix_len = 64; /* Default 64bit prefix length. */
110
111
- substrings = g_strsplit(ip6_net, "/", 2);
112
- if (!substrings || !substrings[0]) {
113
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net",
114
- "a valid IPv6 prefix");
115
- goto out;
116
- }
117
+ substrings = g_strsplit(ip6_net, "/", 2);
118
+ if (!substrings || !substrings[0]) {
119
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net",
120
+ "a valid IPv6 prefix");
121
+ goto out;
122
+ }
123
124
- prefix_addr = substrings[0];
125
+ prefix_addr = substrings[0];
126
127
- /* Handle user-specified prefix length. */
128
- if (substrings[1] &&
129
- qemu_strtoul(substrings[1], NULL, 10, &prefix_len))
130
- {
131
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
132
- "ipv6-prefixlen", "a number");
133
- goto out;
134
- }
135
-
136
- qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort);
137
- qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len,
138
- &error_abort);
139
- qemu_opt_unset(opts, "ipv6-net");
140
+ /* Handle user-specified prefix length. */
141
+ if (substrings[1] &&
142
+ qemu_strtoul(substrings[1], NULL, 10, &prefix_len))
143
+ {
144
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
145
+ "ipv6-prefixlen", "a number");
146
+ goto out;
147
}
148
+
149
+ qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort);
150
+ qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len,
151
+ &error_abort);
152
+ qemu_opt_unset(opts, "ipv6-net");
153
}
154
155
/* Create an ID for -net if the user did not specify one */
156
@@ -XXX,XX +XXX,XX @@ static int net_init_client(void *dummy, QemuOpts *opts, Error **errp)
157
158
static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp)
159
{
160
+ const char *type = qemu_opt_get(opts, "type");
161
+
162
+ if (type && is_help_option(type)) {
163
+ show_netdevs();
164
+ exit(0);
165
+ }
166
return net_client_init(opts, true, errp);
167
}
56
168
57
--
169
--
58
2.5.0
170
2.7.4
59
171
60
172
diff view generated by jsdifflib
1
From: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
2
3
Currently offloads disabled by guest via the VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET
3
https://bugzilla.redhat.com/show_bug.cgi?id=1829272
4
command are not preserved on VM migration.
4
When deleting queue pair, purge pending RX packets if any.
5
Instead all offloads reported by guest features (via VIRTIO_PCI_GUEST_FEATURES)
5
Example of problematic flow:
6
get enabled.
6
1. Bring up q35 VM with tap (vhost off) and virtio-net or e1000e
7
What happens is: first the VirtIONet::curr_guest_offloads gets restored and offloads
7
2. Run ping flood to the VM NIC ( 1 ms interval)
8
are getting set correctly:
8
3. Hot unplug the NIC device (device_del)
9
During unplug process one or more packets come, the NIC
10
can't receive, tap disables read_poll
11
4. Hot plug the device (device_add) with the same netdev
12
The tap stays with read_poll disabled and does not receive
13
any packets anymore (tap_send never triggered)
9
14
10
#0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=0, tso6=0, ecn=0, ufo=0) at net/net.c:474
15
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
11
#1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720
12
#2 virtio_net_post_load_device (opaque=0x555557701ca0, version_id=11) at hw/net/virtio-net.c:2334
13
#3 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577c80 <vmstate_virtio_net_device>, opaque=0x555557701ca0, version_id=11)
14
at migration/vmstate.c:168
15
#4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2197
16
#5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036
17
#6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 <vmstate_virtio_net>, opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143
18
#7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829
19
#8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211
20
#9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395
21
#10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467
22
#11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449
23
24
However later on the features are getting restored, and offloads get reset to
25
everything supported by features:
26
27
#0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=1, tso6=1, ecn=0, ufo=0) at net/net.c:474
28
#1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720
29
#2 virtio_net_set_features (vdev=0x555557701ca0, features=5104441767) at hw/net/virtio-net.c:773
30
#3 virtio_set_features_nocheck (vdev=0x555557701ca0, val=5104441767) at hw/virtio/virtio.c:2052
31
#4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2220
32
#5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036
33
#6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 <vmstate_virtio_net>, opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143
34
#7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829
35
#8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211
36
#9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395
37
#10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467
38
#11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449
39
40
Fix this by preserving the state in saved_guest_offloads field and
41
pushing out offload initialization to the new post load hook.
42
43
Cc: qemu-stable@nongnu.org
44
Signed-off-by: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
45
Signed-off-by: Jason Wang <jasowang@redhat.com>
16
Signed-off-by: Jason Wang <jasowang@redhat.com>
46
---
17
---
47
hw/net/virtio-net.c | 27 ++++++++++++++++++++++++---
18
net/net.c | 12 ++++++++----
48
include/hw/virtio/virtio-net.h | 2 ++
19
1 file changed, 8 insertions(+), 4 deletions(-)
49
2 files changed, 26 insertions(+), 3 deletions(-)
50
20
51
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
21
diff --git a/net/net.c b/net/net.c
52
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
53
--- a/hw/net/virtio-net.c
23
--- a/net/net.c
54
+++ b/hw/net/virtio-net.c
24
+++ b/net/net.c
55
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
25
@@ -XXX,XX +XXX,XX @@ void qemu_del_nic(NICState *nic)
56
n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
26
27
qemu_macaddr_set_free(&nic->conf->macaddr);
28
29
- /* If this is a peer NIC and peer has already been deleted, free it now. */
30
- if (nic->peer_deleted) {
31
- for (i = 0; i < queues; i++) {
32
- qemu_free_net_client(qemu_get_subqueue(nic, i)->peer);
33
+ for (i = 0; i < queues; i++) {
34
+ NetClientState *nc = qemu_get_subqueue(nic, i);
35
+ /* If this is a peer NIC and peer has already been deleted, free it now. */
36
+ if (nic->peer_deleted) {
37
+ qemu_free_net_client(nc->peer);
38
+ } else if (nc->peer) {
39
+ /* if there are RX packets pending, complete them */
40
+ qemu_purge_queued_packets(nc->peer);
41
}
57
}
42
}
58
43
59
- if (peer_has_vnet_hdr(n)) {
60
- virtio_net_apply_guest_offloads(n);
61
- }
62
+ /*
63
+ * curr_guest_offloads will be later overwritten by the
64
+ * virtio_set_features_nocheck call done from the virtio_load.
65
+ * Here we make sure it is preserved and restored accordingly
66
+ * in the virtio_net_post_load_virtio callback.
67
+ */
68
+ n->saved_guest_offloads = n->curr_guest_offloads;
69
70
virtio_net_set_queues(n);
71
72
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
73
return 0;
74
}
75
76
+static int virtio_net_post_load_virtio(VirtIODevice *vdev)
77
+{
78
+ VirtIONet *n = VIRTIO_NET(vdev);
79
+ /*
80
+ * The actual needed state is now in saved_guest_offloads,
81
+ * see virtio_net_post_load_device for detail.
82
+ * Restore it back and apply the desired offloads.
83
+ */
84
+ n->curr_guest_offloads = n->saved_guest_offloads;
85
+ if (peer_has_vnet_hdr(n)) {
86
+ virtio_net_apply_guest_offloads(n);
87
+ }
88
+
89
+ return 0;
90
+}
91
+
92
/* tx_waiting field of a VirtIONetQueue */
93
static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = {
94
.name = "virtio-net-queue-tx_waiting",
95
@@ -XXX,XX +XXX,XX @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
96
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
97
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
98
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
99
+ vdc->post_load = virtio_net_post_load_virtio;
100
vdc->vmsd = &vmstate_virtio_net_device;
101
}
102
103
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
104
index XXXXXXX..XXXXXXX 100644
105
--- a/include/hw/virtio/virtio-net.h
106
+++ b/include/hw/virtio/virtio-net.h
107
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
108
char *netclient_name;
109
char *netclient_type;
110
uint64_t curr_guest_offloads;
111
+ /* used on saved state restore phase to preserve the curr_guest_offloads */
112
+ uint64_t saved_guest_offloads;
113
AnnounceTimer announce_timer;
114
bool needs_vnet_hdr_swap;
115
bool mtu_bypass_backend;
116
--
44
--
117
2.5.0
45
2.7.4
118
46
119
47
diff view generated by jsdifflib
1
From: Sven Schnelle <svens@stackframe.org>
1
From: yuanjungong <ruc_gongyuanjun@163.com>
2
2
3
This adds the basic functionality to emulate a Tulip NIC.
3
Close fd before returning.
4
4
5
Implemented are:
5
Buglink: https://bugs.launchpad.net/qemu/+bug/1904486
6
6
7
- RX and TX functionality
7
Signed-off-by: yuanjungong <ruc_gongyuanjun@163.com>
8
- Perfect Frame Filtering
9
- Big/Little Endian descriptor support
10
- 93C46 EEPROM support
11
- LXT970 PHY
12
13
Not implemented, mostly because i had no OS using these functions:
14
15
- Imperfect frame filtering
16
- General Purpose Timer
17
- Transmit automatic polling
18
- Boot ROM support
19
- SIA interface
20
- Big/Little Endian data buffer conversion
21
22
Successfully tested with the following Operating Systems:
23
24
- MSDOS with Microsoft Network Client 3.0 and DEC ODI drivers
25
- HPPA Linux
26
- Windows XP
27
- HP-UX
28
29
Signed-off-by: Sven Schnelle <svens@stackframe.org>
30
Message-Id: <20191022155413.4619-1-svens@stackframe.org>
31
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
32
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
33
---
10
---
34
MAINTAINERS | 6 +
11
net/tap.c | 2 ++
35
hw/net/Kconfig | 5 +
12
1 file changed, 2 insertions(+)
36
hw/net/Makefile.objs | 1 +
37
hw/net/trace-events | 14 +
38
hw/net/tulip.c | 1029 ++++++++++++++++++++++++++++++++++++++++++++++
39
hw/net/tulip.h | 267 ++++++++++++
40
include/hw/pci/pci_ids.h | 1 +
41
7 files changed, 1323 insertions(+)
42
create mode 100644 hw/net/tulip.c
43
create mode 100644 hw/net/tulip.h
44
13
45
diff --git a/MAINTAINERS b/MAINTAINERS
14
diff --git a/net/tap.c b/net/tap.c
46
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
47
--- a/MAINTAINERS
16
--- a/net/tap.c
48
+++ b/MAINTAINERS
17
+++ b/net/tap.c
49
@@ -XXX,XX +XXX,XX @@ M: Stefan Weil <sw@weilnetz.de>
18
@@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name,
50
S: Maintained
19
if (ret < 0) {
51
F: hw/net/eepro100.c
20
error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
52
21
name, fd);
53
+tulip
22
+ close(fd);
54
+M: Sven Schnelle <svens@stackframe.org>
23
return -1;
55
+S: Maintained
24
}
56
+F: hw/net/tulip.c
25
57
+F: hw/net/tulip.h
26
@@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name,
58
+
27
vhostfdname, vnet_hdr, fd, &err);
59
Generic Loader
28
if (err) {
60
M: Alistair Francis <alistair@alistair23.me>
29
error_propagate(errp, err);
61
S: Maintained
30
+ close(fd);
62
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
31
return -1;
63
index XXXXXXX..XXXXXXX 100644
32
}
64
--- a/hw/net/Kconfig
33
} else if (tap->has_fds) {
65
+++ b/hw/net/Kconfig
66
@@ -XXX,XX +XXX,XX @@ config PCNET_PCI
67
config PCNET_COMMON
68
bool
69
70
+config TULIP
71
+ bool
72
+ default y if PCI_DEVICES
73
+ depends on PCI
74
+
75
config E1000_PCI
76
bool
77
default y if PCI_DEVICES
78
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
79
index XXXXXXX..XXXXXXX 100644
80
--- a/hw/net/Makefile.objs
81
+++ b/hw/net/Makefile.objs
82
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_E1000E_PCI_EXPRESS) += e1000e.o e1000e_core.o e1000x_common.
83
common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
84
common-obj-$(CONFIG_VMXNET3_PCI) += net_tx_pkt.o net_rx_pkt.o
85
common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
86
+common-obj-$(CONFIG_TULIP) += tulip.o
87
88
common-obj-$(CONFIG_SMC91C111) += smc91c111.o
89
common-obj-$(CONFIG_LAN9118) += lan9118.o
90
diff --git a/hw/net/trace-events b/hw/net/trace-events
91
index XXXXXXX..XXXXXXX 100644
92
--- a/hw/net/trace-events
93
+++ b/hw/net/trace-events
94
@@ -XXX,XX +XXX,XX @@ virtio_net_announce_notify(void) ""
95
virtio_net_announce_timer(int round) "%d"
96
virtio_net_handle_announce(int round) "%d"
97
virtio_net_post_load_device(void)
98
+
99
+# tulip.c
100
+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
101
+tulip_reg_read(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
102
+tulip_receive(const uint8_t *buf, size_t len) "buf %p size %zu"
103
+tulip_descriptor(const char *prefix, uint32_t addr, uint32_t status, uint32_t control, uint32_t len1, uint32_t len2, uint32_t buf1, uint32_t buf2) "%s 0x%08x: status 0x%08x control 0x%03x len1 %4d len2 %4d buf1 0x%08x buf2 0x%08x"
104
+tulip_rx_state(const char *state) "RX %s"
105
+tulip_tx_state(const char *state) "TX %s"
106
+tulip_irq(uint32_t mask, uint32_t en, const char *state) "mask 0x%08x ie 0x%08x %s"
107
+tulip_mii_write(int phy, int reg, uint16_t data) "phy 0x%x reg 0x%x data 0x%04x"
108
+tulip_mii_read(int phy, int reg, uint16_t data) "phy 0x%x, reg 0x%x data 0x%04x"
109
+tulip_reset(void) ""
110
+tulip_setup_frame(void) ""
111
+tulip_setup_filter(int n, uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) "%d: %02x:%02x:%02x:%02x:%02x:%02x"
112
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
113
new file mode 100644
114
index XXXXXXX..XXXXXXX
115
--- /dev/null
116
+++ b/hw/net/tulip.c
117
@@ -XXX,XX +XXX,XX @@
118
+/*
119
+ * QEMU TULIP Emulation
120
+ *
121
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
122
+ *
123
+ * This work is licensed under the GNU GPL license version 2 or later.
124
+ */
125
+
126
+#include "qemu/osdep.h"
127
+#include "qemu/log.h"
128
+#include "hw/irq.h"
129
+#include "hw/pci/pci.h"
130
+#include "hw/qdev-properties.h"
131
+#include "hw/nvram/eeprom93xx.h"
132
+#include "migration/vmstate.h"
133
+#include "sysemu/sysemu.h"
134
+#include "tulip.h"
135
+#include "trace.h"
136
+#include "net/eth.h"
137
+
138
+typedef struct TULIPState {
139
+ PCIDevice dev;
140
+ MemoryRegion io;
141
+ MemoryRegion memory;
142
+ NICConf c;
143
+ qemu_irq irq;
144
+ NICState *nic;
145
+ eeprom_t *eeprom;
146
+ uint32_t csr[16];
147
+
148
+ /* state for MII */
149
+ uint32_t old_csr9;
150
+ uint32_t mii_word;
151
+ uint32_t mii_bitcnt;
152
+
153
+ hwaddr current_rx_desc;
154
+ hwaddr current_tx_desc;
155
+
156
+ uint8_t rx_frame[2048];
157
+ uint8_t tx_frame[2048];
158
+ uint16_t tx_frame_len;
159
+ uint16_t rx_frame_len;
160
+ uint16_t rx_frame_size;
161
+
162
+ uint32_t rx_status;
163
+ uint8_t filter[16][6];
164
+} TULIPState;
165
+
166
+static const VMStateDescription vmstate_pci_tulip = {
167
+ .name = "tulip",
168
+ .fields = (VMStateField[]) {
169
+ VMSTATE_PCI_DEVICE(dev, TULIPState),
170
+ VMSTATE_UINT32_ARRAY(csr, TULIPState, 16),
171
+ VMSTATE_UINT32(old_csr9, TULIPState),
172
+ VMSTATE_UINT32(mii_word, TULIPState),
173
+ VMSTATE_UINT32(mii_bitcnt, TULIPState),
174
+ VMSTATE_UINT64(current_rx_desc, TULIPState),
175
+ VMSTATE_UINT64(current_tx_desc, TULIPState),
176
+ VMSTATE_BUFFER(rx_frame, TULIPState),
177
+ VMSTATE_BUFFER(tx_frame, TULIPState),
178
+ VMSTATE_UINT16(rx_frame_len, TULIPState),
179
+ VMSTATE_UINT16(tx_frame_len, TULIPState),
180
+ VMSTATE_UINT16(rx_frame_size, TULIPState),
181
+ VMSTATE_UINT32(rx_status, TULIPState),
182
+ VMSTATE_UINT8_2DARRAY(filter, TULIPState, 16, 6),
183
+ VMSTATE_END_OF_LIST()
184
+ }
185
+};
186
+
187
+static void tulip_desc_read(TULIPState *s, hwaddr p,
188
+ struct tulip_descriptor *desc)
189
+{
190
+ if (s->csr[0] & CSR0_DBO) {
191
+ desc->status = ldl_be_pci_dma(&s->dev, p);
192
+ desc->control = ldl_be_pci_dma(&s->dev, p + 4);
193
+ desc->buf_addr1 = ldl_be_pci_dma(&s->dev, p + 8);
194
+ desc->buf_addr2 = ldl_be_pci_dma(&s->dev, p + 12);
195
+ } else {
196
+ desc->status = ldl_le_pci_dma(&s->dev, p);
197
+ desc->control = ldl_le_pci_dma(&s->dev, p + 4);
198
+ desc->buf_addr1 = ldl_le_pci_dma(&s->dev, p + 8);
199
+ desc->buf_addr2 = ldl_le_pci_dma(&s->dev, p + 12);
200
+ }
201
+}
202
+
203
+static void tulip_desc_write(TULIPState *s, hwaddr p,
204
+ struct tulip_descriptor *desc)
205
+{
206
+ if (s->csr[0] & CSR0_DBO) {
207
+ stl_be_pci_dma(&s->dev, p, desc->status);
208
+ stl_be_pci_dma(&s->dev, p + 4, desc->control);
209
+ stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1);
210
+ stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2);
211
+ } else {
212
+ stl_le_pci_dma(&s->dev, p, desc->status);
213
+ stl_le_pci_dma(&s->dev, p + 4, desc->control);
214
+ stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1);
215
+ stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2);
216
+ }
217
+}
218
+
219
+static void tulip_update_int(TULIPState *s)
220
+{
221
+ uint32_t ie = s->csr[5] & s->csr[7];
222
+ bool assert = false;
223
+
224
+ s->csr[5] &= ~(CSR5_AIS | CSR5_NIS);
225
+
226
+ if (ie & (CSR5_TI | CSR5_TU | CSR5_RI | CSR5_GTE | CSR5_ERI)) {
227
+ s->csr[5] |= CSR5_NIS;
228
+ }
229
+
230
+ if (ie & (CSR5_LC | CSR5_GPI | CSR5_FBE | CSR5_LNF | CSR5_ETI | CSR5_RWT |
231
+ CSR5_RPS | CSR5_RU | CSR5_UNF | CSR5_LNP_ANC | CSR5_TJT |
232
+ CSR5_TPS)) {
233
+ s->csr[5] |= CSR5_AIS;
234
+ }
235
+
236
+ assert = s->csr[5] & s->csr[7] & (CSR5_AIS | CSR5_NIS);
237
+ trace_tulip_irq(s->csr[5], s->csr[7], assert ? "assert" : "deassert");
238
+ qemu_set_irq(s->irq, assert);
239
+}
240
+
241
+static bool tulip_rx_stopped(TULIPState *s)
242
+{
243
+ return ((s->csr[5] >> CSR5_RS_SHIFT) & CSR5_RS_MASK) == CSR5_RS_STOPPED;
244
+}
245
+
246
+static void tulip_dump_tx_descriptor(TULIPState *s,
247
+ struct tulip_descriptor *desc)
248
+{
249
+ trace_tulip_descriptor("TX ", s->current_tx_desc,
250
+ desc->status, desc->control >> 22,
251
+ desc->control & 0x7ff, (desc->control >> 11) & 0x7ff,
252
+ desc->buf_addr1, desc->buf_addr2);
253
+}
254
+
255
+static void tulip_dump_rx_descriptor(TULIPState *s,
256
+ struct tulip_descriptor *desc)
257
+{
258
+ trace_tulip_descriptor("RX ", s->current_rx_desc,
259
+ desc->status, desc->control >> 22,
260
+ desc->control & 0x7ff, (desc->control >> 11) & 0x7ff,
261
+ desc->buf_addr1, desc->buf_addr2);
262
+}
263
+
264
+static void tulip_next_rx_descriptor(TULIPState *s,
265
+ struct tulip_descriptor *desc)
266
+{
267
+ if (desc->control & RDES1_RER) {
268
+ s->current_rx_desc = s->csr[3];
269
+ } else if (desc->control & RDES1_RCH) {
270
+ s->current_rx_desc = desc->buf_addr2;
271
+ } else {
272
+ s->current_rx_desc += sizeof(struct tulip_descriptor) +
273
+ (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2);
274
+ }
275
+ s->current_rx_desc &= ~3ULL;
276
+}
277
+
278
+static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
279
+{
280
+ int len1 = (desc->control >> RDES1_BUF1_SIZE_SHIFT) & RDES1_BUF1_SIZE_MASK;
281
+ int len2 = (desc->control >> RDES1_BUF2_SIZE_SHIFT) & RDES1_BUF2_SIZE_MASK;
282
+ int len;
283
+
284
+ if (s->rx_frame_len && len1) {
285
+ if (s->rx_frame_len > len1) {
286
+ len = len1;
287
+ } else {
288
+ len = s->rx_frame_len;
289
+ }
290
+ pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
291
+ (s->rx_frame_size - s->rx_frame_len), len);
292
+ s->rx_frame_len -= len;
293
+ }
294
+
295
+ if (s->rx_frame_len && len2) {
296
+ if (s->rx_frame_len > len2) {
297
+ len = len2;
298
+ } else {
299
+ len = s->rx_frame_len;
300
+ }
301
+ pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
302
+ (s->rx_frame_size - s->rx_frame_len), len);
303
+ s->rx_frame_len -= len;
304
+ }
305
+}
306
+
307
+static bool tulip_filter_address(TULIPState *s, const uint8_t *addr)
308
+{
309
+ static const char broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
310
+ bool ret = false;
311
+ int i;
312
+
313
+ for (i = 0; i < 16 && ret == false; i++) {
314
+ if (!memcmp(&s->filter[i], addr, ETH_ALEN)) {
315
+ ret = true;
316
+ }
317
+ }
318
+
319
+ if (!memcmp(addr, broadcast, ETH_ALEN)) {
320
+ return true;
321
+ }
322
+
323
+ if (s->csr[6] & (CSR6_PR | CSR6_RA)) {
324
+ /* Promiscuous mode enabled */
325
+ s->rx_status |= RDES0_FF;
326
+ return true;
327
+ }
328
+
329
+ if ((s->csr[6] & CSR6_PM) && (addr[0] & 1)) {
330
+ /* Pass all Multicast enabled */
331
+ s->rx_status |= RDES0_MF;
332
+ return true;
333
+ }
334
+
335
+ if (s->csr[6] & CSR6_IF) {
336
+ ret ^= true;
337
+ }
338
+ return ret;
339
+}
340
+
341
+static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size)
342
+{
343
+ struct tulip_descriptor desc;
344
+
345
+ trace_tulip_receive(buf, size);
346
+
347
+ if (size < 14 || size > 2048 || s->rx_frame_len || tulip_rx_stopped(s)) {
348
+ return 0;
349
+ }
350
+
351
+ if (!tulip_filter_address(s, buf)) {
352
+ return size;
353
+ }
354
+
355
+ do {
356
+ tulip_desc_read(s, s->current_rx_desc, &desc);
357
+ tulip_dump_rx_descriptor(s, &desc);
358
+
359
+ if (!(desc.status & RDES0_OWN)) {
360
+ s->csr[5] |= CSR5_RU;
361
+ tulip_update_int(s);
362
+ return s->rx_frame_size - s->rx_frame_len;
363
+ }
364
+ desc.status = 0;
365
+
366
+ if (!s->rx_frame_len) {
367
+ s->rx_frame_size = size + 4;
368
+ s->rx_status = RDES0_LS |
369
+ ((s->rx_frame_size & RDES0_FL_MASK) << RDES0_FL_SHIFT);
370
+ desc.status |= RDES0_FS;
371
+ memcpy(s->rx_frame, buf, size);
372
+ s->rx_frame_len = s->rx_frame_size;
373
+ }
374
+
375
+ tulip_copy_rx_bytes(s, &desc);
376
+
377
+ if (!s->rx_frame_len) {
378
+ desc.status |= s->rx_status;
379
+ s->csr[5] |= CSR5_RI;
380
+ tulip_update_int(s);
381
+ }
382
+ tulip_dump_rx_descriptor(s, &desc);
383
+ tulip_desc_write(s, s->current_rx_desc, &desc);
384
+ tulip_next_rx_descriptor(s, &desc);
385
+ } while (s->rx_frame_len);
386
+ return size;
387
+}
388
+
389
+static ssize_t tulip_receive_nc(NetClientState *nc,
390
+ const uint8_t *buf, size_t size)
391
+{
392
+ return tulip_receive(qemu_get_nic_opaque(nc), buf, size);
393
+}
394
+
395
+
396
+static NetClientInfo net_tulip_info = {
397
+ .type = NET_CLIENT_DRIVER_NIC,
398
+ .size = sizeof(NICState),
399
+ .receive = tulip_receive_nc,
400
+};
401
+
402
+static const char *tulip_reg_name(const hwaddr addr)
403
+{
404
+ switch (addr) {
405
+ case CSR(0):
406
+ return "CSR0";
407
+
408
+ case CSR(1):
409
+ return "CSR1";
410
+
411
+ case CSR(2):
412
+ return "CSR2";
413
+
414
+ case CSR(3):
415
+ return "CSR3";
416
+
417
+ case CSR(4):
418
+ return "CSR4";
419
+
420
+ case CSR(5):
421
+ return "CSR5";
422
+
423
+ case CSR(6):
424
+ return "CSR6";
425
+
426
+ case CSR(7):
427
+ return "CSR7";
428
+
429
+ case CSR(8):
430
+ return "CSR8";
431
+
432
+ case CSR(9):
433
+ return "CSR9";
434
+
435
+ case CSR(10):
436
+ return "CSR10";
437
+
438
+ case CSR(11):
439
+ return "CSR11";
440
+
441
+ case CSR(12):
442
+ return "CSR12";
443
+
444
+ case CSR(13):
445
+ return "CSR13";
446
+
447
+ case CSR(14):
448
+ return "CSR14";
449
+
450
+ case CSR(15):
451
+ return "CSR15";
452
+
453
+ default:
454
+ break;
455
+ }
456
+ return "";
457
+}
458
+
459
+static const char *tulip_rx_state_name(int state)
460
+{
461
+ switch (state) {
462
+ case CSR5_RS_STOPPED:
463
+ return "STOPPED";
464
+
465
+ case CSR5_RS_RUNNING_FETCH:
466
+ return "RUNNING/FETCH";
467
+
468
+ case CSR5_RS_RUNNING_CHECK_EOR:
469
+ return "RUNNING/CHECK EOR";
470
+
471
+ case CSR5_RS_RUNNING_WAIT_RECEIVE:
472
+ return "WAIT RECEIVE";
473
+
474
+ case CSR5_RS_SUSPENDED:
475
+ return "SUSPENDED";
476
+
477
+ case CSR5_RS_RUNNING_CLOSE:
478
+ return "RUNNING/CLOSE";
479
+
480
+ case CSR5_RS_RUNNING_FLUSH:
481
+ return "RUNNING/FLUSH";
482
+
483
+ case CSR5_RS_RUNNING_QUEUE:
484
+ return "RUNNING/QUEUE";
485
+
486
+ default:
487
+ break;
488
+ }
489
+ return "";
490
+}
491
+
492
+static const char *tulip_tx_state_name(int state)
493
+{
494
+ switch (state) {
495
+ case CSR5_TS_STOPPED:
496
+ return "STOPPED";
497
+
498
+ case CSR5_TS_RUNNING_FETCH:
499
+ return "RUNNING/FETCH";
500
+
501
+ case CSR5_TS_RUNNING_WAIT_EOT:
502
+ return "RUNNING/WAIT EOT";
503
+
504
+ case CSR5_TS_RUNNING_READ_BUF:
505
+ return "RUNNING/READ BUF";
506
+
507
+ case CSR5_TS_RUNNING_SETUP:
508
+ return "RUNNING/SETUP";
509
+
510
+ case CSR5_TS_SUSPENDED:
511
+ return "SUSPENDED";
512
+
513
+ case CSR5_TS_RUNNING_CLOSE:
514
+ return "RUNNING/CLOSE";
515
+
516
+ default:
517
+ break;
518
+ }
519
+ return "";
520
+}
521
+
522
+static void tulip_update_rs(TULIPState *s, int state)
523
+{
524
+ s->csr[5] &= ~(CSR5_RS_MASK << CSR5_RS_SHIFT);
525
+ s->csr[5] |= (state & CSR5_RS_MASK) << CSR5_RS_SHIFT;
526
+ trace_tulip_rx_state(tulip_rx_state_name(state));
527
+}
528
+
529
+static uint16_t tulip_mdi_default[] = {
530
+ /* MDI Registers 0 - 6, 7 */
531
+ 0x3100, 0xf02c, 0x7810, 0x0000, 0x0501, 0x4181, 0x0000, 0x0000,
532
+ /* MDI Registers 8 - 15 */
533
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
534
+ /* MDI Registers 16 - 31 */
535
+ 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
536
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
537
+};
538
+
539
+/* Readonly mask for MDI (PHY) registers */
540
+static const uint16_t tulip_mdi_mask[] = {
541
+ 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
542
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
543
+ 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
544
+ 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
545
+};
546
+
547
+static uint16_t tulip_mii_read(TULIPState *s, int phy, int reg)
548
+{
549
+ uint16_t ret = 0;
550
+ if (phy == 1) {
551
+ ret = tulip_mdi_default[reg];
552
+ }
553
+ trace_tulip_mii_read(phy, reg, ret);
554
+ return ret;
555
+}
556
+
557
+static void tulip_mii_write(TULIPState *s, int phy, int reg, uint16_t data)
558
+{
559
+ trace_tulip_mii_write(phy, reg, data);
560
+
561
+ if (phy != 1) {
562
+ return;
563
+ }
564
+
565
+ tulip_mdi_default[reg] &= ~tulip_mdi_mask[reg];
566
+ tulip_mdi_default[reg] |= (data & tulip_mdi_mask[reg]);
567
+}
568
+
569
+static void tulip_mii(TULIPState *s)
570
+{
571
+ uint32_t changed = s->old_csr9 ^ s->csr[9];
572
+ uint16_t data;
573
+ int op, phy, reg;
574
+
575
+ if (!(changed & CSR9_MDC)) {
576
+ return;
577
+ }
578
+
579
+ if (!(s->csr[9] & CSR9_MDC)) {
580
+ return;
581
+ }
582
+
583
+ s->mii_bitcnt++;
584
+ s->mii_word <<= 1;
585
+
586
+ if (s->csr[9] & CSR9_MDO && (s->mii_bitcnt < 16 ||
587
+ !(s->csr[9] & CSR9_MII))) {
588
+ /* write op or address bits */
589
+ s->mii_word |= 1;
590
+ }
591
+
592
+ if (s->mii_bitcnt >= 16 && (s->csr[9] & CSR9_MII)) {
593
+ if (s->mii_word & 0x8000) {
594
+ s->csr[9] |= CSR9_MDI;
595
+ } else {
596
+ s->csr[9] &= ~CSR9_MDI;
597
+ }
598
+ }
599
+
600
+ if (s->mii_word == 0xffffffff) {
601
+ s->mii_bitcnt = 0;
602
+ } else if (s->mii_bitcnt == 16) {
603
+ op = (s->mii_word >> 12) & 0x0f;
604
+ phy = (s->mii_word >> 7) & 0x1f;
605
+ reg = (s->mii_word >> 2) & 0x1f;
606
+
607
+ if (op == 6) {
608
+ s->mii_word = tulip_mii_read(s, phy, reg);
609
+ }
610
+ } else if (s->mii_bitcnt == 32) {
611
+ op = (s->mii_word >> 28) & 0x0f;
612
+ phy = (s->mii_word >> 23) & 0x1f;
613
+ reg = (s->mii_word >> 18) & 0x1f;
614
+ data = s->mii_word & 0xffff;
615
+
616
+ if (op == 5) {
617
+ tulip_mii_write(s, phy, reg, data);
618
+ }
619
+ }
620
+}
621
+
622
+static uint32_t tulip_csr9_read(TULIPState *s)
623
+{
624
+ if (s->csr[9] & CSR9_SR) {
625
+ if (eeprom93xx_read(s->eeprom)) {
626
+ s->csr[9] |= CSR9_SR_DO;
627
+ } else {
628
+ s->csr[9] &= ~CSR9_SR_DO;
629
+ }
630
+ }
631
+
632
+ tulip_mii(s);
633
+ return s->csr[9];
634
+}
635
+
636
+static void tulip_update_ts(TULIPState *s, int state)
637
+{
638
+ s->csr[5] &= ~(CSR5_TS_MASK << CSR5_TS_SHIFT);
639
+ s->csr[5] |= (state & CSR5_TS_MASK) << CSR5_TS_SHIFT;
640
+ trace_tulip_tx_state(tulip_tx_state_name(state));
641
+}
642
+
643
+static uint64_t tulip_read(void *opaque, hwaddr addr,
644
+ unsigned size)
645
+{
646
+ TULIPState *s = opaque;
647
+ uint64_t data = 0;
648
+
649
+ switch (addr) {
650
+ case CSR(9):
651
+ data = tulip_csr9_read(s);
652
+ break;
653
+
654
+ case CSR(12):
655
+ /* Fake autocompletion complete until we have PHY emulation */
656
+ data = 5 << CSR12_ANS_SHIFT;
657
+ break;
658
+
659
+ default:
660
+ if (addr & 7) {
661
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: read access at unknown address"
662
+ " 0x%"PRIx64"\n", __func__, addr);
663
+ } else {
664
+ data = s->csr[addr >> 3];
665
+ }
666
+ break;
667
+ }
668
+ trace_tulip_reg_read(addr, tulip_reg_name(addr), size, data);
669
+ return data;
670
+}
671
+
672
+static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
673
+{
674
+ if (s->tx_frame_len) {
675
+ if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) {
676
+ /* Internal or external Loopback */
677
+ tulip_receive(s, s->tx_frame, s->tx_frame_len);
678
+ } else {
679
+ qemu_send_packet(qemu_get_queue(s->nic),
680
+ s->tx_frame, s->tx_frame_len);
681
+ }
682
+ }
683
+
684
+ if (desc->control & TDES1_IC) {
685
+ s->csr[5] |= CSR5_TI;
686
+ tulip_update_int(s);
687
+ }
688
+}
689
+
690
+static void tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
691
+{
692
+ int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
693
+ int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
694
+
695
+ if (len1) {
696
+ pci_dma_read(&s->dev, desc->buf_addr1,
697
+ s->tx_frame + s->tx_frame_len, len1);
698
+ s->tx_frame_len += len1;
699
+ }
700
+
701
+ if (len2) {
702
+ pci_dma_read(&s->dev, desc->buf_addr2,
703
+ s->tx_frame + s->tx_frame_len, len2);
704
+ s->tx_frame_len += len2;
705
+ }
706
+ desc->status = (len1 + len2) ? 0 : 0x7fffffff;
707
+}
708
+
709
+static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n)
710
+{
711
+ int offset = n * 12;
712
+
713
+ s->filter[n][0] = buf[offset];
714
+ s->filter[n][1] = buf[offset + 1];
715
+
716
+ s->filter[n][2] = buf[offset + 4];
717
+ s->filter[n][3] = buf[offset + 5];
718
+
719
+ s->filter[n][4] = buf[offset + 8];
720
+ s->filter[n][5] = buf[offset + 9];
721
+
722
+ trace_tulip_setup_filter(n, s->filter[n][5], s->filter[n][4],
723
+ s->filter[n][3], s->filter[n][2], s->filter[n][1], s->filter[n][0]);
724
+}
725
+
726
+static void tulip_setup_frame(TULIPState *s,
727
+ struct tulip_descriptor *desc)
728
+{
729
+ uint8_t buf[4096];
730
+ int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
731
+ int i;
732
+
733
+ trace_tulip_setup_frame();
734
+
735
+ if (len == 192) {
736
+ pci_dma_read(&s->dev, desc->buf_addr1, buf, len);
737
+ for (i = 0; i < 16; i++) {
738
+ tulip_setup_filter_addr(s, buf, i);
739
+ }
740
+ }
741
+
742
+ desc->status = 0x7fffffff;
743
+
744
+ if (desc->control & TDES1_IC) {
745
+ s->csr[5] |= CSR5_TI;
746
+ tulip_update_int(s);
747
+ }
748
+}
749
+
750
+static void tulip_next_tx_descriptor(TULIPState *s,
751
+ struct tulip_descriptor *desc)
752
+{
753
+ if (desc->control & TDES1_TER) {
754
+ s->current_tx_desc = s->csr[4];
755
+ } else if (desc->control & TDES1_TCH) {
756
+ s->current_tx_desc = desc->buf_addr2;
757
+ } else {
758
+ s->current_tx_desc += sizeof(struct tulip_descriptor) +
759
+ (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2);
760
+ }
761
+ s->current_tx_desc &= ~3ULL;
762
+}
763
+
764
+static uint32_t tulip_ts(TULIPState *s)
765
+{
766
+ return (s->csr[5] >> CSR5_TS_SHIFT) & CSR5_TS_MASK;
767
+}
768
+
769
+static void tulip_xmit_list_update(TULIPState *s)
770
+{
771
+ struct tulip_descriptor desc;
772
+
773
+ if (tulip_ts(s) != CSR5_TS_SUSPENDED) {
774
+ return;
775
+ }
776
+
777
+ for (;;) {
778
+ tulip_desc_read(s, s->current_tx_desc, &desc);
779
+ tulip_dump_tx_descriptor(s, &desc);
780
+
781
+ if (!(desc.status & TDES0_OWN)) {
782
+ tulip_update_ts(s, CSR5_TS_SUSPENDED);
783
+ s->csr[5] |= CSR5_TU;
784
+ tulip_update_int(s);
785
+ return;
786
+ }
787
+
788
+ if (desc.control & TDES1_SET) {
789
+ tulip_setup_frame(s, &desc);
790
+ } else {
791
+ if (desc.control & TDES1_FS) {
792
+ s->tx_frame_len = 0;
793
+ }
794
+
795
+ tulip_copy_tx_buffers(s, &desc);
796
+
797
+ if (desc.control & TDES1_LS) {
798
+ tulip_tx(s, &desc);
799
+ }
800
+ }
801
+ tulip_desc_write(s, s->current_tx_desc, &desc);
802
+ tulip_next_tx_descriptor(s, &desc);
803
+ }
804
+}
805
+
806
+static void tulip_csr9_write(TULIPState *s, uint32_t old_val,
807
+ uint32_t new_val)
808
+{
809
+ if (new_val & CSR9_SR) {
810
+ eeprom93xx_write(s->eeprom,
811
+ !!(new_val & CSR9_SR_CS),
812
+ !!(new_val & CSR9_SR_SK),
813
+ !!(new_val & CSR9_SR_DI));
814
+ }
815
+}
816
+
817
+static void tulip_reset(TULIPState *s)
818
+{
819
+ trace_tulip_reset();
820
+
821
+ s->csr[0] = 0xfe000000;
822
+ s->csr[1] = 0xffffffff;
823
+ s->csr[2] = 0xffffffff;
824
+ s->csr[5] = 0xf0000000;
825
+ s->csr[6] = 0x32000040;
826
+ s->csr[7] = 0xf3fe0000;
827
+ s->csr[8] = 0xe0000000;
828
+ s->csr[9] = 0xfff483ff;
829
+ s->csr[11] = 0xfffe0000;
830
+ s->csr[12] = 0x000000c6;
831
+ s->csr[13] = 0xffff0000;
832
+ s->csr[14] = 0xffffffff;
833
+ s->csr[15] = 0x8ff00000;
834
+}
835
+
836
+static void tulip_qdev_reset(DeviceState *dev)
837
+{
838
+ PCIDevice *d = PCI_DEVICE(dev);
839
+ TULIPState *s = TULIP(d);
840
+
841
+ tulip_reset(s);
842
+}
843
+
844
+static void tulip_write(void *opaque, hwaddr addr,
845
+ uint64_t data, unsigned size)
846
+{
847
+ TULIPState *s = opaque;
848
+ trace_tulip_reg_write(addr, tulip_reg_name(addr), size, data);
849
+
850
+ switch (addr) {
851
+ case CSR(0):
852
+ s->csr[0] = data;
853
+ if (data & CSR0_SWR) {
854
+ tulip_reset(s);
855
+ tulip_update_int(s);
856
+ }
857
+ break;
858
+
859
+ case CSR(1):
860
+ tulip_xmit_list_update(s);
861
+ break;
862
+
863
+ case CSR(2):
864
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
865
+ break;
866
+
867
+ case CSR(3):
868
+ s->csr[3] = data & ~3ULL;
869
+ s->current_rx_desc = s->csr[3];
870
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
871
+ break;
872
+
873
+ case CSR(4):
874
+ s->csr[4] = data & ~3ULL;
875
+ s->current_tx_desc = s->csr[4];
876
+ tulip_xmit_list_update(s);
877
+ break;
878
+
879
+ case CSR(5):
880
+ /* Status register, write clears bit */
881
+ s->csr[5] &= ~(data & (CSR5_TI | CSR5_TPS | CSR5_TU | CSR5_TJT |
882
+ CSR5_LNP_ANC | CSR5_UNF | CSR5_RI | CSR5_RU |
883
+ CSR5_RPS | CSR5_RWT | CSR5_ETI | CSR5_GTE |
884
+ CSR5_LNF | CSR5_FBE | CSR5_ERI | CSR5_AIS |
885
+ CSR5_NIS | CSR5_GPI | CSR5_LC));
886
+ tulip_update_int(s);
887
+ break;
888
+
889
+ case CSR(6):
890
+ s->csr[6] = data;
891
+ if (s->csr[6] & CSR6_SR) {
892
+ tulip_update_rs(s, CSR5_RS_RUNNING_WAIT_RECEIVE);
893
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
894
+ } else {
895
+ tulip_update_rs(s, CSR5_RS_STOPPED);
896
+ }
897
+
898
+ if (s->csr[6] & CSR6_ST) {
899
+ tulip_update_ts(s, CSR5_TS_SUSPENDED);
900
+ tulip_xmit_list_update(s);
901
+ } else {
902
+ tulip_update_ts(s, CSR5_TS_STOPPED);
903
+ }
904
+ break;
905
+
906
+ case CSR(7):
907
+ s->csr[7] = data;
908
+ tulip_update_int(s);
909
+ break;
910
+
911
+ case CSR(8):
912
+ s->csr[9] = data;
913
+ break;
914
+
915
+ case CSR(9):
916
+ tulip_csr9_write(s, s->csr[9], data);
917
+ /* don't clear MII read data */
918
+ s->csr[9] &= CSR9_MDI;
919
+ s->csr[9] |= (data & ~CSR9_MDI);
920
+ tulip_mii(s);
921
+ s->old_csr9 = s->csr[9];
922
+ break;
923
+
924
+ case CSR(10):
925
+ s->csr[10] = data;
926
+ break;
927
+
928
+ case CSR(11):
929
+ s->csr[11] = data;
930
+ break;
931
+
932
+ case CSR(12):
933
+ /* SIA Status register, some bits are cleared by writing 1 */
934
+ s->csr[12] &= ~(data & (CSR12_MRA | CSR12_TRA | CSR12_ARA));
935
+ break;
936
+
937
+ case CSR(13):
938
+ s->csr[13] = data;
939
+ break;
940
+
941
+ case CSR(14):
942
+ s->csr[14] = data;
943
+ break;
944
+
945
+ case CSR(15):
946
+ s->csr[15] = data;
947
+ break;
948
+
949
+ default:
950
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write to CSR at unknown address "
951
+ "0x%"PRIx64"\n", __func__, addr);
952
+ break;
953
+ }
954
+}
955
+
956
+static const MemoryRegionOps tulip_ops = {
957
+ .read = tulip_read,
958
+ .write = tulip_write,
959
+ .endianness = DEVICE_LITTLE_ENDIAN,
960
+ .impl = {
961
+ .min_access_size = 4,
962
+ .max_access_size = 4,
963
+ },
964
+};
965
+
966
+static void tulip_idblock_crc(TULIPState *s, uint16_t *srom)
967
+{
968
+ int word, n;
969
+ char bit;
970
+ unsigned char bitval, crc;
971
+ const int len = 9;
972
+ n = 0;
973
+ crc = -1;
974
+
975
+ for (word = 0; word < len; word++) {
976
+ for (bit = 15; bit >= 0; bit--) {
977
+ if ((word == (len - 1)) && (bit == 7)) {
978
+ /*
979
+ * Insert the correct CRC result into input data stream
980
+ * in place.
981
+ */
982
+ srom[len - 1] = (srom[len - 1] & 0xff00) | (unsigned short)crc;
983
+ break;
984
+ }
985
+ n++;
986
+ bitval = ((srom[word] >> bit) & 1) ^ ((crc >> 7) & 1);
987
+ crc = crc << 1;
988
+ if (bitval == 1) {
989
+ crc ^= 6;
990
+ crc |= 0x01;
991
+ }
992
+ }
993
+ }
994
+}
995
+
996
+static uint16_t tulip_srom_crc(TULIPState *s, uint8_t *eeprom, size_t len)
997
+{
998
+ unsigned long crc = 0xffffffff;
999
+ unsigned long flippedcrc = 0;
1000
+ unsigned char currentbyte;
1001
+ unsigned int msb, bit, i;
1002
+
1003
+ for (i = 0; i < len; i++) {
1004
+ currentbyte = eeprom[i];
1005
+ for (bit = 0; bit < 8; bit++) {
1006
+ msb = (crc >> 31) & 1;
1007
+ crc <<= 1;
1008
+ if (msb ^ (currentbyte & 1)) {
1009
+ crc ^= 0x04c11db6;
1010
+ crc |= 0x00000001;
1011
+ }
1012
+ currentbyte >>= 1;
1013
+ }
1014
+ }
1015
+
1016
+ for (i = 0; i < 32; i++) {
1017
+ flippedcrc <<= 1;
1018
+ bit = crc & 1;
1019
+ crc >>= 1;
1020
+ flippedcrc += bit;
1021
+ }
1022
+ return (flippedcrc ^ 0xffffffff) & 0xffff;
1023
+}
1024
+
1025
+static const uint8_t eeprom_default[128] = {
1026
+ 0x3c, 0x10, 0x4f, 0x10, 0x00, 0x00, 0x00, 0x00,
1027
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1028
+ 0x56, 0x08, 0x04, 0x01, 0x00, 0x80, 0x48, 0xb3,
1029
+ 0x0e, 0xa7, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08,
1030
+ 0x01, 0x8d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x78,
1031
+ 0xe0, 0x01, 0x00, 0x50, 0x00, 0x18, 0x00, 0x00,
1032
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1033
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1034
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1035
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1036
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1037
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x6b,
1038
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1039
+ 0x48, 0xb3, 0x0e, 0xa7, 0x40, 0x00, 0x00, 0x00,
1040
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1041
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042
+};
1043
+
1044
+static void tulip_fill_eeprom(TULIPState *s)
1045
+{
1046
+ uint16_t *eeprom = eeprom93xx_data(s->eeprom);
1047
+ memcpy(eeprom, eeprom_default, 128);
1048
+
1049
+ /* patch in our mac address */
1050
+ eeprom[10] = cpu_to_le16(s->c.macaddr.a[0] | (s->c.macaddr.a[1] << 8));
1051
+ eeprom[11] = cpu_to_le16(s->c.macaddr.a[2] | (s->c.macaddr.a[3] << 8));
1052
+ eeprom[12] = cpu_to_le16(s->c.macaddr.a[4] | (s->c.macaddr.a[5] << 8));
1053
+ tulip_idblock_crc(s, eeprom);
1054
+ eeprom[63] = cpu_to_le16(tulip_srom_crc(s, (uint8_t *)eeprom, 126));
1055
+}
1056
+
1057
+static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp)
1058
+{
1059
+ TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev);
1060
+ uint8_t *pci_conf;
1061
+
1062
+ pci_conf = s->dev.config;
1063
+ pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
1064
+
1065
+ s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64);
1066
+ tulip_fill_eeprom(s);
1067
+
1068
+ memory_region_init_io(&s->io, OBJECT(&s->dev), &tulip_ops, s,
1069
+ "tulip-io", 128);
1070
+
1071
+ memory_region_init_io(&s->memory, OBJECT(&s->dev), &tulip_ops, s,
1072
+ "tulip-mem", 128);
1073
+
1074
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
1075
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memory);
1076
+
1077
+ s->irq = pci_allocate_irq(&s->dev);
1078
+
1079
+ qemu_macaddr_default_if_unset(&s->c.macaddr);
1080
+
1081
+ s->nic = qemu_new_nic(&net_tulip_info, &s->c,
1082
+ object_get_typename(OBJECT(pci_dev)),
1083
+ pci_dev->qdev.id, s);
1084
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
1085
+}
1086
+
1087
+static void pci_tulip_exit(PCIDevice *pci_dev)
1088
+{
1089
+ TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev);
1090
+
1091
+ qemu_del_nic(s->nic);
1092
+ qemu_free_irq(s->irq);
1093
+ eeprom93xx_free(&pci_dev->qdev, s->eeprom);
1094
+}
1095
+
1096
+static void tulip_instance_init(Object *obj)
1097
+{
1098
+ PCIDevice *pci_dev = PCI_DEVICE(obj);
1099
+ TULIPState *d = DO_UPCAST(TULIPState, dev, pci_dev);
1100
+
1101
+ device_add_bootindex_property(obj, &d->c.bootindex,
1102
+ "bootindex", "/ethernet-phy@0",
1103
+ &pci_dev->qdev, NULL);
1104
+}
1105
+
1106
+static Property tulip_properties[] = {
1107
+ DEFINE_NIC_PROPERTIES(TULIPState, c),
1108
+ DEFINE_PROP_END_OF_LIST(),
1109
+};
1110
+
1111
+static void tulip_class_init(ObjectClass *klass, void *data)
1112
+{
1113
+ DeviceClass *dc = DEVICE_CLASS(klass);
1114
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1115
+
1116
+ k->realize = pci_tulip_realize;
1117
+ k->exit = pci_tulip_exit;
1118
+ k->vendor_id = PCI_VENDOR_ID_DEC;
1119
+ k->device_id = PCI_DEVICE_ID_DEC_21143;
1120
+ k->subsystem_vendor_id = 0x103c;
1121
+ k->subsystem_id = 0x104f;
1122
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1123
+ dc->vmsd = &vmstate_pci_tulip;
1124
+ dc->props = tulip_properties;
1125
+ dc->reset = tulip_qdev_reset;
1126
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1127
+}
1128
+
1129
+static const TypeInfo tulip_info = {
1130
+ .name = TYPE_TULIP,
1131
+ .parent = TYPE_PCI_DEVICE,
1132
+ .instance_size = sizeof(TULIPState),
1133
+ .class_init = tulip_class_init,
1134
+ .instance_init = tulip_instance_init,
1135
+ .interfaces = (InterfaceInfo[]) {
1136
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1137
+ { },
1138
+ },
1139
+};
1140
+
1141
+static void tulip_register_types(void)
1142
+{
1143
+ type_register_static(&tulip_info);
1144
+}
1145
+
1146
+type_init(tulip_register_types)
1147
diff --git a/hw/net/tulip.h b/hw/net/tulip.h
1148
new file mode 100644
1149
index XXXXXXX..XXXXXXX
1150
--- /dev/null
1151
+++ b/hw/net/tulip.h
1152
@@ -XXX,XX +XXX,XX @@
1153
+#ifndef HW_TULIP_H
1154
+#define HW_TULIP_H
1155
+
1156
+#include "qemu/units.h"
1157
+#include "net/net.h"
1158
+
1159
+#define TYPE_TULIP "tulip"
1160
+#define TULIP(obj) OBJECT_CHECK(TULIPState, (obj), TYPE_TULIP)
1161
+
1162
+#define CSR(_x) ((_x) << 3)
1163
+
1164
+#define CSR0_SWR BIT(0)
1165
+#define CSR0_BAR BIT(1)
1166
+#define CSR0_DSL_SHIFT 2
1167
+#define CSR0_DSL_MASK 0x1f
1168
+#define CSR0_BLE BIT(7)
1169
+#define CSR0_PBL_SHIFT 8
1170
+#define CSR0_PBL_MASK 0x3f
1171
+#define CSR0_CAC_SHIFT 14
1172
+#define CSR0_CAC_MASK 0x3
1173
+#define CSR0_DAS 0x10000
1174
+#define CSR0_TAP_SHIFT 17
1175
+#define CSR0_TAP_MASK 0x7
1176
+#define CSR0_DBO 0x100000
1177
+#define CSR1_TPD 0x01
1178
+#define CSR0_RLE BIT(23)
1179
+#define CSR0_WIE BIT(24)
1180
+
1181
+#define CSR2_RPD 0x01
1182
+
1183
+#define CSR5_TI BIT(0)
1184
+#define CSR5_TPS BIT(1)
1185
+#define CSR5_TU BIT(2)
1186
+#define CSR5_TJT BIT(3)
1187
+#define CSR5_LNP_ANC BIT(4)
1188
+#define CSR5_UNF BIT(5)
1189
+#define CSR5_RI BIT(6)
1190
+#define CSR5_RU BIT(7)
1191
+#define CSR5_RPS BIT(8)
1192
+#define CSR5_RWT BIT(9)
1193
+#define CSR5_ETI BIT(10)
1194
+#define CSR5_GTE BIT(11)
1195
+#define CSR5_LNF BIT(12)
1196
+#define CSR5_FBE BIT(13)
1197
+#define CSR5_ERI BIT(14)
1198
+#define CSR5_AIS BIT(15)
1199
+#define CSR5_NIS BIT(16)
1200
+#define CSR5_RS_SHIFT 17
1201
+#define CSR5_RS_MASK 7
1202
+#define CSR5_TS_SHIFT 20
1203
+#define CSR5_TS_MASK 7
1204
+
1205
+#define CSR5_TS_STOPPED 0
1206
+#define CSR5_TS_RUNNING_FETCH 1
1207
+#define CSR5_TS_RUNNING_WAIT_EOT 2
1208
+#define CSR5_TS_RUNNING_READ_BUF 3
1209
+#define CSR5_TS_RUNNING_SETUP 5
1210
+#define CSR5_TS_SUSPENDED 6
1211
+#define CSR5_TS_RUNNING_CLOSE 7
1212
+
1213
+#define CSR5_RS_STOPPED 0
1214
+#define CSR5_RS_RUNNING_FETCH 1
1215
+#define CSR5_RS_RUNNING_CHECK_EOR 2
1216
+#define CSR5_RS_RUNNING_WAIT_RECEIVE 3
1217
+#define CSR5_RS_SUSPENDED 4
1218
+#define CSR5_RS_RUNNING_CLOSE 5
1219
+#define CSR5_RS_RUNNING_FLUSH 6
1220
+#define CSR5_RS_RUNNING_QUEUE 7
1221
+
1222
+#define CSR5_EB_SHIFT 23
1223
+#define CSR5_EB_MASK 7
1224
+
1225
+#define CSR5_GPI BIT(26)
1226
+#define CSR5_LC BIT(27)
1227
+
1228
+#define CSR6_HP BIT(0)
1229
+#define CSR6_SR BIT(1)
1230
+#define CSR6_HO BIT(2)
1231
+#define CSR6_PB BIT(3)
1232
+#define CSR6_IF BIT(4)
1233
+#define CSR6_SB BIT(5)
1234
+#define CSR6_PR BIT(6)
1235
+#define CSR6_PM BIT(7)
1236
+#define CSR6_FKD BIT(8)
1237
+#define CSR6_FD BIT(9)
1238
+
1239
+#define CSR6_OM_SHIFT 10
1240
+#define CSR6_OM_MASK 3
1241
+#define CSR6_OM_NORMAL 0
1242
+#define CSR6_OM_INT_LOOPBACK 1
1243
+#define CSR6_OM_EXT_LOOPBACK 2
1244
+
1245
+#define CSR6_FC BIT(12)
1246
+#define CSR6_ST BIT(13)
1247
+
1248
+
1249
+#define CSR6_TR_SHIFT 14
1250
+#define CSR6_TR_MASK 3
1251
+#define CSR6_TR_72 0
1252
+#define CSR6_TR_96 1
1253
+#define CSR6_TR_128 2
1254
+#define CSR6_TR_160 3
1255
+
1256
+#define CSR6_CA BIT(17)
1257
+#define CSR6_RA BIT(30)
1258
+#define CSR6_SC BIT(31)
1259
+
1260
+#define CSR7_TIM BIT(0)
1261
+#define CSR7_TSM BIT(1)
1262
+#define CSR7_TUM BIT(2)
1263
+#define CSR7_TJM BIT(3)
1264
+#define CSR7_LPM BIT(4)
1265
+#define CSR7_UNM BIT(5)
1266
+#define CSR7_RIM BIT(6)
1267
+#define CSR7_RUM BIT(7)
1268
+#define CSR7_RSM BIT(8)
1269
+#define CSR7_RWM BIT(9)
1270
+#define CSR7_TMM BIT(11)
1271
+#define CSR7_LFM BIT(12)
1272
+#define CSR7_SEM BIT(13)
1273
+#define CSR7_ERM BIT(14)
1274
+#define CSR7_AIM BIT(15)
1275
+#define CSR7_NIM BIT(16)
1276
+
1277
+#define CSR8_MISSED_FRAME_OVL BIT(16)
1278
+#define CSR8_MISSED_FRAME_CNT_MASK 0xffff
1279
+
1280
+#define CSR9_DATA_MASK 0xff
1281
+#define CSR9_SR_CS BIT(0)
1282
+#define CSR9_SR_SK BIT(1)
1283
+#define CSR9_SR_DI BIT(2)
1284
+#define CSR9_SR_DO BIT(3)
1285
+#define CSR9_REG BIT(10)
1286
+#define CSR9_SR BIT(11)
1287
+#define CSR9_BR BIT(12)
1288
+#define CSR9_WR BIT(13)
1289
+#define CSR9_RD BIT(14)
1290
+#define CSR9_MOD BIT(15)
1291
+#define CSR9_MDC BIT(16)
1292
+#define CSR9_MDO BIT(17)
1293
+#define CSR9_MII BIT(18)
1294
+#define CSR9_MDI BIT(19)
1295
+
1296
+#define CSR11_CON BIT(16)
1297
+#define CSR11_TIMER_MASK 0xffff
1298
+
1299
+#define CSR12_MRA BIT(0)
1300
+#define CSR12_LS100 BIT(1)
1301
+#define CSR12_LS10 BIT(2)
1302
+#define CSR12_APS BIT(3)
1303
+#define CSR12_ARA BIT(8)
1304
+#define CSR12_TRA BIT(9)
1305
+#define CSR12_NSN BIT(10)
1306
+#define CSR12_TRF BIT(11)
1307
+#define CSR12_ANS_SHIFT 12
1308
+#define CSR12_ANS_MASK 7
1309
+#define CSR12_LPN BIT(15)
1310
+#define CSR12_LPC_SHIFT 16
1311
+#define CSR12_LPC_MASK 0xffff
1312
+
1313
+#define CSR13_SRL BIT(0)
1314
+#define CSR13_CAC BIT(2)
1315
+#define CSR13_AUI BIT(3)
1316
+#define CSR13_SDM_SHIFT 4
1317
+#define CSR13_SDM_MASK 0xfff
1318
+
1319
+#define CSR14_ECEN BIT(0)
1320
+#define CSR14_LBK BIT(1)
1321
+#define CSR14_DREN BIT(2)
1322
+#define CSR14_LSE BIT(3)
1323
+#define CSR14_CPEN_SHIFT 4
1324
+#define CSR14_CPEN_MASK 3
1325
+#define CSR14_MBO BIT(6)
1326
+#define CSR14_ANE BIT(7)
1327
+#define CSR14_RSQ BIT(8)
1328
+#define CSR14_CSQ BIT(9)
1329
+#define CSR14_CLD BIT(10)
1330
+#define CSR14_SQE BIT(11)
1331
+#define CSR14_LTE BIT(12)
1332
+#define CSR14_APE BIT(13)
1333
+#define CSR14_SPP BIT(14)
1334
+#define CSR14_TAS BIT(15)
1335
+
1336
+#define CSR15_JBD BIT(0)
1337
+#define CSR15_HUJ BIT(1)
1338
+#define CSR15_JCK BIT(2)
1339
+#define CSR15_ABM BIT(3)
1340
+#define CSR15_RWD BIT(4)
1341
+#define CSR15_RWR BIT(5)
1342
+#define CSR15_LE1 BIT(6)
1343
+#define CSR15_LV1 BIT(7)
1344
+#define CSR15_TSCK BIT(8)
1345
+#define CSR15_FUSQ BIT(9)
1346
+#define CSR15_FLF BIT(10)
1347
+#define CSR15_LSD BIT(11)
1348
+#define CSR15_DPST BIT(12)
1349
+#define CSR15_FRL BIT(13)
1350
+#define CSR15_LE2 BIT(14)
1351
+#define CSR15_LV2 BIT(15)
1352
+
1353
+#define RDES0_OF BIT(0)
1354
+#define RDES0_CE BIT(1)
1355
+#define RDES0_DB BIT(2)
1356
+#define RDES0_RJ BIT(4)
1357
+#define RDES0_FT BIT(5)
1358
+#define RDES0_CS BIT(6)
1359
+#define RDES0_TL BIT(7)
1360
+#define RDES0_LS BIT(8)
1361
+#define RDES0_FS BIT(9)
1362
+#define RDES0_MF BIT(10)
1363
+#define RDES0_RF BIT(11)
1364
+#define RDES0_DT_SHIFT 12
1365
+#define RDES0_DT_MASK 3
1366
+#define RDES0_LE BIT(14)
1367
+#define RDES0_ES BIT(15)
1368
+#define RDES0_FL_SHIFT 16
1369
+#define RDES0_FL_MASK 0x3fff
1370
+#define RDES0_FF BIT(30)
1371
+#define RDES0_OWN BIT(31)
1372
+
1373
+#define RDES1_BUF1_SIZE_SHIFT 0
1374
+#define RDES1_BUF1_SIZE_MASK 0x7ff
1375
+
1376
+#define RDES1_BUF2_SIZE_SHIFT 11
1377
+#define RDES1_BUF2_SIZE_MASK 0x7ff
1378
+#define RDES1_RCH BIT(24)
1379
+#define RDES1_RER BIT(25)
1380
+
1381
+#define TDES0_DE BIT(0)
1382
+#define TDES0_UF BIT(1)
1383
+#define TDES0_LF BIT(2)
1384
+#define TDES0_CC_SHIFT 3
1385
+#define TDES0_CC_MASK 0xf
1386
+#define TDES0_HF BIT(7)
1387
+#define TDES0_EC BIT(8)
1388
+#define TDES0_LC BIT(9)
1389
+#define TDES0_NC BIT(10)
1390
+#define TDES0_LO BIT(11)
1391
+#define TDES0_TO BIT(14)
1392
+#define TDES0_ES BIT(15)
1393
+#define TDES0_OWN BIT(31)
1394
+
1395
+#define TDES1_BUF1_SIZE_SHIFT 0
1396
+#define TDES1_BUF1_SIZE_MASK 0x7ff
1397
+
1398
+#define TDES1_BUF2_SIZE_SHIFT 11
1399
+#define TDES1_BUF2_SIZE_MASK 0x7ff
1400
+
1401
+#define TDES1_FT0 BIT(22)
1402
+#define TDES1_DPD BIT(23)
1403
+#define TDES1_TCH BIT(24)
1404
+#define TDES1_TER BIT(25)
1405
+#define TDES1_AC BIT(26)
1406
+#define TDES1_SET BIT(27)
1407
+#define TDES1_FT1 BIT(28)
1408
+#define TDES1_FS BIT(29)
1409
+#define TDES1_LS BIT(30)
1410
+#define TDES1_IC BIT(31)
1411
+
1412
+struct tulip_descriptor {
1413
+ uint32_t status;
1414
+ uint32_t control;
1415
+ uint32_t buf_addr1;
1416
+ uint32_t buf_addr2;
1417
+};
1418
+
1419
+#endif
1420
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
1421
index XXXXXXX..XXXXXXX 100644
1422
--- a/include/hw/pci/pci_ids.h
1423
+++ b/include/hw/pci/pci_ids.h
1424
@@ -XXX,XX +XXX,XX @@
1425
#define PCI_DEVICE_ID_LSI_SAS0079 0x0079
1426
1427
#define PCI_VENDOR_ID_DEC 0x1011
1428
+#define PCI_DEVICE_ID_DEC_21143 0x0019
1429
#define PCI_DEVICE_ID_DEC_21154 0x0026
1430
1431
#define PCI_VENDOR_ID_CIRRUS 0x1013
1432
--
34
--
1433
2.5.0
35
2.7.4
1434
36
1435
37
diff view generated by jsdifflib
1
From: Fan Yang <Fan_Yang@sjtu.edu.cn>
1
From: Keqian Zhu <zhukeqian1@huawei.com>
2
2
3
'colo_mark_tcp_pkt' should return 'true' when packets are the same, and
3
Fixes: 63c4db4c2e6d (net: relocate paths to helpers and scripts)
4
'false' otherwise. However, it returns 'true' when
4
Signed-off-by: Keqian Zhu <zhukeqian1@huawei.com>
5
'colo_compare_packet_payload' returns non-zero while
6
'colo_compare_packet_payload' is just a 'memcmp'. The result is that
7
COLO-compare reports inconsistent TCP packets when they are actually
8
the same.
9
10
Fixes: f449c9e549c ("colo: compare the packet based on the tcp sequence number")
11
Cc: qemu-stable@nongnu.org
12
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
13
Signed-off-by: Fan Yang <Fan_Yang@sjtu.edu.cn>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
---
6
---
16
net/colo-compare.c | 6 +++---
7
net/tap.c | 3 ++-
17
1 file changed, 3 insertions(+), 3 deletions(-)
8
1 file changed, 2 insertions(+), 1 deletion(-)
18
9
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
10
diff --git a/net/tap.c b/net/tap.c
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
12
--- a/net/tap.c
22
+++ b/net/colo-compare.c
13
+++ b/net/tap.c
23
@@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
14
@@ -XXX,XX +XXX,XX @@ free_fail:
24
*mark = 0;
15
script = default_script = get_relocated_path(DEFAULT_NETWORK_SCRIPT);
25
16
}
26
if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
17
if (!downscript) {
27
- if (colo_compare_packet_payload(ppkt, spkt,
18
- downscript = default_downscript = get_relocated_path(DEFAULT_NETWORK_SCRIPT);
28
+ if (!colo_compare_packet_payload(ppkt, spkt,
19
+ downscript = default_downscript =
29
ppkt->header_size, spkt->header_size,
20
+ get_relocated_path(DEFAULT_NETWORK_DOWN_SCRIPT);
30
ppkt->payload_size)) {
21
}
31
*mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
22
32
@@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
23
if (tap->has_ifname) {
33
34
/* one part of secondary packet payload still need to be compared */
35
if (!after(ppkt->seq_end, spkt->seq_end)) {
36
- if (colo_compare_packet_payload(ppkt, spkt,
37
+ if (!colo_compare_packet_payload(ppkt, spkt,
38
ppkt->header_size + ppkt->offset,
39
spkt->header_size + spkt->offset,
40
ppkt->payload_size - ppkt->offset)) {
41
@@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
42
/* primary packet is longer than secondary packet, compare
43
* the same part and mark the primary packet offset
44
*/
45
- if (colo_compare_packet_payload(ppkt, spkt,
46
+ if (!colo_compare_packet_payload(ppkt, spkt,
47
ppkt->header_size + ppkt->offset,
48
spkt->header_size + spkt->offset,
49
spkt->payload_size - spkt->offset)) {
50
--
24
--
51
2.5.0
25
2.7.4
52
26
53
27
diff view generated by jsdifflib