NVIDIA Sensor IIO Kernel Changes Break Common IIO Drivers

I am trying to add a new IIO sensor driver to the kernel source and build it into the existing kernel. In particular I am trying to utilize the IIO device drivers from ST in the LSM6DS family that are multi-functional IIO devices. This is not uncommon as many IIO devices on the market support several functions within the same device. These devices work by having a core framework that allows access to multiple features of the chip all using the same hardware interface. They then allocate (iio_device_alloc) and register (iio_device_register) multiple IIO devices that have the core device as the parent of the IIO devices.

However, the changes by NVIDIA here in the latest 4.9 kernel nv-tegra: linux-4.9: iio: core: add Android L support for sensors to industrialio-core.c cause issues with multi-function IIO device drivers that have a single parent device. The changes appear to be NVIDIA specific and related to the NVS (NVIDIA Sensor) support and do not exist in upstream kernels, and are possibly only for Android.

I have tested with JetPack 4.4 Developer Preview (L4T R32.4.2) release and I get the following kernel error from the industrialio-core.c in iio_device_register() @ sysfs_create_link() line 1597 when the second iio_dev gets registered with the same parent:

sysfs: cannot create duplicate filename ‘/devices/3180000.i2c/i2c-2/2-006a/iio_device’
WARNING: CPU: 5 PID: 7506 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88
Call trace:
sysfs_warn_dup+0x68/0x88
sysfs_do_create_link_sd.isra.0+0xe4/0xf0
sysfs_create_link+0x40/0x68
iio_device_register+0x5d0/0x6c0
devm_iio_device_register+0x50/0xa0
st_lsm6dso_probe+0x634/0x908
st_lsm6dso_i2c_probe+0x2c/0x38
i2c_device_probe+0x144/0x258
driver_probe_device+0xd8/0x408

It appears the problem exists on all version of L4T that are using the 4.9 kernel.

The extra call to sysfs_create_link() that NVIDIA added to the industrialio-core.c iio_device_register() function, does not seem necessary. All it looks like it is doing is creating a link iio_device -> iio:deviceX in the parent device’s sysfs directory, which does not seem necessary or that helpful.

Can the calls to sysfs_create_link/sysfs_delete_link() that NVIDIA added in industrialio-core.c be completely removed?

Or if the symbolic link needs to be created for some Android API, can the error condition on failure at least be downgraded from an error condition that causes a failed iio_device_register() to just a warning message?

The reason the IIO modifications were made were to allow a multi-device part, e.g. a chip with multiple sensors, to “virtualize” each sensor as a single chip which would then load a virtualized driver for that sensor. This is strictly a NVS (NVidia Sensor) framework feature at the kernel level.
If you are not using any NVS kernel drivers, then this modification can be removed.

Could you have the repo step here.

Thanks

What is a repo step?

How can I see the problem step by step.

Hi Erik,
Thanks for your response. I see that.

Is there a reason that the symlink(s) in the parent device have to be created each time iio_device_register() is called?

Why does the iio_dev->dev.type have to be changed? What was wrong with the old method of using the link_name exclusively to setup and configure the symlinks?

Would NVIDIA be open to a patch submission that would maintain the special functionality with the symlink creation for users calling nvs_device_alloc() API and all other users going through the standard kernel API iio_device_alloc() not getting the symlink created? If yes, I can submit my change here or wherever that would be appropriate, if someone (yourself) would consider merging it into the official NVIDIA Linux kernel.

  1. cd <Linux_for_Tegra>/sources/kernel/kernel-4.9
  2. git fetch https://github.com/sweng5080/nvidia-linux-4.9.git refs/heads/iio-core-symlink-register-issue && git checkout FETCH_HEAD
  3. Build the Kernel Image
  4. Load the Kernel Image to the Jetson TX2 device
  5. Wait for device to boot with new Kernel Image that includes the ST LSM6DSO accel/gyro driver built-in
  6. Manually add a new fake lsm6dso I2C device using the sysfs interface on bus 2:
    sudo bash -c "echo lsm6dso 0x6a > /sys/bus/i2c/devices/i2c-2/new_device"

The kernel will log an error message that occurred in the iio core code:

[ 84.303350] sysfs: cannot create duplicate filename ‘/devices/3180000.i2c/i2c-2/2-006a/iio_device’
[ 84.312422] ------------[ cut here ]------------
[ 84.317044] WARNING: CPU: 0 PID: 7652 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x68/0x88
[ 84.324686] Modules linked in: bnep fuse hid_logitech_hidpp hid_logitech_dj zram spidev overlay nvgpu bluedroid_pm ip_tables x_tables
[ 84.324709] CPU: 0 PID: 7652 Comm: bash Not tainted 4.9.140-tegra #29
[ 84.324711] Hardware name: quill (DT)
[ 84.324713] task: ffffffc1c22c3800 task.stack: ffffffc1afc18000
[ 84.324717] PC is at sysfs_warn_dup+0x68/0x88
[ 84.324719] LR is at sysfs_warn_dup+0x68/0x88
[ 84.324722] pc : [] lr : [] pstate: 40400045
[ 84.324723] sp : ffffffc1afc1b860
[ 84.324725] x29: ffffffc1afc1b860 x28: ffffff80090bac50
[ 84.324729] x27: ffffff80090b9d90 x26: 000000000000000c
[ 84.324733] x25: 0000000000000000 x24: ffffffc1e4ff33b0
[ 84.324737] x23: 0000000000000001 x22: ffffff800950b0f0
[ 84.324740] x21: ffffffc1e3c07168 x20: ffffff800950b0f0
[ 84.324744] x19: ffffffc1d2cba000 x18: 0000000000000010
[ 84.324747] x17: 0000000000000000 x16: 0000000000000000
[ 84.324750] x15: ffffffffffffffff x14: 303030303831332f
[ 84.324754] x13: 736563697665642f x12: 2720656d616e656c
[ 84.324757] x11: 6966206574616369 x10: 000000000000051f
[ 84.324761] x9 : 65726320746f6e6e x8 : ffffff80083d3ad0
[ 84.324764] x7 : ffffff8009eb4198 x6 : ffffffc1f703cbf0
[ 84.324768] x5 : ffffffc1f703cbf0 x4 : 0000000000000000
[ 84.324771] x3 : ffffffc1f70427f8 x2 : ffffffc1f703cbf0
[ 84.324775] x1 : ffffffc1c22c3800 x0 : 0000000000000056
[ 84.324779] —[ end trace 6bca2ec3681cf38c ]—
[ 84.329388] Call trace:
[ 84.329393] [] sysfs_warn_dup+0x68/0x88
[ 84.329396] [] sysfs_do_create_link_sd.isra.0+0xe4/0xf0
[ 84.329399] [] sysfs_create_link+0x40/0x68
[ 84.329404] [] iio_device_register+0x5d0/0x6c0
[ 84.329407] [] devm_iio_device_register+0x50/0xa0
[ 84.329410] [] st_lsm6dso_probe+0x608/0x8b8
[ 84.329413] [] st_lsm6dso_i2c_probe+0x2c/0x38
[ 84.329417] [] i2c_device_probe+0x144/0x258
[ 84.329421] [] driver_probe_device+0xd8/0x408
[ 84.329424] [] __device_attach_driver+0xa8/0x148
[ 84.329426] [] bus_for_each_drv+0x58/0xa8
[ 84.329429] [] __device_attach+0xc8/0x158
[ 84.329431] [] device_initial_probe+0x24/0x30
[ 84.329434] [] bus_probe_device+0x9c/0xa8
[ 84.329436] [] device_add+0x3d0/0x5d8
[ 84.329438] [] device_register+0x28/0x38
[ 84.329441] [] i2c_new_device+0x138/0x218
[ 84.329444] [] i2c_sysfs_new_device+0xc0/0x1f0
[ 84.329448] [] dev_attr_store+0x44/0x60
[ 84.329452] [] sysfs_kf_write+0x58/0x80
[ 84.329454] [] kernfs_fop_write+0xfc/0x1e0
[ 84.329459] [] __vfs_write+0x48/0x118
[ 84.329462] [] vfs_write+0xac/0x1b0
[ 84.329464] [] SyS_write+0x54/0xb0
[ 84.329468] [] el0_svc_naked+0x34/0x38
[ 84.329531] st_lsm6dso_i2c 2-006a: Failed to create link for iio_device -17
[ 84.336889] st_lsm6dso_i2c: probe of 2-006a failed with error -17
[ 84.343088] i2c i2c-2: new_device: Instantiated device lsm6dso at 0x6a

@JDSchroeder
Please help to try these patch.

0001-iio-core-Remove-NVS-multi-link.patch.txt (4.4 KB)
0001-nvs-core-Remove-multi-link.patch.txt (1.5 KB)

Hi JDSchroeder,

Have you tried with the provided patches?
Any result can be shared?

I built and verified with the L4T 32.4.2 kernel that 0001-iio-core-Remove-NVS-multi-link.patch does fix the issue I was having with the iio symlinks (all but in a different/cleaner way than my original change). I do not have CONFIG_NVS set in my kernel configuration. So I only did a code review of 0001-nvs-core-Remove-multi-link.patch and it should work properly.

Will these be merged into the git tree or do they still have to undergo more review?

The target is merge to J4.5