[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code
From: |
Akihiko Odaki |
Subject: |
[PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code |
Date: |
Sat, 14 Jan 2023 13:10:01 +0900 |
Start off igb test implementation by copying e1000e code first as igb
resembles e1000e.
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
MAINTAINERS | 2 +
tests/qtest/igb-test.c | 242 +++++++++++++++++++++++++++++++++++++++
tests/qtest/libqos/igb.c | 226 ++++++++++++++++++++++++++++++++++++
3 files changed, 470 insertions(+)
create mode 100644 tests/qtest/igb-test.c
create mode 100644 tests/qtest/libqos/igb.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 8c59cd28a3..2599cd673c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2222,6 +2222,8 @@ igb
M: Akihiko Odaki <akihiko.odaki@daynix.com>
S: Maintained
F: hw/net/igb*
+F: tests/qtest/igb-test.c
+F: tests/qtest/libqos/igb.c
eepro100
M: Stefan Weil <sw@weilnetz.de>
diff --git a/tests/qtest/igb-test.c b/tests/qtest/igb-test.c
new file mode 100644
index 0000000000..98706355e3
--- /dev/null
+++ b/tests/qtest/igb-test.c
@@ -0,0 +1,242 @@
+/*
+ * QTest testcase for e1000e NIC
+ *
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Leonid Bloch <leonid@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/pci-pc.h"
+#include "net/eth.h"
+#include "qemu/sockets.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "libqos/libqos-malloc.h"
+#include "libqos/e1000e.h"
+#include "hw/net/e1000_regs.h"
+
+static const struct eth_header test = {
+ .h_dest = E1000E_ADDRESS,
+ .h_source = E1000E_ADDRESS,
+};
+
+static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator
*alloc)
+{
+ struct e1000_tx_desc descr;
+ char buffer[64];
+ int ret;
+ uint32_t recv_len;
+
+ /* Prepare test data buffer */
+ uint64_t data = guest_alloc(alloc, sizeof(buffer));
+ memwrite(data, &test, sizeof(test));
+
+ /* Prepare TX descriptor */
+ memset(&descr, 0, sizeof(descr));
+ descr.buffer_addr = cpu_to_le64(data);
+ descr.lower.data = cpu_to_le32(E1000_TXD_CMD_RS |
+ E1000_TXD_CMD_EOP |
+ E1000_TXD_CMD_DEXT |
+ E1000_TXD_DTYP_D |
+ sizeof(buffer));
+
+ /* Put descriptor to the ring */
+ e1000e_tx_ring_push(d, &descr);
+
+ /* Wait for TX WB interrupt */
+ e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
+
+ /* Check DD bit */
+ g_assert_cmphex(le32_to_cpu(descr.upper.data) & E1000_TXD_STAT_DD, ==,
+ E1000_TXD_STAT_DD);
+
+ /* Check data sent to the backend */
+ ret = recv(test_sockets[0], &recv_len, sizeof(recv_len), 0);
+ g_assert_cmpint(ret, == , sizeof(recv_len));
+ ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
+ g_assert_cmpint(ret, ==, sizeof(buffer));
+ g_assert_false(memcmp(buffer, &test, sizeof(test)));
+
+ /* Free test data buffer */
+ guest_free(alloc, data);
+}
+
+static void e1000e_receive_verify(QE1000E *d, int *test_sockets,
QGuestAllocator *alloc)
+{
+ union e1000_rx_desc_extended descr;
+
+ struct eth_header test_iov = test;
+ int len = htonl(sizeof(test));
+ struct iovec iov[] = {
+ {
+ .iov_base = &len,
+ .iov_len = sizeof(len),
+ },{
+ .iov_base = &test_iov,
+ .iov_len = sizeof(test),
+ },
+ };
+
+ char buffer[64];
+ int ret;
+
+ /* Send a dummy packet to device's socket*/
+ ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test));
+ g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
+
+ /* Prepare test data buffer */
+ uint64_t data = guest_alloc(alloc, sizeof(buffer));
+
+ /* Prepare RX descriptor */
+ memset(&descr, 0, sizeof(descr));
+ descr.read.buffer_addr = cpu_to_le64(data);
+
+ /* Put descriptor to the ring */
+ e1000e_rx_ring_push(d, &descr);
+
+ /* Wait for TX WB interrupt */
+ e1000e_wait_isr(d, E1000E_RX0_MSG_ID);
+
+ /* Check DD bit */
+ g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) &
+ E1000_RXD_STAT_DD, ==, E1000_RXD_STAT_DD);
+
+ /* Check data sent to the backend */
+ memread(data, buffer, sizeof(buffer));
+ g_assert_false(memcmp(buffer, &test, sizeof(test)));
+
+ /* Free test data buffer */
+ guest_free(alloc, data);
+}
+
+static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
+{
+ /* init does nothing */
+}
+
+static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
+{
+ QE1000E_PCI *e1000e = obj;
+ QE1000E *d = &e1000e->e1000e;
+ QOSGraphObject *e_object = obj;
+ QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+ /* FIXME: add spapr support */
+ if (qpci_check_buggy_msi(dev)) {
+ return;
+ }
+
+ e1000e_send_verify(d, data, alloc);
+}
+
+static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
+{
+ QE1000E_PCI *e1000e = obj;
+ QE1000E *d = &e1000e->e1000e;
+ QOSGraphObject *e_object = obj;
+ QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+ /* FIXME: add spapr support */
+ if (qpci_check_buggy_msi(dev)) {
+ return;
+ }
+
+ e1000e_receive_verify(d, data, alloc);
+}
+
+static void test_e1000e_multiple_transfers(void *obj, void *data,
+ QGuestAllocator *alloc)
+{
+ static const long iterations = 4 * 1024;
+ long i;
+
+ QE1000E_PCI *e1000e = obj;
+ QE1000E *d = &e1000e->e1000e;
+ QOSGraphObject *e_object = obj;
+ QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+ /* FIXME: add spapr support */
+ if (qpci_check_buggy_msi(dev)) {
+ return;
+ }
+
+ for (i = 0; i < iterations; i++) {
+ e1000e_send_verify(d, data, alloc);
+ e1000e_receive_verify(d, data, alloc);
+ }
+
+}
+
+static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
+{
+ QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */
+ QE1000E_PCI *dev = obj;
+
+ if (dev->pci_dev.bus->not_hotpluggable) {
+ g_test_skip("pci bus does not support hotplug");
+ return;
+ }
+
+ qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
+ qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
+}
+
+static void data_test_clear(void *sockets)
+{
+ int *test_sockets = sockets;
+
+ close(test_sockets[0]);
+ qos_invalidate_command_line();
+ close(test_sockets[1]);
+ g_free(test_sockets);
+}
+
+static void *data_test_init(GString *cmd_line, void *arg)
+{
+ int *test_sockets = g_new(int, 2);
+ int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
+ g_assert_cmpint(ret, != , -1);
+
+ g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
+ test_sockets[1]);
+
+ g_test_queue_destroy(data_test_clear, test_sockets);
+ return test_sockets;
+}
+
+static void register_e1000e_test(void)
+{
+ QOSGraphTestOptions opts = {
+ .before = data_test_init,
+ };
+
+ qos_add_test("init", "e1000e", test_e1000e_init, &opts);
+ qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
+ qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
+ qos_add_test("multiple_transfers", "e1000e",
+ test_e1000e_multiple_transfers, &opts);
+ qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
+}
+
+libqos_init(register_e1000e_test);
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
new file mode 100644
index 0000000000..925654c7fd
--- /dev/null
+++ b/tests/qtest/libqos/igb.c
@@ -0,0 +1,226 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "hw/net/e1000_regs.h"
+#include "hw/pci/pci_ids.h"
+#include "../libqtest.h"
+#include "pci-pc.h"
+#include "qemu/sockets.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "libqos-malloc.h"
+#include "qgraph.h"
+#include "e1000e.h"
+
+#define E1000E_IVAR_TEST_CFG \
+ (((E1000E_RX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) <<
E1000_IVAR_RXQ0_SHIFT) | \
+ ((E1000E_TX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) <<
E1000_IVAR_TXQ0_SHIFT) | \
+ E1000_IVAR_TX_INT_EVERY_WB)
+
+#define E1000E_RING_LEN (0x1000)
+
+void e1000e_tx_ring_push(QE1000E *d, void *descr)
+{
+ QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+ uint32_t tail = e1000e_macreg_read(d, E1000_TDT);
+ uint32_t len = e1000e_macreg_read(d, E1000_TDLEN) / E1000_RING_DESC_LEN;
+
+ qtest_memwrite(d_pci->pci_dev.bus->qts,
+ d->tx_ring + tail * E1000_RING_DESC_LEN,
+ descr, E1000_RING_DESC_LEN);
+ e1000e_macreg_write(d, E1000_TDT, (tail + 1) % len);
+
+ /* Read WB data for the packet transmitted */
+ qtest_memread(d_pci->pci_dev.bus->qts,
+ d->tx_ring + tail * E1000_RING_DESC_LEN,
+ descr, E1000_RING_DESC_LEN);
+}
+
+void e1000e_rx_ring_push(QE1000E *d, void *descr)
+{
+ QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+ uint32_t tail = e1000e_macreg_read(d, E1000_RDT);
+ uint32_t len = e1000e_macreg_read(d, E1000_RDLEN) / E1000_RING_DESC_LEN;
+
+ qtest_memwrite(d_pci->pci_dev.bus->qts,
+ d->rx_ring + tail * E1000_RING_DESC_LEN,
+ descr, E1000_RING_DESC_LEN);
+ e1000e_macreg_write(d, E1000_RDT, (tail + 1) % len);
+
+ /* Read WB data for the packet received */
+ qtest_memread(d_pci->pci_dev.bus->qts,
+ d->rx_ring + tail * E1000_RING_DESC_LEN,
+ descr, E1000_RING_DESC_LEN);
+}
+
+static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
+{
+ QPCIDevice *res = data;
+ memcpy(res, dev, sizeof(QPCIDevice));
+ g_free(dev);
+}
+
+void e1000e_wait_isr(QE1000E *d, uint16_t msg_id)
+{
+ QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+ guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+
+ do {
+ if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
+ return;
+ }
+ qtest_clock_step(d_pci->pci_dev.bus->qts, 10000);
+ } while (g_get_monotonic_time() < end_time);
+
+ g_error("Timeout expired");
+}
+
+static void e1000e_pci_destructor(QOSGraphObject *obj)
+{
+ QE1000E_PCI *epci = (QE1000E_PCI *) obj;
+ qpci_iounmap(&epci->pci_dev, epci->mac_regs);
+ qpci_msix_disable(&epci->pci_dev);
+}
+
+static void e1000e_pci_start_hw(QOSGraphObject *obj)
+{
+ QE1000E_PCI *d = (QE1000E_PCI *) obj;
+ uint32_t val;
+
+ /* Enable the device */
+ qpci_device_enable(&d->pci_dev);
+
+ /* Reset the device */
+ val = e1000e_macreg_read(&d->e1000e, E1000_CTRL);
+ e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST |
E1000_CTRL_SLU);
+
+ /* Enable and configure MSI-X */
+ qpci_msix_enable(&d->pci_dev);
+ e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG);
+
+ /* Check the device status - link and speed */
+ val = e1000e_macreg_read(&d->e1000e, E1000_STATUS);
+ g_assert_cmphex(val & (E1000_STATUS_LU | E1000_STATUS_ASDV_1000),
+ ==, E1000_STATUS_LU | E1000_STATUS_ASDV_1000);
+
+ /* Initialize TX/RX logic */
+ e1000e_macreg_write(&d->e1000e, E1000_RCTL, 0);
+ e1000e_macreg_write(&d->e1000e, E1000_TCTL, 0);
+
+ /* Notify the device that the driver is ready */
+ val = e1000e_macreg_read(&d->e1000e, E1000_CTRL_EXT);
+ e1000e_macreg_write(&d->e1000e, E1000_CTRL_EXT,
+ val | E1000_CTRL_EXT_DRV_LOAD);
+
+ e1000e_macreg_write(&d->e1000e, E1000_TDBAL,
+ (uint32_t) d->e1000e.tx_ring);
+ e1000e_macreg_write(&d->e1000e, E1000_TDBAH,
+ (uint32_t) (d->e1000e.tx_ring >> 32));
+ e1000e_macreg_write(&d->e1000e, E1000_TDLEN, E1000E_RING_LEN);
+ e1000e_macreg_write(&d->e1000e, E1000_TDT, 0);
+ e1000e_macreg_write(&d->e1000e, E1000_TDH, 0);
+
+ /* Enable transmit */
+ e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN);
+
+ e1000e_macreg_write(&d->e1000e, E1000_RDBAL,
+ (uint32_t)d->e1000e.rx_ring);
+ e1000e_macreg_write(&d->e1000e, E1000_RDBAH,
+ (uint32_t)(d->e1000e.rx_ring >> 32));
+ e1000e_macreg_write(&d->e1000e, E1000_RDLEN, E1000E_RING_LEN);
+ e1000e_macreg_write(&d->e1000e, E1000_RDT, 0);
+ e1000e_macreg_write(&d->e1000e, E1000_RDH, 0);
+
+ /* Enable receive */
+ e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
+ e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN |
+ E1000_RCTL_UPE |
+ E1000_RCTL_MPE);
+
+ /* Enable all interrupts */
+ e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
+
+}
+
+static void *e1000e_pci_get_driver(void *obj, const char *interface)
+{
+ QE1000E_PCI *epci = obj;
+ if (!g_strcmp0(interface, "e1000e-if")) {
+ return &epci->e1000e;
+ }
+
+ /* implicit contains */
+ if (!g_strcmp0(interface, "pci-device")) {
+ return &epci->pci_dev;
+ }
+
+ fprintf(stderr, "%s not present in e1000e\n", interface);
+ g_assert_not_reached();
+}
+
+static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
+ void *addr)
+{
+ QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
+ QPCIBus *bus = pci_bus;
+ QPCIAddress *address = addr;
+
+ qpci_device_foreach(bus, address->vendor_id, address->device_id,
+ e1000e_foreach_callback, &d->pci_dev);
+
+ /* Map BAR0 (mac registers) */
+ d->mac_regs = qpci_iomap(&d->pci_dev, 0, NULL);
+
+ /* Allocate and setup TX ring */
+ d->e1000e.tx_ring = guest_alloc(alloc, E1000E_RING_LEN);
+ g_assert(d->e1000e.tx_ring != 0);
+
+ /* Allocate and setup RX ring */
+ d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
+ g_assert(d->e1000e.rx_ring != 0);
+
+ d->obj.get_driver = e1000e_pci_get_driver;
+ d->obj.start_hw = e1000e_pci_start_hw;
+ d->obj.destructor = e1000e_pci_destructor;
+
+ return &d->obj;
+}
+
+static void e1000e_register_nodes(void)
+{
+ QPCIAddress addr = {
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = E1000_DEV_ID_82574L,
+ };
+
+ /*
+ * FIXME: every test using this node needs to setup a -netdev socket,id=hs0
+ * otherwise QEMU is not going to start
+ */
+ QOSGraphEdgeOptions opts = {
+ .extra_device_opts = "netdev=hs0",
+ };
+ add_qpci_address(&opts, &addr);
+
+ qos_node_create_driver("e1000e", e1000e_pci_create);
+ qos_node_consumes("e1000e", "pci-bus", &opts);
+}
+
+libqos_init(e1000e_register_nodes);
--
2.39.0
- [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr, (continued)
- [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr, Akihiko Odaki, 2023/01/13
- [PATCH v2 02/13] pcie: Introduce pcie_sriov_num_vfs, Akihiko Odaki, 2023/01/13
- [PATCH v2 03/13] e1000: Split header files, Akihiko Odaki, 2023/01/13
- [PATCH v2 04/13] igb: Copy e1000e code, Akihiko Odaki, 2023/01/13
- [PATCH v2 05/13] igb: Rename identifiers, Akihiko Odaki, 2023/01/13
- [PATCH v2 06/13] igb: Build igb, Akihiko Odaki, 2023/01/13
- [PATCH v2 07/13] igb: Transform to 82576 implementation, Akihiko Odaki, 2023/01/13
- [PATCH v2 08/13] tests/qtest/e1000e-test: Fabricate ethernet header, Akihiko Odaki, 2023/01/13
- [PATCH v2 11/13] tests/qtest/libqos/igb: Transform to igb tests, Akihiko Odaki, 2023/01/13
- [PATCH v2 09/13] tests/qtest/libqos/e1000e: Export macreg functions, Akihiko Odaki, 2023/01/13
- [PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code,
Akihiko Odaki <=
- [PATCH v2 12/13] tests/avocado: Add igb test, Akihiko Odaki, 2023/01/13
- [PATCH v2 13/13] docs/system/devices/igb: Add igb documentation, Akihiko Odaki, 2023/01/13
- Re: [PATCH v2 00/13] Introduce igb, Jason Wang, 2023/01/16
- Re: [PATCH v2 00/13] Introduce igb, Akihiko Odaki, 2023/01/23
- RE: [PATCH v2 00/13] Introduce igb, Sriram Yagnaraman, 2023/01/24
- RE: [PATCH v2 00/13] Introduce igb, Sriram Yagnaraman, 2023/01/26
- Re: [PATCH v2 00/13] Introduce igb, Akihiko Odaki, 2023/01/26
- RE: [PATCH v2 00/13] Introduce igb, Sriram Yagnaraman, 2023/01/28
- Re: [PATCH v2 00/13] Introduce igb, Akihiko Odaki, 2023/01/30
- RE: [PATCH v2 00/13] Introduce igb, Sriram Yagnaraman, 2023/01/31