[U-Boot] [PATCH 3/3] test/py: add spi_flash tests

Michal Simek michal.simek at xilinx.com
Tue Feb 27 08:51:02 UTC 2018


Hi Liam,

On 27.2.2018 05:17, Liam Beguin wrote:
> Add basic tests for the spi_flash subsystem.

Good to see this patch.
FYI: We have created qspi tests too but didn't push it out because of
missing sf_configs options as you have below. We are testing the whole
flash all the time.
Test was designed to use more randomization to make sure that every run
is working with different data. We found several issues thanks to this.
(Also keep in your mind that some tests depends on order which is wrong
but we didn't have time to clean them yet)
IIRC I have sent that patch to mainline in past and using sf_configs was
suggested too.

https://github.com/Xilinx/u-boot-xlnx/blob/master/test/py/tests/test_qspi.py

> 
> Signed-off-by: Liam Beguin <liambeguin at gmail.com>
> ---
>  test/py/tests/test_sf.py | 233 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 233 insertions(+)
> 
> diff --git a/test/py/tests/test_sf.py b/test/py/tests/test_sf.py
> new file mode 100644
> index 000000000000..7017d8072ea9
> --- /dev/null
> +++ b/test/py/tests/test_sf.py
> @@ -0,0 +1,233 @@
> +# Copyright (c) 2017, Xiphos Systems Corp. All rights reserved.
> +#
> +# SPDX-License-Identifier: GPL-2.0
> +
> +import re
> +import pytest
> +import u_boot_utils
> +
> +
> +"""
> +Note: This test relies on boardenv_* containing configuration values to define
> +which spi flash areas are available for testing.  Without this, this test will
> +be automatically skipped.
> +For example:
> +
> +# Boolean indicating whether the SF tests should be skipped.
> +env__sf_skip = False
> +
> +# A list of sections of flash memory to be tested.
> +env__sf_configs = (
> +    {
> +        # Optional, [[bus:]cs] argument used in `sf probe`
> +        'id': "0",
> +        # Where in SPI flash should the test operate.
> +        'offset': 0x00000000,
> +        # This value is optional.
> +        #   If present, specifies the size to use for read/write operations.
> +        #   If missing, the SPI Flash page size is used as a default (based on
> +        #   the `sf probe` output).
> +        'len': 0x10000,
> +        # Specifies if the test can write to offset
> +        'writeable': False,
> +    },
> +)
> +"""
> +
> +
> +def sf_prepare(u_boot_console, env__sf_config, verbose=False):
> +    """Check global state of the SPI Flash before running any test.
> +
> +   Args:
> +        u_boot_console: A U-Boot console connection.
> +        env__sf_config: The single SPI flash device configuration on which to
> +            run the tests.
> +
> +    Returns:
> +        Nothing.
> +    """
> +
> +    if u_boot_console.config.env.get('env__sf_skip', True):
> +        pytest.skip('sf test disabled in environment')
> +
> +    # NOTE: sf read at address 0 fails because map_physmem 'converts' it
> +    #       address 0 to a pointer.
> +    ram_address = u_boot_utils.find_ram_base(u_boot_console) + 0x10

Maybe you can add it to sf_configs too.


> +
> +    probe_id = env__sf_config.get('id', '')
> +    output = u_boot_console.run_command('sf probe ' + probe_id)
> +    if 'SF: Detected' not in output:
> +        pytest.fail('No flash device available')
> +
> +    m = re.search('page size (.+?) Bytes', output)
> +    if m:
> +        try:
> +            page_size = int(m.group(1))
> +        except ValueError:
> +            pytest.fail('SPI Flash page size not recognized')
> +
> +    m = re.search('erase size (.+?) KiB', output)
> +    if m:
> +        try:
> +            erase_size = int(m.group(1))
> +        except ValueError:
> +            pytest.fail('SPI Flash erase size not recognized')
> +
> +        erase_size *= 1024
> +
> +    m = re.search('total (.+?) MiB', output)
> +    if m:
> +        try:
> +            total_size = int(m.group(1))
> +        except ValueError:
> +            pytest.fail('SPI Flash total size not recognized')
> +
> +        total_size *= 1024 * 1024
> +
> +    if verbose:
> +        u_boot_console.log.info('Page size is: ' + str(page_size) + ' B')
> +        u_boot_console.log.info('Erase size is: ' + str(erase_size) + ' B')
> +        u_boot_console.log.info('Total size is: ' + str(total_size) + ' B')
> +
> +    env__sf_config['len'] = env__sf_config.get('len', erase_size)
> +    if env__sf_config['offset'] % erase_size or \
> +            env__sf_config['len'] % erase_size:
> +        u_boot_console.log.warning("erase offset/length not multiple of "
> +                                   "erase size")

Is this only warning or you can destroy any data by that?



> +
> +    env__sf_config['ram_address'] = ram_address
> +
> +
> +def crc32(u_boot_console, address, count):
> +    """Helper function used to compute the CRC32 value of a section of RAM.
> +
> +    Args:
> +        u_boot_console: A U-Boot console connection.
> +        address: Address where data starts.
> +        count: Amount of data to use for calculation.
> +
> +    Returns:
> +        CRC32 value
> +    """
> +
> +    output = u_boot_console.run_command('crc32 %08x %x' % (address, count))
> +
> +    m = re.search('==> ([0-9a-fA-F]{8})$', output)
> +    if not m:
> +        pytest.fail('CRC32 failed')
> +
> +    return m.group(1)
> +
> +
> +def sf_read(u_boot_console, env__sf_config, size=None):
> +    """Helper function used to read and compute the CRC32 value of a section of
> +    SPI Flash memory.
> +
> +    Args:
> +        u_boot_console: A U-Boot console connection.
> +        env__sf_config: The single SPI flash device configuration on which to
> +            run the tests.
> +        size: Optional, used to override env__sf_config value.
> +
> +    Returns:
> +        CRC32 value of SPI Flash section
> +    """
> +
> +    if size is None:
> +        size = env__sf_config['len']
> +
> +    u_boot_console.run_command('mw %08x 0 %x' % (env__sf_config['ram_address'],
> +                                                 size))

Any reason for this write? It should be rewritten by sf read below anyway.

> +
> +    response = u_boot_console.run_command('sf read %08x %08x %x' %
> +                                          (env__sf_config['ram_address'],
> +                                           env__sf_config['offset'],
> +                                           size))
> +    assert 'Read: OK' in response, "Read operation failed"
> +
> +    return crc32(u_boot_console, env__sf_config['ram_address'],
> +                 env__sf_config['len'])
> +
> +
> +def sf_update(u_boot_console, env__sf_config):
> +    """Helper function used to update a section of SPI Flash memory.
> +
> +   Args:
> +        u_boot_console: A U-Boot console connection.
> +        env__sf_config: The single SPI flash device configuration on which to
> +           run the tests.
> +
> +    Returns:
> +        CRC32 value of SPI Flash section
> +    """
> +    from time import time
> +
> +    u_boot_console.run_command('mw %08x %08x %x' %
> +                               (env__sf_config['ram_address'], time(),
> +                                env__sf_config['len']))

ditto

> +    crc_ram = crc32(u_boot_console, env__sf_config['ram_address'],
> +                    env__sf_config['len'])
> +    u_boot_console.run_command('sf update %08x %08x %x' %
> +                               (env__sf_config['ram_address'],
> +                                env__sf_config['offset'],
> +                                env__sf_config['len']))
> +
> +    crc2 = sf_read(u_boot_console, env__sf_config)
> +
> +    return (crc2 == crc_ram)
> +
> +
> + at pytest.mark.buildconfigspec("cmd_sf")
> +def test_sf_read(u_boot_console, env__sf_config):
> +    sf_prepare(u_boot_console, env__sf_config)
> +
> +    output = u_boot_console.run_command('sf read %08x %08x %x' %
> +                                        (env__sf_config['ram_address'],
> +                                         env__sf_config['offset'],
> +                                         env__sf_config['len']))
> +    assert 'Read: OK' in output, "Read operation failed"
> +
> +
> + at pytest.mark.buildconfigspec("cmd_sf")
> + at pytest.mark.buildconfigspec("cmd_crc32")
> + at pytest.mark.buildconfigspec("cmd_memory")
> +def test_sf_read_twice(u_boot_console, env__sf_config):
> +    sf_prepare(u_boot_console, env__sf_config)
> +
> +    crc1 = sf_read(u_boot_console, env__sf_config)
> +    crc2 = sf_read(u_boot_console, env__sf_config)

The test is using the same memory. I tried to avoid that to make sure
that there is no issue with memory itself. Small offset should be enough.
Also these sf read should be able to write bytes to non align addresses
to make sure that driver is handling that properly.


> +
> +    assert crc1 == crc2, "CRC32 of two successive read operation do not match"
> +
> +
> + at pytest.mark.buildconfigspec("cmd_sf")
> + at pytest.mark.buildconfigspec("cmd_crc32")
> + at pytest.mark.buildconfigspec("cmd_memory")
> +def test_sf_erase(u_boot_console, env__sf_config):
> +    if not env__sf_config['writeable']:
> +        pytest.skip('flash config is tagged as not writeable')
> +
> +    sf_prepare(u_boot_console, env__sf_config)
> +    output = u_boot_console.run_command('sf erase %08x %x' %
> +                                        (env__sf_config['offset'],
> +                                         env__sf_config['len']))
> +    assert 'Erased: OK' in output, "Erase operation failed"
> +
> +    u_boot_console.run_command('mw %08x ffffffff %x' %
> +                               (env__sf_config['ram_address'],
> +                                env__sf_config['len']))
> +    crc1 = crc32(u_boot_console, env__sf_config['ram_address'],
> +                 env__sf_config['len'])
> +
> +    crc2 = sf_read(u_boot_console, env__sf_config)
> +    assert crc1 == crc2, "CRC32 of erase section does not match expected value"
> +
> +
> + at pytest.mark.buildconfigspec("cmd_sf")
> + at pytest.mark.buildconfigspec("cmd_memory")
> +def test_sf_update(u_boot_console, env__sf_config):
> +    if not env__sf_config['writeable']:
> +        pytest.skip('flash config is tagged as not writeable')
> +
> +    sf_prepare(u_boot_console, env__sf_config)
> +    assert sf_update(u_boot_console, env__sf_config) is True
> 

Also I wanted to design these tests that you will check bytes in front
of and behind region in DDR to make sure that your driver is writing
just amount of data you requested not aligned with words for example.

Anyway good to see this patch.

Thanks,
Michal




More information about the U-Boot mailing list