diff options
author | Tom Rini <trini@konsulko.com> | 2024-01-17 09:12:27 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-01-17 09:12:27 -0500 |
commit | 106332d6cc583c4339e07020989d09b567900a59 (patch) | |
tree | 746beb976633e80b5c824805100490bb51cb9ffb /test | |
parent | 043ca8c8a9b181cf6f17441e9b89b5ee33206309 (diff) | |
parent | a300ac3851440906a3934915bd12db2b96987a6a (diff) |
Merge branch '2024-01-16-assorted-updates-and-improvements'
- Add more pytests to exercise functionality on real hardware, cleanup
and add tests around "cp"/memmove, add phyCORE-AM62x and Phytium
Pe2201 platforms, Nuvoton NPCM BMC reset driver and improve QEMU
SMBIOS support
Diffstat (limited to 'test')
-rw-r--r-- | test/cmd/Makefile | 1 | ||||
-rw-r--r-- | test/cmd/mem_copy.c | 168 | ||||
-rw-r--r-- | test/py/requirements.txt | 2 | ||||
-rw-r--r-- | test/py/tests/test_i2c.py | 116 | ||||
-rw-r--r-- | test/py/tests/test_mdio.py | 79 | ||||
-rw-r--r-- | test/py/tests/test_memtest.py | 68 | ||||
-rw-r--r-- | test/py/tests/test_mii.py | 92 | ||||
-rw-r--r-- | test/py/tests/test_net.py | 57 |
8 files changed, 582 insertions, 1 deletions
diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 7e40e25b9e..478ef4c6f0 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o obj-$(CONFIG_CMD_HISTORY) += history.o obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o +obj-$(CONFIG_CMD_MEMORY) += mem_copy.o ifdef CONFIG_CMD_PCI obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o endif diff --git a/test/cmd/mem_copy.c b/test/cmd/mem_copy.c new file mode 100644 index 0000000000..1ba0cebbbe --- /dev/null +++ b/test/cmd/mem_copy.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for memory 'cp' command + */ + +#include <command.h> +#include <console.h> +#include <mapmem.h> +#include <dm/test.h> +#include <test/ut.h> + +#define BUF_SIZE 256 + +/* Declare a new mem test */ +#define MEM_TEST(_name) UNIT_TEST(_name, 0, mem_test) + +struct param { + int d, s, count; +}; + +static int do_test(struct unit_test_state *uts, + const char *suffix, int d, int s, int count) +{ + const long addr = 0x1000; + u8 shadow[BUF_SIZE]; + u8 *buf; + int i, w, bytes; + + buf = map_sysmem(addr, BUF_SIZE); + + /* Fill with distinct bytes. */ + for (i = 0; i < BUF_SIZE; ++i) + buf[i] = shadow[i] = i; + + /* Parameter sanity checking. */ + w = cmd_get_data_size(suffix, 4); + ut_assert(w == 1 || w == 2 || w == 4 || (MEM_SUPPORT_64BIT_DATA && w == 8)); + + bytes = count * w; + ut_assert(d < BUF_SIZE); + ut_assert(d + bytes <= BUF_SIZE); + ut_assert(s < BUF_SIZE); + ut_assert(s + bytes <= BUF_SIZE); + + /* This is exactly what we expect to happen to "buf" */ + memmove(shadow + d, shadow + s, bytes); + + run_commandf("cp%s 0x%lx 0x%lx 0x%x", suffix, addr + s, addr + d, count); + + ut_asserteq(0, memcmp(buf, shadow, BUF_SIZE)); + + unmap_sysmem(buf); + + return 0; +} + +static int mem_test_cp_b(struct unit_test_state *uts) +{ + static const struct param tests[] = { + { 0, 128, 128 }, + { 128, 0, 128 }, + { 0, 16, 32 }, + { 16, 0, 32 }, + { 60, 100, 100 }, + { 100, 60, 100 }, + { 123, 54, 96 }, + { 54, 123, 96 }, + }; + const struct param *p; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + p = &tests[i]; + ret = do_test(uts, ".b", p->d, p->s, p->count); + if (ret) + return ret; + } + + return 0; +} +MEM_TEST(mem_test_cp_b); + +static int mem_test_cp_w(struct unit_test_state *uts) +{ + static const struct param tests[] = { + { 0, 128, 64 }, + { 128, 0, 64 }, + { 0, 16, 16 }, + { 16, 0, 16 }, + { 60, 100, 50 }, + { 100, 60, 50 }, + { 123, 54, 48 }, + { 54, 123, 48 }, + }; + const struct param *p; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + p = &tests[i]; + ret = do_test(uts, ".w", p->d, p->s, p->count); + if (ret) + return ret; + } + + return 0; +} +MEM_TEST(mem_test_cp_w); + +static int mem_test_cp_l(struct unit_test_state *uts) +{ + static const struct param tests[] = { + { 0, 128, 32 }, + { 128, 0, 32 }, + { 0, 16, 8 }, + { 16, 0, 8 }, + { 60, 100, 25 }, + { 100, 60, 25 }, + { 123, 54, 24 }, + { 54, 123, 24 }, + }; + const struct param *p; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + p = &tests[i]; + ret = do_test(uts, ".l", p->d, p->s, p->count); + if (ret) + return ret; + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + p = &tests[i]; + ret = do_test(uts, "", p->d, p->s, p->count); + if (ret) + return ret; + } + + return 0; +} +MEM_TEST(mem_test_cp_l); + +#if MEM_SUPPORT_64BIT_DATA +static int mem_test_cp_q(struct unit_test_state *uts) +{ + static const struct param tests[] = { + { 0, 128, 16 }, + { 128, 0, 16 }, + { 0, 16, 8 }, + { 16, 0, 8 }, + { 60, 100, 15 }, + { 100, 60, 15 }, + { 123, 54, 12 }, + { 54, 123, 12 }, + }; + const struct param *p; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + p = &tests[i]; + ret = do_test(uts, ".q", p->d, p->s, p->count); + if (ret) + return ret; + } + + return 0; +} +MEM_TEST(mem_test_cp_q); +#endif diff --git a/test/py/requirements.txt b/test/py/requirements.txt index f7e76bdb91..07348b6159 100644 --- a/test/py/requirements.txt +++ b/test/py/requirements.txt @@ -12,7 +12,7 @@ packaging==21.3 pbr==5.4.3 pluggy==0.13.0 py==1.10.0 -pycryptodomex==3.9.8 +pycryptodomex==3.19.1 pyelftools==0.27 pygit2==1.9.2 pyparsing==3.0.7 diff --git a/test/py/tests/test_i2c.py b/test/py/tests/test_i2c.py new file mode 100644 index 0000000000..825d0c2e6e --- /dev/null +++ b/test/py/tests/test_i2c.py @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: GPL-2.0 +# (C) Copyright 2023, Advanced Micro Devices, Inc. + +import pytest +import random +import re + +""" +Note: This test relies on boardenv_* containing configuration values to define +the i2c device info including the bus list and eeprom address/value. This test +will be automatically skipped without this. + +For example: + +# Setup env__i2c_device_test to set the i2c bus list and probe_all boolean +# parameter. For i2c_probe_all_buses case, if probe_all parameter is set to +# False then it probes all the buses listed in bus_list instead of probing all +# the buses available. +env__i2c_device_test = { + 'bus_list': [0, 2, 5, 12, 16, 18], + 'probe_all': False, +} + +# Setup env__i2c_eeprom_device_test to set the i2c bus number, eeprom address +# and configured value for i2c_eeprom test case. Test will be skipped if +# env__i2c_eeprom_device_test is not set +env__i2c_eeprom_device_test = { + 'bus': 3, + 'eeprom_addr': 0x54, + 'eeprom_val': '30 31', +} +""" + +def get_i2c_test_env(u_boot_console): + f = u_boot_console.config.env.get("env__i2c_device_test", None) + if not f: + pytest.skip("No I2C device to test!") + else: + bus_list = f.get("bus_list", None) + if not bus_list: + pytest.skip("I2C bus list is not provided!") + probe_all = f.get("probe_all", False) + return bus_list, probe_all + +@pytest.mark.buildconfigspec("cmd_i2c") +def test_i2c_bus(u_boot_console): + bus_list, probe = get_i2c_test_env(u_boot_console) + bus = random.choice(bus_list) + expected_response = f"Bus {bus}:" + response = u_boot_console.run_command("i2c bus") + assert expected_response in response + +@pytest.mark.buildconfigspec("cmd_i2c") +def test_i2c_dev(u_boot_console): + bus_list, probe = get_i2c_test_env(u_boot_console) + expected_response = "Current bus is" + response = u_boot_console.run_command("i2c dev") + assert expected_response in response + +@pytest.mark.buildconfigspec("cmd_i2c") +def test_i2c_probe(u_boot_console): + bus_list, probe = get_i2c_test_env(u_boot_console) + bus = random.choice(bus_list) + expected_response = f"Setting bus to {bus}" + response = u_boot_console.run_command(f"i2c dev {bus}") + assert expected_response in response + expected_response = "Valid chip addresses:" + response = u_boot_console.run_command("i2c probe") + assert expected_response in response + +@pytest.mark.buildconfigspec("cmd_i2c") +def test_i2c_eeprom(u_boot_console): + f = u_boot_console.config.env.get("env__i2c_eeprom_device_test", None) + if not f: + pytest.skip("No I2C eeprom to test!") + + bus = f.get("bus", 0) + if bus < 0: + pytest.fail("No bus specified via env__i2c_eeprom_device_test!") + + addr = f.get("eeprom_addr", -1) + if addr < 0: + pytest.fail("No eeprom address specified via env__i2c_eeprom_device_test!") + + value = f.get("eeprom_val") + if not value: + pytest.fail( + "No eeprom configured value provided via env__i2c_eeprom_device_test!" + ) + + # Enable i2c mux bridge + u_boot_console.run_command("i2c dev %x" % bus) + u_boot_console.run_command("i2c probe") + output = u_boot_console.run_command("i2c md %x 0 5" % addr) + assert value in output + +@pytest.mark.buildconfigspec("cmd_i2c") +def test_i2c_probe_all_buses(u_boot_console): + bus_list, probe = get_i2c_test_env(u_boot_console) + bus = random.choice(bus_list) + expected_response = f"Bus {bus}:" + response = u_boot_console.run_command("i2c bus") + assert expected_response in response + + # Get all the bus list + if probe: + buses = re.findall("Bus (.+?):", response) + bus_list = [int(x) for x in buses] + + for dev in bus_list: + expected_response = f"Setting bus to {dev}" + response = u_boot_console.run_command(f"i2c dev {dev}") + assert expected_response in response + expected_response = "Valid chip addresses:" + response = u_boot_console.run_command("i2c probe") + assert expected_response in response diff --git a/test/py/tests/test_mdio.py b/test/py/tests/test_mdio.py new file mode 100644 index 0000000000..89711e70b5 --- /dev/null +++ b/test/py/tests/test_mdio.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0 +# (C) Copyright 2023, Advanced Micro Devices, Inc. + +import pytest +import re + +""" +Note: This test relies on boardenv_* containing configuration values to define +the PHY device info including the device name, address, register address/value +and write data value. This test will be automatically skipped without this. + +For example: + +# Setup env__mdio_util_test to set the PHY address, device names, register +# address, register address value, and write data value to test mdio commands. +# Test will be skipped if env_mdio_util_test is not set +env__mdio_util_test = { + "eth0": {"phy_addr": 0xc, "device_name": "TI DP83867", "reg": 0, + "reg_val": 0x1000, "write_val": 0x100}, + "eth1": {"phy_addr": 0xa0, "device_name": "TI DP83867", "reg": 1, + "reg_val": 0x2000, "write_val": 0x100}, +} +""" + +def get_mdio_test_env(u_boot_console): + f = u_boot_console.config.env.get("env__mdio_util_test", None) + if not f or len(f) == 0: + pytest.skip("No PHY device to test!") + else: + return f + +@pytest.mark.buildconfigspec("cmd_mii") +@pytest.mark.buildconfigspec("phylib") +def test_mdio_list(u_boot_console): + f = get_mdio_test_env(u_boot_console) + output = u_boot_console.run_command("mdio list") + for dev, val in f.items(): + phy_addr = val.get("phy_addr") + dev_name = val.get("device_name") + + assert f"{phy_addr:x} -" in output + assert dev_name in output + +@pytest.mark.buildconfigspec("cmd_mii") +@pytest.mark.buildconfigspec("phylib") +def test_mdio_read(u_boot_console): + f = get_mdio_test_env(u_boot_console) + output = u_boot_console.run_command("mdio list") + for dev, val in f.items(): + phy_addr = hex(val.get("phy_addr")) + dev_name = val.get("device_name") + reg = hex(val.get("reg")) + reg_val = hex(val.get("reg_val")) + + output = u_boot_console.run_command(f"mdio read {phy_addr} {reg}") + assert f"PHY at address {int(phy_addr, 16):x}:" in output + assert f"{int(reg, 16):x} - {reg_val}" in output + +@pytest.mark.buildconfigspec("cmd_mii") +@pytest.mark.buildconfigspec("phylib") +def test_mdio_write(u_boot_console): + f = get_mdio_test_env(u_boot_console) + output = u_boot_console.run_command("mdio list") + for dev, val in f.items(): + phy_addr = hex(val.get("phy_addr")) + dev_name = val.get("device_name") + reg = hex(val.get("reg")) + reg_val = hex(val.get("reg_val")) + wr_val = hex(val.get("write_val")) + + u_boot_console.run_command(f"mdio write {phy_addr} {reg} {wr_val}") + output = u_boot_console.run_command(f"mdio read {phy_addr} {reg}") + assert f"PHY at address {int(phy_addr, 16):x}:" in output + assert f"{int(reg, 16):x} - {wr_val}" in output + + u_boot_console.run_command(f"mdio write {phy_addr} {reg} {reg_val}") + output = u_boot_console.run_command(f"mdio read {phy_addr} {reg}") + assert f"PHY at address {int(phy_addr, 16):x}:" in output + assert f"{int(reg, 16):x} - {reg_val}" in output diff --git a/test/py/tests/test_memtest.py b/test/py/tests/test_memtest.py new file mode 100644 index 0000000000..0618d96f1b --- /dev/null +++ b/test/py/tests/test_memtest.py @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0 +# (C) Copyright 2023, Advanced Micro Devices, Inc. + +import pytest + +""" +Note: This test relies on boardenv_* containing configuration values to define +the memory test parameters such as start address, memory size, pattern, +iterations and timeout. This test will be automatically skipped without this. + +For example: + +# Setup env__memtest to set the start address of the memory range, size of the +# memory range to test from starting address, pattern to be written to memory, +# number of test iterations, and expected time to complete the test of mtest +# command. start address, size, and pattern parameters value should be in hex +# and rest of the params value should be integer. +env__memtest = { + 'start_addr': 0x0, + 'size': 0x1000, + 'pattern': 0x0, + 'iteration': 16, + 'timeout': 50000, +} +""" + +def get_memtest_env(u_boot_console): + f = u_boot_console.config.env.get("env__memtest", None) + if not f: + pytest.skip("memtest is not enabled!") + else: + start = f.get("start_addr", 0x0) + size = f.get("size", 0x1000) + pattern = f.get("pattern", 0x0) + iteration = f.get("iteration", 2) + timeout = f.get("timeout", 50000) + end = hex(int(start) + int(size)) + return start, end, pattern, iteration, timeout + +@pytest.mark.buildconfigspec("cmd_memtest") +def test_memtest_negative(u_boot_console): + """Negative testcase where end address is smaller than starting address and + pattern is invalid.""" + start, end, pattern, iteration, timeout = get_memtest_env(u_boot_console) + expected_response = "Refusing to do empty test" + response = u_boot_console.run_command( + f"mtest 2000 1000 {pattern} {hex(iteration)}" + ) + assert expected_response in response + output = u_boot_console.run_command("echo $?") + assert not output.endswith("0") + u_boot_console.run_command(f"mtest {start} {end} 'xyz' {hex(iteration)}") + output = u_boot_console.run_command("echo $?") + assert not output.endswith("0") + +@pytest.mark.buildconfigspec("cmd_memtest") +def test_memtest_ddr(u_boot_console): + """Test that md reads memory as expected, and that memory can be modified + using the mw command.""" + start, end, pattern, iteration, timeout = get_memtest_env(u_boot_console) + expected_response = f"Tested {str(iteration)} iteration(s) with 0 errors." + with u_boot_console.temporary_timeout(timeout): + response = u_boot_console.run_command( + f"mtest {start} {end} {pattern} {hex(iteration)}" + ) + assert expected_response in response + output = u_boot_console.run_command("echo $?") + assert output.endswith("0") diff --git a/test/py/tests/test_mii.py b/test/py/tests/test_mii.py new file mode 100644 index 0000000000..7b6816d108 --- /dev/null +++ b/test/py/tests/test_mii.py @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: GPL-2.0 +# (C) Copyright 2023, Advanced Micro Devices, Inc. + +import pytest +import re + +""" +Note: This test doesn't rely on boardenv_* configuration value but they can +change test behavior. + +For example: + +# Setup env__mii_deive_test_skip to True if tests with ethernet PHY devices +# should be skipped. For example: Missing PHY device +env__mii_device_test_skip = True + +# Setup env__mii_device_test to set the MII device names. Test will be skipped +# if env_mii_device_test is not set +env__mii_device_test = { + 'device_list': ['eth0', 'eth1'], +} +""" + +@pytest.mark.buildconfigspec("cmd_mii") +def test_mii_info(u_boot_console): + if u_boot_console.config.env.get("env__mii_device_test_skip", False): + pytest.skip("MII device test is not enabled!") + expected_output = "PHY" + output = u_boot_console.run_command("mii info") + if not re.search(r"PHY (.+?):", output): + pytest.skip("PHY device does not exist!") + assert expected_output in output + +@pytest.mark.buildconfigspec("cmd_mii") +def test_mii_list(u_boot_console): + if u_boot_console.config.env.get("env__mii_device_test_skip", False): + pytest.skip("MII device test is not enabled!") + + f = u_boot_console.config.env.get("env__mii_device_test", None) + if not f: + pytest.skip("No MII device to test!") + + dev_list = f.get("device_list") + if not dev_list: + pytest.fail("No MII device list provided via env__mii_device_test!") + + expected_output = "Current device" + output = u_boot_console.run_command("mii device") + mii_devices = ( + re.search(r"MII devices: '(.+)'", output).groups()[0].replace("'", "").split() + ) + + assert len([x for x in dev_list if x in mii_devices]) == len(dev_list) + assert expected_output in output + +@pytest.mark.buildconfigspec("cmd_mii") +def test_mii_set_device(u_boot_console): + test_mii_list(u_boot_console) + f = u_boot_console.config.env.get("env__mii_device_test", None) + dev_list = f.get("device_list") + output = u_boot_console.run_command("mii device") + current_dev = re.search(r"Current device: '(.+?)'", output).groups()[0] + + for dev in dev_list: + u_boot_console.run_command(f"mii device {dev}") + output = u_boot_console.run_command("echo $?") + assert output.endswith("0") + + u_boot_console.run_command(f"mii device {current_dev}") + output = u_boot_console.run_command("mii device") + dev = re.search(r"Current device: '(.+?)'", output).groups()[0] + assert current_dev == dev + +@pytest.mark.buildconfigspec("cmd_mii") +def test_mii_read(u_boot_console): + test_mii_list(u_boot_console) + output = u_boot_console.run_command("mii info") + eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16)) + u_boot_console.run_command(f"mii read {eth_addr} 0") + output = u_boot_console.run_command("echo $?") + assert output.endswith("0") + +@pytest.mark.buildconfigspec("cmd_mii") +def test_mii_dump(u_boot_console): + test_mii_list(u_boot_console) + expected_response = "PHY control register" + output = u_boot_console.run_command("mii info") + eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16)) + response = u_boot_console.run_command(f"mii dump {eth_addr} 0") + assert expected_response in response + output = u_boot_console.run_command("echo $?") + assert output.endswith("0") diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py index 4ff3dafd62..cc2e53c698 100644 --- a/test/py/tests/test_net.py +++ b/test/py/tests/test_net.py @@ -8,6 +8,7 @@ import pytest import u_boot_utils import uuid import datetime +import re """ Note: This test relies on boardenv_* containing configuration values to define @@ -31,6 +32,11 @@ env__net_uses_pci = True # set to False. env__net_dhcp_server = True +# False or omitted if a DHCP server is attached to the network, and dhcp abort +# case should be tested. +# If DHCP abort testing is not possible or desired, set this variable to True. +env__dhcp_abort_test_skip = True + # True if a DHCPv6 server is attached to the network, and should be tested. # If DHCPv6 testing is not possible or desired, this variable may be omitted or # set to False. @@ -120,6 +126,57 @@ def test_net_dhcp(u_boot_console): global net_set_up net_set_up = True +@pytest.mark.buildconfigspec("cmd_dhcp") +@pytest.mark.buildconfigspec("cmd_mii") +def test_net_dhcp_abort(u_boot_console): + """Test the dhcp command by pressing ctrl+c in the middle of dhcp request + + The boardenv_* file may be used to enable/disable this test; see the + comment at the beginning of this file. + """ + + test_dhcp = u_boot_console.config.env.get("env__net_dhcp_server", False) + if not test_dhcp: + pytest.skip("No DHCP server available") + + if u_boot_console.config.env.get("env__dhcp_abort_test_skip", False): + pytest.skip("DHCP abort test is not enabled!") + + u_boot_console.run_command("setenv autoload no") + + # Phy reset before running dhcp command + output = u_boot_console.run_command("mii device") + if not re.search(r"Current device: '(.+?)'", output): + pytest.skip("PHY device does not exist!") + eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0] + u_boot_console.run_command(f"mii device {eth_num}") + output = u_boot_console.run_command("mii info") + eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16)) + u_boot_console.run_command(f"mii modify {eth_addr} 0 0x8000 0x8000") + + u_boot_console.run_command("dhcp", wait_for_prompt=False) + try: + u_boot_console.wait_for("Waiting for PHY auto negotiation to complete") + except: + pytest.skip("Timeout waiting for PHY auto negotiation to complete") + + u_boot_console.wait_for("done") + + # Sending Ctrl-C + output = u_boot_console.run_command( + chr(3), wait_for_echo=False, send_nl=False + ) + + assert "TIMEOUT" not in output + assert "DHCP client bound to address " not in output + assert "Abort" in output + + # Provide a time to recover from Abort - if it is not performed + # There is message like: ethernet@ff0e0000: No link. + u_boot_console.run_command("sleep 1") + # Run the dhcp test to setup the network configuration + test_net_dhcp(u_boot_console) + @pytest.mark.buildconfigspec('cmd_dhcp6') def test_net_dhcp6(u_boot_console): """Test the dhcp6 command. |