Why is my eeprom loop device spitting kernel errors? - linux

I'm working on an embedded linux project using PetaLinux and running on kernel 5.4.0-xilinx-v2020.1. We have multiple apps that needs to write their ~200 bytes config in a file every second for years at a time so we chose to include an 8kB FRAM on the board. The number of apps running isn't fixed, nor is the size of the data each will need to write so a filesystem seems like the easiest, user-friendliest and most transparent solution.
I've found the littlefs-fuse project and I've tested it on my workstation with a 8k loop device, everything is working as expected.
I'm currently in the integration phase and I'm having some issues creating the littlefs filesystem on the FRAM, here's how I'm hoping things would work:
The FRAM is setup in the device-tree as a 24c64-eeprom-compatible i2c device
Linux loads the at24 as expected and create the /sys/bus/i2c/devices/x-xxxx/ folder
I can read and write using bash commands to the /sys/bus/i2c/devices/x-xxxx/eeprom file
I create a loop device using the eeprom file
I use the littlefs-fuse project to create my file system and mount it
I'm currently stuck at the end of part 4, I created a loop device with the eeprom file using losetup -fP /sys/bus/i2c/devices/x-xxxx/eeprom and it works fine without any error but I can't access any data on it.
Here's the error message I get when I try to cat the file
# cat /dev/loop0
cat: read error: Input/output error
And here's what I can find with dmesg concerning the error:
[11950.780699] print_req_error: 5 callbacks suppressed
[11950.780706] blk_update_request: I/O error, dev loop0, sector 0 op 0x0:(READ) flags 0x80700 phys_seg 2 prio class 0
[11950.795985] blk_update_request: I/O error, dev loop0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[11950.805985] buffer_io_error: 3 callbacks suppressed
[11950.805990] Buffer I/O error on dev loop0, logical block 0, async page read
[11950.817854] blk_update_request: I/O error, dev loop0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[11950.827846] Buffer I/O error on dev loop0, logical block 0, async page read
It's completly possible I'm try to fit a square peg in a round hole here but as far as I know, any file is supposed to work with a loop device so I'm confused as to why it's not working as I expect

Related

Linux: writing to the i2c/SMBus

I have a problem with the i2c/SMBus on a Linux System with an Intel Apollo Lake processor. I am trying to read/write from/to an EEPROM but I face some issues. My EEPROM is located at the address 0x56, and I am able to watch the Bus with my Logic Analyzer.
When I try to read from the device via i2ctools (i2cget) the System behaves as expected. My issue occurs when I try to perform a write command via i2cset for example. i2cset ends with an error (Write failed). Because I am able to watch the Bus electrically I can also say that all lines stay HIGH and the Bus is not touched. I was able to activate the dev_dbg() functions in the i2c driver i2c_i801 and when I perform i2cset I am able to find (dmesg) the debug message:
[ 765.095591] [2753] i2c_i801:i801_check_post:433: i801_smbus 0000:00:1f.1: No response
When running my minimal I²C Python code using the smbus2 lib, I get the following error message and the above mentioned debug message:
from smbus2 import SMBus
bus = SMBus(0)
b = bus.read_byte_data(86,10) #<- This is performed
b = bus.write_byte_data(86,10,12) #<- This is not performed
bus.close()
Error:
File "usr/local/lib/python3.8/dist-packagers/smbus2-0.4.0-py3.8.egg/smbus/smbus2.py", line 455, in write_byte_data
ioctl(self.fd, I2C_SMBUS, msg)
OSERROR: [Errno 6] No such device or adress
A big hint for me is that I am not able to perform a write command in the address space form 0x50 to 0x57. My guess is that some driver locks the address space to prevent write command to that "dangerous" area.
My question is: "Does anyone know this kind of behavior and is there a solution so that I can write to my EEPROM at address 0x56? OR Is there a lock surrounding the i2c adress space from 0x50 to 0x57 and who is my opponent?"
I am kind of a newbie to the whole driver and kernel world so please be kind and it is quite possible that I made a beginner mistake.
I would appreciate hints and tips I can look after surrounding my problem.
It seems that I found the cause of my problem. In this Forum post is described that Intel changed a configuration Bit at the SMBus controller.
OK, I know what's going on.
Starting with the 8-Series/C220 chipsets, Intel introduced a new
configuration bit for the SMBus controller in register HOSTC (PCI
D31:F3 Address Offset 40h):
Bit 4 SPD Write Disable - R/WO.
0 = SPD write enabled.
1 = SPD write disabled. Writes to SMBus addresses 50h - 57h are
disabled.
This badly documented change in the configuration explains the issues.
One Challenge is, that to apply and enable changes to the SPD-write Bit the System needs to be rebooted. Unfortunately while rebooting the BIOS will change the Bit back to the default. The only solution seems to be an adaption in the BIOS.
For me, this issue is resolved. I just wanted to share this information in case someone faces the same issues.

how to use i2c driver in kernel space

I have wrote a character driver to control my embedded hardware with my application, In my driver there is a feature to send a command to an I2C device which is connected to my embedded device.
in command line I am able to send the following code to my device:
i2cset -y 0 0x2c 0x00 0x05
I want to do same thing in kernel space within my driver, but I did not find a sample, all I got was in userspace, how can I do that in kernel space?
edit:
I know that with "i2c_master_send" or "i2c_smbus_read_byte" function I can send data to i2c devices, bu this function gets a structure called "i2c_client", I don't know how should I suppose to fill this structure to send data. It might be really silly but I could not figure it out how can I fill this structure.
I have reached my goal with following code in my driver:
****Please read my edit before using this code*****
#define VOL1_CHIP_ADDRESS 0x2c
#define VOL1_DATA_ADDRESS 0
struct i2c_client *clientstr;
struct file * fp;
...
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(KERNEL_DS);
fp = filp_open("/dev/i2c-0",O_RDWR,0);
clientstr = (struct i2c_client *)fp->private_data;
clientstr->addr=VOL1_CHIP_ADDRESS;
i2c_smbus_write_byte_data(clientstr,VOL1_DATA_ADDRESS,0x05);
filp_close(fp,NULL);
set_fs(oldfs);
EDIT:
So I did what I wanted in kernel, opening a file in kernel space regardless of any suggestions not to do so.
But I needed to open a file in kernel module...
So why every body said don't open user space files in kernel?
In these two articles there are some reasons to not using files in kernel , this link and this link.
there are some reasons like:
1- kernel module may lose CPU at any time and the file which is opened by kernel may close.
2- I am not sure really about this, But they said files needs to have a process to stay opened but kernel module itself is not a process(maybe I am wrong!).
3- If any error happens while working with files(open/close/read/write), kernel module can not handle it and causes kernel panic...
I have experienced a lot of kernel panics only while opening and closing the file I wanted to work with. These are some of reasons why you should not use files in kernel modules, So as every body said before "If you need to use files in kernel module you probably did something wrong in your code!"

usb bulk transfer timeout under Linux while it works under Windows

[Edit: I found the reason, see below]
The problem:
I created a "driver" for a device in Windows using Python (PyUSB and libusb-win32). While this software works seamlessly on multiple PCs under Windows, using my Linux (Kubuntu 18.10) test laptop, a sequence of bulk writes of length 512 bytes each times out after the second 512 byte bulk transfer.
Interesting: I also tried the same using VirtualBox. And it turns out using a Windows guest via VirtualBox on the same Linux host, the same error still occurs. So it is not because of
The question:
What can happen under Linux does not happen under Windows that causes a timeout [Errno 110]?
More information, in case it helps:
Under Windows, Wireshark shows timing differences between two of the bulk writes of 6 ms for the first one and 5 ms for every following, while under Linux the delta is only round about 3 ms, which are mostly resulting from a sleep operation (relevant Python source code is attached). Doubling that time does nothing.
dmesg shows messages like 'bulk endpoint ## has invalid maxpacket 64', where ## is 0x01, 0x08 and 0x81.
The device only has one configuration.
The test laptop has only USB 3.0 connectors, where the Windows PCs have both USB 3.0 and 2.0. I tested all.
Wireshark shows the device answering with another (empty) bulk on every bulk write under Linux, while it does not show that under Windows. As far as I understand, that is because USBPcap cannot capture handshakes under Windows. But I am not shure with that, because I do not know if this type of response would really be classified as "URB_BULK out".
I tried libusb0, libusb1 and OpenUSB as backends under Linux, without success.
The bulk transfer in question is the transfer of FPGA firmware to the device.
I am able to communicate with the device before the multiple-512 byte-chunk bulk operation on the same endpoints using only a few bytes. The code that then causes the timeout is the following one in the second iteration of this for loop:
for chunk in chunks: # chunks: array of bytearrays with 512 bytes each
self.write(0x01,chunk)
time.sleep(0.003)
[Edit] The reason I found out that this only occurs on my test laptop using xhci, not on a second Linux test machine using ehci. So this might be caused by xhci. I do not yet have a workaround, but this at least gives an explanation.
It turns out that the device requested less bytes per packet, the desired amount of bytes (64) could be found in dmesg as already written in the question. Since xhci doesn't support that officially, Linux decided to ignore that request. Windows seemingly went with it and split larger packets up in the requested packet size. So the solution was to manually split the data to packets of 64 byte size before transferring it.

The begining and end adress of the Flash memory

I am trying to run linux on an Arduino Yun board. The Arduino board contains an Atheros AR9331 chipset
On U-Boot These are the steps I am doing:
1- Download the kernel :
ar7240> tftp 0x80060000 openwrt-ar71xx-generic-uImage-lzma.bin;
Load address: 0x80060000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
######################
done
Bytes transferred = 1441863 (160047 hex)
2- Erase Flash in order to copy the kernel:
ar7240> erase 0x9fEa0000 +0x160047
Error: end address (0xa0000046) not in flash!
Bad address format
This is the problem It seems that 0x9fEa0000 +0x160047 exceeds the total size of the flash.
So my questions are:
1- How can I figure the total amount of memory reserved for the flash in Uboot (From wich address it starts and ends), I am thinking about changing 0x9fEa0000 by a fewer address but i'am afraid i can harm other things
This is the output of the help:
ar7240> help
? - alias for 'help'
boot - boot default, i.e., run 'bootcmd'
bootd - boot default, i.e., run 'bootcmd'
bootm - boot application image from memory
cp - memory copy
erase - erase FLASH memory
help - print online help
md - memory display
mm - memory modify (auto-incrementing)
mtest - simple RAM test
mw - memory write (fill)
nm - memory modify (constant address)
ping - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
progmac - Set ethernet MAC addresses
reset - Perform RESET of the CPU
run - run commands in an environment variable
setenv - set environment variables
tftpboot- boot image via network using TFTP protocol
version - print monitor version
2- Is there someone experienced with Atheros AR9331 chipset who can help me find the Flash mapping (From where it starts and ends) from the datasheet
You can determine the flash layout from the kernel boot command line. Either run the printenv command in u-boot or boot into the existing kernel and look through the boot log. You need to find something like the following:
(There are plenty of guides on the internet, I took this one from https://finninday.net/wiki/index.php/Arduino_yun, your board may or may not be the same).
linino> printenv
bootargs=console=ttyATH0,115200 board=linino-yun mem=64M rootfstype=squashfs,jffs2 noinitrd mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14656k(rootfs),1280k(kernel),64k(nvram),64k(art),15936k#0x50000(firmware)
bootcmd=bootm 0x9fea0000
This means there are the following partitions:
u-boot 0 to 256K (0x0 - 0x40000)
u-boot-env 256k to 320k (0x40000 - 0x50000)
rootfs (squashfs) 320k to 14976k (0x50000 - 0xea0000)
kernel 14976k to 16256k (0xea0000 - 0xfe0000)
nvram 16256k to 16320k (0xfe0000 - 0xff0000)
art 16320k to 16384k (0xff0000 - 0x1000000)
The rootfs partition is 14M, which is much larger than the rootfs image file (less than 8MB) so in theory you can move the kernel image at a lower address. For this you will need to modify the kernel boot line in the u-boot environment block (rootfs aand kernel partition sizes) and the bootcmd parameter so the u-boot know where the new kernel is located.
Flash is mapped to 0x9f000000 so the value in the bootcmd should be 0x9f000000 + the offset of the kernel in bytes.
What I am not sure about is if there is an overlay filesystem for any persistent changes to the flash. Can you boot into the existing system and post the output of df -h and cat /proc/mounts?

DMA error on start without AC

I installed funtoo on surface pro 2. All works good except situation when you're booting tablet on battery power. In this case I'm getting error bellow every 20 sec and tablet doesn't react on keypress, touch, doesn't log anything. fsck says there is no errors with disk.
EH complete
exception Emask 0x0 SAct 0x0 SErr 0x50000 action 0x6 frozen
SError: {.PHYRdyChg CommWake }
failed command: WRITE DMA
cmd ca/00:20:f0:0f:c4/00::00:00:00:00:e3 tag 15 dma 16384 out
res 40/00:00:00:00:00:/00:00:00:00:00/00 Emask 0x4 (timeout)
statys: {DRDY}
Kernel: sys-kernel/debian-sources 4.8.15
This looks a power saving issue
If you have TLP try to disable it here /usr/sbin/tlp.
Comment out
# set_sata_link_power $1
More info you can find in following discussion
(I know this is mac related discussion but can be useful for finding a solution for your setup)

Resources