@@ -90,6 +90,11 @@ const generic_fuzz_config predefined_configs[] = {
.args = "-M q35 -nodefaults "
"-device e1000e,netdev=net0 -netdev user,id=net0",
.objects = "e1000e",
+ },{
+ .name = "igb",
+ .args = "-M q35 -nodefaults "
+ "-device igb,netdev=net0 -netdev user,id=net0",
+ .objects = "igb",
},{
.name = "cirrus-vga",
.args = "-machine q35 -nodefaults -device cirrus-vga",
@@ -1,10 +1,12 @@
/*
- * QTest testcase for e1000e NIC
+ * QTest testcase for igb NIC
*
+ * Copyright (c) 2022-2023 Red Hat, Inc.
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
+ * Akihiko Odaki <akihiko.odaki@daynix.com>
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
@@ -34,16 +36,16 @@
#include "qemu/bitops.h"
#include "libqos/libqos-malloc.h"
#include "libqos/e1000e.h"
-#include "hw/net/e1000_regs.h"
+#include "hw/net/igb_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)
+static void igb_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
{
- struct e1000_tx_desc descr;
+ union e1000_adv_tx_desc descr;
char buffer[64];
int ret;
uint32_t recv_len;
@@ -54,12 +56,11 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
/* 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));
+ descr.read.buffer_addr = cpu_to_le64(data);
+ descr.read.cmd_type_len = cpu_to_le32(E1000_TXD_CMD_RS |
+ E1000_TXD_CMD_EOP |
+ E1000_TXD_DTYP_D |
+ sizeof(buffer));
/* Put descriptor to the ring */
e1000e_tx_ring_push(d, &descr);
@@ -68,7 +69,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
/* Check DD bit */
- g_assert_cmphex(le32_to_cpu(descr.upper.data) & E1000_TXD_STAT_DD, ==,
+ g_assert_cmphex(le32_to_cpu(descr.wb.status) & E1000_TXD_STAT_DD, ==,
E1000_TXD_STAT_DD);
/* Check data sent to the backend */
@@ -82,9 +83,9 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
guest_free(alloc, data);
}
-static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+static void igb_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
{
- union e1000_rx_desc_extended descr;
+ union e1000_adv_rx_desc descr;
struct eth_header test_iov = test;
int len = htonl(sizeof(test));
@@ -110,7 +111,7 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
/* Prepare RX descriptor */
memset(&descr, 0, sizeof(descr));
- descr.read.buffer_addr = cpu_to_le64(data);
+ descr.read.pkt_addr = cpu_to_le64(data);
/* Put descriptor to the ring */
e1000e_rx_ring_push(d, &descr);
@@ -135,7 +136,7 @@ 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)
+static void test_igb_tx(void *obj, void *data, QGuestAllocator * alloc)
{
QE1000E_PCI *e1000e = obj;
QE1000E *d = &e1000e->e1000e;
@@ -147,10 +148,10 @@ static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
return;
}
- e1000e_send_verify(d, data, alloc);
+ igb_send_verify(d, data, alloc);
}
-static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
+static void test_igb_rx(void *obj, void *data, QGuestAllocator * alloc)
{
QE1000E_PCI *e1000e = obj;
QE1000E *d = &e1000e->e1000e;
@@ -162,11 +163,11 @@ static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
return;
}
- e1000e_receive_verify(d, data, alloc);
+ igb_receive_verify(d, data, alloc);
}
-static void test_e1000e_multiple_transfers(void *obj, void *data,
- QGuestAllocator *alloc)
+static void test_igb_multiple_transfers(void *obj, void *data,
+ QGuestAllocator *alloc)
{
static const long iterations = 4 * 1024;
long i;
@@ -182,13 +183,13 @@ static void test_e1000e_multiple_transfers(void *obj, void *data,
}
for (i = 0; i < iterations; i++) {
- e1000e_send_verify(d, data, alloc);
- e1000e_receive_verify(d, data, alloc);
+ igb_send_verify(d, data, alloc);
+ igb_receive_verify(d, data, alloc);
}
}
-static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
+static void test_igb_hotplug(void *obj, void *data, QGuestAllocator * alloc)
{
QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */
QE1000E_PCI *dev = obj;
@@ -198,8 +199,8 @@ static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
return;
}
- qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
- qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
+ qtest_qmp_device_add(qts, "igb", "igb_net", "{'addr': '0x06'}");
+ qpci_unplug_acpi_device_test(qts, "igb_net", 0x06);
}
static void data_test_clear(void *sockets)
@@ -225,18 +226,18 @@ static void *data_test_init(GString *cmd_line, void *arg)
return test_sockets;
}
-static void register_e1000e_test(void)
+static void register_igb_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);
+ qos_add_test("init", "igb", test_e1000e_init, &opts);
+ qos_add_test("tx", "igb", test_igb_tx, &opts);
+ qos_add_test("rx", "igb", test_igb_rx, &opts);
+ qos_add_test("multiple_transfers", "igb",
+ test_igb_multiple_transfers, &opts);
+ qos_add_test("hotplug", "igb", test_igb_hotplug, &opts);
}
-libqos_init(register_e1000e_test);
+libqos_init(register_igb_test);
@@ -1,6 +1,7 @@
/*
* libqos driver framework
*
+ * Copyright (c) 2022-2023 Red Hat, Inc.
* Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
*
* This library is free software; you can redistribute it and/or
@@ -17,7 +18,8 @@
*/
#include "qemu/osdep.h"
-#include "hw/net/e1000_regs.h"
+#include "hw/net/igb_regs.h"
+#include "hw/net/mii.h"
#include "hw/pci/pci_ids.h"
#include "../libqtest.h"
#include "pci-pc.h"
@@ -29,47 +31,12 @@
#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 IGB_IVAR_TEST_CFG \
+ ((E1000E_RX0_MSG_ID | E1000_IVAR_VALID) << (igb_ivar_entry_rx(0) * 8) | \
+ ((E1000E_TX0_MSG_ID | E1000_IVAR_VALID) << (igb_ivar_entry_tx(0) * 8)))
#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;
@@ -77,21 +44,6 @@ static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
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;
@@ -99,8 +51,9 @@ static void e1000e_pci_destructor(QOSGraphObject *obj)
qpci_msix_disable(&epci->pci_dev);
}
-static void e1000e_pci_start_hw(QOSGraphObject *obj)
+static void igb_pci_start_hw(QOSGraphObject *obj)
{
+ static const uint8_t address[] = E1000E_ADDRESS;
QE1000E_PCI *d = (QE1000E_PCI *) obj;
uint32_t val;
@@ -111,58 +64,65 @@ static void e1000e_pci_start_hw(QOSGraphObject *obj)
val = e1000e_macreg_read(&d->e1000e, E1000_CTRL);
e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST | E1000_CTRL_SLU);
+ /* Setup link */
+ e1000e_macreg_write(&d->e1000e, E1000_MDIC,
+ MII_BMCR_AUTOEN | MII_BMCR_ANRESTART |
+ (MII_BMCR << E1000_MDIC_REG_SHIFT) |
+ (1 << E1000_MDIC_PHY_SHIFT) |
+ E1000_MDIC_OP_WRITE);
+
+ qtest_clock_step(d->pci_dev.bus->qts, 900000000);
+
/* Enable and configure MSI-X */
qpci_msix_enable(&d->pci_dev);
- e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG);
+ e1000e_macreg_write(&d->e1000e, E1000_IVAR0, IGB_IVAR_TEST_CFG);
- /* Check the device status - link and speed */
+ /* Check the device link status */
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);
+ g_assert_cmphex(val & E1000_STATUS_LU, ==, E1000_STATUS_LU);
/* 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,
+ e1000e_macreg_write(&d->e1000e, E1000_TDBAL(0),
(uint32_t) d->e1000e.tx_ring);
- e1000e_macreg_write(&d->e1000e, E1000_TDBAH,
+ e1000e_macreg_write(&d->e1000e, E1000_TDBAH(0),
(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);
+ e1000e_macreg_write(&d->e1000e, E1000_TDLEN(0), E1000E_RING_LEN);
+ e1000e_macreg_write(&d->e1000e, E1000_TDT(0), 0);
+ e1000e_macreg_write(&d->e1000e, E1000_TDH(0), 0);
/* Enable transmit */
e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN);
- e1000e_macreg_write(&d->e1000e, E1000_RDBAL,
+ e1000e_macreg_write(&d->e1000e, E1000_RDBAL(0),
(uint32_t)d->e1000e.rx_ring);
- e1000e_macreg_write(&d->e1000e, E1000_RDBAH,
+ e1000e_macreg_write(&d->e1000e, E1000_RDBAH(0),
(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);
+ e1000e_macreg_write(&d->e1000e, E1000_RDLEN(0), E1000E_RING_LEN);
+ e1000e_macreg_write(&d->e1000e, E1000_RDT(0), 0);
+ e1000e_macreg_write(&d->e1000e, E1000_RDH(0), 0);
+ e1000e_macreg_write(&d->e1000e, E1000_RA,
+ le32_to_cpu(*(uint32_t *)address));
+ e1000e_macreg_write(&d->e1000e, E1000_RA + 4,
+ E1000_RAH_AV | E1000_RAH_POOL_1 |
+ le16_to_cpu(*(uint16_t *)(address + 4)));
/* 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);
+ e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
/* Enable all interrupts */
- e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
+ e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
+ e1000e_macreg_write(&d->e1000e, E1000_EIMS, 0xFFFFFFFF);
}
-static void *e1000e_pci_get_driver(void *obj, const char *interface)
+static void *igb_pci_get_driver(void *obj, const char *interface)
{
QE1000E_PCI *epci = obj;
- if (!g_strcmp0(interface, "e1000e-if")) {
+ if (!g_strcmp0(interface, "igb-if")) {
return &epci->e1000e;
}
@@ -171,12 +131,11 @@ static void *e1000e_pci_get_driver(void *obj, const char *interface)
return &epci->pci_dev;
}
- fprintf(stderr, "%s not present in e1000e\n", interface);
+ fprintf(stderr, "%s not present in igb\n", interface);
g_assert_not_reached();
}
-static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
- void *addr)
+static void *igb_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
{
QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
QPCIBus *bus = pci_bus;
@@ -196,18 +155,18 @@ static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
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.get_driver = igb_pci_get_driver;
+ d->obj.start_hw = igb_pci_start_hw;
d->obj.destructor = e1000e_pci_destructor;
return &d->obj;
}
-static void e1000e_register_nodes(void)
+static void igb_register_nodes(void)
{
QPCIAddress addr = {
.vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = E1000_DEV_ID_82574L,
+ .device_id = E1000_DEV_ID_82576,
};
/*
@@ -219,8 +178,8 @@ static void e1000e_register_nodes(void)
};
add_qpci_address(&opts, &addr);
- qos_node_create_driver("e1000e", e1000e_pci_create);
- qos_node_consumes("e1000e", "pci-bus", &opts);
+ qos_node_create_driver("igb", igb_pci_create);
+ qos_node_consumes("igb", "pci-bus", &opts);
}
-libqos_init(e1000e_register_nodes);
+libqos_init(igb_register_nodes);
@@ -30,6 +30,7 @@ libqos_srcs = files(
'i2c.c',
'i2c-imx.c',
'i2c-omap.c',
+ 'igb.c',
'sdhci.c',
'tpci200.c',
'virtio.c',
@@ -256,6 +256,7 @@ qos_test_ss.add(
'virtio-serial-test.c',
'virtio-iommu-test.c',
'vmxnet3-test.c',
+ 'igb-test.c',
)
if config_host.has_key('CONFIG_POSIX')
qos_test_ss.add(files('e1000e-test.c'))
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> --- tests/qtest/fuzz/generic_fuzz_configs.h | 5 + tests/qtest/igb-test.c | 67 ++++++------ tests/qtest/libqos/igb.c | 139 +++++++++--------------- tests/qtest/libqos/meson.build | 1 + tests/qtest/meson.build | 1 + 5 files changed, 90 insertions(+), 123 deletions(-)