xref: /openbmc/qemu/tests/qtest/e1000e-test.c (revision 00dc9a59)
11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth  * QTest testcase for e1000e NIC
31e8a1faeSThomas Huth  *
41e8a1faeSThomas Huth  * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
51e8a1faeSThomas Huth  * Developed by Daynix Computing LTD (http://www.daynix.com)
61e8a1faeSThomas Huth  *
71e8a1faeSThomas Huth  * Authors:
81e8a1faeSThomas Huth  * Dmitry Fleytman <dmitry@daynix.com>
91e8a1faeSThomas Huth  * Leonid Bloch <leonid@daynix.com>
101e8a1faeSThomas Huth  * Yan Vugenfirer <yan@daynix.com>
111e8a1faeSThomas Huth  *
121e8a1faeSThomas Huth  * This library is free software; you can redistribute it and/or
131e8a1faeSThomas Huth  * modify it under the terms of the GNU Lesser General Public
141e8a1faeSThomas Huth  * License as published by the Free Software Foundation; either
15dc0ad02dSThomas Huth  * version 2.1 of the License, or (at your option) any later version.
161e8a1faeSThomas Huth  *
171e8a1faeSThomas Huth  * This library is distributed in the hope that it will be useful,
181e8a1faeSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
191e8a1faeSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
201e8a1faeSThomas Huth  * Lesser General Public License for more details.
211e8a1faeSThomas Huth  *
221e8a1faeSThomas Huth  * You should have received a copy of the GNU Lesser General Public
231e8a1faeSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
241e8a1faeSThomas Huth  */
251e8a1faeSThomas Huth 
261e8a1faeSThomas Huth 
271e8a1faeSThomas Huth #include "qemu/osdep.h"
281e8a1faeSThomas Huth #include "libqtest-single.h"
291e8a1faeSThomas Huth #include "libqos/pci-pc.h"
30*00dc9a59SAkihiko Odaki #include "net/eth.h"
311e8a1faeSThomas Huth #include "qemu/sockets.h"
321e8a1faeSThomas Huth #include "qemu/iov.h"
331e8a1faeSThomas Huth #include "qemu/module.h"
341e8a1faeSThomas Huth #include "qemu/bitops.h"
35b243c73cSXuzhou Cheng #include "libqos/libqos-malloc.h"
361e8a1faeSThomas Huth #include "libqos/e1000e.h"
37dfa644b2SAkihiko Odaki #include "hw/net/e1000_regs.h"
381e8a1faeSThomas Huth 
39*00dc9a59SAkihiko Odaki static const struct eth_header packet = {
40*00dc9a59SAkihiko Odaki     .h_dest = E1000E_ADDRESS,
41*00dc9a59SAkihiko Odaki     .h_source = E1000E_ADDRESS,
42*00dc9a59SAkihiko Odaki };
43*00dc9a59SAkihiko Odaki 
e1000e_send_verify(QE1000E * d,int * test_sockets,QGuestAllocator * alloc)441e8a1faeSThomas Huth static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
451e8a1faeSThomas Huth {
46dfa644b2SAkihiko Odaki     struct e1000_tx_desc descr;
471e8a1faeSThomas Huth     char buffer[64];
481e8a1faeSThomas Huth     int ret;
491e8a1faeSThomas Huth     uint32_t recv_len;
501e8a1faeSThomas Huth 
511e8a1faeSThomas Huth     /* Prepare test data buffer */
52f2ae2fabSAkihiko Odaki     uint64_t data = guest_alloc(alloc, sizeof(buffer));
53*00dc9a59SAkihiko Odaki     memwrite(data, &packet, sizeof(packet));
541e8a1faeSThomas Huth 
551e8a1faeSThomas Huth     /* Prepare TX descriptor */
561e8a1faeSThomas Huth     memset(&descr, 0, sizeof(descr));
571e8a1faeSThomas Huth     descr.buffer_addr = cpu_to_le64(data);
58dfa644b2SAkihiko Odaki     descr.lower.data = cpu_to_le32(E1000_TXD_CMD_RS   |
59dfa644b2SAkihiko Odaki                                    E1000_TXD_CMD_EOP  |
60dfa644b2SAkihiko Odaki                                    E1000_TXD_CMD_DEXT |
61dfa644b2SAkihiko Odaki                                    E1000_TXD_DTYP_D   |
62f2ae2fabSAkihiko Odaki                                    sizeof(buffer));
631e8a1faeSThomas Huth 
641e8a1faeSThomas Huth     /* Put descriptor to the ring */
651e8a1faeSThomas Huth     e1000e_tx_ring_push(d, &descr);
661e8a1faeSThomas Huth 
671e8a1faeSThomas Huth     /* Wait for TX WB interrupt */
681e8a1faeSThomas Huth     e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
691e8a1faeSThomas Huth 
701e8a1faeSThomas Huth     /* Check DD bit */
71dfa644b2SAkihiko Odaki     g_assert_cmphex(le32_to_cpu(descr.upper.data) & E1000_TXD_STAT_DD, ==,
72dfa644b2SAkihiko Odaki                     E1000_TXD_STAT_DD);
731e8a1faeSThomas Huth 
741e8a1faeSThomas Huth     /* Check data sent to the backend */
75e7b79428SMarc-André Lureau     ret = recv(test_sockets[0], &recv_len, sizeof(recv_len), 0);
761e8a1faeSThomas Huth     g_assert_cmpint(ret, == , sizeof(recv_len));
77f2ae2fabSAkihiko Odaki     ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
78f2ae2fabSAkihiko Odaki     g_assert_cmpint(ret, ==, sizeof(buffer));
79*00dc9a59SAkihiko Odaki     g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
801e8a1faeSThomas Huth 
811e8a1faeSThomas Huth     /* Free test data buffer */
821e8a1faeSThomas Huth     guest_free(alloc, data);
831e8a1faeSThomas Huth }
841e8a1faeSThomas Huth 
e1000e_receive_verify(QE1000E * d,int * test_sockets,QGuestAllocator * alloc)851e8a1faeSThomas Huth static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
861e8a1faeSThomas Huth {
87dfa644b2SAkihiko Odaki     union e1000_rx_desc_extended descr;
881e8a1faeSThomas Huth 
89*00dc9a59SAkihiko Odaki     struct eth_header test_iov = packet;
90*00dc9a59SAkihiko Odaki     int len = htonl(sizeof(packet));
911e8a1faeSThomas Huth     struct iovec iov[] = {
921e8a1faeSThomas Huth         {
931e8a1faeSThomas Huth             .iov_base = &len,
941e8a1faeSThomas Huth             .iov_len = sizeof(len),
951e8a1faeSThomas Huth         },{
96*00dc9a59SAkihiko Odaki             .iov_base = &test_iov,
97*00dc9a59SAkihiko Odaki             .iov_len = sizeof(packet),
981e8a1faeSThomas Huth         },
991e8a1faeSThomas Huth     };
1001e8a1faeSThomas Huth 
1011e8a1faeSThomas Huth     char buffer[64];
1021e8a1faeSThomas Huth     int ret;
1031e8a1faeSThomas Huth 
1041e8a1faeSThomas Huth     /* Send a dummy packet to device's socket*/
105*00dc9a59SAkihiko Odaki     ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(packet));
106*00dc9a59SAkihiko Odaki     g_assert_cmpint(ret, == , sizeof(packet) + sizeof(len));
1071e8a1faeSThomas Huth 
1081e8a1faeSThomas Huth     /* Prepare test data buffer */
109f2ae2fabSAkihiko Odaki     uint64_t data = guest_alloc(alloc, sizeof(buffer));
1101e8a1faeSThomas Huth 
1111e8a1faeSThomas Huth     /* Prepare RX descriptor */
1121e8a1faeSThomas Huth     memset(&descr, 0, sizeof(descr));
1131e8a1faeSThomas Huth     descr.read.buffer_addr = cpu_to_le64(data);
1141e8a1faeSThomas Huth 
1151e8a1faeSThomas Huth     /* Put descriptor to the ring */
1161e8a1faeSThomas Huth     e1000e_rx_ring_push(d, &descr);
1171e8a1faeSThomas Huth 
1181e8a1faeSThomas Huth     /* Wait for TX WB interrupt */
1191e8a1faeSThomas Huth     e1000e_wait_isr(d, E1000E_RX0_MSG_ID);
1201e8a1faeSThomas Huth 
1211e8a1faeSThomas Huth     /* Check DD bit */
1221e8a1faeSThomas Huth     g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) &
123dfa644b2SAkihiko Odaki         E1000_RXD_STAT_DD, ==, E1000_RXD_STAT_DD);
1241e8a1faeSThomas Huth 
1251e8a1faeSThomas Huth     /* Check data sent to the backend */
1261e8a1faeSThomas Huth     memread(data, buffer, sizeof(buffer));
127*00dc9a59SAkihiko Odaki     g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
1281e8a1faeSThomas Huth 
1291e8a1faeSThomas Huth     /* Free test data buffer */
1301e8a1faeSThomas Huth     guest_free(alloc, data);
1311e8a1faeSThomas Huth }
1321e8a1faeSThomas Huth 
test_e1000e_init(void * obj,void * data,QGuestAllocator * alloc)1331e8a1faeSThomas Huth static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
1341e8a1faeSThomas Huth {
1351e8a1faeSThomas Huth     /* init does nothing */
1361e8a1faeSThomas Huth }
1371e8a1faeSThomas Huth 
test_e1000e_tx(void * obj,void * data,QGuestAllocator * alloc)1381e8a1faeSThomas Huth static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
1391e8a1faeSThomas Huth {
1401e8a1faeSThomas Huth     QE1000E_PCI *e1000e = obj;
1411e8a1faeSThomas Huth     QE1000E *d = &e1000e->e1000e;
1421e8a1faeSThomas Huth     QOSGraphObject *e_object = obj;
1431e8a1faeSThomas Huth     QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
1441e8a1faeSThomas Huth 
1451e8a1faeSThomas Huth     /* FIXME: add spapr support */
1461e8a1faeSThomas Huth     if (qpci_check_buggy_msi(dev)) {
1471e8a1faeSThomas Huth         return;
1481e8a1faeSThomas Huth     }
1491e8a1faeSThomas Huth 
1501e8a1faeSThomas Huth     e1000e_send_verify(d, data, alloc);
1511e8a1faeSThomas Huth }
1521e8a1faeSThomas Huth 
test_e1000e_rx(void * obj,void * data,QGuestAllocator * alloc)1531e8a1faeSThomas Huth static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
1541e8a1faeSThomas Huth {
1551e8a1faeSThomas Huth     QE1000E_PCI *e1000e = obj;
1561e8a1faeSThomas Huth     QE1000E *d = &e1000e->e1000e;
1571e8a1faeSThomas Huth     QOSGraphObject *e_object = obj;
1581e8a1faeSThomas Huth     QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
1591e8a1faeSThomas Huth 
1601e8a1faeSThomas Huth     /* FIXME: add spapr support */
1611e8a1faeSThomas Huth     if (qpci_check_buggy_msi(dev)) {
1621e8a1faeSThomas Huth         return;
1631e8a1faeSThomas Huth     }
1641e8a1faeSThomas Huth 
1651e8a1faeSThomas Huth     e1000e_receive_verify(d, data, alloc);
1661e8a1faeSThomas Huth }
1671e8a1faeSThomas Huth 
test_e1000e_multiple_transfers(void * obj,void * data,QGuestAllocator * alloc)1681e8a1faeSThomas Huth static void test_e1000e_multiple_transfers(void *obj, void *data,
1691e8a1faeSThomas Huth                                            QGuestAllocator *alloc)
1701e8a1faeSThomas Huth {
1711e8a1faeSThomas Huth     static const long iterations = 4 * 1024;
1721e8a1faeSThomas Huth     long i;
1731e8a1faeSThomas Huth 
1741e8a1faeSThomas Huth     QE1000E_PCI *e1000e = obj;
1751e8a1faeSThomas Huth     QE1000E *d = &e1000e->e1000e;
1761e8a1faeSThomas Huth     QOSGraphObject *e_object = obj;
1771e8a1faeSThomas Huth     QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
1781e8a1faeSThomas Huth 
1791e8a1faeSThomas Huth     /* FIXME: add spapr support */
1801e8a1faeSThomas Huth     if (qpci_check_buggy_msi(dev)) {
1811e8a1faeSThomas Huth         return;
1821e8a1faeSThomas Huth     }
1831e8a1faeSThomas Huth 
1841e8a1faeSThomas Huth     for (i = 0; i < iterations; i++) {
1851e8a1faeSThomas Huth         e1000e_send_verify(d, data, alloc);
1861e8a1faeSThomas Huth         e1000e_receive_verify(d, data, alloc);
1871e8a1faeSThomas Huth     }
1881e8a1faeSThomas Huth 
1891e8a1faeSThomas Huth }
1901e8a1faeSThomas Huth 
test_e1000e_hotplug(void * obj,void * data,QGuestAllocator * alloc)1911e8a1faeSThomas Huth static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
1921e8a1faeSThomas Huth {
1931e8a1faeSThomas Huth     QTestState *qts = global_qtest;  /* TODO: get rid of global_qtest here */
19402ee7a8aSEric Auger     QE1000E_PCI *dev = obj;
19502ee7a8aSEric Auger 
19602ee7a8aSEric Auger     if (dev->pci_dev.bus->not_hotpluggable) {
19702ee7a8aSEric Auger         g_test_skip("pci bus does not support hotplug");
19802ee7a8aSEric Auger         return;
19902ee7a8aSEric Auger     }
2001e8a1faeSThomas Huth 
2011e8a1faeSThomas Huth     qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
2021e8a1faeSThomas Huth     qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
2031e8a1faeSThomas Huth }
2041e8a1faeSThomas Huth 
data_test_clear(void * sockets)2051e8a1faeSThomas Huth static void data_test_clear(void *sockets)
2061e8a1faeSThomas Huth {
2071e8a1faeSThomas Huth     int *test_sockets = sockets;
2081e8a1faeSThomas Huth 
2091e8a1faeSThomas Huth     close(test_sockets[0]);
2101e8a1faeSThomas Huth     qos_invalidate_command_line();
2111e8a1faeSThomas Huth     close(test_sockets[1]);
2121e8a1faeSThomas Huth     g_free(test_sockets);
2131e8a1faeSThomas Huth }
2141e8a1faeSThomas Huth 
data_test_init(GString * cmd_line,void * arg)2151e8a1faeSThomas Huth static void *data_test_init(GString *cmd_line, void *arg)
2161e8a1faeSThomas Huth {
2171e8a1faeSThomas Huth     int *test_sockets = g_new(int, 2);
2181e8a1faeSThomas Huth     int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
2191e8a1faeSThomas Huth     g_assert_cmpint(ret, != , -1);
2201e8a1faeSThomas Huth 
2211e8a1faeSThomas Huth     g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
2221e8a1faeSThomas Huth                            test_sockets[1]);
2231e8a1faeSThomas Huth 
2241e8a1faeSThomas Huth     g_test_queue_destroy(data_test_clear, test_sockets);
2251e8a1faeSThomas Huth     return test_sockets;
2261e8a1faeSThomas Huth }
2271e8a1faeSThomas Huth 
register_e1000e_test(void)2281e8a1faeSThomas Huth static void register_e1000e_test(void)
2291e8a1faeSThomas Huth {
2301e8a1faeSThomas Huth     QOSGraphTestOptions opts = {
2311e8a1faeSThomas Huth         .before = data_test_init,
2321e8a1faeSThomas Huth     };
2331e8a1faeSThomas Huth 
2341e8a1faeSThomas Huth     qos_add_test("init", "e1000e", test_e1000e_init, &opts);
2351e8a1faeSThomas Huth     qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
2361e8a1faeSThomas Huth     qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
2371e8a1faeSThomas Huth     qos_add_test("multiple_transfers", "e1000e",
2381e8a1faeSThomas Huth                       test_e1000e_multiple_transfers, &opts);
2391e8a1faeSThomas Huth     qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
2401e8a1faeSThomas Huth }
2411e8a1faeSThomas Huth 
2421e8a1faeSThomas Huth libqos_init(register_e1000e_test);
243