aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-02-23 18:59:11 +0000
committerPeter Maydell <peter.maydell@linaro.org>2024-02-23 18:59:11 +0000
commit91e3bf2e925671eb37e3b71cf7fdeb6b7f30248c (patch)
tree1acdff9476c4fc16f41e2039b86118aae18a7ebf /tests
parent3d54cbf269d63ff1d500b35b2bcf4565ff8ad485 (diff)
parent4acc505d2236190efea94746e7f22e2c07bce5d6 (diff)
downloadqemu-91e3bf2e925671eb37e3b71cf7fdeb6b7f30248c.zip
qemu-91e3bf2e925671eb37e3b71cf7fdeb6b7f30248c.tar.gz
qemu-91e3bf2e925671eb37e3b71cf7fdeb6b7f30248c.tar.bz2
Merge tag 'pull-ppc-for-9.0-20240224' of https://gitlab.com/npiggin/qemu into staging
* Avocado tests for ppc64 to boot FreeBSD, run guests with emulated or nested hypervisor facilities, among other things. * Update ppc64 CPU defaults to Power10. * Add a new powernv10-rainier machine to better capture differences between the different Power10 systems. * Implement more device models for powernv. * 4xx TLB flushing performance and correctness improvements. * Correct gdb implementation to access some important SPRs. * Misc cleanups and bug fixes. # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEETkN92lZhb0MpsKeVZ7MCdqhiHK4FAmXYuX0ACgkQZ7MCdqhi # HK6t1Q/9Hxw+MseFUa/6sbWX6mhv/8emrFFOwI9qxapxDoMyic+SjIhR5PPCYh6t # TLE1vJiV54XYB3286hz3eQfDxfHNjkgsF7PYp9SEd6D1rMT9ESxeu5NkifenEfP0 # UoTFXJyfg/OF1h+JQRrVv1m+D4mqGGNCQB4QiU3DYTmRhrhp7H3mKfUX/KvkEwiX # EqZibmrqb9SVSjT66LBQzY328mEH4nipF33QtYKfYjb6kMe8ACSznL2VYP0NmacU # T+3eHJeLtOLeRlHwYfADx2ekRHlsJuE9/fMMHJHb2qxJkHSQ7yGBqSLESAe6kNP8 # TnKJ9x4433K7IjFqaoiDONrMVJbVZDh/DUh1WWdY14iiUOYEy7uLkLtmThmNSyUB # 622Rd5Ch09JWzA/tg1aC9mR2f9boe9/Z1VeHeN8j+sVj1e6MEh8un8SER3X+9TDz # myGLsmPXQnu1yjebycuE+9RAPbR9npOAkQpE5ZfDwjUM7y4s4jzZUKUoIhtCXeEF # eIykVnaGbPlEBGpuf+E+w2ZxhZUIfxRUhuunK8Ib4TE8khJn/Ir4BxoLweSnqtKM # O4xiFvHm72RUVK232Kox5HWbFJ8XSLBUb3ABNGbXXynzAMD+THB4ImFBbysOmIkR # xcF1tWQ+xoMMcCxbx73b0PhO5AR/PgYc2ctug9rAc9fh4ypJLEs= # =LZzb # -----END PGP SIGNATURE----- # gpg: Signature made Fri 23 Feb 2024 15:27:57 GMT # gpg: using RSA key 4E437DDA56616F4329B0A79567B30276A8621CAE # gpg: Good signature from "Nicholas Piggin <npiggin@gmail.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 4E43 7DDA 5661 6F43 29B0 A795 67B3 0276 A862 1CAE * tag 'pull-ppc-for-9.0-20240224' of https://gitlab.com/npiggin/qemu: (47 commits) target/ppc: optimise ppcemb_tlb_t flushing target/ppc: 440 optimise tlbwe TLB flushing target/ppc: 4xx optimise tlbwe_lo TLB flushing target/ppc: 4xx don't flush TLB for a newly written software TLB entry target/ppc: Factor out 4xx ppcemb_tlb_t flushing target/ppc: Fix 440 tlbwe TLB invalidation gaps target/ppc: Add SMT support to time facilities target/ppc: Implement core timebase state machine and TFMR ppc/pnv: Implement the ChipTOD to Core transfer ppc/pnv: Wire ChipTOD model to powernv9 and powernv10 machines ppc/pnv: Add POWER9/10 chiptod model target/ppc: Fix move-to timebase SPR access permissions target/ppc: Improve timebase register defines naming target/ppc: Rename TBL to TB on 64-bit target/ppc: Update gdbstub to read SPR's CFAR, DEC, HDEC, TB-L/U hw/ppc: N1 chiplet wiring hw/ppc: Add N1 chiplet model hw/ppc: Add pnv nest pervasive common chiplet model ppc/pnv: Test pnv i2c master and connected devices ppc/pnv: Add a pca9554 I2C device to powernv10-rainier ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/avocado/boot_linux.py17
-rw-r--r--tests/avocado/boot_linux_console.py11
-rw-r--r--tests/avocado/migration.py1
-rw-r--r--tests/avocado/ppc_hv_tests.py202
-rw-r--r--tests/avocado/ppc_powernv.py23
-rw-r--r--tests/avocado/ppc_pseries.py20
-rw-r--r--tests/qtest/meson.build1
-rw-r--r--tests/qtest/pca9552-test.c6
-rw-r--r--tests/qtest/pnv-host-i2c-test.c491
-rw-r--r--tests/qtest/pnv-xscom-test.c61
-rw-r--r--tests/qtest/pnv-xscom.h80
11 files changed, 835 insertions, 78 deletions
diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py
index 7c47699..cdce4cb 100644
--- a/tests/avocado/boot_linux.py
+++ b/tests/avocado/boot_linux.py
@@ -93,18 +93,25 @@ class BootLinuxPPC64(LinuxTest):
timeout = 360
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
+ @skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited')
def test_pseries_tcg(self):
"""
:avocado: tags=machine:pseries
:avocado: tags=accel:tcg
- :avocado: tags=flaky
"""
self.require_accelerator("tcg")
self.vm.add_args("-accel", "tcg")
self.launch_and_wait(set_up_ssh_connection=False)
+ def test_pseries_kvm(self):
+ """
+ :avocado: tags=machine:pseries
+ :avocado: tags=accel:kvm
+ """
+ self.require_accelerator("kvm")
+ self.vm.add_args("-accel", "kvm")
+ self.vm.add_args("-machine", "cap-ccf-assist=off")
+ self.launch_and_wait(set_up_ssh_connection=False)
class BootLinuxS390X(LinuxTest):
"""
@@ -113,13 +120,11 @@ class BootLinuxS390X(LinuxTest):
timeout = 240
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
+ @skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited')
def test_s390_ccw_virtio_tcg(self):
"""
:avocado: tags=machine:s390-ccw-virtio
:avocado: tags=accel:tcg
- :avocado: tags=flaky
"""
self.require_accelerator("tcg")
self.vm.add_args("-accel", "tcg")
diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
index 3f0180e..a00202d 100644
--- a/tests/avocado/boot_linux_console.py
+++ b/tests/avocado/boot_linux_console.py
@@ -1368,7 +1368,8 @@ class BootLinuxConsole(LinuxKernelTest):
self.wait_for_console_pattern("CPU: " + proc + " generation processor")
self.wait_for_console_pattern("zImage starting: loaded")
self.wait_for_console_pattern("Run /init as init process")
- self.wait_for_console_pattern("Creating 1 MTD partitions")
+ # Device detection output driven by udev probing is sometimes cut off
+ # from console output, suspect S14silence-console init script.
def test_ppc_powernv8(self):
"""
@@ -1386,6 +1387,14 @@ class BootLinuxConsole(LinuxKernelTest):
"""
self.do_test_ppc64_powernv('P9')
+ def test_ppc_powernv10(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv10
+ :avocado: tags=accel:tcg
+ """
+ self.do_test_ppc64_powernv('P10')
+
def test_ppc_g3beige(self):
"""
:avocado: tags=arch:ppc
diff --git a/tests/avocado/migration.py b/tests/avocado/migration.py
index 09b62f8..be6234b 100644
--- a/tests/avocado/migration.py
+++ b/tests/avocado/migration.py
@@ -123,7 +123,6 @@ class PPC64(MigrationTest):
"""
:avocado: tags=arch:ppc64
:avocado: tags=machine:pseries
- :avocado: tags=cpu:power9_v2.0
"""
def test_migration_with_tcp_localhost(self):
diff --git a/tests/avocado/ppc_hv_tests.py b/tests/avocado/ppc_hv_tests.py
new file mode 100644
index 0000000..5080358
--- /dev/null
+++ b/tests/avocado/ppc_hv_tests.py
@@ -0,0 +1,202 @@
+# Tests that specifically try to exercise hypervisor features of the
+# target machines. powernv supports the Power hypervisor ISA, and
+# pseries supports the nested-HV hypervisor spec.
+#
+# Copyright (c) 2023 IBM Corporation
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from avocado import skipIf, skipUnless
+from avocado.utils import archive
+from avocado_qemu import QemuSystemTest
+from avocado_qemu import wait_for_console_pattern, exec_command
+import os
+import time
+import subprocess
+
+deps = ["xorriso"] # dependent tools needed in the test setup/box.
+
+def which(tool):
+ """ looks up the full path for @tool, returns None if not found
+ or if @tool does not have executable permissions.
+ """
+ paths=os.getenv('PATH')
+ for p in paths.split(os.path.pathsep):
+ p = os.path.join(p, tool)
+ if os.path.exists(p) and os.access(p, os.X_OK):
+ return p
+ return None
+
+def missing_deps():
+ """ returns True if any of the test dependent tools are absent.
+ """
+ for dep in deps:
+ if which(dep) is None:
+ return True
+ return False
+
+# Alpine is a light weight distro that supports QEMU. These tests boot
+# that on the machine then run a QEMU guest inside it in KVM mode,
+# that runs the same Alpine distro image.
+# QEMU packages are downloaded and installed on each test. That's not a
+# large download, but it may be more polite to create qcow2 image with
+# QEMU already installed and use that.
+@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test sometimes gets stuck due to console handling problem')
+@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
+@skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited')
+@skipIf(missing_deps(), 'dependencies (%s) not installed' % ','.join(deps))
+class HypervisorTest(QemuSystemTest):
+
+ timeout = 1000
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
+ panic_message = 'Kernel panic - not syncing'
+ good_message = 'VFS: Cannot open root device'
+
+ def extract_from_iso(self, iso, path):
+ """
+ Extracts a file from an iso file into the test workdir
+
+ :param iso: path to the iso file
+ :param path: path within the iso file of the file to be extracted
+ :returns: path of the extracted file
+ """
+ filename = os.path.basename(path)
+
+ cwd = os.getcwd()
+ os.chdir(self.workdir)
+
+ with open(filename, "w") as outfile:
+ cmd = "xorriso -osirrox on -indev %s -cpx %s %s" % (iso, path, filename)
+ subprocess.run(cmd.split(),
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+
+ os.chdir(cwd)
+
+ # Return complete path to extracted file. Because callers to
+ # extract_from_iso() specify 'path' with a leading slash, it is
+ # necessary to use os.path.relpath() as otherwise os.path.join()
+ # interprets it as an absolute path and drops the self.workdir part.
+ return os.path.normpath(os.path.join(self.workdir, filename))
+
+ def setUp(self):
+ super().setUp()
+
+ iso_url = ('https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/ppc64le/alpine-standard-3.18.4-ppc64le.iso')
+
+ # Alpine use sha256 so I recalculated this myself
+ iso_sha256 = 'c26b8d3e17c2f3f0fed02b4b1296589c2390e6d5548610099af75300edd7b3ff'
+ iso_path = self.fetch_asset(iso_url, asset_hash=iso_sha256,
+ algorithm = "sha256")
+
+ self.iso_path = iso_path
+ self.vmlinuz = self.extract_from_iso(iso_path, '/boot/vmlinuz-lts')
+ self.initramfs = self.extract_from_iso(iso_path, '/boot/initramfs-lts')
+
+ def do_start_alpine(self):
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
+ self.vm.add_args("-kernel", self.vmlinuz)
+ self.vm.add_args("-initrd", self.initramfs)
+ self.vm.add_args("-smp", "4", "-m", "2g")
+ self.vm.add_args("-drive", f"file={self.iso_path},format=raw,if=none,id=drive0")
+
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Welcome to Alpine Linux 3.18')
+ exec_command(self, 'root')
+ wait_for_console_pattern(self, 'localhost login:')
+ wait_for_console_pattern(self, 'You may change this message by editing /etc/motd.')
+ exec_command(self, 'setup-alpine -qe')
+ wait_for_console_pattern(self, 'Updating repository indexes... done.')
+
+ def do_stop_alpine(self):
+ exec_command(self, 'poweroff')
+ wait_for_console_pattern(self, 'alpine:~#')
+ self.vm.wait()
+
+ def do_setup_kvm(self):
+ exec_command(self, 'echo http://dl-cdn.alpinelinux.org/alpine/v3.18/main > /etc/apk/repositories')
+ wait_for_console_pattern(self, 'alpine:~#')
+ exec_command(self, 'echo http://dl-cdn.alpinelinux.org/alpine/v3.18/community >> /etc/apk/repositories')
+ wait_for_console_pattern(self, 'alpine:~#')
+ exec_command(self, 'apk update')
+ wait_for_console_pattern(self, 'alpine:~#')
+ exec_command(self, 'apk add qemu-system-ppc64')
+ wait_for_console_pattern(self, 'alpine:~#')
+ exec_command(self, 'modprobe kvm-hv')
+ wait_for_console_pattern(self, 'alpine:~#')
+
+ # This uses the host's block device as the source file for guest block
+ # device for install media. This is a bit hacky but allows reuse of the
+ # iso without having a passthrough filesystem configured.
+ def do_test_kvm(self, hpt=False):
+ if hpt:
+ append = 'disable_radix'
+ else:
+ append = ''
+ exec_command(self, 'qemu-system-ppc64 -nographic -smp 2 -m 1g '
+ '-machine pseries,x-vof=on,accel=kvm '
+ '-machine cap-cfpc=broken,cap-sbbc=broken,'
+ 'cap-ibs=broken,cap-ccf-assist=off '
+ '-drive file=/dev/nvme0n1,format=raw,readonly=on '
+ '-initrd /media/nvme0n1/boot/initramfs-lts '
+ '-kernel /media/nvme0n1/boot/vmlinuz-lts '
+ '-append \'usbcore.nousb ' + append + '\'')
+ # Alpine 3.18 kernel seems to crash in XHCI USB driver.
+ wait_for_console_pattern(self, 'Welcome to Alpine Linux 3.18')
+ exec_command(self, 'root')
+ wait_for_console_pattern(self, 'localhost login:')
+ wait_for_console_pattern(self, 'You may change this message by editing /etc/motd.')
+ exec_command(self, 'poweroff >& /dev/null')
+ wait_for_console_pattern(self, 'localhost:~#')
+ wait_for_console_pattern(self, 'reboot: Power down')
+ time.sleep(1)
+ exec_command(self, '')
+ wait_for_console_pattern(self, 'alpine:~#')
+
+ def test_hv_pseries(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:pseries
+ :avocado: tags=accel:tcg
+ """
+ self.require_accelerator("tcg")
+ self.vm.add_args("-accel", "tcg,thread=multi")
+ self.vm.add_args('-device', 'nvme,serial=1234,drive=drive0')
+ self.vm.add_args("-machine", "x-vof=on,cap-nested-hv=on")
+ self.do_start_alpine()
+ self.do_setup_kvm()
+ self.do_test_kvm()
+ self.do_stop_alpine()
+
+ def test_hv_pseries_kvm(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:pseries
+ :avocado: tags=accel:kvm
+ """
+ self.require_accelerator("kvm")
+ self.vm.add_args("-accel", "kvm")
+ self.vm.add_args('-device', 'nvme,serial=1234,drive=drive0')
+ self.vm.add_args("-machine", "x-vof=on,cap-nested-hv=on,cap-ccf-assist=off")
+ self.do_start_alpine()
+ self.do_setup_kvm()
+ self.do_test_kvm()
+ self.do_stop_alpine()
+
+ def test_hv_powernv(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+ self.require_accelerator("tcg")
+ self.vm.add_args("-accel", "tcg,thread=multi")
+ self.vm.add_args('-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234,drive=drive0',
+ '-device', 'e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0',
+ '-netdev', 'user,id=net0,hostfwd=::20022-:22,hostname=alpine')
+ self.do_start_alpine()
+ self.do_setup_kvm()
+ self.do_test_kvm()
+ self.do_test_kvm(True)
+ self.do_stop_alpine()
diff --git a/tests/avocado/ppc_powernv.py b/tests/avocado/ppc_powernv.py
index d0e5c07..4342941 100644
--- a/tests/avocado/ppc_powernv.py
+++ b/tests/avocado/ppc_powernv.py
@@ -12,11 +12,11 @@ from avocado_qemu import wait_for_console_pattern
class powernvMachine(QemuSystemTest):
timeout = 90
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
panic_message = 'Kernel panic - not syncing'
good_message = 'VFS: Cannot open root device'
- def do_test_linux_boot(self):
+ def do_test_linux_boot(self, command_line = KERNEL_COMMON_COMMAND_LINE):
self.require_accelerator("tcg")
kernel_url = ('https://archives.fedoraproject.org/pub/archive'
'/fedora-secondary/releases/29/Everything/ppc64le/os'
@@ -25,9 +25,8 @@ class powernvMachine(QemuSystemTest):
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
+ '-append', command_line)
self.vm.launch()
def test_linux_boot(self):
@@ -54,6 +53,22 @@ class powernvMachine(QemuSystemTest):
wait_for_console_pattern(self, console_pattern, self.panic_message)
wait_for_console_pattern(self, self.good_message, self.panic_message)
+ def test_linux_smp_hpt_boot(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:powernv
+ :avocado: tags=accel:tcg
+ """
+
+ self.vm.add_args('-smp', '4')
+ self.do_test_linux_boot(self.KERNEL_COMMON_COMMAND_LINE +
+ 'disable_radix')
+ console_pattern = 'smp: Brought up 1 node, 4 CPUs'
+ wait_for_console_pattern(self, 'hash-mmu: Initializing hash mmu',
+ self.panic_message)
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ wait_for_console_pattern(self, self.good_message, self.panic_message)
+
def test_linux_smt_boot(self):
"""
:avocado: tags=arch:ppc64
diff --git a/tests/avocado/ppc_pseries.py b/tests/avocado/ppc_pseries.py
index a8311e6..74aaa4a 100644
--- a/tests/avocado/ppc_pseries.py
+++ b/tests/avocado/ppc_pseries.py
@@ -12,11 +12,11 @@ from avocado_qemu import wait_for_console_pattern
class pseriesMachine(QemuSystemTest):
timeout = 90
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
panic_message = 'Kernel panic - not syncing'
good_message = 'VFS: Cannot open root device'
- def do_test_ppc64_linux_boot(self):
+ def do_test_ppc64_linux_boot(self, kernel_command_line = KERNEL_COMMON_COMMAND_LINE):
kernel_url = ('https://archives.fedoraproject.org/pub/archive'
'/fedora-secondary/releases/29/Everything/ppc64le/os'
'/ppc/ppc64/vmlinuz')
@@ -24,7 +24,6 @@ class pseriesMachine(QemuSystemTest):
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=hvc0'
self.vm.add_args('-kernel', kernel_path,
'-append', kernel_command_line)
self.vm.launch()
@@ -62,6 +61,21 @@ class pseriesMachine(QemuSystemTest):
wait_for_console_pattern(self, console_pattern, self.panic_message)
wait_for_console_pattern(self, self.good_message, self.panic_message)
+ def test_ppc64_linux_hpt_smp_boot(self):
+ """
+ :avocado: tags=arch:ppc64
+ :avocado: tags=machine:pseries
+ """
+
+ self.vm.add_args('-smp', '4')
+ self.do_test_ppc64_linux_boot(self.KERNEL_COMMON_COMMAND_LINE +
+ 'disable_radix')
+ console_pattern = 'smp: Brought up 1 node, 4 CPUs'
+ wait_for_console_pattern(self, 'hash-mmu: Initializing hash mmu',
+ self.panic_message)
+ wait_for_console_pattern(self, console_pattern, self.panic_message)
+ wait_for_console_pattern(self, self.good_message, self.panic_message)
+
def test_ppc64_linux_smt_boot(self):
"""
:avocado: tags=arch:ppc64
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 430d49b..6ea7789 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -167,6 +167,7 @@ qtests_ppc64 = \
qtests_ppc + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \
diff --git a/tests/qtest/pca9552-test.c b/tests/qtest/pca9552-test.c
index d80ed93..ccca2b3 100644
--- a/tests/qtest/pca9552-test.c
+++ b/tests/qtest/pca9552-test.c
@@ -60,7 +60,7 @@ static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
g_assert_cmphex(value, ==, 0x55);
value = i2c_get8(i2cdev, PCA9552_INPUT0);
- g_assert_cmphex(value, ==, 0x0);
+ g_assert_cmphex(value, ==, 0xFF);
pca9552_init(i2cdev);
@@ -68,13 +68,13 @@ static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
g_assert_cmphex(value, ==, 0x54);
value = i2c_get8(i2cdev, PCA9552_INPUT0);
- g_assert_cmphex(value, ==, 0x01);
+ g_assert_cmphex(value, ==, 0xFE);
value = i2c_get8(i2cdev, PCA9552_LS3);
g_assert_cmphex(value, ==, 0x54);
value = i2c_get8(i2cdev, PCA9552_INPUT1);
- g_assert_cmphex(value, ==, 0x10);
+ g_assert_cmphex(value, ==, 0xEF);
}
static void pca9552_register_nodes(void)
diff --git a/tests/qtest/pnv-host-i2c-test.c b/tests/qtest/pnv-host-i2c-test.c
new file mode 100644
index 0000000..c635177
--- /dev/null
+++ b/tests/qtest/pnv-host-i2c-test.c
@@ -0,0 +1,491 @@
+/*
+ * QTest testcase for PowerNV 10 Host I2C Communications
+ *
+ * Copyright (c) 2023, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "hw/misc/pca9554_regs.h"
+#include "hw/misc/pca9552_regs.h"
+#include "pnv-xscom.h"
+
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BIT32(bit) (0x80000000 >> (bit))
+#define PPC_BIT8(bit) (0x80 >> (bit))
+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \
+ PPC_BIT32(bs))
+
+#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
+#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
+#define SETFIELD(m, v, val) \
+ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
+
+#define PNV10_XSCOM_I2CM_BASE 0xa0000
+#define PNV10_XSCOM_I2CM_SIZE 0x1000
+
+#include "hw/i2c/pnv_i2c_regs.h"
+
+typedef struct {
+ QTestState *qts;
+ const PnvChip *chip;
+ int engine;
+} PnvI2cCtlr;
+
+typedef struct {
+ PnvI2cCtlr *ctlr;
+ int port;
+ uint8_t addr;
+} PnvI2cDev;
+
+
+static uint64_t pnv_i2c_xscom_addr(PnvI2cCtlr *ctlr, uint32_t reg)
+{
+ return pnv_xscom_addr(ctlr->chip, PNV10_XSCOM_I2CM_BASE +
+ (PNV10_XSCOM_I2CM_SIZE * ctlr->engine) + reg);
+}
+
+static uint64_t pnv_i2c_xscom_read(PnvI2cCtlr *ctlr, uint32_t reg)
+{
+ return qtest_readq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg));
+}
+
+static void pnv_i2c_xscom_write(PnvI2cCtlr *ctlr, uint32_t reg, uint64_t val)
+{
+ qtest_writeq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg), val);
+}
+
+/* Write len bytes from buf to i2c device with given addr and port */
+static void pnv_i2c_send(PnvI2cDev *dev, const uint8_t *buf, uint16_t len)
+{
+ int byte_num;
+ uint64_t reg64;
+
+ /* select requested port */
+ reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be);
+ reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port);
+ pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64);
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
+ g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
+ I2C_STAT_CMD_COMP);
+
+ /* Send start, with stop, with address and len bytes of data */
+ reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR | I2C_CMD_WITH_STOP;
+ reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr);
+ reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len);
+ pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64);
+
+ /* check status for errors */
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0);
+
+ /* write data bytes to fifo register */
+ for (byte_num = 0; byte_num < len; byte_num++) {
+ reg64 = SETFIELD(I2C_FIFO, 0ull, buf[byte_num]);
+ pnv_i2c_xscom_write(dev->ctlr, I2C_FIFO_REG, reg64);
+ }
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
+ g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
+ I2C_STAT_CMD_COMP);
+}
+
+/* Recieve len bytes into buf from i2c device with given addr and port */
+static void pnv_i2c_recv(PnvI2cDev *dev, uint8_t *buf, uint16_t len)
+{
+ int byte_num;
+ uint64_t reg64;
+
+ /* select requested port */
+ reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be);
+ reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port);
+ pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64);
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
+ g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
+ I2C_STAT_CMD_COMP);
+
+ /* Send start, with stop, with address and len bytes of data */
+ reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR |
+ I2C_CMD_WITH_STOP | I2C_CMD_READ_NOT_WRITE;
+ reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr);
+ reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len);
+ pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64);
+
+ /* check status for errors */
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0);
+
+ /* Read data bytes from fifo register */
+ for (byte_num = 0; byte_num < len; byte_num++) {
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_FIFO_REG);
+ buf[byte_num] = GETFIELD(I2C_FIFO, reg64);
+ }
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
+ g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
+ I2C_STAT_CMD_COMP);
+}
+
+static void pnv_i2c_pca9554_default_cfg(PnvI2cDev *dev)
+{
+ uint8_t buf[2];
+
+ /* input register bits are not inverted */
+ buf[0] = PCA9554_POLARITY;
+ buf[1] = 0;
+ pnv_i2c_send(dev, buf, 2);
+
+ /* All pins are inputs */
+ buf[0] = PCA9554_CONFIG;
+ buf[1] = 0xff;
+ pnv_i2c_send(dev, buf, 2);
+
+ /* Output value for when pins are outputs */
+ buf[0] = PCA9554_OUTPUT;
+ buf[1] = 0xff;
+ pnv_i2c_send(dev, buf, 2);
+}
+
+static void pnv_i2c_pca9554_set_pin(PnvI2cDev *dev, int pin, bool high)
+{
+ uint8_t send_buf[2];
+ uint8_t recv_buf[2];
+ uint8_t mask = 0x1 << pin;
+ uint8_t new_value = ((high) ? 1 : 0) << pin;
+
+ /* read current OUTPUT value */
+ send_buf[0] = PCA9554_OUTPUT;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+
+ /* write new OUTPUT value */
+ send_buf[1] = (recv_buf[0] & ~mask) | new_value;
+ pnv_i2c_send(dev, send_buf, 2);
+
+ /* Update config bit for output */
+ send_buf[0] = PCA9554_CONFIG;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+ send_buf[1] = recv_buf[0] & ~mask;
+ pnv_i2c_send(dev, send_buf, 2);
+}
+
+static uint8_t pnv_i2c_pca9554_read_pins(PnvI2cDev *dev)
+{
+ uint8_t send_buf[1];
+ uint8_t recv_buf[1];
+ uint8_t inputs;
+ send_buf[0] = PCA9554_INPUT;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+ inputs = recv_buf[0];
+ return inputs;
+}
+
+static void pnv_i2c_pca9554_flip_polarity(PnvI2cDev *dev)
+{
+ uint8_t recv_buf[1];
+ uint8_t send_buf[2];
+
+ send_buf[0] = PCA9554_POLARITY;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+ send_buf[1] = recv_buf[0] ^ 0xff;
+ pnv_i2c_send(dev, send_buf, 2);
+}
+
+static void pnv_i2c_pca9554_default_inputs(PnvI2cDev *dev)
+{
+ uint8_t pin_values = pnv_i2c_pca9554_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0xff);
+}
+
+/* Check that setting pin values and polarity changes inputs as expected */
+static void pnv_i2c_pca554_set_pins(PnvI2cDev *dev)
+{
+ uint8_t pin_values;
+ pnv_i2c_pca9554_set_pin(dev, 0, 0);
+ pin_values = pnv_i2c_pca9554_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0xfe);
+ pnv_i2c_pca9554_flip_polarity(dev);
+ pin_values = pnv_i2c_pca9554_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0x01);
+ pnv_i2c_pca9554_set_pin(dev, 2, 0);
+ pin_values = pnv_i2c_pca9554_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0x05);
+ pnv_i2c_pca9554_flip_polarity(dev);
+ pin_values = pnv_i2c_pca9554_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0xfa);
+ pnv_i2c_pca9554_default_cfg(dev);
+ pin_values = pnv_i2c_pca9554_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0xff);
+}
+
+static void pnv_i2c_pca9552_default_cfg(PnvI2cDev *dev)
+{
+ uint8_t buf[2];
+ /* configure pwm/psc regs */
+ buf[0] = PCA9552_PSC0;
+ buf[1] = 0xff;
+ pnv_i2c_send(dev, buf, 2);
+ buf[0] = PCA9552_PWM0;
+ buf[1] = 0x80;
+ pnv_i2c_send(dev, buf, 2);
+ buf[0] = PCA9552_PSC1;
+ buf[1] = 0xff;
+ pnv_i2c_send(dev, buf, 2);
+ buf[0] = PCA9552_PWM1;
+ buf[1] = 0x80;
+ pnv_i2c_send(dev, buf, 2);
+
+ /* configure all pins as inputs */
+ buf[0] = PCA9552_LS0;
+ buf[1] = 0x55;
+ pnv_i2c_send(dev, buf, 2);
+ buf[0] = PCA9552_LS1;
+ buf[1] = 0x55;
+ pnv_i2c_send(dev, buf, 2);
+ buf[0] = PCA9552_LS2;
+ buf[1] = 0x55;
+ pnv_i2c_send(dev, buf, 2);
+ buf[0] = PCA9552_LS3;
+ buf[1] = 0x55;
+ pnv_i2c_send(dev, buf, 2);
+}
+
+static void pnv_i2c_pca9552_set_pin(PnvI2cDev *dev, int pin, bool high)
+{
+ uint8_t send_buf[2];
+ uint8_t recv_buf[2];
+ uint8_t reg = PCA9552_LS0 + (pin / 4);
+ uint8_t shift = (pin % 4) * 2;
+ uint8_t mask = ~(0x3 << shift);
+ uint8_t new_value = ((high) ? 1 : 0) << shift;
+
+ /* read current LSx value */
+ send_buf[0] = reg;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+
+ /* write new value to LSx */
+ send_buf[1] = (recv_buf[0] & mask) | new_value;
+ pnv_i2c_send(dev, send_buf, 2);
+}
+
+static uint16_t pnv_i2c_pca9552_read_pins(PnvI2cDev *dev)
+{
+ uint8_t send_buf[2];
+ uint8_t recv_buf[2];
+ uint16_t inputs;
+ send_buf[0] = PCA9552_INPUT0;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+ inputs = recv_buf[0];
+ send_buf[0] = PCA9552_INPUT1;
+ pnv_i2c_send(dev, send_buf, 1);
+ pnv_i2c_recv(dev, recv_buf, 1);
+ inputs |= recv_buf[0] << 8;
+ return inputs;
+}
+
+static void pnv_i2c_pca9552_default_inputs(PnvI2cDev *dev)
+{
+ uint16_t pin_values = pnv_i2c_pca9552_read_pins(dev);
+ g_assert_cmphex(pin_values, ==, 0xffff);
+}
+
+/*
+ * Set pins 0-4 one at a time and verify that pins 5-9 are
+ * set to the same value
+ */
+static void pnv_i2c_pca552_set_pins(PnvI2cDev *dev)
+{
+ uint16_t pin_values;
+
+ /* set pin 0 low */
+ pnv_i2c_pca9552_set_pin(dev, 0, 0);
+ pin_values = pnv_i2c_pca9552_read_pins(dev);
+
+ /* pins 0 and 5 should be low */
+ g_assert_cmphex(pin_values, ==, 0xffde);
+
+ /* set pin 1 low */
+ pnv_i2c_pca9552_set_pin(dev, 1, 0);
+ pin_values = pnv_i2c_pca9552_read_pins(dev);
+
+ /* pins 0, 1, 5 and 6 should be low */
+ g_assert_cmphex(pin_values, ==, 0xff9c);
+
+ /* set pin 2 low */
+ pnv_i2c_pca9552_set_pin(dev, 2, 0);
+ pin_values = pnv_i2c_pca9552_read_pins(dev);
+
+ /* pins 0, 1, 2, 5, 6 and 7 should be low */
+ g_assert_cmphex(pin_values, ==, 0xff18);
+
+ /* set pin 3 low */
+ pnv_i2c_pca9552_set_pin(dev, 3, 0);
+ pin_values = pnv_i2c_pca9552_read_pins(dev);
+
+ /* pins 0, 1, 2, 3, 5, 6, 7 and 8 should be low */
+ g_assert_cmphex(pin_values, ==, 0xfe10);
+
+ /* set pin 4 low */
+ pnv_i2c_pca9552_set_pin(dev, 4, 0);
+ pin_values = pnv_i2c_pca9552_read_pins(dev);
+
+ /* pins 0, 1, 2, 3, 5, 6, 7, 8 and 9 should be low */
+ g_assert_cmphex(pin_values, ==, 0xfc00);
+
+ /* reset all pins to the high state */
+ pnv_i2c_pca9552_default_cfg(dev);
+ pin_values = pnv_i2c_pca9552_read_pins(dev);
+
+ /* verify all pins went back to the high state */
+ g_assert_cmphex(pin_values, ==, 0xffff);
+}
+
+static void reset_engine(PnvI2cCtlr *ctlr)
+{
+ pnv_i2c_xscom_write(ctlr, I2C_RESET_I2C_REG, 0);
+}
+
+static void check_i2cm_por_regs(QTestState *qts, const PnvChip *chip)
+{
+ int engine;
+ for (engine = 0; engine < chip->num_i2c; engine++) {
+ PnvI2cCtlr ctlr;
+ ctlr.qts = qts;
+ ctlr.chip = chip;
+ ctlr.engine = engine;
+
+ /* Check version in Extended Status Register */
+ uint64_t value = pnv_i2c_xscom_read(&ctlr, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(value & I2C_EXTD_STAT_I2C_VERSION, ==, 0x1700000000);
+
+ /* Check for command complete and bus idle in Status Register */
+ value = pnv_i2c_xscom_read(&ctlr, I2C_STAT_REG);
+ g_assert_cmphex(value & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP),
+ ==,
+ I2C_STAT_CMD_COMP);
+ }
+}
+
+static void reset_all(QTestState *qts, const PnvChip *chip)
+{
+ int engine;
+ for (engine = 0; engine < chip->num_i2c; engine++) {
+ PnvI2cCtlr ctlr;
+ ctlr.qts = qts;
+ ctlr.chip = chip;
+ ctlr.engine = engine;
+ reset_engine(&ctlr);
+ pnv_i2c_xscom_write(&ctlr, I2C_MODE_REG, 0x02be040000000000);
+ }
+}
+
+static void test_host_i2c(const void *data)
+{
+ const PnvChip *chip = data;
+ QTestState *qts;
+ const char *machine = "powernv8";
+ PnvI2cCtlr ctlr;
+ PnvI2cDev pca9552;
+ PnvI2cDev pca9554;
+
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10-rainier";
+ }
+
+ qts = qtest_initf("-M %s -smp %d,cores=1,threads=%d -nographic "
+ "-nodefaults -serial mon:stdio -S "
+ "-d guest_errors",
+ machine, SMT, SMT);
+
+ /* Check the I2C master status registers after POR */
+ check_i2cm_por_regs(qts, chip);
+
+ /* Now do a forced "immediate" reset on all engines */
+ reset_all(qts, chip);
+
+ /* Check that the status values are still good */
+ check_i2cm_por_regs(qts, chip);
+
+ /* P9 doesn't have any i2c devices attached at this time */
+ if (chip->chip_type != PNV_CHIP_POWER10) {
+ qtest_quit(qts);
+ return;
+ }
+
+ /* Initialize for a P10 pca9552 hotplug device */
+ ctlr.qts = qts;
+ ctlr.chip = chip;
+ ctlr.engine = 2;
+ pca9552.ctlr = &ctlr;
+ pca9552.port = 1;
+ pca9552.addr = 0x63;
+
+ /* Set all pca9552 pins as inputs */
+ pnv_i2c_pca9552_default_cfg(&pca9552);
+
+ /* Check that all pins of the pca9552 are high */
+ pnv_i2c_pca9552_default_inputs(&pca9552);
+
+ /* perform individual pin tests */
+ pnv_i2c_pca552_set_pins(&pca9552);
+
+ /* Initialize for a P10 pca9554 CableCard Presence detection device */
+ pca9554.ctlr = &ctlr;
+ pca9554.port = 1;
+ pca9554.addr = 0x25;
+
+ /* Set all pca9554 pins as inputs */
+ pnv_i2c_pca9554_default_cfg(&pca9554);
+
+ /* Check that all pins of the pca9554 are high */
+ pnv_i2c_pca9554_default_inputs(&pca9554);
+
+ /* perform individual pin tests */
+ pnv_i2c_pca554_set_pins(&pca9554);
+
+ qtest_quit(qts);
+}
+
+static void add_test(const char *name, void (*test)(const void *data))
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
+ char *tname = g_strdup_printf("pnv-xscom/%s/%s", name,
+ pnv_chips[i].cpu_model);
+ qtest_add_data_func(tname, &pnv_chips[i], test);
+ g_free(tname);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ add_test("host-i2c", test_host_i2c);
+ return g_test_run();
+}
diff --git a/tests/qtest/pnv-xscom-test.c b/tests/qtest/pnv-xscom-test.c
index 8a5ac11..c814c0f 100644
--- a/tests/qtest/pnv-xscom-test.c
+++ b/tests/qtest/pnv-xscom-test.c
@@ -10,66 +10,7 @@
#include "libqtest.h"
-typedef enum PnvChipType {
- PNV_CHIP_POWER8E, /* AKA Murano (default) */
- PNV_CHIP_POWER8, /* AKA Venice */
- PNV_CHIP_POWER8NVL, /* AKA Naples */
- PNV_CHIP_POWER9, /* AKA Nimbus */
- PNV_CHIP_POWER10,
-} PnvChipType;
-
-typedef struct PnvChip {
- PnvChipType chip_type;
- const char *cpu_model;
- uint64_t xscom_base;
- uint64_t cfam_id;
- uint32_t first_core;
-} PnvChip;
-
-static const PnvChip pnv_chips[] = {
- {
- .chip_type = PNV_CHIP_POWER8,
- .cpu_model = "POWER8",
- .xscom_base = 0x0003fc0000000000ull,
- .cfam_id = 0x220ea04980000000ull,
- .first_core = 0x1,
- }, {
- .chip_type = PNV_CHIP_POWER8NVL,
- .cpu_model = "POWER8NVL",
- .xscom_base = 0x0003fc0000000000ull,
- .cfam_id = 0x120d304980000000ull,
- .first_core = 0x1,
- },
- {
- .chip_type = PNV_CHIP_POWER9,
- .cpu_model = "POWER9",
- .xscom_base = 0x000603fc00000000ull,
- .cfam_id = 0x220d104900008000ull,
- .first_core = 0x0,
- },
- {
- .chip_type = PNV_CHIP_POWER10,
- .cpu_model = "POWER10",
- .xscom_base = 0x000603fc00000000ull,
- .cfam_id = 0x120da04900008000ull,
- .first_core = 0x0,
- },
-};
-
-static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
-{
- uint64_t addr = chip->xscom_base;
-
- if (chip->chip_type == PNV_CHIP_POWER10) {
- addr |= ((uint64_t) pcba << 3);
- } else if (chip->chip_type == PNV_CHIP_POWER9) {
- addr |= ((uint64_t) pcba << 3);
- } else {
- addr |= (((uint64_t) pcba << 4) & ~0xffull) |
- (((uint64_t) pcba << 3) & 0x78);
- }
- return addr;
-}
+#include "pnv-xscom.h"
static uint64_t pnv_xscom_read(QTestState *qts, const PnvChip *chip,
uint32_t pcba)
diff --git a/tests/qtest/pnv-xscom.h b/tests/qtest/pnv-xscom.h
new file mode 100644
index 0000000..6f62941
--- /dev/null
+++ b/tests/qtest/pnv-xscom.h
@@ -0,0 +1,80 @@
+/*
+ * PowerNV XSCOM Bus
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PNV_XSCOM_H
+#define PNV_XSCOM_H
+
+#define SMT 4 /* some tests will break if less than 4 */
+
+typedef enum PnvChipType {
+ PNV_CHIP_POWER8E, /* AKA Murano (default) */
+ PNV_CHIP_POWER8, /* AKA Venice */
+ PNV_CHIP_POWER8NVL, /* AKA Naples */
+ PNV_CHIP_POWER9, /* AKA Nimbus */
+ PNV_CHIP_POWER10,
+} PnvChipType;
+
+typedef struct PnvChip {
+ PnvChipType chip_type;
+ const char *cpu_model;
+ uint64_t xscom_base;
+ uint64_t cfam_id;
+ uint32_t first_core;
+ uint32_t num_i2c;
+} PnvChip;
+
+static const PnvChip pnv_chips[] = {
+ {
+ .chip_type = PNV_CHIP_POWER8,
+ .cpu_model = "POWER8",
+ .xscom_base = 0x0003fc0000000000ull,
+ .cfam_id = 0x220ea04980000000ull,
+ .first_core = 0x1,
+ .num_i2c = 0,
+ }, {
+ .chip_type = PNV_CHIP_POWER8NVL,
+ .cpu_model = "POWER8NVL",
+ .xscom_base = 0x0003fc0000000000ull,
+ .cfam_id = 0x120d304980000000ull,
+ .first_core = 0x1,
+ .num_i2c = 0,
+ },
+ {
+ .chip_type = PNV_CHIP_POWER9,
+ .cpu_model = "POWER9",
+ .xscom_base = 0x000603fc00000000ull,
+ .cfam_id = 0x220d104900008000ull,
+ .first_core = 0x0,
+ .num_i2c = 4,
+ },
+ {
+ .chip_type = PNV_CHIP_POWER10,
+ .cpu_model = "POWER10",
+ .xscom_base = 0x000603fc00000000ull,
+ .cfam_id = 0x120da04900008000ull,
+ .first_core = 0x0,
+ .num_i2c = 4,
+ },
+};
+
+static inline uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
+{
+ uint64_t addr = chip->xscom_base;
+
+ if (chip->chip_type == PNV_CHIP_POWER10) {
+ addr |= ((uint64_t) pcba << 3);
+ } else if (chip->chip_type == PNV_CHIP_POWER9) {
+ addr |= ((uint64_t) pcba << 3);
+ } else {
+ addr |= (((uint64_t) pcba << 4) & ~0xffull) |
+ (((uint64_t) pcba << 3) & 0x78);
+ }
+ return addr;
+}
+
+#endif /* PNV_XSCOM_H */