]>
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 <[email protected]> | |
9 | * Leonid Bloch <[email protected]> | |
10 | * Yan Vugenfirer <[email protected]> | |
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 | |
15 | * version 2 of the License, or (at your option) any later version. | |
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" | |
7c375e22 DF |
28 | #include "libqtest.h" |
29 | #include "qemu-common.h" | |
30 | #include "libqos/pci-pc.h" | |
31 | #include "qemu/sockets.h" | |
32 | #include "qemu/iov.h" | |
33 | #include "qemu/bitops.h" | |
34 | #include "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 */ | |
92 | ret = qemu_recv(test_sockets[0], &recv_len, sizeof(recv_len), 0); | |
93 | g_assert_cmpint(ret, == , sizeof(recv_len)); | |
94 | qemu_recv(test_sockets[0], buffer, 64, 0); | |
95 | g_assert_cmpstr(buffer, == , "TEST"); | |
96 | ||
97 | /* Free test data buffer */ | |
b026393c | 98 | guest_free(alloc, data); |
7c375e22 DF |
99 | } |
100 | ||
b026393c | 101 | static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc) |
7c375e22 DF |
102 | { |
103 | union { | |
104 | struct { | |
105 | uint64_t buffer_addr; | |
106 | uint64_t reserved; | |
107 | } read; | |
108 | struct { | |
109 | struct { | |
110 | uint32_t mrq; | |
111 | union { | |
112 | uint32_t rss; | |
113 | struct { | |
114 | uint16_t ip_id; | |
115 | uint16_t csum; | |
116 | } csum_ip; | |
117 | } hi_dword; | |
118 | } lower; | |
119 | struct { | |
120 | uint32_t status_error; | |
121 | uint16_t length; | |
122 | uint16_t vlan; | |
123 | } upper; | |
124 | } wb; | |
125 | } descr; | |
126 | ||
127 | static const uint32_t esta_dd = BIT(0); | |
128 | ||
129 | char test[] = "TEST"; | |
130 | int len = htonl(sizeof(test)); | |
131 | struct iovec iov[] = { | |
132 | { | |
133 | .iov_base = &len, | |
134 | .iov_len = sizeof(len), | |
135 | },{ | |
136 | .iov_base = test, | |
137 | .iov_len = sizeof(test), | |
138 | }, | |
139 | }; | |
140 | ||
141 | static const int data_len = 64; | |
142 | char buffer[64]; | |
143 | int ret; | |
144 | ||
145 | /* Send a dummy packet to device's socket*/ | |
146 | ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test)); | |
147 | g_assert_cmpint(ret, == , sizeof(test) + sizeof(len)); | |
148 | ||
149 | /* Prepare test data buffer */ | |
b026393c | 150 | uint64_t data = guest_alloc(alloc, data_len); |
7c375e22 DF |
151 | |
152 | /* Prepare RX descriptor */ | |
153 | memset(&descr, 0, sizeof(descr)); | |
154 | descr.read.buffer_addr = cpu_to_le64(data); | |
155 | ||
156 | /* Put descriptor to the ring */ | |
157 | e1000e_rx_ring_push(d, &descr); | |
158 | ||
159 | /* Wait for TX WB interrupt */ | |
160 | e1000e_wait_isr(d, E1000E_RX0_MSG_ID); | |
161 | ||
162 | /* Check DD bit */ | |
163 | g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) & | |
164 | esta_dd, ==, esta_dd); | |
165 | ||
166 | /* Check data sent to the backend */ | |
167 | memread(data, buffer, sizeof(buffer)); | |
168 | g_assert_cmpstr(buffer, == , "TEST"); | |
169 | ||
170 | /* Free test data buffer */ | |
b026393c | 171 | guest_free(alloc, data); |
7c375e22 DF |
172 | } |
173 | ||
b026393c | 174 | static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 175 | { |
b026393c | 176 | /* init does nothing */ |
7c375e22 DF |
177 | } |
178 | ||
b026393c | 179 | static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 180 | { |
b026393c EGE |
181 | QE1000E_PCI *e1000e = obj; |
182 | QE1000E *d = &e1000e->e1000e; | |
183 | QOSGraphObject *e_object = obj; | |
184 | QPCIDevice *dev = e_object->get_driver(e_object, "pci-device"); | |
185 | ||
186 | /* FIXME: add spapr support */ | |
187 | if (qpci_check_buggy_msi(dev)) { | |
188 | return; | |
189 | } | |
7c375e22 | 190 | |
b026393c | 191 | e1000e_send_verify(d, data, alloc); |
7c375e22 DF |
192 | } |
193 | ||
b026393c | 194 | static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 195 | { |
b026393c EGE |
196 | QE1000E_PCI *e1000e = obj; |
197 | QE1000E *d = &e1000e->e1000e; | |
198 | QOSGraphObject *e_object = obj; | |
199 | QPCIDevice *dev = e_object->get_driver(e_object, "pci-device"); | |
200 | ||
201 | /* FIXME: add spapr support */ | |
202 | if (qpci_check_buggy_msi(dev)) { | |
203 | return; | |
204 | } | |
7c375e22 | 205 | |
b026393c | 206 | e1000e_receive_verify(d, data, alloc); |
7c375e22 DF |
207 | } |
208 | ||
b026393c EGE |
209 | static void test_e1000e_multiple_transfers(void *obj, void *data, |
210 | QGuestAllocator *alloc) | |
7c375e22 DF |
211 | { |
212 | static const long iterations = 4 * 1024; | |
213 | long i; | |
214 | ||
b026393c EGE |
215 | QE1000E_PCI *e1000e = obj; |
216 | QE1000E *d = &e1000e->e1000e; | |
217 | QOSGraphObject *e_object = obj; | |
218 | QPCIDevice *dev = e_object->get_driver(e_object, "pci-device"); | |
7c375e22 | 219 | |
b026393c EGE |
220 | /* FIXME: add spapr support */ |
221 | if (qpci_check_buggy_msi(dev)) { | |
222 | return; | |
223 | } | |
7c375e22 DF |
224 | |
225 | for (i = 0; i < iterations; i++) { | |
b026393c EGE |
226 | e1000e_send_verify(d, data, alloc); |
227 | e1000e_receive_verify(d, data, alloc); | |
7c375e22 DF |
228 | } |
229 | ||
7c375e22 DF |
230 | } |
231 | ||
b026393c | 232 | static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc) |
7c375e22 | 233 | { |
6ebb8d2a TH |
234 | QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */ |
235 | ||
82cab70b | 236 | qtest_qmp_device_add("e1000e", "e1000e_net", "{'addr': '0x06'}"); |
6ebb8d2a | 237 | qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06); |
b026393c EGE |
238 | } |
239 | ||
240 | static void data_test_clear(void *sockets) | |
241 | { | |
242 | int *test_sockets = sockets; | |
7c375e22 | 243 | |
b026393c EGE |
244 | close(test_sockets[0]); |
245 | qos_invalidate_command_line(); | |
246 | close(test_sockets[1]); | |
247 | g_free(test_sockets); | |
7c375e22 DF |
248 | } |
249 | ||
b026393c | 250 | static void *data_test_init(GString *cmd_line, void *arg) |
7c375e22 | 251 | { |
b026393c EGE |
252 | int *test_sockets = g_new(int, 2); |
253 | int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets); | |
254 | g_assert_cmpint(ret, != , -1); | |
7c375e22 | 255 | |
b026393c EGE |
256 | g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", |
257 | test_sockets[1]); | |
7c375e22 | 258 | |
b026393c EGE |
259 | g_test_queue_destroy(data_test_clear, test_sockets); |
260 | return test_sockets; | |
7c375e22 | 261 | } |
b026393c EGE |
262 | |
263 | static void register_e1000e_test(void) | |
264 | { | |
265 | QOSGraphTestOptions opts = { | |
266 | .before = data_test_init, | |
267 | }; | |
268 | ||
269 | qos_add_test("init", "e1000e", test_e1000e_init, &opts); | |
270 | qos_add_test("tx", "e1000e", test_e1000e_tx, &opts); | |
271 | qos_add_test("rx", "e1000e", test_e1000e_rx, &opts); | |
272 | qos_add_test("multiple_transfers", "e1000e", | |
273 | test_e1000e_multiple_transfers, &opts); | |
274 | qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts); | |
275 | } | |
276 | ||
277 | libqos_init(register_e1000e_test); |