Using persistent storage in linux kernel - linux

I am trying to use persistent store(Pstore) available in linux kernel but somehow I am not getting the logs in case of kernel panics. I made the following kernel modules in kernel config file as built in:
CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y
CONFIG_PSTORE_RAM=y
Now a/c to documentation pstore I should get the logs on next reboot in /sys/fs/pstore/... (or /dev/pstore/...) but couldn't find the logs there.
Am I missing something...?

Besides the kernel config options:
CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y
CONFIG_PSTORE_PMSG=y
CONFIG_PSTORE_RAM=y
I had to reserve a part of memory in which the logs will be saved. I did this through the device tree like this:
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
pstore: pstore#FF00000 {
no-map;
reg = <0x0 0xFF00000 0x0 0x00100000>; /* pstore/ramoops buffer
starts at memory address 0xFF00000 and is of size 0x00100000 */
};
};
ramoops {
compatible = "ramoops";
memory-region = <&pstore>;
record-size = <0x0 0x00020000>;
console-size = <0x0 0x00020000>;
pmsg-size = <0x0 0x00020000>;
};
Also, check if the following kernel patch is present (which is needed for the kernel to be able to parse the options given above):
https://android-review.googlesource.com/#/c/kernel/common/+/195160/
Another way is to turn it on through the kernel cmdline, for example:
ramoops.mem_address=0x30000000 ramoops.mem_size=0x100000 memmap=0x100000$0x30000000

check if below config options are enabled
CONFIG_PSTORE=y
CONFIG_PSTORE_CONSOLE=y
**CONFIG_PSTORE_FTRACE=y**
CONFIG_PSTORE_RAM=y
But why /dev/pstore file?, it's not needed,
To check if console-ramoops working,
do echo Trigger a kernel panic using command
echo c > /proc/sysrq-trigger
then reboot device manually. after system boots up, run command "/sys/fs/pstore/console-ramoops", check if console_ramoops has got anything logged.

You have to declare platform data as described by #shadowfire. But all kernel cannot use device tree for ramoops.
Generic way to do it, is to add in the source file for your hardware (example for mx6ul : arch/arm/mach-imx/mach-imx6ul.c) the following piece of code in the function xxx_init_machine :
#include <linux/pstore_ram.h>
[...]
static struct ramoops_platform_data ramoops_data = {
.mem_size = <...>,
.mem_address = <...>,
.mem_type = <...>,
.record_size = <...>,
.dump_oops = <...>,
.ecc = <...>,
};
static struct platform_device ramoops_dev = {
.name = "ramoops",
.dev = {
.platform_data = &ramoops_data,
},
};
[... inside xxx_init_machine ...]
int ret;
ret = platform_device_register(&ramoops_dev);
if (ret) {
printk(KERN_ERR "unable to register platform device\n");
return ret;
}
More info available in documentation : ramoops
Do you have logs in dmesg which can confirm that ramoops is enabled successfully ?
# dmesg | grep -i "pstore\|ramoops"
console [pstore-1] enabled
pstore: Registered ramoops as persistent store backend
ramoops: attached 0x20000#0x80000000, ecc: 0/0
Moreover you must mount pstore directory, that's why the directory is empty on your rootfs :
mount -t pstore -o kmsg_bytes=8000 - /sys/fs/pstore
Default size for the mount is 10 Kbytes in you don't set the kmsg_bytes option. You can use /etc/fstab to mount it automatically.

Related

Simple GPIO Device Tree Example for Beaglebone Black Deb 10.3

My goal is to write a simple .dts file (to be compiled to .dtbo using DT 1.4.4) to configure a GPIO output on boot on a Beaglebone Black Rev C running Debian 10.3
I intend to place the .dtbo in /lib/firmware and then specify it in /boot/uEnv.txt
I understand some parts of the .dts file and have tried decompiling exisiting .dtbo files in /lib/firmware/ for guidance but none of them are a simple GPIO output example. A lot of online resources involve make and make install but I believe DT should be able to handle it by now right?
I was able to get the following to compile but with issue:
/* dtc -O dtb -o BB-P8_13-LED.dtbo -b 0 -# BB-P8_13-LED-00A0.dts */
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone-black";
/* identification */
part-number = "BB-P8_13-LED";
version = "00A0";
/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P8.13", /* GPIO_23 */
/* the hardware ip uses */
"gpio23";
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
bb_gpio23_pin: pinmux_bb_gpio23_pin {
pinctrl-single,pins = < 0x024 0x07 >; /*P8_13 GPIO23 MODE7*/
};
};
};
fragment#1 {
target = <&gpio23>;
__overlay__ {
leds {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bb_gpio23_pin>;
compatible = "gpio-leds";
P8_13 {
label = "P8_13";
default-state = "on";
};
};
};
};
};
Q: Why does loading this .dtbo in /boot/uEnv.txt cause all other GPIOs to disappear from /sys/class/gpio/? I thought fragment0 was for excluding a single gpio, not all of them.
###Additional custom capes
uboot_overlay_addr4=/lib/firmware/BB-P8_13-LED-00A0.dtbo
Q: Where are the files for controlling the GPIO (for testing) or rather what can I add to my .dts file so the gpio23 still appears in /sys/class/gpio or even /sys/class/leds? Ultimately I want to be able to control this GPIO with Node-RED.
Q: Do I need to be consistent with my use of P8.13 vs. P8_13? I think I'm mixing up terminology used in .dts files that get compiled with make vs DT.
Q: I think my fragment#1 P8_13 child node is missing something to specify the gpio bank and active high/low setting. Something like "gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;" Where can I look to research which bank GPIO23 is in? What does the '19' mean in that statement?
So Dr. Derek Molly did a really nice job of laying this out and I was able to use the example in his repo. Here is a page he made for explaining how to configure GPIO at boot using Device Tree Overlays:
http://derekmolloy.ie/beaglebone/beaglebone-gpio-programming-on-arm-embedded-linux/
Even though his solution is for kernel 3.8 I was able to get the following to compile on 4.19
/* dtc -O dtb -o BB-P8_13-LED-00A0.dtbo -b 0 -# BB-P8_13-LED-00A0.dts */
/dts-v1/;
/plugin/;
/{
compatible = "ti,beaglebone-black";
part-number = "BB-P8_13-LED";
version = "00A0";
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
pinctrl_test: BB-P8_13-LED {
pinctrl-single,pins = <
0x024 0x27 /* P8_13 9 PULLUP ENABLED OUTPUT MODE7 - The LED Output */
>;
};
};
};
fragment#1 {
target = <&ocp>;
__overlay__ {
test_helper: helper {
compatible = "bone-pinmux-helper";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
status = "okay";
};
};
};
};
All that needs to be edited for a different GPIO pin is the "0x024" (address offset) and the "0x27" to set various aspects of the GPIO like pullup vs. pulldown and pinmux mode. Derek Molly has an older version of his guide which has the table for building the pinmux binary values (that need to be converted to hex): http://derekmolloy.ie/gpios-on-the-beaglebone-black-using-device-tree-overlays/
Most of the information is available in the Beaglebone SRM which I should probably read at some point.
The .dts file in my first answer did not fix my problem. GPIO P8_13 still boots as an input. After more digging and testing I have discovered it is NOT possible to make a GPIO direction survive a reboot. It will always boot to the default and the best you can do is enable a pullup or pulldown resistor to keep the pin high or low until a custom service file (or program) can write to /sys/class/gpio/gpioXXX/direction. I even tried decompiling am335x-boneblack.dtb, editing it, and re-compiling with no luck.
This is sad and incredibly frustrating. What good is an output that flickers during reboot? Guess I'll have to compensate with fancy external circuitry.
Per the original question, you can author a dts file where the GPIO remains in /sys/gpio/class/. See the article I wrote below for an example that works this way.
https://takeofftechnical.com/beaglebone-black-led-control/

How to match a Linux driver with a hardware device

I am writing a Linux driver for some custom hardware. My questions is how does Linux match the hardware to my driver. The hardware's DT entry is
nvme_host_sys#43c00000 {
clock-names = "sys_clk_p", "sys_clk_n", "aclk";
clocks = <0x13 0x13 0x13>;
compatible = "xlnx,nvme-host-sys-1.0";
interrupt-names = "intr";
interrupt-parent = <0x4>;
interrupts = <0x0 0x1d 0x4>;
reg = <0x43c00000 0x80000>;
phandle = <0x38>;
};
I can insert my driver using modprobe and that works fine as I can see the printk in the init being written. I can also create an entry in /dev using mknod and that also works fine. But is the driver now associated with the hardware? Do I need to do something else? Thanks
I found the solution. In the driver code we just need to add the following :-
static struct of_device_id nvmedrv_of_match[] = {
{ .compatible = "xlnx,nvme-host-sys-1.0", },
{ /* end of list */ },
};

Device interfacing using SMBus on Beaglebone Black

I am using ADM1032ARMZ-2R temperature sensor (as a beginner I am not allowed to post more than 2 links here, I have already posted 2 links for the images below - For datasheet please google ADM1032ARMZ-2R) with Beaglebone Black Rev C having pre-installed Debian (kernel - 3.8.13) . The datasheet of ADM1032 says that chip is available for communication at address 0x4D via SMBus Protocol. I have never worked on SMbus before but found that I2C is compatible with SMBus for 100 KHz and less. I tried doing following things
I wrote a device tree overlay. It looks like following (I have kept the frequency as 100 KHz)
// Device Tree Overlay for I2C1 uses Pins P9.17(SCLK) & P9.18(SDA)
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";
part-number = "BBB-I2C1-4D";
version = "00A0";
exclusive-use =
"P9.18", /* i2c1_sda */
"P9.17", /* i2c1_scl */
/* the hardware ip uses */
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
bb_i2c1_pins: pinmux_bb_i2c1_pins {
pinctrl-single,pins = <
0x158 0x72 /* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
0x15c 0x72 /* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
>;
};
};
};
fragment#1 {
target = <&i2c1>;
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bb_i2c1_pins>;
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
/* adding adm1032 as i2c child device on the bus here */
tempsense: tempsense#4d {
compatible = "onsemi,adm1032";
reg = <0x4d>;
};
};
};
};
Compiled this file, copied the resultant .dtbo file in the /lib/firmware directory and successfully inserted it as a virtual cape in the /sys/devices/bone_capemgr.9/slots using echo command. It looks like this
I tried to observe the correctness of the above work using the following command
dtc -f -I fs /proc/device-tree | less
Intended things are happening and it looks like this (Please note that, for i2c1, the "ti,hwmods" field in the image shows "i2c2", but its actually i2c1 so please don't worry about it. I have read about it made sure that whatever it's showing is correct)
Now I am trying to do
i2cdetect -r 1
But I am not able to detect anything
at 0x02, there is a Status register available for reading
i2cget -y -f 0x4d 0x02
I get Read failed response
Where am I going wrong ? Please help.

Linux Kernel IIO events sysfs files only readable

I have the problem that I registered IIO events for rising and falling thresholds.
I can see the sysfs files in events subfolder and can read them, but when I try to write a new threshold it says "permission denied".
following setup:
static const struct iio_event_spec as6200_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}
};
static const struct iio_chan_spec as6200_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.event_spec = as6200_events,
.num_event_specs = ARRAY_SIZE(as6200_events),
}
};
finding: it works when I change the permissions of the in_temp_thresh_rising_value file to 666 via sudo. But why is it not created with this permissions via IIO subsystem?
This is common practice for sysfs files, as writing to those files can alter system's behavior and even compromise or break the system. So if you want to write to those files, you should do that from root, or add your user to corresponding group, or change that file mode (by udev rule or by hand).
Here is how it's done in IIO code:
IIO sysfs node names are derived from next tables in drivers/iio/industrialio-event.c: iio_ev_type_text, iio_ev_dir_text and iio_ev_info_text
node creation path is next: iio_device_add_event() -> __iio_add_chan_devattr() -> __iio_device_attr_init()
file mode for sysfs node is being set in __iio_device_attr_init():
for reading: dev_attr->attr.mode |= S_IRUGO;
so every user can read the node (because S_IRUGO allows Reading for User, Group and Others)
for writing: dev_attr->attr.mode |= S_IWUSR;
so it only can be written by root (because S_IWUSR allows writing only for file owner, which is root)
Another solution to this problem is to use a combination of libiio's network and local contexts. In this case, a libiio daemon would be started with the appropriate privileges to write to the sysfs files, and the user application would then connect with this daemon using a libiio network context.

Modifying the device tree for the Beaglebone Black

I have used Yocto to create a small linux image for the Beaglebone Black. I think I have most everything working like I want it, except I need access to UARTs 2 and 4. When I was using the standard Debian image, I did this with device tree overlays and capemgr. However, I found that the kernel built with Yocto doesn't have capemgr.
My options seem to be:
get the kernel to build with capemgr, or
modify the device tree file with the necessary changes.
Option 2 seems much easier.
The device tree overlays for the UARTs are here and here. I have gone about trying to include those in a couple ways.
I decompiled the device tree blob I had been using and tried to
include these files from there.
I downloaded the full set of dts files and tried to include the
UART device tree overlays in am335x-boneblack.dts.
Both approaches yield an error something like this:
Error: am335x-boneblack.dts:1.1-2 syntax error
FATAL ERROR: Unable to parse input tree
However, I noticed that I get a similar error when trying to compile am335x-boneblack.dts even without modifying it, so I'm likely not even doing that right. (Using the command dtc -I dts -O dtb -o result.dtb am335x-boneblack.dts)
Obviously I don't know what I'm doing. I suspect the device tree overlays have to be modified in some way to be used in the way I'm trying to use them. Or maybe I'm not doing the include right (just adding a #include to the top of the file).
Does anybody have any ideas what I might be doing wrong? Is what I'm trying to do even possible?
So I got this working by taking my device tree blob, decompiling it, and merging in sections from the device tree overlay files, and recompiling. I realized I needed uarts 1 and 2 instead of 2 and 4, so this is slightly different than my original problem.
To decompile the device tree blob:
dtc -I dtb -O dts -o am335x-boneblack.dts am335x-boneblack.dtb
I used the existing uart0 as an example to show me the right sections to work in.
I added a section for uart1 and uart2 in the pinmux section under the section for uart0. It now looks like this:
pinmux_uart0_pins {
pinctrl-single,pins = <0x170 0x30 0x174 0x0>;
linux,phandle = <0x27>;
phandle = <0x27>;
};
bb_uart1_pins: pinmux_bb_uart1_pins {
pinctrl-single,pins = <
0x184 0x20 /* P9.24 uart1_txd.uart1_txd OUTPUT */
0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd INPUT */
>;
};
bb_uart2_pins: pinmux_bb_uart2_pins {
pinctrl-single,pins = <
0x150 0x21 /okay* spi0_sclk.uart2_rxd | MODE1 */
0x154 0x01 /* spi0_d0.uart2_txd | MODE1 */
>;
};
Then later, the serial sections need to be enabled and told what pins to use. I modified existing uart sections, and it now looks like this:
serial#44e09000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart1";
clock-frequency = <0x2dc6c00>;
reg = <0x44e09000 0x2000>;
interrupts = <0x48>;
status = "okay";
dmas = <0x26 0x1a 0x26 0x1b>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <0x27>;
};
serial#48022000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart2";
clock-frequency = <0x2dc6c00>;
reg = <0x48022000 0x2000>;
interrupts = <0x49>;
status = "okay";
dmas = <0x26 0x1c 0x26 0x1d>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&bb_uart1_pins>;
};
serial#48024000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart3";
clock-frequency = <0x2dc6c00>;
reg = <0x48024000 0x2000>;
interrupts = <0x4a>;
status = "okay";
dmas = <0x26 0x1e 0x26 0x1f>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&bb_uart2_pins>;
}
To recompile the device tree:
dtc -I dts -O dtb -o am335x-boneblack.dtb am335x-boneblack.dts
In short, I managed to get this working despite having little to no idea how device trees work.
I also needed to disable hdmi which I did by setting status equal to "disabled" in the hdmi section.

Resources