* [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
0 siblings, 0 replies; 40+ 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] 40+ messages in thread
* [PATCH net-next 0/37] pull-request: can-next 2026-10-15
@ 2026-10-15 1:39 Marc Kleine-Budde
2026-10-15 1:39 ` [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
` (36 more replies)
0 siblings, 37 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:39 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.
Oliver Hartkopp series targets the CAN isotp, bcm and raw protocols
and fixes a use-after-free in the in isotp and bcm and converts the
raw protocol to the same locking scheme.
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.
Oliver Hartkopp' patch removes the Softing CANcard driver.
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.
Fan Wu's patch for the ems_usb driver properly shuts down the
interrupt URB.
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().
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-20261015
for you to fetch changes up to 8348b75aa230036a14d805eec574aeb0e1b95f86:
can: xilinx_can: set CAN FD flags on received frames (2026-10-15 03:36:49 +0200)
----------------------------------------------------------------
linux-can-next-for-7.4-20261015
----------------------------------------------------------------
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
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 (6):
Merge patch series "can: take rtnl_lock() before leaving the notifier list"
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(): avoid use-after-free of skb after can_put_echo_skb()
Maximilian Zimmermann (1):
can: xilinx_can: set CAN FD flags on received frames
Oliver Hartkopp (6):
can: replace ARPHRD_CAN type checks with can_get_ml_priv()
can: proc: remove pointers from CAN specific proc output
can: isotp: fix filter removal race between release and netns change
can: bcm: fix filter removal race between release and netns change
can: raw: take rtnl_lock() before leaving the notifier list
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 (1):
can: proc: reset pkg_stats atomics individually
Sang-Heon Jeon (1):
can: raw: remove redundant NULL check before netdev_hold()
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 | 12 +-
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 | 8 +-
drivers/net/can/spi/mcp251x.c | 8 +-
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 7 +-
drivers/net/can/sun4i_can.c | 11 +-
drivers/net/can/usb/ems_usb.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 | 166 +++-
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 | 56 +-
net/can/gw.c | 9 +-
net/can/isotp.c | 34 +-
net/can/j1939/main.c | 2 +-
net/can/proc.c | 49 +-
net/can/raw.c | 24 +-
47 files changed, 535 insertions(+), 2395 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] 40+ 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-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
@ 2026-10-15 1:39 ` Marc Kleine-Budde
2026-10-15 1:57 ` netdev-bot+sinfo
2026-10-15 1:40 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
` (35 subsequent siblings)
36 siblings, 1 reply; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:39 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] 40+ messages in thread
* [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold()
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
2026-10-15 1:39 ` [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-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 03/37] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
` (34 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 03/37] can: replace ARPHRD_CAN type checks with can_get_ml_priv()
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
2026-10-15 1:39 ` [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-15 1:40 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
` (33 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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. A valid pointer
returned by can_get_ml_priv() therefore identifies a real CAN device.
The referenced commit only converted the j1939 and proc code to this
check, while the other parts of the CAN subsystem still rely on
dev->type == ARPHRD_CAN.
The TUNSETLINK ioctl allows a down TUN/TAP device to set its hardware
type to ARPHRD_CAN while dev->ml_priv remains NULL. Such a repurposed
netdevice passes the ARPHRD_CAN checks and triggers a NULL pointer
dereference when CAN filters are created and when they are removed,
e.g. by the CAN protocols' netdevice notifier handlers. This only
requires owning a TUN/TAP device or CAP_NET_ADMIN in an unprivileged
user namespace.
Convert the remaining ARPHRD_CAN checks in af_can, bcm, gw, isotp and
raw 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/20261012164802.94113-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] 40+ messages in thread
* [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (2 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 03/37] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
` (32 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (3 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 06/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
` (31 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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 exposing kernel addresses was
acceptable when this code was written the times have changed and multiple
attempts have been made to hash or remove such now sensitive data.
This patch removes the disclosure of pointers and instead provides the
function names and sock inode numbers when available. In the case of
KALLSYMS=n (EXPERT setting) the function names can not be resolved and
(unknown) is printed instead. 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>
Link: https://patch.msgid.link/20261012115851.3412-1-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
Documentation/networking/can.rst | 12 ++++++------
include/linux/can/core.h | 2 +-
net/can/af_can.c | 6 +++---
net/can/af_can.h | 2 +-
net/can/bcm.c | 14 +++++++-------
net/can/gw.c | 2 +-
net/can/isotp.c | 4 ++--
net/can/j1939/main.c | 2 +-
net/can/proc.c | 22 ++++++++++++----------
net/can/raw.c | 4 ++--
10 files changed, 36 insertions(+), 34 deletions(-)
diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
index 536ff411da1d..908c199cf6ad 100644
--- a/Documentation/networking/can.rst
+++ b/Documentation/networking/can.rst
@@ -1040,17 +1040,17 @@ As described in :ref:`socketcan-receive-lists` the SocketCAN core uses several f
lists to deliver received CAN frames to CAN protocol modules. These
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::
+CAN network device and the subscribed function name::
foo@bar:~$ cat /proc/net/can/rcvlist_all
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
(any: no entry)
+ device can_id can_mask matches sock_inode function
+ vcan0 000 00000000 0 63586 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..6759662e024c 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -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),
+ "%llu", 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..64994ab48541 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -215,25 +215,27 @@ 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 %10llu" :
+ " %6s %03x %08x %8ld %10llu";
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);
+
+ /* without kallsyms %ps would print the raw text address */
+ if (IS_ENABLED(CONFIG_KALLSYMS))
+ seq_printf(m, " %ps\n", r->func);
+ else
+ seq_puts(m, " (unknown)\n");
}
}
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 000 00000000 0 43798 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] 40+ messages in thread
* [PATCH net-next 06/37] can: isotp: check the frame type, not just the length
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (4 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 07/37] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
` (30 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 07/37] can: isotp: fix filter removal race between release and netns change
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (5 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 06/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 08/37] can: bcm: " Marc Kleine-Budde
` (29 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, Norbert Szetei,
stable, Marc Kleine-Budde
From: Oliver Hartkopp <socketcan@hartkopp.net>
isotp_release() removes the socket from isotp_notifier_list before it
takes rtnl_lock(). As the netdev notifier chain runs under RTNL, a
socket that leaves the list in this window is skipped by isotp_notify()
and has to remove its CAN filters itself.
This fails when the bound device is moved to another network namespace
in this window: isotp_release() passes sock_net(sk) to
can_rx_unregister(), which silently returns when this namespace does not
match dev_net(dev) anymore. As can_rx_register() stores rcv->sk without
taking a reference, the remaining receivers point to the freed socket
and travel with the device into the new namespace:
BUG: KASAN: use-after-free in isotp_rcv+0x1570/0x24d0
Read of size 1 at addr ffff888118130552 by task isotp_ns_uaf/578
can_rcv_filter+0x4af/0x8c0
can_receive+0x28d/0x3c0
can_rcv+0x2a9/0x310
__netif_receive_skb_one_core+0x21a/0x260
process_backlog+0x210/0x760
Take rtnl_lock() before removing the socket from the notifier list, so
that isotp_release() and isotp_notify() can not both skip the removal.
As the notifier chain is always invoked under RTNL (see ASSERT_RTNL() in
call_netdevice_notifiers_info()), isotp_busy_notifier can not point to
the released socket anymore. Replace the now dead busy-wait loop with a
WARN_ON_ONCE(). isotp_notifier_lock is still needed, as isotp_init()
adds new sockets to isotp_notifier_list without holding RTNL.
Additionally use dev_net(so->dev) for the can_rx_unregister() calls, as
the CAN filters live in the device's namespace. With the new locking
both namespaces are equal there, but dev_net(so->dev) is stable under
RTNL and always names the correct namespace.
Fixes: 20bab8b88baa ("can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER")
Reported-by: Norbert Szetei <norbert@doyensec.com>
Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261014142114.280279-2-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/isotp.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/net/can/isotp.c b/net/can/isotp.c
index 5e1c3971ebfc..17ff40a4708d 100644
--- a/net/can/isotp.c
+++ b/net/can/isotp.c
@@ -1488,16 +1488,17 @@ static int isotp_release(struct socket *sock)
/* forced SHUTDOWN may have skipped IDLE (gave up on a signal) */
wake_up_interruptible(&so->wait);
+ rtnl_lock();
+
+ /* The netdev notifier chain runs under RTNL, so isotp_notifier() can't
+ * be walking isotp_notifier_list and point to this socket. The spinlock
+ * is still needed as isotp_init() adds sockets without holding RTNL.
+ */
spin_lock(&isotp_notifier_lock);
- while (isotp_busy_notifier == so) {
- spin_unlock(&isotp_notifier_lock);
- schedule_timeout_uninterruptible(1);
- spin_lock(&isotp_notifier_lock);
- }
+ WARN_ON_ONCE(isotp_busy_notifier == so);
list_del(&so->notifier);
spin_unlock(&isotp_notifier_lock);
- rtnl_lock();
lock_sock(sk);
/* remove current filters & unregister
@@ -1505,11 +1506,11 @@ static int isotp_release(struct socket *sock)
*/
if (so->bound && so->dev) {
if (isotp_register_rxid(so))
- can_rx_unregister(net, so->dev, so->rxid,
+ can_rx_unregister(dev_net(so->dev), so->dev, so->rxid,
SINGLE_MASK(so->rxid),
isotp_rcv, sk);
- can_rx_unregister(net, so->dev, so->txid,
+ can_rx_unregister(dev_net(so->dev), so->dev, so->txid,
SINGLE_MASK(so->txid),
isotp_rcv_echo, sk);
netdev_put(so->dev, &so->dev_tracker);
--
2.53.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH net-next 08/37] can: bcm: fix filter removal race between release and netns change
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (6 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 07/37] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 09/37] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
` (28 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 UTC (permalink / raw)
To: netdev
Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp, Norbert Szetei,
stable, Marc Kleine-Budde
From: Oliver Hartkopp <socketcan@hartkopp.net>
bcm_release() removes the socket from bcm_notifier_list before it takes
any lock that serializes against the netdev notifier chain, which runs
under RTNL. A socket that leaves the list in this window is skipped by
bcm_notify() and has to remove its CAN filters itself.
This fails when the bound device is moved to another network namespace
in this window: bcm_rx_unreg() reads dev_net(dev) without holding RTNL,
and can_rx_unregister() silently returns when this namespace does not
match dev_net(dev) anymore. The op is freed anyway and the remaining
receiver leads to a use-after-free in bcm_rx_handler().
Take rtnl_lock() before removing the socket from the notifier list, so
that bcm_release() and bcm_notify() can not both skip the removal and
dev_net(dev) is stable while the filters are removed. RTNL is dropped
before synchronize_rcu(). As the notifier chain is always invoked under
RTNL, bcm_busy_notifier can not point to the released socket anymore.
Replace the now dead busy-wait loop with a WARN_ON_ONCE().
RTNL is only needed for the notifier list removal and the rx_ops
unregistration. Remove the procfs entry and the tx_ops before taking
RTNL, as remove_proc_entry() waits for concurrent readers of the
world-readable procfs entry, which could otherwise stall RTNL from a
plain close(). bo->bcm_proc_read is cleared so that a NETDEV_UNREGISTER
in bcm_notify() does not remove the entry a second time.
Fixes: 8e8cda6d737d ("can: initial support for network namespaces")
Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Cc: Norbert Szetei <norbert@doyensec.com>
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261014142114.280279-3-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/bcm.c | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 6759662e024c..301920011a30 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1926,21 +1926,19 @@ static int bcm_release(struct socket *sock)
/* remove bcm_ops, timer, rx_unregister(), etc. */
- spin_lock(&bcm_notifier_lock);
- while (bcm_busy_notifier == bo) {
- spin_unlock(&bcm_notifier_lock);
- schedule_timeout_uninterruptible(1);
- spin_lock(&bcm_notifier_lock);
- }
- list_del(&bo->notifier);
- spin_unlock(&bcm_notifier_lock);
-
+ /* Remove the procfs entry and the tx_ops before taking RTNL:
+ * remove_proc_entry() waits for concurrent readers of the entry and
+ * must not hold up RTNL for them. Clear bo->bcm_proc_read so that
+ * bcm_notify() does not remove the entry a second time.
+ */
lock_sock(sk);
#if IS_ENABLED(CONFIG_PROC_FS)
/* remove procfs entry */
- if (net->can.bcmproc_dir && bo->bcm_proc_read)
+ if (net->can.bcmproc_dir && bo->bcm_proc_read) {
remove_proc_entry(bo->procname, net->can.bcmproc_dir);
+ bo->bcm_proc_read = NULL;
+ }
#endif /* CONFIG_PROC_FS */
list_for_each_entry_safe(op, next, &bo->tx_ops, list) {
@@ -1948,6 +1946,21 @@ static int bcm_release(struct socket *sock)
bcm_remove_op(op);
}
+ release_sock(sk);
+
+ rtnl_lock();
+
+ /* The netdev notifier chain runs under RTNL, so bcm_notifier() can't
+ * be walking bcm_notifier_list and point to this socket. The spinlock
+ * is still needed as bcm_init() adds sockets without holding RTNL.
+ */
+ spin_lock(&bcm_notifier_lock);
+ WARN_ON_ONCE(bcm_busy_notifier == bo);
+ list_del(&bo->notifier);
+ spin_unlock(&bcm_notifier_lock);
+
+ lock_sock(sk);
+
list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
/*
* Don't care if we're bound or not (due to netdev problems)
@@ -1973,6 +1986,8 @@ static int bcm_release(struct socket *sock)
}
+ rtnl_unlock();
+
synchronize_rcu();
list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
--
2.53.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH net-next 09/37] can: raw: take rtnl_lock() before leaving the notifier list
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (7 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 08/37] can: bcm: " Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
` (27 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Oliver Hartkopp,
Marc Kleine-Budde
From: Oliver Hartkopp <socketcan@hartkopp.net>
raw_release() removes the socket from raw_notifier_list before it takes
rtnl_lock(). As the netdev notifier chain runs under RTNL, a socket that
leaves the list in this window is skipped by raw_notify() and has to
remove its CAN filters itself.
For raw this is not harmful: raw_release() removes the filters with
dev_net(ro->dev) under RTNL, so they are found even when the bound
device has been moved to another network namespace in this window. The
receivers only remain on the moved device until raw_release() gets
RTNL.
Take rtnl_lock() before removing the socket from the notifier list, so
that raw, isotp and bcm use the same locking scheme in their release
functions. As the notifier chain is always invoked under RTNL,
raw_busy_notifier can not point to the released socket anymore. Replace
the now dead busy-wait loop with a WARN_ON_ONCE().
Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261014142114.280279-4-socketcan@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/raw.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/net/can/raw.c b/net/can/raw.c
index dfea48768b23..d95ce54a4c45 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -422,16 +422,17 @@ static int raw_release(struct socket *sock)
ro = raw_sk(sk);
net = sock_net(sk);
+ rtnl_lock();
+
+ /* The netdev notifier chain runs under RTNL, so raw_notifier() can't
+ * be walking raw_notifier_list and point to this socket. The spinlock
+ * is still needed as raw_init() adds sockets without holding RTNL.
+ */
spin_lock(&raw_notifier_lock);
- while (raw_busy_notifier == ro) {
- spin_unlock(&raw_notifier_lock);
- schedule_timeout_uninterruptible(1);
- spin_lock(&raw_notifier_lock);
- }
+ WARN_ON_ONCE(raw_busy_notifier == ro);
list_del(&ro->notifier);
spin_unlock(&raw_notifier_lock);
- rtnl_lock();
lock_sock(sk);
/* remove current filters & unregister */
--
2.53.0
^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (8 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 09/37] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 11/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
` (26 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Cunhao Lu, stable,
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
Cc: stable@kernel.org
Fixes: ae64438be192 ("can: dev: fix skb drop check")
Fixes: 0ae89beb283a ("can: add destructor for self generated skbs")
Fixes: 3ccd4c6167d3 ("can: Unify droping of invalid tx skbs and netdev stats")
Fixes: 39549eef3587 ("can: CAN Network device driver and Netlink interface")
[mkl: also convert can_dropped_invalid_skb(), can_dev_dropped_skb()]
[mkl: add stable on Cc + add Fixes tags]
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] 40+ messages in thread
* [PATCH net-next 11/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (9 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
` (25 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (10 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 11/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 13/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
` (24 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 13/37] can: rcar_canfd: Fix typos in macro names
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (11 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
` (23 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (12 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 13/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 15/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
` (22 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 15/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (13 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 16/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
` (21 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 16/37] can: rcar_canfd: Do not set registers selecting the CAN mode
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (14 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 15/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 17/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
` (20 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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 fixed_canfd 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
[mkl: update flag name in patch description]
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] 40+ messages in thread
* [PATCH net-next 17/37] can: rcar_canfd: Add support for Renesas RZ/G3S
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (15 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 16/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 18/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
` (19 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 18/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (16 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 17/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 19/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
` (18 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 19/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (17 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 18/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 20/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
` (17 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 20/37] can: rcar_canfd: Derive max_channels from the device tree
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (18 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 19/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 21/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
` (16 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 21/37] dt-bindings: net: can: convert grcan to DT schema
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (19 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 20/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 22/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
` (15 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 22/37] can: rcar_canfd: Add support for Renesas RZ/G3L
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (20 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 21/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 23/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
` (14 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 23/37] can: grcan: update the binding file reference in the driver comment
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (21 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 22/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 24/37] can: remove Softing CANcard driver Marc Kleine-Budde
` (13 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 24/37] can: remove Softing CANcard driver
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (22 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 23/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 25/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
` (12 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 25/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (23 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 24/37] can: remove Softing CANcard driver Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 26/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
` (11 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 26/37] can: cc770: don't discard the IRQ lookup error in probe
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (24 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 25/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 27/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
` (10 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Chaosheng Qu, Marc Kleine-Budde
From: Chaosheng Qu <quchaosheng000406@163.com>
This is a robustness and consistency cleanup, this issue has not been seen
on real hardware.
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
[mkl: clarify commit message]
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] 40+ messages in thread
* [PATCH net-next 27/37] can: cc770: fix the clock divider check on the platform bus
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (25 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 26/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 28/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
` (9 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 28/37] can: ems_usb: use usb_kill_urb() to stop the intr URB
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (26 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 27/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 29/37] can: esd: acc_start_xmit(): avoid use-after-free of skb after can_put_echo_skb() Marc Kleine-Budde
` (8 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 29/37] can: esd: acc_start_xmit(): avoid use-after-free of skb after can_put_echo_skb()
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (27 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 28/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 30/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
` (7 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 UTC (permalink / raw)
To: netdev; +Cc: davem, kuba, linux-can, kernel, Marc Kleine-Budde, stable
After the call to can_put_echo_skb() in acc_start_xmit() the skb is 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
Fixes: 9721866f07e1 ("can: esd: add support for esd GmbH PCIe/402 CAN interface family")
Cc: stable@vger.kernel.org
[mkl: update subject + commit message]
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] 40+ messages in thread
* [PATCH net-next 30/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (28 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 29/37] can: esd: acc_start_xmit(): avoid use-after-free of skb after can_put_echo_skb() Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
` (6 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (29 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 30/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
` (5 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (30 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
` (4 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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
Closes: https://lore.kernel.org/all/20260819145658.29872-1-blbllhy@gmail.com
Reported-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Closes: https://lore.kernel.org/all/20260819145658.29872-1-blbllhy@gmail.com
Suggested-by: Jakub Kicinski <kuba@kernel.org>
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]
[mkl: move Closes trailer to fix checkpatch warning]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
.../net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 136 +++++++++++++++++-
1 file changed, 129 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..2220d197abb5 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,61 @@ 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 +2234,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 +2262,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] 40+ messages in thread
* [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (31 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
` (3 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (32 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
` (2 subsequent siblings)
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (33 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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
[mkl: fix clk leak in sun4ican_remove()]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/sun4i_can.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
index af52285d5a4e..76db6d09d1e6 100644
--- a/drivers/net/can/sun4i_can.c
+++ b/drivers/net/can/sun4i_can.c
@@ -812,9 +812,12 @@ MODULE_DEVICE_TABLE(of, sun4ican_of_match);
static void sun4ican_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
+ struct sun4ican_priv *priv = netdev_priv(dev);
+ struct clk *clk = priv->clk;
unregister_netdev(dev);
free_candev(dev);
+ clk_put(clk);
}
static int sun4ican_probe(struct platform_device *pdev)
@@ -854,13 +857,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 +871,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 +911,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] 40+ messages in thread
* [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (34 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
` (35 preceding siblings ...)
2026-10-15 1:40 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
@ 2026-10-15 1:40 ` Marc Kleine-Budde
36 siblings, 0 replies; 40+ messages in thread
From: Marc Kleine-Budde @ 2026-10-15 1:40 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] 40+ messages in thread
* Re: [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices
2026-10-15 1:39 ` [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-15 1:57 ` netdev-bot+sinfo
0 siblings, 0 replies; 40+ messages in thread
From: netdev-bot+sinfo @ 2026-10-15 1:57 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: netdev, davem, kuba, linux-can, kernel, Vincent Mailhol, stable
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2026-10-15 1:57 UTC | newest]
Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
2026-10-15 1:39 ` [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-15 1:57 ` netdev-bot+sinfo
2026-10-15 1:40 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 03/37] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 06/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 07/37] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 08/37] can: bcm: " Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 09/37] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 11/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 13/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 15/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 16/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 17/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 18/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 19/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 20/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 21/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 22/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 23/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 24/37] can: remove Softing CANcard driver Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 25/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 26/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 27/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 28/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 29/37] can: esd: acc_start_xmit(): avoid use-after-free of skb after can_put_echo_skb() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 30/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
-- strict thread matches above, loose matches on Subject: below --
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox