Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
Cc: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
tests/qtest/libqos/e1000e.h | 11 ++++-
tests/qtest/libqos/e1000e.c | 87 +++++++++++++++++++++++++++++++++++--
tests/qtest/libqos/igb.c | 9 ++++
3 files changed, 102 insertions(+), 5 deletions(-)
diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h
index 30643c80949..63aa8c28a39 100644
--- a/tests/qtest/libqos/e1000e.h
+++ b/tests/qtest/libqos/e1000e.h
@@ -22,8 +22,13 @@
#include "qgraph.h"
#include "pci.h"
-#define E1000E_RX0_MSG_ID (0)
-#define E1000E_TX0_MSG_ID (1)
+enum {
+ E1000E_RX0_MSG_ID,
+ E1000E_TX0_MSG_ID,
+ E1000E_MSG_ID_MAX
+};
+
+#define E1000E_MSIX_DATA ((uint32_t[]) { 0x12345678, 0xabcdef00 })
#define E1000E_ADDRESS { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }
@@ -40,6 +45,7 @@ struct QE1000E_PCI {
QPCIDevice pci_dev;
QPCIBar mac_regs;
QE1000E e1000e;
+ uint64_t msix_msg_addr[E1000E_MSG_ID_MAX];
};
static inline void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
@@ -57,5 +63,6 @@ static inline uint32_t e1000e_macreg_read(QE1000E *d,
uint32_t reg)
void e1000e_wait_isr(QE1000E *d, uint16_t msg_id);
void e1000e_tx_ring_push(QE1000E *d, void *descr);
void e1000e_rx_ring_push(QE1000E *d, void *descr);
+void e1000e_pci_msix_enable_rxtxq_vectors(QE1000E_PCI *d);
#endif
diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c
index 925654c7fd4..49bedb5e009 100644
--- a/tests/qtest/libqos/e1000e.c
+++ b/tests/qtest/libqos/e1000e.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "hw/net/e1000_regs.h"
#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
#include "../libqtest.h"
#include "pci-pc.h"
#include "qemu/sockets.h"
@@ -77,16 +78,48 @@ static void e1000e_foreach_callback(QPCIDevice *dev, int
devfn, void *data)
g_free(dev);
}
+static bool e1000e_test_msix_irq(QE1000E *d, uint16_t msg_id,
+ uint64_t guest_msix_addr,
+ uint32_t msix_data)
+{
+ QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+ QPCIDevice *pci_dev = &d_pci->pci_dev;
+ uint32_t data;
+
+ /* msix irq test must enable msix */
+ g_assert(pci_dev->msix_enabled);
+
+ /* Vector must be enabled (e.g., with enable_rxtxq_vectors) */
+ g_assert(!qpci_msix_masked(pci_dev, msg_id));
+
+ data = qtest_readl(pci_dev->bus->qts, guest_msix_addr);
+ if (data == msix_data) {
+ /* Clear msix addr ready for next interrupt */
+ qtest_writel(pci_dev->bus->qts, guest_msix_addr, 0);
+ return true;
+ } else if (data == 0) {
+ return false;
+ } else {
+ /* Must only be either 0 (no interrupt) or the msix data. */
+ g_assert_not_reached();
+ }
+}
+
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;
+ QPCIDevice *pci_dev = &d_pci->pci_dev;
+ uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+ uint64_t guest_msix_addr = d_pci->msix_msg_addr[msg_id];
+ uint32_t msix_data = E1000E_MSIX_DATA[msg_id];
+
+ assert(pci_dev->msix_enabled);
do {
- if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
+ if (e1000e_test_msix_irq(d, msg_id, guest_msix_addr, msix_data)) {
return;
}
- qtest_clock_step(d_pci->pci_dev.bus->qts, 10000);
+ qtest_clock_step(pci_dev->bus->qts, 10000);
} while (g_get_monotonic_time() < end_time);
g_error("Timeout expired");
@@ -99,6 +132,45 @@ static void e1000e_pci_destructor(QOSGraphObject *obj)
qpci_msix_disable(&epci->pci_dev);
}
+static void e1000e_pci_msix_enable_vector(QE1000E_PCI *d, uint16_t msg_id)
+{
+ QPCIDevice *pci_dev = &d->pci_dev;
+ uint64_t guest_msix_addr = d->msix_msg_addr[msg_id];
+ uint32_t msix_data = E1000E_MSIX_DATA[msg_id];
+ uint32_t control;
+ uint64_t off;
+
+ g_assert_cmpint(msg_id , >=, 0);
+ g_assert_cmpint(msg_id , <, qpci_msix_table_size(pci_dev));
+ g_assert_cmpint(msg_id , <, E1000E_MSG_ID_MAX);
+ g_assert(guest_msix_addr != 0);
+ g_assert(msix_data != 0);
+
+ off = pci_dev->msix_table_off + (msg_id * 16);
+
+ qpci_io_writel(pci_dev, pci_dev->msix_table_bar,
+ off + PCI_MSIX_ENTRY_LOWER_ADDR, guest_msix_addr & ~0UL);
+ qpci_io_writel(pci_dev, pci_dev->msix_table_bar,
+ off + PCI_MSIX_ENTRY_UPPER_ADDR,
+ (guest_msix_addr >> 32) & ~0UL);
+ qpci_io_writel(pci_dev, pci_dev->msix_table_bar,
+ off + PCI_MSIX_ENTRY_DATA, msix_data);
+
+ control = qpci_io_readl(pci_dev, pci_dev->msix_table_bar,
+ off + PCI_MSIX_ENTRY_VECTOR_CTRL);
+ qpci_io_writel(pci_dev, pci_dev->msix_table_bar,
+ off + PCI_MSIX_ENTRY_VECTOR_CTRL,
+ control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
+}
+
+void e1000e_pci_msix_enable_rxtxq_vectors(QE1000E_PCI *d)
+{
+ g_assert(d->pci_dev.msix_enabled);
+
+ e1000e_pci_msix_enable_vector(d, E1000E_RX0_MSG_ID);
+ e1000e_pci_msix_enable_vector(d, E1000E_TX0_MSG_ID);
+}
+
static void e1000e_pci_start_hw(QOSGraphObject *obj)
{
QE1000E_PCI *d = (QE1000E_PCI *) obj;
@@ -113,6 +185,7 @@ static void e1000e_pci_start_hw(QOSGraphObject *obj)
/* Enable and configure MSI-X */
qpci_msix_enable(&d->pci_dev);
+ e1000e_pci_msix_enable_rxtxq_vectors(d);
e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG);
/* Check the device status - link and speed */
@@ -196,6 +269,14 @@ 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);
+ /* Allocate and clear msix msg addr for TX */
+ d->msix_msg_addr[E1000E_TX0_MSG_ID] = guest_alloc(alloc, 4);
+ g_assert(d->msix_msg_addr[E1000E_TX0_MSG_ID] != 0);
+
+ /* Allocate and clear msix msg addr for RX */
+ d->msix_msg_addr[E1000E_RX0_MSG_ID] = guest_alloc(alloc, 4);
+ g_assert(d->msix_msg_addr[E1000E_RX0_MSG_ID] != 0);
+
d->obj.get_driver = e1000e_pci_get_driver;
d->obj.start_hw = e1000e_pci_start_hw;
d->obj.destructor = e1000e_pci_destructor;
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
index f40c4ec4cd2..c902634b3df 100644
--- a/tests/qtest/libqos/igb.c
+++ b/tests/qtest/libqos/igb.c
@@ -75,6 +75,7 @@ static void igb_pci_start_hw(QOSGraphObject *obj)
/* Enable and configure MSI-X */
qpci_msix_enable(&d->pci_dev);
+ e1000e_pci_msix_enable_rxtxq_vectors(d);
e1000e_macreg_write(&d->e1000e, E1000_IVAR0, IGB_IVAR_TEST_CFG);
/* Check the device link status */
@@ -161,6 +162,14 @@ static void *igb_pci_create(void *pci_bus, QGuestAllocator
*alloc, void *addr)
d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
g_assert(d->e1000e.rx_ring != 0);
+ /* Allocate and clear msix msg addr for TX */
+ d->msix_msg_addr[E1000E_TX0_MSG_ID] = guest_alloc(alloc, 4);
+ g_assert(d->msix_msg_addr[E1000E_TX0_MSG_ID] != 0);
+
+ /* Allocate and clear msix msg addr for RX */
+ d->msix_msg_addr[E1000E_RX0_MSG_ID] = guest_alloc(alloc, 4);
+ g_assert(d->msix_msg_addr[E1000E_RX0_MSG_ID] != 0);
+
d->obj.get_driver = igb_pci_get_driver;
d->obj.start_hw = igb_pci_start_hw;
d->obj.destructor = e1000e_pci_destructor;