From 9744d1a547847dea89277b00606fe4c837c1b4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Danis?= Date: Fri, 20 Mar 2020 10:59:22 +0100 Subject: [PATCH 01/20] cmd: Add command to display or save Linux PStore dumps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a new pstore command allowing to display or save ramoops logs (oops, panic, console, ftrace and user) generated by a previous kernel crash. PStore parameters can be set in U-Boot configuration file, or at run-time using "pstore set" command. Records size should be the same as the ones used by kernel, and should be a power of 2. This command allows: - to display uncompressed logs - to save compressed or uncompressed logs, compressed logs are saved as a compressed stream, it may need some work to be able to decompress it, e.g. adding a fake header: "printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" | cat - dmesg-ramoops-0.enc.z | gzip -dc" - ECC part is not used to check memory corruption - only 1st FTrace log is displayed or saved Signed-off-by: Frédéric Danis [trini: Minor updates for current design, correct spacing in rST] Signed-off-by: Tom Rini Cc: Heinrich Schuchardt Cc: Wolfgang Denk Cc: Heiko Schocher --- cmd/Kconfig | 71 +++++++ cmd/Makefile | 1 + cmd/pstore.c | 506 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/index.rst | 7 + doc/pstore.rst | 80 ++++++++ 5 files changed, 665 insertions(+) create mode 100644 cmd/pstore.c create mode 100644 doc/pstore.rst diff --git a/cmd/Kconfig b/cmd/Kconfig index 4cb171790b3..a3166e4f314 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1751,6 +1751,77 @@ config CMD_QFW feature is to allow easy loading of files passed to qemu-system via -kernel / -initrd +config CMD_PSTORE + bool "pstore" + help + This provides access to Linux PStore with Rammoops backend. The main + feature is to allow to display or save PStore records. + + See doc/pstore.rst for more information. + +if CMD_PSTORE + +config CMD_PSTORE_MEM_ADDR + hex "Memory Address" + depends on CMD_PSTORE + help + Base addr used for PStore ramoops memory, should be identical to + ramoops.mem_address parameter used by kernel + +config CMD_PSTORE_MEM_SIZE + hex "Memory size" + depends on CMD_PSTORE + default "0x10000" + help + Size of PStore ramoops memory, should be identical to ramoops.mem_size + parameter used by kernel, a power of 2 and larger than the sum of the + record sizes + +config CMD_PSTORE_RECORD_SIZE + hex "Dump record size" + depends on CMD_PSTORE + default "0x1000" + help + Size of each dump done on oops/panic, should be identical to + ramoops.record_size parameter used by kernel and a power of 2 + Must be non-zero + +config CMD_PSTORE_CONSOLE_SIZE + hex "Kernel console log size" + depends on CMD_PSTORE + default "0x1000" + help + Size of kernel console log, should be identical to + ramoops.console_size parameter used by kernel and a power of 2 + Must be non-zero + +config CMD_PSTORE_FTRACE_SIZE + hex "FTrace log size" + depends on CMD_PSTORE + default "0x1000" + help + Size of ftrace log, should be identical to ramoops.ftrace_size + parameter used by kernel and a power of 2 + +config CMD_PSTORE_PMSG_SIZE + hex "User space message log size" + depends on CMD_PSTORE + default "0x1000" + help + Size of user space message log, should be identical to + ramoops.pmsg_size parameter used by kernel and a power of 2 + +config CMD_PSTORE_ECC_SIZE + int "ECC size" + depends on CMD_PSTORE + default "0" + help + if non-zero, the option enables ECC support and specifies ECC buffer + size in bytes (1 is a special value, means 16 bytes ECC), should be + identical to ramoops.ramoops_ecc parameter used by kernel + +endif + source "cmd/mvebu/Kconfig" config CMD_TERMINAL diff --git a/cmd/Makefile b/cmd/Makefile index 015b83764c6..19a891633f6 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_CMD_PCI) += pci.o endif obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PMC) += pmc.o +obj-$(CONFIG_CMD_PSTORE) += pstore.o obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_CMD_QFW) += qfw.o diff --git a/cmd/pstore.c b/cmd/pstore.c new file mode 100644 index 00000000000..530eb03b182 --- /dev/null +++ b/cmd/pstore.c @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright © 2019 Collabora Ltd + */ + +#include +#include +#include +#include +#include +#include +#include + +struct persistent_ram_buffer { + u32 sig; + u32 start; + u32 size; + u8 data[0]; +}; + +#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ +#define RAMOOPS_KERNMSG_HDR "====" + +#define PSTORE_TYPE_DMESG 0 +#define PSTORE_TYPE_CONSOLE 2 +#define PSTORE_TYPE_FTRACE 3 +#define PSTORE_TYPE_PMSG 7 +#define PSTORE_TYPE_ALL 255 + +static phys_addr_t pstore_addr = CONFIG_CMD_PSTORE_MEM_ADDR; +static phys_size_t pstore_length = CONFIG_CMD_PSTORE_MEM_SIZE; +static unsigned int pstore_record_size = CONFIG_CMD_PSTORE_RECORD_SIZE; +static unsigned int pstore_console_size = CONFIG_CMD_PSTORE_CONSOLE_SIZE; +static unsigned int pstore_ftrace_size = CONFIG_CMD_PSTORE_FTRACE_SIZE; +static unsigned int pstore_pmsg_size = CONFIG_CMD_PSTORE_PMSG_SIZE; +static unsigned int pstore_ecc_size = CONFIG_CMD_PSTORE_ECC_SIZE; +static unsigned int buffer_size; + + /** + * pstore_read_kmsg_hdr() - Check kernel header and get compression flag if + * available. + * @buffer: Kernel messages buffer. + * @compressed: Returns TRUE if kernel buffer is compressed, else FALSE. + * + * Check if buffer starts with a kernel header of the form: + * ====.[-]\n + * If is equal to 'C' then the buffer is compressed, else iter + * should be 'D'. + * + * Return: Length of kernel header. + */ +static int pstore_read_kmsg_hdr(char *buffer, bool *compressed) +{ + char *ptr = buffer; + *compressed = false; + + if (strncmp(RAMOOPS_KERNMSG_HDR, ptr, strlen(RAMOOPS_KERNMSG_HDR)) != 0) + return 0; + + ptr += strlen(RAMOOPS_KERNMSG_HDR); + + ptr = strchr(ptr, '\n'); + if (!ptr) + return 0; + + if (ptr[-2] == '-' && ptr[-1] == 'C') + *compressed = true; + + return ptr - buffer + 1; +} + +/** + * pstore_get_buffer() - Get unwrapped record buffer + * @sig: Signature to check + * @buffer: Buffer containing wrapped record + * @size: wrapped record size + * @dest: Buffer used to store unwrapped record + * + * The record starts with header. + * The signature is 'DBGC' for all records except for Ftrace's record(s) wich + * use LINUX_VERSION_CODE ^ 'DBGC'. + * Use 0 for @sig to prevent checking signature. + * Start and size are 4 bytes long. + * + * Return: record's length + */ +static u32 pstore_get_buffer(u32 sig, phys_addr_t buffer, u32 size, char *dest) +{ + struct persistent_ram_buffer *prb = + (struct persistent_ram_buffer *)map_sysmem(buffer, size); + u32 dest_size; + + if (sig == 0 || prb->sig == sig) { + if (prb->size == 0) { + log_debug("found existing empty buffer\n"); + return 0; + } + + if (prb->size > size) { + log_debug("found existing invalid buffer, size %u, start %u\n", + prb->size, prb->start); + return 0; + } + } else { + log_debug("no valid data in buffer (sig = 0x%08x)\n", prb->sig); + return 0; + } + + log_debug("found existing buffer, size %u, start %u\n", + prb->size, prb->start); + + memcpy(dest, &prb->data[prb->start], prb->size - prb->start); + memcpy(dest + prb->size - prb->start, &prb->data[0], prb->start); + + dest_size = prb->size; + unmap_sysmem(prb); + + return dest_size; +} + +/** + * pstore_init_buffer_size() - Init buffer size to largest record size + * + * Records, console, FTrace and user logs can use different buffer sizes. + * This function allows to retrieve the biggest one. + */ +static void pstore_init_buffer_size(void) +{ + if (pstore_record_size > buffer_size) + buffer_size = pstore_record_size; + + if (pstore_console_size > buffer_size) + buffer_size = pstore_console_size; + + if (pstore_ftrace_size > buffer_size) + buffer_size = pstore_ftrace_size; + + if (pstore_pmsg_size > buffer_size) + buffer_size = pstore_pmsg_size; +} + +/** + * pstore_set() - Initialize PStore settings from command line arguments + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Set pstore reserved memory info, starting at 'addr' for 'len' bytes. + * Default length for records is 4K. + * Mandatory arguments: + * - addr: ramoops starting address + * - len: ramoops total length + * Optional arguments: + * - record-size: size of one panic or oops record ('dump' type) + * - console-size: size of the kernel logs record + * - ftrace-size: size of the ftrace record(s), this can be a single record or + * divided in parts based on number of CPUs + * - pmsg-size: size of the user space logs record + * - ecc-size: enables/disables ECC support and specifies ECC buffer size in + * bytes (0 disables it, 1 is a special value, means 16 bytes ECC) + * + * Return: zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int pstore_set(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + if (argc < 3) + return CMD_RET_USAGE; + + /* Address is specified since argc > 2 + */ + pstore_addr = simple_strtoul(argv[1], NULL, 16); + + /* Length is specified since argc > 2 + */ + pstore_length = simple_strtoul(argv[2], NULL, 16); + + if (argc > 3) + pstore_record_size = simple_strtoul(argv[3], NULL, 16); + + if (argc > 4) + pstore_console_size = simple_strtoul(argv[4], NULL, 16); + + if (argc > 5) + pstore_ftrace_size = simple_strtoul(argv[5], NULL, 16); + + if (argc > 6) + pstore_pmsg_size = simple_strtoul(argv[6], NULL, 16); + + if (argc > 7) + pstore_ecc_size = simple_strtoul(argv[7], NULL, 16); + + if (pstore_length < (pstore_record_size + pstore_console_size + + pstore_ftrace_size + pstore_pmsg_size)) { + printf("pstore should be larger than the sum of all records sizes\n"); + pstore_length = 0; + } + + log_debug("pstore set done: start 0x%08llx - length 0x%llx\n", + (unsigned long long)pstore_addr, + (unsigned long long)pstore_length); + + return 0; +} + +/** + * pstore_print_buffer() - Print buffer + * @type: buffer type + * @buffer: buffer to print + * @size: buffer size + * + * Print buffer type and content + */ +static void pstore_print_buffer(char *type, char *buffer, u32 size) +{ + u32 i = 0; + + printf("**** %s\n", type); + while (i < size && buffer[i] != 0) { + putc(buffer[i]); + i++; + } +} + +/** + * pstore_display() - Display existing records in pstore reserved memory + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * A 'record-type' can be given to only display records of this kind. + * If no 'record-type' is given, all valid records are dispayed. + * 'record-type' can be one of 'dump', 'console', 'ftrace' or 'user'. For 'dump' + * and 'ftrace' types, a 'nb' can be given to only display one record. + * + * Return: zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int pstore_display(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + int type = PSTORE_TYPE_ALL; + phys_addr_t ptr; + char *buffer; + u32 size; + int header_len = 0; + bool compressed; + + if (argc > 1) { + if (!strcmp(argv[1], "dump")) + type = PSTORE_TYPE_DMESG; + else if (!strcmp(argv[1], "console")) + type = PSTORE_TYPE_CONSOLE; + else if (!strcmp(argv[1], "ftrace")) + type = PSTORE_TYPE_FTRACE; + else if (!strcmp(argv[1], "user")) + type = PSTORE_TYPE_PMSG; + else + return CMD_RET_USAGE; + } + + if (pstore_length == 0) { + printf("Please set PStore configuration\n"); + return CMD_RET_USAGE; + } + + if (buffer_size == 0) + pstore_init_buffer_size(); + + buffer = malloc_cache_aligned(buffer_size); + + if (type == PSTORE_TYPE_DMESG || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr; + phys_addr_t ptr_end = ptr + pstore_length - pstore_pmsg_size + - pstore_ftrace_size - pstore_console_size; + + if (argc > 2) { + ptr += simple_strtoul(argv[2], NULL, 10) + * pstore_record_size; + ptr_end = ptr + pstore_record_size; + } + + while (ptr < ptr_end) { + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_record_size, buffer); + ptr += pstore_record_size; + + if (size == 0) + continue; + + header_len = pstore_read_kmsg_hdr(buffer, &compressed); + if (header_len == 0) { + log_debug("no valid kernel header\n"); + continue; + } + + if (compressed) { + printf("Compressed buffer, display not available\n"); + continue; + } + + pstore_print_buffer("Dump", buffer + header_len, + size - header_len); + } + } + + if (type == PSTORE_TYPE_CONSOLE || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr + pstore_length - pstore_pmsg_size + - pstore_ftrace_size - pstore_console_size; + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_console_size, buffer); + if (size != 0) + pstore_print_buffer("Console", buffer, size); + } + + if (type == PSTORE_TYPE_FTRACE || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr + pstore_length - pstore_pmsg_size + - pstore_ftrace_size; + /* The FTrace record(s) uses LINUX_VERSION_CODE ^ 'DBGC' + * signature, pass 0 to pstore_get_buffer to prevent + * checking it + */ + size = pstore_get_buffer(0, ptr, pstore_ftrace_size, buffer); + if (size != 0) + pstore_print_buffer("FTrace", buffer, size); + } + + if (type == PSTORE_TYPE_PMSG || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr + pstore_length - pstore_pmsg_size; + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_pmsg_size, buffer); + if (size != 0) + pstore_print_buffer("User", buffer, size); + } + + free(buffer); + + return 0; +} + +/** + * pstore_save() - Save existing records from pstore reserved memory + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * the records are saved under 'directory path', which should already exist, + * to partition 'part' on device type 'interface' instance 'dev' + * Filenames are automatically generated, depending on record type, like in + * /sys/fs/pstore under Linux + * + * Return: zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int pstore_save(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + phys_addr_t ptr, ptr_end; + char *buffer; + char *save_argv[6]; + char addr[19], length[19]; + char path[256]; + u32 size; + unsigned int index; + int header_len = 0; + bool compressed; + + if (argc < 4) + return CMD_RET_USAGE; + + if (pstore_length == 0) { + printf("Please set PStore configuration\n"); + return CMD_RET_USAGE; + } + + if (buffer_size == 0) + pstore_init_buffer_size(); + + buffer = malloc_cache_aligned(buffer_size); + sprintf(addr, "0x%p", buffer); + + save_argv[0] = argv[0]; + save_argv[1] = argv[1]; + save_argv[2] = argv[2]; + save_argv[3] = addr; + save_argv[4] = path; + save_argv[5] = length; + + /* Save all Dump records */ + ptr = pstore_addr; + ptr_end = ptr + pstore_length - pstore_pmsg_size - pstore_ftrace_size + - pstore_console_size; + index = 0; + while (ptr < ptr_end) { + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_record_size, buffer); + ptr += pstore_record_size; + + if (size == 0) + continue; + + header_len = pstore_read_kmsg_hdr(buffer, &compressed); + if (header_len == 0) { + log_debug("no valid kernel header\n"); + continue; + } + + sprintf(addr, "0x%08lx", (ulong)map_to_sysmem(buffer + header_len)); + sprintf(length, "0x%X", size - header_len); + sprintf(path, "%s/dmesg-ramoops-%u%s", argv[3], index, + compressed ? ".enc.z" : ""); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + index++; + } + + sprintf(addr, "0x%08lx", (ulong)map_to_sysmem(buffer)); + + /* Save Console record */ + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, pstore_console_size, + buffer); + if (size != 0) { + sprintf(length, "0x%X", size); + sprintf(path, "%s/console-ramoops-0", argv[3]); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + } + ptr += pstore_console_size; + + /* Save FTrace record(s) + * The FTrace record(s) uses LINUX_VERSION_CODE ^ 'DBGC' signature, + * pass 0 to pstore_get_buffer to prevent checking it + */ + size = pstore_get_buffer(0, ptr, pstore_ftrace_size, buffer); + if (size != 0) { + sprintf(length, "0x%X", size); + sprintf(path, "%s/ftrace-ramoops-0", argv[3]); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + } + ptr += pstore_ftrace_size; + + /* Save Console record */ + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, pstore_pmsg_size, + buffer); + if (size != 0) { + sprintf(length, "0x%X", size); + sprintf(path, "%s/pmsg-ramoops-0", argv[3]); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + } + + free(buffer); + + return 0; +} + +static struct cmd_tbl cmd_pstore_sub[] = { + U_BOOT_CMD_MKENT(set, 8, 0, pstore_set, "", ""), + U_BOOT_CMD_MKENT(display, 3, 0, pstore_display, "", ""), + U_BOOT_CMD_MKENT(save, 4, 0, pstore_save, "", ""), +}; + +static int do_pstore(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct cmd_tbl *c; + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_pstore_sub, ARRAY_SIZE(cmd_pstore_sub)); + + if (!c) + return CMD_RET_USAGE; + + return c->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD(pstore, 10, 0, do_pstore, + "Manage Linux Persistent Storage", + "set [record-size] [console-size] [ftrace-size] [pmsg_size] [ecc-size]\n" + "- Set pstore reserved memory info, starting at 'addr' for 'len' bytes.\n" + " Default length for records is 4K.\n" + " 'record-size' is the size of one panic or oops record ('dump' type).\n" + " 'console-size' is the size of the kernel logs record.\n" + " 'ftrace-size' is the size of the ftrace record(s), this can be a single\n" + " record or divided in parts based on number of CPUs.\n" + " 'pmsg-size' is the size of the user space logs record.\n" + " 'ecc-size' enables/disables ECC support and specifies ECC buffer size in\n" + " bytes (0 disables it, 1 is a special value, means 16 bytes ECC).\n" + "pstore display [record-type] [nb]\n" + "- Display existing records in pstore reserved memory. A 'record-type' can\n" + " be given to only display records of this kind. 'record-type' can be one\n" + " of 'dump', 'console', 'ftrace' or 'user'. For 'dump' and 'ftrace' types,\n" + " a 'nb' can be given to only display one record.\n" + "pstore save \n" + "- Save existing records in pstore reserved memory under 'directory path'\n" + " to partition 'part' on device type 'interface' instance 'dev'.\n" + " Filenames are automatically generated, depending on record type, like\n" + " in /sys/fs/pstore under Linux.\n" + " The 'directory-path' should already exist.\n" +); diff --git a/doc/index.rst b/doc/index.rst index fd9f10f28e4..68a083b16ba 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -109,6 +109,13 @@ Android-specific features available in U-Boot. android/index +Command line +------------ +.. toctree:: + :maxdepth: 2 + + pstore.rst + Indices and tables ================== diff --git a/doc/pstore.rst b/doc/pstore.rst new file mode 100644 index 00000000000..4fceb2dd990 --- /dev/null +++ b/doc/pstore.rst @@ -0,0 +1,80 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +PStore command +============== + +Design +------ + +Linux PStore and Ramoops modules (Linux config options PSTORE and PSTORE_RAM) +allow to use memory to pass data from the dying breath of a crashing kernel to +its successor. This command allows to read those records from U-Boot command +line. + +Ramoops is an oops/panic logger that writes its logs to RAM before the system +crashes. It works by logging oopses and panics in a circular buffer. Ramoops +needs a system with persistent RAM so that the content of that area can survive +after a restart. + +Ramoops uses a predefined memory area to store the dump. + +Ramoops parameters can be passed as kernel parameters or through Device Tree, +i.e.:: + + ramoops.mem_address=0x30000000 ramoops.mem_size=0x100000 ramoops.record_size=0x2000 ramoops.console_size=0x2000 memmap=0x100000$0x30000000 + +The same values should be set in U-Boot to be able to retrieve the records. +This values can be set at build time in U-Boot configuration file, or at runtime. + +The PStore configuration parameters are: + +======================= ========== + Name Default +======================= ========== +CMD_PSTORE_MEM_ADDR +CMD_PSTORE_MEM_SIZE 0x10000 +CMD_PSTORE_RECORD_SIZE 0x1000 +CMD_PSTORE_CONSOLE_SIZE 0x1000 +CMD_PSTORE_FTRACE_SIZE 0x1000 +CMD_PSTORE_PMSG_SIZE 0x1000 +CMD_PSTORE_ECC_SIZE 0 +======================= ========== + +Records sizes should be a power of 2. +The memory size and the record/console size must be non-zero. + +Multiple 'dump' records can be stored in the memory reserved for PStore. +The memory size has to be larger than the sum of the record sizes, i.e.:: + + MEM_SIZE >= RECORD_SIZE * n + CONSOLE_SIZE + FTRACE_SIZE + PMSG_SIZE + +Usage +----- + +Generate kernel crash +~~~~~~~~~~~~~~~~~~~~~ + +For test purpose, you can generate a kernel crash by setting reboot timeout to +10 seconds and trigger a panic:: + + $ sudo sh -c "echo 1 > /proc/sys/kernel/sysrq" + $ sudo sh -c "echo 10 > /proc/sys/kernel/panic" + $ sudo sh -c "echo c > /proc/sysrq-trigger" + +Retrieve logs in U-Boot +~~~~~~~~~~~~~~~~~~~~~~~ + +First of all, unless PStore parameters as been set during U-Boot configuration +and match kernel ramoops parameters, it needs to be set using 'pstore set', e.g.:: + + => pstore set 0x30000000 0x100000 0x2000 0x2000 + +Then all available dumps can be displayed +using:: + + => pstore display + +Or saved to an existing directory in an Ext2 or Ext4 partition, e.g. on root +directory of 1st partition of the 2nd MMC:: + + => pstore save mmc 1:1 / From 26f555a6e5454043ed0b0a12d6fce252f5ae5b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Danis?= Date: Fri, 20 Mar 2020 10:59:23 +0100 Subject: [PATCH 02/20] test: Add PStore command tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add PStore command to sandbox and sandbox64 defconfigs. Add test checking: - 'pstore display' of all records - 'pstore display' only the 2nd dump record - 'pstore save' of all records Signed-off-by: Frédéric Danis [trini: Adjust to always load files from source directory] Signed-off-by: Tom Rini Cc: Heinrich Schuchardt Cc: Wolfgang Denk Cc: Heiko Schocher --- configs/sandbox64_defconfig | 2 + configs/sandbox_defconfig | 2 + test/py/tests/test_pstore.py | 77 +++++++++++++++++++++ test/py/tests/test_pstore_data_console.hex | Bin 0 -> 4096 bytes test/py/tests/test_pstore_data_panic1.hex | Bin 0 -> 4096 bytes test/py/tests/test_pstore_data_panic2.hex | Bin 0 -> 4096 bytes 6 files changed, 81 insertions(+) create mode 100644 test/py/tests/test_pstore.py create mode 100644 test/py/tests/test_pstore_data_console.hex create mode 100644 test/py/tests/test_pstore_data_panic1.hex create mode 100644 test/py/tests/test_pstore_data_panic2.hex diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index c3ca796d511..7c713cb4a4f 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -80,6 +80,8 @@ CONFIG_CMD_CBFS=y CONFIG_CMD_CRAMFS=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_PSTORE=y +CONFIG_CMD_PSTORE_MEM_ADDR=0x3000000 CONFIG_MAC_PARTITION=y CONFIG_AMIGA_PARTITION=y CONFIG_OF_CONTROL=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 18f787cb518..6ac29199777 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -93,6 +93,8 @@ CONFIG_CMD_CRAMFS=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_SQUASHFS=y CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_PSTORE=y +CONFIG_CMD_PSTORE_MEM_ADDR=0x3000000 CONFIG_MAC_PARTITION=y CONFIG_AMIGA_PARTITION=y CONFIG_OF_CONTROL=y diff --git a/test/py/tests/test_pstore.py b/test/py/tests/test_pstore.py new file mode 100644 index 00000000000..5a35724f60a --- /dev/null +++ b/test/py/tests/test_pstore.py @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2020, Collabora +# Author: Frédéric Danis + +import pytest +import u_boot_utils +import os +import tempfile +import shutil + +PSTORE_ADDR=0x3000000 +PSTORE_LENGTH=0x100000 +PSTORE_PANIC1='test/py/tests/test_pstore_data_panic1.hex' +PSTORE_PANIC2='test/py/tests/test_pstore_data_panic2.hex' +PSTORE_CONSOLE='test/py/tests/test_pstore_data_console.hex' +ADDR=0x01000008 + +def load_pstore(u_boot_console): + """Load PStore records from sample files""" + + output = u_boot_console.run_command_list([ + 'host load hostfs - 0x%x %s' % (PSTORE_ADDR, + os.path.join(u_boot_console.config.source_dir, PSTORE_PANIC1)), + 'host load hostfs - 0x%x %s' % (PSTORE_ADDR + 4096, + os.path.join(u_boot_console.config.source_dir, PSTORE_PANIC2)), + 'host load hostfs - 0x%x %s' % (PSTORE_ADDR + 253 * 4096, + os.path.join(u_boot_console.config.source_dir, PSTORE_CONSOLE)), + 'pstore set 0x%x 0x%x' % (PSTORE_ADDR, PSTORE_LENGTH)]) + +def checkfile(u_boot_console, path, filesize, checksum): + """Check file against MD5 checksum""" + + output = u_boot_console.run_command_list([ + 'load hostfs - %x %s' % (ADDR, path), + 'printenv filesize']) + assert('filesize=%x' % (filesize) in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(checksum in ''.join(output)) + +@pytest.mark.buildconfigspec('cmd_pstore') +def test_pstore_display_all_records(u_boot_console): + """Test that pstore displays all records.""" + + u_boot_console.run_command('') + load_pstore(u_boot_console) + response = u_boot_console.run_command('pstore display') + assert('**** Dump' in response) + assert('**** Console' in response) + +@pytest.mark.buildconfigspec('cmd_pstore') +def test_pstore_display_one_record(u_boot_console): + """Test that pstore displays only one record.""" + + u_boot_console.run_command('') + load_pstore(u_boot_console) + response = u_boot_console.run_command('pstore display dump 1') + assert('Panic#2 Part1' in response) + assert('**** Console' not in response) + +@pytest.mark.buildconfigspec('cmd_pstore') +def test_pstore_save_records(u_boot_console): + """Test that pstore saves all records.""" + + outdir = tempfile.mkdtemp() + + u_boot_console.run_command('') + load_pstore(u_boot_console) + u_boot_console.run_command('pstore save hostfs - %s' % (outdir)) + + checkfile(u_boot_console, '%s/dmesg-ramoops-0' % (outdir), 3798, '8059335ab4cfa62c77324c491659c503') + checkfile(u_boot_console, '%s/dmesg-ramoops-1' % (outdir), 4035, '3ff30df3429d81939c75d0070b5187b9') + checkfile(u_boot_console, '%s/console-ramoops-0' % (outdir), 4084, 'bb44de4a9b8ebd9b17ae98003287325b') + + shutil.rmtree(outdir) diff --git a/test/py/tests/test_pstore_data_console.hex b/test/py/tests/test_pstore_data_console.hex new file mode 100644 index 0000000000000000000000000000000000000000..e7f426e8928a2793457baced5f66ee165ef429f6 GIT binary patch literal 4096 zcmcgv%TnVw6lJ!(nP0e*4NyZ8zvNd{7IX(_s%e@b&{Z=OMcI}D8f?ie*$MgY`GC1f z?1ZL6Cktj4lpUjc?>YA&9Sz@~dDb&-IDxkz1&BYW{HH_2@lNt}`hF%c=vQY{D}JqApUVz+M^#mQS38q21kR=dA1k z656*dwDxHrn#gIb!N!=1-E&>xgDwrjz_Af2FP@z4lvdzaX=YhgZ%XBT48sLX{ZLm_ zPDKnyPbK0<-l>$;Z%Z$c>pK{J@i~S|h6zy>7x$oN7_fK;cGUADG6$&=L1hs`0QKS( zril``cu(&`!L?=-Xw9IKpfIgDFSv1Kf*Ch~>qQYlPHM`l7^+#x2DWEeiw}D?30&Lu zqsYURQS9u;kd$Sj3aJL2(beJA^{4}~WayepG3b;^j(N`Ra+%N$G`|L&T41flTrm77 zl7bC7{aUMj%0)j*1m-ZU)vU{&ScXQN4qV@YOcuqU(?+|)pqi=961Pu$5^ROr3u5>IHSVMt?8z_X9<$KXq6bOmEx2Ld5{qrht!K;=+w26WfMvl7` z1>cRy|3%?>6@pC^h-aB;+hPDB68mpU;l%*dCB+f#>I%E4o7RHnOt%9;Ht`58$JuI- zLo0}bx8-35VtqH2im9T@M1}KRN-nA;A$J3z$nv)=j3E@hEur;=!7Ztj0?Bl_pzNtF zjlYSBYZKSnro{}C=xv$&q%>0FNuaB>)$ulQA_0lE+J8fr#J2Ueq+XO~-ehexHVu3f z+HSPfz=tG?ZTr7P-qfH4|I;(Wv3r4M`2m9e%rnJu_%!+}!XbeZexIbgf{TxTf@6nx zvRFMSuS@8HeUg^Ce_ZD|{ut+SirtG_j?6(l^{c0)Tij6y z4&r)XA3h$QpB#M;E@e3LOn;9qvWai`w}3mY{Vg_+p8W@WJv%&yQC*f&RWPx8;UcQv zL!CC4SPSt+yMN1Ci6o~t4smZ|I8IP7(YZdu6hQM|Fft1IlSK7%dEalo_I>6?Nk~#^ z(a>XF5~1RxV-lsrVTlz)D65$2+NSG+G<5XJn0kW58}f zM{uAkHkc1BL2$tc6J8@%UR!1|D8KNeQiv=1`DMOme z?6J8p=$l(?Bes(Zbaw+Qo(-P?M5 zQSeKaF&sa-bU0SBfQ!>1-YWK5n`l_H-37ck}31Kv1HH*46{njYvf$=F?HcDDmvrxTgu4T3bU zgZ}O+g#jS}l74@6c|1a2V+niB)v+kDG=H>9bHTxz2~I4A*3+b1CCYVOyobGFXTr{xV}Cau yo`=L!&&H!;E#e_Fr-O-?OIiLfAGn|6h`eHJ!alb`>%~#CVvF0Qi-|XP{eJ;km?x0{ literal 0 HcmV?d00001 diff --git a/test/py/tests/test_pstore_data_panic1.hex b/test/py/tests/test_pstore_data_panic1.hex new file mode 100644 index 0000000000000000000000000000000000000000..988929d12c25fee4c4242776a2ed0d78cdc55948 GIT binary patch literal 4096 zcmb_f-;dn35$0X4!PN+gYmt|}4U(5LnsX>oqNGIU-KfAd1$7R)g?$M>HTkqai!8fmnyeN7Q${^(Yil``WO9Ix}UFLa}f6+H_s5(nim$>3Z6tv^7;~VdrU6l-1l4pwri7lg{kC z!Wg_bhiL)38$sG?YL=^o(aYL)1MSS#rJ6fCvNy)wxL)}t)zvDm?HkIowE3|~b4-e= zw`H2msi@LcWpmrmZQoF0tP^|GvL+cX<_C*9u8R5PQW=0ygj ze6CtcwJMBEt2cyBU2EZM+Pu#tHDYS~LLzrnpE2Gmc9gT5a*1bBbja<#!yrfl=bvk&LMY9<%{DB@dx+&6f zX-F+pyR6dMUat@nQc=x*Ov~FQg)P=oi*%-tOg(>{BB4|ky0-HHQKToh1X0c}|1=@+ z=*h)|g2<=yWm!%LS$nC9MQhE3zNh{GhZ*m zp)=nPV*iRBtJ=I(;KV|ec0!M8Ya6Y=r{clWzeswvQs&Exm74!hV5Lqk>`kF9y@b~N z5m@4J?}{$Zsc1;G1m@IlFx`cj+f>(B@;~rf!N0^$JhT%cjxpmOo^S0CJP53AkhcsL zzJ^6Gwun7nTv4TILa)BkJTjs3<8QFNi01XSQ+PIux1Ci}Pe^k2cw*=~2$0+>YAP66 zo#n4^Hz{Gys`SyD;5>E7b5#d4PJ5i3ZB4ZI?MIO!7bu*#G zU(audo;-in&~ica=*hP6bZIQT`15%x5cZQ759#6ar$jI8b!itZEtU&AoNW|_E?4Kv zMO!cD;5OHxh$BN_G|I_@gw{OZfg-wic-|*4#3XrNL}l!ODqvW>)UK*vH=I@lwgT4h z3u;=WUt@olMN3~3zm+mFvB+X@bbt_X5nj;?r#qoje!E-rb_p9NS>$G9lXyW0wiz2^ zng6#3%P-0a)&ZSpd%68NVNdj@l;YJA8kepWN&4eUp1TSlwsC-{W^v z%aQ+0!$&pQ=STQ)C>_2Je8lEk5BRR(T#_|X=C+GJ3~}1Kscpl?vhvVqczWil;5%@`FY_!c!G$7KJQC^?A zV2B?^GQplPx#Pd)f@9X3Xu*hn$y6Ud*s_TqwCoxp8N|QIzZ&HqwJYfG9sfIg2fG1@ z`ylU*wx`W*M{FA-envsyqw<)1&;Ps8Hpab2?z?OVU-FnTn9~Z3i4KYm-b!H@SKQ}AdtWx9dxJfAFlT)ub1Uk z%@qusho@-*3-8&E(Gp|h;zQJi|cD! z!-b6DB64+i@4<_4Q{H*_u=&8vrfN7h73#gaQKg+fc!=C2lCcND{Qy zMh?`DF{R)ED#0dFS3$;B?|>%U4G%FrH+xTyRxS#-kGnvR`Hs;55_JK5c96Ag(_A&J zV+O8~bF7$KurL?_$D#0$*6(h$t=a-Ni|zpLkK|m%v^$aw_TI=g5ee@~wksL$Kbw7Z z_a^^^lCh&}!b22||9i>U<9kuyuDt(s$rzO5#Ft(I;+*65h3i7-u4*Wkc^Dx{0scp3 z*7!kS$O?s8jiFN;>Q3oC4Yp*0zpWBm^6c#F6;f!{-7CyY(mcWnC7^&YO- z!6n`&$0wcM$uT=PJUKamIeLzcpvsQ$IX-58gW8%M;?p%~&88>pfU!&Z)%y4lsCeAi z(fW{0r?@YEvSw_0#GW&vDO(d`KV$fa9-)Qj@LM{XqWM{8baKe(+4Q4zCt!4qI8Oe- gK1K6im&c6#eu`;b{uY4j*Km4t@E9X-&W;cM16+S2TL1t6 literal 0 HcmV?d00001 diff --git a/test/py/tests/test_pstore_data_panic2.hex b/test/py/tests/test_pstore_data_panic2.hex new file mode 100644 index 0000000000000000000000000000000000000000..8f9d56cbe01e38f5f8fac6d46491497c9d7bda8f GIT binary patch literal 4096 zcmcIn%Wm676lIDmnrzxn7$6%5h2?qNc?oG2vD(x?3%EcE6bKA;G#ti+ElQ=N*x6;# zzwFQS4qql?*)a;5fZ-uDbLR3s&bfE?=I!yn-z7=>`w<@|wO~vLX(phxVf=9R{L~e> zf5FMAE4S?VD|r2$5T?z9a>c=%k@v4W6_m@=ygnlbA96oGcSU*`=6U(|OOlnVWwV7j z>f@Gq{AIrR=zpNs${*2dOJDYJg;H9ak)N)8Sa0)HK{i|GFAnH+2-dPpP_kW-_D!3? zSpdcGEXz2Zl7~FBc?kYjoTorSrhEoq2!0mlg3`WiQfg%*J|KREPr!4;GfriiLA?mV zN3{5ucERFLnK2Ug&{V4ho~l2`_&&Z;7F5Jnh+l88-A=p+J?%`|Er2LWHKj~c#zceq zXj)0b+X&rq{~$Ps3NbjY^yhQG-pz9iAqEHx1_=DX$wt{5*u4jP&@KzWX@pKg=609c z3VH6`{Djj7Maqpl>;&#)51d^5vl+pvlfx#ND zHcSbU!O3h&C^=p&m$?1Pt=FME;^dvni)~1!A(Vu)*vJB%l2Dry{@aTzWLyxyxVk zZ6F7;@GJ-?VudZTf{6&m? z3<)15mBB!@vEOs52kHXHtyL}Tmg^355lJu|CY0r9LT&H9Q$0|D#ImSB8{R!RJ&BcN zqp89VvWH^~yVBirt`B<$r6Y8OYzI!@C>rz;!~hA{Y9z$HVqmhq7~tDb47lJ7PzU*Dh$^sG4Ctt0ASC6Hzef=R zfg~Ke#Hw>;ql$shjLJ5t#u5Wzn6ynFH=-B_i<;k-?wDc#6o-hWgBx=)047Xy?rkxM z4LA#-nGCA8j1QC#`x|Tqv9rcqn6u3j7b>;VM54F8PxMtoeSde~pN0S{Mplyty}{qt z_1DJXh)^#8={p)9mF!k`-|L0|B&+e`WP=HuQ5@7NBfseSaif)3z4cr+8qtH|IGePv zqZ2)7V6@Hgafu!bx~|RhF}r@Sii*}H4 literal 0 HcmV?d00001 From 9ea0a1ee9309054102e61a29e746db672494d385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Danis?= Date: Fri, 20 Mar 2020 10:59:24 +0100 Subject: [PATCH 03/20] cmd: Fixup DT to pass PStore Ramoops parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify configuration and keep synchronized the PStore/Ramoops between U-Boot and the Linux kernel, this commit dynamically adds the Ramoops parameters defined in the U-Boot session to the Device Tree. Signed-off-by: Frédéric Danis Cc: Tom Rini Cc: Heinrich Schuchardt Cc: Wolfgang Denk Cc: Heiko Schocher --- cmd/pstore.c | 38 ++++++++++++++++++++++++++++++++++++++ common/image-fdt.c | 4 ++++ doc/pstore.rst | 2 ++ include/fdt_support.h | 3 +++ 4 files changed, 47 insertions(+) diff --git a/cmd/pstore.c b/cmd/pstore.c index 530eb03b182..9a8b38c7f26 100644 --- a/cmd/pstore.c +++ b/cmd/pstore.c @@ -480,6 +480,44 @@ static int do_pstore(struct cmd_tbl *cmdtp, int flag, int argc, char * const arg return c->cmd(cmdtp, flag, argc, argv); } +void fdt_fixup_pstore(void *blob) +{ + char node[32]; + int nodeoffset; /* node offset from libfdt */ + + nodeoffset = fdt_path_offset(blob, "/"); + if (nodeoffset < 0) { + /* Not found or something else bad happened. */ + log_err("fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); + return; + } + + nodeoffset = fdt_add_subnode(blob, nodeoffset, "reserved-memory"); + if (nodeoffset < 0) { + log_err("Add 'reserved-memory' node failed: %s\n", + fdt_strerror(nodeoffset)); + return; + } + fdt_setprop_u32(blob, nodeoffset, "#address-cells", 2); + fdt_setprop_u32(blob, nodeoffset, "#size-cells", 2); + fdt_setprop_empty(blob, nodeoffset, "ranges"); + + sprintf(node, "ramoops@%llx", (unsigned long long)pstore_addr); + nodeoffset = fdt_add_subnode(blob, nodeoffset, node); + if (nodeoffset < 0) { + log_err("Add '%s' node failed: %s\n", node, fdt_strerror(nodeoffset)); + return; + } + fdt_setprop_string(blob, nodeoffset, "compatible", "ramoops"); + fdt_setprop_u64(blob, nodeoffset, "reg", pstore_addr); + fdt_appendprop_u64(blob, nodeoffset, "reg", pstore_length); + fdt_setprop_u32(blob, nodeoffset, "record-size", pstore_record_size); + fdt_setprop_u32(blob, nodeoffset, "console-size", pstore_console_size); + fdt_setprop_u32(blob, nodeoffset, "ftrace-size", pstore_ftrace_size); + fdt_setprop_u32(blob, nodeoffset, "pmsg-size", pstore_pmsg_size); + fdt_setprop_u32(blob, nodeoffset, "ecc-size", pstore_ecc_size); +} + U_BOOT_CMD(pstore, 10, 0, do_pstore, "Manage Linux Persistent Storage", "set [record-size] [console-size] [ftrace-size] [pmsg_size] [ecc-size]\n" diff --git a/common/image-fdt.c b/common/image-fdt.c index 3d6935ad40b..327a8c4c395 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -567,6 +567,10 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, /* Update ethernet nodes */ fdt_fixup_ethernet(blob); +#if CONFIG_IS_ENABLED(CMD_PSTORE) + /* Append PStore configuration */ + fdt_fixup_pstore(blob); +#endif if (IMAGE_OF_BOARD_SETUP) { fdt_ret = ft_board_setup(blob, gd->bd); if (fdt_ret) { diff --git a/doc/pstore.rst b/doc/pstore.rst index 4fceb2dd990..8427d8fd97a 100644 --- a/doc/pstore.rst +++ b/doc/pstore.rst @@ -25,6 +25,8 @@ i.e.:: The same values should be set in U-Boot to be able to retrieve the records. This values can be set at build time in U-Boot configuration file, or at runtime. +U-Boot automatically patches the Device Tree to pass the Ramoops parameters to +the kernel. The PStore configuration parameters are: diff --git a/include/fdt_support.h b/include/fdt_support.h index 9684cffe80b..dbbac0fb6a3 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -359,4 +359,7 @@ int fdt_update_ethernet_dt(void *blob); #ifdef CONFIG_FSL_MC_ENET void fdt_fixup_board_enet(void *blob); #endif +#ifdef CONFIG_CMD_PSTORE +void fdt_fixup_pstore(void *blob); +#endif #endif /* ifndef __FDT_SUPPORT_H */ From 39916bb45f9e233d6df8ee478c539b100116a34a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 14 Sep 2020 12:50:54 +0200 Subject: [PATCH 04/20] test: sharpen button label unit test Using different strings for the device tree node labels and the label property of buttons sharpens the button label unit test. Signed-off-by: Heinrich Schuchardt Reviewed-by: Philippe Reynes --- arch/sandbox/dts/sandbox.dtsi | 8 ++++---- arch/sandbox/dts/test.dts | 8 ++++---- test/dm/button.c | 6 +++--- test/py/tests/test_button.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index c76ecc013c9..0faad3f3195 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -18,14 +18,14 @@ buttons { compatible = "gpio-keys"; - summer { + btn1 { gpios = <&gpio_a 3 0>; - label = "summer"; + label = "button1"; }; - christmas { + btn2 { gpios = <&gpio_a 4 0>; - label = "christmas"; + label = "button2"; }; }; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index c7d13769116..fa84b2c10f3 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -55,14 +55,14 @@ buttons { compatible = "gpio-keys"; - summer { + btn1 { gpios = <&gpio_a 3 0>; - label = "summer"; + label = "button1"; }; - christmas { + btn2 { gpios = <&gpio_a 4 0>; - label = "christmas"; + label = "button2"; }; }; diff --git a/test/dm/button.c b/test/dm/button.c index 91178017365..ecaa47cf5f3 100644 --- a/test/dm/button.c +++ b/test/dm/button.c @@ -57,17 +57,17 @@ static int dm_test_button_label(struct unit_test_state *uts) { struct udevice *dev, *cmp; - ut_assertok(button_get_by_label("summer", &dev)); + ut_assertok(button_get_by_label("button1", &dev)); ut_asserteq(1, device_active(dev)); ut_assertok(uclass_get_device(UCLASS_BUTTON, 1, &cmp)); ut_asserteq_ptr(dev, cmp); - ut_assertok(button_get_by_label("christmas", &dev)); + ut_assertok(button_get_by_label("button2", &dev)); ut_asserteq(1, device_active(dev)); ut_assertok(uclass_get_device(UCLASS_BUTTON, 2, &cmp)); ut_asserteq_ptr(dev, cmp); - ut_asserteq(-ENODEV, button_get_by_label("spring", &dev)); + ut_asserteq(-ENODEV, button_get_by_label("nobutton", &dev)); return 0; } diff --git a/test/py/tests/test_button.py b/test/py/tests/test_button.py index 98067a98f28..eadd9dd6135 100644 --- a/test/py/tests/test_button.py +++ b/test/py/tests/test_button.py @@ -11,7 +11,7 @@ def test_button_exit_statuses(u_boot_console): expected_response = 'rc:0' response = u_boot_console.run_command('button list; echo rc:$?') assert(expected_response in response) - response = u_boot_console.run_command('button summer; echo rc:$?') + response = u_boot_console.run_command('button button1; echo rc:$?') assert(expected_response in response) expected_response = 'rc:1' From 7cd96a47281145aca4f9c8960a0a2e185b8bd70c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 14 Sep 2020 12:50:55 +0200 Subject: [PATCH 05/20] drivers: gpio: keep output value for input on sandbox For testing purposes keep the output value when switching to input. This allows us to manipulate the input value via the gpio command. Signed-off-by: Heinrich Schuchardt Reviewed-by: Philippe Reynes --- drivers/gpio/sandbox.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index c2f80472b83..eb2600de311 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -185,7 +185,15 @@ static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, dir_flags = get_gpio_dir_flags(dev, offset); - *dir_flags = flags; + /* + * For testing purposes keep the output value when switching to input. + * This allows us to manipulate the input value via the gpio command. + */ + if (flags & GPIOD_IS_IN) + *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) | + (*dir_flags & GPIOD_IS_OUT_ACTIVE); + else + *dir_flags = flags; return 0; } From a6bfd71a96201127836d59736abcb54dc2d5e1a5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 14 Sep 2020 12:50:56 +0200 Subject: [PATCH 06/20] cmd/button: return button status To make the button command useful in a shell script it should return the status of the button: * 0 (true) - pressed, on * 1 (false) - not pressed, off The button command takes only one argument. Correct maxargs. Adjust the Python unit test. Signed-off-by: Heinrich Schuchardt Reviewed-by: Philippe Reynes --- cmd/button.c | 4 ++-- test/py/tests/test_button.py | 36 +++++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/cmd/button.c b/cmd/button.c index 84ad1653c7b..64c5a8fa046 100644 --- a/cmd/button.c +++ b/cmd/button.c @@ -75,11 +75,11 @@ int do_button(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) ret = show_button_state(dev); - return 0; + return !ret; } U_BOOT_CMD( - button, 4, 1, do_button, + button, 2, 1, do_button, "manage buttons", " \tGet button state\n" "button list\t\tShow a list of buttons" diff --git a/test/py/tests/test_button.py b/test/py/tests/test_button.py index eadd9dd6135..3b7f148c8fc 100644 --- a/test/py/tests/test_button.py +++ b/test/py/tests/test_button.py @@ -4,16 +4,34 @@ import pytest @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_button') -def test_button_exit_statuses(u_boot_console): - """Test that non-input button commands correctly return the command - success/failure status.""" +def test_button_list(u_boot_console): + """Test listing buttons""" - expected_response = 'rc:0' response = u_boot_console.run_command('button list; echo rc:$?') - assert(expected_response in response) - response = u_boot_console.run_command('button button1; echo rc:$?') - assert(expected_response in response) + assert('button1' in response) + assert('button2' in response) + assert('rc:0' in response) + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_button') +@pytest.mark.buildconfigspec('cmd_gpio') +def test_button_return_code(u_boot_console): + """Test correct reporting of the button status + + The sandbox gpio driver reports the last output value as input value. + We can use this in our test to emulate different input statuses. + """ + + u_boot_console.run_command('gpio set a3; gpio input a3'); + response = u_boot_console.run_command('button button1; echo rc:$?') + assert('on' in response) + assert('rc:0' in response) + + u_boot_console.run_command('gpio clear a3; gpio input a3'); + response = u_boot_console.run_command('button button1; echo rc:$?') + assert('off' in response) + assert('rc:1' in response) - expected_response = 'rc:1' response = u_boot_console.run_command('button nonexistent-button; echo rc:$?') - assert(expected_response in response) + assert('not found' in response) + assert('rc:1' in response) From 684710dc33b8fa1c366ee9f11424b780f999724c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 19 Sep 2020 07:55:35 +0200 Subject: [PATCH 07/20] arm: enable DM_RNG on QEMU by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EFI_RNG_PROTOCOL is needed for address randomization in Linux. We should provide it by default on QEMU. Reported-by: François Ozog Signed-off-by: Heinrich Schuchardt --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7c206ce734f..b885b9e146f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -938,6 +938,7 @@ config ARCH_QEMU select OF_CONTROL select PL01X_SERIAL imply CMD_DM + imply DM_RNG imply DM_RTC imply RTC_PL031 From 4dee3f785124af2fb533e820579f2f1139c42f99 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 4 Aug 2020 10:05:46 +0100 Subject: [PATCH 08/20] mmc: remove duplicate mmc_get_env_dev() implementations Since it's so trivial I could just about tolerate this when there were only two copies of it. But now there are about to be three. Signed-off-by: David Woodhouse --- drivers/mmc/mmc.c | 9 +++++++++ env/fat.c | 9 --------- env/mmc.c | 5 ----- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d79cdef62ed..11ce110df3e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -3111,3 +3111,12 @@ int mmc_set_bkops_enable(struct mmc *mmc) return 0; } #endif + +__weak int mmc_get_env_dev(void) +{ +#ifdef CONFIG_SYS_MMC_ENV_DEV + return CONFIG_SYS_MMC_ENV_DEV; +#else + return 0; +#endif +} diff --git a/env/fat.c b/env/fat.c index 71bf8bfa18f..653a38fd937 100644 --- a/env/fat.c +++ b/env/fat.c @@ -29,15 +29,6 @@ # define LOADENV #endif -__weak int mmc_get_env_dev(void) -{ -#ifdef CONFIG_SYS_MMC_ENV_DEV - return CONFIG_SYS_MMC_ENV_DEV; -#else - return 0; -#endif -} - static char *env_fat_device_and_part(void) { #ifdef CONFIG_MMC diff --git a/env/mmc.c b/env/mmc.c index ba872701b0d..4e67180b23a 100644 --- a/env/mmc.c +++ b/env/mmc.c @@ -24,11 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; -__weak int mmc_get_env_dev(void) -{ - return CONFIG_SYS_MMC_ENV_DEV; -} - #if CONFIG_IS_ENABLED(OF_CONTROL) static inline int mmc_offset_try_partition(const char *str, int copy, s64 *val) { From b0493bb75a4c5ab8c729dd714bc8a4b2e93eb35b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 4 Aug 2020 10:05:47 +0100 Subject: [PATCH 09/20] env/ext4.c: allow loading from an EXT4 partition on the MMC boot device This parallels what I added for FAT in commit 6731bef6966, allowing the environment to be found in a specific partition on the device that the board's mmc_get_env_dev() returns. On the Banana Pi R2 that means the device that U-Boot was loaded from; either the internal eMMC or an SD card. Signed-off-by: David Woodhouse --- env/Kconfig | 4 ++++ env/ext4.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/env/Kconfig b/env/Kconfig index c6ba08878d6..aa63fae021e 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -477,6 +477,10 @@ config ENV_EXT4_DEVICE_AND_PART If none, first valid partition in device D. If no partition table then means device D. + If ENV_EXT4_INTERFACE is set to "mmc" then device 'D' can be omitted, + leaving the string starting with a colon, and the boot device will + be used. + config ENV_EXT4_FILE string "Name of the EXT4 file to use for the environment" depends on ENV_IS_IN_EXT4 diff --git a/env/ext4.c b/env/ext4.c index f823b694099..e666f7b9455 100644 --- a/env/ext4.c +++ b/env/ext4.c @@ -41,7 +41,21 @@ __weak const char *env_ext4_get_intf(void) __weak const char *env_ext4_get_dev_part(void) { +#ifdef CONFIG_MMC + static char *part_str; + + if (!part_str) { + part_str = CONFIG_ENV_EXT4_DEVICE_AND_PART; + if (!strcmp(CONFIG_ENV_EXT4_INTERFACE, "mmc") && part_str[0] == ':') { + part_str = "0" CONFIG_ENV_EXT4_DEVICE_AND_PART; + part_str[0] += mmc_get_env_dev(); + } + } + + return part_str; +#else return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART; +#endif } static int env_ext4_save_buffer(env_t *env_new) From f9b9b779338ba2dd673fb7b8ae92a01fd9ba6f64 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Thu, 3 Sep 2020 14:25:15 -0300 Subject: [PATCH 10/20] spl: Avoid printing boot device if silent console is enabled Signed-off-by: Otavio Salvador Reviewed-by: Tom Rini Reviewed-by: Stefan Roese --- common/spl/spl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/spl/spl.c b/common/spl/spl.c index 4840d1d3670..63c48fbf33d 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -552,7 +552,9 @@ static int boot_from_devices(struct spl_image_info *spl_image, struct spl_image_loader *loader; loader = spl_ll_find_loader(spl_boot_list[i]); -#if defined(CONFIG_SPL_SERIAL_SUPPORT) && defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if defined(CONFIG_SPL_SERIAL_SUPPORT) \ + && defined(CONFIG_SPL_LIBCOMMON_SUPPORT) \ + && !defined(CONFIG_SILENT_CONSOLE) if (loader) printf("Trying to boot from %s\n", loader->name); else From d74fcee2d8b41ec809ef42e279b60190673897f4 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Tue, 29 Sep 2020 23:14:29 -0300 Subject: [PATCH 11/20] spl: Add SPL_SERIAL as requirement for SDP_USB_SDP The USB SDP protocol require the SPL serial support to allow the build to succeed. Signed-off-by: Otavio Salvador --- common/spl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 807b1dc0593..620ea1e8b43 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1237,6 +1237,7 @@ endchoice config SPL_USB_SDP_SUPPORT bool "Support SDP (Serial Download Protocol)" + depends on SPL_SERIAL_SUPPORT help Enable Serial Download Protocol (SDP) device support in SPL. This allows to download images into memory and execute (jump to) them From 4b2be78ab66ca3f6f177823c0f81fcdd1d476e9b Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Wed, 9 Sep 2020 16:24:56 -0400 Subject: [PATCH 12/20] time: Fix get_ticks being non-monotonic get_ticks does not always succeed. Sometimes it can be called before the timer has been initialized. If it does, it returns a negative errno. This causes the timer to appear non-monotonic, because the value will become much smaller after the timer is initialized. No users of get_ticks which I checked handle errors of this kind. Further, functions like tick_to_time mangle the result of get_ticks, making it very unlikely that one could check for an error without suggesting a patch such as this one. This patch panics if we ever get an error. There are two cases in which this can occur. The first is if we couldn't find/probe the timer for some reason. One reason for this is if the timer is not available so early. This likely indicates misconfiguration. Another reason is that the timer has an invalid/missing device tree binding. In this case, panicing is also correct. The second case covers errors calling get_count. This can only occur if the timer is missing a get_count function (or on RISC-V, but that should be fixed soon). Fixes: c8a7ba9e6a5 Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- lib/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/time.c b/lib/time.c index 47f8c84327d..88bc50405ff 100644 --- a/lib/time.c +++ b/lib/time.c @@ -91,13 +91,13 @@ uint64_t notrace get_ticks(void) ret = dm_timer_init(); if (ret) - return ret; + panic("Could not initialize timer (err %d)\n", ret); #endif } ret = timer_get_count(gd->timer, &count); if (ret) - return ret; + panic("Could not read count from timer (err %d)\n", ret); return count; } From 73fdb9558ed15df868b4b07bdc61ab682b49bd59 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 15 Sep 2020 01:58:11 +0200 Subject: [PATCH 13/20] bootm: add {arch,board}_preboot_os() to bootm.h Functions that are used in multiple C modules should be defined in an include. Signed-off-by: Heinrich Schuchardt Reviewed-by: Michael Walle --- include/bootm.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/bootm.h b/include/bootm.h index 0350c349f37..a812a6bf24f 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -75,4 +75,14 @@ void board_quiesce_devices(void); */ void switch_to_non_secure_mode(void); +/** + * arch_preboot_os() - arch specific configuration before booting + */ +void arch_preboot_os(void); + +/** + * board_preboot_os() - board specific configuration before booting + */ +void board_preboot_os(void); + #endif From c82a97bc5cd2f3923847945993a337f5e904afc2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 5 Oct 2020 08:30:08 +0200 Subject: [PATCH 14/20] global_data.h: convert GD_FLG_* to enum Sphinx documentation is only available for enums not for #defines. Anyway it is better to keep related definitions in an enum. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- include/asm-generic/global_data.h | 106 +++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index d4a4e2215dc..e4a68e0d914 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -138,7 +138,6 @@ typedef struct global_data { struct udevice *watchdog_dev; #endif } gd_t; -#endif #ifdef CONFIG_BOARD_TYPES #define gd_board_type() gd->board_type @@ -146,27 +145,90 @@ typedef struct global_data { #define gd_board_type() 0 #endif -/* - * Global Data Flags +/** + * enum gd_flags - global data flags + * + * See field flags of &struct global_data. */ -#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ -#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ -#define GD_FLG_SILENT 0x00004 /* Silent mode */ -#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */ -#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */ -#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */ -#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ -#define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */ -#define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */ -#define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */ -#define GD_FLG_SPL_INIT 0x00400 /* spl_init() has been called */ -#define GD_FLG_SKIP_RELOC 0x00800 /* Don't relocate */ -#define GD_FLG_RECORD 0x01000 /* Record console */ -#define GD_FLG_ENV_DEFAULT 0x02000 /* Default variable flag */ -#define GD_FLG_SPL_EARLY_INIT 0x04000 /* Early SPL init is done */ -#define GD_FLG_LOG_READY 0x08000 /* Log system is ready for use */ -#define GD_FLG_WDT_READY 0x10000 /* Watchdog is ready for use */ -#define GD_FLG_SKIP_LL_INIT 0x20000 /* Don't perform low-level init */ -#define GD_FLG_SMP_READY 0x40000 /* SMP init is complete */ +enum gd_flags { + /** + * @GD_FLG_RELOC: code was relocated to RAM + */ + GD_FLG_RELOC = 0x00001, + /** + * @GD_FLG_DEVINIT: devices have been initialized + */ + GD_FLG_DEVINIT = 0x00002, + /** + * @GD_FLG_SILENT: silent mode + */ + GD_FLG_SILENT = 0x00004, + /** + * @GD_FLG_POSTFAIL: critical POST test failed + */ + GD_FLG_POSTFAIL = 0x00008, + /** + * @GD_FLG_POSTSTOP: POST sequence aborted + */ + GD_FLG_POSTSTOP = 0x00010, + /** + * @GD_FLG_LOGINIT: log Buffer has been initialized + */ + GD_FLG_LOGINIT = 0x00020, + /** + * @GD_FLG_DISABLE_CONSOLE: disable console (in & out) + */ + GD_FLG_DISABLE_CONSOLE = 0x00040, + /** + * @GD_FLG_ENV_READY: environment imported into hash table + */ + GD_FLG_ENV_READY = 0x00080, + /** + * @GD_FLG_SERIAL_READY: pre-relocation serial console ready + */ + GD_FLG_SERIAL_READY = 0x00100, + /** + * @GD_FLG_FULL_MALLOC_INIT: full malloc() is ready + */ + GD_FLG_FULL_MALLOC_INIT = 0x00200, + /** + * @GD_FLG_SPL_INIT: spl_init() has been called + */ + GD_FLG_SPL_INIT = 0x00400, + /** + * @GD_FLG_SKIP_RELOC: don't relocate + */ + GD_FLG_SKIP_RELOC = 0x00800, + /** + * @GD_FLG_RECORD: record console + */ + GD_FLG_RECORD = 0x01000, + /** + * @GD_FLG_ENV_DEFAULT: default variable flag + */ + GD_FLG_ENV_DEFAULT = 0x02000, + /** + * @GD_FLG_SPL_EARLY_INIT: early SPL initialization is done + */ + GD_FLG_SPL_EARLY_INIT = 0x04000, + /** + * @GD_FLG_LOG_READY: log system is ready for use + */ + GD_FLG_LOG_READY = 0x08000, + /** + * @GD_FLG_WDT_READY: watchdog is ready for use + */ + GD_FLG_WDT_READY = 0x10000, + /** + * @GD_FLG_SKIP_LL_INIT: don't perform low-level initialization + */ + GD_FLG_SKIP_LL_INIT = 0x20000, + /** + * @GD_FLG_SMP_READY: SMP initialization is complete + */ + GD_FLG_SMP_READY = 0x40000, +}; + +#endif /* __ASSEMBLY__ */ #endif /* __ASM_GENERIC_GBL_DATA_H */ From 0c7cd15f3f3500865110a4def87bca6d4c80a0fd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 5 Oct 2020 08:30:09 +0200 Subject: [PATCH 15/20] global_data.h: add Sphinx documentation Add the missing Sphinx documentation for struct global_data and gd_board_type(). Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- include/asm-generic/global_data.h | 372 +++++++++++++++++++++++++----- 1 file changed, 317 insertions(+), 55 deletions(-) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index e4a68e0d914..ebb740d34f3 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -24,121 +24,383 @@ #include #include -typedef struct global_data { +typedef struct global_data gd_t; + +/** + * struct global_data - global data structure + */ +struct global_data { + /** + * @bd: board information + */ struct bd_info *bd; + /** + * @flags: global data flags + * + * See &enum gd_flags + */ unsigned long flags; + /** + * @baudrate: baud rate of the serial interface + */ unsigned int baudrate; - unsigned long cpu_clk; /* CPU clock in Hz! */ + /** + * @cpu_clk: CPU clock rate in Hz + */ + unsigned long cpu_clk; + /** + * @bus_clk: platform clock rate in Hz + */ unsigned long bus_clk; + /** + * @pci_clk: PCI clock rate in Hz + */ /* We cannot bracket this with CONFIG_PCI due to mpc5xxx */ unsigned long pci_clk; + /** + * @mem_clk: memory clock rate in Hz + */ unsigned long mem_clk; #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) || defined(CONFIG_DM_VIDEO) - unsigned long fb_base; /* Base address of framebuffer mem */ + /** + * @fb_base: base address of frame buffer memory + */ + unsigned long fb_base; #endif #if defined(CONFIG_POST) - unsigned long post_log_word; /* Record POST activities */ - unsigned long post_log_res; /* success of POST test */ - unsigned long post_init_f_time; /* When post_init_f started */ + /** + * @post_log_word: active POST tests + * + * @post_log_word is a bit mask defining which POST tests are recorded + * (see constants POST_*). + */ + unsigned long post_log_word; + /** + * @post_log_res: POST results + * + * @post_log_res is a bit mask with the POST results. A bit with value 1 + * indicates successful execution. + */ + unsigned long post_log_res; + /** + * @post_init_f_time: time in ms when post_init_f() started + */ + unsigned long post_init_f_time; #endif #ifdef CONFIG_BOARD_TYPES + /** + * @board_type: board type + * + * If a U-Boot configuration supports multiple board types, the actual + * board type may be stored in this field. + */ unsigned long board_type; #endif - unsigned long have_console; /* serial_init() was called */ + /** + * @have_console: console is available + * + * A value of 1 indicates that serial_init() was called and a console + * is available. + * A value of 0 indicates that console input and output drivers shall + * not be called. + */ + unsigned long have_console; #if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER) - unsigned long precon_buf_idx; /* Pre-Console buffer index */ + /** + * @precon_buf_idx: pre-console buffer index + * + * @precon_buf_idx indicates the current position of the buffer used to + * collect output before the console becomes available + */ + unsigned long precon_buf_idx; #endif - unsigned long env_addr; /* Address of Environment struct */ - unsigned long env_valid; /* Environment valid? enum env_valid */ - unsigned long env_has_init; /* Bitmask of boolean of struct env_location offsets */ - int env_load_prio; /* Priority of the loaded environment */ - - unsigned long ram_base; /* Base address of RAM used by U-Boot */ - unsigned long ram_top; /* Top address of RAM used by U-Boot */ - unsigned long relocaddr; /* Start address of U-Boot in RAM */ - phys_size_t ram_size; /* RAM size */ - unsigned long mon_len; /* monitor len */ - unsigned long irq_sp; /* irq stack pointer */ - unsigned long start_addr_sp; /* start_addr_stackpointer */ + /** + * @env_addr: address of environment structure + * + * @env_addr contains the address of the structure holding the + * environment variables. + */ + unsigned long env_addr; + /** + * @env_valid: environment is valid + * + * See &enum env_valid + */ + unsigned long env_valid; + /** + * @env_has_init: bit mask indicating environment locations + * + * &enum env_location defines which bit relates to which location + */ + unsigned long env_has_init; + /** + * @env_load_prio: priority of the loaded environment + */ + int env_load_prio; + /** + * @ram_base: base address of RAM used by U-Boot + */ + unsigned long ram_base; + /** + * @ram_top: top address of RAM used by U-Boot + */ + unsigned long ram_top; + /** + * @relocaddr: start address of U-Boot in RAM + * + * After relocation this field indicates the address to which U-Boot + * has been relocated. It can be displayed using the bdinfo command. + * Its value is needed to display the source code when debugging with + * GDB using the 'add-symbol-file u-boot ' command. + */ + unsigned long relocaddr; + /** + * @ram_size: RAM size in bytes + */ + phys_size_t ram_size; + /** + * @mon_len: monitor length in bytes + */ + unsigned long mon_len; + /** + * @irq_sp: IRQ stack pointer + */ + unsigned long irq_sp; + /** + * @start_addr_sp: initial stack pointer address + */ + unsigned long start_addr_sp; + /** + * @reloc_off: relocation offset + */ unsigned long reloc_off; - struct global_data *new_gd; /* relocated global data */ + /** + * @new_gd: pointer to relocated global data + */ + struct global_data *new_gd; #ifdef CONFIG_DM - struct udevice *dm_root; /* Root instance for Driver Model */ - struct udevice *dm_root_f; /* Pre-relocation root instance */ - struct list_head uclass_root; /* Head of core tree */ + /** + * @dm_root: root instance for Driver Model + */ + struct udevice *dm_root; + /** + * @dm_root_f: pre-relocation root instance + */ + struct udevice *dm_root_f; + /** + * @uclass_root: head of core tree + */ + struct list_head uclass_root; #endif #ifdef CONFIG_TIMER - struct udevice *timer; /* Timer instance for Driver Model */ + /** + * @timer: timer instance for Driver Model + */ + struct udevice *timer; #endif - - const void *fdt_blob; /* Our device tree, NULL if none */ - void *new_fdt; /* Relocated FDT */ - unsigned long fdt_size; /* Space reserved for relocated FDT */ + /** + * @fdt_blob: U-Boot's own device tree, NULL if none + */ + const void *fdt_blob; + /** + * @new_fdt: relocated device tree + */ + void *new_fdt; + /** + * @fdt_size: space reserved for relocated device space + */ + unsigned long fdt_size; #ifdef CONFIG_OF_LIVE + /** + * @of_root: root node of the live tree + */ struct device_node *of_root; #endif #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) - const void *multi_dtb_fit; /* uncompressed multi-dtb FIT image */ + /** + * @multi_dtb_fit: pointer to uncompressed multi-dtb FIT image + */ + const void *multi_dtb_fit; #endif - struct jt_funcs *jt; /* jump table */ - char env_buf[32]; /* buffer for env_get() before reloc. */ + /** + * @jt: jump table + * + * The jump table contains pointers to exported functions. A pointer to + * the jump table is passed to standalone applications. + */ + struct jt_funcs *jt; + /** + * @env_buf: buffer for env_get() before reloc + */ + char env_buf[32]; #ifdef CONFIG_TRACE - void *trace_buff; /* The trace buffer */ + /** + * @trace_buff: trace buffer + * + * When tracing function in U-Boot this field points to the buffer + * recording the function calls. + */ + void *trace_buff; #endif #if defined(CONFIG_SYS_I2C) - int cur_i2c_bus; /* current used i2c bus */ + /** + * @cur_i2c_bus: currently used I2C bus + */ + int cur_i2c_bus; #endif + /** + * @timebase_h: high 32 bits of timer + */ unsigned int timebase_h; + /** + * @timebase_l: low 32 bits of timer + */ unsigned int timebase_l; #if CONFIG_VAL(SYS_MALLOC_F_LEN) - unsigned long malloc_base; /* base address of early malloc() */ - unsigned long malloc_limit; /* limit address */ - unsigned long malloc_ptr; /* current address */ + /** + * @malloc_base: base address of early malloc() + */ + unsigned long malloc_base; + /** + * @malloc_limit: limit address of early malloc() + */ + unsigned long malloc_limit; + /** + * @malloc_ptr: current address of early malloc() + */ + unsigned long malloc_ptr; #endif #ifdef CONFIG_PCI - struct pci_controller *hose; /* PCI hose for early use */ - phys_addr_t pci_ram_top; /* top of region accessible to PCI */ + /** + * @hose: PCI hose for early use + */ + struct pci_controller *hose; + /** + * @pci_ram_top: top of region accessible to PCI + */ + phys_addr_t pci_ram_top; #endif #ifdef CONFIG_PCI_BOOTDELAY + /** + * @pcidelay_done: delay time before scanning of PIC hose expired + * + * If CONFIG_PCI_BOOTDELAY=y, pci_hose_scan() waits for the number of + * milliseconds defined by environment variable pcidelay before + * scanning. Once this delay has expired the flag @pcidelay_done + * is set to 1. + */ int pcidelay_done; #endif - struct udevice *cur_serial_dev; /* current serial device */ - struct arch_global_data arch; /* architecture-specific data */ + /** + * @cur_serial_dev: current serial device + */ + struct udevice *cur_serial_dev; + /** + * @arch: architecture-specific data + */ + struct arch_global_data arch; #ifdef CONFIG_CONSOLE_RECORD - struct membuff console_out; /* console output */ - struct membuff console_in; /* console input */ + /** + * @console_out: output buffer for console recording + * + * This buffer is used to collect output during console recording. + */ + struct membuff console_out; + /** + * @console_in: input buffer for console recording + * + * If console recording is activated, this buffer can be used to + * emulate input. + */ + struct membuff console_in; #endif #ifdef CONFIG_DM_VIDEO - ulong video_top; /* Top of video frame buffer area */ - ulong video_bottom; /* Bottom of video frame buffer area */ + /** + * @video_top: top of video frame buffer area + */ + ulong video_top; + /** + * @video_bottom: bottom of video frame buffer area + */ + ulong video_bottom; #endif #ifdef CONFIG_BOOTSTAGE - struct bootstage_data *bootstage; /* Bootstage information */ - struct bootstage_data *new_bootstage; /* Relocated bootstage info */ + /** + * @bootstage: boot stage information + */ + struct bootstage_data *bootstage; + /** + * @new_bootstage: relocated boot stage information + */ + struct bootstage_data *new_bootstage; #endif #ifdef CONFIG_LOG - int log_drop_count; /* Number of dropped log messages */ - int default_log_level; /* For devices with no filters */ - struct list_head log_head; /* List of struct log_device */ - int log_fmt; /* Mask containing log format info */ + /** + * @log_drop_count: number of dropped log messages + * + * This counter is incremented for each log message which can not + * be processed because logging is not yet available as signaled by + * flag %GD_FLG_LOG_READY in @flags. + */ + int log_drop_count; + /** + * @default_log_level: default logging level + * + * For logging devices without filters @default_log_level defines the + * logging level, cf. &enum log_level_t. + */ + int default_log_level; + /** + * @log_head: list of logging devices + */ + struct list_head log_head; + /** + * @log_fmt: bit mask for logging format + * + * The @log_fmt bit mask selects the fields to be shown in log messages. + * &enum log_fmt defines the bits of the bit mask. + */ + int log_fmt; #endif #if CONFIG_IS_ENABLED(BLOBLIST) - struct bloblist_hdr *bloblist; /* Bloblist information */ - struct bloblist_hdr *new_bloblist; /* Relocated blolist info */ + /** + * @bloblist: blob list information + */ + struct bloblist_hdr *bloblist; + /** + * @new_bloblist: relocated blob list information + */ + struct bloblist_hdr *new_bloblist; # ifdef CONFIG_SPL + /** + * @spl_handoff: SPL hand-off information + */ struct spl_handoff *spl_handoff; # endif #endif #if defined(CONFIG_TRANSLATION_OFFSET) - fdt_addr_t translation_offset; /* optional translation offset */ + /** + * @translation_offset: optional translation offset + * + * See CONFIG_TRANSLATION_OFFSET. + */ + fdt_addr_t translation_offset; #endif #if CONFIG_IS_ENABLED(WDT) + /** + * @watchdog_dev: watchdog device + */ struct udevice *watchdog_dev; #endif -} gd_t; +}; +/** + * gd_board_type() - retrieve board type + * + * Return: global board type + */ #ifdef CONFIG_BOARD_TYPES #define gd_board_type() gd->board_type #else From 467d90a37eda552bf74368eb0061c27567f37b9c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 5 Oct 2020 08:30:10 +0200 Subject: [PATCH 16/20] doc: global data pointer Add the description of the global data pointer to the generated HTML documentation. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- doc/develop/global_data.rst | 53 +++++++++++++++++++++++++++++++++++++ doc/develop/index.rst | 1 + 2 files changed, 54 insertions(+) create mode 100644 doc/develop/global_data.rst diff --git a/doc/develop/global_data.rst b/doc/develop/global_data.rst new file mode 100644 index 00000000000..9e7c8a24da0 --- /dev/null +++ b/doc/develop/global_data.rst @@ -0,0 +1,53 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Global data +=========== + +Globally required fields are held in the global data structure. A pointer to the +structure is available as symbol gd. The symbol is made available by the macro +%DECLARE_GLOBAL_DATA_PTR. + +Register pointing to global data +-------------------------------- + +On most architectures the global data pointer is stored in a register. + ++------------+----------+ +| ARC | r25 | ++------------+----------+ +| ARM 32bit | r9 | ++------------+----------+ +| ARM 64bit | x18 | ++------------+----------+ +| M68000 | d7 | ++------------+----------+ +| MicroBlaze | r31 | ++------------+----------+ +| NDS32 | r10 | ++------------+----------+ +| Nios II | gp | ++------------+----------+ +| PowerPC | r2 | ++------------+----------+ +| RISC-V | gp (x3) | ++------------+----------+ +| SuperH | r13 | ++------------+----------+ + +The sandbox, x86, and Xtensa are notable exceptions. + +Clang for ARM does not support assigning a global register. When using Clang +gd is defined as an inline function using assembly code. This adds a few bytes +to the code size. + +Binaries called by U-Boot are not aware of the register usage and will not +conserve gd. UEFI binaries call the API provided by U-Boot and may return to +U-Boot. The value of gd has to be saved every time U-Boot is left and restored +whenever U-Boot is reentered. This is also relevant for the implementation of +function tracing. For setting the value of gd function set_gd() can be used. + +Global data structure +--------------------- + +.. kernel-doc:: include/asm-generic/global_data.h + :internal: diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 98a95ad434c..89e80eab945 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -9,4 +9,5 @@ Develop U-Boot coccinelle crash_dumps + global_data logging From 957a3e549314c3d9c587c91d0b582d73d3d00da7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Mon, 5 Oct 2020 09:57:29 +0300 Subject: [PATCH 17/20] treewide: Fix wrong CONFIG_IS_ENABLED() handling CONFIG_IS_ENABLED() takes the kconfig name without the CONFIG_ prefix, e.g. CONFIG_IS_ENABLED(CLK) for CONFIG_CLK. Some of these were being fixed every now and then, see: commit 71ba2cb0d678 ("board: stm32mp1: correct CONFIG_IS_ENABLED usage for LED") commit a5ada25e4213 ("rockchip: clk: fix wrong CONFIG_IS_ENABLED handling") commit 5daf6e56d36c ("common: console: Fix duplicated CONFIG in silent env callback") commit 48bfc31b6484 ("MIPS: bootm: Fix broken boot_env_legacy codepath") Fix all files found by `git grep "CONFIG_IS_ENABLED(CONFIG"` by running ':%s/CONFIG_IS_ENABLED(CONFIG_\(\w+\))/CONFIG_IS_ENABLED(\1)/g' in vim. Signed-off-by: Alper Nebi Yasak Reviewed-by: Simon Glass --- drivers/clk/rockchip/clk_rk3399.c | 2 +- drivers/spi/nxp_fspi.c | 10 +++++----- drivers/sysreset/sysreset_mpc83xx.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 22c373a623c..1ea41f3c5b2 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -1592,7 +1592,7 @@ static int rk3399_pmuclk_ofdata_to_platdata(struct udevice *dev) static int rk3399_pmuclk_bind(struct udevice *dev) { -#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP) +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) int ret; ret = offsetof(struct rk3399_pmucru, pmucru_softrst_con[0]); diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c index c507437f2e7..ebd94925e99 100644 --- a/drivers/spi/nxp_fspi.c +++ b/drivers/spi/nxp_fspi.c @@ -520,7 +520,7 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, fspi_writel(f, FSPI_LCKER_LOCK, f->iobase + FSPI_LCKCR); } -#if CONFIG_IS_ENABLED(CONFIG_CLK) +#if CONFIG_IS_ENABLED(CLK) static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f) { int ret; @@ -808,7 +808,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) int ret, i; u32 reg; -#if CONFIG_IS_ENABLED(CONFIG_CLK) +#if CONFIG_IS_ENABLED(CLK) /* disable and unprepare clock to avoid glitch pass to controller */ nxp_fspi_clk_disable_unprep(f); @@ -898,7 +898,7 @@ static int nxp_fspi_claim_bus(struct udevice *dev) static int nxp_fspi_set_speed(struct udevice *bus, uint speed) { -#if CONFIG_IS_ENABLED(CONFIG_CLK) +#if CONFIG_IS_ENABLED(CLK) struct nxp_fspi *f = dev_get_priv(bus); int ret; @@ -924,7 +924,7 @@ static int nxp_fspi_set_mode(struct udevice *bus, uint mode) static int nxp_fspi_ofdata_to_platdata(struct udevice *bus) { struct nxp_fspi *f = dev_get_priv(bus); -#if CONFIG_IS_ENABLED(CONFIG_CLK) +#if CONFIG_IS_ENABLED(CLK) int ret; #endif @@ -950,7 +950,7 @@ static int nxp_fspi_ofdata_to_platdata(struct udevice *bus) f->ahb_addr = map_physmem(ahb_addr, ahb_size, MAP_NOCACHE); f->memmap_phy_size = ahb_size; -#if CONFIG_IS_ENABLED(CONFIG_CLK) +#if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_name(bus, "fspi_en", &f->clk_en); if (ret) { dev_err(bus, "failed to get fspi_en clock\n"); diff --git a/drivers/sysreset/sysreset_mpc83xx.c b/drivers/sysreset/sysreset_mpc83xx.c index 456f006bc12..4e89971840f 100644 --- a/drivers/sysreset/sysreset_mpc83xx.c +++ b/drivers/sysreset/sysreset_mpc83xx.c @@ -106,7 +106,7 @@ static int print_83xx_arb_event(bool force, char *buf, int size) if (!force && !gd->arch.arbiter_event_address) return 0; - if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL)) { + if (CONFIG_IS_ENABLED(DISPLAY_AER_FULL)) { res = snprintf(buf, size, "Arbiter Event Status:\n" " %s: 0x%08lX\n" @@ -119,7 +119,7 @@ static int print_83xx_arb_event(bool force, char *buf, int size) "Master ID", mstr_id, master[mstr_id], "Transfer Size", tsize_val, tsize_bytes, "Transfer Type", ttype, transfer[ttype]); - } else if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { + } else if (CONFIG_IS_ENABLED(DISPLAY_AER_BRIEF)) { res = snprintf(buf, size, "Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n", gd->arch.arbiter_event_attributes, @@ -183,8 +183,8 @@ static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size) * TODO(mario.six@gdsys.cc): Move this into a dedicated * arbiter driver */ - if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL) || - CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { + if (CONFIG_IS_ENABLED(DISPLAY_AER_FULL) || + CONFIG_IS_ENABLED(DISPLAY_AER_BRIEF)) { /* * If there was a bus monitor reset event, we force the arbiter * event to be printed From b9cca2c57a7f3f51dc044030a2f1665e517edb51 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Mon, 5 Oct 2020 09:57:30 +0300 Subject: [PATCH 18/20] checkpatch.pl: Make CONFIG_IS_ENABLED(CONFIG_*) an error CONFIG_IS_ENABLED() takes the kconfig name without the CONFIG_ prefix, e.g. CONFIG_IS_ENABLED(CLK) for CONFIG_CLK. Make including the prefix an error in checkpatch.pl so calls in the wrong format aren't accidentally reintroduced. Signed-off-by: Alper Nebi Yasak Reviewed-by: Simon Glass --- scripts/checkpatch.pl | 6 ++++++ tools/patman/test_checkpatch.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 4bed2b0cdc7..4ed7e124c9a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2365,6 +2365,12 @@ sub u_boot_line { ERROR("DISABLE_FDT_OR_INITRD_RELOC", "fdt or initrd relocation disabled at boot time\n" . $herecurr); } + + # Do not use CONFIG_ prefix in CONFIG_IS_ENABLED() calls + if ($line =~ /^\+.*CONFIG_IS_ENABLED\(CONFIG_\w*\).*/) { + ERROR("CONFIG_IS_ENABLED_CONFIG", + "CONFIG_IS_ENABLED() takes values without the CONFIG_ prefix\n" . $herecurr); + } } sub process { diff --git a/tools/patman/test_checkpatch.py b/tools/patman/test_checkpatch.py index 792196e6896..f71c70fb13a 100644 --- a/tools/patman/test_checkpatch.py +++ b/tools/patman/test_checkpatch.py @@ -405,6 +405,12 @@ index 0000000..2234c87 pm.add_line('include/myfile.h', '#include ') self.checkSingleMessage(pm, 'BARRED_INCLUDE_IN_HDR', 'error') + def testConfigIsEnabledConfig(self): + """Test for accidental CONFIG_IS_ENABLED(CONFIG_*) calls""" + pm = PatchMaker() + pm.add_line('common/main.c', 'if (CONFIG_IS_ENABLED(CONFIG_CLK))') + self.checkSingleMessage(pm, 'CONFIG_IS_ENABLED_CONFIG', 'error') + if __name__ == "__main__": unittest.main() From c90778ad70e2cf0844f0b10f8aad5d8cac11177a Mon Sep 17 00:00:00 2001 From: Christian Gmeiner Date: Tue, 6 Oct 2020 16:08:35 +0200 Subject: [PATCH 19/20] net: e1000: add defaults for i210 TX/RX PBSIZE Set the defaults on probe for the packet buffer size registers for the i210. The TX/RX PBSIZE register of the i210 resets to its default value only at power-on - see Intel Ethernet Controller I210 Datasheet rev 3.5 chapter 8.3 'Internal Packet Buffer Size Registers'. If something (another driver, another OS, etc.) modifies this register from its default value, the e1000 driver doesn't function correctly. It detects a hang of the transmitter and continuously resets the adapter. Here we set this value to its default when resetting the i210 to resolve this issue. Signed-off-by: Christian Gmeiner --- drivers/net/e1000.c | 5 +++++ drivers/net/e1000.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 49be7667021..8e6c755f641 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -1644,6 +1644,11 @@ e1000_reset_hw(struct e1000_hw *hw) E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP); E1000_WRITE_FLUSH(hw); + if (hw->mac_type == e1000_igb) { + E1000_WRITE_REG(hw, RXPBS, I210_RXPBSIZE_DEFAULT); + E1000_WRITE_REG(hw, TXPBS, I210_TXPBSIZE_DEFAULT); + } + /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */ hw->tbi_compatibility_on = false; diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index 19ed4777d9a..072851ba31c 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -735,6 +735,7 @@ struct e1000_ffvt_entry { #define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ #define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ #define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ #define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ #define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ #define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */ @@ -745,6 +746,7 @@ struct e1000_ffvt_entry { #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */ #define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ #define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ #define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ @@ -2589,4 +2591,8 @@ struct e1000_hw { #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ + +#define I210_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */ +#define I210_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */ + #endif /* _E1000_HW_H_ */ From 40a3008632abd8bb393eefc212547456f2a5cb25 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 6 Oct 2020 17:56:59 +0200 Subject: [PATCH 20/20] doc: Sphinx.override_domain() deprecated Sphinx.override_domain() is deprecated since Sphinx 1.8 and removed in Sphinx 3. Use Sphinx.add_domain(, override=True) instead. Signed-off-by: Heinrich Schuchardt --- doc/sphinx/cdomain.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/sphinx/cdomain.py b/doc/sphinx/cdomain.py index cf13ff3a656..cbac8e608dc 100644 --- a/doc/sphinx/cdomain.py +++ b/doc/sphinx/cdomain.py @@ -48,7 +48,10 @@ major, minor, patch = sphinx.version_info[:3] def setup(app): - app.override_domain(CDomain) + if (major == 1 and minor < 8): + app.override_domain(CDomain) + else: + app.add_domain(CDomain, override=True) return dict( version = __version__,