Skip to content

arch/arm/src/imxrt: Unify FlexCAN TX work and add SIOCGCANERRORS. - #20008

Open
dakejahl wants to merge 4 commits into
apache:masterfrom
dakejahl:dakejahl/imxrt-flexcan-errors
Open

arch/arm/src/imxrt: Unify FlexCAN TX work and add SIOCGCANERRORS.#20008
dakejahl wants to merge 4 commits into
apache:masterfrom
dakejahl:dakejahl/imxrt-flexcan-errors

Conversation

@dakejahl

@dakejahl dakejahl commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Two changes to the i.MX RT FlexCAN SocketCAN driver, plus the network-layer plumbing the second one needs. Reworked per review: the per-command CAN ioctl options are merged into a single NETDEV_CAN_IOCTL.

  1. NETDEV_CAN_BITRATE_IOCTL, NETDEV_CAN_FILTER_IOCTL and NETDEV_CAN_STATE_IOCTL guarded identical option blocks, and every SIOCxCANxxx case in netdev_ifr_ioctl() forwarded a member of the same ifr_ifru union to d_ioctl(). They are merged into one NETDEV_CAN_IOCTL option and one case block that passes the union's address; drivers and defconfigs are updated to the new name. The stm32h7 FDCAN filter cases called stm32_addextfilter(), stm32_delextfilter(), stm32_addstdfilter() and stm32_delstdfilter(), which exist nowhere in the tree and only ever compiled because no stm32h7 config enables NETDEV_CAN_FILTER_IOCTL; a preparatory commit removes them so the commands fall through to the existing -ENOTSUP default.
  2. imxrt_txdone_work() and imxrt_txtimeout_work() shared priv->irqwork. work_queue() cancels a pending callback when its work_s is reused, so whichever was queued second silently replaced the first: deadlines left set, IMASK1 TX bits left off, or expired frames never aborted. Both paths now queue one worker, imxrt_tx_work(), which retires completions before aborting expired mailboxes.
  3. A new SIOCGCANERRORS ioctl (_SIOC(0x0045), behind CONFIG_NETDEV_CAN_IOCTL) returns struct can_ioctl_errors_s: fault-confinement state, TEC, REC, a monotonic bus-error count and the RX mailbox overrun count. SIOCGCANSTATE reports sleep/operational, not fault confinement, so this is a distinct command. The driver counts bus errors by sampling the clear-on-read ESR1 error flags at every driver entry (TX work, RX work, the ioctl) instead of enabling ERRINT, which fires per error frame and storms at bus rate on a dead bus. Frames the CAN socket layer drops for want of an IOB now also count as rx_dropped in the per-device netdev statistics.

Impact

  • New feature: YES, SIOCGCANERRORS, implemented for i.MX RT FlexCAN only; other SocketCAN drivers return -ENOTTY.
  • User: YES. NETDEV_CAN_BITRATE_IOCTL, NETDEV_CAN_FILTER_IOCTL and NETDEV_CAN_STATE_IOCTL no longer exist; configs that enabled any of them must enable NETDEV_CAN_IOCTL instead (in-tree defconfigs are updated). A board that enabled only one command's option now compiles every CAN ioctl case its driver implements.
  • Build: NO change with the option disabled; include/net/if.h gains struct can_ioctl_errors_s and one union member in ifreq/lifreq. The drivers touched by the rename get whole-file nxstyle fixes (whitespace only, token streams verified identical).
  • Hardware: i.MX RT FlexCAN only (the TX worker change affects every i.MX RT SocketCAN user).
  • Documentation: NO documentation of the CAN ioctls exists to update.
  • Security: NO.
  • Compatibility: YES for the ioctl (backward compatible; ifreq does not grow). NO for the three removed config names, see User above.

Testing

Build: imxrt1170-evk:can with CONFIG_NETDEV_CAN_IOCTL=y, nucleo-h743zi2:socketcan, imx95-evk:can, sim:dynconns, arm-none-eabi-gcc 13.2.1, host Linux.

Runtime: i.MX RT1176 (ARK FMU-v6XRT) running PX4 with this change carried on the PX4 NuttX fork (PX4/NuttX#401), two DroneCAN nodes, one per FlexCAN interface, 1 Mbit/s.

Before (stub getErrorCount(), isInBusOffState()): an error-passive controller is invisible from the socket API; uavcan status prints HW errors: 0 regardless.

After, unplugging the CAN2 node for 10 s and reading the ioctl every 2 s (console) while ECR/ESR1 were read over SWD at 20 Hz:

 64.1s  CAN1 error-active TEC 0 REC 0 hw 0    |  CAN2 error-passive TEC 128 REC 0 hw 379
 66.8s  CAN1 error-active TEC 0 REC 0 hw 0    |  CAN2 error-passive TEC 128 REC 0 hw 451
 74.7s  CAN1 error-active TEC 0 REC 0 hw 0    |  CAN2 error-passive TEC 128 REC 0 hw 637
 77.4s  CAN1 error-active TEC 0 REC 0 hw 0    |  CAN2 error-passive TEC 152 REC 0 hw 659
 85.3s  CAN1 error-active TEC 0 REC 0 hw 0    |  CAN2 error-active  TEC 17  REC 0 hw 660
SWD: CAN2 TXERRCNT 128 from 66.9 s, ESR1 fault confinement error-passive, 302 samples over 23 s, 259 with ACKERR; CAN1 0 / error-active on all 5932 samples

With the two nodes moved to 500 kbit/s while the controller stayed at 1 Mbit/s, the ioctl reads error-passive (TEC 0, REC 128) while the controller transmits nothing and (TEC 128, REC 133) while it does. With NETDEV_STATISTICS enabled, /proc/net/can0 showed Dropped advancing (445 frames in 300 s at 3260 frames/s with a 24-buffer IOB pool), which the global CAN statistics alone did not attribute to an interface.

@github-actions github-actions Bot added Area: Networking Effects networking subsystem Arch: arm Issues related to ARM (32-bit) architecture Size: M The size of the change in this PR is medium labels Aug 30, 2026
@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

dakejahl added a commit to PX4/NuttX that referenced this pull request Aug 30, 2026
… counters.

TX-complete and the deadline watchdog each queued their own callback on
the same work_s, and work_queue() cancels whatever is pending when a
work_s is reused, so whichever ran second was dropped: deadlines were
left set, the TX interrupt mask stayed off, or expired frames were never
aborted. Both now queue imxrt_tx_work(), which retires completions
before it aborts expired mailboxes.

Add SIOCGCANERRORS so a socket can read fault confinement, TEC/REC, a
monotonic bus error count and the RX mailbox overrun count. The error
count is sampled from the clear-on-read ESR1 error flags at every driver
entry rather than from ERRINT, which fires per error frame and storms at
bus rate once the bus is dead. Frames the CAN socket layer drops for want
of an IOB now count as rx_dropped in the netdev statistics.

Upstream: apache/nuttx#20008
Comment thread net/netdev/Kconfig Outdated
Comment thread net/netdev/netdev_ioctl.c Outdated
The SIOCxCANxxFILTER cases in fdcan_netdev_ioctl() call
stm32_addextfilter(), stm32_delextfilter(), stm32_addstdfilter() and
stm32_delstdfilter(), none of which exist anywhere in the tree. The
block only ever compiled because no stm32h7 config enables
NETDEV_CAN_FILTER_IOCTL; enabling it breaks the link. The commands now
fall through to the existing -ENOTSUP default, which is also what a
caller observed before.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
…_IOCTL

NETDEV_CAN_BITRATE_IOCTL, NETDEV_CAN_FILTER_IOCTL and
NETDEV_CAN_STATE_IOCTL guarded identical option blocks, and every
SIOCxCANxxx case in netdev_ifr_ioctl() forwarded a member of the same
ifr_ifru union to d_ioctl(). One option and one case block now cover
all of the CAN commands; drivers and defconfigs are updated to the
new name.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
TX-complete and the deadline watchdog each queued their own callback on
the same work_s, and work_queue() cancels whatever is pending when a
work_s is reused, so whichever ran second was dropped: deadlines were
left set, the TX interrupt mask stayed off, or expired frames were never
aborted. Both now queue imxrt_tx_work(), which retires completions
before it aborts expired mailboxes.

Add SIOCGCANERRORS so a socket can read fault confinement, TEC/REC, a
monotonic bus error count and the RX mailbox overrun count. SIOCGCANSTATE
reports sleep/operational, not fault confinement, hence a new command.
The error count is sampled from the clear-on-read ESR1 error flags at
every driver entry rather than from ERRINT, which fires per error frame
and storms at bus rate once the bus is dead. Frames the CAN socket layer
drops for want of an IOB now count as rx_dropped in the netdev
statistics as well as in the global CAN statistics.

Tested on an i.MX RT1176 (ARK FMU-v6XRT) running PX4 with two DroneCAN
nodes: unplugging one node the ioctl reports error-passive, TEC 128,
REC 0 and a monotonic error count, matching ECR/ESR1 read over SWD at
20 Hz, while the other interface stays error-active with zero errors.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Whitespace only: blank lines after declarations, misindented switch
bodies and brace alignment. nxstyle runs over the whole of any file a
change touches, and merging the CAN ioctl options renames a config in
every SocketCAN driver.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
@dakejahl
dakejahl force-pushed the dakejahl/imxrt-flexcan-errors branch from 3f3a38b to 1a8dfc8 Compare August 30, 2026 20:40
@github-actions github-actions Bot added Arch: arm64 Issues related to ARM64 (64-bit) architecture Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Board: arm Board: simulator and removed Size: M The size of the change in this PR is medium labels Aug 30, 2026
dakejahl added a commit to PX4/NuttX that referenced this pull request Aug 30, 2026
The SIOCxCANxxFILTER cases in fdcan_netdev_ioctl() call
stm32_addextfilter(), stm32_delextfilter(), stm32_addstdfilter() and
stm32_delstdfilter(), none of which exist anywhere in the tree. The
block only ever compiled because no stm32h7 config enables
NETDEV_CAN_FILTER_IOCTL; enabling it breaks the link. The commands now
fall through to the existing -ENOTSUP default, which is also what a
caller observed before.

Backport of the same commit on apache/nuttx#20008.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
dakejahl added a commit to PX4/NuttX that referenced this pull request Aug 30, 2026
… NETDEV_CAN_IOCTL.

NETDEV_CAN_BITRATE_IOCTL, NETDEV_CAN_FILTER_IOCTL and
NETDEV_CAN_ERROR_IOCTL guarded identical option blocks, and every
SIOCxCANxxx case in netdev_ifr_ioctl() forwarded a member of the same
ifr_ifru union to d_ioctl(). One option and one case block now cover
all of the CAN commands; drivers and defconfigs are updated to the
new name.

Backport of the same commit on apache/nuttx#20008, requested in its
review. This tree has no NETDEV_CAN_STATE_IOCTL, and the case block
keeps the netdev_ifr_dev() lookup pattern of this branch.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
dakejahl added a commit to PX4/NuttX that referenced this pull request Aug 31, 2026
The SIOCxCANxxFILTER cases in fdcan_netdev_ioctl() call
stm32_addextfilter(), stm32_delextfilter(), stm32_addstdfilter() and
stm32_delstdfilter(), none of which exist anywhere in the tree. The
block only ever compiled because no stm32h7 config enables
NETDEV_CAN_FILTER_IOCTL; enabling it breaks the link. The commands now
fall through to the existing -ENOTSUP default, which is also what a
caller observed before.

Backport of the same commit on apache/nuttx#20008.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
dakejahl added a commit to PX4/NuttX that referenced this pull request Aug 31, 2026
… NETDEV_CAN_IOCTL.

NETDEV_CAN_BITRATE_IOCTL and NETDEV_CAN_FILTER_IOCTL guarded
identical option blocks, and every SIOCxCANxxx case in
netdev_ifr_ioctl() forwarded a member of the same ifr_ifru union
to d_ioctl(). One option and one case block now cover all of the
CAN commands; drivers and defconfigs are updated to the new name.

Backport of the same commit on apache/nuttx#20008, requested in its
review. This tree has no NETDEV_CAN_STATE_IOCTL, and the case block
keeps the netdev_ifr_dev() lookup pattern of this branch.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
dakejahl added a commit to PX4/NuttX that referenced this pull request Aug 31, 2026
…ERRORS.

TX-complete and the deadline watchdog each queued their own callback on
the same work_s, and work_queue() cancels whatever is pending when a
work_s is reused, so whichever ran second was dropped: deadlines were
left set, the TX interrupt mask stayed off, or expired frames were never
aborted. Both now queue imxrt_tx_work(), which retires completions
before it aborts expired mailboxes.

Add SIOCGCANERRORS so a socket can read fault confinement, TEC/REC, a
monotonic bus error count and the RX mailbox overrun count. SIOCGCANSTATE
reports sleep/operational, not fault confinement, hence a new command.
The error count is sampled from the clear-on-read ESR1 error flags at
every driver entry rather than from ERRINT, which fires per error frame
and storms at bus rate once the bus is dead. Frames the CAN socket layer
drops for want of an IOB now count as rx_dropped in the netdev
statistics as well as in the global CAN statistics.

Tested on an i.MX RT1176 (ARK FMU-v6XRT) running PX4 with two DroneCAN
nodes: unplugging one node the ioctl reports error-passive, TEC 128,
REC 0 and a monotonic error count, matching ECR/ESR1 read over SWD at
20 Hz, while the other interface stays error-active with zero errors.

Upstream: apache/nuttx#20008

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Arch: arm64 Issues related to ARM64 (64-bit) architecture Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Area: Networking Effects networking subsystem Board: arm Board: simulator Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants