When working on a Linux system, it can be convenient to use the kernel events tracing mechanism, (described in details in Documentation/trace/events.txt in the Linux kernel sources).
We will only focus on a very simple use case here.
Listing possible event traces
All traceable events are listed under the /sys/kernel/debug/tracing/events/ hierarchy of directories
Access to kernel event tracing is reserved to privileged users, so all instructions below need to be executed with root privileges
To clear the filter for an event, write a '0' to the event's filter
file.
To clear the filters for all events in a subsystem, write a '0' to the
subsystem's filter file.
Following event traces during execution
# cat /sys/kernel/debug/tracing/trace_pipe &
Following this, any enabled event will be traced into the console
Event tracing maynot work with kernel versions < 4.9, due to a limitation in the event tracing mechanism. Functions with event tracing located too far way from the start of a module may not get their events traced. A workaround consists in moving source code files using event tracing at the beginning of the list of object files used to link the module. This is corrected in higher kernel releases.
Before using a Wi-Fi part connected to the SDIO bus of a Linux system, it is necessary that the system detects the HW on the bus.
When detection succeeds, the kernel has retrieved the VID/PID for the device.
Looking for a driver matching the VID/PID is only possible if the VID/PID has been retrieved from the device.
As as consequence, device tree changes related to your device have no effect until SDIO detection is OK.
Linux systems will try to detect SDIO parts on the bus at boot, and every time the mmc bus is bound. Unbinding/binding the mmc bus is what we will use to trace mmc messages related to SDIO detection.
SDIO Detection message
The following message should be visible in dmesg once boot is complete:
mmcX new high speed SDIO card at address 0001
one-line check:
$ dmesg | grep 'new high speed SDIO'
Until this message is present in dmesg
Any device tree change related to your part is not used by the kernel
it is useless to try to load the driver
If this message is not found, it is necessary to debug SDIO detection, going through the following steps:
Retrieving the current device tree
Checking which mmc bus is used for SDIO
Making sure SDIO detection is enabled in the device tree
Checking the mmc bus commands during the SDIO detection phase
Checking the SDIO detection result
These steps are detailed below.
Keep in mind that any change to the device tree is only taken into account on the next reboot, so changing the device tree means rebooting!
If this returns an empty line, SDIO detection is not even triggered. Refer to your system documentation to know how to add SDIO to the device tree.
Check the SDIO pins allocation in the 'sdio_pins' node to make sure they match your HW
Checking which mmc bus is used for SDIO
one-line check (SDIO mmc bus selection):
$ grep -E "mmc[0-2]|mmc@" device_tree.out
The result should contain:
mmc1 = "/soc/sdio@7e300000";
or (depending on the kernel, i.e. the device tree version)
mmc = "/soc/mmc@7e300000";
If this returns an empty line, SDIO is not connected to any mmc bus. Refer to your system documentation to know how to add SDIO to the device tree.
Checking the mmc bus commands during the SDIO detection phase
Until the above checks are ok, it is pointless trying to trace SDIO detection messages, since detection is not even triggered.
This is the trickiest part, since it involves tracking message normally issued at boot, when the system is attempting SDIO detection.
In reality, these are issued every time the mmc bus is bound to the system, so unbinding/binding the mmc bus will trigger a new detection attempt. We use this to avoid activating the traces at boot time, since this is not easy to do.
Preparing the kernel event traces (to be executed with root privileges): Activating mmc request traces:
NB: The attached SDIO_Detection_mmc_request_done_traces.txt file contains the typical traces.
Stopping mmc request traces (once the traces have been retrieved):
This step is necessary to stop tracing, which is otherwise still active. No additional traces are shown because SDIO traffic only uses CMD53 once detection is complete, and CMD53 are filtered out. It is better to stop tracing completely.
If detection is correct, the 'mmcX new high speed SDIO card at address 0001' message is present in dmesg.
Otherwise, check for errors related to the mmc item corresponding to your part.
SDIO pins used for the detection phase
The SDIO detection as shown above only uses SD_CMD and SD_CLK pins, and is generally performed with a 400kHz SD_CLK.
SD_DAT[3:0] are not used yet, so SDIO detection may succeed even though SD_DAT[3:0] are not properly routed.
Host stopping clock after CMD0
Some hosts will stop the SD-CLK clock right after issuing the CMD0 (MMC_GO_IDLE) command.
This is because the SDIO specification does not require a response to CMD0.
In this case, the SDIO detection flow will get interrupted after CMD0, and will not show CMD5, CMD52, etc.
To solve this, apply the patch described at the end of this article in 'Specifics of using a processor which stops the clock after CMD0'
Max SDIO speed too high
During the last steps of SDIO detection, the SoC sets the SDIO part to 'high-speed' mode on 4 data bits, then configures its own hardware to the maximum selected SDIO speed (controllable in the device tree) only at the very end of the SDIO detection, after a long series of about 26 CMD52 commands.
There is a SDIO speed limitation with BRD8022/BRD8023 due to the onboard switches. For this reason, we need to reduce the SDIO clock speed. 25 MHz is generally a good choice, given that choices are limited and vary depending on the platform.
In case there are issues related to the max clock speed, the last CMD52 commands will return with 'cmd_err=-110' (which means 'TIMEOUT'), and will be followed by a short burst of about 4 CMD55 commands.
Whenever the SDIO detection loop fails, it is repeated with a slower clock speed (400, 300, 200, 100 kHz, respectively), but is still ending with the max clock. If the max clock is too high, all 4 loops will eventually fail, therefore the traces will show 4 repeated patterns of:
In this case, check your device tree documentation to check how to reduce the maximum SDIO clock.
Checking the SDIO clock speed
sudo cat /sys/kernel/debug/mmc1/ios
Output:
clock: 50000000 Hz
actual clock: 25000000 Hz
vdd: 21 (3.3 ~ 3.4 V)
bus mode: 2 (push-pull)
chip select: 0 (don't care)
power mode: 2 (on)
bus width: 2 (4 bits)
timing spec: 2 (sd high-speed)
signal voltage: 0 (3.30 V)
driver type: 0 (driver type B)
Given the wide range of platforms and various methods to control the clock speed, checking SD_CLK frequency using an oscilloscope is recommended, to make sure the clock is set as expected (depending on the platform, clock speed options may be limited due to the use of small dividers).
Checking GPIO allocation
sudo cat /sys/kernel/debug/gpio
Output:
GPIOs 0-53, platform/3f200000.gpio, pinctrl-bcm2835:
gpio-12 ( |wakeup ) out lo
gpio-13 ( |reset ) out hi
GPIOs 100-101, platform/soc:virtgpio, brcmvirt-gpio, can sleep:
gpio-100 ( |? ) out lo
Check that wakeup and reset are properly allocated
SDIO Simplified Specification reference
When looking for reference information on SDIO detection please download the `SDIO Simplified Specification` PDF from https://www.sdcard.org/downloads/pls/index.html (Version 3.0 from July, 25, 2018 at the time of writing)
On pages 18/19, Figure 3.2 : Card Initialization Flow in SD mode (SDIO Aware Host) corresponds to our use case.
The following abstracts show the path WF200 should take during init.
If your startup traces don't follow this path, you probably have a HW issue, which could be related to
Missing power supplies
Missing GND
Improper startup detection on SDIO_DAT2/HIF_SEL at boot
Specifics of using a processor which stops the clock after CMD0
There is a specific way of handling the SD_CLK in some (i.e. OMAP, at least) processors, which are stopping SD_CLK a couple cycles after the end of the CMD0 command, without waiting for a response. Our part attempts to send a response to CMD0 and needs a valid clock to do so, so detection fails right after CMD0 (all commands report a timeout).
You need to apply the attached patch in your case, and add the 'mmc-reply-go-idle' property in your device tree:
From 971b651d019dd3efd7593a408ae8c5348d7daf54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= <jerome.pouiller@silabs.com>
Date: Tue, 19 Jun 2018 15:52:36 +0200
Subject: [PATCH] mmc: core: Add a quirk for cards that answer to GO_IDLE_STATE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some SDIO cards try to answer to GO_IDLE_STATE command (aka CMD0). In most
cases, this reply is just ignored by host. However, in some circumstances, it
may cause problems. For example, some hosts stop clock signal just after
command and does not allow card to reply.
Unfortunatly, CMD0 happens before card identification. So it is not possible to
use quirk member from struct mmc_card. Therefore, this patch add an option to
MMC hosts. Users have to add 'mmc-reply-go-idle' flag to MMC host in their DT.
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index ed23b9bedfdc..2cbd849ca462 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -48,6 +48,7 @@ Optional properties:
- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
- dsr: Value the card's (optional) Driver Stage Register (DSR) should be
programmed with. Valid range: [0 .. 0xffff].
+- mmc-reply-go-idle: expect reply on GO_IDLE_STATE command (CMD0)
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index da950c44204d..74d4335ef3ba 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
if (of_property_read_bool(np, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+ if (of_property_read_bool(np, "mmc-reply-go-idle"))
+ host->caps2 |= MMC_REPLY_GO_IDLE;
1. How often the callback function which was configured by zn_uart_register_rx_callback() API will ba called?
This is called for every time the MCU UART RX interrupt is invoked. For this reason, it is extremely important that is callback is lightweight. All heavy processing should be deferred to a thread context.
2. The number configuring by zn_event_enable_irq_events() is not clear.
This configures the number of events that can be queued from the IRQ context.
A configuration of 8 allows for events to be queued from the UART RX callback. i.e. zn_event_issue(my_handler, NULL, ZOS_EVENT_FLAG_FROM_IRQ) can be invoked up to 8 times (without my_handler executing in-between) before the API fails with an overflow error.
3. The meaning of flag used by zn_event_issue() is unclear.
This tells the API that the event_handler is being issued from an IRQ context.
Effectively, this flag tells the API to add the handler to the IRQ handler queue configured with zn_event_enable_irq_events().
4. The relation between the data size specified by zn_uart_receive_bytes() and timeout. If the timeout occurred, will the data be received until the timeout occurred? Or, will the whole data discarded? If the former is the case, can we know the actually received size by zn_uart_get_bytes_received()?
If zn_uart_receive_bytes() returns ZOS_TIMEOUT, then the amount of data read up until the timeout is returned.
zn_uart_get_bytes_received() contains the amount of read data returned in the buffer.
Wi-Fi Knowledge Base
KBA: WF200 Drivers and Firmware download
WF200 Drivers and Firmware are available from Github
For Linux applications
Driver: https://github.com/SiliconLabs/wfx-linux-driver
Firmware: https://github.com/SiliconLabs/wfx-firmware
Tools: https://github.com/SiliconLabs/wfx-linux-tools
https://github.com/SiliconLabs/wfx-common-tools
Files used by WF200 under Linux on Raspberry Pi (Debian)
For RTOS Applications
Driver & Firmware: https://github.com/SiliconLabs/wfx-fullMAC-driver
Tools: https://github.com/SiliconLabs/wfx-fullMAC-tools
https://github.com/SiliconLabs/wfx-common-tools
Linux Kernel events tracing
Linux Kernel events tracing
When working on a Linux system, it can be convenient to use the kernel events tracing mechanism, (described in details in Documentation/trace/events.txt in the Linux kernel sources).
We will only focus on a very simple use case here.
Listing possible event traces
All traceable events are listed under the /sys/kernel/debug/tracing/events/ hierarchy of directories
Typical result:
The first step is obviously to identify the events you want to trace within these.
For example, let's look at the mmc events structure:
The following hierarchy is present, with files and subfolders:
Each folder containing an enable file can be activated/de-activated by writing a 1 or a 0 to the corresponding enable file.
Each filter file corresponds to a list of filters applied to the corresponding event.
Each format file lists all possible parameter (which can be used in filters) and shows the print format for the corresponding trace.
Event traces format
format files list all possible parameters and show the print format:
Enabling/disabling event traces
To enable mmc/mmc_request_done:
To disable mmc/mmc_request_done:
Filtering events
Filtering events is done by writing a filter to the filter file
Filters can be set on each parameter listed in the format file, whether it is a numeric
or a string
or a combination
Clearing filters
Following event traces during execution
Following this, any enabled event will be traced into the console
Linux SDIO detection
Linux SDIO part detection on the SDIO bus
Under Linux, SDIO parts are bound to the mmc bus.
Before using a Wi-Fi part connected to the SDIO bus of a Linux system, it is necessary that the system detects the HW on the bus.
When detection succeeds, the kernel has retrieved the VID/PID for the device.
Looking for a driver matching the VID/PID is only possible if the VID/PID has been retrieved from the device.
Linux systems will try to detect SDIO parts on the bus at boot, and every time the mmc bus is bound. Unbinding/binding the mmc bus is what we will use to trace mmc messages related to SDIO detection.
SDIO Detection message
The following message should be visible in dmesg once boot is complete:
one-line check:
Until this message is present in dmesg
If this message is not found, it is necessary to debug SDIO detection, going through the following steps:
These steps are detailed below.
Retrieving the current device tree
Refer to Linux Device Tree Debugging for information on retrieving the device tree content in a file.
Debugging device tree issues by comparison
Making sure SDIO is enabled in Device Tree
In order for the Linux system to try detecting a part on the SDIO bus, the SDIO bus needs to be part of the Device Tree used at boot.
one-line check (SDIO pins selection):
If this returns an empty line, SDIO detection is not even triggered. Refer to your system documentation to know how to add SDIO to the device tree.
Checking which mmc bus is used for SDIO
one-line check (SDIO mmc bus selection):
or (depending on the kernel, i.e. the device tree version)
If this returns an empty line, SDIO is not connected to any mmc bus. Refer to your system documentation to know how to add SDIO to the device tree.
Checking the mmc bus commands during the SDIO detection phase
This is the trickiest part, since it involves tracking message normally issued at boot, when the system is attempting SDIO detection.
In reality, these are issued every time the mmc bus is bound to the system, so unbinding/binding the mmc bus will trigger a new detection attempt. We use this to avoid activating the traces at boot time, since this is not easy to do.
Preparing the kernel event traces (to be executed with root privileges):
Activating mmc request traces:
Not tracing mmc CMD53 (once working in high-speed mode, to avoid being overloaded with traces once detected):
Tracing the kernel events on mmc1 (adapt the mmc to your own use case):
Unbinding/Binding the mmc bus to trigger a reset and reload the driver:
Typical traces (limited view zooming on 'cmd_opcode' due to extra long lines):
Stopping mmc request traces (once the traces have been retrieved):
This step is necessary to stop tracing, which is otherwise still active. No additional traces are shown because SDIO traffic only uses CMD53 once detection is complete, and CMD53 are filtered out. It is better to stop tracing completely.
Checking the SDIO detection result
If detection is correct, the 'mmcX new high speed SDIO card at address 0001' message is present in dmesg.
Otherwise, check for errors related to the mmc item corresponding to your part.
SDIO pins used for the detection phase
The SDIO detection as shown above only uses SD_CMD and SD_CLK pins, and is generally performed with a 400kHz SD_CLK.
SD_DAT[3:0] are not used yet, so SDIO detection may succeed even though SD_DAT[3:0] are not properly routed.
Host stopping clock after CMD0
Some hosts will stop the SD-CLK clock right after issuing the CMD0 (MMC_GO_IDLE) command.
This is because the SDIO specification does not require a response to CMD0.
In this case, the SDIO detection flow will get interrupted after CMD0, and will not show CMD5, CMD52, etc.
To solve this, apply the patch described at the end of this article in 'Specifics of using a processor which stops the clock after CMD0'
Max SDIO speed too high
During the last steps of SDIO detection, the SoC sets the SDIO part to 'high-speed' mode on 4 data bits, then configures its own hardware to the maximum selected SDIO speed (controllable in the device tree) only at the very end of the SDIO detection, after a long series of about 26 CMD52 commands.
There is a SDIO speed limitation with BRD8022/BRD8023 due to the onboard switches. For this reason, we need to reduce the SDIO clock speed. 25 MHz is generally a good choice, given that choices are limited and vary depending on the platform.
In case there are issues related to the max clock speed, the last CMD52 commands will return with 'cmd_err=-110' (which means 'TIMEOUT'), and will be followed by a short burst of about 4 CMD55 commands.
Whenever the SDIO detection loop fails, it is repeated with a slower clock speed (400, 300, 200, 100 kHz, respectively), but is still ending with the max clock. If the max clock is too high, all 4 loops will eventually fail, therefore the traces will show 4 repeated patterns of:
CMD52
CMD52
CMD0
CMD8
CMD5
CMD5
CMD7
CMD52
. . .
CMD52 / cmd_err=-110
CMD55 / cmd_err=-110
CMD55 / cmd_err=-110
CMD55 / cmd_err=-110
CMD55 / cmd_err=-110
And dmesg will show:
mmc1: error -110 whilst initialising SDIO card
mmc1: error -110 whilst initialising SDIO card
mmc1: error -110 whilst initialising SDIO card
mmc1: error -110 whilst initialising SDIO card
In this case, check your device tree documentation to check how to reduce the maximum SDIO clock.
Checking the SDIO clock speed
sudo cat /sys/kernel/debug/mmc1/ios
Output:
clock: 50000000 Hz
actual clock: 25000000 Hz
vdd: 21 (3.3 ~ 3.4 V)
bus mode: 2 (push-pull)
chip select: 0 (don't care)
power mode: 2 (on)
bus width: 2 (4 bits)
timing spec: 2 (sd high-speed)
signal voltage: 0 (3.30 V)
driver type: 0 (driver type B)
Checking GPIO allocation
sudo cat /sys/kernel/debug/gpio
Output:
Check that wakeup and reset are properly allocated
SDIO Simplified Specification reference
When looking for reference information on SDIO detection please download the `SDIO Simplified Specification` PDF from https://www.sdcard.org/downloads/pls/index.html (Version 3.0 from July, 25, 2018 at the time of writing)
On pages 18/19, Figure 3.2 : Card Initialization Flow in SD mode (SDIO Aware Host) corresponds to our use case.
The following abstracts show the path WF200 should take during init.
If your startup traces don't follow this path, you probably have a HW issue, which could be related to
Specifics of using a processor which stops the clock after CMD0
There is a specific way of handling the SD_CLK in some (i.e. OMAP, at least) processors, which are stopping SD_CLK a couple cycles after the end of the CMD0 command, without waiting for a response. Our part attempts to send a response to CMD0 and needs a valid clock to do so, so detection fails right after CMD0 (all commands report a timeout).
You need to apply the attached patch in your case, and add the 'mmc-reply-go-idle' property in your device tree:
Questions on UART event configuration using ZentriOS API/SDK
1. How often the callback function which was configured by zn_uart_register_rx_callback() API will ba called?
This is called for every time the MCU UART RX interrupt is invoked. For this reason, it is extremely important that is callback is lightweight. All heavy processing should be deferred to a thread context.
2. The number configuring by zn_event_enable_irq_events() is not clear.
This configures the number of events that can be queued from the IRQ context.
A configuration of 8 allows for events to be queued from the UART RX callback. i.e. zn_event_issue(my_handler, NULL, ZOS_EVENT_FLAG_FROM_IRQ) can be invoked up to 8 times (without my_handler executing in-between) before the API fails with an overflow error.
3. The meaning of flag used by zn_event_issue() is unclear.
This tells the API that the event_handler is being issued from an IRQ context.
Effectively, this flag tells the API to add the handler to the IRQ handler queue configured with zn_event_enable_irq_events().
4. The relation between the data size specified by zn_uart_receive_bytes() and timeout. If the timeout occurred, will the data be received until the timeout occurred? Or, will the whole data discarded? If the former is the case, can we know the actually received size by zn_uart_get_bytes_received()?
If zn_uart_receive_bytes() returns ZOS_TIMEOUT, then the amount of data read up until the timeout is returned.
zn_uart_get_bytes_received() contains the amount of read data returned in the buffer.