* [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 7:29 ` sashiko-bot
2026-06-03 10:06 ` Enric Balletbo i Serra
2026-06-03 7:13 ` [PATCH RESEND v4 2/8] can: flexcan: disable all IRQ lines in flexcan_chip_interrupts_enable() Ciprian Costea
` (7 subsequent siblings)
8 siblings, 2 replies; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
On platforms with multiple IRQ lines (S32G2, MCF5441X), all lines are
registered to the same flexcan_irq() handler. Since these are distinct IRQ
numbers, they can be dispatched concurrently on different CPUs. Both
instances then read the same iflag and ESR registers unconditionally,
leading to duplicate frame processing.
Fix this by splitting the monolithic handler into focused parts:
- flexcan_do_mb(): processes mailbox events
- flexcan_do_state(): processes device state change events
- flexcan_do_berr(): processes bus error events
Introduce dedicated IRQ handlers for multi-IRQ platforms:
- flexcan_irq_mb(): mailbox-only, used for mb-0, mb-1 IRQ lines
- flexcan_irq_boff(): state-change-only, used for boff/state IRQ line
- flexcan_irq_berr(): bus-error-only, used for berr IRQ line
The combined flexcan_irq() handler is preserved for single-IRQ
platforms with no functional change.
Fixes: d9cead75b1c6 ("can: flexcan: add mcf5441x support")
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
drivers/net/can/flexcan/flexcan-core.c | 128 +++++++++++++++++++++----
1 file changed, 111 insertions(+), 17 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index f5d22c61503f..f73ff442d530 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1070,16 +1070,14 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
return skb;
}
-static irqreturn_t flexcan_irq(int irq, void *dev_id)
+/* Process mailbox (RX + TX) events */
+static irqreturn_t flexcan_do_mb(struct net_device *dev)
{
- struct net_device *dev = dev_id;
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
irqreturn_t handled = IRQ_NONE;
u64 reg_iflag_tx;
- u32 reg_esr;
- enum can_state last_state = priv->can.state;
/* reception interrupt */
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) {
@@ -1131,25 +1129,57 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
netif_wake_queue(dev);
}
+ return handled;
+}
+
+/* Process bus error events */
+static irqreturn_t flexcan_do_berr(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->regs;
+ irqreturn_t handled = IRQ_NONE;
+ u32 reg_esr;
+
reg_esr = priv->read(®s->esr);
- /* ACK all bus error, state change and wake IRQ sources */
- if (reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT)) {
+ /* ACK bus error interrupt source */
+ if (reg_esr & FLEXCAN_ESR_ERR_INT) {
handled = IRQ_HANDLED;
- priv->write(reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT), ®s->esr);
+ priv->write(FLEXCAN_ESR_ERR_INT, ®s->esr);
}
- /* state change interrupt or broken error state quirk fix is enabled */
- if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
- (priv->devtype_data.quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE |
- FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
- flexcan_irq_state(dev, reg_esr);
-
/* bus error IRQ - handle if bus error reporting is activated */
if ((reg_esr & FLEXCAN_ESR_ERR_BUS) &&
(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
flexcan_irq_bus_err(dev, reg_esr);
+ return handled;
+}
+
+/* Process device state change events */
+static irqreturn_t flexcan_do_state(struct net_device *dev)
+{
+ struct flexcan_priv *priv = netdev_priv(dev);
+ struct flexcan_regs __iomem *regs = priv->regs;
+ irqreturn_t handled = IRQ_NONE;
+ u32 reg_esr;
+ enum can_state last_state = priv->can.state;
+
+ reg_esr = priv->read(®s->esr);
+
+ /* ACK state change and wake IRQ sources */
+ if (reg_esr & (FLEXCAN_ESR_ERR_STATE | FLEXCAN_ESR_WAK_INT)) {
+ handled = IRQ_HANDLED;
+ priv->write(reg_esr & (FLEXCAN_ESR_ERR_STATE | FLEXCAN_ESR_WAK_INT),
+ ®s->esr);
+ }
+
+ /* state change interrupt or broken error state quirk fix is enabled */
+ if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+ (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_BROKEN_WERR_STATE | FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
+ flexcan_irq_state(dev, reg_esr);
+
/* availability of error interrupt among state transitions in case
* bus error reporting is de-activated and
* FLEXCAN_QUIRK_BROKEN_PERR_STATE is enabled:
@@ -1188,6 +1218,65 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
}
}
+ return handled;
+}
+
+/* Combined IRQ handler for single-IRQ platforms */
+static irqreturn_t flexcan_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_mb(dev);
+ handled |= flexcan_do_state(dev);
+ handled |= flexcan_do_berr(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
+/* Mailbox IRQ handler for multi-IRQ platforms */
+static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_mb(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
+/* Bus error IRQ handler for multi-IRQ platforms */
+static irqreturn_t flexcan_irq_berr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_berr(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
+/* Device state change IRQ handler for multi-IRQ platforms */
+static irqreturn_t flexcan_irq_boff(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_state(dev);
+
if (handled)
can_rx_offload_irq_finish(&priv->offload);
@@ -1761,25 +1850,30 @@ static int flexcan_open(struct net_device *dev)
can_rx_offload_enable(&priv->offload);
- err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ err = request_irq(dev->irq, flexcan_irq_mb,
+ IRQF_SHARED, dev->name, dev);
+ else
+ err = request_irq(dev->irq, flexcan_irq,
+ IRQF_SHARED, dev->name, dev);
if (err)
goto out_can_rx_offload_disable;
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
err = request_irq(priv->irq_boff,
- flexcan_irq, IRQF_SHARED, dev->name, dev);
+ flexcan_irq_boff, IRQF_SHARED, dev->name, dev);
if (err)
goto out_free_irq;
err = request_irq(priv->irq_err,
- flexcan_irq, IRQF_SHARED, dev->name, dev);
+ flexcan_irq_berr, IRQF_SHARED, dev->name, dev);
if (err)
goto out_free_irq_boff;
}
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
err = request_irq(priv->irq_secondary_mb,
- flexcan_irq, IRQF_SHARED, dev->name, dev);
+ flexcan_irq_mb, IRQF_SHARED, dev->name, dev);
if (err)
goto out_free_irq_err;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
2026-06-03 7:13 ` [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms Ciprian Costea
@ 2026-06-03 7:29 ` sashiko-bot
2026-06-03 10:06 ` Enric Balletbo i Serra
1 sibling, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-06-03 7:29 UTC (permalink / raw)
To: Ciprian Costea; +Cc: conor+dt, robh, imx, Frank.Li, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The split IRQ handlers break the `FLEXCAN_QUIRK_BROKEN_PERR_STATE` workaround on multi-IRQ platforms, causing silent error state transitions to go undetected.
Pre-existing issues:
- [Critical] Concurrent execution of split IRQ handlers on multi-IRQ platforms causes unsynchronized lockless list corruption in `skb_irq_queue`.
--
commit 1073dfa63bf3a027c9286d2f8ca8d2cf503134a2
Author: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
On platforms with multiple IRQ lines (S32G2, MCF5441X), all lines are
registered to the same flexcan_irq() handler. Since these are distinct IRQ
numbers, they can be dispatched concurrently on different CPUs. Both
instances then read the same iflag and ESR registers unconditionally,
leading to duplicate frame processing.
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> index f5d22c61503fa..f73ff442d5304 100644
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
[ ... ]
> +/* Mailbox IRQ handler for multi-IRQ platforms */
> +static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + irqreturn_t handled;
> +
> + handled = flexcan_do_mb(dev);
[Severity: High]
Does this change break the FLEXCAN_QUIRK_BROKEN_PERR_STATE workaround on
multi-IRQ platforms?
Before this patch, the single monolithic flexcan_irq() mitigated the hardware
erratum by unconditionally polling the error state via flexcan_do_state() on
every interrupt. By leveraging frequent mailbox TX/RX events, it could detect
silent state transitions.
With dedicated handlers, flexcan_irq_mb() now exclusively processes mailbox
events and skips calling flexcan_do_state(). Since the hardware bug prevents
the boff interrupt from firing during state transitions, will the device now
silently enter Error Passive or Bus Off without the software noticing?
> +
> + if (handled)
> + can_rx_offload_irq_finish(&priv->offload);
> +
> + return handled;
> +}
> +
> +/* Bus error IRQ handler for multi-IRQ platforms */
> +static irqreturn_t flexcan_irq_berr(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + irqreturn_t handled;
> +
> + handled = flexcan_do_berr(dev);
[Severity: Critical]
This is a pre-existing issue, but does concurrent execution of these split IRQ
handlers on multi-IRQ platforms cause unsynchronized lockless list corruption?
On platforms with multiple IRQ lines, the distinct hardware interrupts (such
as MB and BERR) can be dispatched concurrently on different CPUs. The handlers
flexcan_irq_mb() and flexcan_irq_berr() concurrently invoke can_rx_offload
functions. For example, flexcan_irq_berr() eventually calls
can_rx_offload_queue_timestamp() via flexcan_irq_bus_err().
These offload functions call __skb_queue_add_sort(&offload->skb_irq_queue, ...),
which performs unsynchronized doubly-linked list pointer manipulation. Since
there are no locks protecting skb_irq_queue, concurrent enqueues from
different CPUs can corrupt the list pointers, resulting in use-after-free
or kernel panics.
While this patch explicitly tries to fix duplicate processing caused by
concurrency, the concurrent pushes to the lockless skb_irq_queue seem to
remain unhandled.
> +
> + if (handled)
> + can_rx_offload_irq_finish(&priv->offload);
> +
> + return handled;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603071342.641874-1-ciprianmarian.costea@oss.nxp.com?part=1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
2026-06-03 7:13 ` [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms Ciprian Costea
2026-06-03 7:29 ` sashiko-bot
@ 2026-06-03 10:06 ` Enric Balletbo i Serra
1 sibling, 0 replies; 19+ messages in thread
From: Enric Balletbo i Serra @ 2026-06-03 10:06 UTC (permalink / raw)
To: Ciprian Costea
Cc: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam, Pengutronix Kernel Team, linux-can, devicetree,
linux-kernel, imx, linux-arm-kernel, NXP S32 Linux Team,
Christophe Lizzi, Alberto Ruiz, Eric Chanudet
Hi Ciprian,
Thank you for the patch series.
On Wed, Jun 3, 2026 at 9:14 AM Ciprian Costea
<ciprianmarian.costea@oss.nxp.com> wrote:
>
> From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
>
> On platforms with multiple IRQ lines (S32G2, MCF5441X), all lines are
> registered to the same flexcan_irq() handler. Since these are distinct IRQ
> numbers, they can be dispatched concurrently on different CPUs. Both
> instances then read the same iflag and ESR registers unconditionally,
> leading to duplicate frame processing.
>
> Fix this by splitting the monolithic handler into focused parts:
> - flexcan_do_mb(): processes mailbox events
> - flexcan_do_state(): processes device state change events
> - flexcan_do_berr(): processes bus error events
>
> Introduce dedicated IRQ handlers for multi-IRQ platforms:
> - flexcan_irq_mb(): mailbox-only, used for mb-0, mb-1 IRQ lines
> - flexcan_irq_boff(): state-change-only, used for boff/state IRQ line
> - flexcan_irq_berr(): bus-error-only, used for berr IRQ line
>
> The combined flexcan_irq() handler is preserved for single-IRQ
> platforms with no functional change.
>
> Fixes: d9cead75b1c6 ("can: flexcan: add mcf5441x support")
> Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Adding here because it doesn't seem to have a cover letter. With the
full series applied on top of the current mainline
Tested-by: Enric Balletbo i Serra <eballetb@.redhat.com>
Tested on the NXP S32G399A-RDB3 with loopback and high-rate traffic.
No regressions observed: CAN frames transmit and receive correctly,
with no duplicates.
Frame reception showed no errors under stress testing.
Thanks,
Enric
> ---
> drivers/net/can/flexcan/flexcan-core.c | 128 +++++++++++++++++++++----
> 1 file changed, 111 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> index f5d22c61503f..f73ff442d530 100644
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
> @@ -1070,16 +1070,14 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
> return skb;
> }
>
> -static irqreturn_t flexcan_irq(int irq, void *dev_id)
> +/* Process mailbox (RX + TX) events */
> +static irqreturn_t flexcan_do_mb(struct net_device *dev)
> {
> - struct net_device *dev = dev_id;
> struct net_device_stats *stats = &dev->stats;
> struct flexcan_priv *priv = netdev_priv(dev);
> struct flexcan_regs __iomem *regs = priv->regs;
> irqreturn_t handled = IRQ_NONE;
> u64 reg_iflag_tx;
> - u32 reg_esr;
> - enum can_state last_state = priv->can.state;
>
> /* reception interrupt */
> if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) {
> @@ -1131,25 +1129,57 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
> netif_wake_queue(dev);
> }
>
> + return handled;
> +}
> +
> +/* Process bus error events */
> +static irqreturn_t flexcan_do_berr(struct net_device *dev)
> +{
> + struct flexcan_priv *priv = netdev_priv(dev);
> + struct flexcan_regs __iomem *regs = priv->regs;
> + irqreturn_t handled = IRQ_NONE;
> + u32 reg_esr;
> +
> reg_esr = priv->read(®s->esr);
>
> - /* ACK all bus error, state change and wake IRQ sources */
> - if (reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT)) {
> + /* ACK bus error interrupt source */
> + if (reg_esr & FLEXCAN_ESR_ERR_INT) {
> handled = IRQ_HANDLED;
> - priv->write(reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT), ®s->esr);
> + priv->write(FLEXCAN_ESR_ERR_INT, ®s->esr);
> }
>
> - /* state change interrupt or broken error state quirk fix is enabled */
> - if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
> - (priv->devtype_data.quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE |
> - FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
> - flexcan_irq_state(dev, reg_esr);
> -
> /* bus error IRQ - handle if bus error reporting is activated */
> if ((reg_esr & FLEXCAN_ESR_ERR_BUS) &&
> (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
> flexcan_irq_bus_err(dev, reg_esr);
>
> + return handled;
> +}
> +
> +/* Process device state change events */
> +static irqreturn_t flexcan_do_state(struct net_device *dev)
> +{
> + struct flexcan_priv *priv = netdev_priv(dev);
> + struct flexcan_regs __iomem *regs = priv->regs;
> + irqreturn_t handled = IRQ_NONE;
> + u32 reg_esr;
> + enum can_state last_state = priv->can.state;
> +
> + reg_esr = priv->read(®s->esr);
> +
> + /* ACK state change and wake IRQ sources */
> + if (reg_esr & (FLEXCAN_ESR_ERR_STATE | FLEXCAN_ESR_WAK_INT)) {
> + handled = IRQ_HANDLED;
> + priv->write(reg_esr & (FLEXCAN_ESR_ERR_STATE | FLEXCAN_ESR_WAK_INT),
> + ®s->esr);
> + }
> +
> + /* state change interrupt or broken error state quirk fix is enabled */
> + if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
> + (priv->devtype_data.quirks &
> + (FLEXCAN_QUIRK_BROKEN_WERR_STATE | FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
> + flexcan_irq_state(dev, reg_esr);
> +
> /* availability of error interrupt among state transitions in case
> * bus error reporting is de-activated and
> * FLEXCAN_QUIRK_BROKEN_PERR_STATE is enabled:
> @@ -1188,6 +1218,65 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
> }
> }
>
> + return handled;
> +}
> +
> +/* Combined IRQ handler for single-IRQ platforms */
> +static irqreturn_t flexcan_irq(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + irqreturn_t handled;
> +
> + handled = flexcan_do_mb(dev);
> + handled |= flexcan_do_state(dev);
> + handled |= flexcan_do_berr(dev);
> +
> + if (handled)
> + can_rx_offload_irq_finish(&priv->offload);
> +
> + return handled;
> +}
> +
> +/* Mailbox IRQ handler for multi-IRQ platforms */
> +static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + irqreturn_t handled;
> +
> + handled = flexcan_do_mb(dev);
> +
> + if (handled)
> + can_rx_offload_irq_finish(&priv->offload);
> +
> + return handled;
> +}
> +
> +/* Bus error IRQ handler for multi-IRQ platforms */
> +static irqreturn_t flexcan_irq_berr(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + irqreturn_t handled;
> +
> + handled = flexcan_do_berr(dev);
> +
> + if (handled)
> + can_rx_offload_irq_finish(&priv->offload);
> +
> + return handled;
> +}
> +
> +/* Device state change IRQ handler for multi-IRQ platforms */
> +static irqreturn_t flexcan_irq_boff(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct flexcan_priv *priv = netdev_priv(dev);
> + irqreturn_t handled;
> +
> + handled = flexcan_do_state(dev);
> +
> if (handled)
> can_rx_offload_irq_finish(&priv->offload);
>
> @@ -1761,25 +1850,30 @@ static int flexcan_open(struct net_device *dev)
>
> can_rx_offload_enable(&priv->offload);
>
> - err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
> + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
> + err = request_irq(dev->irq, flexcan_irq_mb,
> + IRQF_SHARED, dev->name, dev);
> + else
> + err = request_irq(dev->irq, flexcan_irq,
> + IRQF_SHARED, dev->name, dev);
> if (err)
> goto out_can_rx_offload_disable;
>
> if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
> err = request_irq(priv->irq_boff,
> - flexcan_irq, IRQF_SHARED, dev->name, dev);
> + flexcan_irq_boff, IRQF_SHARED, dev->name, dev);
> if (err)
> goto out_free_irq;
>
> err = request_irq(priv->irq_err,
> - flexcan_irq, IRQF_SHARED, dev->name, dev);
> + flexcan_irq_berr, IRQF_SHARED, dev->name, dev);
> if (err)
> goto out_free_irq_boff;
> }
>
> if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
> err = request_irq(priv->irq_secondary_mb,
> - flexcan_irq, IRQF_SHARED, dev->name, dev);
> + flexcan_irq_mb, IRQF_SHARED, dev->name, dev);
> if (err)
> goto out_free_irq_err;
> }
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH RESEND v4 2/8] can: flexcan: disable all IRQ lines in flexcan_chip_interrupts_enable()
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
2026-06-03 7:13 ` [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 7:13 ` [PATCH RESEND v4 3/8] can: flexcan: split rx/tx masks per mailbox IRQ line Ciprian Costea
` (6 subsequent siblings)
8 siblings, 0 replies; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
flexcan_chip_interrupts_enable() disables only the primary IRQ line while
writing to the IMASK and CTRL registers.
On multi-IRQ platforms (S32G2, MCF5441X), the additional IRQ lines (boff,
err, secondary-mb) remain active so their handlers can fire while
registers are inconsistent.
Disable all registered IRQ lines around the IMASK/CTRL writes. This
also fixes the resume path, which calls this function.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
drivers/net/can/flexcan/flexcan-core.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index f73ff442d530..7dde2e623def 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1519,14 +1519,28 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs;
+ u32 quirks = priv->devtype_data.quirks;
u64 reg_imask;
disable_irq(dev->irq);
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ disable_irq(priv->irq_boff);
+ disable_irq(priv->irq_err);
+ }
+ if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
+ disable_irq(priv->irq_secondary_mb);
+
priv->write(priv->reg_ctrl_default, ®s->ctrl);
reg_imask = priv->rx_mask | priv->tx_mask;
priv->write(upper_32_bits(reg_imask), ®s->imask2);
priv->write(lower_32_bits(reg_imask), ®s->imask1);
enable_irq(dev->irq);
+ if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
+ enable_irq(priv->irq_secondary_mb);
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ enable_irq(priv->irq_boff);
+ enable_irq(priv->irq_err);
+ }
}
static void flexcan_chip_interrupts_disable(const struct net_device *dev)
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH RESEND v4 3/8] can: flexcan: split rx/tx masks per mailbox IRQ line
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
2026-06-03 7:13 ` [PATCH RESEND v4 1/8] can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms Ciprian Costea
2026-06-03 7:13 ` [PATCH RESEND v4 2/8] can: flexcan: disable all IRQ lines in flexcan_chip_interrupts_enable() Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 7:49 ` sashiko-bot
2026-06-03 7:13 ` [PATCH RESEND v4 4/8] dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support Ciprian Costea
` (5 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
On S32G2, which has two mailbox IRQ lines (mb-0 for MBs 0-7, mb-1
for MBs 8-127), both handlers currently process the full rx_mask/tx_mask
range,
Introduce struct flexcan_mb_irq to hold per-IRQ-line rx and tx masks.
In flexcan_irq_mb(), the irq argument selects the correct mask set: the
primary MB IRQ uses mb_irq[0] and the secondary uses mb_irq[1].
For single-IRQ platforms, mb_irq[0] holds the full combined masks with no
functional change.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
drivers/net/can/flexcan/flexcan-core.c | 61 +++++++++++++++++++-------
drivers/net/can/flexcan/flexcan.h | 10 ++++-
2 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 7dde2e623def..32e4d4da00a1 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -957,14 +957,16 @@ static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __io
priv->write(lower_32_bits(val), addr);
}
-static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
+static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv,
+ u64 rx_mask)
{
- return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
+ return flexcan_read64_mask(priv, &priv->regs->iflag1, rx_mask);
}
-static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv)
+static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv,
+ u64 tx_mask)
{
- return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask);
+ return flexcan_read64_mask(priv, &priv->regs->iflag1, tx_mask);
}
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
@@ -1071,7 +1073,8 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
}
/* Process mailbox (RX + TX) events */
-static irqreturn_t flexcan_do_mb(struct net_device *dev)
+static irqreturn_t flexcan_do_mb(struct net_device *dev,
+ const struct flexcan_mb_irq *mb_irq)
{
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
@@ -1084,7 +1087,8 @@ static irqreturn_t flexcan_do_mb(struct net_device *dev)
u64 reg_iflag_rx;
int ret;
- while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
+ while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv,
+ mb_irq->rx_mask))) {
handled = IRQ_HANDLED;
ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
reg_iflag_rx);
@@ -1110,10 +1114,10 @@ static irqreturn_t flexcan_do_mb(struct net_device *dev)
}
}
- reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
+ reg_iflag_tx = flexcan_read_reg_iflag_tx(priv, mb_irq->tx_mask);
/* transmission complete interrupt */
- if (reg_iflag_tx & priv->tx_mask) {
+ if (reg_iflag_tx & mb_irq->tx_mask) {
u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
handled = IRQ_HANDLED;
@@ -1125,7 +1129,7 @@ static irqreturn_t flexcan_do_mb(struct net_device *dev)
/* after sending a RTR frame MB is in RX mode */
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
&priv->tx_mb->can_ctrl);
- flexcan_write64(priv, priv->tx_mask, ®s->iflag1);
+ flexcan_write64(priv, mb_irq->tx_mask, ®s->iflag1);
netif_wake_queue(dev);
}
@@ -1228,7 +1232,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct flexcan_priv *priv = netdev_priv(dev);
irqreturn_t handled;
- handled = flexcan_do_mb(dev);
+ handled = flexcan_do_mb(dev, &priv->mb_irq[0]);
handled |= flexcan_do_state(dev);
handled |= flexcan_do_berr(dev);
@@ -1243,9 +1247,15 @@ static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct flexcan_priv *priv = netdev_priv(dev);
+ const struct flexcan_mb_irq *mb_irq;
irqreturn_t handled;
+ int idx;
- handled = flexcan_do_mb(dev);
+ idx = (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ &&
+ irq == priv->irq_secondary_mb) ? 1 : 0;
+ mb_irq = &priv->mb_irq[idx];
+
+ handled = flexcan_do_mb(dev, mb_irq);
if (handled)
can_rx_offload_irq_finish(&priv->offload);
@@ -1473,6 +1483,7 @@ static void flexcan_ram_init(struct net_device *dev)
static int flexcan_rx_offload_setup(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
+ u64 rx_mask, tx_mask;
int err;
if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
@@ -1494,20 +1505,35 @@ static int flexcan_rx_offload_setup(struct net_device *dev)
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_RX_FIFO);
priv->tx_mb_idx = priv->mb_count - 1;
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
- priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
-
priv->offload.mailbox_read = flexcan_mailbox_read;
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) {
priv->offload.mb_first = FLEXCAN_RX_MB_RX_MAILBOX_FIRST;
priv->offload.mb_last = priv->mb_count - 2;
- priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
- priv->offload.mb_first);
+ rx_mask = GENMASK_ULL(priv->offload.mb_last,
+ priv->offload.mb_first);
+ tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
+
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
+ /* S32G2 has two MB IRQ lines with the split at MB 8:
+ * mb-0 IRQ handles MBs 0-7,
+ * mb-1 IRQ handles MBs 8-127.
+ */
+ priv->mb_irq[0].rx_mask = rx_mask & GENMASK_ULL(7, 0);
+ priv->mb_irq[0].tx_mask = tx_mask & GENMASK_ULL(7, 0);
+ priv->mb_irq[1].rx_mask = rx_mask & GENMASK_ULL(63, 8);
+ priv->mb_irq[1].tx_mask = tx_mask & GENMASK_ULL(63, 8);
+ } else {
+ priv->mb_irq[0].rx_mask = rx_mask;
+ priv->mb_irq[0].tx_mask = tx_mask;
+ }
+
err = can_rx_offload_add_timestamp(dev, &priv->offload);
} else {
- priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
+ priv->mb_irq[0].rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
+ priv->mb_irq[0].tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
err = can_rx_offload_add_fifo(dev, &priv->offload,
FLEXCAN_NAPI_WEIGHT);
}
@@ -1531,7 +1557,8 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
disable_irq(priv->irq_secondary_mb);
priv->write(priv->reg_ctrl_default, ®s->ctrl);
- reg_imask = priv->rx_mask | priv->tx_mask;
+ reg_imask = priv->mb_irq[0].rx_mask | priv->mb_irq[0].tx_mask |
+ priv->mb_irq[1].rx_mask | priv->mb_irq[1].tx_mask;
priv->write(upper_32_bits(reg_imask), ®s->imask2);
priv->write(lower_32_bits(reg_imask), ®s->imask1);
enable_irq(dev->irq);
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index 16692a2502eb..22aa097ec3c0 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -75,10 +75,17 @@
*/
#define FLEXCAN_QUIRK_SECONDARY_MB_IRQ BIT(18)
+#define FLEXCAN_NR_MB_IRQS 2
+
struct flexcan_devtype_data {
u32 quirks; /* quirks needed for different IP cores */
};
+struct flexcan_mb_irq {
+ u64 rx_mask;
+ u64 tx_mask;
+};
+
struct flexcan_stop_mode {
struct regmap *gpr;
u8 req_gpr;
@@ -99,8 +106,7 @@ struct flexcan_priv {
u8 clk_src; /* clock source of CAN Protocol Engine */
u8 scu_idx;
- u64 rx_mask;
- u64 tx_mask;
+ struct flexcan_mb_irq mb_irq[FLEXCAN_NR_MB_IRQS];
u32 reg_ctrl_default;
struct clk *clk_ipg;
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 3/8] can: flexcan: split rx/tx masks per mailbox IRQ line
2026-06-03 7:13 ` [PATCH RESEND v4 3/8] can: flexcan: split rx/tx masks per mailbox IRQ line Ciprian Costea
@ 2026-06-03 7:49 ` sashiko-bot
0 siblings, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-06-03 7:49 UTC (permalink / raw)
To: Ciprian Costea; +Cc: devicetree, imx, conor+dt, robh, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Concurrent execution of mailbox IRQ handlers corrupts the lockless `skb_irq_queue` list and tears network statistics.
--
commit bbe7c1e92a358fe90eaccbfc4dbbf6d74daadadd
Author: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
can: flexcan: split rx/tx masks per mailbox IRQ line
This patch splits rx and tx masks per mailbox IRQ line for platforms like
S32G2 which have multiple mailbox IRQs. It introduces a struct to hold these
masks and updates the IRQ handlers to use the correct subset, preventing both
handlers from processing the full mask range.
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> index 7dde2e623defe..32e4d4da00a1c 100644
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
[ ... ]
> @@ -1243,9 +1247,15 @@ static irqreturn_t flexcan_irq_mb(int irq, void *dev_id)
> {
> struct net_device *dev = dev_id;
> struct flexcan_priv *priv = netdev_priv(dev);
> + const struct flexcan_mb_irq *mb_irq;
> irqreturn_t handled;
> + int idx;
>
> - handled = flexcan_do_mb(dev);
> + idx = (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ &&
> + irq == priv->irq_secondary_mb) ? 1 : 0;
> + mb_irq = &priv->mb_irq[idx];
> +
> + handled = flexcan_do_mb(dev, mb_irq);
[Severity: High]
This isn't a bug introduced by this patch, but since the S32G2 platform
supports multiple mailbox IRQ lines (mb-0 and mb-1), can these handlers execute
concurrently on different CPUs?
Both handlers invoke flexcan_do_mb(), which eventually calls
can_rx_offload_irq_offload_timestamp() using the shared priv->offload
structure. This performs a lockless list insertion:
drivers/net/can/dev/rx-offload.c:can_rx_offload_irq_offload_timestamp() {
...
__skb_queue_add_sort(&offload->skb_irq_queue, skb,
can_rx_offload_compare);
...
}
Because __skb_queue_add_sort() does not take internal locks, concurrent
execution by multiple hardirq handlers could corrupt the list pointers.
>
> if (handled)
> can_rx_offload_irq_finish(&priv->offload);
Furthermore, one handler might be concurrently splicing the list while the
other is inserting:
drivers/net/can/dev/rx-offload.c:can_rx_offload_irq_finish() {
...
spin_lock_irqsave(&offload->skb_queue.lock, flags);
skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
...
}
Does the driver need to ensure mutual exclusion between the mailbox IRQ
handlers when accessing the shared skb_irq_queue?
>
> return handled;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603071342.641874-1-ciprianmarian.costea@oss.nxp.com?part=3
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH RESEND v4 4/8] dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
` (2 preceding siblings ...)
2026-06-03 7:13 ` [PATCH RESEND v4 3/8] can: flexcan: split rx/tx masks per mailbox IRQ line Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 8:02 ` sashiko-bot
2026-06-03 7:13 ` [PATCH RESEND v4 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk Ciprian Costea
` (4 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Andra-Teodora Ilie, Larisa Grigore,
Conor Dooley
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Add NXP S32N79 SoC compatible string and interrupt properties.
On S32N79, FlexCAN IP is integrated with two interrupt lines:
one for the mailbox interrupts (0-127) and one for signaling
bus errors and device state changes.
Co-developed-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/net/can/fsl,flexcan.yaml | 30 ++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
index f81d56f7c12a..d098a44c2b9c 100644
--- a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
+++ b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
@@ -26,6 +26,7 @@ properties:
- fsl,ls1021ar2-flexcan
- fsl,lx2160ar1-flexcan
- nxp,s32g2-flexcan
+ - nxp,s32n79-flexcan
- items:
- enum:
- fsl,imx53-flexcan
@@ -173,11 +174,38 @@ allOf:
- const: mb-1
required:
- interrupt-names
- else:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: nxp,s32n79-flexcan
+ then:
+ properties:
+ interrupts:
+ items:
+ - description: Message Buffer interrupt for mailboxes 0-127
+ - description: Bus Error and Device state change interrupt
+ interrupt-names:
+ items:
+ - const: mb-0
+ - const: berr
+ required:
+ - interrupt-names
+
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nxp,s32g2-flexcan
+ - nxp,s32n79-flexcan
+ then:
properties:
interrupts:
maxItems: 1
interrupt-names: false
+
- if:
required:
- xceiver-supply
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 4/8] dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
2026-06-03 7:13 ` [PATCH RESEND v4 4/8] dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support Ciprian Costea
@ 2026-06-03 8:02 ` sashiko-bot
0 siblings, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-06-03 8:02 UTC (permalink / raw)
To: Ciprian Costea; +Cc: conor+dt, robh, imx, devicetree, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Concurrent execution of separate IRQ handlers silently corrupts the lockless skb_irq_queue in the RX offload core.
--
commit 1b40c6c47df0cbe3a237b4923882ceb85a965615
Author: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
Add NXP S32N79 SoC compatible string and interrupt properties.
On S32N79, FlexCAN IP is integrated with two interrupt lines:
one for the mailbox interrupts (0-127) and one for signaling
bus errors and device state changes.
> diff --git a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
> index f81d56f7c12a5..d098a44c2b9c2 100644
> --- a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
> +++ b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
[ ... ]
> @@ -173,11 +174,38 @@ allOf:
> - const: mb-1
> required:
> - interrupt-names
> - else:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: nxp,s32n79-flexcan
> + then:
> + properties:
> + interrupts:
> + items:
> + - description: Message Buffer interrupt for mailboxes 0-127
> + - description: Bus Error and Device state change interrupt
[Severity: High]
This is a pre-existing issue, but can the concurrent execution of these separate
IRQ handlers silently corrupt the lockless skb_irq_queue in the RX offload core?
Since multi-IRQ platforms (like the newly added S32N79) map different FlexCAN
events to distinct hardware IRQ lines, the interrupt handlers can be dispatched
concurrently on different CPUs.
For example, CPU1 could be executing flexcan_irq_mb() while CPU2 is executing
flexcan_irq_boff():
CPU1:
drivers/net/can/flexcan/flexcan-core.c:flexcan_irq_mb() {
...
handled = flexcan_do_mb(dev, mb_irq);
...
}
CPU2:
drivers/net/can/flexcan/flexcan-core.c:flexcan_irq_boff() {
...
handled = flexcan_do_state(dev);
...
}
Both of these paths eventually call into the RX offload core to enqueue
packets:
drivers/net/can/dev/rx-offload.c:can_rx_offload_queue_timestamp() {
...
__skb_queue_add_sort(&offload->skb_irq_queue, skb, can_rx_offload_compare);
...
}
Because __skb_queue_add_sort() and __skb_queue_tail() are lockless queue
operations, won't concurrent insertions from multiple CPUs corrupt the
doubly-linked list pointers and lead to a kernel panic on subsequent accesses?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603071342.641874-1-ciprianmarian.costea@oss.nxp.com?part=4
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH RESEND v4 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
` (3 preceding siblings ...)
2026-06-03 7:13 ` [PATCH RESEND v4 4/8] dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 8:15 ` sashiko-bot
2026-06-03 7:13 ` [PATCH RESEND v4 6/8] can: flexcan: add NXP S32N79 SoC support Ciprian Costea
` (3 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Larisa Grigore
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Introduce FLEXCAN_QUIRK_IRQ_BERR quirk to handle hardware integration
where the FlexCAN module has a dedicated interrupt line for signaling
bus errors and device state changes.
This adds the flexcan_irq_esr() handler which composes
flexcan_do_state() and flexcan_do_berr() to handle platforms where
these events share a single IRQ line.
Also extend flexcan_chip_interrupts_enable() to disable/enable the
new IRQ line during IMASK register writes.
This is required for NXP S32N79 SoC support.
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
drivers/net/can/flexcan/flexcan-core.c | 54 +++++++++++++++++++++-----
drivers/net/can/flexcan/flexcan.h | 2 +
2 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 32e4d4da00a1..23ddf7910641 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -1293,6 +1293,22 @@ static irqreturn_t flexcan_irq_boff(int irq, void *dev_id)
return handled;
}
+/* Combined bus error and state change IRQ handler */
+static irqreturn_t flexcan_irq_esr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct flexcan_priv *priv = netdev_priv(dev);
+ irqreturn_t handled;
+
+ handled = flexcan_do_state(dev);
+ handled |= flexcan_do_berr(dev);
+
+ if (handled)
+ can_rx_offload_irq_finish(&priv->offload);
+
+ return handled;
+}
+
static void flexcan_set_bittiming_ctrl(const struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
@@ -1549,10 +1565,10 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
u64 reg_imask;
disable_irq(dev->irq);
- if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3)
disable_irq(priv->irq_boff);
+ if (quirks & (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
disable_irq(priv->irq_err);
- }
if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
disable_irq(priv->irq_secondary_mb);
@@ -1564,10 +1580,10 @@ static void flexcan_chip_interrupts_enable(const struct net_device *dev)
enable_irq(dev->irq);
if (quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
enable_irq(priv->irq_secondary_mb);
- if (quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
- enable_irq(priv->irq_boff);
+ if (quirks & (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
enable_irq(priv->irq_err);
- }
+ if (quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ enable_irq(priv->irq_boff);
}
static void flexcan_chip_interrupts_disable(const struct net_device *dev)
@@ -1891,7 +1907,8 @@ static int flexcan_open(struct net_device *dev)
can_rx_offload_enable(&priv->offload);
- if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ if (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_IRQ_BERR))
err = request_irq(dev->irq, flexcan_irq_mb,
IRQF_SHARED, dev->name, dev);
else
@@ -1912,6 +1929,13 @@ static int flexcan_open(struct net_device *dev)
goto out_free_irq_boff;
}
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
+ err = request_irq(priv->irq_err,
+ flexcan_irq_esr, IRQF_SHARED, dev->name, dev);
+ if (err)
+ goto out_free_irq_boff;
+ }
+
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ) {
err = request_irq(priv->irq_secondary_mb,
flexcan_irq_mb, IRQF_SHARED, dev->name, dev);
@@ -1926,7 +1950,8 @@ static int flexcan_open(struct net_device *dev)
return 0;
out_free_irq_err:
- if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
+ if (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_IRQ_BERR | FLEXCAN_QUIRK_NR_IRQ_3))
free_irq(priv->irq_err, dev);
out_free_irq_boff:
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
@@ -1958,10 +1983,12 @@ static int flexcan_close(struct net_device *dev)
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SECONDARY_MB_IRQ)
free_irq(priv->irq_secondary_mb, dev);
- if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
+ if (priv->devtype_data.quirks &
+ (FLEXCAN_QUIRK_IRQ_BERR | FLEXCAN_QUIRK_NR_IRQ_3))
free_irq(priv->irq_err, dev);
+
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3)
free_irq(priv->irq_boff, dev);
- }
free_irq(dev->irq, dev);
can_rx_offload_disable(&priv->offload);
@@ -2348,12 +2375,21 @@ static int flexcan_probe(struct platform_device *pdev)
if (transceiver)
priv->can.bitrate_max = transceiver->attrs.max_link_rate;
+ if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
+ priv->irq_err = platform_get_irq_byname(pdev, "berr");
+ if (priv->irq_err < 0) {
+ err = priv->irq_err;
+ goto failed_platform_get_irq;
+ }
+ }
+
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
priv->irq_boff = platform_get_irq(pdev, 1);
if (priv->irq_boff < 0) {
err = priv->irq_boff;
goto failed_platform_get_irq;
}
+
priv->irq_err = platform_get_irq(pdev, 2);
if (priv->irq_err < 0) {
err = priv->irq_err;
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index 22aa097ec3c0..43d4e0da3779 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -74,6 +74,8 @@
* both need to have an interrupt handler registered.
*/
#define FLEXCAN_QUIRK_SECONDARY_MB_IRQ BIT(18)
+/* Setup dedicated bus error and state change IRQ */
+#define FLEXCAN_QUIRK_IRQ_BERR BIT(19)
#define FLEXCAN_NR_MB_IRQS 2
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
2026-06-03 7:13 ` [PATCH RESEND v4 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk Ciprian Costea
@ 2026-06-03 8:15 ` sashiko-bot
0 siblings, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-06-03 8:15 UTC (permalink / raw)
To: Ciprian Costea; +Cc: devicetree, robh, imx, conor+dt, Frank.Li
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Concurrent lockless modification of `skb_irq_queue` leading to linked list corruption.
--
commit 5585c21d3d6c362465f049b7368b7a16b3da034f
Author: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
This commit introduces FLEXCAN_QUIRK_IRQ_BERR to handle hardware with a
dedicated interrupt line for bus errors and device state changes. It adds
the flexcan_irq_esr() handler and enables/disables the new IRQ line as
needed.
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> index 32e4d4da00a1c..23ddf79106410 100644
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
[ ... ]
> @@ -1912,6 +1929,13 @@ static int flexcan_open(struct net_device *dev)
> goto out_free_irq_boff;
> }
>
> + if (priv->devtype_data.quirks & FLEXCAN_QUIRK_IRQ_BERR) {
> + err = request_irq(priv->irq_err,
> + flexcan_irq_esr, IRQF_SHARED, dev->name, dev);
[Severity: High]
This is a pre-existing issue, but this quirk continues a pattern where
separate interrupt handlers are registered on distinct physical IRQ lines.
Is there anything preventing flexcan_irq_esr() from executing concurrently
with the mailbox interrupt handler (flexcan_irq_mb) on a different CPU?
If they run concurrently, can this lead to lockless doubly-linked list
corruption?
The CAN rx_offload framework expects SKB enqueuing functions to be
serialized. However, if flexcan_irq_esr() calls flexcan_do_state() or
flexcan_do_berr() which use can_rx_offload_queue_timestamp(), it will
insert SKBs into offload->skb_irq_queue locklessly via
__skb_queue_add_sort().
At the same time, flexcan_do_mb() running from flexcan_irq_mb() can call
can_rx_offload_irq_offload_timestamp() or
can_rx_offload_get_echo_skb_queue_timestamp(), which also locklessly modify
the same skb_irq_queue.
Could this concurrent access scramble the list's next/prev pointers, leading
to kernel panics or infinite loops during NAPI processing?
> + if (err)
> + goto out_free_irq_boff;
> + }
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603071342.641874-1-ciprianmarian.costea@oss.nxp.com?part=5
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH RESEND v4 6/8] can: flexcan: add NXP S32N79 SoC support
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
` (4 preceding siblings ...)
2026-06-03 7:13 ` [PATCH RESEND v4 5/8] can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 8:25 ` sashiko-bot
2026-06-03 7:13 ` [PATCH RESEND v4 7/8] arm64: dts: s32n79: add FlexCAN nodes Ciprian Costea
` (2 subsequent siblings)
8 siblings, 1 reply; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Andra-Teodora Ilie, Larisa Grigore
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Add device data and compatible string for NXP S32N79 SoC.
FlexCAN IP integration on S32N79 SoC uses two interrupts:
- one for mailboxes 0-127
- one for signaling bus errors and device state changes
Co-developed-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
drivers/net/can/flexcan/flexcan-core.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index 23ddf7910641..9ae0d9eb4ccc 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -397,6 +397,15 @@ static const struct flexcan_devtype_data nxp_s32g2_devtype_data = {
FLEXCAN_QUIRK_SECONDARY_MB_IRQ,
};
+static const struct flexcan_devtype_data nxp_s32n_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
+ FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
+ FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_FD |
+ FLEXCAN_QUIRK_SUPPORT_ECC | FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
+ FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR |
+ FLEXCAN_QUIRK_IRQ_BERR,
+};
+
static const struct can_bittiming_const flexcan_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 4,
@@ -2232,6 +2241,7 @@ static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
{ .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
{ .compatible = "nxp,s32g2-flexcan", .data = &nxp_s32g2_devtype_data, },
+ { .compatible = "nxp,s32n79-flexcan", .data = &nxp_s32n_devtype_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, flexcan_of_match);
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 6/8] can: flexcan: add NXP S32N79 SoC support
2026-06-03 7:13 ` [PATCH RESEND v4 6/8] can: flexcan: add NXP S32N79 SoC support Ciprian Costea
@ 2026-06-03 8:25 ` sashiko-bot
0 siblings, 0 replies; 19+ messages in thread
From: sashiko-bot @ 2026-06-03 8:25 UTC (permalink / raw)
To: Ciprian Costea; +Cc: Frank.Li, robh, devicetree, imx, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Wakeup functionality is broken for multi-IRQ FlexCAN platforms (like S32N79) because `enable_irq_wake()` is called on the mailbox interrupt (`dev->irq`) instead of the state/wakeup interrupt (`priv->irq_err`).
--
commit 39bd2be7b5ab93fd5fb7064b8e7d3eac344ed38f
Author: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
can: flexcan: add NXP S32N79 SoC support
This patch introduces support for the NXP S32N79 SoC in the FlexCAN driver.
It adds a new device data structure specifying necessary quirks, including
multiple interrupt handling, and registers the new compatible string.
> diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
> --- a/drivers/net/can/flexcan/flexcan-core.c
> +++ b/drivers/net/can/flexcan/flexcan-core.c
> @@ -397,6 +397,15 @@ static const struct flexcan_devtype_data nxp_s32g2_devtype_data = {
> FLEXCAN_QUIRK_SECONDARY_MB_IRQ,
> };
>
> +static const struct flexcan_devtype_data nxp_s32n_devtype_data = {
> + .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
> + FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
> + FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_FD |
> + FLEXCAN_QUIRK_SUPPORT_ECC | FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
> + FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR |
> + FLEXCAN_QUIRK_IRQ_BERR,
[Severity: High]
This isn't a bug introduced by this patch, but will wakeup functionality be
broken for this new platform since it uses multiple interrupts?
In flexcan_suspend() and flexcan_resume(), the driver hardcodes
enable_irq_wake(dev->irq) and disable_irq_wake(dev->irq):
flexcan_suspend() {
...
if (device_may_wakeup(device)) {
enable_irq_wake(dev->irq);
...
}
For multi-IRQ platforms using FLEXCAN_QUIRK_IRQ_BERR, dev->irq is dedicated
to mailboxes, while state changes and wakeups (FLEXCAN_ESR_WAK_INT) are
routed to priv->irq_err.
Because enable_irq_wake() is never called for priv->irq_err, will the
interrupt controller mask the actual wakeup interrupt during suspend,
preventing the CAN controller from waking up the CPU?
> +};
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603071342.641874-1-ciprianmarian.costea@oss.nxp.com?part=6
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH RESEND v4 7/8] arm64: dts: s32n79: add FlexCAN nodes
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
` (5 preceding siblings ...)
2026-06-03 7:13 ` [PATCH RESEND v4 6/8] can: flexcan: add NXP S32N79 SoC support Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 7:13 ` [PATCH RESEND v4 8/8] arm64: dts: s32n79: enable FlexCAN devices Ciprian Costea
2026-06-03 9:39 ` [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Bough Chen
8 siblings, 0 replies; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea, Andra-Teodora Ilie
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
The S32N79 integrates multiple FlexCAN instances connected through the RCU
irqsteer interrupt controller.
Co-developed-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Andra-Teodora Ilie <andra.ilie@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32n79.dtsi | 50 +++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32n79.dtsi b/arch/arm64/boot/dts/freescale/s32n79.dtsi
index 94ab58783fdc..c1a4fdead91d 100644
--- a/arch/arm64/boot/dts/freescale/s32n79.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32n79.dtsi
@@ -352,6 +352,56 @@ pmu: pmu {
interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
};
+ rcu-bus {
+ compatible = "simple-bus";
+ ranges = <0x54000000 0x0 0x54000000 0x4000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ irqsteer_rcu: interrupt-controller@55101000 {
+ compatible = "nxp,s32n79-irqsteer";
+ reg = <0x55101000 0x1000>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks 0xf9>;
+ clock-names = "ipg";
+ fsl,channel = <0>;
+ fsl,num-irqs = <512>;
+ status = "disabled";
+ };
+
+ can0: can@55b60000 {
+ compatible = "nxp,s32n79-flexcan";
+ reg = <0x55b60000 0x4000>;
+ interrupt-parent = <&irqsteer_rcu>;
+ interrupts = <0>, <64>;
+ interrupt-names = "mb-0", "berr";
+ clocks = <&clks 0xf9>, <&clks 0xfc>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ can1: can@55b70000 {
+ compatible = "nxp,s32n79-flexcan";
+ reg = <0x55b70000 0x4000>;
+ interrupt-parent = <&irqsteer_rcu>;
+ interrupts = <1>, <65>;
+ interrupt-names = "mb-0", "berr";
+ clocks = <&clks 0xf9>, <&clks 0xfc>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+ };
+
timer: timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH RESEND v4 8/8] arm64: dts: s32n79: enable FlexCAN devices
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
` (6 preceding siblings ...)
2026-06-03 7:13 ` [PATCH RESEND v4 7/8] arm64: dts: s32n79: add FlexCAN nodes Ciprian Costea
@ 2026-06-03 7:13 ` Ciprian Costea
2026-06-03 9:39 ` [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Bough Chen
8 siblings, 0 replies; 19+ messages in thread
From: Ciprian Costea @ 2026-06-03 7:13 UTC (permalink / raw)
To: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam
Cc: Pengutronix Kernel Team, linux-can, devicetree, linux-kernel, imx,
linux-arm-kernel, NXP S32 Linux Team, Christophe Lizzi,
Alberto Ruiz, Enric Balletbo, Eric Chanudet,
Ciprian Marian Costea
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Enable FlexCAN controller instances (can0 and can1) and the required RCU
irqsteer interrupt controller on S32N79-RDB board.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32n79-rdb.dts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32n79-rdb.dts b/arch/arm64/boot/dts/freescale/s32n79-rdb.dts
index 1feccd61258e..65a595d7535f 100644
--- a/arch/arm64/boot/dts/freescale/s32n79-rdb.dts
+++ b/arch/arm64/boot/dts/freescale/s32n79-rdb.dts
@@ -43,10 +43,22 @@ memory@80000000 {
};
};
+&can0 {
+ status = "okay";
+};
+
+&can1 {
+ status = "okay";
+};
+
&irqsteer_coss {
status = "okay";
};
+&irqsteer_rcu {
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support
2026-06-03 7:13 [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Ciprian Costea
` (7 preceding siblings ...)
2026-06-03 7:13 ` [PATCH RESEND v4 8/8] arm64: dts: s32n79: enable FlexCAN devices Ciprian Costea
@ 2026-06-03 9:39 ` Bough Chen
2026-06-03 10:28 ` Enric Balletbo i Serra
8 siblings, 1 reply; 19+ messages in thread
From: Bough Chen @ 2026-06-03 9:39 UTC (permalink / raw)
To: Ciprian Costea
Cc: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam, Pengutronix Kernel Team, linux-can, devicetree,
linux-kernel, imx, linux-arm-kernel, NXP S32 Linux Team,
Christophe Lizzi, Alberto Ruiz, Enric Balletbo, Eric Chanudet
On Wed, Jun 03, 2026 at 09:13:34AM +0200, Ciprian Costea wrote:
> From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
>
> This patch series adds FlexCAN support for the NXP S32N79 SoC.
>
> The S32N79 is an automotive-grade processor from NXP with multiple
> FlexCAN instances. The FlexCAN IP integration on S32N79 differs from
> other SoCs in the interrupt routing - it uses two separate interrupt
> lines:
> - one interrupt for mailboxes 0-127
> - one interrupt for bus error detection and device state changes
>
> The CAN controllers are connected through an irqsteer interrupt
> controller in the RCU (Resource Control Unit) domain.
>
> This series:
> 1. Splits flexcan_irq() into dedicated handlers for multi-IRQ platforms
> 2. Adds dt-bindings documentation for S32N79 FlexCAN
> 3. Introduces FLEXCAN_QUIRK_IRQ_BERR to handle the two-interrupt
> configuration
> 4. Adds S32N79 device data and compatible string to the driver
> 5. Adds FlexCAN device tree nodes for S32N79 SoC
> 6. Enables FlexCAN devices on the S32N79-RDB board
>
> Tested on S32N79-RDB board with CAN and CAN FD communication.
Tested on imx95-19x19-evk board with CAN and CAN FD communication. No issue found.
This means this patch set do not impact the original platforms.
For this patch set, feel free to add tag:
Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
Regards
Haibo Chen
>
> This is a resend of v4 with no changes.
>
> v4 -> v3
> - flexcan_chip_interrupts_enable(): disable/enable all IRQ lines
> (not just dev->irq) during IMASK register writes
> - Split rx/tx masks per mailbox IRQ line (struct flexcan_mb_irq) so
> each handler on S32G2 only processes its own MB range
> - Added received Acked-by tag on DT bindings patch
>
> v3 -> v2
> - Split flexcan_irq() into dedicated handlers (flexcan_irq_mb,
> flexcan_irq_boff, flexcan_irq_berr) to fix duplicate event
> processing when multiple IRQ lines run concurrently (new patch).
> - Added flexcan_irq_esr() handler composing state + berr for S32N79
> - Ordered quirks used by s32n devtype data by value.
>
> v2 -> v1
> - Renamed FLEXCAN_QUIRK_NR_IRQ_2 to FLEXCAN_QUIRK_IRQ_BERR to better
> describe the actual hardware feature
> - Appended new quirk at the end
> - Switched from platform_get_irq to platform_get_irq_byname usage
> - Updated interrupt description in dt-bindings
>
> Ciprian Marian Costea (8):
> can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
> can: flexcan: disable all IRQ lines in
> flexcan_chip_interrupts_enable()
> can: flexcan: split rx/tx masks per mailbox IRQ line
> dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
> can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
> can: flexcan: add NXP S32N79 SoC support
> arm64: dts: s32n79: add FlexCAN nodes
> arm64: dts: s32n79: enable FlexCAN devices
>
> .../bindings/net/can/fsl,flexcan.yaml | 30 ++-
> arch/arm64/boot/dts/freescale/s32n79-rdb.dts | 12 +
> arch/arm64/boot/dts/freescale/s32n79.dtsi | 50 ++++
> drivers/net/can/flexcan/flexcan-core.c | 249 +++++++++++++++---
> drivers/net/can/flexcan/flexcan.h | 12 +-
> 5 files changed, 316 insertions(+), 37 deletions(-)
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support
2026-06-03 9:39 ` [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support Bough Chen
@ 2026-06-03 10:28 ` Enric Balletbo i Serra
2026-06-03 10:33 ` Ciprian Marian Costea
0 siblings, 1 reply; 19+ messages in thread
From: Enric Balletbo i Serra @ 2026-06-03 10:28 UTC (permalink / raw)
To: Bough Chen
Cc: Ciprian Costea, Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam, Pengutronix Kernel Team, linux-can, devicetree,
linux-kernel, imx, linux-arm-kernel, NXP S32 Linux Team,
Christophe Lizzi, Alberto Ruiz, Eric Chanudet
Hi Ciprian,
Sorry in advance for the noise, for some strange reason I didn't get
or find the cover until now, so I added my tested patch in 1. Doing it
now properly.
On Wed, Jun 3, 2026 at 11:44 AM Bough Chen <haibo.chen@oss.nxp.com> wrote:
>
> On Wed, Jun 03, 2026 at 09:13:34AM +0200, Ciprian Costea wrote:
> > From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
> >
> > This patch series adds FlexCAN support for the NXP S32N79 SoC.
> >
> > The S32N79 is an automotive-grade processor from NXP with multiple
> > FlexCAN instances. The FlexCAN IP integration on S32N79 differs from
> > other SoCs in the interrupt routing - it uses two separate interrupt
> > lines:
> > - one interrupt for mailboxes 0-127
> > - one interrupt for bus error detection and device state changes
> >
> > The CAN controllers are connected through an irqsteer interrupt
> > controller in the RCU (Resource Control Unit) domain.
> >
> > This series:
> > 1. Splits flexcan_irq() into dedicated handlers for multi-IRQ platforms
> > 2. Adds dt-bindings documentation for S32N79 FlexCAN
> > 3. Introduces FLEXCAN_QUIRK_IRQ_BERR to handle the two-interrupt
> > configuration
> > 4. Adds S32N79 device data and compatible string to the driver
> > 5. Adds FlexCAN device tree nodes for S32N79 SoC
> > 6. Enables FlexCAN devices on the S32N79-RDB board
> >
> > Tested on S32N79-RDB board with CAN and CAN FD communication.
>
> Tested on imx95-19x19-evk board with CAN and CAN FD communication. No issue found.
> This means this patch set do not impact the original platforms.
>
> For this patch set, feel free to add tag:
> Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
>
> Regards
> Haibo Chen
Tested-by: Enric Balletbo i Serra <eballetb@.redhat.com>
Tested on the NXP S32G399A-RDB3 with loopback and high-rate traffic.
No regressions observed:
CAN frames transmit and receive correctly, with no duplicates.
Frame reception showed no errors during stress testing.
Regards,
Enric Balletbo
> >
> > This is a resend of v4 with no changes.
> >
> > v4 -> v3
> > - flexcan_chip_interrupts_enable(): disable/enable all IRQ lines
> > (not just dev->irq) during IMASK register writes
> > - Split rx/tx masks per mailbox IRQ line (struct flexcan_mb_irq) so
> > each handler on S32G2 only processes its own MB range
> > - Added received Acked-by tag on DT bindings patch
> >
> > v3 -> v2
> > - Split flexcan_irq() into dedicated handlers (flexcan_irq_mb,
> > flexcan_irq_boff, flexcan_irq_berr) to fix duplicate event
> > processing when multiple IRQ lines run concurrently (new patch).
> > - Added flexcan_irq_esr() handler composing state + berr for S32N79
> > - Ordered quirks used by s32n devtype data by value.
> >
> > v2 -> v1
> > - Renamed FLEXCAN_QUIRK_NR_IRQ_2 to FLEXCAN_QUIRK_IRQ_BERR to better
> > describe the actual hardware feature
> > - Appended new quirk at the end
> > - Switched from platform_get_irq to platform_get_irq_byname usage
> > - Updated interrupt description in dt-bindings
> >
> > Ciprian Marian Costea (8):
> > can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
> > can: flexcan: disable all IRQ lines in
> > flexcan_chip_interrupts_enable()
> > can: flexcan: split rx/tx masks per mailbox IRQ line
> > dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
> > can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
> > can: flexcan: add NXP S32N79 SoC support
> > arm64: dts: s32n79: add FlexCAN nodes
> > arm64: dts: s32n79: enable FlexCAN devices
> >
> > .../bindings/net/can/fsl,flexcan.yaml | 30 ++-
> > arch/arm64/boot/dts/freescale/s32n79-rdb.dts | 12 +
> > arch/arm64/boot/dts/freescale/s32n79.dtsi | 50 ++++
> > drivers/net/can/flexcan/flexcan-core.c | 249 +++++++++++++++---
> > drivers/net/can/flexcan/flexcan.h | 12 +-
> > 5 files changed, 316 insertions(+), 37 deletions(-)
> >
> > --
> > 2.43.0
> >
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH RESEND v4 0/8] can: flexcan: Add NXP S32N79 SoC support
2026-06-03 10:28 ` Enric Balletbo i Serra
@ 2026-06-03 10:33 ` Ciprian Marian Costea
0 siblings, 0 replies; 19+ messages in thread
From: Ciprian Marian Costea @ 2026-06-03 10:33 UTC (permalink / raw)
To: Enric Balletbo i Serra, Bough Chen
Cc: Marc Kleine-Budde, Vincent Mailhol, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Fabio Estevam, Pengutronix Kernel Team, linux-can, devicetree,
linux-kernel, imx, linux-arm-kernel, NXP S32 Linux Team,
Christophe Lizzi, Alberto Ruiz, Eric Chanudet
On 6/3/2026 1:28 PM, Enric Balletbo i Serra wrote:
> Hi Ciprian,
>
> Sorry in advance for the noise, for some strange reason I didn't get
> or find the cover until now, so I added my tested patch in 1. Doing it
> now properly.
Hello Enric and Bough Chen,
Thank you for taking time in testing this FlexCAN series against
both functionality on S32N79-RDB and regressions on other platforms.
Best Regards,
Ciprian
>
> On Wed, Jun 3, 2026 at 11:44 AM Bough Chen <haibo.chen@oss.nxp.com> wrote:
>>
>> On Wed, Jun 03, 2026 at 09:13:34AM +0200, Ciprian Costea wrote:
>>> From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
>>>
>>> This patch series adds FlexCAN support for the NXP S32N79 SoC.
>>>
>>> The S32N79 is an automotive-grade processor from NXP with multiple
>>> FlexCAN instances. The FlexCAN IP integration on S32N79 differs from
>>> other SoCs in the interrupt routing - it uses two separate interrupt
>>> lines:
>>> - one interrupt for mailboxes 0-127
>>> - one interrupt for bus error detection and device state changes
>>>
>>> The CAN controllers are connected through an irqsteer interrupt
>>> controller in the RCU (Resource Control Unit) domain.
>>>
>>> This series:
>>> 1. Splits flexcan_irq() into dedicated handlers for multi-IRQ platforms
>>> 2. Adds dt-bindings documentation for S32N79 FlexCAN
>>> 3. Introduces FLEXCAN_QUIRK_IRQ_BERR to handle the two-interrupt
>>> configuration
>>> 4. Adds S32N79 device data and compatible string to the driver
>>> 5. Adds FlexCAN device tree nodes for S32N79 SoC
>>> 6. Enables FlexCAN devices on the S32N79-RDB board
>>>
>>> Tested on S32N79-RDB board with CAN and CAN FD communication.
>>
>> Tested on imx95-19x19-evk board with CAN and CAN FD communication. No issue found.
>> This means this patch set do not impact the original platforms.
>>
>> For this patch set, feel free to add tag:
>> Reviewed-and-tested-by: Haibo Chen <haibo.chen@nxp.com>
>>
>> Regards
>> Haibo Chen
>
> Tested-by: Enric Balletbo i Serra <eballetb@.redhat.com>
>
> Tested on the NXP S32G399A-RDB3 with loopback and high-rate traffic.
> No regressions observed:
> CAN frames transmit and receive correctly, with no duplicates.
> Frame reception showed no errors during stress testing.
>
> Regards,
> Enric Balletbo
>
>>>
>>> This is a resend of v4 with no changes.
>>>
>>> v4 -> v3
>>> - flexcan_chip_interrupts_enable(): disable/enable all IRQ lines
>>> (not just dev->irq) during IMASK register writes
>>> - Split rx/tx masks per mailbox IRQ line (struct flexcan_mb_irq) so
>>> each handler on S32G2 only processes its own MB range
>>> - Added received Acked-by tag on DT bindings patch
>>>
>>> v3 -> v2
>>> - Split flexcan_irq() into dedicated handlers (flexcan_irq_mb,
>>> flexcan_irq_boff, flexcan_irq_berr) to fix duplicate event
>>> processing when multiple IRQ lines run concurrently (new patch).
>>> - Added flexcan_irq_esr() handler composing state + berr for S32N79
>>> - Ordered quirks used by s32n devtype data by value.
>>>
>>> v2 -> v1
>>> - Renamed FLEXCAN_QUIRK_NR_IRQ_2 to FLEXCAN_QUIRK_IRQ_BERR to better
>>> describe the actual hardware feature
>>> - Appended new quirk at the end
>>> - Switched from platform_get_irq to platform_get_irq_byname usage
>>> - Updated interrupt description in dt-bindings
>>>
>>> Ciprian Marian Costea (8):
>>> can: flexcan: use dedicated IRQ handlers for multi-IRQ platforms
>>> can: flexcan: disable all IRQ lines in
>>> flexcan_chip_interrupts_enable()
>>> can: flexcan: split rx/tx masks per mailbox IRQ line
>>> dt-bindings: can: fsl,flexcan: add NXP S32N79 SoC support
>>> can: flexcan: add FLEXCAN_QUIRK_IRQ_BERR quirk
>>> can: flexcan: add NXP S32N79 SoC support
>>> arm64: dts: s32n79: add FlexCAN nodes
>>> arm64: dts: s32n79: enable FlexCAN devices
>>>
>>> .../bindings/net/can/fsl,flexcan.yaml | 30 ++-
>>> arch/arm64/boot/dts/freescale/s32n79-rdb.dts | 12 +
>>> arch/arm64/boot/dts/freescale/s32n79.dtsi | 50 ++++
>>> drivers/net/can/flexcan/flexcan-core.c | 249 +++++++++++++++---
>>> drivers/net/can/flexcan/flexcan.h | 12 +-
>>> 5 files changed, 316 insertions(+), 37 deletions(-)
>>>
>>> --
>>> 2.43.0
>>>
>>
>
^ permalink raw reply [flat|nested] 19+ messages in thread