Add two new groups of functional tests that cover scenarios currently
missing from the ppc64 test suite:
1. pseries live migration (pseries machine type)
- Extends the quick migration suite (already covering mac99) with
tcp-localhost, UNIX socket, and exec (socat) migration tests for
the pseries machine type. This complements the existing
test_ppc64_linux_migration test in test_pseries.py (which boots a
full kernel) by providing lightweight no-boot migration smoke tests
that run quickly.
2. PowerNV NVMe + network device boot (powernv machine type)
- The existing do_test_ppc64_powernv() helper in test_powernv.py
already boots a rootfs from NVMe for P8/P9/P10/P11. This patch
adds a complementary test that also verifies the e1000e network
adapter and USB xHCI controller are probed successfully by Linux -
previously these were present in the device args but no console
check was made for them.
- Adds test_powernv10_rainier() for the powernv10-rainier variant
that models the IBM Rainier system board.
Signed-off-by: Aniket Sahu <[email protected]>
diff --git a/tests/functional/ppc64/meson.build
b/tests/functional/ppc64/meson.build
index cb3c745624..19c32c8b67 100644
--- a/tests/functional/ppc64/meson.build
+++ b/tests/functional/ppc64/meson.build
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-or-later
test_ppc64_timeouts = {
+ 'pseries_migrate' : 60,
+ 'powernv_devices' : 480,
'fadump' : 480,
'hv' : 1000,
'mac99' : 120,
@@ -14,12 +16,14 @@ test_ppc64_timeouts = {
tests_ppc64_system_quick = [
'migration',
'vmstate',
+ 'pseries_migrate',
]
tests_ppc64_system_thorough = [
'e500',
'fadump',
'hv',
+ 'powernv_devices',
'mac99',
'openbsd',
'powernv',
diff --git a/tests/functional/ppc64/test_powernv_devices.py
b/tests/functional/ppc64/test_powernv_devices.py
new file mode 100644
index 0000000000..6135855612
--- /dev/null
+++ b/tests/functional/ppc64/test_powernv_devices.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+#
+# Functional tests that boot Linux on powernv machines and explicitly
+# verify that PCIe-attached devices (NVMe, e1000e, xHCI USB) are
+# detected by the guest kernel. Also covers the powernv10-rainier
+# board variant.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class PowerNVDevicesTest(LinuxKernelTest):
+ """
+ Boot Linux on powernv variants and verify that PCIe devices are
+ detected by the guest.
+
+ The existing test_powernv.py::do_test_ppc64_powernv() attaches an
+ NVMe drive, an e1000e NIC, and an xHCI USB controller, but only
+ waits for the CPU-generation string and the init process. This
+ test adds explicit console pattern checks for each device so that
+ regressions in device enumeration or PCI/PCIe topology are caught.
+
+ An additional test covers powernv10-rainier (the IBM Rainier system
+ board variant) which has a slightly different PHB topology.
+ """
+
+ timeout = 480
+
+ ASSET_KERNEL = Asset(
+ ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/'
+ 'buildroot/qemu_ppc64le_powernv8-2025.02/vmlinux'),
+ '6fd29aff9ad4362511ea5d0acbb510667c7031928e97d64ec15bbc5daf4b8151')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/'
+ 'buildroot/qemu_ppc64le_powernv8-2025.02/rootfs.ext2'),
+ 'aee2192b692077c4bde31cb56ce474424b358f17cec323d5c94af3970c9aada2')
+
+ def setUp(self):
+ super().setUp()
+ self.require_accelerator('tcg')
+
+ def _do_test_powernv_pcie_devices(self, machine):
+ """
+ Boot *machine* and verify NVMe, e1000e, and xHCI are detected.
+
+ Device topology (matches the existing do_test_ppc64_powernv
helper):
+ pcie.2 → NVMe drive (boot device, rootfs)
+ bridge1 → e1000e NIC (addr 0x3)
+ bridge1 → nec-usb-xhci (addr 0x2)
+
+ Expected kernel log patterns checked:
+ * "nvme nvme0" — NVMe controller probe
+ * "e1000e" — Intel e1000e NIC probe
+ * "xhci_hcd" — USB xHCI host controller probe
+ * "Run /sbin/init as init process" — reached userland
+ """
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+
+ self.set_machine(machine)
+ self.vm.set_console()
+ self.vm.add_args(
+ '-kernel', kernel_path,
+ '-drive',
+ f'file={initrd_path},format=raw,if=none,id=drive0,readonly=on',
+ '-append', 'root=/dev/nvme0n1 console=tty0 console=hvc0',
+ '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
+ '-device', 'nvme,drive=drive0,bus=pcie.2,addr=0x0,serial=1234',
+ '-device', 'e1000e,bus=bridge1,addr=0x3',
+ '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2',
+ )
+ self.vm.launch()
+
+ # NVMe controller should be detected first (it is the boot disk).
+ self.wait_for_console_pattern('nvme nvme0')
+
+ # e1000e NIC detection.
+ self.wait_for_console_pattern('e1000e')
+
+ # USB xHCI host controller detection.
+ self.wait_for_console_pattern('xhci_hcd')
+
+ # System reached userland — final sanity check.
+ self.wait_for_console_pattern('Run /sbin/init as init process')
+
+ def test_powernv8_pcie_devices(self):
+ """powernv8 (P8): NVMe + e1000e + xHCI detected."""
+ self._do_test_powernv_pcie_devices('powernv8')
+
+ def test_powernv9_pcie_devices(self):
+ """powernv9 (P9): NVMe + e1000e + xHCI detected."""
+ self._do_test_powernv_pcie_devices('powernv9')
+
+ def test_powernv10_pcie_devices(self):
+ """powernv10 (P10): NVMe + e1000e + xHCI detected."""
+ self._do_test_powernv_pcie_devices('powernv10')
+
+ def test_powernv11_pcie_devices(self):
+ """powernv11 (P11): NVMe + e1000e + xHCI detected."""
+ self._do_test_powernv_pcie_devices('powernv11')
+
+ def test_powernv10_rainier_pcie_devices(self):
+ """
+ powernv10-rainier: NVMe + e1000e + xHCI detected.
+
+ The Rainier board variant maps PCIe root ports slightly
+ differently from the default powernv10 topology. Verify that
+ the same device set is enumerated successfully.
+ """
+ self._do_test_powernv_pcie_devices('powernv10-rainier')
+
+ def test_powernv9_hpt_pcie_devices(self):
+ """
+ powernv9 booted with disable_radix (HPT mode): verify devices.
+
+ Radix MMU is the default on P9. Force the HPT (Hash Page Table)
+ MMU path to exercise an alternative translation code path while
+ still ensuring PCI devices are enumerated correctly.
+ """
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+
+ self.set_machine('powernv9')
+ self.vm.set_console()
+ self.vm.add_args(
+ '-kernel', kernel_path,
+ '-drive',
+ f'file={initrd_path},format=raw,if=none,id=drive0,readonly=on',
+ '-append',
+ 'root=/dev/nvme0n1 console=tty0 console=hvc0 disable_radix',
+ '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
+ '-device', 'nvme,drive=drive0,bus=pcie.2,addr=0x0,serial=1234',
+ '-device', 'e1000e,bus=bridge1,addr=0x3',
+ '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2',
+ )
+ self.vm.launch()
+
+ # HPT-specific boot message.
+ self.wait_for_console_pattern('hash-mmu: Initializing hash mmu')
+
+ # Device checks same as the radix path.
+ self.wait_for_console_pattern('nvme nvme0')
+ self.wait_for_console_pattern('e1000e')
+ self.wait_for_console_pattern('xhci_hcd')
+ self.wait_for_console_pattern('Run /sbin/init as init process')
+
+
+if __name__ == '__main__':
+ PowerNVDevicesTest.main()
diff --git a/tests/functional/ppc64/test_pseries_migrate.py
b/tests/functional/ppc64/test_pseries_migrate.py
new file mode 100644
index 0000000000..0cb929e35f
--- /dev/null
+++ b/tests/functional/ppc64/test_pseries_migrate.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Lightweight (no-boot) migration smoke tests for the pseries machine type.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from migration import MigrationTest
+
+
+class PseriesMigrationTest(MigrationTest):
+ """
+ Lightweight migration smoke tests for pseries.
+
+ No kernel is booted — QEMU is launched with -nodefaults and
+ immediately migrated so the tests run in a few seconds. This
+ catches regressions in the pseries vmstate save/restore path
+ without the overhead of a full kernel boot.
+
+ These complement the existing test_ppc64_linux_migration test in
+ test_pseries.py which exercises migration mid-boot.
+ """
+
+ timeout = 60
+
+ def test_pseries_migration_with_tcp_localhost(self):
+ """Basic TCP-localhost migration for pseries."""
+ self.set_machine('pseries')
+ self.migration_with_tcp_localhost()
+
+ def test_pseries_migration_with_unix(self):
+ """UNIX socket migration for pseries."""
+ self.set_machine('pseries')
+ self.migration_with_unix()
+
+ def test_pseries_migration_with_exec(self):
+ """exec (socat) migration for pseries."""
+ self.set_machine('pseries')
+ self.migration_with_exec()
+
+ def test_powernv_migration_with_tcp_localhost(self):
+ """Basic TCP-localhost migration for powernv."""
+ self.set_machine('powernv')
+ self.migration_with_tcp_localhost()
+
+ def test_powernv_migration_with_unix(self):
+ """UNIX socket migration for powernv."""
+ self.set_machine('powernv')
+ self.migration_with_unix()
+
+ def test_powernv_migration_with_exec(self):
+ """exec (socat) migration for powernv."""
+ self.set_machine('powernv')
+ self.migration_with_exec()
+
+
+if __name__ == '__main__':
+ MigrationTest.main()
--
2.53.0