* [PATCH net-next 0/37] pull-request: can-next 2026-10-09
@ 2026-10-09 13:27 Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
` (37 more replies)
0 siblings, 38 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel
Hello netdev-team,
this is a pull request of 37 patches for net-next/main.
The first patch is by Vincent Mailhol and drops CAN-XL frames on non
CAN-XL devices.
A patch by Sang-Heon Jeon removes a redundant NULL check before
netdev_hold() in the CAN RAW protocol.
Oliver Hartkopp's patch converts the unreliable ARPHRD_CAN type check
to the robust can_get_ml_priv().
A patch by Runyu Xiao for CAN proc resets the pkg_stats using atomics
individually. Oliver Hartkopp also contributes a patch for the CAN
proc to remove kernel pointers from the output.
Tetsuo Handa's patch cancels pending address claim timers in
j1939_ecu_unmap_all().
A patch by Kaixuan Li for the CAN ISOTP protocol improves the check
for the correct CAN CC/FD frames.
The next 3 patches are by Cunhao Lu and make CAN skb freeing safe in
any context in several CAN helper functions.
Claudiu Beznea contributes 5 patches for the rcar_canfd driver to add
support for Renesas RZ/G3S.
Krzysztof Kozlowski's patch updates the renesas,rcar-canfd DT bindings
to restrict the resets in top-level.
Biju Das's series of 3 patches add support for Renesas RZ/G3L CANFD to
the rcar_canfd driver.
Quchaosheng contributes 2 patches to convert the gr_can DR bindings to
DT schema.
Triet Hoang's patch converts several drivers to
DEFINE_SIMPLE_DEV_PM_OPS().
The next 2 patches target the cc770 driver and are by Chaosheng Qu.
They fix error propagation in cc770_platform_probe() and fix a clock
divider check.
A patch by me for the esd driver fixes a potential use-after-free
originated in the acc_start_xmit() function.
Wentao Liang's patch for the flexcan driver fixes a OF node reference
leak in flexcan_setup_stop_mode_gpr().
Ji-Ze Hong contributes a patch for the f81604 driver to fix
use-after-free on disconnect.
A patch by Runyu Xiao fixes a potential deadlock in the error path of
the hi311x CAN driver.
Anton Olsson's patch for the kvaser_usb driver refactors the endpoint
lookup, while Cen Zhang's patch validates the command format before
parsing in the hydra receive path.
A patch by Fan Wu for the kvaser_pciefd driver fixes a use-after-free
in bec poll timer.
Jiale Yao's patch for the mcp251xfd driver rejects devices without
match data.
The next patch by Wentao Liang fixes a clk leak in the error path of
the sun4ican_probe()'s function.
Hemanth Selam's patch for the ucan driver fixes a repeated word 'is'
in a comment.
Maximilian Zimmermann's patch for the xilinx CAN driver adds the
setting the ESI and BSR flags in the receive path if they are active.
regards,
Marc
The following changes since commit d8674294aefef02266c4d47ad10131f1bffbe534:
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-10-08 22:21:56 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git tags/linux-can-next-for-7.4-20261009
for you to fetch changes up to ec2634225bf22a34a79e6557fd34cdf1282658c7:
can: xilinx_can: set CAN FD flags on received frames (2026-10-09 15:24:54 +0200)
----------------------------------------------------------------
linux-can-next-for-7.4-20261009
----------------------------------------------------------------
Anton Olsson (1):
can: kvaser_usb: refactor endpoint lookup
Biju Das (3):
dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC
can: rcar_canfd: Derive max_channels from the device tree
can: rcar_canfd: Add support for Renesas RZ/G3L
Cen Zhang (Microsoft Security FORGE Labs) (1):
can: kvaser_usb: validate command format before parsing in hydra receive path
Chaosheng Qu (1):
can: cc770: don't discard the IRQ lookup error in probe
Claudiu Beznea (5):
dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC
can: rcar_canfd: Fix typos in macro names
can: rcar_canfd: Allow the CAN FD clock to be sourced from fck
can: rcar_canfd: Do not set registers selecting the CAN mode
can: rcar_canfd: Add support for Renesas RZ/G3S
Cunhao Lu (3):
can: skb: make echo skb freeing safe in any IRQ context
can: skb: make CAN skb allocation failure paths IRQ-safe
can: dev: can_put_echo_skb(): free skb on invalid echo index
Fan Wu (2):
can: ems_usb: use usb_kill_urb() to stop the intr URB
can: kvaser_pciefd: fix use-after-free in bec poll timer
Hemanth Selam (1):
can: ucan: fix repeated word 'is' in comment
Ji-Ze Hong (Peter Hong) (1):
can: f81604: f81604_close(): fix use-after-free on disconnect
Jiale Yao (1):
can: mcp251xfd: mcp251xfd_probe(): reject devices without match data
Kaixuan Li (1):
can: isotp: check the frame type, not just the length
Krzysztof Kozlowski (1):
dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level
Marc Kleine-Budde (5):
Merge patch series "can: skb: make echo skb freeing safe in any IRQ context"
Merge patch series "can: rcar_canfd: Add support for Renesas RZ/G3S"
Merge patch series "Add support for Renesas RZ/G3L CANFD"
Merge patch series "dt-bindings: net: can: grcan: convert to DT schema"
can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb()
Maximilian Zimmermann (1):
can: xilinx_can: set CAN FD flags on received frames
Oliver Hartkopp (3):
can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()
can: proc: remove pointers from CAN specific proc output
can: remove Softing CANcard driver
Quchaosheng (3):
dt-bindings: net: can: convert grcan to DT schema
can: grcan: update the binding file reference in the driver comment
can: cc770: fix the clock divider check on the platform bus
Runyu Xiao (2):
can: proc: reset pkg_stats atomics individually
can: hi311x: drop hi3110_lock before free_irq() on open failure
Sang-Heon Jeon (1):
can: raw: remove redundant NULL check before netdev_hold()
Tetsuo Handa (1):
can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all()
Triet Hoang (1):
can: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
Vincent Mailhol (1):
can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
Wentao Liang (2):
can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak
can: sun4i_can: sun4ican_probe(): fix clk leak
.../bindings/net/can/aeroflexgaisler,grcan.yaml | 65 ++
.../devicetree/bindings/net/can/grcan.txt | 28 -
.../bindings/net/can/renesas,rcar-canfd.yaml | 50 +-
Documentation/networking/can.rst | 14 +-
drivers/net/can/Kconfig | 1 -
drivers/net/can/Makefile | 1 -
drivers/net/can/bxcan.c | 8 +-
drivers/net/can/cc770/cc770_platform.c | 9 +-
drivers/net/can/ctucanfd/ctucanfd.h | 4 +-
drivers/net/can/ctucanfd/ctucanfd_pci.c | 4 +-
drivers/net/can/ctucanfd/ctucanfd_platform.c | 4 +-
drivers/net/can/dev/skb.c | 16 +-
drivers/net/can/esd/esdacc.c | 12 +-
drivers/net/can/flexcan/flexcan-core.c | 1 +
drivers/net/can/grcan.c | 4 +-
drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c | 3 +-
drivers/net/can/m_can/m_can_pci.c | 8 +-
drivers/net/can/rcar/rcar_canfd.c | 103 ++-
drivers/net/can/softing/Kconfig | 31 -
drivers/net/can/softing/Makefile | 5 -
drivers/net/can/softing/softing.h | 168 ----
drivers/net/can/softing/softing_cs.c | 335 --------
drivers/net/can/softing/softing_fw.c | 700 -----------------
drivers/net/can/softing/softing_main.c | 864 ---------------------
drivers/net/can/softing/softing_platform.h | 41 -
drivers/net/can/spi/hi311x.c | 11 +-
drivers/net/can/spi/mcp251x.c | 8 +-
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 7 +-
drivers/net/can/sun4i_can.c | 8 +-
drivers/net/can/usb/ems_usb.c | 2 +-
drivers/net/can/usb/f81604.c | 2 +-
drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 2 -
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 19 +-
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 165 +++-
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 17 -
drivers/net/can/usb/ucan.c | 2 +-
drivers/net/can/xilinx_can.c | 6 +
include/linux/can/core.h | 2 +-
include/linux/can/dev.h | 2 +-
include/linux/can/skb.h | 4 +-
net/can/af_can.c | 21 +-
net/can/af_can.h | 2 +-
net/can/bcm.c | 23 +-
net/can/gw.c | 9 +-
net/can/isotp.c | 17 +-
net/can/j1939/bus.c | 30 +
net/can/j1939/main.c | 2 +-
net/can/proc.c | 43 +-
net/can/raw.c | 11 +-
49 files changed, 520 insertions(+), 2374 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/can/aeroflexgaisler,grcan.yaml
delete mode 100644 Documentation/devicetree/bindings/net/can/grcan.txt
delete mode 100644 drivers/net/can/softing/Kconfig
delete mode 100644 drivers/net/can/softing/Makefile
delete mode 100644 drivers/net/can/softing/softing.h
delete mode 100644 drivers/net/can/softing/softing_cs.c
delete mode 100644 drivers/net/can/softing/softing_fw.c
delete mode 100644 drivers/net/can/softing/softing_main.c
delete mode 100644 drivers/net/can/softing/softing_platform.h
^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
` (36 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Vincent Mailhol, stable,
Marc Kleine-Budde
From: Vincent Mailhol <mailhol@kernel.org>
Sending a PF_PACKET bypasses the CAN framework logic and can directly
reach a CAN driver's xmit() function. The PF_PACKET framework only
checks that skb->len does not exceed the net_device MTU.
For a CAN device that is not CAN XL capable, anything above CANFD_MTU
(72 bytes) is therefore dropped before it reaches the driver. However,
CAN XL frames are variable length. can_is_canxl_skb() accepts lengths in
the range CANXL_HDR_SIZE + CANXL_MIN_DLEN up to CANXL_MTU, i.e. 13 to
2060 bytes.
As a result, an ETH_P_CANXL skb with a length between 13 and 72 bytes
can pass both the MTU and the can_dropped_invalid_skb() checks.
A driver that does not support CAN XL will interpret canxl_frame->flags
as a length because of the overlap with can_frame->len. And because
CANXL_XLF is set, the resulting length is between 128 and 255. For
drivers that do not check can_frame->len before copying can_frame->data,
as most drivers do, this results in a buffer overflow of up to 247
bytes.
Drop ETH_P_CANXL skbs if the device does not have the CAN_CAP_XL
capability. Keep can_is_canxl_skb() for the validation of CAN XL skbs.
Closes: https://sashiko.dev/#/patchset/20260731-master-v5-0-5b27029dee20@qq.com?part=1
Fixes: fb08cba12b52 ("can: canxl: update CAN infrastructure for CAN XL frames")
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Link: https://patch.msgid.link/20260731-drop_canxl_frames-v1-1-7387b70353b3@kernel.org
Cc: stable@kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/dev/skb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 14edec5afb57..bc0787535b52 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -4,6 +4,7 @@
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
*/
+#include <linux/can/can-ml.h>
#include <linux/can/dev.h>
#include <linux/module.h>
#include <net/can.h>
@@ -388,7 +389,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
break;
case ETH_P_CANXL:
- if (!can_is_canxl_skb(skb))
+ if (!can_cap_enabled(dev, CAN_CAP_XL) || !can_is_canxl_skb(skb))
goto inval_skb;
break;
base-commit: d8674294aefef02266c4d47ad10131f1bffbe534
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold()
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 03/37] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv() Marc Kleine-Budde
` (35 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Sang-Heon Jeon, Oliver Hartkopp,
Marc Kleine-Budde
From: Sang-Heon Jeon <ekffu200098@gmail.com>
netdev_hold() does nothing if dev is NULL, so the check before the call
is redundant.
So remove it. No functional change.
This is the result of running the Coccinelle script from
scripts/coccinelle/free/ifnulldev_put.cocci after commit f83b8a58695c
("coccinelle: ifnulldev_put: update outdated helper names").
Signed-off-by: Sang-Heon Jeon <ekffu200098@gmail.com>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260831052031.902699-1-ekffu200098@gmail.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/raw.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/can/raw.c b/net/can/raw.c
index 0acd4f6c6dd6..6944ebab3feb 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -529,8 +529,7 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
ro->bound = 1;
/* bind() ok -> hold a reference for new ro->dev */
ro->dev = dev;
- if (ro->dev)
- netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL);
+ netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL);
}
out_put_dev:
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 03/37] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
` (34 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, stable,
Oleksij Rempel, Marc Kleine-Budde
From: Oliver Hartkopp <socketcan@hartkopp.net>
Commit 4e096a18867a ("net: introduce CAN specific pointer in the struct
net_device") introduced an explicit way to assign the midlayer private
pointer (dev->ml_priv) to named users like ML_PRIV_CAN.
With this extension the CAN device specific ml_priv assignment became a
robust indicator to identify a valid CAN device, when can_get_ml_priv()
returns a valid pointer.
This has been used directly by the referenced commit in the CAN specific
j1939 and proc code but not in the other parts of the CAN subsystem.
With the TUN/TAP driver a device's ARPHRD type can be controlled by
userspace independently of its midlayer private data (ml_priv). The
TUNSETLINK ioctl allows a down TUN/TAP device to overwrite its hardware
type to become ARPHRD_CAN while dev->ml_priv remains NULL (uninitialized).
Instead of checking dev->type being the unreliable ARPHRD_CAN value convert
the missing "valid CAN devices" checks to can_get_ml_priv().
Fixes: 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device")
Cc: stable@kernel.org
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261009121115.61012-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/af_can.c | 15 ++++++---------
net/can/bcm.c | 7 ++++---
net/can/gw.c | 7 ++++---
net/can/isotp.c | 5 +++--
net/can/raw.c | 4 ++--
5 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 34fe3b28d576..dc27ace43719 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -226,7 +226,7 @@ int can_send(struct sk_buff *skb, int loop)
goto inval_skb;
}
- if (unlikely(skb->dev->type != ARPHRD_CAN)) {
+ if (unlikely(!can_get_ml_priv(skb->dev))) {
err = -EPERM;
goto inval_skb;
}
@@ -452,7 +452,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
/* insert new receiver (dev,canid,mask) -> (func,data) */
- if (dev && (dev->type != ARPHRD_CAN || !can_get_ml_priv(dev)))
+ if (dev && !can_get_ml_priv(dev))
return -ENODEV;
if (dev && !net_eq(net, dev_net(dev)))
@@ -519,7 +519,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
struct can_dev_rcv_lists *dev_rcv_lists;
- if (dev && dev->type != ARPHRD_CAN)
+ if (dev && !can_get_ml_priv(dev))
return;
if (dev && !net_eq(net, dev_net(dev)))
@@ -684,8 +684,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
- if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
- !csx || !can_is_can_skb(skb))) {
+ if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_can_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@@ -710,8 +709,7 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
- if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
- !csx || !can_is_canfd_skb(skb))) {
+ if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canfd_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@@ -736,8 +734,7 @@ static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
- if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
- !csx || !can_is_canxl_skb(skb))) {
+ if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canxl_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
dev->type, skb->len);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 3d637a1e0ac1..60406439a13f 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -54,6 +54,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
+#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/bcm.h>
@@ -1719,7 +1720,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
goto out_release;
}
- if (dev->type != ARPHRD_CAN) {
+ if (!can_get_ml_priv(dev)) {
dev_put(dev);
ret = -ENODEV;
goto out_release;
@@ -1867,7 +1868,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- if (dev->type != ARPHRD_CAN)
+ if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
@@ -2024,7 +2025,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
ret = -ENODEV;
goto fail;
}
- if (dev->type != ARPHRD_CAN) {
+ if (!can_get_ml_priv(dev)) {
dev_put(dev);
ret = -ENODEV;
goto fail;
diff --git a/net/can/gw.c b/net/can/gw.c
index 5793cb2420ed..54bb5bd3242a 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -52,6 +52,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
+#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/gw.h>
@@ -612,7 +613,7 @@ static int cgw_notifier(struct notifier_block *nb,
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct net *net = dev_net(dev);
- if (dev->type != ARPHRD_CAN)
+ if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg == NETDEV_UNREGISTER) {
@@ -1163,7 +1164,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!gwj->src.dev)
goto out;
- if (gwj->src.dev->type != ARPHRD_CAN)
+ if (!can_get_ml_priv(gwj->src.dev))
goto out;
gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
@@ -1171,7 +1172,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!gwj->dst.dev)
goto out;
- if (gwj->dst.dev->type != ARPHRD_CAN)
+ if (!can_get_ml_priv(gwj->dst.dev))
goto out;
/* is sending the skb back to the incoming interface intended? */
diff --git a/net/can/isotp.c b/net/can/isotp.c
index f5dc9d04bd68..6c28802c0605 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -65,6 +65,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
+#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/isotp.h>
@@ -1610,7 +1611,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
err = -ENODEV;
goto out;
}
- if (dev->type != ARPHRD_CAN) {
+ if (!can_get_ml_priv(dev)) {
err = -ENODEV;
goto out_put_dev;
}
@@ -1897,7 +1898,7 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- if (dev->type != ARPHRD_CAN)
+ if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
diff --git a/net/can/raw.c b/net/can/raw.c
index 6944ebab3feb..ad611906b308 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -348,7 +348,7 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- if (dev->type != ARPHRD_CAN)
+ if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
@@ -491,7 +491,7 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
err = -ENODEV;
goto out;
}
- if (dev->type != ARPHRD_CAN) {
+ if (!can_get_ml_priv(dev)) {
err = -ENODEV;
goto out_put_dev;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (2 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 03/37] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv() Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
` (33 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Runyu Xiao, stable,
Oliver Hartkopp, Marc Kleine-Budde
From: Runyu Xiao <runyu.xiao@seu.edu.cn>
Commit 80b5f90158d1 ("can: statistics: use atomic access in hot path")
converted several members of struct can_pkg_stats to atomic_long_t and
updated the hot TX/RX and procfs read paths to use atomic_long_*()
helpers. However, can_init_stats() still clears the whole struct with
memset().
can_init_stats() is reached from can_stat_update() in timer context and
also from the procfs reset path. Those paths can run while the TX/RX hot
paths are concurrently updating rx_frames, tx_frames, matches and their
*_delta counters. Hitting the whole-struct memset() in that window
performs plain writes to fields that otherwise follow an atomic_long_t
access contract, which can lose or mix live statistics updates.
This issue was found by source-level API-misuse analysis looking for
whole-object resets left behind after atomic_long_t conversions, then
manually audited on Linux v6.18.21.
Replace the whole-struct memset() with a helper that resets the
atomic_long_t counters via atomic_long_set() and clears the derived
scalar statistics explicitly. This preserves the existing reset
semantics for scalar fields while restoring atomic access discipline for
the live counters.
Build-tested by compiling net/can/proc.o on x86_64 netdev/main.
Runtime-tested with a QEMU + vcan setup on Linux v6.18.21 by driving
concurrent traffic and reset_stats reads, which reproduced inconsistent
exported statistics before the fix.
Fixes: 80b5f90158d1 ("can: statistics: use atomic access in hot path")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260512133937.21957-1-runyu.xiao@seu.edu.cn
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/proc.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/net/can/proc.c b/net/can/proc.c
index de4d05ae3459..64b3bdc2fa7e 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -76,16 +76,39 @@ static const char rx_list_name[][8] = {
* af_can statistics stuff
*/
+static void can_reset_pkg_stats(struct can_pkg_stats *pkg_stats)
+{
+ atomic_long_set(&pkg_stats->rx_frames, 0);
+ atomic_long_set(&pkg_stats->tx_frames, 0);
+ atomic_long_set(&pkg_stats->matches, 0);
+
+ pkg_stats->total_rx_rate = 0;
+ pkg_stats->total_tx_rate = 0;
+ pkg_stats->total_rx_match_ratio = 0;
+
+ pkg_stats->current_rx_rate = 0;
+ pkg_stats->current_tx_rate = 0;
+ pkg_stats->current_rx_match_ratio = 0;
+
+ pkg_stats->max_rx_rate = 0;
+ pkg_stats->max_tx_rate = 0;
+ pkg_stats->max_rx_match_ratio = 0;
+
+ atomic_long_set(&pkg_stats->rx_frames_delta, 0);
+ atomic_long_set(&pkg_stats->tx_frames_delta, 0);
+ atomic_long_set(&pkg_stats->matches_delta, 0);
+}
+
static void can_init_stats(struct net *net)
{
struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
/*
- * This memset function is called from a timer context (when
+ * This stats reset is called from a timer context (when
* can_stattimer is active which is the default) OR in a process
* context (reading the proc_fs when can_stattimer is disabled).
*/
- memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
+ can_reset_pkg_stats(pkg_stats);
pkg_stats->jiffies_init = jiffies;
rcv_lists_stats->stats_reset++;
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (3 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 06/37] can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all() Marc Kleine-Budde
` (32 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp,
Sebastian Andrzej Siewior, Marc Kleine-Budde
From: Oliver Hartkopp <socketcan@hartkopp.net>
The proc content in /proc/net/can/ and /proc/net/can-bcm/ is intended to
check the internal filter lists (af_can, can_raw) and the efficiency and
functionality of can_bcm jobs. While it was ok to leak kernel internal
addresses at time of writing the times have changed and multiple attempts
have been taken to hash or remove such now sensible data.
This patch removes the disclosure of pointers and instead provides the
function names and sock inode numbers when available. As there's no known
tooling around the CAN specific proc output breaking the ABI with this
rework creates no issue.
Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://patch.msgid.link/20260815103400.117175-1-socketcan@hartkopp.net
[mkl: fix checkpatch warning]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
Documentation/networking/can.rst | 14 +++++++-------
include/linux/can/core.h | 2 +-
net/can/af_can.c | 6 +++---
net/can/af_can.h | 2 +-
net/can/bcm.c | 16 ++++++++--------
net/can/gw.c | 2 +-
net/can/isotp.c | 4 ++--
net/can/j1939/main.c | 2 +-
net/can/proc.c | 16 ++++++----------
net/can/raw.c | 4 ++--
10 files changed, 32 insertions(+), 36 deletions(-)
diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
index 536ff411da1d..7bdb27a22a0e 100644
--- a/Documentation/networking/can.rst
+++ b/Documentation/networking/can.rst
@@ -1042,15 +1042,15 @@ receive lists, their filters and the count of filter matches can be
checked in the appropriate receive list. All entries contain the
device and a protocol module identifier::
- foo@bar:~$ cat /proc/net/can/rcvlist_all
+ foo@bar:~$ cat /proc/net/can/rcvlist_fil
- receive list 'rx_all':
- (vcan3: no entry)
- (vcan2: no entry)
- (vcan1: no entry)
- device can_id can_mask function userdata matches ident
- vcan0 000 00000000 f88e6370 f6c6f400 0 raw
+ receive list 'rx_fil':
(any: no entry)
+ device can_id can_mask matches sock_inode function
+ vcan0 80000123 c00007ff 0 000000000000f862 raw_rcv [can_raw]
+ (vcan1: no entry)
+ (vcan2: no entry)
+ (vcan3: no entry)
In this example an application requests any CAN traffic from vcan0::
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 2de74c2b78b6..effb5c31ef40 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -51,7 +51,7 @@ extern void can_proto_unregister(const struct can_proto *cp);
int can_rx_register(struct net *net, struct net_device *dev,
canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *),
- void *data, char *ident, struct sock *sk);
+ void *data, u64 ino, struct sock *sk);
extern void can_rx_unregister(struct net *net, struct net_device *dev,
canid_t can_id, canid_t mask,
diff --git a/net/can/af_can.c b/net/can/af_can.c
index dc27ace43719..d97f85fc3232 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -418,7 +418,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask,
* @mask: CAN mask (see description)
* @func: callback function on filter match
* @data: returned parameter for callback function
- * @ident: string for calling module identification
+ * @ino: inode number of sock (0 = unknown)
* @sk: socket pointer (might be NULL)
*
* Description:
@@ -443,7 +443,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask,
*/
int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
canid_t mask, void (*func)(struct sk_buff *, void *),
- void *data, char *ident, struct sock *sk)
+ void *data, u64 ino, struct sock *sk)
{
struct receiver *rcv;
struct hlist_head *rcv_list;
@@ -472,7 +472,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
atomic_long_set(&rcv->matches, 0);
rcv->func = func;
rcv->data = data;
- rcv->ident = ident;
+ rcv->ino = ino;
rcv->sk = sk;
hlist_add_head_rcu(&rcv->list, rcv_list);
diff --git a/net/can/af_can.h b/net/can/af_can.h
index 87887014f562..6e593ed5db5f 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -55,7 +55,7 @@ struct receiver {
atomic_long_t matches;
void (*func)(struct sk_buff *skb, void *data);
void *data;
- char *ident;
+ u64 ino;
struct sock *sk;
struct rcu_head rcu;
};
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 60406439a13f..cb6a3d4cb076 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -144,7 +144,7 @@ struct bcm_sock {
struct list_head tx_ops;
unsigned long dropped_usr_msgs;
struct proc_dir_entry *bcm_proc_read;
- char procname [32]; /* inode number in decimal with \0 */
+ char procname[18]; /* inode number in hex with \0 */
};
static LIST_HEAD(bcm_notifier_list);
@@ -221,9 +221,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
struct bcm_sock *bo = bcm_sk(sk);
struct bcm_op *op;
- seq_printf(m, ">>> socket %pK", sk->sk_socket);
- seq_printf(m, " / sk %pK", sk);
- seq_printf(m, " / bo %pK", bo);
+ seq_printf(m, ">>> sock inode %s", bo->procname);
seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
seq_printf(m, " <<<\n");
@@ -1537,7 +1535,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op,
- "bcm", sk);
+ sock_i_ino(sk), sk);
/* keep a tracked reference so that a later
* unregister can safely reach the device even
@@ -1561,7 +1559,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
} else {
err = can_rx_register(sock_net(sk), NULL, op->can_id,
REGMASK(op->can_id),
- bcm_rx_handler, op, "bcm", sk);
+ bcm_rx_handler, op,
+ sock_i_ino(sk), sk);
}
if (err) {
@@ -2041,8 +2040,9 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
#if IS_ENABLED(CONFIG_PROC_FS)
if (net->can.bcmproc_dir) {
- /* unique socket address as filename */
- sprintf(bo->procname, "%llu", sock_i_ino(sk));
+ /* use unique socket inode number as filename */
+ snprintf(bo->procname, sizeof(bo->procname),
+ "%016llx", sock_i_ino(sk));
bo->bcm_proc_read = proc_create_net_single(bo->procname, 0644,
net->can.bcmproc_dir,
bcm_proc_show, sk);
diff --git a/net/can/gw.c b/net/can/gw.c
index 54bb5bd3242a..8a5327d8a00e 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -580,7 +580,7 @@ static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
{
return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
- gwj, "gw", NULL);
+ gwj, 0, NULL);
}
static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
diff --git a/net/can/isotp.c b/net/can/isotp.c
index 6c28802c0605..1a272ce6a2bd 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -1626,14 +1626,14 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
if (isotp_register_rxid(so))
can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
- isotp_rcv, sk, "isotp", sk);
+ isotp_rcv, sk, sock_i_ino(sk), sk);
/* no consecutive frame echo skb in flight */
WRITE_ONCE(so->cfecho, 0);
/* register for echo skb's */
can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
- isotp_rcv_echo, sk, "isotpe", sk);
+ isotp_rcv_echo, sk, sock_i_ino(sk), sk);
/* switch to new settings */
so->ifindex = ifindex;
diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
index 5e5e6c228f22..d9384cf0e356 100644
--- a/net/can/j1939/main.c
+++ b/net/can/j1939/main.c
@@ -184,7 +184,7 @@ static int j1939_can_rx_register(struct j1939_priv *priv)
j1939_priv_get(priv);
ret = can_rx_register(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK,
- j1939_can_recv, priv, "j1939", NULL);
+ j1939_can_recv, priv, 0, NULL);
if (ret < 0) {
j1939_priv_put(priv);
return ret;
diff --git a/net/can/proc.c b/net/can/proc.c
index 64b3bdc2fa7e..33d99543e3fe 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -215,25 +215,21 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
hlist_for_each_entry_rcu(r, rx_list, list) {
char *fmt = (r->can_id & CAN_EFF_FLAG)?
- " %-5s %08x %08x %pK %pK %8ld %s\n" :
- " %-5s %03x %08x %pK %pK %8ld %s\n";
+ " %6s %08x %08x %8ld %016llx %ps\n" :
+ " %6s %03x %08x %8ld %016llx %ps\n";
seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
- r->func, r->data, atomic_long_read(&r->matches),
- r->ident);
+ atomic_long_read(&r->matches), r->ino, r->func);
}
}
static void can_print_recv_banner(struct seq_file *m)
{
/*
- * can1. 00000000 00000000 00000000
- * ....... 0 tp20
+ * device can_id can_mask matches sock_inode function
+ * vcan0 80000123 c00007ff 0 000000000000ab16 raw_rcv [can_raw]
*/
- if (IS_ENABLED(CONFIG_64BIT))
- seq_puts(m, " device can_id can_mask function userdata matches ident\n");
- else
- seq_puts(m, " device can_id can_mask function userdata matches ident\n");
+ seq_puts(m, " device can_id can_mask matches sock_inode function\n");
}
static int can_stats_proc_show(struct seq_file *m, void *v)
diff --git a/net/can/raw.c b/net/can/raw.c
index ad611906b308..dfea48768b23 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -226,7 +226,7 @@ static int raw_enable_filters(struct net *net, struct net_device *dev,
for (i = 0; i < count; i++) {
err = can_rx_register(net, dev, filter[i].can_id,
filter[i].can_mask,
- raw_rcv, sk, "raw", sk);
+ raw_rcv, sk, sock_i_ino(sk), sk);
if (err) {
/* clean up successfully registered filters */
while (--i >= 0)
@@ -247,7 +247,7 @@ static int raw_enable_errfilter(struct net *net, struct net_device *dev,
if (err_mask)
err = can_rx_register(net, dev, 0, err_mask | CAN_ERR_FLAG,
- raw_rcv, sk, "raw", sk);
+ raw_rcv, sk, sock_i_ino(sk), sk);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 06/37] can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all()
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (4 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 07/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
` (31 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Tetsuo Handa,
syzbot+e2af46126e0644cbebdd, Marc Kleine-Budde
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
syzbot is reporting "struct j1939_ecu" refcount leak, for
j1939_ecu_get(ecu);
priv->ents[ecu->addr] = ecu;
in j1939_ecu_map_locked() from j1939_ecu_timer_handler() can succeed
even after
priv->ents[ecu->addr] = NULL;
j1939_ecu_put(ecu);
in j1939_ecu_unmap_locked() from j1939_ecu_unmap_all() from
__j1939_rx_release() from j1939_netdev_stop() has completed.
unregister_netdevice: waiting for vxcan1 to become free. Usage count = 3
ref_tracker: netdev@ffff8880710f0700 has 1/2 users at
__netdev_tracker_alloc include/linux/netdevice.h:4496 [inline]
netdev_hold include/linux/netdevice.h:4525 [inline]
j1939_ecu_create_locked+0x1c9/0x400 net/can/j1939/bus.c:159
j1939_local_ecu_get+0xeb/0x220 net/can/j1939/bus.c:293
j1939_sk_bind+0x70a/0xc60 net/can/j1939/socket.c:529
__sys_bind_socket net/socket.c:1920 [inline]
__sys_bind+0x2e3/0x410 net/socket.c:1951
__do_sys_bind net/socket.c:1956 [inline]
__se_sys_bind net/socket.c:1954 [inline]
__x64_sys_bind+0x7a/0x90 net/socket.c:1954
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
ref_tracker: netdev@ffff8880710f0700 has 1/2 users at
__netdev_tracker_alloc include/linux/netdevice.h:4496 [inline]
netdev_hold include/linux/netdevice.h:4525 [inline]
j1939_priv_create net/can/j1939/main.c:140 [inline]
j1939_netdev_start+0x387/0xb20 net/can/j1939/main.c:268
j1939_sk_bind+0x946/0xc60 net/can/j1939/socket.c:506
__sys_bind_socket net/socket.c:1920 [inline]
__sys_bind+0x2e3/0x410 net/socket.c:1951
__do_sys_bind net/socket.c:1956 [inline]
__se_sys_bind net/socket.c:1954 [inline]
__x64_sys_bind+0x7a/0x90 net/socket.c:1954
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fix this race condition by canceling address claim timers from
j1939_ecu_unmap_all().
Reported-by: syzbot+e2af46126e0644cbebdd@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e2af46126e0644cbebdd
Assisted-by: Gemini-Pro gpt-6-astra opus-5-5
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Link: https://patch.msgid.link/9ba38419-967a-4d47-bcdf-bbb2fa7d3e9f@I-love.SAKURA.ne.jp
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/j1939/bus.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/net/can/j1939/bus.c b/net/can/j1939/bus.c
index cdc3c0a71937..0d109d1a3b4a 100644
--- a/net/can/j1939/bus.c
+++ b/net/can/j1939/bus.c
@@ -99,8 +99,38 @@ void j1939_ecu_unmap(struct j1939_ecu *ecu)
void j1939_ecu_unmap_all(struct j1939_priv *priv)
{
int i;
+ struct j1939_ecu *ecu;
write_lock_bh(&priv->lock);
+ /* Cancel all pending address claim timers before unmapping.
+ * This prevents an orphaned late-firing timer from re-mapping
+ * an ECU after the spaces are cleared.
+ */
+rescan_timers:
+ list_for_each_entry(ecu, &priv->ecus, list) {
+ int ret = hrtimer_try_to_cancel(&ecu->ac_timer);
+
+ if (ret == 0) { /* Not active or already finished. */
+ continue;
+ } else if (ret == 1) { /* Successfully canceled. */
+ /* Drop a ref from j1939_ecu_timer_start(). */
+ j1939_ecu_put(ecu);
+ } else { /* Executing on another CPU. */
+ /* Let j1939_ecu_timer_cancel() determine whether to
+ * drop a ref from j1939_ecu_timer_start(). But guard
+ * with a local ref in order to make sure that unlocked
+ * j1939_ecu_put() from j1939_ecu_timer_cancel() cannot
+ * be the final reference.
+ */
+ j1939_ecu_get(ecu);
+ write_unlock_bh(&priv->lock);
+ j1939_ecu_timer_cancel(ecu);
+ write_lock_bh(&priv->lock);
+ j1939_ecu_put(ecu);
+ }
+ goto rescan_timers;
+ }
+ /* Unmap any remaining mapped ECUs */
for (i = 0; i < ARRAY_SIZE(priv->ents); i++)
if (priv->ents[i].ecu)
j1939_ecu_unmap_locked(priv->ents[i].ecu);
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 07/37] can: isotp: check the frame type, not just the length
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (5 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 06/37] can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all() Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 08/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
` (30 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Kaixuan Li, Oliver Hartkopp,
Quchaosheng, stable, Marc Kleine-Budde
From: Kaixuan Li <kaixuanli0131@gmail.com>
isotp_rcv() separates Classic CAN from CAN FD by skb->len alone:
if (skb->len != so->ll.mtu)
return;
cf = (struct canfd_frame *)skb->data;
A CAN XL frame with cxl->len 4 is CAN_MTU bytes, so it passes, and is then
read as a canfd_frame whose len comes out of canxl_frame.flags: at least
0x80.
Of the paths that follow, only the flow control one uses that length
without bounding it first, so check_pad() walks to 255 over a 16-byte
frame and the caller reports EBADMSG on an unrelated socket.
bcm_rx_handler(), j1939_can_recv(), can_can_gw_rcv() and raw_rcv() check
the frame type here, and can_dropped_invalid_skb() switches on
skb->protocol on the transmit side. isotp_rcv() is the gap.
Fixes: fb08cba12b52 ("can: canxl: update CAN infrastructure for CAN XL frames")
Signed-off-by: Kaixuan Li <kaixuanli0131@gmail.com>
Reviewed-by: Oliver Hartkopp <socketcan@hartkopp.net>
Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Quchaosheng <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20260920035626.2581040-1-kaixuanli0131@gmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/isotp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/can/isotp.c b/net/can/isotp.c
index 1a272ce6a2bd..5e1c3971ebfc 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -756,6 +756,14 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
if (skb->len != so->ll.mtu)
return;
+ /* check for correct CAN CC/FD frame content */
+ if (so->ll.mtu == CAN_MTU) {
+ if (!can_is_can_skb(skb))
+ return;
+ } else if (!can_is_canfd_skb(skb)) {
+ return;
+ }
+
cf = (struct canfd_frame *)skb->data;
/* if enabled: check reception of my configured extended address */
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 08/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (6 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 07/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 09/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
` (29 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Claudiu Beznea, Rob Herring (Arm),
Geert Uytterhoeven, Marc Kleine-Budde
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
The CAN FD controller found on the Renesas RZ/G3S SoC is largely compatible
with the variant present on the RZ/G3E SoC. The main differences are:
- the RZ/G3S provides only two CAN FD channels
- the RZ/G3S supports only CAN FD operation; the Channel n CAN FD
Configuration Register does not implement the bits used to select
classical CAN-only mode (bit 30) or CAN FD-only mode (bit 28);
consequently, bit 31 (CAN FD Frame Distinction Enable) of the same
register is also not implemented
- some bits in several registers (mainly reserved or status bits) are
read-write on the RZ/G3S but read-only on the RZ/G3E; their behavior is
otherwise identical: the bits read back as 0 on both SoCs and software
is allowed to write only 0 to them on the RZ/G3S
- the RZ/G3S provides 256 acceptance filters, compared to 768 on the
RZ/G3E
- the RZ/G3S can use PCLK clock as the CAN FD clock source through an
internal clock divider, while also supporting an external CAN FD clock
source
Since:
- the SoC clock generator provides to the CAN IP only the peripheral and
the RAM clocks
- when sourced from the peripheral clock, the CAN-FD clock is obtained
inside the IP itself by dividing the peripheral clock
- the assigned-clocks and assigned-clock-rates properties are specific to
the CAN-FD clock
the assigned-clocks and assigned-clock-rates properties were dropped from
the required properties list of the Renesas RZ/G3S SoC.
Add documentation for the Renesas RZ/G3S SoC.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20260902141544.565763-2-claudiu.beznea+renesas@tuxon.dev
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
.../bindings/net/can/renesas,rcar-canfd.yaml | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
index b9d9dd7a7967..bbaaef8f4282 100644
--- a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
+++ b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
@@ -13,6 +13,7 @@ properties:
compatible:
oneOf:
- enum:
+ - renesas,r9a08g045-canfd # RZ/G3S
- renesas,r9a09g047-canfd # RZ/G3E
- renesas,r9a09g077-canfd # RZ/T2H
@@ -185,8 +186,6 @@ required:
- clocks
- clock-names
- power-domains
- - assigned-clocks
- - assigned-clock-rates
- channel0
- channel1
@@ -198,6 +197,7 @@ allOf:
compatible:
contains:
enum:
+ - renesas,r9a08g045-canfd
- renesas,rzg2l-canfd
then:
properties:
@@ -266,6 +266,7 @@ allOf:
compatible:
contains:
enum:
+ - renesas,r9a08g045-canfd
- renesas,r9a09g077-canfd
- renesas,rcar-gen3-canfd
- renesas,rzg2l-canfd
@@ -330,6 +331,7 @@ allOf:
compatible:
contains:
enum:
+ - renesas,r9a08g045-canfd
- renesas,r9a09g047-canfd
- renesas,rzg2l-canfd
then:
@@ -350,6 +352,20 @@ allOf:
properties:
reset-names: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a08g045-canfd
+ then:
+ properties:
+ renesas,no-can-fd: false
+ renesas,fd-only: false
+ else:
+ required:
+ - assigned-clocks
+ - assigned-clock-rates
+
unevaluatedProperties: false
examples:
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 09/37] can: rcar_canfd: Fix typos in macro names
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (7 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 08/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
` (28 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Claudiu Beznea, Biju Das,
Geert Uytterhoeven, Marc Kleine-Budde
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
The bits 1..0 of the Channel n Control Register are named CHMDC (Channel
Mode select). Fix typos in macro names by replacing DMC with MDC.
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20260902141544.565763-3-claudiu.beznea+renesas@tuxon.dev
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rcar/rcar_canfd.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index fcc37b73ed43..b7c4fe3477ac 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -132,9 +132,9 @@
#define RCANFD_CCTR_BEIE BIT(8)
#define RCANFD_CCTR_CSLPR BIT(2)
#define RCANFD_CCTR_CHMDC_MASK (0x3)
-#define RCANFD_CCTR_CHDMC_COPM (0x0)
-#define RCANFD_CCTR_CHDMC_CRESET (0x1)
-#define RCANFD_CCTR_CHDMC_CHLT (0x2)
+#define RCANFD_CCTR_CHMDC_COPM (0x0)
+#define RCANFD_CCTR_CHMDC_CRESET (0x1)
+#define RCANFD_CCTR_CHMDC_CHLT (0x2)
/* RSCFDnCFDCmSTS / RSCFDnCmSTS */
#define RCANFD_CSTS_COMSTS BIT(7)
@@ -828,7 +828,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
rcar_canfd_update_bit(gpriv->base, RCANFD_CCTR(ch),
RCANFD_CCTR_CHMDC_MASK,
- RCANFD_CCTR_CHDMC_CRESET);
+ RCANFD_CCTR_CHMDC_CRESET);
/* Ensure Channel reset mode */
err = readl_poll_timeout((gpriv->base + RCANFD_CSTS(ch)), sts,
@@ -1504,7 +1504,7 @@ static int rcar_canfd_start(struct net_device *ndev)
/* Set channel to Operational mode */
rcar_canfd_update_bit(priv->base, RCANFD_CCTR(ch),
- RCANFD_CCTR_CHMDC_MASK, RCANFD_CCTR_CHDMC_COPM);
+ RCANFD_CCTR_CHMDC_MASK, RCANFD_CCTR_CHMDC_COPM);
/* Verify channel mode change */
err = readl_poll_timeout((priv->base + RCANFD_CSTS(ch)), sts,
@@ -1578,7 +1578,7 @@ static void rcar_canfd_stop(struct net_device *ndev)
/* Transition to channel reset mode */
rcar_canfd_update_bit(priv->base, RCANFD_CCTR(ch),
- RCANFD_CCTR_CHMDC_MASK, RCANFD_CCTR_CHDMC_CRESET);
+ RCANFD_CCTR_CHMDC_MASK, RCANFD_CCTR_CHMDC_CRESET);
/* Check Channel reset mode */
err = readl_poll_timeout((priv->base + RCANFD_CSTS(ch)), sts,
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (8 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 09/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 11/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
` (27 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Cunhao Lu, Marc Kleine-Budde
From: Cunhao Lu <1579567540@qq.com>
can_put_echo_skb() can be called with hardware interrupts disabled. Its
direct drop paths use kfree_skb(), while can_create_echo_skb() uses
kfree_skb() when cloning fails and consume_skb() after a successful clone.
None of these helpers is safe in every IRQ context.
Use dev_kfree_skb_any() for all drop paths and dev_consume_skb_any() when
consuming a successfully cloned skb. This preserves the respective skb drop
and consumed semantics regardless of the caller IRQ context.
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_E84809CF236D0137885E7E4E4D58340B3208@qq.com
[mkl: also convert can_dropped_invalid_skb(), can_dev_dropped_skb()]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/dev/skb.c | 6 +++---
include/linux/can/dev.h | 2 +-
include/linux/can/skb.h | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index bc0787535b52..46c151eece8f 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -63,7 +63,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
(skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD) &&
skb->protocol != htons(ETH_P_CANXL))) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
@@ -91,7 +91,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
} else {
/* locking problem with netif_stop_queue() ?? */
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return -EBUSY;
}
@@ -403,7 +403,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
return false;
inval_skb:
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return true;
}
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 6d0710d6f571..346faddee02e 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -176,7 +176,7 @@ static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_buff *s
return can_dropped_invalid_skb(dev, skb);
invalid_skb:
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return true;
}
diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h
index 5d27843862fc..87ace09c0d8b 100644
--- a/include/linux/can/skb.h
+++ b/include/linux/can/skb.h
@@ -78,12 +78,12 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
nskb = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!nskb)) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NULL;
}
can_skb_set_owner(nskb, skb->sk);
- consume_skb(skb);
+ dev_consume_skb_any(skb);
return nskb;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 11/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (9 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
` (26 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Claudiu Beznea,
Geert Uytterhoeven, Marc Kleine-Budde
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
On the Renesas RZ/G3S, the CAN FD clock can be sourced either from fck
(the peripheral clock) or from an external clock (can_clk). When fck is
used, it is divided internally by the CAN FD controller.
Adjust the existing canfd clock handling code to support the RZ/G3S CAN.
The existing struct rcar_canfd_hw_info instances were updated to address
the request in the Link discussion.
Link: https://lore.kernel.org/all/1d9719e3-10ff-4cd8-b729-55fea93c37ce@wanadoo.fr
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20260902141544.565763-4-claudiu.beznea+renesas@tuxon.dev
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rcar/rcar_canfd.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index b7c4fe3477ac..f9173774387f 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -444,6 +444,7 @@ struct rcar_canfd_hw_info {
unsigned ch_interface_mode:1; /* Has channel interface mode */
unsigned shared_can_regs:1; /* Has shared classical can registers */
unsigned external_clk:1; /* Has external clock */
+ unsigned fcan_pclk:1; /* Has fcan sourced from pclk. */
};
/* Channel priv data */
@@ -617,6 +618,7 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
.ch_interface_mode = 0,
.shared_can_regs = 0,
.external_clk = 1,
+ .fcan_pclk = 0,
};
static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
@@ -634,6 +636,7 @@ static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
.ch_interface_mode = 1,
.shared_can_regs = 1,
.external_clk = 1,
+ .fcan_pclk = 0,
};
static const struct rcar_canfd_hw_info rzg2l_hw_info = {
@@ -651,6 +654,7 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
.ch_interface_mode = 0,
.shared_can_regs = 0,
.external_clk = 1,
+ .fcan_pclk = 0,
};
static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
@@ -668,6 +672,7 @@ static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
.ch_interface_mode = 1,
.shared_can_regs = 1,
.external_clk = 0,
+ .fcan_pclk = 0,
};
static const struct rcar_canfd_hw_info r9a09g077_hw_info = {
@@ -685,6 +690,7 @@ static const struct rcar_canfd_hw_info r9a09g077_hw_info = {
.ch_interface_mode = 1,
.shared_can_regs = 1,
.external_clk = 1,
+ .fcan_pclk = 0,
};
/* Helper functions */
@@ -2190,13 +2196,20 @@ static int rcar_canfd_probe(struct platform_device *pdev)
*/
gpriv->can_clk = devm_clk_get(dev, "can_clk");
if (IS_ERR(gpriv->can_clk) || (clk_get_rate(gpriv->can_clk) == 0)) {
- gpriv->can_clk = devm_clk_get(dev, "canfd");
- if (IS_ERR(gpriv->can_clk))
- return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
- "cannot get canfd clock\n");
+ if (info->fcan_pclk) {
+ fcan_freq = clk_get_rate(gpriv->clkp);
+ gpriv->can_clk = NULL;
+ } else {
+ gpriv->can_clk = devm_clk_get(dev, "canfd");
+ if (IS_ERR(gpriv->can_clk))
+ return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
+ "cannot get canfd clock\n");
+
+ fcan_freq = clk_get_rate(gpriv->can_clk);
+ }
/* CANFD clock may be further divided within the IP */
- fcan_freq = clk_get_rate(gpriv->can_clk) / info->postdiv;
+ fcan_freq /= info->postdiv;
} else {
fcan_freq = clk_get_rate(gpriv->can_clk);
gpriv->extclk = gpriv->info->external_clk;
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (10 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 11/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 13/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
` (25 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Cunhao Lu, Marc Kleine-Budde
From: Cunhao Lu <1579567540@qq.com>
The CAN skb allocation helpers are used from hardware interrupt receive
handlers. If can_skb_ext_add() fails, they release the newly allocated skb
with kfree_skb(), which is not safe in hardware interrupt context.
Use dev_kfree_skb_any() for the allocation failure paths in
alloc_can_skb(), alloc_canfd_skb(), and alloc_canxl_skb().
Fixes: 96ea3a1e2d31 ("can: add CAN skb extension infrastructure")
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_C825C17D442F801351CE2FBC4984064B4605@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/dev/skb.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 46c151eece8f..3e36c0368bae 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -228,7 +228,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
csx = can_skb_ext_add(skb);
if (!csx) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
goto out_error_cc;
}
@@ -259,7 +259,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
csx = can_skb_ext_add(skb);
if (!csx) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
goto out_error_fd;
}
@@ -297,7 +297,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev,
csx = can_skb_ext_add(skb);
if (!csx) {
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
goto out_error_xl;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 13/37] can: rcar_canfd: Do not set registers selecting the CAN mode
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (11 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
` (24 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Claudiu Beznea, Biju Das,
Geert Uytterhoeven, Marc Kleine-Budde
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
The bits 30 (classical CAN-only mode) and 28 (FD-only enable) of the
Channel n CAN-FD Configuration Register of the Renesas RZ/G3S SoC are not
available. The IP supports only CAN-FD mode. RZ/G3S HW manual (revision
1.30) specify the bits are read as zero and the write value should always
be zero.
Add the mode_select_na flag in struct rcar_canfd_hw_info to cover RZ/G3S
and avoid writing to unavailable bits.
The existing struct rcar_canfd_hw_info instances were updated to address
the request in the Link discussion.
Commit prepares for the addition of the Renesas RZ/G3S SoC.
Link: https://lore.kernel.org/all/1d9719e3-10ff-4cd8-b729-55fea93c37ce@wanadoo.fr
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20260902141544.565763-5-claudiu.beznea+renesas@tuxon.dev
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rcar/rcar_canfd.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index f9173774387f..ac5d5959d8e4 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -445,6 +445,7 @@ struct rcar_canfd_hw_info {
unsigned shared_can_regs:1; /* Has shared classical can registers */
unsigned external_clk:1; /* Has external clock */
unsigned fcan_pclk:1; /* Has fcan sourced from pclk. */
+ unsigned fixed_canfd:1; /* Has mode fixed to canfd. */
};
/* Channel priv data */
@@ -619,6 +620,7 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
.shared_can_regs = 0,
.external_clk = 1,
.fcan_pclk = 0,
+ .fixed_canfd = 0,
};
static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
@@ -637,6 +639,7 @@ static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
.shared_can_regs = 1,
.external_clk = 1,
.fcan_pclk = 0,
+ .fixed_canfd = 0,
};
static const struct rcar_canfd_hw_info rzg2l_hw_info = {
@@ -655,6 +658,7 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
.shared_can_regs = 0,
.external_clk = 1,
.fcan_pclk = 0,
+ .fixed_canfd = 0,
};
static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
@@ -673,6 +677,7 @@ static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
.shared_can_regs = 1,
.external_clk = 0,
.fcan_pclk = 0,
+ .fixed_canfd = 0,
};
static const struct rcar_canfd_hw_info r9a09g077_hw_info = {
@@ -691,6 +696,7 @@ static const struct rcar_canfd_hw_info r9a09g077_hw_info = {
.shared_can_regs = 1,
.external_clk = 1,
.fcan_pclk = 0,
+ .fixed_canfd = 0,
};
/* Helper functions */
@@ -846,6 +852,9 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
}
/* Set the controller into appropriate mode */
+ if (gpriv->info->fixed_canfd)
+ continue;
+
if (gpriv->info->ch_interface_mode) {
/* Do not set CLOE and FDOE simultaneously */
if (!gpriv->fdmode) {
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (12 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 13/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 15/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
` (23 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Cunhao Lu, stable,
Vincent Mailhol, Marc Kleine-Budde
From: Cunhao Lu <1579567540@qq.com>
can_put_echo_skb() consumes the skb on all paths except when the echo
index is out of bounds. This leaves ownership with the caller on -EINVAL,
unlike the other error paths, and can leak the skb if the caller expects
consistent semantics.
Free the skb before returning -EINVAL so that all return paths consume it.
Fixes: 6411959c10fe ("can: dev: can_put_echo_skb(): don't crash kernel if can_priv::echo_skb is accessed out of bounds")
Cc: stable@vger.kernel.org
Reviewed-by: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: Cunhao Lu <1579567540@qq.com>
Link: https://patch.msgid.link/tencent_683AA16E643DE00211CD2FB62991264DC605@qq.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
FAQ:
Q: `can_skb_init_valid()` directly modifies `skb->data` without checking if
the SKB is cloned or shared. Is this violating SKB shared buffer rules and
causing data corruption?
A: The finding about can_skb_init_valid() modifying skb->data on a
potentially shared buffer is not relevant for this (correct) patch.
The FDF-flag write in can_skb_init_valid() only matters for PF_PACKET
use: PF_CAN allocators already set CANFD_FDF. The write exists to
normalize frames for PF_PACKET observers (tcpdump/Wireshark) so they can
distinguish classic CAN from CAN FD at the netdev level, and to
compensate for PF_PACKET senders that omit the bit. That normalization
is functionally required.
The shared-buffer concern only becomes realistic through a specific
chain: a PF_PACKET sender injects a CANFD-sized frame, the CAN driver's
loopback puts an echo skb back into can_rcv(), and cgw (without
modfuncs) clones it for forwarding to another interface. Only on that
second can_skb_init_valid() call is the skb cloned. By then the bit was
already set on the exclusive skb during the initial xmit path, so the
flags |= CANFD_FDF write is strictly idempotent for any parallel
consumer of the shared buffer - no memory-safety or
information-disclosure consequence. It's a formal violation of the skb
sharing rules without an observable effect, so the current code can stay
as-is.
Link: https://lore.kernel.org/all/54a3cc01-abcf-4a33-b932-39bb1f68cdd5@hartkopp.net/
[mkl: convert Oliver's mail to FAQ section]
---
drivers/net/can/dev/skb.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 3e36c0368bae..738d5968dfa6 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -55,6 +55,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 15/37] can: rcar_canfd: Add support for Renesas RZ/G3S
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (13 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 16/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
` (22 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Claudiu Beznea, Biju Das,
Geert Uytterhoeven, Marc Kleine-Budde
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Add support for Renesas RZ/G3S
The Renesas RZ/G3S CAN-FD controller is largely compatible with the
variant found on the Renesas RZ/G3E. The main differences are:
- the RZ/G3S provides 16 AFL pages
- the RZ/G3S supports only two channels
- the RZ/G3S supports only CAN-FD operation and does not implement the
bits used to select between classical CAN-only and CAN FD-only modes.
- the RZ/G3S includes an internal divider that allows the peripheral
clock to be used as the CAN FD clock source.
Add support for the Renesas RZ/G3S.
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20260902141544.565763-6-claudiu.beznea+renesas@tuxon.dev
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rcar/rcar_canfd.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index ac5d5959d8e4..74c3c3f20991 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -661,6 +661,26 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
.fixed_canfd = 0,
};
+static const struct rcar_canfd_hw_info r9a08g045_hw_info = {
+ .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
+ .data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
+ .tdc_const = &rcar_canfd_gen4_tdc_const,
+ .regs = &rcar_gen4_regs,
+ .sh = &rcar_gen4_shift_data,
+ .rnc_field_width = 16,
+ .max_aflpn = 15,
+ .max_cftml = 31,
+ .max_channels = 2,
+ .postdiv = 2,
+ .shared_global_irqs = 0,
+ .multi_channel_irqs = 1,
+ .ch_interface_mode = 1,
+ .shared_can_regs = 1,
+ .external_clk = 1,
+ .fcan_pclk = 1,
+ .fixed_canfd = 1,
+};
+
static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
.nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
.data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
@@ -2383,6 +2403,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
{ .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
+ { .compatible = "renesas,r9a08g045-canfd", .data = &r9a08g045_hw_info },
{ .compatible = "renesas,r9a09g047-canfd", .data = &r9a09g047_hw_info },
{ .compatible = "renesas,r9a09g077-canfd", .data = &r9a09g077_hw_info },
{ .compatible = "renesas,rcar-gen3-canfd", .data = &rcar_gen3_hw_info },
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 16/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (14 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 15/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 17/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
` (21 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Biju Das, Geert Uytterhoeven,
Krzysztof Kozlowski, Marc Kleine-Budde
From: Biju Das <biju.das.jz@bp.renesas.com>
Document the RZ/G3L (R9A08G046) SoC support.
RZ/G3L has 11 interrupts and 3 CANFD channels compared to 8 interrupts
and 2 CANFD channels on RZ/G3S. RZ/G3L has 288 buffers in total
compared to 192 buffers in RZ/G3S.
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20261001075742.21961-2-biju.das.jz@bp.renesas.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
.../bindings/net/can/renesas,rcar-canfd.yaml | 24 ++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
index 1a7a9ce45e97..4b94bc8d911b 100644
--- a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
+++ b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
@@ -14,6 +14,7 @@ properties:
oneOf:
- enum:
- renesas,r9a08g045-canfd # RZ/G3S
+ - renesas,r9a08g046-canfd # RZ/G3L
- renesas,r9a09g047-canfd # RZ/G3E
- renesas,r9a09g077-canfd # RZ/T2H
@@ -294,6 +295,25 @@ allOf:
patternProperties:
"^channel[6-7]$": false
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a08g046-canfd
+ then:
+ properties:
+ interrupts:
+ minItems: 11
+
+ interrupt-names:
+ minItems: 11
+
+ resets:
+ minItems: 2
+
+ patternProperties:
+ "^channel[3-7]$": false
+
- if:
properties:
compatible:
@@ -358,7 +378,9 @@ allOf:
properties:
compatible:
contains:
- const: renesas,r9a08g045-canfd
+ enum:
+ - renesas,r9a08g045-canfd
+ - renesas,r9a08g046-canfd
then:
properties:
renesas,no-can-fd: false
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 17/37] can: rcar_canfd: Derive max_channels from the device tree
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (15 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 16/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 18/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
` (20 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Biju Das, Claudiu Beznea,
Geert Uytterhoeven, Marc Kleine-Budde
From: Biju Das <biju.das.jz@bp.renesas.com>
The maximum number of channels is currently hardcoded per SoC in
struct rcar_canfd_hw_info. Since the DT describes the channels as
child nodes of the controller, the count can be obtained at probe time
with of_get_child_count() instead.
Drop max_channels from struct rcar_canfd_hw_info and store the value
in struct rcar_canfd_global, so it no longer needs to be maintained
for each SoC variant. Update all for_each_set_bit() users over
channels_mask to use gpriv->max_channels.
No functional change.
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20261001075742.21961-3-biju.das.jz@bp.renesas.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rcar/rcar_canfd.c | 39 +++++++++++++++----------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 74c3c3f20991..41c395118949 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -436,7 +436,6 @@ struct rcar_canfd_hw_info {
u8 rnc_field_width;
u8 max_aflpn;
u8 max_cftml;
- u8 max_channels;
u8 postdiv;
/* hardware features */
unsigned shared_global_irqs:1; /* Has shared global irqs */
@@ -478,6 +477,7 @@ struct rcar_canfd_global {
struct reset_control *rstc1;
struct reset_control *rstc2;
const struct rcar_canfd_hw_info *info;
+ u8 max_channels;
};
/* CAN FD mode nominal rate constants */
@@ -613,7 +613,6 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
.rnc_field_width = 8,
.max_aflpn = 31,
.max_cftml = 15,
- .max_channels = 2,
.postdiv = 2,
.shared_global_irqs = 1,
.ch_interface_mode = 0,
@@ -632,7 +631,6 @@ static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
.rnc_field_width = 16,
.max_aflpn = 127,
.max_cftml = 31,
- .max_channels = 8,
.postdiv = 2,
.shared_global_irqs = 1,
.ch_interface_mode = 1,
@@ -651,7 +649,6 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
.rnc_field_width = 8,
.max_aflpn = 31,
.max_cftml = 15,
- .max_channels = 2,
.postdiv = 1,
.multi_channel_irqs = 1,
.ch_interface_mode = 0,
@@ -670,7 +667,6 @@ static const struct rcar_canfd_hw_info r9a08g045_hw_info = {
.rnc_field_width = 16,
.max_aflpn = 15,
.max_cftml = 31,
- .max_channels = 2,
.postdiv = 2,
.shared_global_irqs = 0,
.multi_channel_irqs = 1,
@@ -690,7 +686,6 @@ static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
.rnc_field_width = 16,
.max_aflpn = 63,
.max_cftml = 31,
- .max_channels = 6,
.postdiv = 1,
.multi_channel_irqs = 1,
.ch_interface_mode = 1,
@@ -709,7 +704,6 @@ static const struct rcar_canfd_hw_info r9a09g077_hw_info = {
.rnc_field_width = 16,
.max_aflpn = 15,
.max_cftml = 31,
- .max_channels = 2,
.postdiv = 1,
.multi_channel_irqs = 1,
.ch_interface_mode = 1,
@@ -854,7 +848,7 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
}
/* Transition all Channels to reset mode */
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
rcar_canfd_clear_bit(gpriv->base,
RCANFD_CCTR(ch), RCANFD_CCTR_CSLPR);
@@ -922,7 +916,7 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg);
/* Channel configuration settings */
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
rcar_canfd_set_bit(gpriv->base, RCANFD_CCTR(ch),
RCANFD_CCTR_ERRD);
rcar_canfd_update_bit(gpriv->base, RCANFD_CCTR(ch),
@@ -1293,7 +1287,7 @@ static irqreturn_t rcar_canfd_global_err_interrupt(int irq, void *dev_id)
struct rcar_canfd_global *gpriv = dev_id;
u32 ch;
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels)
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
rcar_canfd_handle_global_err(gpriv, ch);
return IRQ_HANDLED;
@@ -1325,7 +1319,7 @@ static irqreturn_t rcar_canfd_global_receive_fifo_interrupt(int irq, void *dev_i
struct rcar_canfd_global *gpriv = dev_id;
u32 ch;
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels)
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
rcar_canfd_handle_global_receive(gpriv, ch);
return IRQ_HANDLED;
@@ -1339,7 +1333,7 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
/* Global error interrupts still indicate a condition specific
* to a channel. RxFIFO interrupt is a global interrupt.
*/
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
rcar_canfd_handle_global_err(gpriv, ch);
rcar_canfd_handle_global_receive(gpriv, ch);
}
@@ -1435,7 +1429,7 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
u32 ch;
/* Common FIFO is a per channel resource */
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
rcar_canfd_handle_channel_err(gpriv, ch);
rcar_canfd_handle_channel_tx(gpriv, ch);
}
@@ -2072,7 +2066,7 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
rcar_canfd_configure_controller(gpriv);
/* Configure per channel attributes */
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
/* Configure Channel's Rx fifo */
rcar_canfd_configure_rx(gpriv, ch);
@@ -2145,14 +2139,18 @@ static int rcar_canfd_probe(struct platform_device *pdev)
bool fdmode = true; /* CAN FD only mode - default */
char name[9] = "channelX";
u32 ch, fcan_freq;
+ u8 max_channels;
int i;
info = of_device_get_match_data(dev);
+ max_channels = of_get_child_count(dev->of_node);
+ if (max_channels > RCANFD_NUM_CHANNELS)
+ return -EINVAL;
if (of_property_read_bool(dev->of_node, "renesas,no-can-fd"))
fdmode = false; /* Classical CAN only mode */
- for (i = 0; i < info->max_channels; ++i) {
+ for (i = 0; i < max_channels; ++i) {
name[7] = '0' + i;
of_child = of_get_available_child_by_name(dev->of_node, name);
if (of_child) {
@@ -2199,6 +2197,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
gpriv->pdev = pdev;
gpriv->channels_mask = channels_mask;
gpriv->fdmode = fdmode;
+ gpriv->max_channels = max_channels;
gpriv->info = info;
if (of_property_read_bool(dev->of_node, "renesas,fd-only"))
@@ -2300,7 +2299,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
if (err)
goto fail_mode;
- for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
transceivers[ch]);
if (err)
@@ -2314,7 +2313,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
return 0;
fail_channel:
- for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels)
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
rcar_canfd_channel_remove(gpriv, ch);
fail_mode:
rcar_canfd_global_deinit(gpriv, false);
@@ -2327,7 +2326,7 @@ static void rcar_canfd_remove(struct platform_device *pdev)
struct rcar_canfd_global *gpriv = platform_get_drvdata(pdev);
u32 ch;
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]);
rcar_canfd_channel_remove(gpriv, ch);
}
@@ -2341,7 +2340,7 @@ static int rcar_canfd_suspend(struct device *dev)
int err;
u32 ch;
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
struct rcar_canfd_channel *priv = gpriv->ch[ch];
struct net_device *ndev = priv->ndev;
@@ -2378,7 +2377,7 @@ static int rcar_canfd_resume(struct device *dev)
return err;
}
- for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
struct rcar_canfd_channel *priv = gpriv->ch[ch];
struct net_device *ndev = priv->ndev;
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 18/37] dt-bindings: net: can: convert grcan to DT schema
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (16 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 17/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 19/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
` (19 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Quchaosheng, Rob Herring (Arm),
Marc Kleine-Budde
From: Quchaosheng <quchaosheng000406@163.com>
grcan.txt is the only CAN controller binding whose device does not have a
compatible string. There are no device tree source files for LEON SPARC,
and the nodes are built by the PROM from the AMBA plug&play information,
which carries a core name and a register window but no compatible. The
driver matches on the node name instead.
It is the last of the five CAN controller bindings that were still written
as free-form text; the other four are posted separately.
A binding without a compatible string is not selected by dtbs_check,
because nodes are matched through their compatible values. The schema
therefore needs an explicit select on the node name. This is the same
mechanism ethernet-phy.yaml uses for optional-compatible nodes, and
without it the schema would never be applied to anything.
Two further details are worth pointing out, because the text binding got
them wrong or left them implicit:
- "systemid" is not a property of the controller node. The driver and
arch/sparc/kernel/leon_kernel.c both read it from the "/ambapp0" node,
so it is described in the description rather than in properties. The
binding is stricter than the text file here, and dtbs_check now
rejects a controller node that carries it.
- The node name format is "<core name>@<irq>,<address>", as built by
ambapp_path_component() in arch/sparc/kernel/prom_32.c from the "name"
and "reg" properties of the AMBA plug&play core. The select pattern
and the example follow that format.
The "name" property of the text binding is not described: dtc enforces
that it equals the base node name and then deletes it from the output, so
it never reaches a compiled devicetree.
This binding does not reference can-controller.yaml, unlike the other CAN
controller schemas. That common schema constrains the node name to
"^can(@.*)?$", which these nodes cannot satisfy -- they are named after
the AMBA plug&play core. Referencing it makes every valid node fail.
No functional change. The driver comment is updated by a separate patch.
Assisted-by: LLM
Signed-off-by: Quchaosheng <quchaosheng000406@163.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Link: https://patch.msgid.link/20260929073703.2748220-2-quchaosheng000406@163.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
.../net/can/aeroflexgaisler,grcan.yaml | 65 +++++++++++++++++++
.../devicetree/bindings/net/can/grcan.txt | 28 --------
2 files changed, 65 insertions(+), 28 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/can/aeroflexgaisler,grcan.yaml
delete mode 100644 Documentation/devicetree/bindings/net/can/grcan.txt
diff --git a/Documentation/devicetree/bindings/net/can/aeroflexgaisler,grcan.yaml b/Documentation/devicetree/bindings/net/can/aeroflexgaisler,grcan.yaml
new file mode 100644
index 000000000000..d5cba5b1bac1
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/aeroflexgaisler,grcan.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/can/aeroflexgaisler,grcan.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aeroflex Gaisler GRCAN and GRHCAN CAN controllers
+
+maintainers:
+ - Marc Kleine-Budde <mkl@pengutronix.de>
+
+description: |
+ The GRCAN and GRHCAN CAN controllers are available in the GRLIB VHDL IP
+ core library.
+
+ On a LEON SPARC system there are no device tree source files. The nodes
+ are built by the PROM from the AMBA plug&play information, which does not
+ provide a compatible string. The driver therefore matches on the node
+ name, which is built as "<core name>@<irq>,<address>" from the "name" and
+ "reg" properties of the AMBA plug&play core.
+
+ The GRLIB build ID is not a property of the controller node either. It is
+ read from the "systemid" property of the "/ambapp0" node, and the TX bug
+ workaround is enabled when that property is absent or when its least
+ significant 16 bits are smaller than 4100.
+
+select:
+ properties:
+ $nodename:
+ pattern: '^(01_034|01_03d|GAISLER_GRCAN|GAISLER_GRHCAN)@'
+ required:
+ - $nodename
+
+properties:
+ reg:
+ maxItems: 1
+
+ freq:
+ description:
+ Frequency of the external oscillator clock in Hz, which is the
+ frequency of the AMBA bus in the ordinary case.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ interrupts:
+ maxItems: 1
+ description:
+ Interrupt number of the controller, as built from the AMBA plug&play
+ information.
+
+required:
+ - reg
+ - freq
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ /* AMBA plug&play children are named "<core name>@<irq>,<address>" */
+ GAISLER_GRCAN@c,80000000 {
+ reg = <0x80000000 0x1000>;
+ freq = <40000000>;
+ interrupts = <12>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/net/can/grcan.txt b/Documentation/devicetree/bindings/net/can/grcan.txt
deleted file mode 100644
index 34ef3498f887..000000000000
--- a/Documentation/devicetree/bindings/net/can/grcan.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-Aeroflex Gaisler GRCAN and GRHCAN CAN controllers.
-
-The GRCAN and CRHCAN CAN controllers are available in the GRLIB VHDL IP core
-library.
-
-Note: These properties are built from the AMBA plug&play in a Leon SPARC system
-(the ordinary environment for GRCAN and GRHCAN). There are no dts files for
-sparc.
-
-Required properties:
-
-- name : Should be "GAISLER_GRCAN", "01_03d", "GAISLER_GRHCAN" or "01_034"
-
-- reg : Address and length of the register set for the device
-
-- freq : Frequency of the external oscillator clock in Hz (the frequency of
- the amba bus in the ordinary case)
-
-- interrupts : Interrupt number for this device
-
-Optional properties:
-
-- systemid : If not present or if the value of the least significant 16 bits
- of this 32-bit property is smaller than GRCAN_TXBUG_SAFE_GRLIB_VERSION
- a bug workaround is activated.
-
-For further information look in the documentation for the GLIB IP core library:
-http://www.gaisler.com/products/grlib/grip.pdf
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 19/37] can: rcar_canfd: Add support for Renesas RZ/G3L
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (17 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 18/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 20/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
` (18 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Biju Das, Geert Uytterhoeven,
Claudiu Beznea, Marc Kleine-Budde
From: Biju Das <biju.das.jz@bp.renesas.com>
Add support for Renesas RZ/G3L CANFD IP. RZ/G3L has 3 channels and
11 interrupts, compared 2 channels and 8 interrupts on RZ/G3S.
RZ/G3L has 288 buffers compared to 192 buffers on RZ/G3S.
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20261001075742.21961-4-biju.das.jz@bp.renesas.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/rcar/rcar_canfd.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 41c395118949..c64387967368 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2403,6 +2403,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
{ .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
{ .compatible = "renesas,r9a08g045-canfd", .data = &r9a08g045_hw_info },
+ { .compatible = "renesas,r9a08g046-canfd", .data = &r9a08g045_hw_info },
{ .compatible = "renesas,r9a09g047-canfd", .data = &r9a09g047_hw_info },
{ .compatible = "renesas,r9a09g077-canfd", .data = &r9a09g077_hw_info },
{ .compatible = "renesas,rcar-gen3-canfd", .data = &rcar_gen3_hw_info },
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 20/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (18 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 19/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 21/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
` (17 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Krzysztof Kozlowski,
Rob Herring (Arm), Biju Das, Marc Kleine-Budde
From: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Properties varying per variant of the device should still have the
broadest constraints set in the top level, so add such for the "resets".
Since top-level part says "reset-names" cannot accept one item, disallow
it for the two variants which do not use it in practice.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20261001060825.53335-2-krzysztof.kozlowski@oss.qualcomm.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
.../devicetree/bindings/net/can/renesas,rcar-canfd.yaml | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
index bbaaef8f4282..1a7a9ce45e97 100644
--- a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
+++ b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
@@ -133,7 +133,9 @@ properties:
power-domains:
maxItems: 1
- resets: true
+ resets:
+ minItems: 1
+ maxItems: 2
reset-names:
items:
@@ -209,7 +211,6 @@ allOf:
resets:
minItems: 2
- maxItems: 2
- if:
properties:
@@ -231,6 +232,8 @@ allOf:
resets:
maxItems: 1
+ reset-names: false
+
- if:
properties:
compatible:
@@ -246,7 +249,6 @@ allOf:
resets:
minItems: 2
- maxItems: 2
- if:
properties:
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 21/37] can: grcan: update the binding file reference in the driver comment
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (19 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 20/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 22/37] can: remove Softing CANcard driver Marc Kleine-Budde
` (16 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Quchaosheng, Marc Kleine-Budde
From: Quchaosheng <quchaosheng000406@163.com>
grcan.txt is replaced by aeroflexgaisler,grcan.yaml. Point the comment at
the new file. No functional change.
Assisted-by: LLM
Signed-off-by: Quchaosheng <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20260929073703.2748220-3-quchaosheng000406@163.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/grcan.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index ce12fa6df56d..1b4944d1d06d 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -10,8 +10,8 @@
* Full documentation of the GRCAN core can be found here:
* http://www.gaisler.com/products/grlib/grip.pdf
*
- * See "Documentation/devicetree/bindings/net/can/grcan.txt" for information on
- * open firmware properties.
+ * See "Documentation/devicetree/bindings/net/can/aeroflexgaisler,grcan.yaml"
+ * for information on open firmware properties.
*
* See "Documentation/ABI/testing/sysfs-class-net-grcan" for information on the
* sysfs interface.
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 22/37] can: remove Softing CANcard driver
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (20 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 21/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 23/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
` (15 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, Kurt Van Dijck,
Marc Kleine-Budde
From: Oliver Hartkopp <socketcan@hartkopp.net>
The PCMCIA Softing CANcard2 is discontinued since 2013 and the latest
Windows drivers date back to Windows 7/8. The CANcard2 and also the
rebranded Vector CANcardXL make use of a firmware to drive its onboard
CPU to handle raw CAN messages (DPRAM) and its capability to perform
timing critical Classical CAN protocols like ISO 15765-2:2004.
The Softing Linux driver supported none of those higher layer CAN
protocols but only raw CAN CC traffic. In 2026 this functionality is
substituted with cost-effective USB CAN adapters, e.g. gs_usb.
Remove the softing driver as there's no known user and we lack the access
to this at least 25 y/o hardware for 10 years now.
Cc: Kurt Van Dijck <kurt.van.dijck@eia.be>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260815103428.117201-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/Kconfig | 1 -
drivers/net/can/Makefile | 1 -
drivers/net/can/softing/Kconfig | 31 -
drivers/net/can/softing/Makefile | 5 -
drivers/net/can/softing/softing.h | 168 ----
drivers/net/can/softing/softing_cs.c | 335 --------
drivers/net/can/softing/softing_fw.c | 700 -----------------
drivers/net/can/softing/softing_main.c | 864 ---------------------
drivers/net/can/softing/softing_platform.h | 41 -
9 files changed, 2146 deletions(-)
delete mode 100644 drivers/net/can/softing/Kconfig
delete mode 100644 drivers/net/can/softing/Makefile
delete mode 100644 drivers/net/can/softing/softing.h
delete mode 100644 drivers/net/can/softing/softing_cs.c
delete mode 100644 drivers/net/can/softing/softing_fw.c
delete mode 100644 drivers/net/can/softing/softing_main.c
delete mode 100644 drivers/net/can/softing/softing_platform.h
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index a8fad6fe5302..fb16f67a99f9 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -254,7 +254,6 @@ source "drivers/net/can/peak_canfd/Kconfig"
source "drivers/net/can/rcar/Kconfig"
source "drivers/net/can/rockchip/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
-source "drivers/net/can/softing/Kconfig"
source "drivers/net/can/spi/Kconfig"
source "drivers/net/can/usb/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 4010d17f8583..fa2cdd7bcd0a 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -13,7 +13,6 @@ obj-y += rcar/
obj-y += rockchip/
obj-y += spi/
obj-y += usb/
-obj-y += softing/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_BXCAN) += bxcan.o
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
deleted file mode 100644
index 8afd7d0a1000..000000000000
--- a/drivers/net/can/softing/Kconfig
+++ /dev/null
@@ -1,31 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config CAN_SOFTING
- tristate "Softing Gmbh CAN generic support"
- depends on HAS_IOMEM
- help
- Support for CAN cards from Softing Gmbh & some cards
- from Vector Gmbh.
- Softing Gmbh CAN cards come with 1 or 2 physical buses.
- Those cards typically use Dual Port RAM to communicate
- with the host CPU. The interface is then identical for PCI
- and PCMCIA cards. This driver operates on a platform device,
- which has been created by softing_cs or softing_pci driver.
- Warning:
- The API of the card does not allow fine control per bus, but
- controls the 2 buses on the card together.
- As such, some actions (start/stop/busoff recovery) on 1 bus
- must bring down the other bus too temporarily.
-
-config CAN_SOFTING_CS
- tristate "Softing Gmbh CAN pcmcia cards"
- depends on PCMCIA
- depends on CAN_SOFTING
- help
- Support for PCMCIA cards from Softing Gmbh & some cards
- from Vector Gmbh.
- You need firmware for these, which you can get at
- https://github.com/linux-can/can-firmware
- This version of the driver is written against
- firmware version 4.6 (softing-fw-4.6-binaries.tar.gz)
- In order to use the card as CAN device, you need the Softing generic
- support too.
diff --git a/drivers/net/can/softing/Makefile b/drivers/net/can/softing/Makefile
deleted file mode 100644
index c51154000377..000000000000
--- a/drivers/net/can/softing/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-softing-y := softing_main.o softing_fw.o
-obj-$(CONFIG_CAN_SOFTING) += softing.o
-obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o
diff --git a/drivers/net/can/softing/softing.h b/drivers/net/can/softing/softing.h
deleted file mode 100644
index 2893007ea05e..000000000000
--- a/drivers/net/can/softing/softing.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * softing common interfaces
- *
- * by Kurt Van Dijck, 2008-2010
- */
-
-#include <linux/atomic.h>
-#include <linux/netdevice.h>
-#include <linux/ktime.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <linux/can.h>
-#include <linux/can/dev.h>
-
-#include "softing_platform.h"
-
-struct softing;
-
-struct softing_priv {
- struct can_priv can; /* must be the first member! */
- struct net_device *netdev;
- struct softing *card;
- struct {
- int pending;
- /* variables which hold the circular buffer */
- int echo_put;
- int echo_get;
- } tx;
- struct can_bittiming_const btr_const;
- int index;
- uint8_t output;
- uint16_t chip;
-};
-#define netdev2softing(netdev) ((struct softing_priv *)netdev_priv(netdev))
-
-struct softing {
- const struct softing_platform_data *pdat;
- struct platform_device *pdev;
- struct net_device *net[2];
- spinlock_t spin; /* protect this structure & DPRAM access */
- ktime_t ts_ref;
- ktime_t ts_overflow; /* timestamp overflow value, in ktime */
-
- struct {
- /* indication of firmware status */
- int up;
- /* protection of the 'up' variable */
- struct mutex lock;
- } fw;
- struct {
- int nr;
- int requested;
- int svc_count;
- unsigned int dpram_position;
- } irq;
- struct {
- int pending;
- int last_bus;
- /*
- * keep the bus that last tx'd a message,
- * in order to let every netdev queue resume
- */
- } tx;
- __iomem uint8_t *dpram;
- unsigned long dpram_phys;
- unsigned long dpram_size;
- struct {
- uint16_t fw_version, hw_version, license, serial;
- uint16_t chip[2];
- unsigned int freq; /* remote cpu's operating frequency */
- } id;
-};
-
-int softing_default_output(struct net_device *netdev);
-
-ktime_t softing_raw2ktime(struct softing *card, u32 raw);
-
-int softing_chip_poweron(struct softing *card);
-
-int softing_bootloader_command(struct softing *card, int16_t cmd,
- const char *msg);
-
-/* Load firmware after reset */
-int softing_load_fw(const char *file, struct softing *card,
- __iomem uint8_t *virt, unsigned int size, int offset);
-
-/* Load final application firmware after bootloader */
-int softing_load_app_fw(const char *file, struct softing *card);
-
-/*
- * enable or disable irq
- * only called with fw.lock locked
- */
-int softing_enable_irq(struct softing *card, int enable);
-
-/* start/stop 1 bus on card */
-int softing_startstop(struct net_device *netdev, int up);
-
-/* netif_rx() */
-int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
- ktime_t ktime);
-
-/* SOFTING DPRAM mappings */
-#define DPRAM_RX 0x0000
- #define DPRAM_RX_SIZE 32
- #define DPRAM_RX_CNT 16
-#define DPRAM_RX_RD 0x0201 /* uint8_t */
-#define DPRAM_RX_WR 0x0205 /* uint8_t */
-#define DPRAM_RX_LOST 0x0207 /* uint8_t */
-
-#define DPRAM_FCT_PARAM 0x0300 /* int16_t [20] */
-#define DPRAM_FCT_RESULT 0x0328 /* int16_t */
-#define DPRAM_FCT_HOST 0x032b /* uint16_t */
-
-#define DPRAM_INFO_BUSSTATE 0x0331 /* uint16_t */
-#define DPRAM_INFO_BUSSTATE2 0x0335 /* uint16_t */
-#define DPRAM_INFO_ERRSTATE 0x0339 /* uint16_t */
-#define DPRAM_INFO_ERRSTATE2 0x033d /* uint16_t */
-#define DPRAM_RESET 0x0341 /* uint16_t */
-#define DPRAM_CLR_RECV_FIFO 0x0345 /* uint16_t */
-#define DPRAM_RESET_TIME 0x034d /* uint16_t */
-#define DPRAM_TIME 0x0350 /* uint64_t */
-#define DPRAM_WR_START 0x0358 /* uint8_t */
-#define DPRAM_WR_END 0x0359 /* uint8_t */
-#define DPRAM_RESET_RX_FIFO 0x0361 /* uint16_t */
-#define DPRAM_RESET_TX_FIFO 0x0364 /* uint8_t */
-#define DPRAM_READ_FIFO_LEVEL 0x0365 /* uint8_t */
-#define DPRAM_RX_FIFO_LEVEL 0x0366 /* uint16_t */
-#define DPRAM_TX_FIFO_LEVEL 0x0366 /* uint16_t */
-
-#define DPRAM_TX 0x0400 /* uint16_t */
- #define DPRAM_TX_SIZE 16
- #define DPRAM_TX_CNT 32
-#define DPRAM_TX_RD 0x0601 /* uint8_t */
-#define DPRAM_TX_WR 0x0605 /* uint8_t */
-
-#define DPRAM_COMMAND 0x07e0 /* uint16_t */
-#define DPRAM_RECEIPT 0x07f0 /* uint16_t */
-#define DPRAM_IRQ_TOHOST 0x07fe /* uint8_t */
-#define DPRAM_IRQ_TOCARD 0x07ff /* uint8_t */
-
-#define DPRAM_V2_RESET 0x0e00 /* uint8_t */
-#define DPRAM_V2_IRQ_TOHOST 0x0e02 /* uint8_t */
-
-#define TXMAX (DPRAM_TX_CNT - 1)
-
-/* DPRAM return codes */
-#define RES_NONE 0
-#define RES_OK 1
-#define RES_NOK 2
-#define RES_UNKNOWN 3
-/* DPRAM flags */
-#define CMD_TX 0x01
-#define CMD_ACK 0x02
-#define CMD_XTD 0x04
-#define CMD_RTR 0x08
-#define CMD_ERR 0x10
-#define CMD_BUS2 0x80
-
-/* returned fifo entry bus state masks */
-#define SF_MASK_BUSOFF 0x80
-#define SF_MASK_EPASSIVE 0x60
-
-/* bus states */
-#define STATE_BUSOFF 2
-#define STATE_EPASSIVE 1
-#define STATE_EACTIVE 0
diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c
deleted file mode 100644
index 3cea14cf055a..000000000000
--- a/drivers/net/can/softing/softing_cs.c
+++ /dev/null
@@ -1,335 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2008-2010
- *
- * - Kurt Van Dijck, EIA Electronics
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#include "softing_platform.h"
-
-static int softingcs_index;
-static DEFINE_SPINLOCK(softingcs_index_lock);
-
-static int softingcs_reset(struct platform_device *pdev, int v);
-static int softingcs_enable_irq(struct platform_device *pdev, int v);
-
-/*
- * platform_data descriptions
- */
-#define MHZ (1000*1000)
-static const struct softing_platform_data softingcs_platform_data[] = {
-{
- .name = "CANcard",
- .manf = 0x0168, .prod = 0x001,
- .generation = 1,
- .nbus = 2,
- .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
- .dpram_size = 0x0800,
- .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
- .reset = softingcs_reset,
- .enable_irq = softingcs_enable_irq,
-}, {
- .name = "CANcard-NEC",
- .manf = 0x0168, .prod = 0x002,
- .generation = 1,
- .nbus = 2,
- .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
- .dpram_size = 0x0800,
- .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
- .reset = softingcs_reset,
- .enable_irq = softingcs_enable_irq,
-}, {
- .name = "CANcard-SJA",
- .manf = 0x0168, .prod = 0x004,
- .generation = 1,
- .nbus = 2,
- .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
- .dpram_size = 0x0800,
- .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
- .reset = softingcs_reset,
- .enable_irq = softingcs_enable_irq,
-}, {
- .name = "CANcard-2",
- .manf = 0x0168, .prod = 0x005,
- .generation = 2,
- .nbus = 2,
- .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
- .dpram_size = 0x1000,
- .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
- .reset = softingcs_reset,
- .enable_irq = NULL,
-}, {
- .name = "Vector-CANcard",
- .manf = 0x0168, .prod = 0x081,
- .generation = 1,
- .nbus = 2,
- .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
- .dpram_size = 0x0800,
- .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
- .reset = softingcs_reset,
- .enable_irq = softingcs_enable_irq,
-}, {
- .name = "Vector-CANcard-SJA",
- .manf = 0x0168, .prod = 0x084,
- .generation = 1,
- .nbus = 2,
- .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
- .dpram_size = 0x0800,
- .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
- .reset = softingcs_reset,
- .enable_irq = softingcs_enable_irq,
-}, {
- .name = "Vector-CANcard-2",
- .manf = 0x0168, .prod = 0x085,
- .generation = 2,
- .nbus = 2,
- .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
- .dpram_size = 0x1000,
- .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
- .reset = softingcs_reset,
- .enable_irq = NULL,
-}, {
- .name = "EDICcard-NEC",
- .manf = 0x0168, .prod = 0x102,
- .generation = 1,
- .nbus = 2,
- .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
- .dpram_size = 0x0800,
- .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
- .reset = softingcs_reset,
- .enable_irq = softingcs_enable_irq,
-}, {
- .name = "EDICcard-2",
- .manf = 0x0168, .prod = 0x105,
- .generation = 2,
- .nbus = 2,
- .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
- .dpram_size = 0x1000,
- .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
- .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
- .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
- .reset = softingcs_reset,
- .enable_irq = NULL,
-}, {
- 0, 0,
-},
-};
-
-MODULE_FIRMWARE(fw_dir "bcard.bin");
-MODULE_FIRMWARE(fw_dir "ldcard.bin");
-MODULE_FIRMWARE(fw_dir "cancard.bin");
-MODULE_FIRMWARE(fw_dir "cansja.bin");
-
-MODULE_FIRMWARE(fw_dir "bcard2.bin");
-MODULE_FIRMWARE(fw_dir "ldcard2.bin");
-MODULE_FIRMWARE(fw_dir "cancrd2.bin");
-
-static const struct softing_platform_data
-*softingcs_find_platform_data(unsigned int manf, unsigned int prod)
-{
- const struct softing_platform_data *lp;
-
- for (lp = softingcs_platform_data; lp->manf; ++lp) {
- if ((lp->manf == manf) && (lp->prod == prod))
- return lp;
- }
- return NULL;
-}
-
-/*
- * platformdata callbacks
- */
-static int softingcs_reset(struct platform_device *pdev, int v)
-{
- struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
-
- dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
- return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
-}
-
-static int softingcs_enable_irq(struct platform_device *pdev, int v)
-{
- struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
-
- dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
- return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
-}
-
-/*
- * pcmcia check
- */
-static int softingcs_probe_config(struct pcmcia_device *pcmcia, void *priv_data)
-{
- struct softing_platform_data *pdat = priv_data;
- struct resource *pres;
- int memspeed = 0;
-
- WARN_ON(!pdat);
- pres = pcmcia->resource[PCMCIA_IOMEM_0];
- if (resource_size(pres) < 0x1000)
- return -ERANGE;
-
- pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
- if (pdat->generation < 2) {
- pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
- memspeed = 3;
- } else {
- pres->flags |= WIN_DATA_WIDTH_16;
- }
- return pcmcia_request_window(pcmcia, pres, memspeed);
-}
-
-static void softingcs_remove(struct pcmcia_device *pcmcia)
-{
- struct platform_device *pdev = pcmcia->priv;
-
- /* free bits */
- platform_device_unregister(pdev);
- /* release pcmcia stuff */
- pcmcia_disable_device(pcmcia);
-}
-
-/*
- * platform_device wrapper
- * pdev->resource has 2 entries: io & irq
- */
-static void softingcs_pdev_release(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- kfree(pdev);
-}
-
-static int softingcs_probe(struct pcmcia_device *pcmcia)
-{
- int ret;
- struct platform_device *pdev;
- const struct softing_platform_data *pdat;
- struct resource *pres;
- struct dev {
- struct platform_device pdev;
- struct resource res[2];
- } *dev;
-
- /* find matching platform_data */
- pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
- if (!pdat)
- return -ENOTTY;
-
- /* setup pcmcia device */
- pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
- CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
- if (ret)
- goto pcmcia_failed;
-
- ret = pcmcia_enable_device(pcmcia);
- if (ret < 0)
- goto pcmcia_failed;
-
- pres = pcmcia->resource[PCMCIA_IOMEM_0];
- if (!pres) {
- ret = -EBADF;
- goto pcmcia_bad;
- }
-
- /* create softing platform device */
- dev = kzalloc_obj(*dev);
- if (!dev) {
- ret = -ENOMEM;
- goto mem_failed;
- }
- dev->pdev.resource = dev->res;
- dev->pdev.num_resources = ARRAY_SIZE(dev->res);
- dev->pdev.dev.release = softingcs_pdev_release;
-
- pdev = &dev->pdev;
- pdev->dev.platform_data = (void *)pdat;
- pdev->dev.parent = &pcmcia->dev;
- pcmcia->priv = pdev;
-
- /* platform device resources */
- pdev->resource[0].flags = IORESOURCE_MEM;
- pdev->resource[0].start = pres->start;
- pdev->resource[0].end = pres->end;
-
- pdev->resource[1].flags = IORESOURCE_IRQ;
- pdev->resource[1].start = pcmcia->irq;
- pdev->resource[1].end = pdev->resource[1].start;
-
- /* platform device setup */
- spin_lock(&softingcs_index_lock);
- pdev->id = softingcs_index++;
- spin_unlock(&softingcs_index_lock);
- pdev->name = "softing";
- dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
- ret = platform_device_register(pdev);
- if (ret < 0)
- goto platform_failed;
-
- dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
- return 0;
-
-platform_failed:
- platform_device_put(pdev);
-mem_failed:
-pcmcia_bad:
-pcmcia_failed:
- pcmcia_disable_device(pcmcia);
- pcmcia->priv = NULL;
- return ret;
-}
-
-static const struct pcmcia_device_id softingcs_ids[] = {
- /* softing */
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
- /* vector, manufacturer? */
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
- /* EDIC */
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
- PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
- PCMCIA_DEVICE_NULL,
-};
-
-MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
-
-static struct pcmcia_driver softingcs_driver = {
- .owner = THIS_MODULE,
- .name = "softingcs",
- .id_table = softingcs_ids,
- .probe = softingcs_probe,
- .remove = softingcs_remove,
-};
-
-module_pcmcia_driver(softingcs_driver);
-
-MODULE_DESCRIPTION("softing CANcard driver"
- ", links PCMCIA card to softing driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c
deleted file mode 100644
index 282570daf3ef..000000000000
--- a/drivers/net/can/softing/softing_fw.c
+++ /dev/null
@@ -1,700 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2008-2010
- *
- * - Kurt Van Dijck, EIA Electronics
- */
-
-#include <linux/firmware.h>
-#include <linux/sched/signal.h>
-#include <asm/div64.h>
-#include <asm/io.h>
-
-#include "softing.h"
-
-/*
- * low level DPRAM command.
- * Make sure that card->dpram[DPRAM_FCT_HOST] is preset
- */
-static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
- const char *msg)
-{
- int ret;
- unsigned long stamp;
-
- iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
- iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
- iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
- /* be sure to flush this to the card */
- wmb();
- stamp = jiffies + 1 * HZ;
- /* wait for card */
- do {
- /* DPRAM_FCT_HOST is _not_ aligned */
- ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
- (ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
- /* don't have any cached variables */
- rmb();
- if (ret == RES_OK)
- /* read return-value now */
- return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
-
- if ((ret != vector) || time_after(jiffies, stamp))
- break;
- /* process context => relax */
- usleep_range(500, 10000);
- } while (1);
-
- ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
- dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
- return ret;
-}
-
-static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
-{
- int ret;
-
- ret = _softing_fct_cmd(card, cmd, 0, msg);
- if (ret > 0) {
- dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
- ret = -EIO;
- }
- return ret;
-}
-
-int softing_bootloader_command(struct softing *card, int16_t cmd,
- const char *msg)
-{
- int ret;
- unsigned long stamp;
-
- iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
- iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
- /* be sure to flush this to the card */
- wmb();
- stamp = jiffies + 3 * HZ;
- /* wait for card */
- do {
- ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
- /* don't have any cached variables */
- rmb();
- if (ret == RES_OK)
- return 0;
- if (time_after(jiffies, stamp))
- break;
- /* process context => relax */
- usleep_range(500, 10000);
- } while (!signal_pending(current));
-
- ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
- dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
- return ret;
-}
-
-static int fw_parse(const u8 **pmem, const u8 *limit, u16 *ptype,
- u32 *paddr, u16 *plen, const u8 **pdat)
-{
- uint16_t checksum[2];
- const u8 *mem;
- const u8 *record_end;
-
- /*
- * firmware records are a binary, unaligned stream composed of:
- * uint16_t type;
- * uint32_t addr;
- * uint16_t len;
- * uint8_t dat[len];
- * uint16_t checksum;
- * all values in little endian.
- * We could define a struct for this, with __attribute__((packed)),
- * but would that solve the alignment in _all_ cases (cfr. the
- * struct itself may be an odd address)?
- *
- * I chose to use leXX_to_cpup() since this solves both
- * endianness & alignment.
- */
- mem = *pmem;
- /* A record needs an 8-byte prefix and a 2-byte checksum. */
- if (mem > limit || limit - mem < 10)
- return -EINVAL;
-
- *ptype = le16_to_cpup((void *)&mem[0]);
- *paddr = le32_to_cpup((void *)&mem[2]);
- *plen = le16_to_cpup((void *)&mem[6]);
- if (*plen > limit - mem - 10)
- return -EINVAL;
-
- *pdat = &mem[8];
- /* verify checksum */
- record_end = &mem[8 + *plen];
- checksum[0] = le16_to_cpup((void *)record_end);
- for (checksum[1] = 0; mem < record_end; ++mem)
- checksum[1] += *mem;
- if (checksum[0] != checksum[1])
- return -EINVAL;
- /* increment */
- *pmem += 10 + *plen;
- return 0;
-}
-
-int softing_load_fw(const char *file, struct softing *card,
- __iomem uint8_t *dpram, unsigned int size, int offset)
-{
- const struct firmware *fw;
- int ret;
- const uint8_t *mem, *end, *dat;
- uint16_t type, len;
- uint32_t addr;
- uint8_t *buf = NULL, *new_buf;
- s64 dpram_offset;
- int buflen = 0;
- int8_t type_end = 0;
-
- ret = request_firmware(&fw, file, &card->pdev->dev);
- if (ret < 0)
- return ret;
- dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
- ", offset %c0x%04x\n",
- card->pdat->name, file, (unsigned int)fw->size,
- (offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
- /* parse the firmware */
- mem = fw->data;
- end = &mem[fw->size];
- /* look for header record */
- ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
- if (ret < 0)
- goto failed;
- if (type != 0xffff)
- goto failed;
- if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
- ret = -EINVAL;
- goto failed;
- }
- /* ok, we had a header */
- while (mem < end) {
- ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
- if (ret < 0)
- goto failed;
- if (type == 3) {
- /* start address, not used here */
- continue;
- } else if (type == 1) {
- /* eof */
- type_end = 1;
- break;
- } else if (type != 0) {
- ret = -EINVAL;
- goto failed;
- }
-
- dpram_offset = (s64)addr + offset;
- if (dpram_offset < 0 || dpram_offset > size ||
- len > size - dpram_offset) {
- ret = -EINVAL;
- goto failed;
- }
- memcpy_toio(&dpram[dpram_offset], dat, len);
- /* be sure to flush caches from IO space */
- mb();
- if (len > buflen) {
- /* align buflen */
- buflen = (len + (1024-1)) & ~(1024-1);
- new_buf = krealloc(buf, buflen, GFP_KERNEL);
- if (!new_buf) {
- ret = -ENOMEM;
- goto failed;
- }
- buf = new_buf;
- }
- /* verify record data */
- memcpy_fromio(buf, &dpram[dpram_offset], len);
- if (memcmp(buf, dat, len)) {
- /* is not ok */
- dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
- ret = -EIO;
- goto failed;
- }
- }
- if (!type_end)
- /* no end record seen */
- goto failed;
- ret = 0;
-failed:
- kfree(buf);
- release_firmware(fw);
- if (ret < 0)
- dev_info(&card->pdev->dev, "firmware %s failed\n", file);
- return ret;
-}
-
-int softing_load_app_fw(const char *file, struct softing *card)
-{
- const struct firmware *fw;
- const uint8_t *mem, *end, *dat;
- int ret, j;
- uint16_t type, len;
- uint32_t addr, start_addr = 0;
- unsigned int sum, rx_sum;
- int8_t type_end = 0, type_entrypoint = 0;
-
- ret = request_firmware(&fw, file, &card->pdev->dev);
- if (ret) {
- dev_alert(&card->pdev->dev, "request_firmware(%s) got %i\n",
- file, ret);
- return ret;
- }
- dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
- file, (unsigned long)fw->size);
- /* parse the firmware */
- mem = fw->data;
- end = &mem[fw->size];
- /* look for header record */
- ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
- if (ret)
- goto failed;
- ret = -EINVAL;
- if (type != 0xffff) {
- dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
- type);
- goto failed;
- }
- if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
- dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
- len, dat);
- goto failed;
- }
- /* ok, we had a header */
- while (mem < end) {
- ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
- if (ret)
- goto failed;
-
- if (type == 3) {
- /* start address */
- start_addr = addr;
- type_entrypoint = 1;
- continue;
- } else if (type == 1) {
- /* eof */
- type_end = 1;
- break;
- } else if (type != 0) {
- dev_alert(&card->pdev->dev,
- "unknown record type 0x%04x\n", type);
- ret = -EINVAL;
- goto failed;
- }
-
- /* regular data */
- for (sum = 0, j = 0; j < len; ++j)
- sum += dat[j];
- /* work in 16bit (target) */
- sum &= 0xffff;
-
- if (card->pdat->app.offs > card->dpram_size ||
- len > card->dpram_size - card->pdat->app.offs) {
- ret = -EINVAL;
- goto failed;
- }
-
- memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
- iowrite32(card->pdat->app.offs + card->pdat->app.addr,
- &card->dpram[DPRAM_COMMAND + 2]);
- iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
- iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
- iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
- ret = softing_bootloader_command(card, 1, "loading app.");
- if (ret < 0)
- goto failed;
- /* verify checksum */
- rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
- if (rx_sum != sum) {
- dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
- ", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
- ret = -EIO;
- goto failed;
- }
- }
- if (!type_end || !type_entrypoint)
- goto failed;
- /* start application in card */
- iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
- iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
- ret = softing_bootloader_command(card, 3, "start app.");
- if (ret < 0)
- goto failed;
- ret = 0;
-failed:
- release_firmware(fw);
- if (ret < 0)
- dev_info(&card->pdev->dev, "firmware %s failed\n", file);
- return ret;
-}
-
-static int softing_reset_chip(struct softing *card)
-{
- int ret;
-
- do {
- /* reset chip */
- iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
- iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
- iowrite8(1, &card->dpram[DPRAM_RESET]);
- iowrite8(0, &card->dpram[DPRAM_RESET+1]);
-
- ret = softing_fct_cmd(card, 0, "reset_can");
- if (!ret)
- break;
- if (signal_pending(current))
- /* don't wait any longer */
- break;
- } while (1);
- card->tx.pending = 0;
- return ret;
-}
-
-int softing_chip_poweron(struct softing *card)
-{
- int ret;
- /* sync */
- ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
- if (ret < 0)
- goto failed;
-
- ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
- if (ret < 0)
- goto failed;
-
- ret = softing_reset_chip(card);
- if (ret < 0)
- goto failed;
- /* get_serial */
- ret = softing_fct_cmd(card, 43, "get_serial_number");
- if (ret < 0)
- goto failed;
- card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
- /* get_version */
- ret = softing_fct_cmd(card, 12, "get_version");
- if (ret < 0)
- goto failed;
- card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
- card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
- card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
- card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
- card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
- return 0;
-failed:
- return ret;
-}
-
-static void softing_initialize_timestamp(struct softing *card)
-{
- uint64_t ovf;
-
- card->ts_ref = ktime_get();
-
- /* 16MHz is the reference */
- ovf = 0x100000000ULL * 16;
- do_div(ovf, card->pdat->freq ?: 16);
-
- card->ts_overflow = ktime_add_us(0, ovf);
-}
-
-ktime_t softing_raw2ktime(struct softing *card, u32 raw)
-{
- uint64_t rawl;
- ktime_t now, real_offset;
- ktime_t target;
- ktime_t tmp;
-
- now = ktime_get();
- real_offset = ktime_sub(ktime_get_real(), now);
-
- /* find nsec from card */
- rawl = raw * 16;
- do_div(rawl, card->pdat->freq ?: 16);
- target = ktime_add_us(card->ts_ref, rawl);
- /* test for overflows */
- tmp = ktime_add(target, card->ts_overflow);
- while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
- card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
- target = tmp;
- tmp = ktime_add(target, card->ts_overflow);
- }
- return ktime_add(target, real_offset);
-}
-
-static inline int softing_error_reporting(struct net_device *netdev)
-{
- struct softing_priv *priv = netdev_priv(netdev);
-
- return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
- ? 1 : 0;
-}
-
-int softing_startstop(struct net_device *dev, int up)
-{
- int ret;
- struct softing *card;
- struct softing_priv *priv;
- struct net_device *netdev;
- int bus_bitmask_start;
- int j, error_reporting;
- struct can_frame msg;
- const struct can_bittiming *bt;
-
- priv = netdev_priv(dev);
- card = priv->card;
-
- if (!card->fw.up)
- return -EIO;
-
- ret = mutex_lock_interruptible(&card->fw.lock);
- if (ret)
- return ret;
-
- bus_bitmask_start = 0;
- if (up)
- /* prepare to start this bus as well */
- bus_bitmask_start |= (1 << priv->index);
- /* bring netdevs down */
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- netdev = card->net[j];
- if (!netdev)
- continue;
- priv = netdev_priv(netdev);
-
- if (dev != netdev)
- netif_stop_queue(netdev);
-
- if (netif_running(netdev)) {
- if (dev != netdev)
- bus_bitmask_start |= (1 << j);
- priv->tx.pending = 0;
- priv->tx.echo_put = 0;
- priv->tx.echo_get = 0;
- /*
- * this bus' may just have called open_candev()
- * which is rather stupid to call close_candev()
- * already
- * but we may come here from busoff recovery too
- * in which case the echo_skb _needs_ flushing too.
- * just be sure to call open_candev() again
- */
- close_candev(netdev);
- }
- priv->can.state = CAN_STATE_STOPPED;
- }
- card->tx.pending = 0;
-
- softing_enable_irq(card, 0);
- ret = softing_reset_chip(card);
- if (ret)
- goto failed;
- if (!bus_bitmask_start)
- /* no buses to be brought up */
- goto card_done;
-
- if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
- && (softing_error_reporting(card->net[0])
- != softing_error_reporting(card->net[1]))) {
- dev_alert(&card->pdev->dev,
- "err_reporting flag differs for buses\n");
- goto invalid;
- }
- error_reporting = 0;
- if (bus_bitmask_start & 1) {
- netdev = card->net[0];
- priv = netdev_priv(netdev);
- error_reporting += softing_error_reporting(netdev);
- /* init chip 1 */
- bt = &priv->can.bittiming;
- iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
- iowrite16(bt->phase_seg1 + bt->prop_seg,
- &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
- &card->dpram[DPRAM_FCT_PARAM + 10]);
- ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
- if (ret < 0)
- goto failed;
- /* set mode */
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
- ret = softing_fct_cmd(card, 3, "set_mode[0]");
- if (ret < 0)
- goto failed;
- /* set filter */
- /* 11bit id & mask */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
- /* 29bit id.lo & mask.lo & id.hi & mask.hi */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
- iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
- ret = softing_fct_cmd(card, 7, "set_filter[0]");
- if (ret < 0)
- goto failed;
- /* set output control */
- iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
- ret = softing_fct_cmd(card, 5, "set_output[0]");
- if (ret < 0)
- goto failed;
- }
- if (bus_bitmask_start & 2) {
- netdev = card->net[1];
- priv = netdev_priv(netdev);
- error_reporting += softing_error_reporting(netdev);
- /* init chip2 */
- bt = &priv->can.bittiming;
- iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
- iowrite16(bt->phase_seg1 + bt->prop_seg,
- &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
- &card->dpram[DPRAM_FCT_PARAM + 10]);
- ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
- if (ret < 0)
- goto failed;
- /* set mode2 */
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
- ret = softing_fct_cmd(card, 4, "set_mode[1]");
- if (ret < 0)
- goto failed;
- /* set filter2 */
- /* 11bit id & mask */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
- /* 29bit id.lo & mask.lo & id.hi & mask.hi */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
- iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
- ret = softing_fct_cmd(card, 8, "set_filter[1]");
- if (ret < 0)
- goto failed;
- /* set output control2 */
- iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
- ret = softing_fct_cmd(card, 6, "set_output[1]");
- if (ret < 0)
- goto failed;
- }
-
- /* enable_error_frame
- *
- * Error reporting is switched off at the moment since
- * the receiving of them is not yet 100% verified
- * This should be enabled sooner or later
- */
- if (0 && error_reporting) {
- ret = softing_fct_cmd(card, 51, "enable_error_frame");
- if (ret < 0)
- goto failed;
- }
-
- /* initialize interface */
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
- ret = softing_fct_cmd(card, 17, "initialize_interface");
- if (ret < 0)
- goto failed;
- /* enable_fifo */
- ret = softing_fct_cmd(card, 36, "enable_fifo");
- if (ret < 0)
- goto failed;
- /* enable fifo tx ack */
- ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
- if (ret < 0)
- goto failed;
- /* enable fifo tx ack2 */
- ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
- if (ret < 0)
- goto failed;
- /* start_chip */
- ret = softing_fct_cmd(card, 11, "start_chip");
- if (ret < 0)
- goto failed;
- iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
- iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
- if (card->pdat->generation < 2) {
- iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
- /* flush the DPRAM caches */
- wmb();
- }
-
- softing_initialize_timestamp(card);
-
- /*
- * do socketcan notifications/status changes
- * from here, no errors should occur, or the failed: part
- * must be reviewed
- */
- memset(&msg, 0, sizeof(msg));
- msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
- msg.len = CAN_ERR_DLC;
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- if (!(bus_bitmask_start & (1 << j)))
- continue;
- netdev = card->net[j];
- if (!netdev)
- continue;
- priv = netdev_priv(netdev);
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- open_candev(netdev);
- if (dev != netdev) {
- /* notify other buses on the restart */
- softing_netdev_rx(netdev, &msg, 0);
- ++priv->can.can_stats.restarts;
- }
- netif_wake_queue(netdev);
- }
-
- /* enable interrupts */
- ret = softing_enable_irq(card, 1);
- if (ret)
- goto failed;
-card_done:
- mutex_unlock(&card->fw.lock);
- return 0;
-invalid:
- ret = -EINVAL;
-failed:
- softing_enable_irq(card, 0);
- softing_reset_chip(card);
- mutex_unlock(&card->fw.lock);
- /* bring all other interfaces down */
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- netdev = card->net[j];
- if (!netdev)
- continue;
- dev_close(netdev);
- }
- return ret;
-}
-
-int softing_default_output(struct net_device *netdev)
-{
- struct softing_priv *priv = netdev_priv(netdev);
- struct softing *card = priv->card;
-
- switch (priv->chip) {
- case 1000:
- return (card->pdat->generation < 2) ? 0xfb : 0xfa;
- case 5:
- return 0x60;
- default:
- return 0x40;
- }
-}
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
deleted file mode 100644
index 519ab3097f86..000000000000
--- a/drivers/net/can/softing/softing_main.c
+++ /dev/null
@@ -1,864 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2008-2010
- *
- * - Kurt Van Dijck, EIA Electronics
- */
-
-#include <linux/ethtool.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-#include "softing.h"
-
-#define TX_ECHO_SKB_MAX (((TXMAX+1)/2)-1)
-
-/*
- * test is a specific CAN netdev
- * is online (ie. up 'n running, not sleeping, not busoff
- */
-static inline int canif_is_active(struct net_device *netdev)
-{
- struct can_priv *can = netdev_priv(netdev);
-
- if (!netif_running(netdev))
- return 0;
- return (can->state <= CAN_STATE_ERROR_PASSIVE);
-}
-
-/* reset DPRAM */
-static inline void softing_set_reset_dpram(struct softing *card)
-{
- if (card->pdat->generation >= 2) {
- spin_lock_bh(&card->spin);
- iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) & ~1,
- &card->dpram[DPRAM_V2_RESET]);
- spin_unlock_bh(&card->spin);
- }
-}
-
-static inline void softing_clr_reset_dpram(struct softing *card)
-{
- if (card->pdat->generation >= 2) {
- spin_lock_bh(&card->spin);
- iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) | 1,
- &card->dpram[DPRAM_V2_RESET]);
- spin_unlock_bh(&card->spin);
- }
-}
-
-/* trigger the tx queue-ing */
-static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct softing_priv *priv = netdev_priv(dev);
- struct softing *card = priv->card;
- int ret;
- uint8_t *ptr;
- uint8_t fifo_wr, fifo_rd;
- struct can_frame *cf = (struct can_frame *)skb->data;
- uint8_t buf[DPRAM_TX_SIZE];
-
- if (can_dev_dropped_skb(dev, skb))
- return NETDEV_TX_OK;
-
- spin_lock(&card->spin);
-
- ret = NETDEV_TX_BUSY;
- if (!card->fw.up ||
- (card->tx.pending >= TXMAX) ||
- (priv->tx.pending >= TX_ECHO_SKB_MAX))
- goto xmit_done;
- fifo_wr = ioread8(&card->dpram[DPRAM_TX_WR]);
- fifo_rd = ioread8(&card->dpram[DPRAM_TX_RD]);
- if (fifo_wr == fifo_rd)
- /* fifo full */
- goto xmit_done;
- memset(buf, 0, sizeof(buf));
- ptr = buf;
- *ptr = CMD_TX;
- if (cf->can_id & CAN_RTR_FLAG)
- *ptr |= CMD_RTR;
- if (cf->can_id & CAN_EFF_FLAG)
- *ptr |= CMD_XTD;
- if (priv->index)
- *ptr |= CMD_BUS2;
- ++ptr;
- *ptr++ = cf->len;
- *ptr++ = (cf->can_id >> 0);
- *ptr++ = (cf->can_id >> 8);
- if (cf->can_id & CAN_EFF_FLAG) {
- *ptr++ = (cf->can_id >> 16);
- *ptr++ = (cf->can_id >> 24);
- } else {
- /* increment 1, not 2 as you might think */
- ptr += 1;
- }
- if (!(cf->can_id & CAN_RTR_FLAG))
- memcpy(ptr, &cf->data[0], cf->len);
- memcpy_toio(&card->dpram[DPRAM_TX + DPRAM_TX_SIZE * fifo_wr],
- buf, DPRAM_TX_SIZE);
- if (++fifo_wr >= DPRAM_TX_CNT)
- fifo_wr = 0;
- iowrite8(fifo_wr, &card->dpram[DPRAM_TX_WR]);
- card->tx.last_bus = priv->index;
- ++card->tx.pending;
- ++priv->tx.pending;
- can_put_echo_skb(skb, dev, priv->tx.echo_put, 0);
- ++priv->tx.echo_put;
- if (priv->tx.echo_put >= TX_ECHO_SKB_MAX)
- priv->tx.echo_put = 0;
- /* can_put_echo_skb() saves the skb, safe to return TX_OK */
- ret = NETDEV_TX_OK;
-xmit_done:
- spin_unlock(&card->spin);
- if (card->tx.pending >= TXMAX) {
- int j;
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- if (card->net[j])
- netif_stop_queue(card->net[j]);
- }
- }
- if (ret != NETDEV_TX_OK)
- netif_stop_queue(dev);
-
- return ret;
-}
-
-/*
- * shortcut for skb delivery
- */
-int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
- ktime_t ktime)
-{
- struct sk_buff *skb;
- struct can_frame *cf;
-
- skb = alloc_can_skb(netdev, &cf);
- if (!skb)
- return -ENOMEM;
- memcpy(cf, msg, sizeof(*msg));
- skb->tstamp = ktime;
- return netif_rx(skb);
-}
-
-/*
- * softing_handle_1
- * pop 1 entry from the DPRAM queue, and process
- */
-static int softing_handle_1(struct softing *card)
-{
- struct net_device *netdev;
- struct softing_priv *priv;
- ktime_t ktime;
- struct can_frame msg;
- int cnt = 0, lost_msg;
- uint8_t fifo_rd, fifo_wr, cmd;
- uint8_t *ptr;
- uint32_t tmp_u32;
- uint8_t buf[DPRAM_RX_SIZE];
-
- memset(&msg, 0, sizeof(msg));
- /* test for lost msgs */
- lost_msg = ioread8(&card->dpram[DPRAM_RX_LOST]);
- if (lost_msg) {
- int j;
- /* reset condition */
- iowrite8(0, &card->dpram[DPRAM_RX_LOST]);
- /* prepare msg */
- msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
- msg.len = CAN_ERR_DLC;
- msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
- /*
- * service to all buses, we don't know which it was applicable
- * but only service buses that are online
- */
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- netdev = card->net[j];
- if (!netdev)
- continue;
- if (!canif_is_active(netdev))
- /* a dead bus has no overflows */
- continue;
- ++netdev->stats.rx_over_errors;
- softing_netdev_rx(netdev, &msg, 0);
- }
- /* prepare for other use */
- memset(&msg, 0, sizeof(msg));
- ++cnt;
- }
-
- fifo_rd = ioread8(&card->dpram[DPRAM_RX_RD]);
- fifo_wr = ioread8(&card->dpram[DPRAM_RX_WR]);
-
- if (++fifo_rd >= DPRAM_RX_CNT)
- fifo_rd = 0;
- if (fifo_wr == fifo_rd)
- return cnt;
-
- memcpy_fromio(buf, &card->dpram[DPRAM_RX + DPRAM_RX_SIZE*fifo_rd],
- DPRAM_RX_SIZE);
- mb();
- /* trigger dual port RAM */
- iowrite8(fifo_rd, &card->dpram[DPRAM_RX_RD]);
-
- ptr = buf;
- cmd = *ptr++;
- if (cmd == 0xff)
- /* not quite useful, probably the card has got out */
- return 0;
- netdev = card->net[0];
- if (cmd & CMD_BUS2)
- netdev = card->net[1];
- priv = netdev_priv(netdev);
-
- if (cmd & CMD_ERR) {
- uint8_t can_state, state;
-
- state = *ptr++;
-
- msg.can_id = CAN_ERR_FLAG;
- msg.len = CAN_ERR_DLC;
-
- if (state & SF_MASK_BUSOFF) {
- can_state = CAN_STATE_BUS_OFF;
- msg.can_id |= CAN_ERR_BUSOFF;
- state = STATE_BUSOFF;
- } else if (state & SF_MASK_EPASSIVE) {
- can_state = CAN_STATE_ERROR_PASSIVE;
- msg.can_id |= CAN_ERR_CRTL;
- msg.data[1] = CAN_ERR_CRTL_TX_PASSIVE;
- state = STATE_EPASSIVE;
- } else {
- can_state = CAN_STATE_ERROR_ACTIVE;
- msg.can_id |= CAN_ERR_CRTL;
- state = STATE_EACTIVE;
- }
- /* update DPRAM */
- iowrite8(state, &card->dpram[priv->index ?
- DPRAM_INFO_BUSSTATE2 : DPRAM_INFO_BUSSTATE]);
- /* timestamp */
- tmp_u32 = le32_to_cpup((void *)ptr);
- ktime = softing_raw2ktime(card, tmp_u32);
-
- ++netdev->stats.rx_errors;
- /* update internal status */
- if (can_state != priv->can.state) {
- priv->can.state = can_state;
- if (can_state == CAN_STATE_ERROR_PASSIVE)
- ++priv->can.can_stats.error_passive;
- else if (can_state == CAN_STATE_BUS_OFF) {
- /* this calls can_close_cleanup() */
- ++priv->can.can_stats.bus_off;
- can_bus_off(netdev);
- netif_stop_queue(netdev);
- }
- /* trigger socketcan */
- softing_netdev_rx(netdev, &msg, ktime);
- }
-
- } else {
- if (cmd & CMD_RTR)
- msg.can_id |= CAN_RTR_FLAG;
- msg.len = can_cc_dlc2len(*ptr++);
- if (cmd & CMD_XTD) {
- msg.can_id |= CAN_EFF_FLAG;
- msg.can_id |= le32_to_cpup((void *)ptr);
- ptr += 4;
- } else {
- msg.can_id |= le16_to_cpup((void *)ptr);
- ptr += 2;
- }
- /* timestamp */
- tmp_u32 = le32_to_cpup((void *)ptr);
- ptr += 4;
- ktime = softing_raw2ktime(card, tmp_u32);
- if (!(msg.can_id & CAN_RTR_FLAG))
- memcpy(&msg.data[0], ptr, 8);
- /* update socket */
- if (cmd & CMD_ACK) {
- /* acknowledge, was tx msg */
- struct sk_buff *skb;
- skb = priv->can.echo_skb[priv->tx.echo_get];
- if (skb)
- skb->tstamp = ktime;
- ++netdev->stats.tx_packets;
- netdev->stats.tx_bytes +=
- can_get_echo_skb(netdev, priv->tx.echo_get,
- NULL);
- ++priv->tx.echo_get;
- if (priv->tx.echo_get >= TX_ECHO_SKB_MAX)
- priv->tx.echo_get = 0;
- if (priv->tx.pending)
- --priv->tx.pending;
- if (card->tx.pending)
- --card->tx.pending;
- } else {
- int ret;
-
- ret = softing_netdev_rx(netdev, &msg, ktime);
- if (ret == NET_RX_SUCCESS) {
- ++netdev->stats.rx_packets;
- if (!(msg.can_id & CAN_RTR_FLAG))
- netdev->stats.rx_bytes += msg.len;
- } else {
- ++netdev->stats.rx_dropped;
- }
- }
- }
- ++cnt;
- return cnt;
-}
-
-/*
- * real interrupt handler
- */
-static irqreturn_t softing_irq_thread(int irq, void *dev_id)
-{
- struct softing *card = (struct softing *)dev_id;
- struct net_device *netdev;
- struct softing_priv *priv;
- int j, offset, work_done;
-
- work_done = 0;
- spin_lock_bh(&card->spin);
- while (softing_handle_1(card) > 0) {
- ++card->irq.svc_count;
- ++work_done;
- }
- spin_unlock_bh(&card->spin);
- /* resume tx queue's */
- offset = card->tx.last_bus;
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- if (card->tx.pending >= TXMAX)
- break;
- netdev = card->net[(j + offset + 1) % card->pdat->nbus];
- if (!netdev)
- continue;
- priv = netdev_priv(netdev);
- if (!canif_is_active(netdev))
- /* it makes no sense to wake dead buses */
- continue;
- if (priv->tx.pending >= TX_ECHO_SKB_MAX)
- continue;
- ++work_done;
- netif_wake_queue(netdev);
- }
- return work_done ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/*
- * interrupt routines:
- * schedule the 'real interrupt handler'
- */
-static irqreturn_t softing_irq_v2(int irq, void *dev_id)
-{
- struct softing *card = (struct softing *)dev_id;
- uint8_t ir;
-
- ir = ioread8(&card->dpram[DPRAM_V2_IRQ_TOHOST]);
- iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
- return (1 == ir) ? IRQ_WAKE_THREAD : IRQ_NONE;
-}
-
-static irqreturn_t softing_irq_v1(int irq, void *dev_id)
-{
- struct softing *card = (struct softing *)dev_id;
- uint8_t ir;
-
- ir = ioread8(&card->dpram[DPRAM_IRQ_TOHOST]);
- iowrite8(0, &card->dpram[DPRAM_IRQ_TOHOST]);
- return ir ? IRQ_WAKE_THREAD : IRQ_NONE;
-}
-
-/*
- * netdev/candev interoperability
- */
-static int softing_netdev_open(struct net_device *ndev)
-{
- int ret;
-
- /* check or determine and set bittime */
- ret = open_candev(ndev);
- if (ret)
- return ret;
-
- ret = softing_startstop(ndev, 1);
- if (ret < 0)
- close_candev(ndev);
-
- return ret;
-}
-
-static int softing_netdev_stop(struct net_device *ndev)
-{
- netif_stop_queue(ndev);
-
- /* softing cycle does close_candev() */
- return softing_startstop(ndev, 0);
-}
-
-static int softing_candev_set_mode(struct net_device *ndev, enum can_mode mode)
-{
- int ret;
-
- switch (mode) {
- case CAN_MODE_START:
- /* softing_startstop does close_candev() */
- ret = softing_startstop(ndev, 1);
- return ret;
- case CAN_MODE_STOP:
- case CAN_MODE_SLEEP:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/*
- * Softing device management helpers
- */
-int softing_enable_irq(struct softing *card, int enable)
-{
- int ret;
-
- if (!card->irq.nr) {
- return 0;
- } else if (card->irq.requested && !enable) {
- free_irq(card->irq.nr, card);
- card->irq.requested = 0;
- } else if (!card->irq.requested && enable) {
- ret = request_threaded_irq(card->irq.nr,
- (card->pdat->generation >= 2) ?
- softing_irq_v2 : softing_irq_v1,
- softing_irq_thread, IRQF_SHARED,
- dev_name(&card->pdev->dev), card);
- if (ret) {
- dev_alert(&card->pdev->dev,
- "request_threaded_irq(%u) failed\n",
- card->irq.nr);
- return ret;
- }
- card->irq.requested = 1;
- }
- return 0;
-}
-
-static void softing_card_shutdown(struct softing *card)
-{
- int fw_up = 0;
-
- if (mutex_lock_interruptible(&card->fw.lock)) {
- /* return -ERESTARTSYS */;
- }
- fw_up = card->fw.up;
- card->fw.up = 0;
-
- if (card->irq.requested && card->irq.nr) {
- free_irq(card->irq.nr, card);
- card->irq.requested = 0;
- }
- if (fw_up) {
- if (card->pdat->enable_irq)
- card->pdat->enable_irq(card->pdev, 0);
- softing_set_reset_dpram(card);
- if (card->pdat->reset)
- card->pdat->reset(card->pdev, 1);
- }
- mutex_unlock(&card->fw.lock);
-}
-
-static int softing_card_boot(struct softing *card)
-{
- int ret, j;
- static const uint8_t stream[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
- unsigned char back[sizeof(stream)];
-
- if (mutex_lock_interruptible(&card->fw.lock))
- return -ERESTARTSYS;
- if (card->fw.up) {
- mutex_unlock(&card->fw.lock);
- return 0;
- }
- /* reset board */
- if (card->pdat->enable_irq)
- card->pdat->enable_irq(card->pdev, 1);
- /* boot card */
- softing_set_reset_dpram(card);
- if (card->pdat->reset)
- card->pdat->reset(card->pdev, 1);
- for (j = 0; (j + sizeof(stream)) < card->dpram_size;
- j += sizeof(stream)) {
-
- memcpy_toio(&card->dpram[j], stream, sizeof(stream));
- /* flush IO cache */
- mb();
- memcpy_fromio(back, &card->dpram[j], sizeof(stream));
-
- if (!memcmp(back, stream, sizeof(stream)))
- continue;
- /* memory is not equal */
- dev_alert(&card->pdev->dev, "dpram failed at 0x%04x\n", j);
- ret = -EIO;
- goto failed;
- }
- wmb();
- /* load boot firmware */
- ret = softing_load_fw(card->pdat->boot.fw, card, card->dpram,
- card->dpram_size,
- card->pdat->boot.offs - card->pdat->boot.addr);
- if (ret < 0)
- goto failed;
- /* load loader firmware */
- ret = softing_load_fw(card->pdat->load.fw, card, card->dpram,
- card->dpram_size,
- card->pdat->load.offs - card->pdat->load.addr);
- if (ret < 0)
- goto failed;
-
- if (card->pdat->reset)
- card->pdat->reset(card->pdev, 0);
- softing_clr_reset_dpram(card);
- ret = softing_bootloader_command(card, 0, "card boot");
- if (ret < 0)
- goto failed;
- ret = softing_load_app_fw(card->pdat->app.fw, card);
- if (ret < 0)
- goto failed;
-
- ret = softing_chip_poweron(card);
- if (ret < 0)
- goto failed;
-
- card->fw.up = 1;
- mutex_unlock(&card->fw.lock);
- return 0;
-failed:
- card->fw.up = 0;
- if (card->pdat->enable_irq)
- card->pdat->enable_irq(card->pdev, 0);
- softing_set_reset_dpram(card);
- if (card->pdat->reset)
- card->pdat->reset(card->pdev, 1);
- mutex_unlock(&card->fw.lock);
- return ret;
-}
-
-/*
- * netdev sysfs
- */
-static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct net_device *ndev = to_net_dev(dev);
- struct softing_priv *priv = netdev2softing(ndev);
-
- return sprintf(buf, "%i\n", priv->chip);
-}
-
-static ssize_t show_output(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct net_device *ndev = to_net_dev(dev);
- struct softing_priv *priv = netdev2softing(ndev);
-
- return sprintf(buf, "0x%02x\n", priv->output);
-}
-
-static ssize_t store_output(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct net_device *ndev = to_net_dev(dev);
- struct softing_priv *priv = netdev2softing(ndev);
- struct softing *card = priv->card;
- unsigned long val;
- int ret;
-
- ret = kstrtoul(buf, 0, &val);
- if (ret < 0)
- return ret;
- val &= 0xFF;
-
- ret = mutex_lock_interruptible(&card->fw.lock);
- if (ret)
- return -ERESTARTSYS;
- if (netif_running(ndev)) {
- mutex_unlock(&card->fw.lock);
- return -EBUSY;
- }
- priv->output = val;
- mutex_unlock(&card->fw.lock);
- return count;
-}
-
-static const DEVICE_ATTR(chip, 0444, show_chip, NULL);
-static const DEVICE_ATTR(output, 0644, show_output, store_output);
-
-static const struct attribute *const netdev_sysfs_attrs[] = {
- &dev_attr_chip.attr,
- &dev_attr_output.attr,
- NULL,
-};
-static const struct attribute_group netdev_sysfs_group = {
- .name = NULL,
- .attrs = (struct attribute **)netdev_sysfs_attrs,
-};
-
-static const struct net_device_ops softing_netdev_ops = {
- .ndo_open = softing_netdev_open,
- .ndo_stop = softing_netdev_stop,
- .ndo_start_xmit = softing_netdev_start_xmit,
-};
-
-static const struct ethtool_ops softing_ethtool_ops = {
- .get_ts_info = ethtool_op_get_ts_info,
-};
-
-static const struct can_bittiming_const softing_btr_const = {
- .name = KBUILD_MODNAME,
- .tseg1_min = 1,
- .tseg1_max = 16,
- .tseg2_min = 1,
- .tseg2_max = 8,
- .sjw_max = 4, /* overruled */
- .brp_min = 1,
- .brp_max = 32, /* overruled */
- .brp_inc = 1,
-};
-
-
-static struct net_device *softing_netdev_create(struct softing *card,
- uint16_t chip_id)
-{
- struct net_device *netdev;
- struct softing_priv *priv;
-
- netdev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
- if (!netdev) {
- dev_alert(&card->pdev->dev, "alloc_candev failed\n");
- return NULL;
- }
- priv = netdev_priv(netdev);
- priv->netdev = netdev;
- priv->card = card;
- memcpy(&priv->btr_const, &softing_btr_const, sizeof(priv->btr_const));
- priv->btr_const.brp_max = card->pdat->max_brp;
- priv->btr_const.sjw_max = card->pdat->max_sjw;
- priv->can.bittiming_const = &priv->btr_const;
- priv->can.clock.freq = 8000000;
- priv->chip = chip_id;
- priv->output = softing_default_output(netdev);
- SET_NETDEV_DEV(netdev, &card->pdev->dev);
-
- netdev->flags |= IFF_ECHO;
- netdev->netdev_ops = &softing_netdev_ops;
- netdev->ethtool_ops = &softing_ethtool_ops;
- priv->can.do_set_mode = softing_candev_set_mode;
- priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
-
- return netdev;
-}
-
-static int softing_netdev_register(struct net_device *netdev)
-{
- int ret;
-
- ret = register_candev(netdev);
- if (ret) {
- dev_alert(&netdev->dev, "register failed\n");
- return ret;
- }
- if (sysfs_create_group(&netdev->dev.kobj, &netdev_sysfs_group) < 0)
- netdev_alert(netdev, "sysfs group failed\n");
-
- return 0;
-}
-
-static void softing_netdev_cleanup(struct net_device *netdev)
-{
- sysfs_remove_group(&netdev->dev.kobj, &netdev_sysfs_group);
- unregister_candev(netdev);
- free_candev(netdev);
-}
-
-/*
- * sysfs for Platform device
- */
-#define DEV_ATTR_RO(name, member) \
-static ssize_t show_##name(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct softing *card = dev_get_drvdata(dev); \
- return sprintf(buf, "%u\n", card->member); \
-} \
-static DEVICE_ATTR(name, 0444, show_##name, NULL)
-
-#define DEV_ATTR_RO_STR(name, member) \
-static ssize_t show_##name(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct softing *card = dev_get_drvdata(dev); \
- return sprintf(buf, "%s\n", card->member); \
-} \
-static DEVICE_ATTR(name, 0444, show_##name, NULL)
-
-DEV_ATTR_RO(serial, id.serial);
-DEV_ATTR_RO_STR(firmware, pdat->app.fw);
-DEV_ATTR_RO(firmware_version, id.fw_version);
-DEV_ATTR_RO_STR(hardware, pdat->name);
-DEV_ATTR_RO(hardware_version, id.hw_version);
-DEV_ATTR_RO(license, id.license);
-
-static struct attribute *softing_pdev_attrs[] = {
- &dev_attr_serial.attr,
- &dev_attr_firmware.attr,
- &dev_attr_firmware_version.attr,
- &dev_attr_hardware.attr,
- &dev_attr_hardware_version.attr,
- &dev_attr_license.attr,
- NULL,
-};
-
-static const struct attribute_group softing_pdev_group = {
- .name = NULL,
- .attrs = softing_pdev_attrs,
-};
-
-/*
- * platform driver
- */
-static void softing_pdev_remove(struct platform_device *pdev)
-{
- struct softing *card = platform_get_drvdata(pdev);
- int j;
-
- /* first, disable card*/
- softing_card_shutdown(card);
-
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- if (!card->net[j])
- continue;
- softing_netdev_cleanup(card->net[j]);
- card->net[j] = NULL;
- }
- sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
-
- iounmap(card->dpram);
- kfree(card);
-}
-
-static int softing_pdev_probe(struct platform_device *pdev)
-{
- const struct softing_platform_data *pdat = dev_get_platdata(&pdev->dev);
- struct softing *card;
- struct net_device *netdev;
- struct softing_priv *priv;
- struct resource *pres;
- int ret;
- int j;
-
- if (!pdat) {
- dev_warn(&pdev->dev, "no platform data\n");
- return -EINVAL;
- }
- if (pdat->nbus > ARRAY_SIZE(card->net)) {
- dev_warn(&pdev->dev, "%u nets??\n", pdat->nbus);
- return -EINVAL;
- }
-
- card = kzalloc_obj(*card);
- if (!card)
- return -ENOMEM;
- card->pdat = pdat;
- card->pdev = pdev;
- platform_set_drvdata(pdev, card);
- mutex_init(&card->fw.lock);
- spin_lock_init(&card->spin);
-
- ret = -EINVAL;
- pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!pres)
- goto platform_resource_failed;
- card->dpram_phys = pres->start;
- card->dpram_size = resource_size(pres);
- card->dpram = ioremap(card->dpram_phys, card->dpram_size);
- if (!card->dpram) {
- dev_alert(&card->pdev->dev, "dpram ioremap failed\n");
- goto ioremap_failed;
- }
-
- pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (pres)
- card->irq.nr = pres->start;
-
- /* reset card */
- ret = softing_card_boot(card);
- if (ret < 0) {
- dev_alert(&pdev->dev, "failed to boot\n");
- goto boot_failed;
- }
-
- /* only now, the chip's are known */
- card->id.freq = card->pdat->freq;
-
- ret = sysfs_create_group(&pdev->dev.kobj, &softing_pdev_group);
- if (ret < 0) {
- dev_alert(&card->pdev->dev, "sysfs failed\n");
- goto sysfs_failed;
- }
-
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- card->net[j] = netdev =
- softing_netdev_create(card, card->id.chip[j]);
- if (!netdev) {
- dev_alert(&pdev->dev, "failed to make can[%i]", j);
- ret = -ENOMEM;
- goto netdev_failed;
- }
- netdev->dev_id = j;
- priv = netdev_priv(card->net[j]);
- priv->index = j;
- ret = softing_netdev_register(netdev);
- if (ret) {
- free_candev(netdev);
- card->net[j] = NULL;
- dev_alert(&card->pdev->dev,
- "failed to register can[%i]\n", j);
- goto netdev_failed;
- }
- }
- dev_info(&card->pdev->dev, "%s ready.\n", card->pdat->name);
- return 0;
-
-netdev_failed:
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- if (!card->net[j])
- continue;
- softing_netdev_cleanup(card->net[j]);
- }
- sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
-sysfs_failed:
- softing_card_shutdown(card);
-boot_failed:
- iounmap(card->dpram);
-ioremap_failed:
-platform_resource_failed:
- kfree(card);
- return ret;
-}
-
-static struct platform_driver softing_driver = {
- .driver = {
- .name = KBUILD_MODNAME,
- },
- .probe = softing_pdev_probe,
- .remove = softing_pdev_remove,
-};
-
-module_platform_driver(softing_driver);
-
-MODULE_ALIAS("platform:softing");
-MODULE_DESCRIPTION("Softing DPRAM CAN driver");
-MODULE_AUTHOR("Kurt Van Dijck <kurt.van.dijck@eia.be>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/softing/softing_platform.h b/drivers/net/can/softing/softing_platform.h
deleted file mode 100644
index cd8d7904c5f0..000000000000
--- a/drivers/net/can/softing/softing_platform.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#include <linux/platform_device.h>
-
-#ifndef _SOFTING_DEVICE_H_
-#define _SOFTING_DEVICE_H_
-
-/* softing firmware directory prefix */
-#define fw_dir "softing-4.6/"
-
-struct softing_platform_data {
- unsigned int manf;
- unsigned int prod;
- /*
- * generation
- * 1st with NEC or SJA1000
- * 8bit, exclusive interrupt, ...
- * 2nd only SJA1000
- * 16bit, shared interrupt
- */
- int generation;
- int nbus; /* # buses on device */
- unsigned int freq; /* operating frequency in Hz */
- unsigned int max_brp;
- unsigned int max_sjw;
- unsigned long dpram_size;
- const char *name;
- struct {
- unsigned long offs;
- unsigned long addr;
- const char *fw;
- } boot, load, app;
- /*
- * reset() function
- * bring pdev in or out of reset, depending on value
- */
- int (*reset)(struct platform_device *pdev, int value);
- int (*enable_irq)(struct platform_device *pdev, int value);
-};
-
-#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 23/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (21 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 22/37] can: remove Softing CANcard driver Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 24/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
` (14 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Triet Hoang, Marc Kleine-Budde
From: Triet Hoang <triet.hoang.dev@gmail.com>
Convert the deprecated SIMPLE_DEV_PM_OPS to DEFINE_SIMPLE_DEV_PM_OPS and
pm_sleep_ptr().
This lets us drop the __maybe_unused annotations from the suspend and
resume callbacks, also reduces kernel size in case CONFIG_PM or
CONFIG_PM_SLEEP is disabled.
Signed-off-by: Triet Hoang <triet.hoang.dev@gmail.com>
Link: https://patch.msgid.link/20260822074701.22856-1-triet.hoang.dev@gmail.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/bxcan.c | 8 ++++----
drivers/net/can/ctucanfd/ctucanfd.h | 4 ++--
drivers/net/can/ctucanfd/ctucanfd_pci.c | 4 ++--
drivers/net/can/ctucanfd/ctucanfd_platform.c | 4 ++--
drivers/net/can/m_can/m_can_pci.c | 8 ++++----
drivers/net/can/spi/hi311x.c | 8 ++++----
drivers/net/can/spi/mcp251x.c | 8 ++++----
7 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/drivers/net/can/bxcan.c b/drivers/net/can/bxcan.c
index 4bddd015775b..622c5d73e33a 100644
--- a/drivers/net/can/bxcan.c
+++ b/drivers/net/can/bxcan.c
@@ -1042,7 +1042,7 @@ static void bxcan_remove(struct platform_device *pdev)
free_candev(ndev);
}
-static int __maybe_unused bxcan_suspend(struct device *dev)
+static int bxcan_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct bxcan_priv *priv = netdev_priv(ndev);
@@ -1059,7 +1059,7 @@ static int __maybe_unused bxcan_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused bxcan_resume(struct device *dev)
+static int bxcan_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct bxcan_priv *priv = netdev_priv(ndev);
@@ -1076,7 +1076,7 @@ static int __maybe_unused bxcan_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(bxcan_pm_ops, bxcan_suspend, bxcan_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bxcan_pm_ops, bxcan_suspend, bxcan_resume);
static const struct of_device_id bxcan_of_match[] = {
{.compatible = "st,stm32f4-bxcan"},
@@ -1087,7 +1087,7 @@ MODULE_DEVICE_TABLE(of, bxcan_of_match);
static struct platform_driver bxcan_driver = {
.driver = {
.name = KBUILD_MODNAME,
- .pm = &bxcan_pm_ops,
+ .pm = pm_sleep_ptr(&bxcan_pm_ops),
.of_match_table = bxcan_of_match,
},
.probe = bxcan_probe,
diff --git a/drivers/net/can/ctucanfd/ctucanfd.h b/drivers/net/can/ctucanfd/ctucanfd.h
index 0e9904f6a05d..7dcd7dc507e4 100644
--- a/drivers/net/can/ctucanfd/ctucanfd.h
+++ b/drivers/net/can/ctucanfd/ctucanfd.h
@@ -76,7 +76,7 @@ int ctucan_probe_common(struct device *dev, void __iomem *addr,
void (*set_drvdata_fnc)(struct device *dev,
struct net_device *ndev));
-int ctucan_suspend(struct device *dev) __maybe_unused;
-int ctucan_resume(struct device *dev) __maybe_unused;
+int ctucan_suspend(struct device *dev);
+int ctucan_resume(struct device *dev);
#endif /*__CTUCANFD__*/
diff --git a/drivers/net/can/ctucanfd/ctucanfd_pci.c b/drivers/net/can/ctucanfd/ctucanfd_pci.c
index 4b6db28f7b67..9c9c41c3058c 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_pci.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_pci.c
@@ -259,7 +259,7 @@ static void ctucan_pci_remove(struct pci_dev *pdev)
kfree(bdata);
}
-static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
static const struct pci_device_id ctucan_pci_tbl[] = {
{PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
@@ -273,7 +273,7 @@ static struct pci_driver ctucan_pci_driver = {
.id_table = ctucan_pci_tbl,
.probe = ctucan_pci_probe,
.remove = ctucan_pci_remove,
- .driver.pm = &ctucan_pci_pm_ops,
+ .driver.pm = pm_sleep_ptr(&ctucan_pci_pm_ops),
};
module_pci_driver(ctucan_pci_driver);
diff --git a/drivers/net/can/ctucanfd/ctucanfd_platform.c b/drivers/net/can/ctucanfd/ctucanfd_platform.c
index 70e2577c8541..4962b00ee8ac 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_platform.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_platform.c
@@ -99,7 +99,7 @@ static void ctucan_platform_remove(struct platform_device *pdev)
free_candev(ndev);
}
-static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
/* Match table for OF platform binding */
static const struct of_device_id ctucan_of_match[] = {
@@ -114,7 +114,7 @@ static struct platform_driver ctucanfd_driver = {
.remove = ctucan_platform_remove,
.driver = {
.name = DRV_NAME,
- .pm = &ctucan_platform_pm_ops,
+ .pm = pm_sleep_ptr(&ctucan_platform_pm_ops),
.of_match_table = ctucan_of_match,
},
};
diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c
index d11a7c88fc32..d31179312026 100644
--- a/drivers/net/can/m_can/m_can_pci.c
+++ b/drivers/net/can/m_can/m_can_pci.c
@@ -169,17 +169,17 @@ static void m_can_pci_remove(struct pci_dev *pci)
pci_free_irq_vectors(pci);
}
-static __maybe_unused int m_can_pci_suspend(struct device *dev)
+static int m_can_pci_suspend(struct device *dev)
{
return m_can_class_suspend(dev);
}
-static __maybe_unused int m_can_pci_resume(struct device *dev)
+static int m_can_pci_resume(struct device *dev)
{
return m_can_class_resume(dev);
}
-static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
m_can_pci_suspend, m_can_pci_resume);
static const struct pci_device_id m_can_pci_id_table[] = {
@@ -195,7 +195,7 @@ static struct pci_driver m_can_pci_driver = {
.remove = m_can_pci_remove,
.id_table = m_can_pci_id_table,
.driver = {
- .pm = &m_can_pci_pm_ops,
+ .pm = pm_sleep_ptr(&m_can_pci_pm_ops),
},
};
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index ae90e6716de5..076a3efa1bff 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -972,7 +972,7 @@ static void hi3110_can_remove(struct spi_device *spi)
free_candev(net);
}
-static int __maybe_unused hi3110_can_suspend(struct device *dev)
+static int hi3110_can_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct hi3110_priv *priv = spi_get_drvdata(spi);
@@ -1002,7 +1002,7 @@ static int __maybe_unused hi3110_can_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hi3110_can_resume(struct device *dev)
+static int hi3110_can_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct hi3110_priv *priv = spi_get_drvdata(spi);
@@ -1022,13 +1022,13 @@ static int __maybe_unused hi3110_can_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(hi3110_can_pm_ops, hi3110_can_suspend, hi3110_can_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(hi3110_can_pm_ops, hi3110_can_suspend, hi3110_can_resume);
static struct spi_driver hi3110_can_driver = {
.driver = {
.name = DEVICE_NAME,
.of_match_table = hi3110_of_match,
- .pm = &hi3110_can_pm_ops,
+ .pm = pm_sleep_ptr(&hi3110_can_pm_ops),
},
.id_table = hi3110_id_table,
.probe = hi3110_can_probe,
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 0d0190ae094a..d971890487b6 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1490,7 +1490,7 @@ static void mcp251x_can_remove(struct spi_device *spi)
free_candev(net);
}
-static int __maybe_unused mcp251x_can_suspend(struct device *dev)
+static int mcp251x_can_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1517,7 +1517,7 @@ static int __maybe_unused mcp251x_can_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mcp251x_can_resume(struct device *dev)
+static int mcp251x_can_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1551,14 +1551,14 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
+static DEFINE_SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
mcp251x_can_resume);
static struct spi_driver mcp251x_can_driver = {
.driver = {
.name = DEVICE_NAME,
.of_match_table = mcp251x_of_match,
- .pm = &mcp251x_can_pm_ops,
+ .pm = pm_sleep_ptr(&mcp251x_can_pm_ops),
},
.id_table = mcp251x_id_table,
.probe = mcp251x_can_probe,
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 24/37] can: cc770: don't discard the IRQ lookup error in probe
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (22 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 23/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 25/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
` (13 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Chaosheng Qu, Marc Kleine-Budde
From: Chaosheng Qu <quchaosheng000406@163.com>
cc770_platform_probe() collapses every failure of platform_get_irq()
into -ENODEV:
irq = platform_get_irq(pdev, 0);
if (!mem || irq <= 0)
return -ENODEV;
That discards -EPROBE_DEFER, so a probe that has to wait for its
interrupt controller is never retried and the device stays unbound.
Return the lookup error unchanged, which is what the neighbouring CAN
platform drivers already do (c_can_platform.c, flexcan-core.c,
sja1000_platform.c). A device tree without an interrupt now reports
-ENXIO rather than -ENODEV; the driver core treats those two the same
way, so the outcome does not change.
The memory resource is checked first and on its own, so a missing
region no longer triggers an IRQ lookup that cannot succeed.
Assisted-by: LLM
Signed-off-by: Chaosheng Qu <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20261009105556.301821-1-quchaosheng000406@163.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/cc770/cc770_platform.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c
index b6c4f02ffb97..64fbdf14e8ab 100644
--- a/drivers/net/can/cc770/cc770_platform.c
+++ b/drivers/net/can/cc770/cc770_platform.c
@@ -156,10 +156,13 @@ static int cc770_platform_probe(struct platform_device *pdev)
int err, irq;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!mem || irq <= 0)
+ if (!mem)
return -ENODEV;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
mem_size = resource_size(mem);
if (!request_mem_region(mem->start, mem_size, pdev->name))
return -EBUSY;
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 25/37] can: cc770: fix the clock divider check on the platform bus
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (23 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 24/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 26/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
` (12 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Quchaosheng, Marc Kleine-Budde
From: Quchaosheng <quchaosheng000406@163.com>
cc770_get_platform_data() tests priv->cpu_interface for CPUIF_DSC before
assigning it from pdata->cir:
priv->can.clock.freq = pdata->osc_freq;
if (priv->cpu_interface & CPUIF_DSC)
priv->can.clock.freq /= 2;
priv->clkout = pdata->cor;
priv->bus_config = pdata->bcr;
priv->cpu_interface = pdata->cir;
priv comes from alloc_cc770dev() -> alloc_candev() -> alloc_netdev_mqs(),
which uses kvzalloc_flex(), so cpu_interface is still zero here and the
test can never match.
A board that sets CPUIF_DSC in pdata->cir therefore gets its system clock
halved in the hardware but not in can.clock.freq, and the bit timing is
computed from twice the real clock. The platform data example in the file
header, .cir = 0x41, sets that bit.
Assign pdata->cir before the test, as the ISA path in cc770_isa.c already
does.
Fixes: e285e44d91fe ("can: cc770: add platform bus driver for the CC770 and AN82527")
Assisted-by: LLM
Signed-off-by: Quchaosheng <quchaosheng000406@163.com>
Link: https://patch.msgid.link/20260917114311.534863-1-quchaosheng000406@163.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/cc770/cc770_platform.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c
index 64fbdf14e8ab..ac81670762c7 100644
--- a/drivers/net/can/cc770/cc770_platform.c
+++ b/drivers/net/can/cc770/cc770_platform.c
@@ -137,11 +137,11 @@ static int cc770_get_platform_data(struct platform_device *pdev,
struct cc770_platform_data *pdata = dev_get_platdata(&pdev->dev);
priv->can.clock.freq = pdata->osc_freq;
+ priv->cpu_interface = pdata->cir;
if (priv->cpu_interface & CPUIF_DSC)
priv->can.clock.freq /= 2;
priv->clkout = pdata->cor;
priv->bus_config = pdata->bcr;
- priv->cpu_interface = pdata->cir;
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 26/37] can: ems_usb: use usb_kill_urb() to stop the intr URB
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (24 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 25/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 27/37] can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb() Marc Kleine-Budde
` (11 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Fan Wu, stable, Song Li,
Marc Kleine-Budde
From: Fan Wu <fanwu01@zju.edu.cn>
The intr URB submitted in ems_usb_start() is not anchored, and its
completion handler ems_usb_read_interrupt_callback() resubmits it, so
it stays in flight as long as the interface is up. But unlink_all_urbs()
stops this URB with usb_unlink_urb(), which only initiates an
asynchronous unlink and returns without waiting for the handler.
The handler can therefore still be running while ems_usb_disconnect()
frees its data: it reads the transfer buffer dev->intr_in_buffer, which
is kfree()d there, and dereferences the private context, which is
released via free_candev() together with the network device.
Fix this by stopping the intr URB with usb_kill_urb(), which waits
until the handler has returned, so the frees in ems_usb_disconnect()
happen strictly after the last callback.
The handler treats the -ENOENT completion of a killed URB as terminal and
does not take RTNL or any sleeping lock, so the resubmit loop is cut and
no RTNL deadlock occurs.
This issue was found by an in-house static analysis tool.
Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface")
Cc: stable@vger.kernel.org
Co-developed-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260923030522.409344-1-fanwu01@zju.edu.cn
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/ems_usb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 24cf8f651f8f..2d31f0b86859 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -748,7 +748,7 @@ static void unlink_all_urbs(struct ems_usb *dev)
{
int i;
- usb_unlink_urb(dev->intr_urb);
+ usb_kill_urb(dev->intr_urb);
usb_kill_anchored_urbs(&dev->rx_submitted);
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 27/37] can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb()
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (25 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 26/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
@ 2026-10-09 13:27 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 28/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
` (10 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:27 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Marc Kleine-Budde
After the call to can_put_echo_skb() in acc_start_xmit() the skb should be
considered invalid and not accessed anymore, but acc_txq_put() will access
the skb's data.
So far acc_txq_put() first loads the CAN data into the controller then
starts the TX. Move the start-TX functionality into the acc_txq_start()
function.
In acc_start_xmit(), first load the data into the controller using
acc_txq_put(), then can_put_echo_skb() and finally start the TX with
acc_txq_start().
Link: https://patch.msgid.link/20260929-esd-fix-skb-deref-v2-1-542e3e19fb25@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/esd/esdacc.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/can/esd/esdacc.c b/drivers/net/can/esd/esdacc.c
index 73e66f9a3781..05d41ed34a02 100644
--- a/drivers/net/can/esd/esdacc.c
+++ b/drivers/net/can/esd/esdacc.c
@@ -62,14 +62,17 @@ static void acc_resetmode_leave(struct acc_core *core)
acc_resetmode_entered(core);
}
-static void acc_txq_put(struct acc_core *core, u32 acc_id, u32 acc_dlc,
- const void *data)
+static void acc_txq_put(struct acc_core *core, u32 acc_dlc, const void *data)
{
acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1,
*((const u32 *)(data + 4)));
acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_0,
*((const u32 *)data));
acc_write32(core, ACC_CORE_OF_TXFIFO_DLC, acc_dlc);
+}
+
+static void acc_txq_start(struct acc_core *core, u32 acc_id)
+{
/* CAN id must be written at last. This write starts TX. */
acc_write32(core, ACC_CORE_OF_TXFIFO_ID, acc_id);
}
@@ -287,11 +290,12 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
acc_id = cf->can_id & CAN_SFF_MASK;
}
- can_put_echo_skb(skb, netdev, core->tx_fifo_head, 0);
+ acc_txq_put(core, acc_dlc, cf->data);
+ can_put_echo_skb(skb, netdev, core->tx_fifo_head, 0);
core->tx_fifo_head = acc_tx_fifo_next(core, tx_fifo_head);
- acc_txq_put(core, acc_id, acc_dlc, cf->data);
+ acc_txq_start(core, acc_id);
return NETDEV_TX_OK;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 28/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (26 preceding siblings ...)
2026-10-09 13:27 ` [PATCH net-next 27/37] can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb() Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 29/37] can: f81604: f81604_close(): fix use-after-free on disconnect Marc Kleine-Budde
` (9 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Wentao Liang, stable,
Marc Kleine-Budde
From: Wentao Liang <vulab@iscas.ac.cn>
of_find_node_by_phandle() takes a reference on the GPR node and the error
path releases it through out_put_nodeq. The success path returns before
reaching that label, so the reference is leaked every time the stop mode is
set up successfully, and the node can never be freed.
Release the node reference before returning.
Fixes: e9f2a856e102 ("can: flexcan: fix an use-after-free in flexcan_setup_stop_mode()")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
Link: https://patch.msgid.link/20260917095302.2145506-1-vulab@iscas.ac.cn
[mkl: update Fixes: tag]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/flexcan/flexcan-core.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 86b40abe9e76..30ae7c344a05 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1986,6 +1986,7 @@ static int flexcan_setup_stop_mode_gpr(struct platform_device *pdev)
"gpr %s req_gpr=0x02%x req_bit=%u\n",
gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit);
+ of_node_put(gpr_np);
return 0;
out_put_node:
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 29/37] can: f81604: f81604_close(): fix use-after-free on disconnect
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (27 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 28/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 30/37] can: hi311x: drop hi3110_lock before free_irq() on open failure Marc Kleine-Budde
` (8 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Ji-Ze Hong (Peter Hong),
Marc Kleine-Budde, stable
From: "Ji-Ze Hong (Peter Hong)" <peter_hong@fintek.com.tw>
Unregister the URBs before cancelling clear_reg_work to prevent an URB
completion handler from scheduling work after cancel_work_sync() has
returned.
Otherwise the pending work may run after the netdev and private data are
freed, resulting in a use-after-free.
Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Closes: https://lore.kernel.org/all/20260824133009.CF85A1F00A3A@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>
Link: https://patch.msgid.link/20260901-f81604-fix-v1-1-c55b5178f9f8@fintek.com.tw
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/f81604.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
index 4c147b9d6d69..bb155b876924 100644
--- a/drivers/net/can/usb/f81604.c
+++ b/drivers/net/can/usb/f81604.c
@@ -1075,10 +1075,10 @@ static int f81604_close(struct net_device *netdev)
f81604_set_reset_mode(priv);
netif_stop_queue(netdev);
- cancel_work_sync(&priv->clear_reg_work);
close_candev(netdev);
f81604_unregister_urbs(priv);
+ cancel_work_sync(&priv->clear_reg_work);
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 30/37] can: hi311x: drop hi3110_lock before free_irq() on open failure
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (28 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 29/37] can: f81604: f81604_close(): fix use-after-free on disconnect Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
` (7 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Runyu Xiao, stable,
Marc Kleine-Budde
From: Runyu Xiao <runyu.xiao@seu.edu.cn>
hi3110_open() requests a threaded IRQ and then performs hardware
setup while holding priv->hi3110_lock. If reset, setup, or
normal-mode entry fails, the error path calls free_irq() while still
holding that mutex.
The threaded handler takes priv->hi3110_lock before checking
force_quit, while free_irq() waits for the threaded handler to finish.
That can deadlock the open() rollback path against a pending IRQ
thread.
Set force_quit, drop hi3110_lock before free_irq(), and take the
mutex again for the remaining hardware cleanup.
Fixes: 57e83fb9b746 ("can: hi311x: Add Holt HI-311x CAN driver")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
Link: https://patch.msgid.link/20260820020631.316418-1-runyu.xiao@seu.edu.cn
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/spi/hi311x.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index 076a3efa1bff..927555b5d581 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -787,7 +787,10 @@ static int hi3110_open(struct net_device *net)
return 0;
out_free_irq:
+ priv->force_quit = 1;
+ mutex_unlock(&priv->hi3110_lock);
free_irq(spi->irq, priv);
+ mutex_lock(&priv->hi3110_lock);
hi3110_hw_sleep(spi);
out_close:
hi3110_power_enable(priv->transceiver, 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (29 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 30/37] can: hi311x: drop hi3110_lock before free_irq() on open failure Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
` (6 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Anton Olsson, Jimmy Assarsson,
Marc Kleine-Budde
From: Anton Olsson <anol@kvaser.com>
The check for endpoint addresses in mhydra is redundant as the correct in
and out endpoints will always be first.
Move kvaser_usb_leaf_setup_endpoints() to kvaser_usb_core() and use with
both mhydra and leaf. Remove dev_setup_endpoint() from struct
kvaser_usb_dev_ops.
Signed-off-by: Anton Olsson <anol@kvaser.com>
Reviewed-by: Jimmy Assarsson <extja@kvaser.com>
Link: https://patch.msgid.link/20260817112052.1477126-1-anol@kvaser.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 2 --
.../net/can/usb/kvaser_usb/kvaser_usb_core.c | 19 +++++++++++-
.../net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 30 -------------------
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 17 -----------
4 files changed, 18 insertions(+), 50 deletions(-)
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
index 46a1b6907a50..2e862120ec3f 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
@@ -161,7 +161,6 @@ struct kvaser_usb_net_priv {
* @dev_get_data_busparams: readback data busparams
* @dev_get_berr_counter: used for can.do_get_berr_counter
*
- * @dev_setup_endpoints: setup USB in and out endpoints
* @dev_init_card: initialize card
* @dev_init_channel: initialize channel
* @dev_remove_channel: uninitialize channel
@@ -189,7 +188,6 @@ struct kvaser_usb_dev_ops {
int (*dev_get_data_busparams)(struct kvaser_usb_net_priv *priv);
int (*dev_get_berr_counter)(const struct net_device *netdev,
struct can_berr_counter *bec);
- int (*dev_setup_endpoints)(struct kvaser_usb *dev);
int (*dev_init_card)(struct kvaser_usb *dev);
int (*dev_init_channel)(struct kvaser_usb_net_priv *priv);
void (*dev_remove_channel)(struct kvaser_usb_net_priv *priv);
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
index d0a2a2a33c1c..9687dfb89b4c 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -926,6 +926,23 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
return err;
}
+static int kvaser_usb_setup_endpoints(struct kvaser_usb *dev)
+{
+ struct usb_host_interface *iface_desc;
+ int ret;
+
+ iface_desc = dev->intf->cur_altsetting;
+
+ /* use first bulk endpoint for in and out */
+ ret = usb_find_common_endpoints(iface_desc, &dev->bulk_in,
+ &dev->bulk_out, NULL, NULL);
+
+ if (ret)
+ return -ENODEV;
+
+ return 0;
+}
+
static int kvaser_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -949,7 +966,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
dev->driver_info = driver_info;
ops = driver_info->ops;
- err = ops->dev_setup_endpoints(dev);
+ err = kvaser_usb_setup_endpoints(dev);
if (err) {
dev_err_probe(&intf->dev, err, "Cannot get usb endpoint(s)");
goto free_devlink;
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
index efbb7bed34c9..ad168cad1d78 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
@@ -37,9 +37,6 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_kcan;
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc;
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt;
-#define KVASER_USB_HYDRA_BULK_EP_IN_ADDR 0x82
-#define KVASER_USB_HYDRA_BULK_EP_OUT_ADDR 0x02
-
#define KVASER_USB_HYDRA_MAX_TRANSID 0xff
#define KVASER_USB_HYDRA_MIN_TRANSID 0x01
@@ -1733,32 +1730,6 @@ static int kvaser_usb_hydra_get_berr_counter(const struct net_device *netdev,
return 0;
}
-static int kvaser_usb_hydra_setup_endpoints(struct kvaser_usb *dev)
-{
- const struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *ep;
- int i;
-
- iface_desc = dev->intf->cur_altsetting;
-
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- ep = &iface_desc->endpoint[i].desc;
-
- if (!dev->bulk_in && usb_endpoint_is_bulk_in(ep) &&
- ep->bEndpointAddress == KVASER_USB_HYDRA_BULK_EP_IN_ADDR)
- dev->bulk_in = ep;
-
- if (!dev->bulk_out && usb_endpoint_is_bulk_out(ep) &&
- ep->bEndpointAddress == KVASER_USB_HYDRA_BULK_EP_OUT_ADDR)
- dev->bulk_out = ep;
-
- if (dev->bulk_in && dev->bulk_out)
- return 0;
- }
-
- return -ENODEV;
-}
-
static int kvaser_usb_hydra_init_card(struct kvaser_usb *dev)
{
int err;
@@ -2203,7 +2174,6 @@ const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = {
.dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming,
.dev_get_data_busparams = kvaser_usb_hydra_get_data_busparams,
.dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter,
- .dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints,
.dev_init_card = kvaser_usb_hydra_init_card,
.dev_init_channel = kvaser_usb_hydra_init_channel,
.dev_get_software_info = kvaser_usb_hydra_get_software_info,
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index a876c7819b81..00302b5c6223 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -1964,22 +1964,6 @@ static int kvaser_usb_leaf_get_berr_counter(const struct net_device *netdev,
return 0;
}
-static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev)
-{
- struct usb_host_interface *iface_desc;
- int ret;
-
- iface_desc = dev->intf->cur_altsetting;
-
- /* use first bulk endpoint for in and out */
- ret = usb_find_common_endpoints(iface_desc, &dev->bulk_in, &dev->bulk_out,
- NULL, NULL);
- if (ret)
- return -ENODEV;
-
- return 0;
-}
-
const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
.dev_set_mode = kvaser_usb_leaf_set_mode,
.dev_set_bittiming = kvaser_usb_leaf_set_bittiming,
@@ -1987,7 +1971,6 @@ const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
.dev_set_data_bittiming = NULL,
.dev_get_data_busparams = NULL,
.dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter,
- .dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints,
.dev_init_card = kvaser_usb_leaf_init_card,
.dev_init_channel = kvaser_usb_leaf_init_channel,
.dev_remove_channel = kvaser_usb_leaf_remove_channel,
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (30 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
` (5 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel,
Cen Zhang (Microsoft Security FORGE Labs), AutonomousCodeSecurity,
Xiang Mei (Microsoft), stable, Marc Kleine-Budde
From: "Cen Zhang (Microsoft Security FORGE Labs)" <cenzhang@linux.microsoft.com>
The receive-path command parsers (kvaser_usb_hydra_wait_cmd and
kvaser_usb_hydra_read_bulk_callback) call kvaser_usb_hydra_cmd_size()
without verifying that enough buffer remains. For CMD_EXTENDED,
kvaser_usb_hydra_cmd_size() unconditionally reads a 2-byte len field
at offset 4. A malicious USB device can place a CMD_EXTENDED header at
the end of a 3072-byte bulk transfer such that only 4 bytes remain,
causing a 2-byte slab-out-of-bounds read.
BUG: KASAN: slab-out-of-bounds in kvaser_usb_hydra_wait_cmd+0x3f1/0x480
[kvaser_usb_hydra.c:678]
Read of size 2 at addr ffff888013f7ec00 by task kworker/0:0/9
kvaser_usb_hydra_wait_cmd+0x3f1/0x480
kvaser_usb_hydra_get_software_details+0x1c7/0x5d0
kvaser_usb_probe+0x36a/0x1240
Additionally, if the device sends CMD_EXTENDED with len=0,
kvaser_usb_hydra_cmd_size() returns 0 and the parser loops forever
(pos += 0), permanently burning one CPU core.
A positive but undersized extended length can also pass the buffer extent
check and reach a handler. For example, an 8-byte CMD_RX_MESSAGE_FD at
the end of an RX URB causes kvaser_usb_hydra_rx_msg_ext() to read fixed
fields and payload past the buffer.
Add receive-side length validation which preserves incomplete headers for
reassembly, rejects extended lengths outside 8..128 bytes, and checks each
known extended command against the minimum length its handler consumes.
For CMD_RX_MESSAGE_FD, derive the required length from its flags and DLC
so valid variable-length commands remain accepted. Apply the checks to
both receive paths and clear malformed leftover state before returning.
Fixes: aec5fb2268b7 ("can: kvaser_usb: Add support for Kvaser USB hydra family")
Reported-by: AutonomousCodeSecurity@microsoft.com
Reported-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Closes: https://lore.kernel.org/all/20260819145658.29872-1-blbllhy@gmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Cen Zhang (Microsoft Security FORGE Labs) <cenzhang@linux.microsoft.com>
Link: https://patch.msgid.link/20260910135000.34796-1-cenzhang@linux.microsoft.com
[mkl: reduce scope of err in kvaser_usb_hydra_read_bulk_callback()]
[mkl: increase readability, reformat to make use of ~100 columns]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
.../net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 135 +++++++++++++++++-
1 file changed, 128 insertions(+), 7 deletions(-)
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
index ad168cad1d78..68bbccb94bb1 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
@@ -533,6 +533,82 @@ static size_t kvaser_usb_hydra_cmd_size(struct kvaser_cmd *cmd)
return ret;
}
+/* -EAGAIN means incomplete; -EINVAL rejects an invalid command length. */
+static int kvaser_usb_hydra_cmd_size_rx(struct kvaser_cmd *cmd,
+ size_t remaining, size_t *cmd_len)
+{
+ if (remaining < sizeof(cmd->header.cmd_no))
+ return -EAGAIN;
+
+ if (cmd->header.cmd_no == CMD_EXTENDED &&
+ remaining < offsetof(struct kvaser_cmd_ext, cmd_no_ext))
+ return -EAGAIN;
+
+ *cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+ if (cmd->header.cmd_no != CMD_EXTENDED)
+ return 0;
+
+ if (*cmd_len < offsetof(struct kvaser_cmd_ext, rx_can) ||
+ *cmd_len > KVASER_USB_HYDRA_MAX_CMD_LEN)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int kvaser_usb_hydra_verify_cmd_size(const struct kvaser_cmd *cmd,
+ size_t cmd_len)
+{
+ const struct kvaser_cmd_ext *cmd_ext;
+ size_t min_len;
+
+ if (cmd->header.cmd_no != CMD_EXTENDED)
+ return 0;
+
+ cmd_ext = (const struct kvaser_cmd_ext *)cmd;
+
+ /* Keep this switch in sync with kvaser_usb_hydra_handle_cmd_ext(). */
+ switch (cmd_ext->cmd_no_ext) {
+ case CMD_TX_ACKNOWLEDGE_FD:
+ min_len = offsetof(struct kvaser_cmd_ext, tx_ack.timestamp) +
+ sizeof(cmd_ext->tx_ack.timestamp);
+ break;
+
+ case CMD_RX_MESSAGE_FD: {
+ u32 flags;
+
+ min_len = offsetof(struct kvaser_cmd_ext, rx_can.kcan_payload);
+ if (cmd_len < min_len)
+ return -EINVAL;
+
+ flags = le32_to_cpu(cmd_ext->rx_can.flags);
+ if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
+ min_len += sizeof(cmd_ext->rx_can.err_frame_data);
+ } else if (!(flags & KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME)) {
+ u32 kcan_header;
+ u8 dlc;
+
+ kcan_header = le32_to_cpu(cmd_ext->rx_can.kcan_header);
+ dlc = (kcan_header & KVASER_USB_KCAN_DATA_DLC_MASK) >>
+ KVASER_USB_KCAN_DATA_DLC_SHIFT;
+
+ if (flags & KVASER_USB_HYDRA_CF_FLAG_FDF)
+ min_len += can_fd_dlc2len(dlc);
+ else
+ min_len += can_cc_dlc2len(dlc);
+ }
+ break;
+ }
+
+ default:
+ return 0;
+ }
+
+ if (cmd_len < min_len)
+ return -EINVAL;
+
+ return 0;
+}
+
static struct kvaser_usb_net_priv *
kvaser_usb_hydra_net_priv_from_cmd(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
@@ -672,8 +748,9 @@ static int kvaser_usb_hydra_wait_cmd(const struct kvaser_usb *dev, u8 cmd_no,
size_t cmd_len;
tmp_cmd = buf + pos;
- cmd_len = kvaser_usb_hydra_cmd_size(tmp_cmd);
- if (pos + cmd_len > actual_len) {
+ err = kvaser_usb_hydra_cmd_size_rx(tmp_cmd, actual_len - pos,&cmd_len);
+ if (err || pos + cmd_len > actual_len ||
+ kvaser_usb_hydra_verify_cmd_size(tmp_cmd, cmd_len)) {
dev_err_ratelimited(&dev->intf->dev,
"Format error\n");
break;
@@ -2091,27 +2168,60 @@ static void kvaser_usb_hydra_read_bulk_callback(struct kvaser_usb *dev,
spin_lock_irqsave(usb_rx_leftover_lock, irq_flags);
usb_rx_leftover_len = card_data->usb_rx_leftover_len;
if (usb_rx_leftover_len) {
+ const size_t cmd_size_field_end = offsetof(struct kvaser_cmd_ext, cmd_no_ext);
int remaining_bytes;
+ int err;
cmd = (struct kvaser_cmd *)card_data->usb_rx_leftover;
- cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+ if (cmd->header.cmd_no == CMD_EXTENDED &&
+ usb_rx_leftover_len < cmd_size_field_end) {
+ remaining_bytes = min_t(int, len, cmd_size_field_end - usb_rx_leftover_len);
- remaining_bytes = min_t(unsigned int, len,
+ memcpy(card_data->usb_rx_leftover + usb_rx_leftover_len, buf, remaining_bytes);
+ usb_rx_leftover_len += remaining_bytes;
+ card_data->usb_rx_leftover_len = usb_rx_leftover_len;
+ pos += remaining_bytes;
+
+ if (usb_rx_leftover_len < cmd_size_field_end) {
+ spin_unlock_irqrestore(usb_rx_leftover_lock,
+ irq_flags);
+ return;
+ }
+ }
+
+ err = kvaser_usb_hydra_cmd_size_rx(cmd, usb_rx_leftover_len,
+ &cmd_len);
+ if (err || cmd_len < usb_rx_leftover_len) {
+ dev_err(&dev->intf->dev, "Format error\n");
+ card_data->usb_rx_leftover_len = 0;
+ spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags);
+ return;
+ }
+
+ remaining_bytes = min_t(unsigned int, len - pos,
cmd_len - usb_rx_leftover_len);
/* Make sure we do not overflow usb_rx_leftover */
if (remaining_bytes + usb_rx_leftover_len >
KVASER_USB_HYDRA_MAX_CMD_LEN) {
dev_err(&dev->intf->dev, "Format error\n");
+ card_data->usb_rx_leftover_len = 0;
spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags);
return;
}
- memcpy(card_data->usb_rx_leftover + usb_rx_leftover_len, buf,
+ memcpy(card_data->usb_rx_leftover + usb_rx_leftover_len, buf + pos,
remaining_bytes);
pos += remaining_bytes;
if (remaining_bytes + usb_rx_leftover_len == cmd_len) {
+ if (kvaser_usb_hydra_verify_cmd_size(cmd, cmd_len)) {
+ dev_err(&dev->intf->dev, "Format error\n");
+ card_data->usb_rx_leftover_len = 0;
+ spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags);
+ return;
+ }
+
kvaser_usb_hydra_handle_cmd(dev, cmd);
usb_rx_leftover_len = 0;
} else {
@@ -2123,11 +2233,17 @@ static void kvaser_usb_hydra_read_bulk_callback(struct kvaser_usb *dev,
spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags);
while (pos < len) {
+ int err;
+
cmd = buf + pos;
- cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+ err = kvaser_usb_hydra_cmd_size_rx(cmd, len - pos, &cmd_len);
+ if (err && err != -EAGAIN) {
+ dev_err(&dev->intf->dev, "Format error\n");
+ return;
+ }
- if (pos + cmd_len > len) {
+ if (err == -EAGAIN || pos + cmd_len > len) {
/* We got first part of a command */
int leftover_bytes;
@@ -2145,6 +2261,11 @@ static void kvaser_usb_hydra_read_bulk_callback(struct kvaser_usb *dev,
break;
}
+ if (kvaser_usb_hydra_verify_cmd_size(cmd, cmd_len)) {
+ dev_err(&dev->intf->dev, "Format error\n");
+ return;
+ }
+
kvaser_usb_hydra_handle_cmd(dev, cmd);
pos += cmd_len;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (31 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
` (4 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Fan Wu, stable, Marc Kleine-Budde
From: Fan Wu <fanwu01@zju.edu.cn>
The bec poll timer is rearmed from the interrupt handler, so the
timer_delete() call in kvaser_pciefd_remove() neither waits for a
callback that is already running nor stops the handler from rearming
the timer until the interrupt is freed later in the same function.
The timer can therefore still be pending or running when free_candev()
frees the CAN device, causing a use-after-free in
kvaser_pciefd_bec_poll_timer().
Use timer_shutdown_sync() instead, which waits for a running callback
and makes a later rearm a no-op. Also drain the timer in
kvaser_pciefd_teardown_can_ctrls(), which frees the CAN devices on the
probe error paths.
This issue was found by an in-house static analysis tool.
Fixes: 26ad340e582d ("can: kvaser_pciefd: Add driver for Kvaser PCIEcan devices")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260818063832.383829-1-fanwu01@zju.edu.cn
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c b/drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c
index d8c9bfb20230..a0597db72086 100644
--- a/drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c
+++ b/drivers/net/can/kvaser_pciefd/kvaser_pciefd_core.c
@@ -1739,6 +1739,7 @@ static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie)
iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
kvaser_pciefd_pwm_stop(can);
kvaser_pciefd_devlink_port_unregister(can);
+ timer_shutdown_sync(&can->bec_poll_timer);
free_candev(can->can.dev);
}
}
@@ -1879,7 +1880,7 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev)
struct kvaser_pciefd_can *can = pcie->can[i];
unregister_candev(can->can.dev);
- timer_delete(&can->bec_poll_timer);
+ timer_shutdown_sync(&can->bec_poll_timer);
kvaser_pciefd_pwm_stop(can);
kvaser_pciefd_devlink_port_unregister(can);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (32 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
` (3 subsequent siblings)
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Jiale Yao, Marc Kleine-Budde
From: Jiale Yao <yaojiale02@163.com>
A device bound through driver_override need not match an entry in the
driver tables. In that case spi_get_device_match_data() returns NULL, but
mcp251xfd_probe() dereferences the result while copying the device type
data.
Reject devices without match data before continuing probe.
Signed-off-by: Jiale Yao <yaojiale02@163.com>
Link: https://patch.msgid.link/20260925133716.2230252-1-yaojiale02@163.com
Fixes: 55e5b97f003e ("can: mcp25xxfd: add driver for Microchip MCP25xxFD SPI CAN")
[mkl: update Fixes tag]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index f441f2265299..8759bc05bd8f 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -2213,6 +2213,7 @@ MODULE_DEVICE_TABLE(spi, mcp251xfd_id_table);
static int mcp251xfd_probe(struct spi_device *spi)
{
+ const struct mcp251xfd_devtype_data *devtype_data;
struct net_device *ndev;
struct mcp251xfd_priv *priv;
struct gpio_desc *rx_int;
@@ -2222,6 +2223,10 @@ static int mcp251xfd_probe(struct spi_device *spi)
u32 freq = 0;
int err;
+ devtype_data = spi_get_device_match_data(spi);
+ if (!devtype_data)
+ return -ENODATA;
+
if (!spi->irq)
return dev_err_probe(&spi->dev, -ENXIO,
"No IRQ specified (maybe node \"interrupts-extended\" in DT missing)!\n");
@@ -2307,7 +2312,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
priv->reg_vdd = reg_vdd;
priv->reg_xceiver = reg_xceiver;
priv->xstbyen = device_property_present(&spi->dev, "microchip,xstbyen");
- priv->devtype_data = *(struct mcp251xfd_devtype_data *)spi_get_device_match_data(spi);
+ priv->devtype_data = *devtype_data;
/* Errata Reference:
* mcp2517fd: DS80000792C 5., mcp2518fd: DS80000789E 4.,
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (33 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
` (2 subsequent siblings)
37 siblings, 1 reply; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Wentao Liang, stable,
Marc Kleine-Budde
From: Wentao Liang <vulab@iscas.ac.cn>
In sun4ican_probe(), the clock is obtained with of_clk_get(), which returns
a reference that must be released with clk_put(). If platform_get_irq(),
devm_platform_ioremap_resource(), alloc_candev() or register_candev()
fails, the reference is never released, leaking the clock.
Fix this by adding an exit_put_clk label that releases the clock and
jumping to it from all error paths after the of_clk_get() call.
Fixes: 0738eff14d81 ("can: Allwinner A10/A20 CAN Controller support - Kernel module")
Cc: stable@vger.kernel.org
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
Link: https://patch.msgid.link/20260917104514.2147347-1-vulab@iscas.ac.cn
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/sun4i_can.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
index af52285d5a4e..311526107ed8 100644
--- a/drivers/net/can/sun4i_can.c
+++ b/drivers/net/can/sun4i_can.c
@@ -854,13 +854,13 @@ static int sun4ican_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
err = -ENODEV;
- goto exit;
+ goto exit_put_clk;
}
addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(addr)) {
err = PTR_ERR(addr);
- goto exit;
+ goto exit_put_clk;
}
dev = alloc_candev(sizeof(struct sun4ican_priv), 1);
@@ -868,7 +868,7 @@ static int sun4ican_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"could not allocate memory for CAN device\n");
err = -ENOMEM;
- goto exit;
+ goto exit_put_clk;
}
dev->netdev_ops = &sun4ican_netdev_ops;
@@ -908,6 +908,8 @@ static int sun4ican_probe(struct platform_device *pdev)
exit_free:
free_candev(dev);
+exit_put_clk:
+ clk_put(clk);
exit:
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (34 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
2026-10-09 13:57 ` [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Hemanth Selam, Marc Kleine-Budde
From: Hemanth Selam <hemanth.selam@gmail.com>
Drop the second 'is', reported by checkpatch.pl as a possible repeated
word. Only touches a comment, no code changes.
Assisted-by: Cursor:claude-opus-5
Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com>
Link: https://patch.msgid.link/20260904125018.10923-1-hemanth.selam@gmail.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/ucan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index f72e0644c5fd..6b088a05a901 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -61,7 +61,7 @@
* the following way:
*
* m[n].len <=> the length if message n(including the header in bytes)
- * m[n] is is aligned to a 4 byte boundary, hence
+ * m[n] is aligned to a 4 byte boundary, hence
* offset(m[0]) := 0;
* offset(m[n+1]) := offset(m[n]) + (m[n].len + 3) & 3
*
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (35 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
@ 2026-10-09 13:28 ` Marc Kleine-Budde
2026-10-09 13:57 ` [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:28 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Maximilian Zimmermann, stable,
Marc Kleine-Budde
From: Maximilian Zimmermann <maxz@spacecubics.com>
The Xilinx CAN FD controller reports the bit rate switch (BRS) and error
state indicator (ESI) in the receive buffer DLC register. The receive
path currently uses this register to determine frame format and payload
length, but does not set BRS and ESI in struct canfd_frame::flags.
This results in applications being unable to receive the BRS and ESI
flags, even when the controller correctly received them.
Add the ESI register mask and copy the controller flags to the
corresponding SocketCAN canfd_frame struct.
Fixes: c223da689324 ("can: xilinx_can: Add support for CANFD FD frames")
Cc: stable@vger.kernel.org
Signed-off-by: Maximilian Zimmermann <maxz@spacecubics.com>
Link: https://patch.msgid.link/20260921-fix-xilinx-canfd-flags-v1-1-a371c90b4e7c@spacecubics.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/xilinx_can.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index 43d7f22820b8..52661e088205 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -157,6 +157,7 @@ enum xcan_reg {
#define XCAN_2_FSR_RI_MASK 0x0000003F /* RX Read Index */
#define XCAN_DLCR_EDL_MASK 0x08000000 /* EDL Mask in DLC */
#define XCAN_DLCR_BRS_MASK 0x04000000 /* BRS Mask in DLC */
+#define XCAN_DLCR_ESI_MASK 0x02000000 /* ESI Mask in DLC */
#define XCAN_ECC_CFG_REECRX_MASK BIT(2) /* Reset RX FIFO ECC error counters */
#define XCAN_ECC_CFG_REECTXOL_MASK BIT(1) /* Reset TXOL FIFO ECC error counters */
#define XCAN_ECC_CFG_REECTXTL_MASK BIT(0) /* Reset TXTL FIFO ECC error counters */
@@ -959,6 +960,11 @@ static int xcanfd_rx(struct net_device *ndev, int frame_base)
/* Check the frame received is FD or not*/
if (dlc & XCAN_DLCR_EDL_MASK) {
+ if (dlc & XCAN_DLCR_BRS_MASK)
+ cf->flags |= CANFD_BRS;
+ if (dlc & XCAN_DLCR_ESI_MASK)
+ cf->flags |= CANFD_ESI;
+
for (i = 0; i < cf->len; i += 4) {
dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base) +
(dwindex * XCANFD_DW_BYTES);
--
2.53.0
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 0/37] pull-request: can-next 2026-10-09
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
` (36 preceding siblings ...)
2026-10-09 13:28 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
@ 2026-10-09 13:57 ` Marc Kleine-Budde
37 siblings, 0 replies; 57+ messages in thread
From: Marc Kleine-Budde @ 2026-10-09 13:57 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel
[-- Attachment #1: Type: text/plain, Size: 1771 bytes --]
On 09.10.2026 15:27:32, Marc Kleine-Budde wrote:
> Hello netdev-team,
>
> this is a pull request of 37 patches for net-next/main.
>
> The first patch is by Vincent Mailhol and drops CAN-XL frames on non
> CAN-XL devices.
>
> A patch by Sang-Heon Jeon removes a redundant NULL check before
> netdev_hold() in the CAN RAW protocol.
>
> Oliver Hartkopp's patch converts the unreliable ARPHRD_CAN type check
> to the robust can_get_ml_priv().
>
> A patch by Runyu Xiao for CAN proc resets the pkg_stats using atomics
> individually. Oliver Hartkopp also contributes a patch for the CAN
> proc to remove kernel pointers from the output.
>
> Tetsuo Handa's patch cancels pending address claim timers in
> j1939_ecu_unmap_all().
>
> A patch by Kaixuan Li for the CAN ISOTP protocol improves the check
> for the correct CAN CC/FD frames.
>
> The next 3 patches are by Cunhao Lu and make CAN skb freeing safe in
> any context in several CAN helper functions.
>
> Claudiu Beznea contributes 5 patches for the rcar_canfd driver to add
> support for Renesas RZ/G3S.
>
> Krzysztof Kozlowski's patch updates the renesas,rcar-canfd DT bindings
> to restrict the resets in top-level.
>
> Biju Das's series of 3 patches add support for Renesas RZ/G3L CANFD to
> the rcar_canfd driver.
>
> Quchaosheng contributes 2 patches to convert the gr_can DR bindings to
> DT schema.
Forgot to mention, that a patch by Oliver Hartkopp removes the Softing
CANcard driver.
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 03/37] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()
2026-10-09 13:27 ` [PATCH net-next 03/37] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv() Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The commit message calls the change a conversion of 'unreliable'
ARPHRD_CAN checks to 'robust' can_get_ml_priv() checks.
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but isotp_bind()
in net/can/isotp.c ignores the return values of both can_rx_register()…
--
can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()
This patch replaces the remaining dev->type != ARPHRD_CAN checks in
af_can, bcm, gw, isotp and raw with can_get_ml_priv(). The reason given is
that TUNSETLINK can switch a down TUN/TAP device to ARPHRD_CAN while its
ml_priv stays NULL.
Link: https://patch.msgid.link/20261009121115.61012-1-socketcan@hartkopp.net
> diff --git a/net/can/af_can.c b/net/can/af_can.c
> index 34fe3b28d576f..dc27ace43719d 100644
> --- a/net/can/af_can.c
> +++ b/net/can/af_can.c
[ ... ]
> @@ -519,7 +519,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
> struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
> struct can_dev_rcv_lists *dev_rcv_lists;
>
> - if (dev && dev->type != ARPHRD_CAN)
> + if (dev && !can_get_ml_priv(dev))
> return;
[Severity: Low]
The commit message describes this change as replacing "unreliable" checks
with "robust" ones. Should it also say that the change closes a NULL
pointer dereference that a user can trigger?
Before this patch, the sequence looks like this:
ioctl(TUNSETLINK, ARPHRD_CAN) on a down tun device
tun->dev->type = (int) arg; /* ml_priv stays NULL */
isotp_bind()
old dev->type != ARPHRD_CAN check passes
can_rx_register() returns -ENODEV, return value ignored
so->bound = 1; so->dev = dev;
isotp_release() or isotp_notify()
can_rx_unregister(net, so->dev, ...)
old dev->type != ARPHRD_CAN guard passes
can_dev_rcv_lists_find()
can_ml = can_get_ml_priv(dev); /* NULL */
return &can_ml->dev_rcv_lists;
hlist_for_each_entry_rcu() walks the near-NULL pointer
dev_rcv_lists sits at offset 0 of struct can_ml_priv, so the returned
pointer is near-NULL and the list walk oopses.
Triggering this only requires owning a tun device, or CAP_NET_ADMIN inside
an unprivileged user namespace.
The patch carries a Cc: stable tag. Could the message name the oops in
can_rx_unregister() (reached through isotp_release() or isotp_notify()) and
the privilege needed to trigger it?
[ ... ]
> diff --git a/net/can/isotp.c b/net/can/isotp.c
> index f5dc9d04bd686..6c28802c0605f 100644
> --- a/net/can/isotp.c
> +++ b/net/can/isotp.c
[ ... ]
> @@ -1610,7 +1611,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
> err = -ENODEV;
> goto out;
> }
> - if (dev->type != ARPHRD_CAN) {
> + if (!can_get_ml_priv(dev)) {
> err = -ENODEV;
> goto out_put_dev;
> }
[Severity: Medium]
This is a pre-existing issue, not one introduced by this patch. Further
down, isotp_bind() still ignores the return values of both
can_rx_register() calls:
if (isotp_register_rxid(so))
can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
isotp_rcv, sk, ...);
...
can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
isotp_rcv_echo, sk, ...);
/* switch to new settings */
...
so->bound = 1;
The can_get_ml_priv() check above now rules out -ENODEV. Using
dev_get_by_index(net, ...) also guarantees the netns matches. That leaves
one possible failure: -ENOMEM from can_rx_register():
rcv = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
if (!rcv)
return -ENOMEM;
If that allocation fails, bind() still returns 0. The socket then never
receives flow control frames, or never receives its own TX echoes.
Transfers would stall until the hrtimers fire. Later, isotp_release() or
isotp_notify() would hit the "receive list entry not found" warning in
can_rx_unregister().
Should isotp_bind() check these return values, and unwind the first
registration if the second one fails?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output
2026-10-09 13:27 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The commit says it stops /proc/net/can/ from leaking kernel
pointers, but on some builds it now leaks a raw kernel text address.
- [Low] The procfs example in Documentation/networking/can.rst was
replaced, but the text around it was not updated.
--
can: proc: remove pointers from CAN specific proc output
This patch stops printing kernel pointers in /proc/net/can/rcvlist_* and
/proc/net/can-bcm/. It prints socket inode numbers and %ps callback names
instead. The ident string argument of can_rx_register() becomes a u64
inode number, and the bcm proc file name is now the inode number in hex.
Link: https://patch.msgid.link/20260815103400.117175-1-socketcan@hartkopp.net
> diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
> index 536ff411da1d1..7bdb27a22a0ea 100644
> --- a/Documentation/networking/can.rst
> +++ b/Documentation/networking/can.rst
> @@ -1042,15 +1042,15 @@ receive lists, their filters and the count of filter matches can be
> checked in the appropriate receive list. All entries contain the
> device and a protocol module identifier::
>
> - foo@bar:~$ cat /proc/net/can/rcvlist_all
> + foo@bar:~$ cat /proc/net/can/rcvlist_fil
>
> - receive list 'rx_all':
> - (vcan3: no entry)
> - (vcan2: no entry)
> - (vcan1: no entry)
> - device can_id can_mask function userdata matches ident
> - vcan0 000 00000000 f88e6370 f6c6f400 0 raw
> + receive list 'rx_fil':
> (any: no entry)
> + device can_id can_mask matches sock_inode function
> + vcan0 80000123 c00007ff 0 000000000000f862 raw_rcv [can_raw]
> + (vcan1: no entry)
> + (vcan2: no entry)
> + (vcan3: no entry)
>
> In this example an application requests any CAN traffic from vcan0::
[Severity: Low]
This isn't a bug, but the text around the new example still describes the
old one. The sentence after the example says:
In this example an application requests any CAN traffic from vcan0::
That matched the old rx_all entry, which had can_id 000 and mask 00000000.
The new entry is in rx_fil with can_id 80000123 and can_mask c00007ff. It
only matches non-RTR EFF frames whose low 11 ID bits are 0x123.
The sentence before the example also still says every entry contains "a
protocol module identifier". The new function column is the %ps name of
the callback. It only shows a "[can_raw]" style tag when the protocol is
built as a module, and it is a plain number on !KALLSYMS builds.
Should this text be updated to match the new output?
[ ... ]
> diff --git a/net/can/proc.c b/net/can/proc.c
> index 64b3bdc2fa7e0..33d99543e3fe2 100644
> --- a/net/can/proc.c
> +++ b/net/can/proc.c
> @@ -215,25 +215,21 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
>
> hlist_for_each_entry_rcu(r, rx_list, list) {
> char *fmt = (r->can_id & CAN_EFF_FLAG)?
> - " %-5s %08x %08x %pK %pK %8ld %s\n" :
> - " %-5s %03x %08x %pK %pK %8ld %s\n";
> + " %6s %08x %08x %8ld %016llx %ps\n" :
> + " %6s %03x %08x %8ld %016llx %ps\n";
>
> seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
> - r->func, r->data, atomic_long_read(&r->matches),
> - r->ident);
> + atomic_long_read(&r->matches), r->ino, r->func);
> }
> }
[Severity: High]
On CONFIG_KALLSYMS=n builds, does can_print_rcvlist() now print a raw
kernel text address?
The old format printed r->func with %pK. %pK follows kptr_restrict, so
unprivileged readers saw a hashed or zeroed value. With %ps, symbol_string()
falls back to the raw value when kallsyms is not built in:
lib/vsprintf.c:symbol_string() {
...
#else
return special_hex_number(buf, end, value, sizeof(void *));
#endif
}
In that case the plain address of raw_rcv, bcm_rx_handler, isotp_rcv,
isotp_rcv_echo, can_can_gw_rcv or j1939_can_recv would be printed.
can_init_proc() creates the rcvlist_* files with mode 0644. An unprivileged
user can also add an entry by opening a CAN_RAW socket, through
raw_enable_filters()->can_rx_register(). CAN has no KALLSYMS dependency in
net/can/Kconfig, and KALLSYMS can be turned off under EXPERT.
Those builds also lose the old r->ident string ("raw", "bcm", "isotp",
"gw", "j1939"). The column then shows only a number, not a protocol
identifier.
Would a fixed per-protocol name work better here? Another option is to
print a placeholder, or keep %pK, when CONFIG_KALLSYMS is off.
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 06/37] can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all()
2026-10-09 13:27 ` [PATCH net-next 06/37] can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all() Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 6 potential
issue(s) to consider.
Critical: 0 (1) · High: 2 (1) · Medium: 1 · Low: 3
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The fix does not fully close the race it targets.
- [High] can: j1939: list corruption in __j1939_ecu_release due to
unlocked list_del
- [Medium] The new cancel loop in j1939_ecu_unmap_all()
(net/can/j1939/bus.c:109-132) ends every non-zero…
- [Low] The commit fixes a user-triggerable refcount leak that hangs
netdev unregister, but it has no 'Fixes:' tag and no 'Cc:…
- [Low] The ownership comment in j1939_ecu_timer_start()
(net/can/j1939/bus.c:142-144) still says the timer-held reference is…
- [Low] The new comment on the hrtimer_try_to_cancel() < 0 branch in
j1939_ecu_unmap_all() (net/can/j1939/bus.c:118) says the timer is…
Pre-existing issues:
- [Critical] This problem wasn't introduced by this patch, but
__j1939_ecu_release() (net/can/j1939/bus.c:17-26) calls…
- [High] This problem wasn't introduced by this patch, but
j1939_ac_process() (net/can/j1939/address-claim.c) takes…
--
can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all()
This patch makes j1939_ecu_unmap_all() cancel pending address claim
hrtimers on priv->ecus before it clears priv->ents[]. The goal is to stop
a late j1939_ecu_timer_handler() from re-mapping an ECU after teardown,
which leaks the ECU's references and hangs unregister_netdevice().
Link: https://patch.msgid.link/9ba38419-967a-4d47-bcdf-bbb2fa7d3e9f@I-love.SAKURA.ne.jp
> Reported-by: syzbot+e2af46126e0644cbebdd@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=e2af46126e0644cbebdd
[Severity: Low]
Should this have a Fixes: tag and a Cc: stable@vger.kernel.org trailer?
j1939_ecu_unmap_all(), j1939_ecu_timer_start(), j1939_ecu_timer_cancel()
and j1939_ecu_timer_handler() all appear unchanged since:
Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol")
Other fixes in the same series do carry Fixes: and Cc: stable trailers.
Examples are "can: proc: reset pkg_stats atomics individually" and "can:
convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv()".
> diff --git a/net/can/j1939/bus.c b/net/can/j1939/bus.c
> index cdc3c0a719379..0d109d1a3b4ae 100644
> --- a/net/can/j1939/bus.c
> +++ b/net/can/j1939/bus.c
> @@ -99,8 +99,38 @@ void j1939_ecu_unmap(struct j1939_ecu *ecu)
> void j1939_ecu_unmap_all(struct j1939_priv *priv)
> {
> int i;
> + struct j1939_ecu *ecu;
>
> write_lock_bh(&priv->lock);
> + /* Cancel all pending address claim timers before unmapping.
> + * This prevents an orphaned late-firing timer from re-mapping
> + * an ECU after the spaces are cleared.
> + */
[Severity: High]
Does this fully close the race? The cancel loop only sees timers that are
armed while priv->lock is held. Nothing seems to stop a new timer from
being armed after the final write_unlock_bh() in this function.
In __j1939_rx_release(), j1939_can_rx_unregister() reaches
can_rx_unregister(). That function only does hlist_del_rcu() and
call_rcu(). It does not wait for a j1939_can_recv() that is already running
on another CPU:
net/can/j1939/main.c:__j1939_rx_release() {
j1939_can_rx_unregister(priv);
j1939_ecu_unmap_all(priv);
j1939_priv_set(priv->ndev, NULL);
...
}
Could this sequence happen?
CPU A CPU B
j1939_can_recv()
j1939_ac_recv()
j1939_ac_process()
__j1939_rx_release()
j1939_can_rx_unregister()
j1939_ecu_unmap_all()
write_lock_bh(&priv->lock)
write_lock_bh(&priv->lock) <cancel timers, clear ents[]>
<spins> write_unlock_bh(&priv->lock)
j1939_ecu_create_locked()
j1939_ecu_timer_start()
j1939_priv_set(priv->ndev, NULL)
250 ms later, j1939_ecu_timer_handler() calls j1939_ecu_map_locked() with
no teardown check. The ECU then goes back into priv->ents[] with an extra
reference.
j1939_priv_get_by_ndev() now returns NULL, so no later
j1939_ecu_unmap_all() can run for this priv. Would the ECU, its
netdev_hold() tracker and its priv reference then leak? That would give the
same "waiting for vxcan1 to become free" hang this patch is meant to fix.
The comment above seems to hold only for timers armed before the loop runs.
Would a synchronize_net() between j1939_can_rx_unregister() and
j1939_ecu_unmap_all() close this? Another option is a teardown flag checked
under priv->lock in j1939_ac_process(), j1939_ecu_timer_start() and
j1939_ecu_timer_handler().
> +rescan_timers:
> + list_for_each_entry(ecu, &priv->ecus, list) {
> + int ret = hrtimer_try_to_cancel(&ecu->ac_timer);
> +
> + if (ret == 0) { /* Not active or already finished. */
> + continue;
> + } else if (ret == 1) { /* Successfully canceled. */
> + /* Drop a ref from j1939_ecu_timer_start(). */
> + j1939_ecu_put(ecu);
[Severity: High]
This looks pre-existing, but the new cancel loop depends on it. When
the last reference to a j1939_ecu goes away, __j1939_ecu_release()
does list_del(&ecu->list) on priv->ecus and frees the ECU. It does
not take priv->lock itself. It therefore relies on every final
j1939_ecu_put() being done under write_lock_bh(&priv->lock).
The lookup helpers do not guarantee that. j1939_ecu_get_by_addr()
and j1939_ecu_get_by_name() take read_lock_bh(&priv->lock), take a
reference and release the lock again. Their callers, for example
j1939_ac_recv(), then call j1939_ecu_put() with no lock held.
In the meantime another path may drop the remaining references under
priv->lock. The unlocked put is then the final one. Its list_del()
can run concurrently with a reader such as j1939_ecu_get_by_name()
walking priv->ecus under read_lock_bh(). It can also race with a
writer such as the rescan loop added here, or the list_add_tail() in
j1939_ecu_create_locked().
Can that corrupt priv->ecus, or let a walker step onto a freed
j1939_ecu?
With this patch, the timer reference of a pending ECU is dropped here
during teardown instead of later by j1939_ecu_timer_handler(). That
makes it more likely that a transient lookup reference ends up being
the last one.
The comment in the -1 branch shows the invariant is already
understood for j1939_ecu_timer_cancel(): an unlocked put must never
be the final reference. Should it also be enforced for the existing
unlocked callers?
Taking priv->lock inside __j1939_ecu_release() would deadlock for
the many callers that already hold it. Would a separate put helper
that wraps kref_put() in write_lock_bh(&priv->lock) work for the
unlocked callers? Or would you rather convert priv->ecus to RCU?
[Severity: Low]
This put is a new third release site for the timer reference. The comment
in j1939_ecu_timer_start() still lists only two:
/* The ECU is held here and released in the
* j1939_ecu_timer_handler() or j1939_ecu_timer_cancel().
*/
Should that comment be updated to mention j1939_ecu_unmap_all()? The same
applies to the ref counting notes in j1939_ac_process().
> + } else { /* Executing on another CPU. */
[Severity: Low]
Is "Executing on another CPU" accurate? The hrtimer_try_to_cancel()
kernel-doc defines -1 only as "the timer is currently executing the
callback function and cannot be stopped".
On PREEMPT_RT without CONFIG_PREEMPT_RT_NEEDS_BH_LOCK, local_bh_disable()
only disables migration. The soft callback can therefore be preempted on
the same CPU before it takes priv->lock. The comment above
hrtimer_cancel_wait_running() describes this case.
The fallback to hrtimer_cancel() handles this correctly, so only the
comment is affected.
> + /* Let j1939_ecu_timer_cancel() determine whether to
> + * drop a ref from j1939_ecu_timer_start(). But guard
> + * with a local ref in order to make sure that unlocked
> + * j1939_ecu_put() from j1939_ecu_timer_cancel() cannot
> + * be the final reference.
> + */
> + j1939_ecu_get(ecu);
[Severity: Critical]
This is a pre-existing issue, but can this kref_get() find an ECU whose
refcount has already reached zero?
__j1939_ecu_release() calls list_del(&ecu->list) on priv->ecus under
whatever lock the final putter holds. j1939_ac_recv() drops its reference
with no lock held, after j1939_ecu_get_by_addr() has released
read_lock_bh:
net/can/j1939/address-claim.c:j1939_ac_recv() {
...
ecu = j1939_ecu_get_by_addr(priv, skcb->addr.sa);
if (ecu) {
skcb->addr.src_name = ecu->name;
j1939_ecu_put(ecu);
}
...
}
Take a mapped remote ECU that holds only its ents[] reference:
CPU X CPU Y
j1939_ac_recv()
j1939_ecu_get_by_addr() /* 2 */
j1939_ac_process() /* idle SA */
write_lock_bh(&priv->lock)
j1939_ecu_get_by_name_locked() /* 3 */
j1939_ecu_unmap_locked() /* 2 */
j1939_ecu_put() /* 1 */
write_unlock_bh(&priv->lock)
j1939_ecu_put() /* 0 */
__j1939_ecu_release()
list_del(&ecu->list) /* priv->lock not held */
kfree(ecu)
A third CPU may be walking or changing priv->ecus under priv->lock at the
same time. Examples are this new rescan loop, j1939_ecu_find_by_name_locked()
and the list_add_tail() in j1939_ecu_create_locked().
Could that corrupt priv->ecus or lead to a use-after-free of the
j1939_ecu? The comment above describes the very invariant that
j1939_ac_recv() breaks: an unlocked j1939_ecu_put() must not be the final
reference.
> + write_unlock_bh(&priv->lock);
> + j1939_ecu_timer_cancel(ecu);
[Severity: High]
This isn't a bug introduced by this patch. Here the lock is dropped before
j1939_ecu_timer_cancel(), but j1939_ac_process() still calls it with
write_lock_bh(&priv->lock) held:
net/can/j1939/address-claim.c:j1939_ac_process() {
...
write_lock_bh(&priv->lock);
...
/* cancel pending (previous) address claim */
j1939_ecu_timer_cancel(ecu);
...
}
hrtimer_cancel() waits for a running callback to finish, and
j1939_ecu_timer_handler() starts with write_lock_bh(&priv->lock). Suppose
an AC frame for a NAME with a different or idle SA arrives just as that
ECU's ac_timer expires:
CPU0 (CAN rx) CPU1 (HRTIMER_SOFTIRQ)
j1939_ac_process()
write_lock_bh(&priv->lock)
j1939_ecu_timer_handler()
write_lock_bh(&priv->lock)
<spins>
j1939_ecu_timer_cancel()
hrtimer_cancel()
<waits for callback>
Can these two CPUs deadlock? On !PREEMPT_RT,
hrtimer_cancel_wait_running() is just cpu_relax(). On PREEMPT_RT this
looks like an ABBA between priv->lock and softirq_expiry_lock.
The new unlocked j1939_ecu_timer_cancel() call here runs with
j1939_netdev_lock or RTNL held. It would also hang behind such a deadlock.
> + write_lock_bh(&priv->lock);
> + j1939_ecu_put(ecu);
> + }
> + goto rescan_timers;
[Severity: Medium]
Can this goto make the walk quadratic? Every nonzero return from
hrtimer_try_to_cancel() restarts the walk from the head of priv->ecus,
with write_lock_bh(&priv->lock) held. ECUs that survive cancellation are
scanned again on every restart.
On the NETDEV_DOWN path, j1939_netdev_notify() calls j1939_ecu_unmap_all()
while sockets are still bound. j1939_sk_netdev_event_netdown() does not
drop their local ECU references.
Consider N bound sockets with distinct NAMEs, each with a 250 ms timer left
pending by AC frames. That looks like O(N^2) work with BH disabled and RTNL
held.
The restart is only needed in the -1 branch, where the lock is dropped. In
the ret == 1 case only the current entry can be freed. Would
list_for_each_entry_safe(), with a restart only in the -1 branch, keep the
common case linear?
> + }
> + /* Unmap any remaining mapped ECUs */
> for (i = 0; i < ARRAY_SIZE(priv->ents); i++)
> if (priv->ents[i].ecu)
> j1939_ecu_unmap_locked(priv->ents[i].ecu);
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context
2026-10-09 13:27 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] Commit "can: skb: make echo skb freeing safe in any IRQ context"
fixes a bug that is real and long-standing, but its message has no…
--
can: skb: make echo skb freeing safe in any IRQ context
This commit changes the kfree_skb() and consume_skb() calls in
can_put_echo_skb(), can_create_echo_skb(), can_dropped_invalid_skb() and
can_dev_dropped_skb() to dev_kfree_skb_any() and dev_consume_skb_any().
With this change, these paths are safe when the caller has hardware
interrupts disabled.
Link: https://patch.msgid.link/tencent_E84809CF236D0137885E7E4E4D58340B3208@qq.com
> can_put_echo_skb() can be called with hardware interrupts disabled. Its
> direct drop paths use kfree_skb(), while can_create_echo_skb() uses
> kfree_skb() when cloning fails and consume_skb() after a successful clone.
> None of these helpers is safe in every IRQ context.
[Severity: Low]
The code change looks fine, but should the commit message have a Fixes:
tag and Cc: stable?
The premise is correct. For example, janz-ican3 reaches
can_create_echo_skb() with hard IRQs disabled:
drivers/net/can/janz-ican3.c:ican3_xmit()
spin_lock_irqsave(&mod->lock, flags);
...
ican3_put_echo_skb(mod, skb);
can_create_echo_skb(skb);
consume_skb(skb); /* or kfree_skb() if skb_clone() fails */
Before this patch, that consume_skb() ran the skb destructor (normally
sock_wfree()) from skb_release_head_state() with IRQs off.
dev_consume_skb_any() and dev_kfree_skb_any() exist to avoid exactly that.
The old code is also in stable trees. Could the message name an affected
caller such as ican3_xmit(), and the commit that introduced the problem?
The companion patch in this series, "can: skb: make CAN skb allocation
failure paths IRQ-safe", does have a Fixes: tag.
> [mkl: also convert can_dropped_invalid_skb(), can_dev_dropped_skb()]
Could the message also say which IRQ-disabled context reaches
can_dropped_invalid_skb() and can_dev_dropped_skb()? Right now the reason
for converting these two helpers isn't given.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 11/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck
2026-10-09 13:27 ` [PATCH net-next 11/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The patch adds an fCAN source taken from fck (`info->fcan_pclk`)
in rcar_canfd_probe(), but the comments and the probe log still…
--
can: rcar_canfd: Allow the CAN FD clock to be sourced from fck
This patch adds an fcan_pclk hardware flag to struct rcar_canfd_hw_info.
When the flag is set and can_clk is missing or runs at 0 Hz,
rcar_canfd_probe() takes fCAN from the peripheral clock (fck) and divides
it by postdiv, rather than looking up the "canfd" clock. Every existing
hw_info instance sets fcan_pclk to 0.
Link: https://lore.kernel.org/all/1d9719e3-10ff-4cd8-b729-55fea93c37ce@wanadoo.fr
Link: https://patch.msgid.link/20260902141544.565763-4-claudiu.beznea+renesas@tuxon.dev
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index b7c4fe3477ac5..f9173774387fa 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
[ ... ]
> @@ -2190,13 +2196,20 @@ static int rcar_canfd_probe(struct platform_device *pdev)
> */
> gpriv->can_clk = devm_clk_get(dev, "can_clk");
> if (IS_ERR(gpriv->can_clk) || (clk_get_rate(gpriv->can_clk) == 0)) {
> - gpriv->can_clk = devm_clk_get(dev, "canfd");
> - if (IS_ERR(gpriv->can_clk))
> - return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
> - "cannot get canfd clock\n");
> + if (info->fcan_pclk) {
> + fcan_freq = clk_get_rate(gpriv->clkp);
> + gpriv->can_clk = NULL;
[Severity: Low]
This isn't a bug, but should the comments and the probe log message be
updated for this new fck path?
The comment just above this hunk in rcar_canfd_probe() still describes
only two choices:
/* fCAN clock: Pick External clock. If not available fallback to
* CANFD clock
*/
When fcan_pclk is set, the fallback is fck (gpriv->clkp) and "canfd" is
never looked up.
On this path gpriv->extclk stays false. The dev_info() at the end of
rcar_canfd_probe() will therefore still print "canfd clk":
dev_info(dev, "global operational state (%s clk, %s mode)\n",
gpriv->extclk ? "ext" : "canfd",
...
But no canfd clock was acquired, and fCAN actually comes from fck.
The field comments in struct rcar_canfd_global are also out of date:
struct clk *can_clk; /* fCAN clock */
...
bool extclk; /* CANFD or Ext clock */
On this path can_clk is now NULL, and there are three possible fCAN
sources, not two.
Every hw_info sets fcan_pclk = 0 in this commit. Later in the series,
r9a08g045_hw_info sets .fcan_pclk = 1 and is used for both RZ/G3S and
RZ/G3L. None of these comments or the log string are changed elsewhere
in the series. On those SoCs, the boot log would report the wrong fCAN
clock source.
> + } else {
> + gpriv->can_clk = devm_clk_get(dev, "canfd");
> + if (IS_ERR(gpriv->can_clk))
> + return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
> + "cannot get canfd clock\n");
> +
> + fcan_freq = clk_get_rate(gpriv->can_clk);
> + }
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 13/37] can: rcar_canfd: Do not set registers selecting the CAN mode
2026-10-09 13:27 ` [PATCH net-next 13/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The commit message does not match the code.
--
can: rcar_canfd: Do not set registers selecting the CAN mode
This patch adds a hardware feature flag to struct rcar_canfd_hw_info. On
RZ/G3S, which only supports CAN-FD mode, the flag makes
rcar_canfd_reset_controller() skip writing the CLOE and FDOE bits in the
channel CAN-FD configuration register. Every existing hw_info instance
now sets the new flag to 0 explicitly.
Link: https://lore.kernel.org/all/1d9719e3-10ff-4cd8-b729-55fea93c37ce@wanadoo.fr
Link: https://patch.msgid.link/20260902141544.565763-5-claudiu.beznea+renesas@tuxon.dev
> Add the mode_select_na flag in struct rcar_canfd_hw_info to cover RZ/G3S
> and avoid writing to unavailable bits.
[Severity: Low]
This isn't a bug, but the flag name in the commit message doesn't match
the code.
The patch adds this field to struct rcar_canfd_hw_info in
drivers/net/can/rcar/rcar_canfd.c:
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index f9173774387fa..ac5d5959d8e4c 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
> @@ -445,6 +445,7 @@ struct rcar_canfd_hw_info {
> unsigned shared_can_regs:1; /* Has shared classical can registers */
> unsigned external_clk:1; /* Has external clock */
> unsigned fcan_pclk:1; /* Has fcan sourced from pclk. */
> + unsigned fixed_canfd:1; /* Has mode fixed to canfd. */
> };
[ ... ]
> @@ -846,6 +852,9 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
> }
>
> /* Set the controller into appropriate mode */
> + if (gpriv->info->fixed_canfd)
> + continue;
> +
Both the hw_info initializers and the check in
rcar_canfd_reset_controller() use fixed_canfd. The name mode_select_na
does not appear anywhere in drivers/net/can/, either at this commit or
later in the series. It looks like the flag was renamed during review
and the commit message was not updated.
Could the commit message be updated to say fixed_canfd?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 15/37] can: rcar_canfd: Add support for Renesas RZ/G3S
2026-10-09 13:27 ` [PATCH net-next 15/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] r9a08g045_hw_info sets fixed_canfd = 1.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but it is
reachable on the newly added RZ/G3S variant.
- [High] This problem wasn't introduced by this patch, but RZ/G3S
(multi_channel_irqs = 1) uses the affected path.
--
can: rcar_canfd: Add support for Renesas RZ/G3S
This commit adds an rcar_canfd_hw_info entry for the RZ/G3S (r9a08g045)
CAN-FD controller and binds it to the "renesas,r9a08g045-canfd"
compatible. The new variant has two channels, 16 AFL pages, per-channel
IRQs, a CAN FD clock taken from pclk and a fixed CAN-FD mode.
Link: https://patch.msgid.link/20260902141544.565763-6-claudiu.beznea+renesas@tuxon.dev
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index ac5d5959d8e4c..74c3c3f20991f 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
> @@ -661,6 +661,26 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
> .fixed_canfd = 0,
> };
>
> +static const struct rcar_canfd_hw_info r9a08g045_hw_info = {
> + .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
[ ... ]
> + .postdiv = 2,
> + .shared_global_irqs = 0,
> + .multi_channel_irqs = 1,
[Severity: High]
This is a pre-existing issue and was not introduced by this patch. RZ/G3S
sets multi_channel_irqs, so it uses the affected path. Can the IRQ
handlers touch a channel object after it has been freed?
rcar_canfd_channel_probe() registers the per-channel handlers with priv
as dev_id:
err = devm_request_irq(dev, err_irq,
rcar_canfd_channel_err_interrupt, 0,
irq_name, priv);
priv lives inside the ndev allocation. rcar_canfd_channel_remove()
frees that allocation with free_candev(priv->ndev), but the managed IRQs
are only released after remove() returns.
Nothing calls synchronize_irq(), devm_free_irq() or disable_irq() before
the free, and gpriv->ch[ch] is never cleared.
rcar_canfd_disable_channel_interrupts() only masks the controller. It
does not wait for a handler that is already running on another CPU.
The global handlers look easier to hit. In rcar_canfd_remove():
for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]);
rcar_canfd_channel_remove(gpriv, ch);
}
rcar_canfd_global_deinit(gpriv, true);
Channel 0 is freed while channel 1 is still up. The global interrupts
stay enabled until rcar_canfd_global_deinit() runs. If channel 1
traffic or a global error raises g_recc or g_err, the handler walks
every bit in channels_mask:
rcar_canfd_global_receive_fifo_interrupt()
rcar_canfd_handle_global_receive(gpriv, 0)
priv = gpriv->ch[0];
sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(gpriv, ridx));
That reads priv->base from the freed channel 0 object, and the handler
may also schedule priv->napi on it.
Should the IRQs be released or synchronized, and gpriv->ch[ch] cleared,
before free_candev()? Should the global interrupts also be disabled
before any channel is freed?
> + .ch_interface_mode = 1,
> + .shared_can_regs = 1,
> + .external_clk = 1,
> + .fcan_pclk = 1,
> + .fixed_canfd = 1,
[Severity: Low]
With fixed_canfd set, rcar_canfd_reset_controller() skips the mode
programming, so the hardware always stays in CAN-FD mode:
/* Set the controller into appropriate mode */
if (gpriv->info->fixed_canfd)
continue;
rcar_canfd_probe() still reads the DT mode properties without checking
info->fixed_canfd:
if (of_property_read_bool(dev->of_node, "renesas,no-can-fd"))
fdmode = false; /* Classical CAN only mode */
...
if (of_property_read_bool(dev->of_node, "renesas,fd-only"))
gpriv->fd_only_mode = true; /* FD-Only mode for CAN-FD */
If either property appears on an r9a08g045 node, wouldn't the software
state disagree with the hardware?
With renesas,no-can-fd, the FIFOs are set up for 8-byte payloads and
CMPOC is left clear. CMPOF also goes unreported, because
rcar_canfd_global_error() checks gpriv->fdmode first, and
CAN_CTRLMODE_FD is never set.
With renesas,fd-only, the probe message says "fd-only" even though FDOE
is never written.
The binding already forbids both properties for this compatible, so
only a DT that fails schema validation can get here. Would it still be
worth forcing fdmode = true and fd_only_mode = false, with a warning,
when info->fixed_canfd is set?
> +};
> +
> static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
> .nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
> .data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
> @@ -2383,6 +2403,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
>
> static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
> { .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
> + { .compatible = "renesas,r9a08g045-canfd", .data = &r9a08g045_hw_info },
[Severity: High]
This isn't a bug introduced by this patch, but the new compatible makes
it reachable on RZ/G3S. Is the ndev freed twice when register_candev()
fails?
rcar_canfd_channel_probe() publishes the channel before it registers
it:
gpriv->ch[priv->channel] = priv;
err = register_candev(ndev);
if (err) {
...
goto fail_candev;
}
...
fail_candev:
netif_napi_del(&priv->napi);
fail:
free_candev(ndev);
return err;
After this error path, gpriv->ch[ch] still points at the freed priv.
rcar_canfd_probe() then jumps to fail_channel and calls
rcar_canfd_channel_remove() for every bit in channels_mask, including
the channel that just failed:
struct rcar_canfd_channel *priv = gpriv->ch[ch];
if (priv) {
unregister_candev(priv->ndev);
netif_napi_del(&priv->napi);
free_candev(priv->ndev);
}
That reads freed memory and unregisters a netdev that was never
registered. It then calls free_candev() on it a second time.
One way to hit this is a controller node with termination-gpios whose
GPIO provider has not bound yet. In that case can_get_termination()
returns -EPROBE_DEFER and register_candev() fails.
The assignment came from commit c5048a7b2c23ab and the error path from
commit dd3bd23eb43891. Should gpriv->ch[ch] be cleared on this error
path?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 16/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC
2026-10-09 13:27 ` [PATCH net-next 16/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The patch adds the RZ/G3L compatible (renesas,r9a08g046-canfd)
but does not add it to the existing allOf block in…
- [Low] The new RZ/G3L allOf block in
Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml…
--
dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC
This commit adds the renesas,r9a08g046-canfd compatible for the RZ/G3L SoC
to the R-Car CAN FD binding. It adds a new allOf block for RZ/G3L that
covers 11 interrupts, 2 resets and channels 0-2. It also adds RZ/G3L next to
RZ/G3S in the block that disallows renesas,no-can-fd and renesas,fd-only.
Link: https://patch.msgid.link/20261001075742.21961-2-biju.das.jz@bp.renesas.com
> diff --git a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
> index bbaaef8f4282e..cef20f0403715 100644
> --- a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
> +++ b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
[ ... ]
> @@ -292,6 +293,25 @@ allOf:
> patternProperties:
> "^channel[6-7]$": false
>
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: renesas,r9a08g046-canfd
> + then:
> + properties:
> + interrupts:
> + minItems: 11
> +
> + interrupt-names:
> + minItems: 11
[Severity: Low]
Should interrupts and interrupt-names also have maxItems: 11 here?
The top-level interrupts and interrupt-names lists have 20 entries. With
only a lower bound in this block, the schema accepts anywhere from 11 to 20
entries for RZ/G3L. That means ch3_*, ch4_* and ch5_* interrupts pass
validation, even though this same block sets "^channel[3-7]$": false. The
commit message also says the part has 11 interrupts (2 global plus 3 for
each of channels 0-2).
The other variants use exact counts:
RZ/G3S and RZ/G2L: maxItems: 8, combined with the top-level minItems: 8
RZ/G3E: minItems: 20, combined with the implied top-level maximum of 20
Since 11 falls between those two bounds, RZ/G3L seems to need both a
minimum and a maximum. The upper bound is still missing at the end of the
series.
resets had the same problem at this commit, since the top level was
resets: true. That part is fixed later in the series by "dt-bindings: can:
renesas,rcar-canfd: Restrict resets in top-level", which changes the top
level to minItems: 1, maxItems: 2.
> +
> + resets:
> + minItems: 2
[Severity: Medium]
Is renesas,r9a08g046-canfd missing from the existing allOf block that makes
resets and reset-names required? That block still reads:
- if:
properties:
compatible:
contains:
enum:
- renesas,r9a08g045-canfd
- renesas,r9a09g047-canfd
- renesas,rzg2l-canfd
then:
required:
- resets
- reset-names
The minItems: 2 here only applies when resets is present, so it doesn't
make the property required. An RZ/G3L node with no resets and no
reset-names would still pass dtbs_check. Every other variant either
requires resets or forbids them (RZ/T2H).
The driver won't catch the omission either. rcar_canfd_probe() gets both
resets as optional:
gpriv->rstc1 = devm_reset_control_get_optional_exclusive(dev, "rstp_n");
...
gpriv->rstc2 = devm_reset_control_get_optional_exclusive(dev, "rstc_n");
These calls return NULL when the resets are absent. rcar_canfd_global_init()
then calls reset_control_reset() on those NULL handles, which does nothing.
Probe succeeds, but the controller is never reset or released from reset.
This patch does add r9a08g046 next to r9a08g045 in the no-can-fd/fd-only
block. Later in the series, neither "can: rcar_canfd: Add support for
Renesas RZ/G3L" nor "dt-bindings: can: renesas,rcar-canfd: Restrict resets
in top-level" adds it to the required-resets enum.
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 17/37] can: rcar_canfd: Derive max_channels from the device tree
2026-10-09 13:27 ` [PATCH net-next 17/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.
Critical: 0 · High: 0 (2) · Medium: 1 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] rcar_canfd_probe() now sets max_channels from
of_get_child_count(dev->of_node), which is the number of child nodes.
- [Low] The patch removes the per-SoC max_channels from struct
rcar_canfd_hw_info.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but the probe
error path has a use-after-free and double free.
- [High] This problem wasn't introduced by this patch, but the
controller-wide IRQ handlers (rcar_canfd_global_interrupt,…
--
can: rcar_canfd: Derive max_channels from the device tree
This commit removes the per-SoC max_channels from struct
rcar_canfd_hw_info. Probe now gets the channel count from
of_get_child_count(), and the value is stored in struct
rcar_canfd_global. All for_each_set_bit() loops over channels_mask now
use gpriv->max_channels as their bound.
Link: https://patch.msgid.link/20261001075742.21961-3-biju.das.jz@bp.renesas.com
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index 74c3c3f20991f..41c3951189490 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
[ ... ]
> @@ -2145,14 +2139,18 @@ static int rcar_canfd_probe(struct platform_device *pdev)
> bool fdmode = true; /* CAN FD only mode - default */
> char name[9] = "channelX";
> u32 ch, fcan_freq;
> + u8 max_channels;
> int i;
>
> info = of_device_get_match_data(dev);
> + max_channels = of_get_child_count(dev->of_node);
> + if (max_channels > RCANFD_NUM_CHANNELS)
> + return -EINVAL;
[Severity: Low]
With max_channels gone from struct rcar_canfd_hw_info, the only limit
left here is RCANFD_NUM_CHANNELS (8). That is the IP-wide maximum, not
the number of channels a given SoC implements.
Suppose a DT enabled channel2 on a 2-channel part (R-Car Gen3, RZ/G2L,
RZ/G3S, RZ/T2H). Would rcar_canfd_reset_controller() and
rcar_canfd_global_init() then access CCTR/CSTS/RFCC/CFCC/AFL registers
for a channel that does not exist? Probe would then fail after the
CSTS poll times out, with a "reset controller failed" message.
The binding already rejects such DTs for every compatible (for example
"^channel[2-7]$": false). This only affects DTs that fail schema
validation. Is it intended that the driver no longer has a per-SoC
limit?
>
> if (of_property_read_bool(dev->of_node, "renesas,no-can-fd"))
> fdmode = false; /* Classical CAN only mode */
>
> - for (i = 0; i < info->max_channels; ++i) {
> + for (i = 0; i < max_channels; ++i) {
> name[7] = '0' + i;
> of_child = of_get_available_child_by_name(dev->of_node, name);
[Severity: Medium]
Does this loop still find every channel node when the channel numbers
have gaps?
of_get_child_count() returns the number of child nodes. The number in
the "channelN" name, however, is the hardware channel index. It becomes
the bit in channels_mask and the ch used for RCANFD_CCTR(ch),
RCANFD_CSTS(ch), fcbase[ch], the RX FIFO index and the AFL rules.
renesas,rcar-canfd.yaml requires only channel0 and channel1 and allows
any subset of channel[2-7].
Take R-Car V4H as an example. It uses rcar_gen4_hw_info, which had
max_channels = 8 before this patch. With only channel0, channel1 and
channel5 in the DT, max_channels becomes 3. This loop never looks up
channel5, so bit 5 is never set in channels_mask. Every later
for_each_set_bit() is also capped at 3.
Hardware channel 5 is then never put into reset mode, its FIFOs and AFL
rule are never configured, and no candev is registered for it. Probe
still succeeds and nothing is logged. Before this patch, channel5 was
found.
All in-tree dtsi files list their channel nodes without gaps. Setting
status = "disabled" keeps the node, so the count stays the same. Only
DTs that omit a middle channel node or remove it with /delete-node/ are
affected. This code is unchanged at the end of the series.
The commit message says "No functional change". Should this loop be
bounded by the highest channel index, or by a per-SoC limit, rather
than by the number of nodes?
[ ... ]
> @@ -2300,7 +2299,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
> if (err)
> goto fail_mode;
>
> - for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
> + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
> err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
> transceivers[ch]);
> if (err)
> @@ -2314,7 +2313,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
> return 0;
>
> fail_channel:
> - for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels)
> + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
> rcar_canfd_channel_remove(gpriv, ch);
[Severity: High]
This isn't a bug introduced by this patch, but can this cleanup loop
free the failing channel's netdev twice?
rcar_canfd_channel_probe() sets the channel pointer before it calls
register_candev():
gpriv->ch[priv->channel] = priv;
err = register_candev(ndev);
if (err) {
...
goto fail_candev;
}
...
fail_candev:
netif_napi_del(&priv->napi);
fail:
free_candev(ndev);
priv is netdev_priv(ndev). After free_candev(), gpriv->ch[ch] still
holds a non-NULL pointer to freed memory. The fail_channel loop then
visits the same channel, and rcar_canfd_channel_remove() does:
struct rcar_canfd_channel *priv = gpriv->ch[ch];
if (priv) {
unregister_candev(priv->ndev);
netif_napi_del(&priv->napi);
free_candev(priv->ndev);
}
This calls unregister_candev() through freed memory on a netdev that
was never registered. A second free_candev() follows.
The ordering goes back to commit c5048a7b2c23 ("can: rcar_canfd:
rcar_canfd_channel_probe(): register the CAN device when fully ready"),
which moved the gpriv->ch[] assignment ahead of register_candev(). It
is still present at the end of this series.
Would clearing gpriv->ch[priv->channel] on the failure path, or setting
it only after register_candev() succeeds, avoid this?
[ ... ]
> @@ -2327,7 +2326,7 @@ static void rcar_canfd_remove(struct platform_device *pdev)
> struct rcar_canfd_global *gpriv = platform_get_drvdata(pdev);
> u32 ch;
>
> - for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
> + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
> rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]);
> rcar_canfd_channel_remove(gpriv, ch);
> }
[Severity: High]
This is a pre-existing issue, but can the global IRQ handlers
dereference a freed channel while this loop runs?
Four handlers walk every bit in channels_mask: rcar_canfd_global_interrupt(),
rcar_canfd_global_err_interrupt(),
rcar_canfd_global_receive_fifo_interrupt(), and the shared Gen3 handler
rcar_canfd_channel_interrupt(). They use gpriv->ch[ch] with no NULL
check, lock or RCU:
rcar_canfd_handle_global_err() {
struct rcar_canfd_channel *priv = gpriv->ch[ch];
struct net_device *ndev = priv->ndev;
...
gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL);
...
}
In this loop, channel 0 is unregistered and freed while channel 1 is
still running.
rcar_canfd_stop() disables only that channel's CCTR interrupts and its
own FIFOs. The global interrupts stay enabled until
rcar_canfd_global_deinit() runs after the loop. The devm IRQs are
released only after remove() returns.
Suppose a frame arrives on channel 1 in that window. The handler starts
at ch = 0 and reads priv->ndev and priv->base from the freed channel 0
priv, in hardirq context.
rcar_canfd_probe() has a similar window. rcar_canfd_global_init()
enables the global interrupts before rcar_canfd_channel_probe() fills
gpriv->ch[]. Once can0 is registered and brought up, traffic can raise
the global IRQ while gpriv->ch[1] is still NULL. The fail_channel path
also frees channels before the global interrupts are disabled.
This patch only changes the loop bound to gpriv->max_channels. The race
is still present at the end of the series.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 18/37] dt-bindings: net: can: convert grcan to DT schema
2026-10-09 13:27 ` [PATCH net-next 18/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] Commit "dt-bindings: net: can: convert grcan to DT schema"
deletes Documentation/devicetree/bindings/net/can/grcan.txt, but the…
--
dt-bindings: net: can: convert grcan to DT schema
This converts the free-form grcan.txt binding to a YAML DT schema. Because
these nodes have no compatible string, the schema selects them by node name.
The text file is then deleted.
Link: https://patch.msgid.link/20260929073703.2748220-2-quchaosheng000406@163.com
[ ... ]
> diff --git a/Documentation/devicetree/bindings/net/can/grcan.txt b/Documentation/devicetree/bindings/net/can/grcan.txt
> deleted file mode 100644
> index 34ef3498f8870..0000000000000
> --- a/Documentation/devicetree/bindings/net/can/grcan.txt
> +++ /dev/null
> @@ -1,28 +0,0 @@
> -Aeroflex Gaisler GRCAN and GRHCAN CAN controllers.
[ ... ]
[Severity: Low]
After this commit, the file header comment in drivers/net/can/grcan.c still
points to the file being deleted here:
drivers/net/can/grcan.c:
* See "Documentation/devicetree/bindings/net/can/grcan.txt" for information on
* open firmware properties.
Would scripts/documentation-file-ref-check report this as a broken
reference at this commit?
The commit message says "The driver comment is updated by a separate patch."
A later commit in the same series, "can: grcan: update the binding file
reference in the driver comment", changes the comment to point to
aeroflexgaisler,grcan.yaml. So the stale reference only shows up when this
commit is bisected to or backported on its own.
Could the comment update be folded into this patch, or ordered before it?
That would keep the reference valid at every point in the series.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 19/37] can: rcar_canfd: Add support for Renesas RZ/G3L
2026-10-09 13:27 ` [PATCH net-next 19/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
@ 2026-10-10 14:02 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:02 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] This patch maps "renesas,r9a08g046-canfd" (RZ/G3L) to
r9a08g045_hw_info, so RZ/G3L gets exactly the RZ/G3S handling in…
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but it is in the
probe path the new compatible uses.
- [High] This problem wasn't introduced by this patch, but the reused
remove/teardown path frees channel objects while interrupt handlers…
- [Medium] This problem wasn't introduced by this patch, but
rcar_canfd_global_init() already unwinds its own resources on every…
--
can: rcar_canfd: Add support for Renesas RZ/G3L
This adds the "renesas,r9a08g046-canfd" compatible to rcar_canfd_of_table.
The new entry reuses the existing RZ/G3S hardware info, r9a08g045_hw_info.
The commit message says RZ/G3L has 3 channels, 11 interrupts and 288
buffers.
Link: https://patch.msgid.link/20261001075742.21961-4-biju.das.jz@bp.renesas.com
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index 41c3951189490..c643879673680 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
> @@ -2403,6 +2403,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
> static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
> { .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
> { .compatible = "renesas,r9a08g045-canfd", .data = &r9a08g045_hw_info },
> + { .compatible = "renesas,r9a08g046-canfd", .data = &r9a08g045_hw_info },
[Severity: Low]
This entry gives RZ/G3L the same handling as RZ/G3S, and that handling
expects the rstp_n and rstc_n resets. Should the binding also make those
resets mandatory for RZ/G3L?
In renesas,rcar-canfd.yaml, the block that requires them lists only three
compatibles:
- if:
properties:
compatible:
contains:
enum:
- renesas,r9a08g045-canfd
- renesas,r9a09g047-canfd
- renesas,rzg2l-canfd
then:
required:
- resets
- reset-names
The r9a08g046 block only has "resets: minItems: 2", and that rule only
applies when the property is present.
Two other rules list RZ/G3S and RZ/G3L together: the no-can-fd/fd-only ban
and the assigned-clocks exemption. This rule does not.
As a result, an RZ/G3L DT with no resets, or with resets but no
reset-names, still passes dtbs_check. rcar_canfd_probe() gets both resets
as optional:
gpriv->rstc1 = devm_reset_control_get_optional_exclusive(dev, "rstp_n");
...
gpriv->rstc2 = devm_reset_control_get_optional_exclusive(dev, "rstc_n");
Either mistake in the DT returns NULL without an error. In that case
reset_control_reset(NULL) in rcar_canfd_global_init() does nothing. The IP
then stays in reset, and the GRAMINIT/GRSTSTS poll in
rcar_canfd_reset_controller() times out. The resulting probe error does not
mention the missing reset.
The later patch in this series, "dt-bindings: can: renesas,rcar-canfd:
Restrict resets in top-level", does not add r9a08g046 to this list either.
[ ... ]
[Severity: High]
This is a pre-existing issue, not one introduced by this patch, but RZ/G3L
also goes through this probe error path. rcar_canfd_channel_probe() stores
the channel pointer before it registers the netdev:
gpriv->ch[priv->channel] = priv;
err = register_candev(ndev);
if (err) {
...
goto fail_candev;
}
...
fail_candev:
netif_napi_del(&priv->napi);
fail:
free_candev(ndev);
free_candev() frees priv, because priv is netdev_priv(ndev). gpriv->ch[ch]
still points to it afterwards.
rcar_canfd_probe() then unwinds every channel in channels_mask:
fail_channel:
for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
rcar_canfd_channel_remove(gpriv, ch);
rcar_canfd_channel_remove() only checks for NULL:
if (priv) {
unregister_candev(priv->ndev);
netif_napi_del(&priv->napi);
free_candev(priv->ndev);
}
When register_candev() fails, does this read priv->ndev from freed memory?
It would also call unregister_candev() on a netdev that was never
registered, then call free_candev() on the same allocation again.
Could gpriv->ch[ch] be cleared on the fail_candev path, or set only after
register_candev() succeeds?
[Severity: High]
This is also a pre-existing issue, not one introduced by this patch. It
still affects RZ/G3L, which has shared_global_irqs == 0 like RZ/G3S.
rcar_canfd_remove() frees the channels one by one while the global
interrupts are still enabled:
for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels) {
rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]);
rcar_canfd_channel_remove(gpriv, ch);
}
rcar_canfd_global_deinit(gpriv, true);
rcar_canfd_channel_remove() calls free_candev() but does not clear
gpriv->ch[ch]. The global interrupts are masked only later, in
rcar_canfd_global_deinit().
The g_recc and g_err IRQs come from devm_request_irq(), so they stay
registered until remove returns. The same applies to the per-channel
err/trx IRQs, which use the freed priv as dev_id.
Both global handlers loop over every channel in channels_mask and use
gpriv->ch[ch] without checking it:
rcar_canfd_handle_global_receive():
struct rcar_canfd_channel *priv = gpriv->ch[ch];
...
sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(gpriv, ridx));
rcar_canfd_handle_global_err():
struct rcar_canfd_channel *priv = gpriv->ch[ch];
struct net_device *ndev = priv->ndev;
Suppose channel 0 is already freed and channel 1 is still up. A frame
received on channel 1 then raises g_recc:
rcar_canfd_global_receive_fifo_interrupt()
rcar_canfd_handle_global_receive(gpriv, 0)
priv->base, priv->napi <- channel 0, already freed
Can this cause a use-after-free in hardirq context? The g_err path looks
the same: rcar_canfd_handle_global_err() could call
rcar_canfd_global_error() on the freed ndev.
rcar_canfd_disable_channel_interrupts() only clears the CCTR error and
TX-abort enables. It does not affect the global RX FIFO interrupt.
[Severity: Medium]
This is a pre-existing issue as well, not one introduced by this patch.
rcar_canfd_global_init() already unwinds its own resources on every error
path:
fail_mode:
rcar_canfd_disable_global_interrupts(gpriv);
fail_reset2:
reset_control_assert(gpriv->rstc2);
fail_reset1:
reset_control_assert(gpriv->rstc1);
fail_ram_clk:
clk_disable_unprepare(gpriv->clk_ram);
fail_clk:
clk_disable_unprepare(gpriv->clkp);
return err;
rcar_canfd_probe() still sends that failure through the full deinit:
err = rcar_canfd_global_init(gpriv);
if (err)
goto fail_mode;
...
fail_mode:
rcar_canfd_global_deinit(gpriv, false);
rcar_canfd_global_deinit() then calls rcar_canfd_disable_global_interrupts()
again, asserts both resets again, and calls clk_disable_unprepare() on
clk_ram and clkp a second time.
Are both clocks disabled and unprepared twice whenever
rcar_canfd_global_init() fails? Possible triggers are a
reset_control_reset() error, a rcar_canfd_reset_controller() timeout (as in
the missing reset case above), or the GSTS mode change timeout.
If clk_prepare_enable(gpriv->clkp) is the call that failed, the clocks are
disabled without ever having been enabled. In all of these cases, GCTR is
read-modify-written after the module clock has already been turned off.
Should the probe error path jump to fail_dev here instead?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 20/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level
2026-10-09 13:27 ` [PATCH net-next 20/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The binding never makes `resets`/`reset-names` required for
RZ/G3L (`renesas,r9a08g046-canfd`), although the driver treats it…
- [Low] The commit message says the patch disallows "reset-names" for the
two R-Car variants (renesas,rcar-gen3-canfd and renesas,rcar-…
--
dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level
This commit adds top-level minItems: 1 and maxItems: 2 limits to the
resets property. It drops the per-variant maxItems: 2 lines, which the new
top-level limit makes redundant. It also adds reset-names: false to the
R-Car gen3/gen4 conditional block.
Link: https://patch.msgid.link/20261001060825.53335-2-krzysztof.kozlowski@oss.qualcomm.com
> diff --git a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
> index cef20f0403715..4b94bc8d911be 100644
> --- a/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
> +++ b/Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml
[ ... ]
> @@ -232,6 +233,8 @@ allOf:
> resets:
> maxItems: 1
>
> + reset-names: false
> +
[Severity: Low]
The commit message says:
Since top-level part says "reset-names" cannot accept one item, disallow
it for the two variants which do not use it in practice.
Weren't these two variants already blocked from using reset-names before
this patch? Further down in allOf there is an existing block for the same
two compatibles:
- if:
properties:
compatible:
contains:
enum:
- renesas,rcar-gen3-canfd
- renesas,rcar-gen4-canfd
then:
required:
- resets
properties:
reset-names: false
The patch doesn't touch that block. As a result, the added
reset-names: false copies a constraint that already exists, and validation
results don't change.
Could the added line be dropped, or one of the two copies removed and the
commit message reworded? As written, the message describes a behaviour
change that this patch doesn't make.
> - if:
> properties:
> compatible:
> @@ -247,7 +250,6 @@ allOf:
>
> resets:
> minItems: 2
> - maxItems: 2
>
[Severity: Medium]
This patch reworks the per-variant reset constraints. Should
renesas,r9a08g046-canfd (RZ/G3L) also be added to the allOf block that
requires resets and reset-names? That block currently lists only:
- if:
properties:
compatible:
contains:
enum:
- renesas,r9a08g045-canfd
- renesas,r9a09g047-canfd
- renesas,rzg2l-canfd
then:
required:
- resets
- reset-names
The RZ/G3L block only sets resets: minItems: 2. That constraint applies
only when resets is present.
The driver handles RZ/G3L exactly like RZ/G3S. In
drivers/net/can/rcar/rcar_canfd.c:
{ .compatible = "renesas,r9a08g046-canfd", .data = &r9a08g045_hw_info },
rcar_canfd_probe() looks up both resets by name as optional:
gpriv->rstc1 = devm_reset_control_get_optional_exclusive(dev, "rstp_n");
...
gpriv->rstc2 = devm_reset_control_get_optional_exclusive(dev, "rstc_n");
Consider an r9a08g046 node with no resets, or with resets but no
reset-names. It passes dtbs_check, and probe gets NULL handles. Then, in
rcar_canfd_global_init(), the calls
err = reset_control_reset(gpriv->rstc1);
...
err = reset_control_reset(gpriv->rstc2);
do nothing, and rcar_canfd_reset_controller() runs on a block that may
still be held in reset.
This gap came from the earlier commit in this series,
"dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC", not from this
patch. It is still present at the end of the series.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 24/37] can: cc770: don't discard the IRQ lookup error in probe
2026-10-09 13:27 ` [PATCH net-next 24/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The commit message describes a user-visible failure ("a probe
that has to wait for its interrupt controller is never retried and the…
--
can: cc770: don't discard the IRQ lookup error in probe
This patch changes cc770_platform_probe() so that it checks the memory
resource first. It then returns the platform_get_irq() error unchanged
instead of turning every failure into -ENODEV, so -EPROBE_DEFER now
reaches the driver core.
Link: https://patch.msgid.link/20261009105556.301821-1-quchaosheng000406@163.com
> That discards -EPROBE_DEFER, so a probe that has to wait for its
> interrupt controller is never retried and the device stays unbound.
[Severity: Low]
Does any real configuration hit this failure?
The code change looks correct, and so do the technical claims in the
message:
- platform_get_irq() passes -EPROBE_DEFER through.
- call_driver_probe() handles -ENODEV and -ENXIO the same way.
The only in-tree users of cc770_platform are powerpc device trees.
arch/powerpc/boot/dts/tqm8548.dts and tqm8548-bigflash.dts:
compatible = "bosch,cc770";
interrupt-parent = <&mpic>;
arch/powerpc/boot/dts/tqm8xx.dts:
compatible = "intc,82527";
interrupt-parent = <&PIC>;
The MPIC and the 8xx PIC are both set up during init_IRQ, so these
boards should not see -EPROBE_DEFER. No in-tree board file registers
the device through platform data.
The message describes a failure that users would see, but it has no
Fixes: tag. Could it say whether this was seen on real hardware, or
whether it is a robustness and consistency cleanup? Without that, stable
backporters cannot tell which it is.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 26/37] can: ems_usb: use usb_kill_urb() to stop the intr URB
2026-10-09 13:27 ` [PATCH net-next 26/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The commit message describes the disconnect race and leaves out
the more easily reached ifdown/reopen failure that this change also…
Pre-existing issues:
- [Critical] Double free of the DMA-coherent RX buffers in
drivers/net/can/usb/ems_usb.c.
- [Medium] ems_usb_start() returns errors after URBs are already in
flight and does not stop them, and ems_usb_open() does not clean up…
--
can: ems_usb: use usb_kill_urb() to stop the intr URB
This commit replaces usb_unlink_urb() with usb_kill_urb() for the
interrupt URB in unlink_all_urbs(). Teardown now waits for
ems_usb_read_interrupt_callback() to return before ems_usb_disconnect()
frees intr_in_buffer and the candev.
Link: https://patch.msgid.link/20260923030522.409344-1-fanwu01@zju.edu.cn
> The handler can therefore still be running while ems_usb_disconnect()
> frees its data: it reads the transfer buffer dev->intr_in_buffer, which
> is kfree()d there, and dereferences the private context, which is
> released via free_candev() together with the network device.
[Severity: Low]
This disconnect window does exist, but it is fairly narrow.
ems_usb_driver does not set soft_unbind, so usb_unbind_interface() does
this before calling ->disconnect:
drivers/usb/core/driver.c:usb_unbind_interface() {
...
if (!driver->soft_unbind || udev->state == USB_STATE_NOTATTACHED)
usb_disable_interface(udev, intf, false);
driver->disconnect(intf);
...
}
usb_disable_interface() reaches usb_hcd_flush_endpoint(), which kills
the URBs still queued on the endpoint. The only case left is a URB that
the HCD has already dequeued but whose BH giveback has not run yet.
The ifdown path seems easier to hit. In ems_usb_close(), the old
usb_unlink_urb() call did not raise urb->reject. So if the intr URB
completed with status 0 at that moment, the handler resubmitted it:
ems_usb_read_interrupt_callback() {
...
case 0:
dev->free_slots = dev->intr_in_buffer[1];
...
err = usb_submit_urb(urb, GFP_ATOMIC);
...
}
The URB then kept polling after ifdown. The next ems_usb_open() failed
with -EBUSY, and usb_submit_urb() printed the "URB submitted while
active" WARN. This patch fixes that case too.
Should the commit message mention it, since stable backporters may use
it to judge impact?
> The handler treats the -ENOENT completion of a killed URB as terminal and
> does not take RTNL or any sleeping lock, so the resubmit loop is cut and
> no RTNL deadlock occurs.
If the URB completes with status 0 just as it is being killed, the
handler does not see -ENOENT. In that case the loop is stopped by
urb->reject in usb_kill_urb(): the resubmit fails and "failed
resubmitting intr urb" is logged. Could the wording reflect both cases?
> diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
> index 24cf8f651f8f1..2d31f0b86859c 100644
> --- a/drivers/net/can/usb/ems_usb.c
> +++ b/drivers/net/can/usb/ems_usb.c
> @@ -748,7 +748,7 @@ static void unlink_all_urbs(struct ems_usb *dev)
> {
> int i;
>
> - usb_unlink_urb(dev->intr_urb);
> + usb_kill_urb(dev->intr_urb);
>
> usb_kill_anchored_urbs(&dev->rx_submitted);
>
[Severity: Critical]
This is a pre-existing issue and was not introduced by this patch. It is
in the same function and on the same disconnect path, though. Can the
RX coherent buffers be freed twice here?
The loop right after this frees each buffer but never clears the saved
pointers:
for (i = 0; i < MAX_RX_URBS; ++i)
usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
dev->rxbuf[i], dev->rxbuf_dma[i]);
If the interface has been opened at least once, the first free happens
in ems_usb_close(). That runs on a normal ifdown, or from
unregister_netdev() when the device is unplugged while up.
ems_usb_disconnect() then calls unlink_all_urbs() again:
ems_usb_disconnect()
unregister_netdev(dev->netdev); -> ems_usb_close()->unlink_all_urbs()
unlink_all_urbs(dev); -> usb_free_coherent() on same rxbuf[]
hcd_buffer_free() only skips NULL addresses. So the stale pointers go on
to dma_pool_free(), kfree() or gen_pool_free() a second time.
A similar case: after an open/close cycle, a later ems_usb_start() can
leave its RX loop early on an alloc or submit failure. The remaining
rxbuf[] slots then still point at buffers that were already freed.
The free loop came from commit 9969e3c5f40c ("can: ems_usb:
ems_usb_start(): fix possible memory leak"). Would setting
dev->rxbuf[i] = NULL after the free fix this? Another option would be to
avoid the second unlink_all_urbs() call in ems_usb_disconnect().
[Severity: Medium]
This is also pre-existing and was not introduced by this patch. Can
ems_usb_start() return an error while URBs are still in flight?
If the intr URB submit fails, the function returns with the RX URBs
still anchored on dev->rx_submitted and running:
err = usb_submit_urb(dev->intr_urb, GFP_KERNEL);
if (err) {
netdev_warn(netdev, "intr URB submit failed: %d\n", err);
return err;
}
If a later ems_usb_control_cmd() or ems_usb_write_mode() fails, the
failed label only prints a warning and returns. The intr URB and the RX
URBs keep running.
ems_usb_open() handles this with only close_candev(). ndo_stop is not
called after a failed ndo_open, so unlink_all_urbs() never runs. Both
completion handlers keep resubmitting while the interface is down.
On the next open, usb_submit_urb() on the still-active intr_urb hits:
if (urb->hcpriv) {
WARN_ONCE(1, "URB %p submitted while active\n", urb);
return -EBUSY;
}
The open keeps failing until the device is replugged.
Each retry also overwrites dev->rxbuf[] and dev->rxbuf_dma[]. That leaks
the coherent buffers from the earlier attempt: disconnect kills their
URBs through the anchor but never frees the buffers.
With this patch, disconnect at least kills the leftover intr URB
synchronously.
Should the ems_usb_start() error paths kill the intr URB and the
anchored RX URBs before returning?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 27/37] can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb()
2026-10-09 13:27 ` [PATCH net-next 27/37] can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb() Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] This commit fixes a use-after-free that is reachable in practice,
but it has no `Fixes:` or `Cc: stable@vger.kernel.org` trailer.
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but
acc_txq_put() (drivers/net/can/esd/esdacc.c) loads the CAN payload as…
--
can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb()
This commit splits acc_txq_put() in two. acc_txq_put() now only loads the
payload and DLC into the controller, and the new acc_txq_start() writes the
CAN id, which starts the TX. acc_start_xmit() now loads the data before it
calls can_put_echo_skb(), and starts the TX afterwards.
Link: https://patch.msgid.link/20260929-esd-fix-skb-deref-v2-1-542e3e19fb25@pengutronix.de
> After the call to can_put_echo_skb() in acc_start_xmit() the skb should be
> considered invalid and not accessed anymore, but acc_txq_put() will access
> the skb's data.
[Severity: Low]
Should this patch carry a Fixes: tag and Cc: stable@vger.kernel.org?
The phrase "should be considered invalid" makes the problem sound
theoretical. The old ordering looks like a reachable use-after-free, though.
can_put_echo_skb() frees the original skb on several paths:
drivers/net/can/dev/skb.c:can_put_echo_skb() {
...
if (!(dev->flags & IFF_ECHO) || ...) {
dev_kfree_skb_any(skb);
return 0;
}
if (!priv->echo_skb[idx]) {
skb = can_create_echo_skb(skb);
if (!skb)
return -ENOMEM;
...
} else {
...
dev_kfree_skb_any(skb);
return -EBUSY;
}
...
}
can_create_echo_skb() also frees the skb when the GFP_ATOMIC clone fails:
include/linux/can/skb.h:can_create_echo_skb() {
nskb = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!nskb)) {
dev_kfree_skb_any(skb);
return NULL;
}
...
}
In ndo_start_xmit, dev_kfree_skb_any() frees the skb right away. The old
call to acc_txq_put(core, acc_id, acc_dlc, cf->data) then read 8 bytes of
freed memory and loaded them into the TX FIFO as the CAN payload.
This ordering came in with commit 9721866f07e1 ("can: esd: add support for
esd GmbH PCIe/402 CAN interface family"). Could the following be added?
Fixes: 9721866f07e1 ("can: esd: add support for esd GmbH PCIe/402 CAN interface family")
Cc: stable@vger.kernel.org
Could the commit message also say that the old order read freed skb data
whenever can_put_echo_skb() failed?
> diff --git a/drivers/net/can/esd/esdacc.c b/drivers/net/can/esd/esdacc.c
> index 73e66f9a3781c..05d41ed34a02e 100644
> --- a/drivers/net/can/esd/esdacc.c
> +++ b/drivers/net/can/esd/esdacc.c
> @@ -62,14 +62,17 @@ static void acc_resetmode_leave(struct acc_core *core)
> acc_resetmode_entered(core);
> }
>
> -static void acc_txq_put(struct acc_core *core, u32 acc_id, u32 acc_dlc,
> - const void *data)
> +static void acc_txq_put(struct acc_core *core, u32 acc_dlc, const void *data)
> {
> acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1,
> *((const u32 *)(data + 4)));
> acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_0,
> *((const u32 *)data));
[Severity: Medium]
This is a pre-existing issue and was not introduced by this patch. Since
acc_txq_put() is being reworked anyway, are the payload bytes reversed on
big-endian hosts?
The payload is loaded as native-endian u32 values. It is then written with
acc_write32_noswap(), which despite its name goes through iowrite32():
drivers/net/can/esd/esdacc.h:acc_write32_noswap() {
iowrite32(v, core->addr + offs);
}
iowrite32() works like writel() and applies cpu_to_le32(). On a big-endian
CPU, the bytes inside each 32-bit word get swapped. On little-endian, b0
lands in register byte lane 0; on big-endian, b3 lands there.
The RX path in handle_core_msg_rxtxdone() keeps the byte order on any host:
memcpy(cf->data, msg->data, cf->len);
So TX and RX handle the payload differently on BE hosts. The driver only
depends on PCI && HAS_DMA, so it can be built for BE PCI platforms such as
powerpc, parisc or big-endian mips.
Would an accessor that keeps memory byte order work here instead, for
example __raw_writel() or iowrite32_rep(addr, data, 1)?
> acc_write32(core, ACC_CORE_OF_TXFIFO_DLC, acc_dlc);
> +}
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 29/37] can: f81604: f81604_close(): fix use-after-free on disconnect
2026-10-09 13:28 ` [PATCH net-next 29/37] can: f81604: f81604_close(): fix use-after-free on disconnect Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.
Critical: 0 · High: 2 (2) · Medium: 0 (1) · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The fix only covers ndo_stop.
- [High] The fix reorders only one of the two works that the int URB
completion handler can schedule.
- [Low] The patch fixes a use-after-free and carries 'Cc:
stable@vger.kernel.org', but the commit message has no Fixes: tag.
Pre-existing issues:
- [High] Each bus-off restart submits a new set of URBs on top of the
ones that are already running.
- [High] f81604_close() calls close_candev() -> can_flush_echo_skb()
(line 1078) while URB completions can still use priv->echo_skb[0].
- [Medium] f81604_close() puts the controller into reset mode with IER
off (f81604_set_reset_mode(), line 1075) before it stops the async…
--
can: f81604: f81604_close(): fix use-after-free on disconnect
This commit moves cancel_work_sync(&priv->clear_reg_work) in f81604_close()
to after f81604_unregister_urbs(). After that change, an URB completion
handler can no longer schedule clear_reg_work once the cancel has returned.
The goal is to stop the work from running after the netdev and private data
are freed.
Closes: https://lore.kernel.org/all/20260824133009.CF85A1F00A3A@smtp.kernel.org/
Link: https://patch.msgid.link/20260901-f81604-fix-v1-1-c55b5178f9f8@fintek.com.tw
> Cc: stable@vger.kernel.org
[Severity: Low]
This isn't a bug, but should this have a Fixes: tag next to the stable Cc?
The teardown order in f81604_close() looks unchanged since the driver was
added, so the tag would be:
Fixes: 88da17436973 ("can: usb: f81604: add Fintek F81604 support")
> diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
> index 4c147b9d6d690..bb155b8769245 100644
> --- a/drivers/net/can/usb/f81604.c
> +++ b/drivers/net/can/usb/f81604.c
> @@ -1075,10 +1075,10 @@ static int f81604_close(struct net_device *netdev)
> f81604_set_reset_mode(priv);
[Severity: Medium]
This is a pre-existing issue, but can a bus-off restart running at the same
time undo this reset? can_restart_work()->can_restart() does not take RTNL.
The restart_work timer could fire while f81604_set_reset_mode() is doing
its control transfers:
can_restart()
f81604_set_mode(CAN_MODE_START)
f81604_start()
f81604_set_normal_mode()
clears MOD.RM, writes IER = IRQ_ALL & ~RI
In that case, cancel_delayed_work_sync() in close_candev() only waits for
the restart to finish. f81604_unregister_urbs() then kills the URBs the
restart submitted, but nothing puts the chip back into reset mode.
Would ndo_stop then return with the SJA1000 core still in operating mode on
the bus while the netdev is down?
>
> netif_stop_queue(netdev);
> - cancel_work_sync(&priv->clear_reg_work);
> close_candev(netdev);
[Severity: High]
This reorders clear_reg_work, but doesn't restart_work have the same
problem? close_candev() runs cancel_delayed_work_sync(&priv->restart_work)
here, but the int URB stays live until f81604_unregister_urbs() below.
Suppose an int URB completes in that window with F81604_SJA1000_IRQ_EI and
SR.BS set. f81604_handle_can_bus_errors() then does:
if (data->sr & F81604_SJA1000_SR_BS)
can_state = CAN_STATE_BUS_OFF;
...
if (can_state == CAN_STATE_BUS_OFF)
can_bus_off(netdev);
If restart_ms is set, can_bus_off() re-arms the work:
if (priv->restart_ms)
schedule_delayed_work(&priv->restart_work,
msecs_to_jiffies(priv->restart_ms));
The interrupt report could be a buffered or in-flight one, or come from a
malicious device. It can also arrive if the IER-off write in
f81604_set_reset_mode() failed, because f81604_close() ignores its return
value.
Nothing cancels restart_work after that. When it fires,
can_restart()->f81604_set_mode()->f81604_start() puts the chip back into
normal mode, resubmits the URBs and wakes the queue on an interface that is
down.
If the device is unplugged before restart_ms expires,
f81604_disconnect()->unregister_netdev() skips ndo_stop because the device
is already down. free_candev() then frees can_priv while the restart_work
timer is still armed.
Would it be better to call f81604_unregister_urbs() before close_candev(),
as gs_usb and peak_usb do?
[Severity: High]
This is a pre-existing issue, but can close_candev()->can_flush_echo_skb()
race here with URB completions that use priv->echo_skb[0]?
The int URB is only killed later, by f81604_unregister_urbs(). The TX URBs
from f81604_start_xmit() are never anchored, so they are never killed or
waited for:
f81604_start_xmit()
can_put_echo_skb(skb, netdev, 0, 0);
ret = usb_submit_urb(write_urb, GFP_ATOMIC);
can_flush_echo_skb() checks and frees echo_skb[i] without a lock.
f81604_handle_tx() does the same through can_get_echo_skb() and
can_free_echo_skb(). f81604_write_bulk_callback() does it through
can_free_echo_skb() on error statuses. Both run in completion context.
If both sides see a non-NULL echo_skb[0], could the skb be freed twice? Or
could __can_get_echo_skb() read it after the flush has freed it?
Killing all URBs, including TX, before close_candev() looks like it would
avoid this.
>
> f81604_unregister_urbs(priv);
> + cancel_work_sync(&priv->clear_reg_work);
[Severity: High]
This covers ndo_stop, but can clear_reg_work still be left pending after a
failed open? In f81604_start(), the URBs are already live when
f81604_set_normal_mode() runs:
ret = f81604_register_urbs(priv);
if (ret)
return ret;
ret = f81604_set_normal_mode(priv);
if (ret) {
f81604_unregister_urbs(priv);
return ret;
}
The int URB may complete with error bits in isrc during
f81604_set_normal_mode(). If so, f81604_handle_can_bus_errors() calls
schedule_work(&priv->clear_reg_work).
If f81604_set_normal_mode() then fails (for example -ENODEV during
hot-unplug), the error path kills the URBs but does not cancel the work.
f81604_open() then only calls close_candev().
Since the open failed, IFF_UP is never set, so on disconnect:
f81604_disconnect()
unregister_netdev()
netif_close_many() skips ndo_stop for devices without IFF_UP
free_candev()
frees the netdev and the embedded f81604_port_priv
Could f81604_clear_reg_work() then run on the freed priv?
Would adding cancel_work_sync() to the f81604_start() error path, or
calling it unconditionally in f81604_disconnect() before free_candev(),
cover this case?
[Severity: High]
This is a pre-existing issue, but does each bus-off restart submit another
set of URBs on top of the ones already running?
can_restart()->f81604_set_mode() calls f81604_start(). f81604_start() then
calls f81604_register_urbs() without calling f81604_unregister_urbs()
first. The completion callbacks resubmit on success, so nothing kills the
open-time URBs at bus-off.
Each restart would then leave another F81604_MAX_RX_URBS bulk URBs plus an
int URB in flight, with their buffers, until ndo_stop.
Also, if f81604_set_normal_mode() fails during a restart, the error path
calls f81604_unregister_urbs(), which kills every anchored URB, including
the open-time set. Would the interface then stay up with no RX or int URBs
until the next down/up?
>
> return 0;
> }
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 30/37] can: hi311x: drop hi3110_lock before free_irq() on open failure
2026-10-09 13:28 ` [PATCH net-next 30/37] can: hi311x: drop hi3110_lock before free_irq() on open failure Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 (1) · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] The rollback in hi3110_open() (drivers/net/can/spi/hi311x.c,
lines 789-794) sets priv->force_quit = 1 and drops hi3110_lock before…
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but the driver's
own restart_work is never cancelled or flushed during shutdown.
--
can: hi311x: drop hi3110_lock before free_irq() on open failure
This patch changes the hi3110_open() error path. It now sets force_quit
and drops hi3110_lock before calling free_irq(), then takes the mutex
again for the remaining hardware cleanup. This avoids a deadlock against
the threaded IRQ handler, which takes hi3110_lock before it checks
force_quit.
Link: https://patch.msgid.link/20260820020631.316418-1-runyu.xiao@seu.edu.cn
> diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
> index 076a3efa1bfff..927555b5d581e 100644
> --- a/drivers/net/can/spi/hi311x.c
> +++ b/drivers/net/can/spi/hi311x.c
> @@ -787,7 +787,10 @@ static int hi3110_open(struct net_device *net)
> return 0;
>
> out_free_irq:
> + priv->force_quit = 1;
> + mutex_unlock(&priv->hi3110_lock);
> free_irq(spi->irq, priv);
[Severity: Medium]
Can this rollback turn the old deadlock into an IRQ storm when
hi3110_set_normal_mode() fails?
The IRQ is requested with IRQF_ONESHOT | IRQF_TRIGGER_HIGH. Before
hi3110_set_normal_mode() returns -EBUSY, it has already armed the chip:
drivers/net/can/spi/hi311x.c:hi3110_set_normal_mode() {
hi3110_write(spi, HI3110_WRITE_INTE, HI3110_INT_BUSERR |
HI3110_INT_RXFIFO | HI3110_INT_TXCPLT);
hi3110_write(spi, HI3110_WRITE_CTRL1, HI3110_CTRL1_TXEN);
...
hi3110_write(spi, HI3110_WRITE_CTRL0, reg);
mdelay(HI3110_OST_DELAY_MS);
reg = hi3110_read(spi, HI3110_READ_CTRL0);
if ((reg & HI3110_CTRL0_MODE_MASK) != reg)
return -EBUSY;
...
}
A received frame or a bus error during the mdelay() window can assert
INT. Once force_quit is set, hi3110_can_ist() skips the whole
while (!priv->force_quit) loop. It never reads STATF, the FIFO or INTF,
but it still returns IRQ_HANDLED.
irq_finalize_oneshot() then unmasks the line, which is still asserted.
The interrupt fires again right away, so the SCHED_FIFO IRQ thread spins
until free_irq() finally shuts the line down.
If the IRQ thread was blocked on hi3110_lock, the new mutex_unlock()
wakes it. On the same CPU (always the case on UP), it can preempt the
opener, which holds RTNL, before the opener reaches free_irq().
The opener then only runs again through RT throttling or the fair
dl_server. That bounds the stall to about one RT period by default, but
the stall can be indefinite if those safeguards are disabled.
Would it be better to quiet the chip while still holding the mutex,
before force_quit is set and the lock is dropped? That could mirror
what hi3110_stop() does:
hi3110_write(spi, HI3110_WRITE_CTRL1, 0x0);
hi3110_write(spi, HI3110_WRITE_INTE, 0x0);
hi3110_read(spi, HI3110_READ_INTF);
Another option is calling disable_irq_nosync() before mutex_unlock().
hi3110_stop() already uses the same force_quit then free_irq() ordering
while INTE is still enabled, so the same hazard exists there. In the
open() rollback path, though, it is new with this patch.
> + mutex_lock(&priv->hi3110_lock);
> hi3110_hw_sleep(spi);
> out_close:
> hi3110_power_enable(priv->transceiver, 0);
[Severity: Medium]
This is a pre-existing issue that this patch did not introduce, but is
priv->restart_work ever cancelled or flushed on shutdown?
hi3110_do_set_mode() queues it for CAN_MODE_START:
drivers/net/can/spi/hi311x.c:hi3110_do_set_mode() {
...
priv->restart_tx = 1;
if (priv->can.restart_ms == 0)
priv->after_suspend = HI3110_AFTER_SUSPEND_RESTART;
queue_work(priv->wq, &priv->restart_work);
...
}
hi3110_stop() calls close_candev(), which only cancels the CAN core's
delayed restart_work. It never calls
cancel_work_sync(&priv->restart_work), and neither does the hi3110_open()
rollback.
If the work is still pending at ifdown or during a failed open(),
hi3110_restart_work_handler() can run after cleanup. It takes
hi3110_lock and calls hi3110_hw_reset(), hi3110_setup() and
hi3110_set_normal_mode(), which re-arms INTE, TXEN and normal mode. It
then clears force_quit and calls netif_wake_queue() on the downed
interface.
The controller would then be back on the bus while the interface is
administratively down.
The new unlocked window around free_irq() in hi3110_open() gives the
worker one more place to run. It does not seem to make things worse than
the existing post-stop case, because free_irq() still completes and the
rollback then calls hi3110_hw_sleep().
There is no use-after-free here, because hi3110_can_remove() runs
destroy_workqueue() before free_candev().
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak
2026-10-09 13:28 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
@ 2026-10-10 14:03 ` netdev-bot+sashiko
0 siblings, 0 replies; 57+ messages in thread
From: netdev-bot+sashiko @ 2026-10-10 14:03 UTC (permalink / raw)
To: mkl; +Cc: netdev, davem, kuba, linux-can, kernel, hemanth.selam
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 (1) · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The fix is incomplete: the of_clk_get() clock reference still
leaks when the device is removed.
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but
sun4ican_probe() replaces the real error codes from of_clk_get() and…
--
can: sun4i_can: sun4ican_probe(): fix clk leak
This commit adds an exit_put_clk label to sun4ican_probe(). The clock
reference taken with of_clk_get() is now released with clk_put() when
platform_get_irq(), devm_platform_ioremap_resource(), alloc_candev() or
register_candev() fails.
Link: https://patch.msgid.link/20260917104514.2147347-1-vulab@iscas.ac.cn
> diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
> index af52285d5a4e0..311526107ed81 100644
> --- a/drivers/net/can/sun4i_can.c
> +++ b/drivers/net/can/sun4i_can.c
> @@ -854,13 +854,13 @@ static int sun4ican_probe(struct platform_device *pdev)
> irq = platform_get_irq(pdev, 0);
> if (irq < 0) {
> err = -ENODEV;
> - goto exit;
> + goto exit_put_clk;
> }
[Severity: Medium]
This is a pre-existing issue and was not introduced by this patch, but
this block is being touched anyway. Does replacing the return value of
platform_get_irq() with -ENODEV break probe deferral?
platform_get_irq() can return -EPROBE_DEFER. For example, of_irq_get()
returns it when irq_find_host() cannot find the interrupt controller
domain yet.
The of_clk_get() error path a few lines above does the same thing:
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "unable to request clock\n");
err = -ENODEV;
goto exit;
}
of_clk_get() returns -EPROBE_DEFER when the clock provider has not
registered yet.
The driver core only retries a probe that returns -EPROBE_DEFER. If the
clock provider or interrupt controller registers after this driver
probes, would the CAN interface ever bind? Would it be better to return
PTR_ERR(clk) and irq instead?
[ ... ]
> @@ -908,6 +908,8 @@ static int sun4ican_probe(struct platform_device *pdev)
>
> exit_free:
> free_candev(dev);
> +exit_put_clk:
> + clk_put(clk);
> exit:
> return err;
> }
[Severity: High]
This covers the probe error paths. Does the clock reference from
of_clk_get() still leak when the device is removed?
On a successful probe the reference is stored in priv->clk:
priv->clk = clk;
sun4ican_remove() never drops it:
static void sun4ican_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_netdev(dev);
free_candev(dev);
}
free_candev() calls free_netdev(), which frees the private area that
holds priv->clk. After that, nothing is left to release the reference.
The clk_put() added here is the only one in the file.
So each successful probe followed by a module unload or sysfs unbind
would still leak the struct clk. It would also leave the clk_core
refcount and the clock provider's module reference held for good.
Would switching to devm_clk_get(&pdev->dev, NULL) be simpler? It would
handle both the probe error paths and the remove path, and the
exit_put_clk label would no longer be needed.
If the manual clk_put() is kept, sun4ican_remove() would need to read
priv->clk before calling free_candev(), because priv lives inside the
netdev allocation.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009134323.64064-2-mkl%40pengutronix.de
^ permalink raw reply [flat|nested] 57+ messages in thread
end of thread, other threads:[~2026-10-10 14:03 UTC | newest]
Thread overview: 57+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-09 13:27 [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 03/37] can: convert unreliable ARPHRD_CAN type checks to robust can_get_ml_priv() Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 06/37] can: j1939: cancel pending address claim timers from j1939_ecu_unmap_all() Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 07/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 08/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 09/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 11/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 13/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 15/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 16/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 17/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 18/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 19/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
2026-10-10 14:02 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 20/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 21/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 22/37] can: remove Softing CANcard driver Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 23/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 24/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 25/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
2026-10-09 13:27 ` [PATCH net-next 26/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:27 ` [PATCH net-next 27/37] can: esd: acc_start_xmit(): do not touch skb after can_put_echo_skb() Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 28/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 29/37] can: f81604: f81604_close(): fix use-after-free on disconnect Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 30/37] can: hi311x: drop hi3110_lock before free_irq() on open failure Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
2026-10-10 14:03 ` netdev-bot+sashiko
2026-10-09 13:28 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
2026-10-09 13:28 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
2026-10-09 13:57 ` [PATCH net-next 0/37] pull-request: can-next 2026-10-09 Marc Kleine-Budde
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox