summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig86
-rw-r--r--common/Makefile2
-rw-r--r--common/board_f.c23
-rw-r--r--common/board_r.c27
-rw-r--r--common/console.c7
-rw-r--r--common/image.c9
-rw-r--r--common/log.c245
-rw-r--r--common/log_console.c23
-rw-r--r--common/stdio.c6
-rw-r--r--common/usb_hub.c4
10 files changed, 372 insertions, 60 deletions
diff --git a/common/Kconfig b/common/Kconfig
index c50d6ebb2ad..4da095a4fd7 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -420,6 +420,92 @@ config SYS_STDIO_DEREGISTER
endmenu
+menu "Logging"
+
+config LOG
+ bool "Enable logging support"
+ help
+ This enables support for logging of status and debug messages. These
+ can be displayed on the console, recorded in a memory buffer, or
+ discarded if not needed. Logging supports various categories and
+ levels of severity.
+
+config SPL_LOG
+ bool "Enable logging support in SPL"
+ help
+ This enables support for logging of status and debug messages. These
+ can be displayed on the console, recorded in a memory buffer, or
+ discarded if not needed. Logging supports various categories and
+ levels of severity.
+
+config LOG_MAX_LEVEL
+ int "Maximum log level to record"
+ depends on LOG
+ default 5
+ help
+ This selects the maximum log level that will be recorded. Any value
+ higher than this will be ignored. If possible log statements below
+ this level will be discarded at build time. Levels:
+
+ 0 - panic
+ 1 - critical
+ 2 - error
+ 3 - warning
+ 4 - note
+ 5 - info
+ 6 - detail
+ 7 - debug
+
+config SPL_LOG_MAX_LEVEL
+ int "Maximum log level to record in SPL"
+ depends on SPL_LOG
+ default 3
+ help
+ This selects the maximum log level that will be recorded. Any value
+ higher than this will be ignored. If possible log statements below
+ this level will be discarded at build time. Levels:
+
+ 0 - panic
+ 1 - critical
+ 2 - error
+ 3 - warning
+ 4 - note
+ 5 - info
+ 6 - detail
+ 7 - debug
+
+config LOG_CONSOLE
+ bool "Allow log output to the console"
+ depends on LOG
+ default y
+ help
+ Enables a log driver which writes log records to the console.
+ Generally the console is the serial port or LCD display. Only the
+ log message is shown - other details like level, category, file and
+ line number are omitted.
+
+config LOG_SPL_CONSOLE
+ bool "Allow log output to the console in SPL"
+ depends on LOG_SPL
+ default y
+ help
+ Enables a log driver which writes log records to the console.
+ Generally the console is the serial port or LCD display. Only the
+ log message is shown - other details like level, category, file and
+ line number are omitted.
+
+config LOG_TEST
+ bool "Provide a test for logging"
+ depends on LOG
+ default y if SANDBOX
+ help
+ This enables a 'log test' command to test logging. It is normally
+ executed from a pytest and simply outputs logging information
+ in various different ways to test that the logging system works
+ correctly with varoius settings.
+
+endmenu
+
config DEFAULT_FDT_FILE
string "Default fdt file"
help
diff --git a/common/Makefile b/common/Makefile
index cec506fe3e1..14166209fe4 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -128,5 +128,7 @@ obj-y += cli.o
obj-$(CONFIG_FSL_DDR_INTERACTIVE) += cli_simple.o cli_readline.o
obj-$(CONFIG_CMD_DFU) += dfu.o
obj-y += command.o
+obj-$(CONFIG_$(SPL_)LOG) += log.o
+obj-$(CONFIG_$(SPL_)LOG_CONSOLE) += log_console.o
obj-y += s_record.o
obj-y += xyzModem.o
diff --git a/common/board_f.c b/common/board_f.c
index 9220815441e..e46eceda7d0 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -19,7 +19,6 @@
#include <i2c.h>
#include <initcall.h>
#include <init_helpers.h>
-#include <logbuff.h>
#include <malloc.h>
#include <mapmem.h>
#include <os.h>
@@ -296,20 +295,6 @@ static int setup_dest_addr(void)
return 0;
}
-#if defined(CONFIG_LOGBUFFER)
-static int reserve_logbuffer(void)
-{
-#ifndef CONFIG_ALT_LB_ADDR
- /* reserve kernel log buffer */
- gd->relocaddr -= LOGBUFF_RESERVE;
- debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
- gd->relocaddr);
-#endif
-
- return 0;
-}
-#endif
-
#ifdef CONFIG_PRAM
/* reserve protected RAM */
static int reserve_pram(void)
@@ -766,6 +751,7 @@ static const init_fnc_t init_sequence_f[] = {
trace_early_init,
#endif
initf_malloc,
+ log_init,
initf_bootstage, /* uses its own timer, so does not need DM */
initf_console_record,
#if defined(CONFIG_HAVE_FSP)
@@ -846,9 +832,6 @@ static const init_fnc_t init_sequence_f[] = {
* - board info struct
*/
setup_dest_addr,
-#if defined(CONFIG_LOGBUFFER)
- reserve_logbuffer,
-#endif
#ifdef CONFIG_PRAM
reserve_pram,
#endif
@@ -950,8 +933,10 @@ void board_init_f_r(void)
* The pre-relocation drivers may be using memory that has now gone
* away. Mark serial as unavailable - this will fall back to the debug
* UART if available.
+ *
+ * Do the same with log drivers since the memory may not be available.
*/
- gd->flags &= ~GD_FLG_SERIAL_READY;
+ gd->flags &= ~(GD_FLG_SERIAL_READY | GD_FLG_LOG_READY);
#ifdef CONFIG_TIMER
gd->timer = NULL;
#endif
diff --git a/common/board_r.c b/common/board_r.c
index a3b9bfb8ee4..09167c13cc8 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -30,7 +30,6 @@
#if defined(CONFIG_CMD_KGDB)
#include <kgdb.h>
#endif
-#include <logbuff.h>
#include <malloc.h>
#include <mapmem.h>
#ifdef CONFIG_BITBANGMII
@@ -200,19 +199,6 @@ static int initr_addr_map(void)
}
#endif
-#ifdef CONFIG_LOGBUFFER
-unsigned long logbuffer_base(void)
-{
- return gd->ram_top - LOGBUFF_LEN;
-}
-
-static int initr_logbuffer(void)
-{
- logbuff_init_ptrs();
- return 0;
-}
-#endif
-
#ifdef CONFIG_POST
static int initr_post_backlog(void)
{
@@ -628,7 +614,7 @@ static int initr_ide(void)
}
#endif
-#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
+#if defined(CONFIG_PRAM)
/*
* Export available size of memory for Linux, taking into account the
* protected RAM at top of memory
@@ -641,10 +627,6 @@ int initr_mem(void)
# ifdef CONFIG_PRAM
pram = env_get_ulong("pram", 10, CONFIG_PRAM);
# endif
-# if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
- /* Also take the logbuffer into account (pram is in kB) */
- pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
-# endif
sprintf(memsz, "%ldk", (long int) ((gd->ram_size / 1024) - pram));
env_set("mem", memsz);
@@ -709,6 +691,7 @@ static init_fnc_t init_sequence_r[] = {
#endif
initr_barrier,
initr_malloc,
+ log_init,
initr_bootstage, /* Needs malloc() but has its own timer */
initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORY
@@ -753,9 +736,6 @@ static init_fnc_t init_sequence_r[] = {
board_early_init_r,
#endif
INIT_FUNC_WATCHDOG_RESET
-#ifdef CONFIG_LOGBUFFER
- initr_logbuffer,
-#endif
#ifdef CONFIG_POST
initr_post_backlog,
#endif
@@ -877,7 +857,7 @@ static init_fnc_t init_sequence_r[] = {
INIT_FUNC_WATCHDOG_RESET
initr_bedbug,
#endif
-#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
+#if defined(CONFIG_PRAM)
initr_mem,
#endif
#ifdef CONFIG_PS2KBD
@@ -905,6 +885,7 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
gd = new_gd;
#endif
+ gd->flags &= ~GD_FLG_LOG_READY;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
diff --git a/common/console.c b/common/console.c
index d763f2c6846..0e0295514b2 100644
--- a/common/console.c
+++ b/common/console.c
@@ -489,6 +489,13 @@ static inline void print_pre_console_buffer(int flushpoint) {}
void putc(const char c)
{
+#ifdef CONFIG_SANDBOX
+ /* sandbox can send characters to stdout before it has a console */
+ if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+ os_putc(c);
+ return;
+ }
+#endif
#ifdef CONFIG_DEBUG_UART
/* if we don't have a console yet, use the debug UART */
if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
diff --git a/common/image.c b/common/image.c
index 4ec4744589f..4bcf6b3128a 100644
--- a/common/image.c
+++ b/common/image.c
@@ -15,10 +15,6 @@
#include <status_led.h>
#endif
-#ifdef CONFIG_LOGBUFFER
-#include <logbuff.h>
-#endif
-
#include <rtc.h>
#include <environment.h>
@@ -1154,11 +1150,6 @@ int boot_ramdisk_high(struct lmb *lmb, ulong rd_data, ulong rd_len,
}
-#ifdef CONFIG_LOGBUFFER
- /* Prevent initrd from overwriting logbuffer */
- lmb_reserve(lmb, logbuffer_base() - LOGBUFF_OVERHEAD, LOGBUFF_RESERVE);
-#endif
-
debug("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
initrd_high, initrd_copy_to_ram);
diff --git a/common/log.c b/common/log.c
new file mode 100644
index 00000000000..45e46dd5209
--- /dev/null
+++ b/common/log.c
@@ -0,0 +1,245 @@
+/*
+ * Logging support
+ *
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <log.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct log_device *log_device_find_by_name(const char *drv_name)
+{
+ struct log_device *ldev;
+
+ list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ if (!strcmp(drv_name, ldev->drv->name))
+ return ldev;
+ }
+
+ return NULL;
+}
+
+/**
+ * log_has_cat() - check if a log category exists within a list
+ *
+ * @cat_list: List of categories to check, at most LOGF_MAX_CATEGORIES entries
+ * long, terminated by LC_END if fewer
+ * @cat: Category to search for
+ * @return true if @cat is in @cat_list, else false
+ */
+static bool log_has_cat(enum log_category_t cat_list[], enum log_category_t cat)
+{
+ int i;
+
+ for (i = 0; i < LOGF_MAX_CATEGORIES && cat_list[i] != LOGC_END; i++) {
+ if (cat_list[i] == cat)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * log_has_file() - check if a file is with a list
+ *
+ * @file_list: List of files to check, separated by comma
+ * @file: File to check for. This string is matched against the end of each
+ * file in the list, i.e. ignoring any preceding path. The list is
+ * intended to consist of relative pathnames, e.g. common/main.c,cmd/log.c
+ * @return true if @file is in @file_list, else false
+ */
+static bool log_has_file(const char *file_list, const char *file)
+{
+ int file_len = strlen(file);
+ const char *s, *p;
+ int substr_len;
+
+ for (s = file_list; *s; s = p + (*p != '\0')) {
+ p = strchrnul(s, ',');
+ substr_len = p - s;
+ if (file_len >= substr_len &&
+ !strncmp(file + file_len - substr_len, s, substr_len))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * log_passes_filters() - check if a log record passes the filters for a device
+ *
+ * @ldev: Log device to check
+ * @rec: Log record to check
+ * @return true if @rec is not blocked by the filters in @ldev, false if it is
+ */
+static bool log_passes_filters(struct log_device *ldev, struct log_rec *rec)
+{
+ struct log_filter *filt;
+
+ /* If there are no filters, filter on the default log level */
+ if (list_empty(&ldev->filter_head)) {
+ if (rec->level > gd->default_log_level)
+ return false;
+ return true;
+ }
+
+ list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
+ if (rec->level > filt->max_level)
+ continue;
+ if ((filt->flags & LOGFF_HAS_CAT) &&
+ !log_has_cat(filt->cat_list, rec->cat))
+ continue;
+ if (filt->file_list &&
+ !log_has_file(filt->file_list, rec->file))
+ continue;
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * log_dispatch() - Send a log record to all log devices for processing
+ *
+ * The log record is sent to each log device in turn, skipping those which have
+ * filters which block the record
+ *
+ * @rec: Log record to dispatch
+ * @return 0 (meaning success)
+ */
+static int log_dispatch(struct log_rec *rec)
+{
+ struct log_device *ldev;
+
+ list_for_each_entry(ldev, &gd->log_head, sibling_node) {
+ if (log_passes_filters(ldev, rec))
+ ldev->drv->emit(ldev, rec);
+ }
+
+ return 0;
+}
+
+int _log(enum log_category_t cat, enum log_level_t level, const char *file,
+ int line, const char *func, const char *fmt, ...)
+{
+ char buf[CONFIG_SYS_CBSIZE];
+ struct log_rec rec;
+ va_list args;
+
+ rec.cat = cat;
+ rec.level = level;
+ rec.file = file;
+ rec.line = line;
+ rec.func = func;
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ rec.msg = buf;
+ if (!gd || !(gd->flags & GD_FLG_LOG_READY)) {
+ if (gd)
+ gd->log_drop_count++;
+ return -ENOSYS;
+ }
+ log_dispatch(&rec);
+
+ return 0;
+}
+
+int log_add_filter(const char *drv_name, enum log_category_t cat_list[],
+ enum log_level_t max_level, const char *file_list)
+{
+ struct log_filter *filt;
+ struct log_device *ldev;
+ int i;
+
+ ldev = log_device_find_by_name(drv_name);
+ if (!ldev)
+ return -ENOENT;
+ filt = (struct log_filter *)calloc(1, sizeof(*filt));
+ if (!filt)
+ return -ENOMEM;
+
+ if (cat_list) {
+ filt->flags |= LOGFF_HAS_CAT;
+ for (i = 0; ; i++) {
+ if (i == ARRAY_SIZE(filt->cat_list))
+ return -ENOSPC;
+ filt->cat_list[i] = cat_list[i];
+ if (cat_list[i] == LOGC_END)
+ break;
+ }
+ }
+ filt->max_level = max_level;
+ if (file_list) {
+ filt->file_list = strdup(file_list);
+ if (!filt->file_list)
+ goto nomem;
+ }
+ filt->filter_num = ldev->next_filter_num++;
+ list_add_tail(&filt->sibling_node, &ldev->filter_head);
+
+ return filt->filter_num;
+
+nomem:
+ free(filt);
+ return -ENOMEM;
+}
+
+int log_remove_filter(const char *drv_name, int filter_num)
+{
+ struct log_filter *filt;
+ struct log_device *ldev;
+
+ ldev = log_device_find_by_name(drv_name);
+ if (!ldev)
+ return -ENOENT;
+
+ list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
+ if (filt->filter_num == filter_num) {
+ list_del(&filt->sibling_node);
+ free(filt);
+
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int log_init(void)
+{
+ struct log_driver *drv = ll_entry_start(struct log_driver, log_driver);
+ const int count = ll_entry_count(struct log_driver, log_driver);
+ struct log_driver *end = drv + count;
+
+ /*
+ * We cannot add runtime data to the driver since it is likely stored
+ * in rodata. Instead, set up a 'device' corresponding to each driver.
+ * We only support having a single device.
+ */
+ INIT_LIST_HEAD((struct list_head *)&gd->log_head);
+ while (drv < end) {
+ struct log_device *ldev;
+
+ ldev = calloc(1, sizeof(*ldev));
+ if (!ldev) {
+ debug("%s: Cannot allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&ldev->filter_head);
+ ldev->drv = drv;
+ list_add_tail(&ldev->sibling_node,
+ (struct list_head *)&gd->log_head);
+ drv++;
+ }
+ gd->flags |= GD_FLG_LOG_READY;
+ gd->default_log_level = LOGL_INFO;
+
+ return 0;
+}
diff --git a/common/log_console.c b/common/log_console.c
new file mode 100644
index 00000000000..5af73bd8be4
--- /dev/null
+++ b/common/log_console.c
@@ -0,0 +1,23 @@
+/*
+ * Logging support
+ *
+ * Copyright (c) 2017 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <log.h>
+
+static int log_console_emit(struct log_device *ldev, struct log_rec *rec)
+{
+ puts(rec->msg);
+
+ return 0;
+}
+
+LOG_DRIVER(console) = {
+ .name = "console",
+ .emit = log_console_emit,
+};
diff --git a/common/stdio.c b/common/stdio.c
index ee4f0bda9ea..2e5143a0255 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -17,9 +17,6 @@
#include <malloc.h>
#include <stdio_dev.h>
#include <serial.h>
-#ifdef CONFIG_LOGBUFFER
-#include <logbuff.h>
-#endif
#if defined(CONFIG_SYS_I2C)
#include <i2c.h>
@@ -381,9 +378,6 @@ int stdio_add_devices(void)
#if defined(CONFIG_KEYBOARD) && !defined(CONFIG_DM_KEYBOARD)
drv_keyboard_init ();
#endif
-#ifdef CONFIG_LOGBUFFER
- drv_logbuff_init ();
-#endif
drv_system_init ();
serial_stdio_init ();
#ifdef CONFIG_USB_TTY
diff --git a/common/usb_hub.c b/common/usb_hub.c
index 024dadb2774..b46dfa16ccf 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -625,7 +625,7 @@ static int usb_hub_configure(struct usb_device *dev)
short hubCharacteristics;
struct usb_hub_descriptor *descriptor;
struct usb_hub_device *hub;
- __maybe_unused struct usb_hub_status *hubsts;
+ struct usb_hub_status *hubsts;
int ret;
hub = usb_get_hub_device(dev);
@@ -779,9 +779,7 @@ static int usb_hub_configure(struct usb_device *dev)
return ret;
}
-#ifdef DEBUG
hubsts = (struct usb_hub_status *)buffer;
-#endif
debug("get_hub_status returned status %X, change %X\n",
le16_to_cpu(hubsts->wHubStatus),