1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
# 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()
|