From 42c64d1bc9d5d3c68f14b872ab71ec7d5fe97cbc Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 11 Feb 2020 12:41:23 -0500 Subject: sandbox: Update PCI nodes in dts files The way the PCI nodes are written today causes a number of warnings if we stop disabling some of the warnings we pass to DTC. As these warnings aren't disabled in current Linux Kernel builds, we should aim to not disable them here either, so rewrite these slightly. Update the driver model doc as well. Cc: Simon Glass Signed-off-by: Tom Rini --- doc/driver-model/pci-info.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'doc') diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst index 3c1b1adf07..8b9faa1066 100644 --- a/doc/driver-model/pci-info.rst +++ b/doc/driver-model/pci-info.rst @@ -12,10 +12,10 @@ Bus number 0 will need to be requested first, and the alias in the device tree file will point to the correct device:: aliases { - pci0 = &pci; + pci0 = &pcic; }; - pci: pci-controller { + pcic: pci@0 { compatible = "sandbox,pci"; ... }; @@ -138,7 +138,7 @@ be scanned as a PCI device, causing confusion. When this bus is scanned we will end up with something like this:: - `- * pci-controller @ 05c660c8, 0 + `- * pci@0 @ 05c660c8, 0 `- pci@1f,0 @ 05c661c8, 63488 `- emul@1f,0 @ 05c662c8 @@ -152,7 +152,7 @@ host controller node for this functionality to work. .. code-block:: none - pci1: pci-controller1 { + pci1: pci@1 { compatible = "sandbox,pci"; ... sandbox,dev-info = <0x08 0x00 0x1234 0x5678 @@ -166,6 +166,6 @@ fourth cells are PCI vendor ID and device ID respectively. When this bus is scanned we will end up with something like this:: - pci [ + ] pci_sandbo |-- pci-controller1 + pci [ + ] pci_sandbo |-- pci1 pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul -- cgit v1.2.3 From befadde0a24c3a726689745d5a00c8586adc9c84 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Feb 2020 21:48:16 +0100 Subject: log: syslog driver Provide a log driver that broadcasts RFC 3164 messages to syslog servers. rsyslog is one implementation of such a server. The messages are sent to the local broadcast address 255.255.255.255 on port 514. The environment variable log_hostname can be used to provide the HOSTNAME field for the messages. The optional TIMESTAMP field of RFC 3164 is not provided. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- MAINTAINERS | 2 +- common/Kconfig | 7 ++++ common/Makefile | 1 + common/log_syslog.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/README.log | 3 ++ 5 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 common/log_syslog.c (limited to 'doc') diff --git a/MAINTAINERS b/MAINTAINERS index d8d420f84f..0bafe5cabc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -654,7 +654,7 @@ LOGGING M: Simon Glass S: Maintained T: git https://gitlab.denx.de/u-boot/u-boot.git -F: common/log.c +F: common/log* F: cmd/log.c F: test/log/log_test.c F: test/py/tests/test_log.py diff --git a/common/Kconfig b/common/Kconfig index 40da8fa7a3..ee4f748c32 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -775,6 +775,13 @@ config TPL_LOG_CONSOLE log message is shown - other details like level, category, file and line number are omitted. +config LOG_SYSLOG + bool "Log output to syslog server" + depends on LOG && NET + help + Enables a log driver which broadcasts log records via UDP port 514 + to syslog servers. + config LOG_TEST bool "Provide a test for logging" depends on LOG && UNIT_TEST diff --git a/common/Makefile b/common/Makefile index 702f2396cf..d84e10ba99 100644 --- a/common/Makefile +++ b/common/Makefile @@ -132,6 +132,7 @@ obj-$(CONFIG_DFU_OVER_USB) += dfu.o obj-y += command.o obj-$(CONFIG_$(SPL_TPL_)LOG) += log.o obj-$(CONFIG_$(SPL_TPL_)LOG_CONSOLE) += log_console.o +obj-$(CONFIG_$(SPL_TPL_)LOG_SYSLOG) += log_syslog.o obj-y += s_record.o obj-$(CONFIG_CMD_LOADB) += xyzModem.o obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o diff --git a/common/log_syslog.c b/common/log_syslog.c new file mode 100644 index 0000000000..5e3e20e8a4 --- /dev/null +++ b/common/log_syslog.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Log to syslog. + * + * Copyright (c) 2020, Heinrich Schuchardt + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define BUFFER_SIZE 480 + +static void append(char **buf, char *buf_end, const char *fmt, ...) +{ + va_list args; + size_t size = buf_end - *buf; + + va_start(args, fmt); + vsnprintf(*buf, size, fmt, args); + va_end(args); + *buf += strlen(*buf); +} + +static int log_syslog_emit(struct log_device *ldev, struct log_rec *rec) +{ + int ret; + int fmt = gd->log_fmt; + char msg[BUFFER_SIZE]; + char *msg_end = msg + BUFFER_SIZE; + char *ptr = msg; + char *iphdr; + char *log_msg; + int eth_hdr_size; + struct in_addr bcast_ip; + static int processing_msg; + unsigned int log_level; + char *log_hostname; + + /* Fend off messages from the network stack while writing a message */ + if (processing_msg) + return 0; + + processing_msg = 1; + + /* Setup packet buffers */ + net_init(); + /* Disable hardware and put it into the reset state */ + eth_halt(); + /* Set current device according to environment variables */ + eth_set_current(); + /* Get hardware ready for send and receive operations */ + ret = eth_init(); + if (ret < 0) { + eth_halt(); + goto out; + } + + memset(msg, 0, BUFFER_SIZE); + + /* Set ethernet header */ + eth_hdr_size = net_set_ether((uchar *)ptr, net_bcast_ethaddr, PROT_IP); + ptr += eth_hdr_size; + iphdr = ptr; + ptr += IP_UDP_HDR_SIZE; + log_msg = ptr; + + /* + * The syslog log levels defined in RFC 5424 match the U-Boot ones up to + * level 7 (debug). + */ + log_level = rec->level; + if (log_level > 7) + log_level = 7; + /* Leave high bits as 0 to write a 'kernel message' */ + + /* Write log message to buffer */ + append(&ptr, msg_end, "<%u>", log_level); + log_hostname = env_get("log_hostname"); + if (log_hostname) + append(&ptr, msg_end, "%s ", log_hostname); + append(&ptr, msg_end, "uboot: "); + if (fmt & (1 << LOGF_LEVEL)) + append(&ptr, msg_end, "%s.", + log_get_level_name(rec->level)); + if (fmt & (1 << LOGF_CAT)) + append(&ptr, msg_end, "%s,", + log_get_cat_name(rec->cat)); + if (fmt & (1 << LOGF_FILE)) + append(&ptr, msg_end, "%s:", rec->file); + if (fmt & (1 << LOGF_LINE)) + append(&ptr, msg_end, "%d-", rec->line); + if (fmt & (1 << LOGF_FUNC)) + append(&ptr, msg_end, "%s()", rec->func); + if (fmt & (1 << LOGF_MSG)) + append(&ptr, msg_end, "%s%s", + fmt != (1 << LOGF_MSG) ? " " : "", rec->msg); + /* Consider trailing 0x00 */ + ptr++; + + debug("log message: '%s'\n", log_msg); + + /* Broadcast message */ + bcast_ip.s_addr = 0xFFFFFFFFL; + net_set_udp_header((uchar *)iphdr, bcast_ip, 514, 514, ptr - log_msg); + net_send_packet((uchar *)msg, ptr - msg); + +out: + processing_msg = 0; + return ret; +} + +LOG_DRIVER(syslog) = { + .name = "syslog", + .emit = log_syslog_emit, +}; diff --git a/doc/README.log b/doc/README.log index 19856d43da..1057981f45 100644 --- a/doc/README.log +++ b/doc/README.log @@ -147,7 +147,10 @@ several possible determinations for logging information, all of which can be enabled or disabled independently: console - goes to stdout + syslog - broadcast RFC 3164 messages to syslog servers on UDP port 514 +The syslog driver sends the value of environmental variable 'log_hostname' as +HOSTNAME if available. Log format ---------- -- cgit v1.2.3 From da2fa6d86a1f7aea590e7cbcd234718bcfd435b6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Feb 2020 20:18:54 +0100 Subject: doc: driver-model: there is no UCLASS_ETHERNET %s/UCLASS_ETHERNET/UCLASS_ETH/g Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- doc/driver-model/design.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/driver-model/design.rst b/doc/driver-model/design.rst index 5247ecc276..e37b51bf43 100644 --- a/doc/driver-model/design.rst +++ b/doc/driver-model/design.rst @@ -579,7 +579,7 @@ a USB bus with several devices attached to it, each from a different (made up) uclass:: xhci_usb (UCLASS_USB) - eth (UCLASS_ETHERNET) + eth (UCLASS_ETH) camera (UCLASS_CAMERA) flash (UCLASS_FLASH_STORAGE) -- cgit v1.2.3 From b0dcc87106464c3fc019e3771378a092fd32ebdb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 5 Apr 2020 15:38:19 -0600 Subject: dm: core: Read parent ofdata before children At present a device can read its ofdata before its parent has done the same. This can cause problems in the case where the parent has a 'ranges' property, thus affecting the operation of dev_read_addr(), for example. We already probe parent devices before children so it does not seem to be a large step to do the same with ofdata. Make the change and update the documentation in this area. Signed-off-by: Simon Glass Tested-by: Ley Foon Tan --- doc/driver-model/design.rst | 94 +++++++++++++++++++++++++++++++++------------ drivers/core/device.c | 16 ++++++++ test/dm/test-fdt.c | 25 ++++++++++++ 3 files changed, 111 insertions(+), 24 deletions(-) (limited to 'doc') diff --git a/doc/driver-model/design.rst b/doc/driver-model/design.rst index e37b51bf43..635effcef6 100644 --- a/doc/driver-model/design.rst +++ b/doc/driver-model/design.rst @@ -683,11 +683,17 @@ probe/remove which is independent of bind/unbind. This is partly because in U-Boot it may be expensive to probe devices and we don't want to do it until they are needed, or perhaps until after relocation. -Activation/probe -^^^^^^^^^^^^^^^^ +Reading ofdata +^^^^^^^^^^^^^^ + +Most devices have data in the device tree which they can read to find out the +base address of hardware registers and parameters relating to driver +operation. This is called 'ofdata' (Open-Firmware data). -When a device needs to be used, U-Boot activates it, by following these -steps (see device_probe()): +The device's_ofdata_to_platdata() implemnents allocation and reading of +platdata. A parent's ofdata is always read before a child. + +The steps are: 1. If priv_auto_alloc_size is non-zero, then the device-private space is allocated for the device and zeroed. It will be accessible as @@ -713,32 +719,72 @@ steps (see device_probe()): space. The controller can hold information about the USB state of each of its children. - 5. All parent devices are probed. It is not possible to activate a device + 5. If the driver provides an ofdata_to_platdata() method, then this is + called to convert the device tree data into platform data. This should + do various calls like dev_read_u32(dev, ...) to access the node and store + the resulting information into dev->platdata. After this point, the device + works the same way whether it was bound using a device tree node or + U_BOOT_DEVICE() structure. In either case, the platform data is now stored + in the platdata structure. Typically you will use the + platdata_auto_alloc_size feature to specify the size of the platform data + structure, and U-Boot will automatically allocate and zero it for you before + entry to ofdata_to_platdata(). But if not, you can allocate it yourself in + ofdata_to_platdata(). Note that it is preferable to do all the device tree + decoding in ofdata_to_platdata() rather than in probe(). (Apart from the + ugliness of mixing configuration and run-time data, one day it is possible + that U-Boot will cache platform data for devices which are regularly + de/activated). + + 5. The device is marked 'platdata valid'. + +Note that ofdata reading is always done (for a child and all its parents) +before probing starts. Thus devices go through two distinct states when +probing: reading platform data and actually touching the hardware to bring +the device up. + +Having probing separate from ofdata-reading helps deal with of-platdata, where +the probe() method is common to both DT/of-platdata operation, but the +ofdata_to_platdata() method is implemented differently. + +Another case has come up where this separate is useful. Generation of ACPI +tables uses the of-platdata but does not want to probe the device. Probing +would cause U-Boot to violate one of its design principles, viz that it +should only probe devices that are used. For ACPI we want to generate a +table for each device, even if U-Boot does not use it. In fact it may not +even be possible to probe the device - e.g. an SD card which is not +present will cause an error on probe, yet we still must tell Linux about +the SD card connector in case it is used while Linux is running. + +It is important that the ofdata_to_platdata() method does not actually probe +the device itself. However there are cases where other devices must be probed +in the ofdata_to_platdata() method. An example is where a device requires a +GPIO for it to operate. To select a GPIO obviously requires that the GPIO +device is probed. This is OK when used by common, core devices such as GPIO, +clock, interrupts, reset and the like. + +If your device relies on its parent setting up a suitable address space, so +that dev_read_addr() works correctly, then make sure that the parent device +has its setup code in ofdata_to_platdata(). If it has it in the probe method, +then you cannot call dev_read_addr() from the child device's +ofdata_to_platdata() method. Move it to probe() instead. Buses like PCI can +fall afoul of this rule. + +Activation/probe +^^^^^^^^^^^^^^^^ + +When a device needs to be used, U-Boot activates it, by first reading ofdata +as above and then following these steps (see device_probe()): + + 1. All parent devices are probed. It is not possible to activate a device unless its predecessors (all the way up to the root device) are activated. This means (for example) that an I2C driver will require that its bus be activated. - 6. The device's sequence number is assigned, either the requested one + 2. The device's sequence number is assigned, either the requested one (assuming no conflicts) or the next available one if there is a conflict or nothing particular is requested. - 7. If the driver provides an ofdata_to_platdata() method, then this is - called to convert the device tree data into platform data. This should - do various calls like fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), ...) - to access the node and store the resulting information into dev->platdata. - After this point, the device works the same way whether it was bound - using a device tree node or U_BOOT_DEVICE() structure. In either case, - the platform data is now stored in the platdata structure. Typically you - will use the platdata_auto_alloc_size feature to specify the size of the - platform data structure, and U-Boot will automatically allocate and zero - it for you before entry to ofdata_to_platdata(). But if not, you can - allocate it yourself in ofdata_to_platdata(). Note that it is preferable - to do all the device tree decoding in ofdata_to_platdata() rather than - in probe(). (Apart from the ugliness of mixing configuration and run-time - data, one day it is possible that U-Boot will cache platform data for - devices which are regularly de/activated). - - 8. The device's probe() method is called. This should do anything that + 4. The device's probe() method is called. This should do anything that is required by the device to get it going. This could include checking that the hardware is actually present, setting up clocks for the hardware and setting up hardware registers to initial values. The code @@ -753,7 +799,7 @@ steps (see device_probe()): allocate the priv space here yourself. The same applies also to platdata_auto_alloc_size. Remember to free them in the remove() method. - 9. The device is marked 'activated' + 5. The device is marked 'activated' 10. The uclass's post_probe() method is called, if one exists. This may cause the uclass to do some housekeeping to record the device as diff --git a/drivers/core/device.c b/drivers/core/device.c index 534cfa7314..0157bb1fe0 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -321,6 +321,22 @@ int device_ofdata_to_platdata(struct udevice *dev) if (dev->flags & DM_FLAG_PLATDATA_VALID) return 0; + /* Ensure all parents have ofdata */ + if (dev->parent) { + ret = device_ofdata_to_platdata(dev->parent); + if (ret) + goto fail; + + /* + * The device might have already been probed during + * the call to device_probe() on its parent device + * (e.g. PCI bridge devices). Test the flags again + * so that we don't mess up the device. + */ + if (dev->flags & DM_FLAG_PLATDATA_VALID) + return 0; + } + drv = dev->driver; assert(drv); diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 7c9472a358..a56275aef9 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -992,3 +992,28 @@ static int dm_test_first_child_probe(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_first_child_probe, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test that ofdata is read for parents before children */ +static int dm_test_ofdata_order(struct unit_test_state *uts) +{ + struct udevice *bus, *dev; + + ut_assertok(uclass_find_first_device(UCLASS_I2C, &bus)); + ut_assertnonnull(bus); + ut_assert(!(bus->flags & DM_FLAG_PLATDATA_VALID)); + + ut_assertok(device_find_first_child(bus, &dev)); + ut_assertnonnull(dev); + ut_assert(!(dev->flags & DM_FLAG_PLATDATA_VALID)); + + /* read the child's ofdata which should cause the parent's to be read */ + ut_assertok(device_ofdata_to_platdata(dev)); + ut_assert(dev->flags & DM_FLAG_PLATDATA_VALID); + ut_assert(bus->flags & DM_FLAG_PLATDATA_VALID); + + ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); + ut_assert(!(bus->flags & DM_FLAG_ACTIVATED)); + + return 0; +} +DM_TEST(dm_test_ofdata_order, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- cgit v1.2.3