]>
Commit | Line | Data |
---|---|---|
7c375e22 DF |
1 | /* |
2 | * QTest testcase for e1000e NIC | |
3 | * | |
4 | * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com) | |
5 | * Developed by Daynix Computing LTD (http://www.daynix.com) | |
6 | * | |
7 | * Authors: | |
8 | * Dmitry Fleytman <dmitry@daynix.com> | |
9 | * Leonid Bloch <leonid@daynix.com> | |
10 | * Yan Vugenfirer <yan@daynix.com> | |
11 | * | |
12 | * This library is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU Lesser General Public | |
14 | * License as published by the Free Software Foundation; either | |
dc0ad02d | 15 | * version 2.1 of the License, or (at your option) any later version. |
7c375e22 DF |
16 | * |
17 | * This library is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * Lesser General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Lesser General Public | |
23 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
24 | */ | |
25 | ||
26 | ||
27 | #include "qemu/osdep.h" | |
dd210749 | 28 | #include "libqtest-single.h" |
7c375e22 DF |
29 | #include "libqos/pci-pc.h" |
30 | #include "qemu/sockets.h" | |
31 | #include "qemu/iov.h" | |
0b8fa32f | 32 | #include "qemu/module.h" |
7c375e22 | 33 | #include "qemu/bitops.h" |
b243c73c | 34 | #include "libqos/libqos-malloc.h" |
b026393c | 35 | #include "libqos/e1000e.h" |
7c375e22 | 36 | |
b026393c | 37 | static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc) |
7c375e22 DF |
38 | { |
39 | struct { | |
40 | uint64_t buffer_addr; | |
41 | union { | |
42 | uint32_t data; | |
43 | struct { | |
44 | uint16_t length; | |
45 | uint8_t cso; | |
46 | uint8_t cmd; | |
47 | } flags; | |
48 | } lower; | |
49 | union { | |
50 | uint32_t data; | |
51 | struct { | |
52 | uint8_t status; | |
53 | uint8_t css; | |
54 | uint16_t special; | |
55 | } fields; | |
56 | } upper; | |
57 | } descr; | |
58 | ||
59 | static const uint32_t dtyp_data = BIT(20); | |
60 | static const uint32_t dtyp_ext = BIT(29); | |
61 | static const uint32_t dcmd_rs = BIT(27); | |
62 | static const uint32_t dcmd_eop = BIT(24); | |
63 | static const uint32_t dsta_dd = BIT(0); | |
64 | static const int data_len = 64; | |
65 | char buffer[64]; | |
66 | int ret; | |
67 | uint32_t recv_len; | |
68 | ||
69 | /* Prepare test data buffer */ | |
b026393c | 70 | uint64_t data = guest_alloc(alloc, data_len); |
7c375e22 DF |
71 | memwrite(data, "TEST", 5); |
72 | ||
73 | /* Prepare TX descriptor */ | |
74 | memset(&descr, 0, sizeof(descr)); | |
75 | descr.buffer_addr = cpu_to_le64(data); | |
76 | descr.lower.data = cpu_to_le32(dcmd_rs | | |
77 | dcmd_eop | | |
78 | dtyp_ext | | |
79 | dtyp_data | | |
80 | data_len); | |
81 | ||
82 | /* Put descriptor to the ring */ | |
83 | e1000e_tx_ring_push(d, &descr); | |
84 | ||
85 | /* Wait for TX WB interrupt */ | |
86 | e1000e_wait_isr(d, E1000E_TX0_MSG_ID); | |
87 | ||
88 | /* Check DD bit */ | |
89 | g_assert_cmphex(le32_to_cpu(descr.upper.data) & dsta_dd, ==, dsta_dd); | |
90 | ||
91 | /* Check data sent to the backend */ | |
e7b79428 | 92 | ret = recv(test_sockets[0], &recv_len, sizeof(recv_len), 0); |
7c375e22 | 93 | g_assert_cmpint(ret, == , sizeof(recv_len)); |
e7b79428 | 94 | ret = recv(test_sockets[0], buffer, 64, 0); |
380822ed | 95 | g_assert_cmpint(ret, >=, 5); |
7c375e22 DF |
96 | g_assert_cmpstr(buffer, == , "TEST"); |
97 | ||
98 | /* Free test data buffer */ | |
b026393c | 99 | guest_free(alloc, data); |
7c375e22 DF |
100 | } |
101 | ||
b026393c | 102 | static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc) |
7c375e22 DF |
103 | { |
104 | union { | |
105 | struct { | |
106 | uint64_t buffer_addr; | |
107 | uint64_t reserved; | |
108 | } read; | |
109 | struct { | |
110 | struct { | |
111 | uint32_t mrq; | |
112 | union { | |
113 | uint32_t rss; | |
114 | struct { | |
115 | uint16_t ip_id; | |
116 | uint16_t csum; | |
117 | } csum_ip; | |
118 | } hi_dword; | |
119 | } lower; | |
120 | struct { | |
121 | uint32_t status_error; | |
122 | uint16_t length; | |
123 | uint16_t vlan; | |
124 | } upper; | |
125 | } wb; | |
126 | } descr; | |
127 | ||
128 | static const uint32_t esta_dd = BIT(0); | |
129 | ||
130 | char test[] = "TEST"; | |
131 | int len = htonl(sizeof(test)); | |
132 | struct iovec iov[] = { | |
133 | { | |
134 | .iov_base = &len, | |
135 | .iov_len = sizeof(len), | |
136 | },{ | |
137 | .iov_base = test, | |
138 | .iov_len = sizeof(test), | |
139 | }, | |
140 | }; | |
141 | ||
142 | static const int data_len = 64; | |
143 | char buffer[64]; | |
144 | int ret; | |
145 | ||
146 | /* Send a dummy packet to device's socket*/ | |
147 | ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test)); | |
148 | g_assert_cmpint(ret, == , sizeof(test) + sizeof(len)); | |
149 | ||
150 | /* Prepare test data buffer */ | |
b026393c | 151 | uint64_t data = guest_alloc(alloc, data_len); |
7c375e22 DF |
152 | |
153 | /* Prepare RX descriptor */ | |
154 | memset(&descr, 0, sizeof(descr)); | |
155 | descr.read.buffer_addr = cpu_to_le64(data); | |
156 | ||
157 | /* Put descriptor to the ring */ | |
158 | e1000e_rx_ring_push(d, &descr); | |
159 | ||
160 | /* Wait for TX WB interrupt */ | |
161 | e1000e_wait_isr(d, E1000E_RX0_MSG_ID); | |
162 | ||
163 | /* Check DD bit */ | |
164 | g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) & | |
165 | esta_dd, ==, esta_dd); | |
166 | ||
167 | /* Check data sent to the backend */ | |
168 | memread(data, buffer, sizeof(buffer)); | |
169 | g_assert_cmpstr(buffer, == , "TEST"); | |
170 | ||
171 | /* Free test data buffer */ | |
b026393c | 172 | guest_free(alloc, data); |
7c375e22 DF |
173 | } |
174 | ||
b026393c | 175 | static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 176 | { |
b026393c | 177 | /* init does nothing */ |
7c375e22 DF |
178 | } |
179 | ||
b026393c | 180 | static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 181 | { |
b026393c EGE |
182 | QE1000E_PCI *e1000e = obj; |
183 | QE1000E *d = &e1000e->e1000e; | |
184 | QOSGraphObject *e_object = obj; | |
185 | QPCIDevice *dev = e_object->get_driver(e_object, "pci-device"); | |
186 | ||
187 | /* FIXME: add spapr support */ | |
188 | if (qpci_check_buggy_msi(dev)) { | |
189 | return; | |
190 | } | |
7c375e22 | 191 | |
b026393c | 192 | e1000e_send_verify(d, data, alloc); |
7c375e22 DF |
193 | } |
194 | ||
b026393c | 195 | static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 196 | { |
b026393c EGE |
197 | QE1000E_PCI *e1000e = obj; |
198 | QE1000E *d = &e1000e->e1000e; | |
199 | QOSGraphObject *e_object = obj; | |
200 | QPCIDevice *dev = e_object->get_driver(e_object, "pci-device"); | |
201 | ||
202 | /* FIXME: add spapr support */ | |
203 | if (qpci_check_buggy_msi(dev)) { | |
204 | return; | |
205 | } | |
7c375e22 | 206 | |
b026393c | 207 | e1000e_receive_verify(d, data, alloc); |
7c375e22 DF |
208 | } |
209 | ||
b026393c EGE |
210 | static void test_e1000e_multiple_transfers(void *obj, void *data, |
211 | QGuestAllocator *alloc) | |
7c375e22 DF |
212 | { |
213 | static const long iterations = 4 * 1024; | |
214 | long i; | |
215 | ||
b026393c EGE |
216 | QE1000E_PCI *e1000e = obj; |
217 | QE1000E *d = &e1000e->e1000e; | |
218 | QOSGraphObject *e_object = obj; | |
219 | QPCIDevice *dev = e_object->get_driver(e_object, "pci-device"); | |
7c375e22 | 220 | |
b026393c EGE |
221 | /* FIXME: add spapr support */ |
222 | if (qpci_check_buggy_msi(dev)) { | |
223 | return; | |
224 | } | |
7c375e22 DF |
225 | |
226 | for (i = 0; i < iterations; i++) { | |
b026393c EGE |
227 | e1000e_send_verify(d, data, alloc); |
228 | e1000e_receive_verify(d, data, alloc); | |
7c375e22 DF |
229 | } |
230 | ||
7c375e22 DF |
231 | } |
232 | ||
b026393c | 233 | static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 234 | { |
6ebb8d2a | 235 | QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */ |
02ee7a8a EA |
236 | QE1000E_PCI *dev = obj; |
237 | ||
238 | if (dev->pci_dev.bus->not_hotpluggable) { | |
239 | g_test_skip("pci bus does not support hotplug"); | |
240 | return; | |
241 | } | |
6ebb8d2a | 242 | |
e5758de4 | 243 | qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}"); |
6ebb8d2a | 244 | qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06); |
b026393c EGE |
245 | } |
246 | ||
247 | static void data_test_clear(void *sockets) | |
248 | { | |
249 | int *test_sockets = sockets; | |
7c375e22 | 250 | |
b026393c EGE |
251 | close(test_sockets[0]); |
252 | qos_invalidate_command_line(); | |
253 | close(test_sockets[1]); | |
254 | g_free(test_sockets); | |
7c375e22 DF |
255 | } |
256 | ||
b026393c | 257 | static void *data_test_init(GString *cmd_line, void *arg) |
7c375e22 | 258 | { |
b026393c EGE |
259 | int *test_sockets = g_new(int, 2); |
260 | int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets); | |
261 | g_assert_cmpint(ret, != , -1); | |
7c375e22 | 262 | |
b026393c EGE |
263 | g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", |
264 | test_sockets[1]); | |
7c375e22 | 265 | |
b026393c EGE |
266 | g_test_queue_destroy(data_test_clear, test_sockets); |
267 | return test_sockets; | |
7c375e22 | 268 | } |
b026393c EGE |
269 | |
270 | static void register_e1000e_test(void) | |
271 | { | |
272 | QOSGraphTestOptions opts = { | |
273 | .before = data_test_init, | |
274 | }; | |
275 | ||
276 | qos_add_test("init", "e1000e", test_e1000e_init, &opts); | |
277 | qos_add_test("tx", "e1000e", test_e1000e_tx, &opts); | |
278 | qos_add_test("rx", "e1000e", test_e1000e_rx, &opts); | |
279 | qos_add_test("multiple_transfers", "e1000e", | |
280 | test_e1000e_multiple_transfers, &opts); | |
281 | qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts); | |
282 | } | |
283 | ||
284 | libqos_init(register_e1000e_test); |