[PATCH can-next 11/13] can: gs_usb: implement CAN_CTRLMODE_BERR_REPORTING for devices without native support

From: Marc Kleine-Budde

Date: Mon Jul 20 2026 - 10:25:15 EST


RX or TX problems on the CAN bus are signaled by the controller in the form
of CAN bus error. Each bus error increases the CAN error
counters (successful RX or TX decreases the counters). When certain limits
are crossed the controller changes into a different state.

As CAN bus errors might come at a very high rate (>1 KHz), they are
disabled in Linux by default.

Commit 2f3cdad1c616 ("can: gs_usb: add ability to enable / disable berr
reporting") added support to disable CAN bus error reporting if the
firmware supports it. The candlelight firmware recently added support for
this.

Implement CAN_CTRLMODE_BERR_REPORTING for devices that don't support
disabling CAN bus error reporting.

In gs_usb_receive_bulk_callback(), check if the driver received a CAN error
message. If CAN bus error reporting is disabled, drop CAN bus errors, but
process CAN state changes.

Unconditionally announce that the driver supports CAN bus error reporting
by setting CAN_CTRLMODE_BERR_REPORTING in ctrlmode_supported. But only
request CAN bus error reporting from the device if the firmware supports
it and the user space has configured it.

Link: https://github.com/candle-usb/candleLight_fw/pull/303
Signed-off-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx>
---
drivers/net/can/usb/gs_usb.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 186abc95c977..bc69e6b3c512 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -724,7 +724,8 @@ gs_usb_should_handle_can_error(const struct gs_can *dev, const struct gs_host_fr
return true;

/* handle CAN bus errors */
- if (hf->can_id & cpu_to_le32(CAN_ERR_LOSTARB | CAN_ERR_PROT | CAN_ERR_TRX | CAN_ERR_ACK))
+ if (dev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING &&
+ hf->can_id & cpu_to_le32(CAN_ERR_LOSTARB | CAN_ERR_PROT | CAN_ERR_TRX | CAN_ERR_ACK))
return true;

return false;
@@ -1182,7 +1183,7 @@ static int gs_can_open(struct net_device *netdev)
if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
flags |= GS_CAN_FEATURE_ONE_SHOT;

- if (ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+ if (ctrlmode & CAN_CTRLMODE_BERR_REPORTING && dev->feature & GS_CAN_FEATURE_BERR_REPORTING)
flags |= GS_CAN_FEATURE_BERR_REPORTING;

if (ctrlmode & CAN_CTRLMODE_FD)
@@ -1519,7 +1520,8 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->can.clock.freq = le32_to_cpu(bt_const.fclk_can);
dev->can.bittiming_const = &dev->bt_const;

- dev->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC;
+ dev->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING |
+ CAN_CTRLMODE_CC_LEN8_DLC;

feature = le32_to_cpu(bt_const.feature);
dev->feature = FIELD_GET(GS_CAN_FEATURE_MASK, feature);
@@ -1621,9 +1623,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
}
}

- if (feature & GS_CAN_FEATURE_BERR_REPORTING)
- dev->can.ctrlmode_supported |= CAN_CTRLMODE_BERR_REPORTING;
-
if (feature & GS_CAN_FEATURE_GET_STATE)
dev->can.do_get_berr_counter = gs_usb_can_get_berr_counter;


--
2.53.0