blob: 479a612b4ec2f469fb54293e0245f95be1d9e8d0 [file] [log] [blame]
# SPDX-License-Identifier: GPL-2.0
# (C) Copyright 2023, Advanced Micro Devices, Inc.
import pytest
import random
import string
import test_net
"""
Note: This test relies on boardenv_* containing configuration values to define
RPU applications information for AMD's ZynqMP SoC which contains, application
names, processors, address where it is built, expected output and the tftp load
addresses. This test will be automatically skipped without this.
It also relies on dhcp or setup_static net test to support tftp to load
application on DDR. All the environment parameters are stored sequentially.
The length of all parameters values should be same. For example, if 2 app_names
are defined in a list as a value of parameter 'app_name' then the other
parameters value also should have a list with 2 items.
It will run RPU cases for all the applications defined in boardenv_*
configuration file.
Example:
env__zynqmp_rpu_apps = {
'app_name': ['hello_world_r5_0_ddr.elf', 'hello_world_r5_1_ddr.elf'],
'proc': ['rpu0', 'rpu1'],
'cpu_num': [4, 5],
'addr': [0xA00000, 0xB00000],
'output': ['Successfully ran Hello World application on DDR from RPU0',
'Successfully ran Hello World application on DDR from RPU1'],
'tftp_addr': [0x100000, 0x200000],
}
"""
# Get rpu apps params from env
def get_rpu_apps_env(u_boot_console):
rpu_apps = u_boot_console.config.env.get('env__zynqmp_rpu_apps', False)
if not rpu_apps:
pytest.skip('ZynqMP RPU application info not defined!')
apps = rpu_apps.get('app_name', None)
if not apps:
pytest.skip('No RPU application found!')
procs = rpu_apps.get('proc', None)
if not procs:
pytest.skip('No RPU application processor provided!')
cpu_nums = rpu_apps.get('cpu_num', None)
if not cpu_nums:
pytest.skip('No CPU number for respective processor provided!')
addrs = rpu_apps.get('addr', None)
if not addrs:
pytest.skip('No RPU application build address found!')
outputs = rpu_apps.get('output', None)
if not outputs:
pytest.skip('Expected output not found!')
tftp_addrs = rpu_apps.get('tftp_addr', None)
if not tftp_addrs:
pytest.skip('TFTP address to load application not found!')
return apps, procs, cpu_nums, addrs, outputs, tftp_addrs
# Check return code
def ret_code(u_boot_console):
return u_boot_console.run_command('echo $?')
# Initialize tcm
def tcminit(u_boot_console, rpu_mode):
output = u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode)
assert 'Initializing TCM overwrites TCM content' in output
return ret_code(u_boot_console)
# Load application in DDR
def load_app_ddr(u_boot_console, tftp_addr, app):
output = u_boot_console.run_command('tftpboot %x %s' % (tftp_addr, app))
assert 'TIMEOUT' not in output
assert 'Bytes transferred = ' in output
# Load elf
u_boot_console.run_command('bootelf -p %x' % tftp_addr)
assert ret_code(u_boot_console).endswith('0')
# Disable cpus
def disable_cpus(u_boot_console, cpu_nums):
for num in cpu_nums:
u_boot_console.run_command(f'cpu {num} disable')
# Load apps on RPU cores
def rpu_apps_load(u_boot_console, rpu_mode):
apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
u_boot_console)
test_net.test_net_dhcp(u_boot_console)
if not test_net.net_set_up:
test_net.test_net_setup_static(u_boot_console)
try:
assert tcminit(u_boot_console, rpu_mode).endswith('0')
for i in range(len(apps)):
if rpu_mode == 'lockstep' and procs[i] != 'rpu0':
continue
load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
rel_addr = int(addrs[i] + 0x3C)
# Release cpu at app load address
cpu_num = cpu_nums[i]
cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode)
output = u_boot_console.run_command(cmd)
exp_op = f'Using TCM jump trampoline for address {hex(rel_addr)}'
assert exp_op in output
assert f'R5 {rpu_mode} mode' in output
u_boot_console.wait_for(outputs[i])
assert ret_code(u_boot_console).endswith('0')
finally:
disable_cpus(u_boot_console, cpu_nums)
@pytest.mark.buildconfigspec('cmd_zynqmp')
def test_zynqmp_rpu_app_load_split(u_boot_console):
rpu_apps_load(u_boot_console, 'split')
@pytest.mark.buildconfigspec('cmd_zynqmp')
def test_zynqmp_rpu_app_load_lockstep(u_boot_console):
rpu_apps_load(u_boot_console, 'lockstep')
@pytest.mark.buildconfigspec('cmd_zynqmp')
def test_zynqmp_rpu_app_load_negative(u_boot_console):
apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
u_boot_console)
# Invalid commands
u_boot_console.run_command('zynqmp tcminit mode')
assert ret_code(u_boot_console).endswith('1')
rand_str = ''.join(random.choices(string.ascii_lowercase, k=4))
u_boot_console.run_command('zynqmp tcminit %s' % rand_str)
assert ret_code(u_boot_console).endswith('1')
rand_num = random.randint(2, 100)
u_boot_console.run_command('zynqmp tcminit %d' % rand_num)
assert ret_code(u_boot_console).endswith('1')
test_net.test_net_dhcp(u_boot_console)
if not test_net.net_set_up:
test_net.test_net_setup_static(u_boot_console)
try:
rpu_mode = 'split'
assert tcminit(u_boot_console, rpu_mode).endswith('0')
for i in range(len(apps)):
load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
# Run in split mode at different load address
rel_addr = int(addrs[i]) + random.randint(200, 1000)
cpu_num = cpu_nums[i]
cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode)
output = u_boot_console.run_command(cmd)
exp_op = f'Using TCM jump trampoline for address {hex(rel_addr)}'
assert exp_op in output
assert f'R5 {rpu_mode} mode' in output
assert not outputs[i] in output
# Invalid rpu mode
rand_str = ''.join(random.choices(string.ascii_lowercase, k=4))
cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rand_str)
output = u_boot_console.run_command(cmd)
assert exp_op in output
assert f'Unsupported mode' in output
assert not ret_code(u_boot_console).endswith('0')
# Switch to lockstep mode, without disabling CPUs
rpu_mode = 'lockstep'
u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode)
assert not ret_code(u_boot_console).endswith('0')
# Disable cpus
disable_cpus(u_boot_console, cpu_nums)
# Switch to lockstep mode, after disabling CPUs
output = u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode)
assert 'Initializing TCM overwrites TCM content' in output
assert ret_code(u_boot_console).endswith('0')
# Run lockstep mode for RPU1
for i in range(len(apps)):
if procs[i] == 'rpu0':
continue
load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
rel_addr = int(addrs[i] + 0x3C)
cpu_num = cpu_nums[i]
cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode)
output = u_boot_console.run_command(cmd)
exp_op = f'Using TCM jump trampoline for address {hex(rel_addr)}'
assert exp_op in output
assert f'R5 {rpu_mode} mode' in output
assert u_boot_console.p.expect([outputs[i]])
finally:
disable_cpus(u_boot_console, cpu_nums)
# This forces the console object to be shutdown, so any subsequent test
# will reset the board back into U-Boot.
u_boot_console.drain_console()
u_boot_console.cleanup_spawn()