Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ modules.order
vmlinux.*dom*
**/include/config/**

# QEMU downloaded by build.sh script
qemu
# QEMU downloaded by build.sh script. Anchored: an unanchored "qemu" also
# matches the DIRECTORIES of that name inside the layers (meta-qemu/
# recipes-qemu/qemu/), which silently swallowed the recipe's patch files.
/qemu

# Backup files
*~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
SRC_URI += "\
file://0001-virt.c.patch \
file://0002-virt.h.patch \
file://0003-Kconfig.patch \
"
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -82,6 +82,10 @@
@@ -42,6 +42,7 @@
#include "hw/vfio/vfio-amd-xgbe.h"
#include "hw/display/ramfb.h"
#include "net/net.h"
+#include "hw/net/lan9118.h"
#include "sysemu/device_tree.h"
#include "sysemu/numa.h"
#include "sysemu/runstate.h"
@@ -82,6 +83,10 @@
#include "hw/char/pl011.h"
#include "qemu/guest-random.h"

Expand All @@ -11,7 +19,7 @@
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
void *data) \
@@ -145,6 +149,12 @@
@@ -145,6 +150,20 @@
[VIRT_GIC_ITS] = { 0x08080000, 0x00020000 },
/* This redistributor space allows up to 2*64kB*123 CPUs */
[VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 },
Expand All @@ -20,23 +28,45 @@
+ [VIRT_KMI0] = { 0x08801000, 0x00001000 },
+ [VIRT_KMI1] = { 0x08802000, 0x00001000 },
+ [VIRT_ABSMOUSE] = { 0x08803000, 0x00001000 },
+
+ /* SMSC LAN9118 Ethernet MAC. It sits with the other SO3-added devices
+ * rather than at the 0x1a000000 the SO3 device trees inherited from
+ * vexpress-a15: that address falls inside VIRT_PCIE_MMIO below, whose
+ * gpex window covers the whole range and shadows anything mapped
+ * underneath it (the guest then reads back nothing and the chip is
+ * never detected). */
+ [VIRT_ETH] = { 0x08804000, 0x00001000 },
+
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
@@ -199,6 +209,11 @@
@@ -199,6 +218,12 @@
[VIRT_SECURE_UART] = 8,
[VIRT_ACPI_GED] = 9,
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
+
+ [VIRT_CLCD] = 10,
+ [VIRT_KMI0] = 11,
+ [VIRT_KMI1] = 12,
+ [VIRT_ETH] = 15,
+
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
@@ -2022,6 +2037,109 @@
@@ -1487,6 +1512,12 @@
vms->bus = pci->bus;
if (vms->bus) {
for (i = 0; i < nb_nics; i++) {
+ /* Skip a slot an on-board NIC already took (the SO3 LAN9118
+ * created just before this call): the PCI code would reject its
+ * model with "Unsupported NIC model: lan9118". */
+ if (nd_table[i].instantiated) {
+ continue;
+ }
pci_nic_init_nofail(&nd_table[i], pci->bus, mc->default_nic, NULL);
}
}
@@ -2022,6 +2053,109 @@
}
}

Expand Down Expand Up @@ -146,7 +176,33 @@
static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
@@ -2326,6 +2444,51 @@
@@ -2287,6 +2421,25 @@

create_rtc(vms);

+ /* SMSC LAN9118 Ethernet MAC — the NIC the SO3 smc911x driver
+ * (devices/net/smc911x_lwip.c, "smsc,smc911x") binds to, at the address
+ * and SPI the SO3 device trees declare. QEMU's own virt machine offers
+ * only virtio-net, which SO3 has no driver for.
+ *
+ * Taken from the legacy on-board NIC slot, so a run without -nic/-net
+ * leaves the machine exactly as it was and the guest simply finds no chip
+ * (smc911x_detect_chip() fails cleanly). scripts/st.sh passes
+ * "-nic user,model=lan9118".
+ *
+ * This has to happen BEFORE create_pcie(): that one hands every nd_table
+ * entry no on-board device has claimed to pci_nic_init_nofail(), which
+ * bails out with "Unsupported NIC model: lan9118".
+ */
+ if (nd_table[0].used) {
+ lan9118_init(&nd_table[0], vms->memmap[VIRT_ETH].base,
+ qdev_get_gpio_in(vms->gic, vms->irqmap[VIRT_ETH]));
+ }
+
create_pcie(vms);

if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) {
@@ -2326,6 +2479,51 @@
vms->fw_cfg, OBJECT(vms));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -58,6 +58,12 @@
@@ -58,6 +58,13 @@
VIRT_GIC_VCPU,
VIRT_GIC_ITS,
VIRT_GIC_REDIST,
Expand All @@ -9,6 +9,7 @@
+ VIRT_KMI0,
+ VIRT_KMI1,
+ VIRT_ABSMOUSE,
+ VIRT_ETH,
+
VIRT_SMMU,
VIRT_UART,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -1,5 +1,6 @@
config ARM_VIRT
bool
+ select LAN9118 # SO3 Ethernet (smsc,smc911x)
imply PCI_DEVICES
imply TEST_DEVICES
imply VFIO_AMD_XGBE
74 changes: 64 additions & 10 deletions doc/source/lwip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,72 @@ chapter.

.. note::

Networking is **opt-in**: it is enabled with ``CONFIG_NET`` and is *off* in
the default ``virt64_defconfig``. The smc911x MAC is present on boards such as
the ARM Versatile Express; QEMU's ``virt`` machine does not provide one, so a
different NIC driver is needed to exercise the stack there.
Networking is **opt-in**: ``CONFIG_NET`` plus ``CONFIG_SMC911X``. Both are on
in the four QEMU virt defconfigs (``virt32``/``virt64``, plain and ``_fb``),
and off everywhere else — rpi4 and verdin have no driver for their own MAC
yet.

The NIC on QEMU virt
====================

QEMU's stock ``virt`` machine offers only virtio-net, which SO3 has no driver
for. The so3 QEMU patch therefore adds an **SMSC LAN9118** to the machine model,
next to the PL111/PL050 devices it already adds:

- MMIO base ``0x08804000`` (``VIRT_ETH`` in the ``hw/arm/virt.c`` memmap,
``ethernet@08804000`` in ``dts/virt{32,64}.dts``);
- interrupt SPI 15 (``irqmap[VIRT_ETH]``, and ``interrupts = <0 15 4>`` in the
same DT nodes).

Two details are worth knowing. The MAC is **not** at the ``0x1a000000`` the SO3
device trees inherited from vexpress-a15: that address is inside the PCIe MMIO
window, whose gpex alias covers the whole range and shadows anything mapped
underneath, so the guest read back nothing and never detected the chip. And it
is only instantiated when the command line fills the legacy on-board NIC slot
(``-nic``/``-net``); without it the machine is exactly as it was and
``smc911x_detect_chip()`` simply fails.

Trying it out
=============

With ``CONFIG_NET`` enabled and a supported NIC, the ``ping`` application
exercises the stack end to end. Under QEMU, ``st.sh`` attaches a **user-mode
(slirp)** network device — QEMU itself plays DHCP, DNS and NAT, and forwards host
port ``2222`` to the guest's port ``22`` — so nothing has to be set up on the host
and no ``sudo`` is needed. The trade-off is that the guest is NAT'd and not
reachable from the LAN. (``scripts/qemu-ifup.sh`` / ``qemu-ifdown.sh`` are
``ping`` exercises the stack end to end::

/ % ping -c 6 10.0.2.2
64 bytes from 10.0.2.2: icmp_seq=1 ttl=255 time=6.497070 ms
64 bytes from 10.0.2.2: icmp_seq=2 ttl=255 time=0.601074 ms
...
6 packets transmitted, 6 received, 0.000000% packet loss

``st.sh`` attaches two NICs on **user-mode (slirp)** networking — QEMU itself
plays DHCP, DNS and NAT, so nothing has to be set up on the host and no ``sudo``
is needed. The LAN9118 (``-nic user,model=lan9118``) is the one SO3 drives; the
virtio-net device is there for the Linux agency of the AVZ boot chain, and
carries the host port ``2222`` → guest port ``22`` forward. Each guest ignores
the NIC it cannot drive. The trade-off of slirp is that the guest is NAT'd and
not reachable from the LAN. (``scripts/qemu-ifup.sh`` / ``qemu-ifdown.sh`` are
leftovers from the earlier ``tap``-and-bridge setup and are no longer used.)

The interface comes up by DHCP during ``netif_add()``, so the address is
announced on the console shortly after boot::

Network Interface Controller (NIC) found LAN9118
smc911x: detected LAN9118 controller
IP Network up and running with address 10.0.2.15

Pinging past the slirp gateway (``10.0.2.2``) needs the **host** to let QEMU
open ICMP sockets, otherwise slirp emulates the echo over UDP and relays back
the port-unreachable it gets::

From 192.168.1.1 icmp_seq=1 Destination Port Unreachable

The kernel decides that with ``net.ipv4.ping_group_range``, whose default on
several distributions is the empty range ``1 0``. Widening it (``sysctl -w
net.ipv4.ping_group_range="0 2147483647"``) lets slirp forward the echo for
real. Nothing in SO3 is involved either way.

.. note::

The **RX Status Level** the driver programs into ``FIFO_INT`` must be 0: the
controller raises the RSFL interrupt when the RX status FIFO holds *more*
entries than that level, so a level of 1 only interrupts once a second frame
has arrived, and every reception stays one frame behind.
24 changes: 24 additions & 0 deletions scripts/st.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ N_QEMU_INSTANCES=`ps -A | grep qemu-system | wc -l`
launch_qemu() {
QEMU_MAC_ADDR="$(printf 'DE:AD:BE:EF:%02X:%02X\n' $((N_QEMU_INSTANCES)) $((N_QEMU_INSTANCES)))"

# Second NIC (SO3's LAN9118, see ETH_OPT below) — must not collide with
# the virtio-net one above.
QEMU_ETH_MAC_ADDR="$(printf 'DE:AD:BE:EF:%02X:%02X\n' $((0x10 + N_QEMU_INSTANCES)) $((N_QEMU_INSTANCES)))"

GDB_PORT=$((${GDB_PORT_BASE} + ${N_QEMU_INSTANCES}))

echo -e "\033[01;36mMAC addr: " ${QEMU_MAC_ADDR} "\033[0;37m"
Expand Down Expand Up @@ -81,6 +85,24 @@ launch_qemu() {
DISPLAY_OPT="-display none"
fi

# Networking. Two NICs are attached, because the two kinds of guest this
# script boots need different ones:
#
# * virtio-net for the Linux agency (AVZ boot chain) — it has no
# smc911x node in its device tree, and hostfwd puts guest ssh on host
# port 2222;
# * an SMSC LAN9118 for SO3, whose only Ethernet driver is smc911x
# (devices/net/smc911x_lwip.c). QEMU's stock 'virt' machine has no
# such device; the so3 QEMU patch adds one at 0x08804000 / SPI 15 —
# the address and IRQ the SO3 device trees declare — and creates it
# only when the legacy on-board NIC slot is filled, which is what
# -nic does here.
#
# Both sit on their own user-mode (slirp) stack: QEMU plays DHCP, DNS and
# NAT internally, so the guest gets 10.0.2.15 with no host setup and no
# sudo. Whichever guest is booted simply ignores the NIC it cannot drive.
ETH_OPT="-nic user,model=lan9118,mac=${QEMU_ETH_MAC_ADDR}"

if [ "$IB_PLATFORM" == "virt64" ]; then
QEMU_BIN="$IB_ROOT_DIR/qemu/build/qemu-system-aarch64"
echo Starting on virt64
Expand Down Expand Up @@ -135,6 +157,7 @@ launch_qemu() {
${DISPLAY_OPT} \
-netdev user,id=n1,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=n1,mac=${QEMU_MAC_ADDR} \
${ETH_OPT} \
-gdb tcp::${GDB_PORT}
fi

Expand All @@ -158,6 +181,7 @@ launch_qemu() {
${DISPLAY_OPT} \
-netdev user,id=n1,hostfwd=tcp::2222-:22 \
-device virtio-net-device,netdev=n1,mac=${QEMU_MAC_ADDR} \
${ETH_OPT} \
-gdb tcp::${GDB_PORT}
fi

Expand Down
3 changes: 2 additions & 1 deletion so3/so3/configs/virt32_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ CONFIG_SCHED_FREQ_PREEMPTION=y
CONFIG_UART=y
CONFIG_IO_MAPPING_BASE=0xe0000000
# CONFIG_I2C is not set
# CONFIG_NET is not set
CONFIG_NET=y
# CONFIG_FB is not set
# CONFIG_INPUT is not set
# CONFIG_NS16550 is not set
Expand All @@ -52,6 +52,7 @@ CONFIG_GIC=y
CONFIG_GIC_V2=y
# CONFIG_PL050_KMI is not set
# CONFIG_VIRT_INPUT is not set
CONFIG_SMC911X=y

#
# SO3 Applications
Expand Down
3 changes: 2 additions & 1 deletion so3/so3/configs/virt32_fb_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ CONFIG_SCHED_FREQ_PREEMPTION=y
CONFIG_UART=y
CONFIG_IO_MAPPING_BASE=0xe0000000
# CONFIG_I2C is not set
# CONFIG_NET is not set
CONFIG_NET=y
CONFIG_FB=y
CONFIG_INPUT=y
# CONFIG_NS16550 is not set
Expand All @@ -55,6 +55,7 @@ CONFIG_PL111_CLCD=y
# CONFIG_VIRTFB is not set
CONFIG_PL050_KMI=y
# CONFIG_VIRT_INPUT is not set
CONFIG_SMC911X=y

#
# SO3 Applications
Expand Down
3 changes: 2 additions & 1 deletion so3/so3/configs/virt64_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ CONFIG_SCHED_FREQ_PREEMPTION=y
CONFIG_UART=y
CONFIG_IO_MAPPING_BASE=0xffff900000000000
# CONFIG_I2C is not set
# CONFIG_NET is not set
CONFIG_NET=y
# CONFIG_FB is not set
# CONFIG_INPUT is not set
# CONFIG_NS16550 is not set
Expand All @@ -55,6 +55,7 @@ CONFIG_GIC_V2=y
# CONFIG_PL111_CLCD is not set
# CONFIG_QEMU_RAMFB is not set
# CONFIG_PL050_KMI is not set
CONFIG_SMC911X=y

#
# SO3 Applications
Expand Down
3 changes: 2 additions & 1 deletion so3/so3/configs/virt64_fb_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ CONFIG_SCHED_FREQ_PREEMPTION=y
CONFIG_UART=y
CONFIG_IO_MAPPING_BASE=0xffff900000000000
# CONFIG_I2C is not set
# CONFIG_NET is not set
CONFIG_NET=y
CONFIG_FB=y
CONFIG_INPUT=y
# CONFIG_NS16550 is not set
Expand All @@ -57,6 +57,7 @@ CONFIG_PL111_CLCD=y
# CONFIG_VIRTFB is not set
CONFIG_PL050_KMI=y
# CONFIG_VIRT_INPUT is not set
CONFIG_SMC911X=y

#
# SO3 Applications
Expand Down
2 changes: 1 addition & 1 deletion so3/so3/devices/net/Kconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

config SMC911X
bool "smc911x network interface"
depends on VIRT32
depends on VIRT32 || VIRT64
depends on NET


Expand Down
Loading
Loading