mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 09:43:56 -06:00
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJkCvgFAAoJEO8Ells5jWIRHiUH/jhydpJHIqnAPxHQAwGtmyhb 9Z52UOzW5V6KxfZJ+bQ4RPFkS2UwcxmeadPHY4zvvJTVBLAgG3QVgP4igj8CXKCI xRnwMgTNeu655kZQ5P/elTwdBTCJFODk7Egg/bH3H1ZiUhXBhVRhK7q/wMgtlZkZ Kexo6txCK4d941RNzEh45ZaGhdELE+B+D7cRuQgBs/DXZtJpsyEzBbP8KYSMHuER AXfWo0YIBYj7X3ek9D6j0pbOkB61vqtYd7W6xV4iDrJCcFBIOspJbbBb1tGCHola AXo5/OhRmiQnp/c/HTbJIDbrj0sq/r7LxYK4zY1x7UPbewHS9R+wz+FfqSmoBF0= =056y -----END PGP SIGNATURE----- Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging # -----BEGIN PGP SIGNATURE----- # Version: GnuPG v1 # # iQEcBAABAgAGBQJkCvgFAAoJEO8Ells5jWIRHiUH/jhydpJHIqnAPxHQAwGtmyhb # 9Z52UOzW5V6KxfZJ+bQ4RPFkS2UwcxmeadPHY4zvvJTVBLAgG3QVgP4igj8CXKCI # xRnwMgTNeu655kZQ5P/elTwdBTCJFODk7Egg/bH3H1ZiUhXBhVRhK7q/wMgtlZkZ # Kexo6txCK4d941RNzEh45ZaGhdELE+B+D7cRuQgBs/DXZtJpsyEzBbP8KYSMHuER # AXfWo0YIBYj7X3ek9D6j0pbOkB61vqtYd7W6xV4iDrJCcFBIOspJbbBb1tGCHola # AXo5/OhRmiQnp/c/HTbJIDbrj0sq/r7LxYK4zY1x7UPbewHS9R+wz+FfqSmoBF0= # =056y # -----END PGP SIGNATURE----- # gpg: Signature made Fri 10 Mar 2023 09:27:33 GMT # gpg: using RSA key EF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * tag 'net-pull-request' of https://github.com/jasowang/qemu: (44 commits) ebpf: fix compatibility with libbpf 1.0+ docs/system/devices/igb: Add igb documentation tests/avocado: Add igb test igb: Introduce qtest for igb device tests/qtest/libqos/e1000e: Export macreg functions tests/qtest/e1000e-test: Fabricate ethernet header Intrdocue igb device emulation e1000: Split header files pcie: Introduce pcie_sriov_num_vfs net/eth: Introduce EthL4HdrProto e1000e: Implement system clock net/eth: Report if headers are actually present e1000e: Count CRC in Tx statistics e1000: Count CRC in Tx statistics e1000e: Combine rx traces MAINTAINERS: Add e1000e test files MAINTAINERS: Add Akihiko Odaki as a e1000e reviewer e1000e: Do not assert when MSI-X is disabled later hw/net/net_tx_pkt: Check the payload length hw/net/net_tx_pkt: Implement TCP segmentation ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7284d53f6f
53 changed files with 9775 additions and 2307 deletions
38
tests/avocado/igb.py
Normal file
38
tests/avocado/igb.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# ethtool tests for igb registers, interrupts, etc
|
||||
|
||||
from avocado_qemu import LinuxTest
|
||||
|
||||
class IGB(LinuxTest):
|
||||
"""
|
||||
:avocado: tags=accel:kvm
|
||||
:avocado: tags=arch:x86_64
|
||||
:avocado: tags=distro:fedora
|
||||
:avocado: tags=distro_version:31
|
||||
:avocado: tags=machine:q35
|
||||
"""
|
||||
|
||||
timeout = 180
|
||||
|
||||
def test(self):
|
||||
self.require_accelerator('kvm')
|
||||
kernel_url = self.distro.pxeboot_url + 'vmlinuz'
|
||||
kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
|
||||
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
|
||||
initrd_url = self.distro.pxeboot_url + 'initrd.img'
|
||||
initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
|
||||
initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
|
||||
|
||||
# Ideally we want to test MSI as well, but it is blocked by a bug
|
||||
# fixed with:
|
||||
# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=28e96556baca7056d11d9fb3cdd0aba4483e00d8
|
||||
kernel_params = self.distro.default_kernel_params + ' pci=nomsi'
|
||||
|
||||
self.vm.add_args('-kernel', kernel_path,
|
||||
'-initrd', initrd_path,
|
||||
'-append', kernel_params,
|
||||
'-accel', 'kvm',
|
||||
'-device', 'igb')
|
||||
self.launch_and_wait()
|
||||
self.ssh_command('dnf -y install ethtool')
|
||||
self.ssh_command('ethtool -t eth1 offline')
|
|
@ -27,6 +27,7 @@
|
|||
#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"
|
||||
|
@ -35,9 +36,13 @@
|
|||
#include "libqos/e1000e.h"
|
||||
#include "hw/net/e1000_regs.h"
|
||||
|
||||
static const struct eth_header packet = {
|
||||
.h_dest = E1000E_ADDRESS,
|
||||
.h_source = E1000E_ADDRESS,
|
||||
};
|
||||
|
||||
static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
|
||||
{
|
||||
static const char test[] = "TEST";
|
||||
struct e1000_tx_desc descr;
|
||||
char buffer[64];
|
||||
int ret;
|
||||
|
@ -45,7 +50,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
|
|||
|
||||
/* Prepare test data buffer */
|
||||
uint64_t data = guest_alloc(alloc, sizeof(buffer));
|
||||
memwrite(data, test, sizeof(test));
|
||||
memwrite(data, &packet, sizeof(packet));
|
||||
|
||||
/* Prepare TX descriptor */
|
||||
memset(&descr, 0, sizeof(descr));
|
||||
|
@ -71,7 +76,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
|
|||
g_assert_cmpint(ret, == , sizeof(recv_len));
|
||||
ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
|
||||
g_assert_cmpint(ret, ==, sizeof(buffer));
|
||||
g_assert_cmpstr(buffer, == , test);
|
||||
g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
|
||||
|
||||
/* Free test data buffer */
|
||||
guest_free(alloc, data);
|
||||
|
@ -81,15 +86,15 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
|
|||
{
|
||||
union e1000_rx_desc_extended descr;
|
||||
|
||||
char test[] = "TEST";
|
||||
int len = htonl(sizeof(test));
|
||||
struct eth_header test_iov = packet;
|
||||
int len = htonl(sizeof(packet));
|
||||
struct iovec iov[] = {
|
||||
{
|
||||
.iov_base = &len,
|
||||
.iov_len = sizeof(len),
|
||||
},{
|
||||
.iov_base = test,
|
||||
.iov_len = sizeof(test),
|
||||
.iov_base = &test_iov,
|
||||
.iov_len = sizeof(packet),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -97,8 +102,8 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
|
|||
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));
|
||||
ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(packet));
|
||||
g_assert_cmpint(ret, == , sizeof(packet) + sizeof(len));
|
||||
|
||||
/* Prepare test data buffer */
|
||||
uint64_t data = guest_alloc(alloc, sizeof(buffer));
|
||||
|
@ -119,7 +124,7 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
|
|||
|
||||
/* Check data sent to the backend */
|
||||
memread(data, buffer, sizeof(buffer));
|
||||
g_assert_cmpstr(buffer, == , test);
|
||||
g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
|
||||
|
||||
/* Free test data buffer */
|
||||
guest_free(alloc, data);
|
||||
|
|
|
@ -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",
|
||||
|
|
256
tests/qtest/igb-test.c
Normal file
256
tests/qtest/igb-test.c
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* 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>
|
||||
*
|
||||
* 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/igb_regs.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
static const struct eth_header packet = {
|
||||
.h_dest = E1000E_ADDRESS,
|
||||
.h_source = E1000E_ADDRESS,
|
||||
};
|
||||
|
||||
static void igb_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
|
||||
{
|
||||
union e1000_adv_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, &packet, sizeof(packet));
|
||||
|
||||
/* Prepare TX descriptor */
|
||||
memset(&descr, 0, sizeof(descr));
|
||||
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);
|
||||
|
||||
/* Wait for TX WB interrupt */
|
||||
e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
|
||||
|
||||
/* Check DD bit */
|
||||
g_assert_cmphex(le32_to_cpu(descr.wb.status) & 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, &packet, sizeof(packet)));
|
||||
|
||||
/* Free test data buffer */
|
||||
guest_free(alloc, data);
|
||||
}
|
||||
|
||||
static void igb_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
|
||||
{
|
||||
union e1000_adv_rx_desc descr;
|
||||
|
||||
struct eth_header test_iov = packet;
|
||||
int len = htonl(sizeof(packet));
|
||||
struct iovec iov[] = {
|
||||
{
|
||||
.iov_base = &len,
|
||||
.iov_len = sizeof(len),
|
||||
},{
|
||||
.iov_base = &test_iov,
|
||||
.iov_len = sizeof(packet),
|
||||
},
|
||||
};
|
||||
|
||||
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(packet));
|
||||
g_assert_cmpint(ret, == , sizeof(packet) + sizeof(len));
|
||||
|
||||
/* Prepare test data buffer */
|
||||
uint64_t data = guest_alloc(alloc, sizeof(buffer));
|
||||
|
||||
/* Prepare RX descriptor */
|
||||
memset(&descr, 0, sizeof(descr));
|
||||
descr.read.pkt_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, &packet, sizeof(packet)));
|
||||
|
||||
/* 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_igb_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;
|
||||
}
|
||||
|
||||
igb_send_verify(d, data, alloc);
|
||||
}
|
||||
|
||||
static void test_igb_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;
|
||||
}
|
||||
|
||||
igb_receive_verify(d, data, alloc);
|
||||
}
|
||||
|
||||
static void test_igb_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++) {
|
||||
igb_send_verify(d, data, alloc);
|
||||
igb_receive_verify(d, data, alloc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void *data_test_init_no_socket(GString *cmd_line, void *arg)
|
||||
{
|
||||
g_string_append(cmd_line, " -netdev hubport,hubid=0,id=hs0 ");
|
||||
return arg;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (dev->pci_dev.bus->not_hotpluggable) {
|
||||
g_test_skip("pci bus does not support hotplug");
|
||||
return;
|
||||
}
|
||||
|
||||
qtest_qmp_device_add(qts, "igb", "igb_net", "{'addr': '0x06'}");
|
||||
qpci_unplug_acpi_device_test(qts, "igb_net", 0x06);
|
||||
}
|
||||
|
||||
static void register_igb_test(void)
|
||||
{
|
||||
QOSGraphTestOptions opts = { 0 };
|
||||
|
||||
#ifndef _WIN32
|
||||
opts.before = data_test_init,
|
||||
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);
|
||||
#endif
|
||||
|
||||
opts.before = data_test_init_no_socket;
|
||||
qos_add_test("hotplug", "igb", test_igb_hotplug, &opts);
|
||||
}
|
||||
|
||||
libqos_init(register_igb_test);
|
|
@ -36,18 +36,6 @@
|
|||
|
||||
#define E1000E_RING_LEN (0x1000)
|
||||
|
||||
static void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
|
||||
{
|
||||
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
|
||||
qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
|
||||
}
|
||||
|
||||
static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
|
||||
{
|
||||
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
|
||||
return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg);
|
||||
}
|
||||
|
||||
void e1000e_tx_ring_push(QE1000E *d, void *descr)
|
||||
{
|
||||
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#define E1000E_RX0_MSG_ID (0)
|
||||
#define E1000E_TX0_MSG_ID (1)
|
||||
|
||||
#define E1000E_ADDRESS { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }
|
||||
|
||||
typedef struct QE1000E QE1000E;
|
||||
typedef struct QE1000E_PCI QE1000E_PCI;
|
||||
|
||||
|
@ -40,6 +42,18 @@ struct QE1000E_PCI {
|
|||
QE1000E e1000e;
|
||||
};
|
||||
|
||||
static inline void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
|
||||
{
|
||||
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
|
||||
qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
|
||||
}
|
||||
|
||||
static inline uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
|
||||
{
|
||||
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
|
||||
return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, 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);
|
||||
|
|
185
tests/qtest/libqos/igb.c
Normal file
185
tests/qtest/libqos/igb.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* 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
|
||||
* 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/igb_regs.h"
|
||||
#include "hw/net/mii.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 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)
|
||||
|
||||
static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
|
||||
{
|
||||
QPCIDevice *res = data;
|
||||
memcpy(res, dev, sizeof(QPCIDevice));
|
||||
g_free(dev);
|
||||
}
|
||||
|
||||
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 igb_pci_start_hw(QOSGraphObject *obj)
|
||||
{
|
||||
static const uint8_t address[] = E1000E_ADDRESS;
|
||||
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);
|
||||
|
||||
/* 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_IVAR0, IGB_IVAR_TEST_CFG);
|
||||
|
||||
/* Check the device link status */
|
||||
val = e1000e_macreg_read(&d->e1000e, E1000_STATUS);
|
||||
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);
|
||||
|
||||
e1000e_macreg_write(&d->e1000e, E1000_TDBAL(0),
|
||||
(uint32_t) d->e1000e.tx_ring);
|
||||
e1000e_macreg_write(&d->e1000e, E1000_TDBAH(0),
|
||||
(uint32_t) (d->e1000e.tx_ring >> 32));
|
||||
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(0),
|
||||
(uint32_t)d->e1000e.rx_ring);
|
||||
e1000e_macreg_write(&d->e1000e, E1000_RDBAH(0),
|
||||
(uint32_t)(d->e1000e.rx_ring >> 32));
|
||||
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);
|
||||
|
||||
/* Enable all interrupts */
|
||||
e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
|
||||
e1000e_macreg_write(&d->e1000e, E1000_EIMS, 0xFFFFFFFF);
|
||||
|
||||
}
|
||||
|
||||
static void *igb_pci_get_driver(void *obj, const char *interface)
|
||||
{
|
||||
QE1000E_PCI *epci = obj;
|
||||
if (!g_strcmp0(interface, "igb-if")) {
|
||||
return &epci->e1000e;
|
||||
}
|
||||
|
||||
/* implicit contains */
|
||||
if (!g_strcmp0(interface, "pci-device")) {
|
||||
return &epci->pci_dev;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s not present in igb\n", interface);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static void *igb_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 = igb_pci_get_driver;
|
||||
d->obj.start_hw = igb_pci_start_hw;
|
||||
d->obj.destructor = e1000e_pci_destructor;
|
||||
|
||||
return &d->obj;
|
||||
}
|
||||
|
||||
static void igb_register_nodes(void)
|
||||
{
|
||||
QPCIAddress addr = {
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = E1000_DEV_ID_82576,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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("igb", igb_pci_create);
|
||||
qos_node_consumes("igb", "pci-bus", &opts);
|
||||
}
|
||||
|
||||
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',
|
||||
|
|
|
@ -259,6 +259,7 @@ qos_test_ss.add(
|
|||
'virtio-scsi-test.c',
|
||||
'virtio-iommu-test.c',
|
||||
'vmxnet3-test.c',
|
||||
'igb-test.c',
|
||||
)
|
||||
|
||||
if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue