* [PATCH v3 01/15] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:44 ` Krzysztof Kozlowski
2026-01-22 12:10 ` [PATCH v3 02/15] net: can: Convert gaisler,grcan to DT schema Arun Muthusamy
` (14 subsequent siblings)
15 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Ludwig Rydberg,
Arun Muthusamy, Krzysztof Kozlowski
From: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
Frontgrade Gaisler AB provides IP cores and supporting development tools
for embedded processors based on the SPARC and RISC-V architectures.
Some essential products are the LEON and NOEL synthesizable processor
models together with a complete development environment and a library of
IP cores (GRLIB).
The company specializes in digital hardware design (ASIC/FPGA) for both
commercial and aerospace applications.
Web site: https://www.gaisler.com/
Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 424aa7b911a7..4e1b4eeff9ff 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -594,6 +594,8 @@ patternProperties:
description: Fujitsu Ltd.
"^fxtec,.*":
description: FX Technology Ltd.
+ "^gaisler,.*":
+ description: Frontgrade Gaisler AB
"^galaxycore,.*":
description: GalaxyCore Inc.
"^gameforce,.*":
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v3 01/15] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB
2026-01-22 12:10 ` [PATCH v3 01/15] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
@ 2026-01-22 12:44 ` Krzysztof Kozlowski
0 siblings, 0 replies; 31+ messages in thread
From: Krzysztof Kozlowski @ 2026-01-22 12:44 UTC (permalink / raw)
To: Arun Muthusamy, robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Ludwig Rydberg
On 22/01/2026 13:10, Arun Muthusamy wrote:
> From: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
>
> Frontgrade Gaisler AB provides IP cores and supporting development tools
> for embedded processors based on the SPARC and RISC-V architectures.
> Some essential products are the LEON and NOEL synthesizable processor
> models together with a complete development environment and a library of
> IP cores (GRLIB).
>
> The company specializes in digital hardware design (ASIC/FPGA) for both
> commercial and aerospace applications.
>
> Web site: https://www.gaisler.com/
>
> Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
>
There is no blank line between tags.
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
Please use b4 to work with your patchset (e.g. `b4 trailers`), so you
won't be making such mistakes.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 02/15] net: can: Convert gaisler,grcan to DT schema
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 01/15] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 03/15] MAINTAINERS: Add maintainers for GRCAN CAN network driver Arun Muthusamy
` (13 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy
Migrate device tree bindings for Gaisler GRCAN, GRHCAN
and GRCANFD CAN controllers from a text format to YAML format.
Additional changes:
- Remove stale systemid property
removed in commit 1e93ed26acf0 ("can: grcan: grcan_probe():
fix broken system id check for errata workaround needs")
- Make freq optional
- Add clocks
- Add compatible
- Add example
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../bindings/net/can/gaisler,grcan.yaml | 62 +++++++++++++++++++
.../devicetree/bindings/net/can/grcan.txt | 28 ---------
2 files changed, 62 insertions(+), 28 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
delete mode 100644 Documentation/devicetree/bindings/net/can/grcan.txt
diff --git a/Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml b/Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
new file mode 100644
index 000000000000..8fea97c7319a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/can/gaisler,grcan.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aeroflex Gaisler GRCAN, GRHCAN and GRCANFD CAN controllers.
+
+description: |
+ GRCAN, GRCANFD, GRHCAN controllers are available in the GRLIB VHDL
+ IP core library.
+ For further information look in the documentation for the GRLIB IP library:
+ https://download.gaisler.com/products/GRLIB/doc/grip.pdf
+
+maintainers:
+ - Arun Muthusamy <arun.muthusamy@gaisler.com>
+ - Andreas Larsson <andreas@gaisler.com>
+
+allOf:
+ - $ref: can-controller.yaml#
+
+properties:
+ compatible:
+ enum:
+ - gaisler,grcan
+ - gaisler,grcanfd
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ freq:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Frequency of the external oscillator clock in Hz (the frequency of the
+ AMBA bus in the ordinary case).
+ This property should be used by systems where the common clock
+ framework is not supported.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ can@ff400000 {
+ compatible = "gaisler,grcanfd";
+ clocks = <&sysclock>;
+ reg = <0xff400000 0x400>;
+ interrupt-parent = <&plic0>;
+ interrupts = <6>;
+ };
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.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 03/15] MAINTAINERS: Add maintainers for GRCAN CAN network driver
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 01/15] dt-bindings: Add vendor prefix for Frontgrade Gaisler AB Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 02/15] net: can: Convert gaisler,grcan to DT schema Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 04/15] can: grcan: Add clock handling Arun Muthusamy
` (12 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy
Add Arun Muthusamy and Andreas Larsson as maintainers for
the GRCAN CAN network driver, This entry ensures clear
communication channels for maintaining the Documentation
and driver code associated with GRCAN.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 0dc4aa37d903..14ddd48e063f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10706,6 +10706,14 @@ F: drivers/gpio/gpiolib-cdev.c
F: include/uapi/linux/gpio.h
F: tools/gpio/
+GRCAN CAN NETWORK DRIVER
+M: Andreas Larsson <andreas@gaisler.com>
+M: Arun Muthusamy <arun.muthusamy@gaisler.com>
+L: linux-can@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/net/can/gaisler,grcan.yaml
+F: drivers/net/can/grcan.c
+
GRETH 10/100/1G Ethernet MAC device driver
M: Andreas Larsson <andreas@gaisler.com>
L: netdev@vger.kernel.org
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 04/15] can: grcan: Add clock handling
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (2 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 03/15] MAINTAINERS: Add maintainers for GRCAN CAN network driver Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-23 13:44 ` Marc Kleine-Budde
2026-01-22 12:10 ` [PATCH v3 05/15] can: grcan: Replace bit timing macros with literal values Arun Muthusamy
` (11 subsequent siblings)
15 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
Arun Muthusamy
From: Daniel Hellstrom <daniel@gaisler.com>
Add clock handling and add error messages for missing 'freq' DT property.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 3b1b09943436..538a9b4f82ab 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -34,7 +34,7 @@
#include <linux/spinlock.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-
+#include <linux/clk.h>
#include <linux/dma-mapping.h>
#define DRV_NAME "grcan"
@@ -1644,6 +1644,7 @@ static int grcan_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
struct device_node *sysid_parent;
+ struct clk *clk;
u32 sysid, ambafreq;
int irq, err;
void __iomem *base;
@@ -1663,8 +1664,20 @@ static int grcan_probe(struct platform_device *ofdev)
err = of_property_read_u32(np, "freq", &ambafreq);
if (err) {
- dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n");
- goto exit_error;
+ clk = devm_clk_get(&ofdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err_probe(&ofdev->dev, PTR_ERR(clk),
+ "Failed both to get \"freq\" property and clock for fallback\n");
+ err = PTR_ERR(clk);
+ goto exit_error;
+ }
+ if (clk) {
+ ambafreq = clk_get_rate(clk);
+ if (!ambafreq) {
+ dev_err(&ofdev->dev, "Invalid or Uninitialized clock\n");
+ return -EINVAL;
+ }
+ }
}
base = devm_platform_ioremap_resource(ofdev, 0);
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v3 04/15] can: grcan: Add clock handling
2026-01-22 12:10 ` [PATCH v3 04/15] can: grcan: Add clock handling Arun Muthusamy
@ 2026-01-23 13:44 ` Marc Kleine-Budde
2026-01-27 13:27 ` Arun Muthusamy
0 siblings, 1 reply; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 13:44 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can, Daniel Hellstrom
[-- Attachment #1: Type: text/plain, Size: 2172 bytes --]
On 22.01.2026 13:10:27, Arun Muthusamy wrote:
> From: Daniel Hellstrom <daniel@gaisler.com>
>
> Add clock handling and add error messages for missing 'freq' DT property.
>
> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
> drivers/net/can/grcan.c | 19 ++++++++++++++++---
> 1 file changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index 3b1b09943436..538a9b4f82ab 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -34,7 +34,7 @@
> #include <linux/spinlock.h>
> #include <linux/of.h>
> #include <linux/of_irq.h>
> -
> +#include <linux/clk.h>
> #include <linux/dma-mapping.h>
>
> #define DRV_NAME "grcan"
> @@ -1644,6 +1644,7 @@ static int grcan_probe(struct platform_device *ofdev)
> {
> struct device_node *np = ofdev->dev.of_node;
> struct device_node *sysid_parent;
> + struct clk *clk;
> u32 sysid, ambafreq;
> int irq, err;
> void __iomem *base;
> @@ -1663,8 +1664,20 @@ static int grcan_probe(struct platform_device *ofdev)
>
> err = of_property_read_u32(np, "freq", &ambafreq);
> if (err) {
> - dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n");
> - goto exit_error;
> + clk = devm_clk_get(&ofdev->dev, NULL);
> + if (IS_ERR(clk)) {
> + dev_err_probe(&ofdev->dev, PTR_ERR(clk),
> + "Failed both to get \"freq\" property and clock for fallback\n");
> + err = PTR_ERR(clk);
> + goto exit_error;
> + }
I think devm_clk_get() either returns an error pointer or a valid clock
pointer.
> + if (clk) {
> + ambafreq = clk_get_rate(clk);
> + if (!ambafreq) {
> + dev_err(&ofdev->dev, "Invalid or Uninitialized clock\n");
> + return -EINVAL;
> + }
> + }
> }
>
> base = devm_platform_ioremap_resource(ofdev, 0);
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 04/15] can: grcan: Add clock handling
2026-01-23 13:44 ` Marc Kleine-Budde
@ 2026-01-27 13:27 ` Arun Muthusamy
0 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-27 13:27 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can, Daniel Hellstrom
On 1/23/26 14:44, Marc Kleine-Budde wrote:
> On 22.01.2026 13:10:27, Arun Muthusamy wrote:
>> From: Daniel Hellstrom <daniel@gaisler.com>
>>
>> Add clock handling and add error messages for missing 'freq' DT property.
>>
>> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
>> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
>> ---
>> drivers/net/can/grcan.c | 19 ++++++++++++++++---
>> 1 file changed, 16 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
>> index 3b1b09943436..538a9b4f82ab 100644
>> --- a/drivers/net/can/grcan.c
>> +++ b/drivers/net/can/grcan.c
>> @@ -34,7 +34,7 @@
>> #include <linux/spinlock.h>
>> #include <linux/of.h>
>> #include <linux/of_irq.h>
>> -
>> +#include <linux/clk.h>
>> #include <linux/dma-mapping.h>
>>
>> #define DRV_NAME "grcan"
>> @@ -1644,6 +1644,7 @@ static int grcan_probe(struct platform_device *ofdev)
>> {
>> struct device_node *np = ofdev->dev.of_node;
>> struct device_node *sysid_parent;
>> + struct clk *clk;
>> u32 sysid, ambafreq;
>> int irq, err;
>> void __iomem *base;
>> @@ -1663,8 +1664,20 @@ static int grcan_probe(struct platform_device *ofdev)
>>
>> err = of_property_read_u32(np, "freq", &ambafreq);
>> if (err) {
>> - dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n");
>> - goto exit_error;
>> + clk = devm_clk_get(&ofdev->dev, NULL);
>> + if (IS_ERR(clk)) {
>> + dev_err_probe(&ofdev->dev, PTR_ERR(clk),
>> + "Failed both to get \"freq\" property and clock for fallback\n");
>> + err = PTR_ERR(clk);
>> + goto exit_error;
>> + }
> I think devm_clk_get() either returns an error pointer or a valid clock
> pointer.
>
>> + if (clk) {
>> + ambafreq = clk_get_rate(clk);
>> + if (!ambafreq) {
>> + dev_err(&ofdev->dev, "Invalid or Uninitialized clock\n");
>> + return -EINVAL;
>> + }
>> + }
>> }
>>
>> base = devm_platform_ioremap_resource(ofdev, 0);
>>
you are correct, since devm_clk_get() returns either a valid clock pointer or an error pointer, "if (clk)" check is indeed redundant.
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 05/15] can: grcan: Replace bit timing macros with literal values
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (3 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 04/15] can: grcan: Add clock handling Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 06/15] can: grcan: Simplify timing configuration Arun Muthusamy
` (10 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy,
Daniel Hellstrom
Refactor the bit timing constants in grcan_bittiming_const by replacing
macros with literal values.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
---
drivers/net/can/grcan.c | 27 +++++++++------------------
1 file changed, 9 insertions(+), 18 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 538a9b4f82ab..f34ca558fa5d 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -36,6 +36,7 @@
#include <linux/of_irq.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include <linux/bitfield.h>
#define DRV_NAME "grcan"
@@ -93,16 +94,6 @@ struct grcan_registers {
(GRCAN_CONF_BPR | GRCAN_CONF_RSJ | GRCAN_CONF_PS1 \
| GRCAN_CONF_PS2 | GRCAN_CONF_SCALER)
-#define GRCAN_CONF_RSJ_MIN 1
-#define GRCAN_CONF_RSJ_MAX 4
-#define GRCAN_CONF_PS1_MIN 1
-#define GRCAN_CONF_PS1_MAX 15
-#define GRCAN_CONF_PS2_MIN 2
-#define GRCAN_CONF_PS2_MAX 8
-#define GRCAN_CONF_SCALER_MIN 0
-#define GRCAN_CONF_SCALER_MAX 255
-#define GRCAN_CONF_SCALER_INC 1
-
#define GRCAN_CONF_BPR_BIT 8
#define GRCAN_CONF_RSJ_BIT 12
#define GRCAN_CONF_PS1_BIT 20
@@ -392,14 +383,14 @@ static struct grcan_device_config grcan_module_config =
static const struct can_bittiming_const grcan_bittiming_const = {
.name = DRV_NAME,
- .tseg1_min = GRCAN_CONF_PS1_MIN + 1,
- .tseg1_max = GRCAN_CONF_PS1_MAX + 1,
- .tseg2_min = GRCAN_CONF_PS2_MIN,
- .tseg2_max = GRCAN_CONF_PS2_MAX,
- .sjw_max = GRCAN_CONF_RSJ_MAX,
- .brp_min = GRCAN_CONF_SCALER_MIN + 1,
- .brp_max = GRCAN_CONF_SCALER_MAX + 1,
- .brp_inc = GRCAN_CONF_SCALER_INC,
+ .tseg1_min = 2,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
};
static int grcan_set_bittiming(struct net_device *dev)
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 06/15] can: grcan: Simplify timing configuration
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (4 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 05/15] can: grcan: Replace bit timing macros with literal values Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 07/15] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
` (9 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy,
Daniel Hellstrom
Remove redundant error checks and use FIELD_PREP for bit timing
assignments to simplify the timing configuration
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
---
drivers/net/can/grcan.c | 41 +++++++++++++----------------------------
1 file changed, 13 insertions(+), 28 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index f34ca558fa5d..5a63d0a0365f 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -396,41 +396,26 @@ static const struct can_bittiming_const grcan_bittiming_const = {
static int grcan_set_bittiming(struct net_device *dev)
{
struct grcan_priv *priv = netdev_priv(dev);
- struct grcan_registers __iomem *regs = priv->regs;
- struct can_bittiming *bt = &priv->can.bittiming;
- u32 timing = 0;
+ struct grcan_registers __iomem *regs;
int bpr, rsj, ps1, ps2, scaler;
+ struct can_bittiming *bt;
+ u32 timing = 0;
- /* Should never happen - function will not be called when
- * device is up
- */
- if (grcan_read_bits(®s->ctrl, GRCAN_CTRL_ENABLE))
- return -EBUSY;
+ regs = priv->regs;
+ bt = &priv->can.bittiming;
bpr = 0; /* Note bpr and brp are different concepts */
rsj = bt->sjw;
ps1 = (bt->prop_seg + bt->phase_seg1) - 1; /* tseg1 - 1 */
ps2 = bt->phase_seg2;
- scaler = (bt->brp - 1);
- netdev_dbg(dev, "Request for BPR=%d, RSJ=%d, PS1=%d, PS2=%d, SCALER=%d",
- bpr, rsj, ps1, ps2, scaler);
- if (!(ps1 > ps2)) {
- netdev_err(dev, "PS1 > PS2 must hold: PS1=%d, PS2=%d\n",
- ps1, ps2);
- return -EINVAL;
- }
- if (!(ps2 >= rsj)) {
- netdev_err(dev, "PS2 >= RSJ must hold: PS2=%d, RSJ=%d\n",
- ps2, rsj);
- return -EINVAL;
- }
-
- timing |= (bpr << GRCAN_CONF_BPR_BIT) & GRCAN_CONF_BPR;
- timing |= (rsj << GRCAN_CONF_RSJ_BIT) & GRCAN_CONF_RSJ;
- timing |= (ps1 << GRCAN_CONF_PS1_BIT) & GRCAN_CONF_PS1;
- timing |= (ps2 << GRCAN_CONF_PS2_BIT) & GRCAN_CONF_PS2;
- timing |= (scaler << GRCAN_CONF_SCALER_BIT) & GRCAN_CONF_SCALER;
- netdev_info(dev, "setting timing=0x%x\n", timing);
+ scaler = bt->brp - 1;
+
+ timing |= FIELD_PREP(GRCAN_CONF_BPR, bpr);
+ timing |= FIELD_PREP(GRCAN_CONF_RSJ, rsj);
+ timing |= FIELD_PREP(GRCAN_CONF_PS1, ps1);
+ timing |= FIELD_PREP(GRCAN_CONF_PS2, ps2);
+ timing |= FIELD_PREP(GRCAN_CONF_SCALER, scaler);
+ netdev_dbg(dev, "setting timing=0x%x\n", timing);
grcan_write_bits(®s->conf, timing, GRCAN_CONF_TIMING);
return 0;
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 07/15] can: grcan: add FD capability detection and nominal bit-timing
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (5 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 06/15] can: grcan: Simplify timing configuration Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-23 13:52 ` Marc Kleine-Budde
2026-01-22 12:10 ` [PATCH v3 08/15] can: grcan: optimize DMA by 32-bit accesses Arun Muthusamy
` (8 subsequent siblings)
15 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy,
Daniel Hellstrom
Add capability for the driver to detect CAN FD support
and adjust accordingly. Introduce structures and functions
for setting nominal bit-timing for standard CAN FD.
The `grcan_hwcap` structure defines hardware capabilities like
CAN FD support and baud-rate options. Additionally, improved
device tree compatibility by updating the `of_device_id` table
for better matching of GRCAN and GRCANFD devices. Also update
Kconfig to mention GRCANFD support.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
---
drivers/net/can/Kconfig | 6 +-
drivers/net/can/grcan.c | 142 +++++++++++++++++++++++++++++++++++-----
2 files changed, 130 insertions(+), 18 deletions(-)
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index d43d56694667..96f61b40a898 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -133,10 +133,12 @@ config CAN_FLEXCAN
Say Y here if you want to support for Freescale FlexCAN.
config CAN_GRCAN
- tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
+ tristate "Aeroflex Gaisler GRCAN(FD) and GRHCAN CAN devices"
depends on OF && HAS_DMA && HAS_IOMEM
help
- Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
+ Say Y here if you want to use Aeroflex Gaisler GRCAN or GRCANFD
+ or GRHCAN.
+
Note that the driver supports little endian, even though little
endian syntheses of the cores would need some modifications on
the hardware level to work.
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 5a63d0a0365f..5d09f61a153c 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -33,6 +33,7 @@
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
@@ -51,7 +52,11 @@ struct grcan_registers {
u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
u32 smask; /* 0x18 - CanMASK */
u32 scode; /* 0x1c - CanCODE */
- u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x100)];
+ u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x40)];
+ u32 nbtr; /* 0x40 */
+ u32 fdbtr; /* 0x44 */
+ u32 tdelay; /* 0x48 */
+ u32 __reserved2_[GRCAN_RESERVE_SIZE(0x48, 0x100)];
u32 pimsr; /* 0x100 */
u32 pimr; /* 0x104 */
u32 pisr; /* 0x108 */
@@ -203,6 +208,39 @@ struct grcan_registers {
#error "Invalid default buffer size"
#endif
+#define GRCANFD_NBTR_SCALER GENMASK(23, 16)
+#define GRCANFD_NBTR_PS1 GENMASK(17, 10)
+#define GRCANFD_NBTR_PS2 GENMASK(9, 5)
+#define GRCANFD_NBTR_SJW GENMASK(4, 0)
+#define GRCANFD_NBTR_TIMING \
+ (GRCANFD_NBTR_SCALER | GRCANFD_NBTR_PS1 | GRCANFD_NBTR_PS2 | \
+ GRCANFD_NBTR_SJW)
+
+#define GRCANFD_FDBTR_SCALER 0x00ff0000
+#define GRCANFD_FDBTR_PS1 0x00003c00
+#define GRCANFD_FDBTR_PS2 0x000001e0
+#define GRCANFD_FDBTR_SJW 0x0000000f
+#define GRCANFD_FDBTR_TIMING \
+ (GRCANFD_FDBTR_SCALER | GRCANFD_FDBTR_PS1 | GRCANFD_FDBTR_PS2 | \
+ GRCANFD_FDBTR_SJW)
+
+#define GRCANFD_FDBTR_SCALER_BIT 16
+#define GRCANFD_FDBTR_PS1_BIT 10
+#define GRCANFD_FDBTR_PS2_BIT 5
+#define GRCANFD_FDBTR_SJW_BIT 0
+
+/* Hardware capabilities */
+struct grcan_hwcap {
+ /* CAN-FD capable, indicates GRCANFD IP.
+ * The GRCANFD has different baud-rate registers and extended DMA
+ * format to also describe FD-frames.
+ */
+ const struct can_bittiming_const *bt_const;
+ int (*set_bittiming)(struct net_device *dev);
+ bool txbug_possible;
+ bool fd;
+};
+
struct grcan_dma_buffer {
size_t size;
void *buf;
@@ -245,6 +283,7 @@ struct grcan_priv {
struct napi_struct napi;
struct grcan_registers __iomem *regs; /* ioremap'ed registers */
+ const struct grcan_hwcap *hwcap;
struct grcan_device_config config;
struct grcan_dma dma;
@@ -295,6 +334,7 @@ struct grcan_priv {
*/
bool resetting;
bool closing;
+
};
/* Wait time for a short wait for ongoing to clear */
@@ -393,6 +433,19 @@ static const struct can_bittiming_const grcan_bittiming_const = {
.brp_inc = 1,
};
+/* GRCANFD nominal boundaries for baud-rate parameters */
+static const struct can_bittiming_const grcanfd_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 2,
+ .tseg1_max = 63,
+ .tseg2_min = 2,
+ .tseg2_max = 16,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+};
+
static int grcan_set_bittiming(struct net_device *dev)
{
struct grcan_priv *priv = netdev_priv(dev);
@@ -421,6 +474,32 @@ static int grcan_set_bittiming(struct net_device *dev)
return 0;
}
+static int grcanfd_set_bittiming(struct net_device *dev)
+{
+ struct grcan_priv *priv = netdev_priv(dev);
+ struct grcan_registers __iomem *regs;
+ int sjw, ps1, ps2, scaler;
+ struct can_bittiming *bt;
+ u32 timing = 0;
+
+ regs = priv->regs;
+ bt = &priv->can.bittiming;
+
+ sjw = bt->sjw;
+ ps1 = (bt->prop_seg + bt->phase_seg1);
+ ps2 = bt->phase_seg2;
+ scaler = bt->brp - 1;
+
+ timing |= FIELD_PREP(GRCANFD_NBTR_SJW, sjw);
+ timing |= FIELD_PREP(GRCANFD_NBTR_PS1, ps1);
+ timing |= FIELD_PREP(GRCANFD_NBTR_PS2, ps2);
+ timing |= FIELD_PREP(GRCANFD_NBTR_SCALER, scaler);
+ netdev_info(dev, "setting timing=0x%x\n", timing);
+ grcan_write_bits(®s->nbtr, timing, GRCANFD_NBTR_TIMING);
+
+ return 0;
+}
+
static int grcan_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
@@ -1545,7 +1624,8 @@ static const struct ethtool_ops grcan_ethtool_ops = {
static int grcan_setup_netdev(struct platform_device *ofdev,
void __iomem *base,
- int irq, u32 ambafreq, bool txbug)
+ int irq, u32 ambafreq, bool txbug,
+ const struct grcan_hwcap *hwcap)
{
struct net_device *dev;
struct grcan_priv *priv;
@@ -1568,14 +1648,14 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
priv->dev = dev;
priv->ofdev_dev = &ofdev->dev;
priv->regs = base;
- priv->can.bittiming_const = &grcan_bittiming_const;
- priv->can.do_set_bittiming = grcan_set_bittiming;
+ priv->can.bittiming_const = hwcap->bt_const;
priv->can.do_set_mode = grcan_set_mode;
priv->can.do_get_berr_counter = grcan_get_berr_counter;
priv->can.clock.freq = ambafreq;
priv->can.ctrlmode_supported =
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
priv->need_txbug_workaround = txbug;
+ priv->hwcap = hwcap;
/* Discover if triple sampling is supported by hardware */
regs = priv->regs;
@@ -1620,22 +1700,33 @@ static int grcan_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
struct device_node *sysid_parent;
+ const struct grcan_hwcap *hwcap;
struct clk *clk;
u32 sysid, ambafreq;
int irq, err;
void __iomem *base;
bool txbug = true;
+ hwcap = device_get_match_data(&ofdev->dev);
+ if (!hwcap) {
+ dev_err(&ofdev->dev, "Platform data not provided!\n");
+ return -ENODEV;
+ }
+
/* Compare GRLIB version number with the first that does not
* have the tx bug (see start_xmit)
*/
- sysid_parent = of_find_node_by_path("/ambapp0");
- if (sysid_parent) {
- err = of_property_read_u32(sysid_parent, "systemid", &sysid);
- if (!err && ((sysid & GRLIB_VERSION_MASK) >=
- GRCAN_TXBUG_SAFE_GRLIB_VERSION))
- txbug = false;
- of_node_put(sysid_parent);
+ if (!hwcap->txbug_possible) {
+ txbug = false;
+ } else {
+ sysid_parent = of_find_node_by_path("/ambapp0");
+ if (sysid_parent) {
+ err = of_property_read_u32(sysid_parent, "systemid", &sysid);
+ if (!err && ((sysid & GRLIB_VERSION_MASK) >=
+ GRCAN_TXBUG_SAFE_GRLIB_VERSION))
+ txbug = false;
+ of_node_put(sysid_parent);
+ }
}
err = of_property_read_u32(np, "freq", &ambafreq);
@@ -1671,7 +1762,7 @@ static int grcan_probe(struct platform_device *ofdev)
grcan_sanitize_module_config(ofdev);
- err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug);
+ err = grcan_setup_netdev(ofdev, base, irq, ambafreq, txbug, hwcap);
if (err)
goto exit_dispose_irq;
@@ -1698,11 +1789,30 @@ static void grcan_remove(struct platform_device *ofdev)
free_candev(dev);
}
+static const struct grcan_hwcap grcan_hwcap = {
+ .fd = false,
+ .txbug_possible = true,
+ .bt_const = &grcan_bittiming_const,
+ .set_bittiming = grcan_set_bittiming,
+};
+
+static const struct grcan_hwcap grcanfd_hwcap = {
+ .fd = true,
+ .txbug_possible = false,
+ .bt_const = &grcanfd_bittiming_const,
+ .set_bittiming = grcanfd_set_bittiming,
+};
+
static const struct of_device_id grcan_match[] = {
- {.name = "GAISLER_GRCAN"},
- {.name = "01_03d"},
- {.name = "GAISLER_GRHCAN"},
- {.name = "01_034"},
+ {.name = "GAISLER_GRCAN", .data = &grcan_hwcap},
+ {.name = "01_03d", .data = &grcan_hwcap},
+ {.name = "GAISLER_GRHCAN", .data = &grcan_hwcap},
+ {.name = "01_034", .data = &grcan_hwcap},
+ {.compatible = "gaisler,grcan", .data = &grcan_hwcap},
+ /* GRCANFD */
+ {.compatible = "gaisler,grcanfd", .data = &grcanfd_hwcap},
+ {.name = "GAISLER_GRCANFD", .data = &grcanfd_hwcap},
+ {.name = "01_0b5", .data = &grcanfd_hwcap},
{},
};
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v3 07/15] can: grcan: add FD capability detection and nominal bit-timing
2026-01-22 12:10 ` [PATCH v3 07/15] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
@ 2026-01-23 13:52 ` Marc Kleine-Budde
0 siblings, 0 replies; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 13:52 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can, Daniel Hellstrom
[-- Attachment #1: Type: text/plain, Size: 8614 bytes --]
On 22.01.2026 13:10:30, Arun Muthusamy wrote:
> Add capability for the driver to detect CAN FD support
> and adjust accordingly. Introduce structures and functions
> for setting nominal bit-timing for standard CAN FD.
> The `grcan_hwcap` structure defines hardware capabilities like
> CAN FD support and baud-rate options. Additionally, improved
> device tree compatibility by updating the `of_device_id` table
> for better matching of GRCAN and GRCANFD devices. Also update
> Kconfig to mention GRCANFD support.
>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
> ---
> drivers/net/can/Kconfig | 6 +-
> drivers/net/can/grcan.c | 142 +++++++++++++++++++++++++++++++++++-----
> 2 files changed, 130 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index d43d56694667..96f61b40a898 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -133,10 +133,12 @@ config CAN_FLEXCAN
> Say Y here if you want to support for Freescale FlexCAN.
>
> config CAN_GRCAN
> - tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
> + tristate "Aeroflex Gaisler GRCAN(FD) and GRHCAN CAN devices"
> depends on OF && HAS_DMA && HAS_IOMEM
> help
> - Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
> + Say Y here if you want to use Aeroflex Gaisler GRCAN or GRCANFD
> + or GRHCAN.
> +
> Note that the driver supports little endian, even though little
> endian syntheses of the cores would need some modifications on
> the hardware level to work.
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index 5a63d0a0365f..5d09f61a153c 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -33,6 +33,7 @@
> #include <linux/platform_device.h>
> #include <linux/spinlock.h>
> #include <linux/of.h>
> +#include <linux/of_device.h>
> #include <linux/of_irq.h>
> #include <linux/clk.h>
> #include <linux/dma-mapping.h>
> @@ -51,7 +52,11 @@ struct grcan_registers {
> u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
> u32 smask; /* 0x18 - CanMASK */
> u32 scode; /* 0x1c - CanCODE */
> - u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x100)];
> + u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x40)];
> + u32 nbtr; /* 0x40 */
> + u32 fdbtr; /* 0x44 */
> + u32 tdelay; /* 0x48 */
> + u32 __reserved2_[GRCAN_RESERVE_SIZE(0x48, 0x100)];
> u32 pimsr; /* 0x100 */
> u32 pimr; /* 0x104 */
> u32 pisr; /* 0x108 */
> @@ -203,6 +208,39 @@ struct grcan_registers {
> #error "Invalid default buffer size"
> #endif
>
> +#define GRCANFD_NBTR_SCALER GENMASK(23, 16)
> +#define GRCANFD_NBTR_PS1 GENMASK(17, 10)
> +#define GRCANFD_NBTR_PS2 GENMASK(9, 5)
> +#define GRCANFD_NBTR_SJW GENMASK(4, 0)
> +#define GRCANFD_NBTR_TIMING \
> + (GRCANFD_NBTR_SCALER | GRCANFD_NBTR_PS1 | GRCANFD_NBTR_PS2 | \
> + GRCANFD_NBTR_SJW)
> +
> +#define GRCANFD_FDBTR_SCALER 0x00ff0000
> +#define GRCANFD_FDBTR_PS1 0x00003c00
> +#define GRCANFD_FDBTR_PS2 0x000001e0
> +#define GRCANFD_FDBTR_SJW 0x0000000f
> +#define GRCANFD_FDBTR_TIMING \
> + (GRCANFD_FDBTR_SCALER | GRCANFD_FDBTR_PS1 | GRCANFD_FDBTR_PS2 | \
> + GRCANFD_FDBTR_SJW)
> +
> +#define GRCANFD_FDBTR_SCALER_BIT 16
> +#define GRCANFD_FDBTR_PS1_BIT 10
> +#define GRCANFD_FDBTR_PS2_BIT 5
> +#define GRCANFD_FDBTR_SJW_BIT 0
> +
> +/* Hardware capabilities */
> +struct grcan_hwcap {
> + /* CAN-FD capable, indicates GRCANFD IP.
> + * The GRCANFD has different baud-rate registers and extended DMA
> + * format to also describe FD-frames.
> + */
> + const struct can_bittiming_const *bt_const;
> + int (*set_bittiming)(struct net_device *dev);
> + bool txbug_possible;
> + bool fd;
> +};
> +
> struct grcan_dma_buffer {
> size_t size;
> void *buf;
> @@ -245,6 +283,7 @@ struct grcan_priv {
> struct napi_struct napi;
>
> struct grcan_registers __iomem *regs; /* ioremap'ed registers */
> + const struct grcan_hwcap *hwcap;
> struct grcan_device_config config;
> struct grcan_dma dma;
>
> @@ -295,6 +334,7 @@ struct grcan_priv {
> */
> bool resetting;
> bool closing;
> +
Please remove this change
> };
>
> /* Wait time for a short wait for ongoing to clear */
> @@ -393,6 +433,19 @@ static const struct can_bittiming_const grcan_bittiming_const = {
> .brp_inc = 1,
> };
>
> +/* GRCANFD nominal boundaries for baud-rate parameters */
> +static const struct can_bittiming_const grcanfd_bittiming_const = {
> + .name = DRV_NAME,
> + .tseg1_min = 2,
> + .tseg1_max = 63,
> + .tseg2_min = 2,
> + .tseg2_max = 16,
> + .sjw_max = 16,
> + .brp_min = 1,
> + .brp_max = 256,
> + .brp_inc = 1,
> +};
> +
> static int grcan_set_bittiming(struct net_device *dev)
> {
> struct grcan_priv *priv = netdev_priv(dev);
> @@ -421,6 +474,32 @@ static int grcan_set_bittiming(struct net_device *dev)
> return 0;
> }
>
> +static int grcanfd_set_bittiming(struct net_device *dev)
> +{
> + struct grcan_priv *priv = netdev_priv(dev);
> + struct grcan_registers __iomem *regs;
> + int sjw, ps1, ps2, scaler;
> + struct can_bittiming *bt;
> + u32 timing = 0;
> +
> + regs = priv->regs;
> + bt = &priv->can.bittiming;
> +
> + sjw = bt->sjw;
> + ps1 = (bt->prop_seg + bt->phase_seg1);
> + ps2 = bt->phase_seg2;
> + scaler = bt->brp - 1;
> +
> + timing |= FIELD_PREP(GRCANFD_NBTR_SJW, sjw);
> + timing |= FIELD_PREP(GRCANFD_NBTR_PS1, ps1);
> + timing |= FIELD_PREP(GRCANFD_NBTR_PS2, ps2);
> + timing |= FIELD_PREP(GRCANFD_NBTR_SCALER, scaler);
> + netdev_info(dev, "setting timing=0x%x\n", timing);
make it debug or remove
> + grcan_write_bits(®s->nbtr, timing, GRCANFD_NBTR_TIMING);
> +
> + return 0;
> +}
> +
> static int grcan_get_berr_counter(const struct net_device *dev,
> struct can_berr_counter *bec)
> {
> @@ -1545,7 +1624,8 @@ static const struct ethtool_ops grcan_ethtool_ops = {
>
> static int grcan_setup_netdev(struct platform_device *ofdev,
> void __iomem *base,
> - int irq, u32 ambafreq, bool txbug)
> + int irq, u32 ambafreq, bool txbug,
> + const struct grcan_hwcap *hwcap)
> {
> struct net_device *dev;
> struct grcan_priv *priv;
> @@ -1568,14 +1648,14 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
> priv->dev = dev;
> priv->ofdev_dev = &ofdev->dev;
> priv->regs = base;
> - priv->can.bittiming_const = &grcan_bittiming_const;
> - priv->can.do_set_bittiming = grcan_set_bittiming;
> + priv->can.bittiming_const = hwcap->bt_const;
> priv->can.do_set_mode = grcan_set_mode;
> priv->can.do_get_berr_counter = grcan_get_berr_counter;
> priv->can.clock.freq = ambafreq;
> priv->can.ctrlmode_supported =
> CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
> priv->need_txbug_workaround = txbug;
> + priv->hwcap = hwcap;
>
> /* Discover if triple sampling is supported by hardware */
> regs = priv->regs;
> @@ -1620,22 +1700,33 @@ static int grcan_probe(struct platform_device *ofdev)
> {
> struct device_node *np = ofdev->dev.of_node;
> struct device_node *sysid_parent;
> + const struct grcan_hwcap *hwcap;
> struct clk *clk;
> u32 sysid, ambafreq;
> int irq, err;
> void __iomem *base;
> bool txbug = true;
>
> + hwcap = device_get_match_data(&ofdev->dev);
> + if (!hwcap) {
> + dev_err(&ofdev->dev, "Platform data not provided!\n");
> + return -ENODEV;
> + }
> +
All entries in grcan_match have a corresponding data member, so I think
you can remove this check.
[...]
> static const struct of_device_id grcan_match[] = {
> - {.name = "GAISLER_GRCAN"},
> - {.name = "01_03d"},
> - {.name = "GAISLER_GRHCAN"},
> - {.name = "01_034"},
> + {.name = "GAISLER_GRCAN", .data = &grcan_hwcap},
> + {.name = "01_03d", .data = &grcan_hwcap},
> + {.name = "GAISLER_GRHCAN", .data = &grcan_hwcap},
> + {.name = "01_034", .data = &grcan_hwcap},
> + {.compatible = "gaisler,grcan", .data = &grcan_hwcap},
> + /* GRCANFD */
> + {.compatible = "gaisler,grcanfd", .data = &grcanfd_hwcap},
> + {.name = "GAISLER_GRCANFD", .data = &grcanfd_hwcap},
> + {.name = "01_0b5", .data = &grcanfd_hwcap},
> {},
> };
>
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 08/15] can: grcan: optimize DMA by 32-bit accesses
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (6 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 07/15] can: grcan: add FD capability detection and nominal bit-timing Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 09/15] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit Arun Muthusamy
` (7 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
Arun Muthusamy
From: Daniel Hellstrom <daniel@gaisler.com>
Optimizes DMA transfers in the GRCAN driver by reorganizing
data handling to use 32-bit accesses instead of individual
byte accesses.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 26 ++++++++++----------------
1 file changed, 10 insertions(+), 16 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 5d09f61a153c..e2415529db45 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -194,9 +194,6 @@ struct grcan_registers {
#define GRCAN_MSG_OFF 0x00000002
#define GRCAN_MSG_PASS 0x00000001
-#define GRCAN_MSG_DATA_SLOT_INDEX(i) (2 + (i) / 4)
-#define GRCAN_MSG_DATA_SHIFT(i) ((3 - (i) % 4) * 8)
-
#define GRCAN_BUFFER_ALIGNMENT 1024
#define GRCAN_DEFAULT_BUFFER_SIZE 1024
#define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
@@ -1218,7 +1215,7 @@ static int grcan_receive(struct net_device *dev, int budget)
struct sk_buff *skb;
u32 wr, rd, startrd;
u32 *slot;
- u32 i, rtr, eff, j, shift;
+ u32 rtr, eff;
int work_done = 0;
rd = grcan_read_reg(®s->rxrd);
@@ -1254,11 +1251,10 @@ static int grcan_receive(struct net_device *dev, int budget)
if (rtr) {
cf->can_id |= CAN_RTR_FLAG;
} else {
- for (i = 0; i < cf->len; i++) {
- j = GRCAN_MSG_DATA_SLOT_INDEX(i);
- shift = GRCAN_MSG_DATA_SHIFT(i);
- cf->data[i] = (u8)(slot[j] >> shift);
- }
+ if (cf->can_dlc > 0)
+ memcpy(cf->data, &slot[2], sizeof(u32));
+ if (cf->can_dlc > 4)
+ memcpy(cf->data + 4, &slot[3], sizeof(u32));
stats->rx_bytes += cf->len;
}
@@ -1397,8 +1393,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
u32 id, txwr, txrd, space, txctrl;
int slotindex;
u32 *slot;
- u32 i, rtr, eff, dlc, tmp, err;
- int j, shift;
+ u32 rtr, eff, dlc, tmp, err;
unsigned long flags;
u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
@@ -1451,11 +1446,10 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
slot[2] = 0;
slot[3] = 0;
- for (i = 0; i < dlc; i++) {
- j = GRCAN_MSG_DATA_SLOT_INDEX(i);
- shift = GRCAN_MSG_DATA_SHIFT(i);
- slot[j] |= cf->data[i] << shift;
- }
+ if (dlc > 0)
+ memcpy(&slot[2], cf->data, sizeof(u32));
+ if (dlc > 4)
+ memcpy(&slot[3], cf->data + 4, sizeof(u32));
/* Checking that channel has not been disabled. These cases
* should never happen
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 09/15] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (7 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 08/15] can: grcan: optimize DMA by 32-bit accesses Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 10/15] can: grcan: Add saving and restoring of CAN FD baud-rate registers Arun Muthusamy
` (6 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
Arun Muthusamy
From: Daniel Hellstrom <daniel@gaisler.com>
Sets the DMA mask for GRCAN and GRCANFD devices to 32-bit.
Setting the DMA mask and coherent DMA mask to 32-bit ensures proper
memory addressing during DMA operations
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index e2415529db45..a2a5a5c868ff 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1747,6 +1747,13 @@ static int grcan_probe(struct platform_device *ofdev)
goto exit_error;
}
+ /* On 64-bit systems.. GRCAN and GRCANFD can only address 32-bit */
+ err = dma_set_mask_and_coherent(&ofdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err_probe(&ofdev->dev, err, "No usable DMA configuration.\n");
+ goto exit_error;
+ }
+
irq = irq_of_parse_and_map(np, GRCAN_IRQIX_IRQ);
if (!irq) {
dev_err(&ofdev->dev, "no irq found\n");
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 10/15] can: grcan: Add saving and restoring of CAN FD baud-rate registers
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (8 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 09/15] can: grcan: set DMA mask for GRCAN and GRCANFD to 32-bit Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-23 14:00 ` Marc Kleine-Budde
2026-01-22 12:10 ` [PATCH v3 11/15] can: grcan: Reserve space between cap and next register to align with address layout Arun Muthusamy
` (5 subsequent siblings)
15 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
Arun Muthusamy
From: Daniel Hellstrom <daniel@gaisler.com>
While reset the GRCAN baud-rates are preserved, since GRCANFD has the
baud-rate in different registers we need to add saving of those
registers too.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index a2a5a5c868ff..0ee6e9bfbe7f 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -517,15 +517,27 @@ static void grcan_reset(struct net_device *dev)
struct grcan_priv *priv = netdev_priv(dev);
struct grcan_registers __iomem *regs = priv->regs;
u32 config = grcan_read_reg(®s->conf);
+ u32 nbtr, fdbtr;
+
+ if (priv->hwcap->fd) {
+ nbtr = grcan_read_reg(®s->nbtr);
+ fdbtr = grcan_read_reg(®s->fdbtr);
+ }
grcan_set_bits(®s->ctrl, GRCAN_CTRL_RESET);
grcan_write_reg(®s->conf, config);
+ if (priv->hwcap->fd) {
+ grcan_write_reg(®s->nbtr, nbtr);
+ grcan_write_reg(®s->fdbtr, fdbtr);
+ }
priv->eskbp = grcan_read_reg(®s->txrd);
priv->can.state = CAN_STATE_STOPPED;
/* Turn off hardware filtering - regs->rxcode set to 0 by reset */
grcan_write_reg(®s->rxmask, 0);
+
+ priv->hwcap->set_bittiming(dev);
}
/* stop device without changing any configurations */
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v3 10/15] can: grcan: Add saving and restoring of CAN FD baud-rate registers
2026-01-22 12:10 ` [PATCH v3 10/15] can: grcan: Add saving and restoring of CAN FD baud-rate registers Arun Muthusamy
@ 2026-01-23 14:00 ` Marc Kleine-Budde
2026-01-28 8:35 ` Arun Muthusamy
0 siblings, 1 reply; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 14:00 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can, Daniel Hellstrom
[-- Attachment #1: Type: text/plain, Size: 1911 bytes --]
On 22.01.2026 13:10:33, Arun Muthusamy wrote:
> From: Daniel Hellstrom <daniel@gaisler.com>
>
> While reset the GRCAN baud-rates are preserved, since GRCANFD has the
> baud-rate in different registers we need to add saving of those
> registers too.
>
> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
> drivers/net/can/grcan.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index a2a5a5c868ff..0ee6e9bfbe7f 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -517,15 +517,27 @@ static void grcan_reset(struct net_device *dev)
> struct grcan_priv *priv = netdev_priv(dev);
> struct grcan_registers __iomem *regs = priv->regs;
> u32 config = grcan_read_reg(®s->conf);
> + u32 nbtr, fdbtr;
> +
> + if (priv->hwcap->fd) {
> + nbtr = grcan_read_reg(®s->nbtr);
Why do you save nbtr....
> + fdbtr = grcan_read_reg(®s->fdbtr);
Who writes fdbtr in the first place?
> + }
>
> grcan_set_bits(®s->ctrl, GRCAN_CTRL_RESET);
> grcan_write_reg(®s->conf, config);
> + if (priv->hwcap->fd) {
> + grcan_write_reg(®s->nbtr, nbtr);
> + grcan_write_reg(®s->fdbtr, fdbtr);
> + }
>
> priv->eskbp = grcan_read_reg(®s->txrd);
> priv->can.state = CAN_STATE_STOPPED;
>
> /* Turn off hardware filtering - regs->rxcode set to 0 by reset */
> grcan_write_reg(®s->rxmask, 0);
> +
> + priv->hwcap->set_bittiming(dev);
...if you configure the bit timing again, wich writes nbtr?
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 10/15] can: grcan: Add saving and restoring of CAN FD baud-rate registers
2026-01-23 14:00 ` Marc Kleine-Budde
@ 2026-01-28 8:35 ` Arun Muthusamy
0 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-28 8:35 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can, Daniel Hellstrom
On 1/23/26 15:00, Marc Kleine-Budde wrote:
> On 22.01.2026 13:10:33, Arun Muthusamy wrote:
>> From: Daniel Hellstrom <daniel@gaisler.com>
>>
>> While reset the GRCAN baud-rates are preserved, since GRCANFD has the
>> baud-rate in different registers we need to add saving of those
>> registers too.
>>
>> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
>> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
>> ---
>> drivers/net/can/grcan.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
>> index a2a5a5c868ff..0ee6e9bfbe7f 100644
>> --- a/drivers/net/can/grcan.c
>> +++ b/drivers/net/can/grcan.c
>> @@ -517,15 +517,27 @@ static void grcan_reset(struct net_device *dev)
>> struct grcan_priv *priv = netdev_priv(dev);
>> struct grcan_registers __iomem *regs = priv->regs;
>> u32 config = grcan_read_reg(®s->conf);
>> + u32 nbtr, fdbtr;
>> +
>> + if (priv->hwcap->fd) {
>> + nbtr = grcan_read_reg(®s->nbtr);
> Why do you save nbtr....
You’re right. nbtr is reprogrammed by set_bittiming() after reset, so saving/restoring nbtr is redundant.
>> + fdbtr = grcan_read_reg(®s->fdbtr);
> Who writes fdbtr in the first place?
These configuration values are embedded into the CAN controller IP at SoC design time(cfg record).
From the driver's standpoint, saving/restoring fdbtr also redundant.
--
BR,
Arun Muthusamy
Software Engineer
Frontgrade Gaisler
T : +46 (0) 700 558 528
arun.muthusamy@gaisler.com
Frontgrade Gaisler AB, Kungsgatan 12, SE-411 19 GÖTEBORG, Sweden.
+46 (0) 31 775 8650, www.gaisler.com
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 11/15] can: grcan: Reserve space between cap and next register to align with address layout
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (9 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 10/15] can: grcan: Add saving and restoring of CAN FD baud-rate registers Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 12/15] can: grcan: Advertise CANFD capability Arun Muthusamy
` (4 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Daniel Hellstrom,
Arun Muthusamy
From: Daniel Hellstrom <daniel@gaisler.com>
Reserves space between the capability register and the next register
within the GRCAN driver to align with the hardware address layout.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 0ee6e9bfbe7f..e99a8c2bffc6 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -49,7 +49,8 @@ struct grcan_registers {
u32 conf; /* 0x00 */
u32 stat; /* 0x04 */
u32 ctrl; /* 0x08 */
- u32 __reserved1[GRCAN_RESERVE_SIZE(0x08, 0x18)];
+ u32 cap; /* 0x0c */
+ u32 __reserved1[GRCAN_RESERVE_SIZE(0x0c, 0x18)];
u32 smask; /* 0x18 - CanMASK */
u32 scode; /* 0x1c - CanCODE */
u32 __reserved2[GRCAN_RESERVE_SIZE(0x1c, 0x40)];
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 12/15] can: grcan: Advertise CANFD capability
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (10 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 11/15] can: grcan: Reserve space between cap and next register to align with address layout Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN Arun Muthusamy
` (3 subsequent siblings)
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy
Advertise CANFD capability for GRCANFD hardware by enabling
CAN_CTRLMODE_FD flag and providing CANFD timing operations.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index e99a8c2bffc6..9fc18064fab1 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1656,11 +1656,14 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
priv->ofdev_dev = &ofdev->dev;
priv->regs = base;
priv->can.bittiming_const = hwcap->bt_const;
+ priv->can.fd.data_bittiming_const = hwcap->bt_const;
priv->can.do_set_mode = grcan_set_mode;
priv->can.do_get_berr_counter = grcan_get_berr_counter;
priv->can.clock.freq = ambafreq;
priv->can.ctrlmode_supported =
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
+ if (hwcap->fd)
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
priv->need_txbug_workaround = txbug;
priv->hwcap = hwcap;
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (11 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 12/15] can: grcan: Advertise CANFD capability Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-23 14:25 ` Marc Kleine-Budde
2026-01-22 12:10 ` [PATCH v3 14/15] can: grcan: Add CANFD RX " Arun Muthusamy
` (2 subsequent siblings)
15 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy
Include CANFD TX support with the legacy CAN support, enabling
support for extended data payloads to provide higher bit rates.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 102 +++++++++++++++++++++++++++++-----------
1 file changed, 74 insertions(+), 28 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 9fc18064fab1..508ad5320cff 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -174,6 +174,7 @@ struct grcan_registers {
#define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
#define GRCAN_MSG_SIZE 16
+#define GRCAN_CLASSIC_DATA_SIZE 8
#define GRCAN_MSG_IDE 0x80000000
#define GRCAN_MSG_RTR 0x40000000
@@ -195,6 +196,10 @@ struct grcan_registers {
#define GRCAN_MSG_OFF 0x00000002
#define GRCAN_MSG_PASS 0x00000001
+#define GRCAN_MSG_EID_MASK GENMASK(28, 0)
+#define GRCAN_MSG_BID_MASK GENMASK(28, 18)
+#define GRCAN_MSG_DLC_MASK GENMASK(31, 28)
+
#define GRCAN_BUFFER_ALIGNMENT 1024
#define GRCAN_DEFAULT_BUFFER_SIZE 1024
#define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
@@ -227,6 +232,9 @@ struct grcan_registers {
#define GRCANFD_FDBTR_PS2_BIT 5
#define GRCANFD_FDBTR_SJW_BIT 0
+#define GRCAN_TX_BRS BIT(25)
+#define GRCAN_TX_FDF BIT(26)
+
/* Hardware capabilities */
struct grcan_hwcap {
/* CAN-FD capable, indicates GRCANFD IP.
@@ -1218,6 +1226,13 @@ static void grcan_transmit_catch_up(struct net_device *dev)
spin_unlock_irqrestore(&priv->lock, flags);
}
+static int grcan_numbds(int len)
+{
+ if (len <= GRCAN_CLASSIC_DATA_SIZE)
+ return 1;
+ return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
+}
+
static int grcan_receive(struct net_device *dev, int budget)
{
struct grcan_priv *priv = netdev_priv(dev);
@@ -1400,15 +1415,22 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct grcan_priv *priv = netdev_priv(dev);
- struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_registers __iomem *regs;
+ u32 eff, rtr, dlc, tmp, err, can_id;
struct grcan_dma *dma = &priv->dma;
- struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 bds, copy_len, payload_offset;
u32 id, txwr, txrd, space, txctrl;
- int slotindex;
- u32 *slot;
- u32 rtr, eff, dlc, tmp, err;
+ struct canfd_frame *cfd;
+ struct can_frame *cf;
unsigned long flags;
- u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
+ u32 oneshotmode;
+ u8 *payload;
+ u32 *slot;
+ u8 len;
+ int i;
+
+ regs = priv->regs;
+ oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
if (can_dev_dropped_skb(dev, skb))
return NETDEV_TX_OK;
@@ -1419,6 +1441,18 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
return NETDEV_TX_BUSY;
+ cfd = (struct canfd_frame *)skb->data;
+ len = cfd->len;
+ can_id = cfd->can_id;
+ payload = cfd->data;
+
+ if (can_is_canfd_skb(skb)) {
+ dlc = can_fd_len2dlc(len);
+ } else {
+ cf = (struct can_frame *)skb->data;
+ dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
+ }
+
/* Reads of priv->eskbp and shut-downs of the queue needs to
* be atomic towards the updates to priv->eskbp and wake-ups
* of the queue in the interrupt handler.
@@ -1427,9 +1461,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
txwr = grcan_read_reg(®s->txwr);
space = grcan_txspace(dma->tx.size, txwr, priv->eskbp);
-
- slotindex = txwr / GRCAN_MSG_SIZE;
- slot = dma->tx.buf + txwr;
+ bds = grcan_numbds(len);
if (unlikely(space == 1))
netif_stop_queue(dev);
@@ -1445,24 +1477,39 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- /* Convert and write CAN message to DMA buffer */
- eff = cf->can_id & CAN_EFF_FLAG;
- rtr = cf->can_id & CAN_RTR_FLAG;
- id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
- dlc = cf->len;
- if (eff)
- tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
- else
- tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
- slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
+ payload_offset = 0;
+ for (i = 0; i < bds; i++) {
+ slot = dma->tx.buf + txwr;
+ memset(slot, 0, GRCAN_MSG_SIZE);
+
+ if (i == 0) {
+ eff = can_id & CAN_EFF_FLAG;
+ rtr = can_id & CAN_RTR_FLAG;
+ id = can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
+ if (eff)
+ tmp = FIELD_PREP(GRCAN_MSG_EID_MASK, id);
+ else
+ tmp = FIELD_PREP(GRCAN_MSG_BID_MASK, id);
+ slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
+ slot[1] = FIELD_PREP(GRCAN_MSG_DLC_MASK, dlc);
+ if (can_is_canfd_skb(skb)) {
+ slot[1] |= GRCAN_TX_FDF;
+ if (cfd->flags & CANFD_BRS)
+ slot[1] |= GRCAN_TX_BRS;
+ }
- slot[1] = ((dlc << GRCAN_MSG_DLC_BIT) & GRCAN_MSG_DLC);
- slot[2] = 0;
- slot[3] = 0;
- if (dlc > 0)
- memcpy(&slot[2], cf->data, sizeof(u32));
- if (dlc > 4)
- memcpy(&slot[3], cf->data + 4, sizeof(u32));
+ copy_len = min(len, 8);
+ memcpy(&slot[2], payload, copy_len);
+ payload_offset += copy_len;
+ } else {
+ copy_len = min(len - payload_offset, GRCAN_MSG_SIZE);
+ memcpy(slot, payload + payload_offset, copy_len);
+ payload_offset += copy_len;
+ }
+ txwr += GRCAN_MSG_SIZE;
+ if (txwr >= dma->tx.size)
+ txwr -= dma->tx.size;
+ }
/* Checking that channel has not been disabled. These cases
* should never happen
@@ -1504,8 +1551,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
wmb();
/* Update write pointer to start transmission */
- grcan_write_reg(®s->txwr,
- grcan_ring_add(txwr, GRCAN_MSG_SIZE, dma->tx.size));
+ grcan_write_reg(®s->txwr, txwr);
return NETDEV_TX_OK;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN
2026-01-22 12:10 ` [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN Arun Muthusamy
@ 2026-01-23 14:25 ` Marc Kleine-Budde
2026-01-27 14:06 ` Arun Muthusamy
0 siblings, 1 reply; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 14:25 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
[-- Attachment #1: Type: text/plain, Size: 3688 bytes --]
On 22.01.2026 13:10:36, Arun Muthusamy wrote:
> Include CANFD TX support with the legacy CAN support, enabling
> support for extended data payloads to provide higher bit rates.
>
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
> drivers/net/can/grcan.c | 102 +++++++++++++++++++++++++++++-----------
> 1 file changed, 74 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index 9fc18064fab1..508ad5320cff 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -174,6 +174,7 @@ struct grcan_registers {
> #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
>
> #define GRCAN_MSG_SIZE 16
> +#define GRCAN_CLASSIC_DATA_SIZE 8
>
> #define GRCAN_MSG_IDE 0x80000000
> #define GRCAN_MSG_RTR 0x40000000
> @@ -195,6 +196,10 @@ struct grcan_registers {
> #define GRCAN_MSG_OFF 0x00000002
> #define GRCAN_MSG_PASS 0x00000001
>
> +#define GRCAN_MSG_EID_MASK GENMASK(28, 0)
> +#define GRCAN_MSG_BID_MASK GENMASK(28, 18)
> +#define GRCAN_MSG_DLC_MASK GENMASK(31, 28)
> +
> #define GRCAN_BUFFER_ALIGNMENT 1024
> #define GRCAN_DEFAULT_BUFFER_SIZE 1024
> #define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
> @@ -227,6 +232,9 @@ struct grcan_registers {
> #define GRCANFD_FDBTR_PS2_BIT 5
> #define GRCANFD_FDBTR_SJW_BIT 0
>
> +#define GRCAN_TX_BRS BIT(25)
> +#define GRCAN_TX_FDF BIT(26)
> +
> /* Hardware capabilities */
> struct grcan_hwcap {
> /* CAN-FD capable, indicates GRCANFD IP.
> @@ -1218,6 +1226,13 @@ static void grcan_transmit_catch_up(struct net_device *dev)
> spin_unlock_irqrestore(&priv->lock, flags);
> }
>
> +static int grcan_numbds(int len)
> +{
> + if (len <= GRCAN_CLASSIC_DATA_SIZE)
> + return 1;
> + return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
This looks strange, what is calculated here? Why is "<=
GRCAN_CLASSIC_DATA_SIZE" a special case?
> +}
> +
> static int grcan_receive(struct net_device *dev, int budget)
> {
> struct grcan_priv *priv = netdev_priv(dev);
> @@ -1400,15 +1415,22 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
> struct net_device *dev)
> {
> struct grcan_priv *priv = netdev_priv(dev);
> - struct grcan_registers __iomem *regs = priv->regs;
> + struct grcan_registers __iomem *regs;
> + u32 eff, rtr, dlc, tmp, err, can_id;
> struct grcan_dma *dma = &priv->dma;
> - struct can_frame *cf = (struct can_frame *)skb->data;
> + u32 bds, copy_len, payload_offset;
> u32 id, txwr, txrd, space, txctrl;
> - int slotindex;
> - u32 *slot;
> - u32 rtr, eff, dlc, tmp, err;
> + struct canfd_frame *cfd;
> + struct can_frame *cf;
> unsigned long flags;
> - u32 oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
> + u32 oneshotmode;
> + u8 *payload;
> + u32 *slot;
> + u8 len;
> + int i;
> +
> + regs = priv->regs;
> + oneshotmode = priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT;
>
> if (can_dev_dropped_skb(dev, skb))
> return NETDEV_TX_OK;
> @@ -1419,6 +1441,18 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
> if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
> return NETDEV_TX_BUSY;
>
> + cfd = (struct canfd_frame *)skb->data;
> + len = cfd->len;
> + can_id = cfd->can_id;
> + payload = cfd->data;
one space in front of the "=" please
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN
2026-01-23 14:25 ` Marc Kleine-Budde
@ 2026-01-27 14:06 ` Arun Muthusamy
2026-01-27 14:12 ` Marc Kleine-Budde
0 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-27 14:06 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
On 1/23/26 15:25, Marc Kleine-Budde wrote:
> On 22.01.2026 13:10:36, Arun Muthusamy wrote:
>> Include CANFD TX support with the legacy CAN support, enabling
>> support for extended data payloads to provide higher bit rates.
>>
>> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
>> ---
>> drivers/net/can/grcan.c | 102 +++++++++++++++++++++++++++++-----------
>> 1 file changed, 74 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
>> index 9fc18064fab1..508ad5320cff 100644
>> --- a/drivers/net/can/grcan.c
>> +++ b/drivers/net/can/grcan.c
>> @@ -174,6 +174,7 @@ struct grcan_registers {
>> #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
>>
>> #define GRCAN_MSG_SIZE 16
>> +#define GRCAN_CLASSIC_DATA_SIZE 8
>>
>> #define GRCAN_MSG_IDE 0x80000000
>> #define GRCAN_MSG_RTR 0x40000000
>> @@ -195,6 +196,10 @@ struct grcan_registers {
>> #define GRCAN_MSG_OFF 0x00000002
>> #define GRCAN_MSG_PASS 0x00000001
>>
>> +#define GRCAN_MSG_EID_MASK GENMASK(28, 0)
>> +#define GRCAN_MSG_BID_MASK GENMASK(28, 18)
>> +#define GRCAN_MSG_DLC_MASK GENMASK(31, 28)
>> +
>> #define GRCAN_BUFFER_ALIGNMENT 1024
>> #define GRCAN_DEFAULT_BUFFER_SIZE 1024
>> #define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
>> @@ -227,6 +232,9 @@ struct grcan_registers {
>> #define GRCANFD_FDBTR_PS2_BIT 5
>> #define GRCANFD_FDBTR_SJW_BIT 0
>>
>> +#define GRCAN_TX_BRS BIT(25)
>> +#define GRCAN_TX_FDF BIT(26)
>> +
>> /* Hardware capabilities */
>> struct grcan_hwcap {
>> /* CAN-FD capable, indicates GRCANFD IP.
>> @@ -1218,6 +1226,13 @@ static void grcan_transmit_catch_up(struct net_device *dev)
>> spin_unlock_irqrestore(&priv->lock, flags);
>> }
>>
>> +static int grcan_numbds(int len)
>> +{
>> + if (len <= GRCAN_CLASSIC_DATA_SIZE)
>> + return 1;
>> + return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> This looks strange, what is calculated here? Why is "<=
> GRCAN_CLASSIC_DATA_SIZE" a special case?
grcan_numbds() calculates the number of buffer descriptors needed based on the data length.
The condition "len <= GRCAN_CLASSIC_DATA_SIZE" addresses cases where the data length fits within a one buffer descriptor.
For data lengths greater than "GRCAN_CLASSIC_DATA_SIZE", it computes additional descriptors needed.
-- BR, Arun Muthusamy Software Engineer Frontgrade Gaisler T : +46 (0)
700 558 528 arun.muthusamy@gaisler.com Frontgrade Gaisler AB, Kungsgatan
12, SE-411 19 GÖTEBORG, Sweden. +46 (0) 31 775 8650, www.gaisler.com
<http://www.gaisler.com>
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN
2026-01-27 14:06 ` Arun Muthusamy
@ 2026-01-27 14:12 ` Marc Kleine-Budde
2026-01-27 14:17 ` Arun Muthusamy
0 siblings, 1 reply; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-27 14:12 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
[-- Attachment #1: Type: text/plain, Size: 3340 bytes --]
On 27.01.2026 15:06:55, Arun Muthusamy wrote:
>
> On 1/23/26 15:25, Marc Kleine-Budde wrote:
> > On 22.01.2026 13:10:36, Arun Muthusamy wrote:
> > > Include CANFD TX support with the legacy CAN support, enabling
> > > support for extended data payloads to provide higher bit rates.
> > >
> > > Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> > > ---
> > > drivers/net/can/grcan.c | 102 +++++++++++++++++++++++++++++-----------
> > > 1 file changed, 74 insertions(+), 28 deletions(-)
> > >
> > > diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> > > index 9fc18064fab1..508ad5320cff 100644
> > > --- a/drivers/net/can/grcan.c
> > > +++ b/drivers/net/can/grcan.c
> > > @@ -174,6 +174,7 @@ struct grcan_registers {
> > > #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
> > >
> > > #define GRCAN_MSG_SIZE 16
> > > +#define GRCAN_CLASSIC_DATA_SIZE 8
> > >
> > > #define GRCAN_MSG_IDE 0x80000000
> > > #define GRCAN_MSG_RTR 0x40000000
> > > @@ -195,6 +196,10 @@ struct grcan_registers {
> > > #define GRCAN_MSG_OFF 0x00000002
> > > #define GRCAN_MSG_PASS 0x00000001
> > >
> > > +#define GRCAN_MSG_EID_MASK GENMASK(28, 0)
> > > +#define GRCAN_MSG_BID_MASK GENMASK(28, 18)
> > > +#define GRCAN_MSG_DLC_MASK GENMASK(31, 28)
> > > +
> > > #define GRCAN_BUFFER_ALIGNMENT 1024
> > > #define GRCAN_DEFAULT_BUFFER_SIZE 1024
> > > #define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
> > > @@ -227,6 +232,9 @@ struct grcan_registers {
> > > #define GRCANFD_FDBTR_PS2_BIT 5
> > > #define GRCANFD_FDBTR_SJW_BIT 0
> > >
> > > +#define GRCAN_TX_BRS BIT(25)
> > > +#define GRCAN_TX_FDF BIT(26)
> > > +
> > > /* Hardware capabilities */
> > > struct grcan_hwcap {
> > > /* CAN-FD capable, indicates GRCANFD IP.
> > > @@ -1218,6 +1226,13 @@ static void grcan_transmit_catch_up(struct net_device *dev)
> > > spin_unlock_irqrestore(&priv->lock, flags);
> > > }
> > >
> > > +static int grcan_numbds(int len)
> > > +{
> > > + if (len <= GRCAN_CLASSIC_DATA_SIZE)
> > > + return 1;
> > > + return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> > This looks strange, what is calculated here? Why is "<=
> > GRCAN_CLASSIC_DATA_SIZE" a special case?
>
> grcan_numbds() calculates the number of buffer descriptors needed based on the data length.
> The condition "len <= GRCAN_CLASSIC_DATA_SIZE" addresses cases where the data length fits within a one buffer descriptor.
> For data lengths greater than "GRCAN_CLASSIC_DATA_SIZE", it computes additional descriptors needed.
What happens if "len = GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE"?
| return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
= 1 + ((GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
= 1 + (( GRCAN_MSG_SIZE - + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
= 1 + 2;
= 3
Is this correct?
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN
2026-01-27 14:12 ` Marc Kleine-Budde
@ 2026-01-27 14:17 ` Arun Muthusamy
2026-01-27 14:18 ` Marc Kleine-Budde
0 siblings, 1 reply; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-27 14:17 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
On 1/27/26 15:12, Marc Kleine-Budde wrote:
> On 27.01.2026 15:06:55, Arun Muthusamy wrote:
>> On 1/23/26 15:25, Marc Kleine-Budde wrote:
>>> On 22.01.2026 13:10:36, Arun Muthusamy wrote:
>>>> Include CANFD TX support with the legacy CAN support, enabling
>>>> support for extended data payloads to provide higher bit rates.
>>>>
>>>> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
>>>> ---
>>>> drivers/net/can/grcan.c | 102 +++++++++++++++++++++++++++++-----------
>>>> 1 file changed, 74 insertions(+), 28 deletions(-)
>>>>
>>>> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
>>>> index 9fc18064fab1..508ad5320cff 100644
>>>> --- a/drivers/net/can/grcan.c
>>>> +++ b/drivers/net/can/grcan.c
>>>> @@ -174,6 +174,7 @@ struct grcan_registers {
>>>> #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
>>>>
>>>> #define GRCAN_MSG_SIZE 16
>>>> +#define GRCAN_CLASSIC_DATA_SIZE 8
>>>>
>>>> #define GRCAN_MSG_IDE 0x80000000
>>>> #define GRCAN_MSG_RTR 0x40000000
>>>> @@ -195,6 +196,10 @@ struct grcan_registers {
>>>> #define GRCAN_MSG_OFF 0x00000002
>>>> #define GRCAN_MSG_PASS 0x00000001
>>>>
>>>> +#define GRCAN_MSG_EID_MASK GENMASK(28, 0)
>>>> +#define GRCAN_MSG_BID_MASK GENMASK(28, 18)
>>>> +#define GRCAN_MSG_DLC_MASK GENMASK(31, 28)
>>>> +
>>>> #define GRCAN_BUFFER_ALIGNMENT 1024
>>>> #define GRCAN_DEFAULT_BUFFER_SIZE 1024
>>>> #define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
>>>> @@ -227,6 +232,9 @@ struct grcan_registers {
>>>> #define GRCANFD_FDBTR_PS2_BIT 5
>>>> #define GRCANFD_FDBTR_SJW_BIT 0
>>>>
>>>> +#define GRCAN_TX_BRS BIT(25)
>>>> +#define GRCAN_TX_FDF BIT(26)
>>>> +
>>>> /* Hardware capabilities */
>>>> struct grcan_hwcap {
>>>> /* CAN-FD capable, indicates GRCANFD IP.
>>>> @@ -1218,6 +1226,13 @@ static void grcan_transmit_catch_up(struct net_device *dev)
>>>> spin_unlock_irqrestore(&priv->lock, flags);
>>>> }
>>>>
>>>> +static int grcan_numbds(int len)
>>>> +{
>>>> + if (len <= GRCAN_CLASSIC_DATA_SIZE)
>>>> + return 1;
>>>> + return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
>>> This looks strange, what is calculated here? Why is "<=
>>> GRCAN_CLASSIC_DATA_SIZE" a special case?
>> grcan_numbds() calculates the number of buffer descriptors needed based on the data length.
>> The condition "len <= GRCAN_CLASSIC_DATA_SIZE" addresses cases where the data length fits within a one buffer descriptor.
>> For data lengths greater than "GRCAN_CLASSIC_DATA_SIZE", it computes additional descriptors needed.
> What happens if "len = GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE"?
>
> | return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
>
> = 1 + ((GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> = 1 + (( GRCAN_MSG_SIZE - + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> = 1 + 2;
> = 3
>
> Is this correct?
>
Thanks for pointing out.
That's not correct. It will be addressed in the next patch series.
--
--
BR,
Arun Muthusamy
Software Engineer
Frontgrade Gaisler
T : +46 (0) 700 558 528
arun.muthusamy@gaisler.com
Frontgrade Gaisler AB, Kungsgatan 12, SE-411 19 GÖTEBORG, Sweden.
+46 (0) 31 775 8650, www.gaisler.com
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN
2026-01-27 14:17 ` Arun Muthusamy
@ 2026-01-27 14:18 ` Marc Kleine-Budde
0 siblings, 0 replies; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-27 14:18 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
[-- Attachment #1: Type: text/plain, Size: 3855 bytes --]
On 27.01.2026 15:17:58, Arun Muthusamy wrote:
>
> On 1/27/26 15:12, Marc Kleine-Budde wrote:
> > On 27.01.2026 15:06:55, Arun Muthusamy wrote:
> > > On 1/23/26 15:25, Marc Kleine-Budde wrote:
> > > > On 22.01.2026 13:10:36, Arun Muthusamy wrote:
> > > > > Include CANFD TX support with the legacy CAN support, enabling
> > > > > support for extended data payloads to provide higher bit rates.
> > > > >
> > > > > Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> > > > > ---
> > > > > drivers/net/can/grcan.c | 102 +++++++++++++++++++++++++++++-----------
> > > > > 1 file changed, 74 insertions(+), 28 deletions(-)
> > > > >
> > > > > diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> > > > > index 9fc18064fab1..508ad5320cff 100644
> > > > > --- a/drivers/net/can/grcan.c
> > > > > +++ b/drivers/net/can/grcan.c
> > > > > @@ -174,6 +174,7 @@ struct grcan_registers {
> > > > > #define GRCAN_IRQ_DEFAULT (GRCAN_IRQ_RX | GRCAN_IRQ_TX | GRCAN_IRQ_ERRORS)
> > > > >
> > > > > #define GRCAN_MSG_SIZE 16
> > > > > +#define GRCAN_CLASSIC_DATA_SIZE 8
> > > > >
> > > > > #define GRCAN_MSG_IDE 0x80000000
> > > > > #define GRCAN_MSG_RTR 0x40000000
> > > > > @@ -195,6 +196,10 @@ struct grcan_registers {
> > > > > #define GRCAN_MSG_OFF 0x00000002
> > > > > #define GRCAN_MSG_PASS 0x00000001
> > > > >
> > > > > +#define GRCAN_MSG_EID_MASK GENMASK(28, 0)
> > > > > +#define GRCAN_MSG_BID_MASK GENMASK(28, 18)
> > > > > +#define GRCAN_MSG_DLC_MASK GENMASK(31, 28)
> > > > > +
> > > > > #define GRCAN_BUFFER_ALIGNMENT 1024
> > > > > #define GRCAN_DEFAULT_BUFFER_SIZE 1024
> > > > > #define GRCAN_VALID_TR_SIZE_MASK 0x001fffc0
> > > > > @@ -227,6 +232,9 @@ struct grcan_registers {
> > > > > #define GRCANFD_FDBTR_PS2_BIT 5
> > > > > #define GRCANFD_FDBTR_SJW_BIT 0
> > > > >
> > > > > +#define GRCAN_TX_BRS BIT(25)
> > > > > +#define GRCAN_TX_FDF BIT(26)
> > > > > +
> > > > > /* Hardware capabilities */
> > > > > struct grcan_hwcap {
> > > > > /* CAN-FD capable, indicates GRCANFD IP.
> > > > > @@ -1218,6 +1226,13 @@ static void grcan_transmit_catch_up(struct net_device *dev)
> > > > > spin_unlock_irqrestore(&priv->lock, flags);
> > > > > }
> > > > >
> > > > > +static int grcan_numbds(int len)
> > > > > +{
> > > > > + if (len <= GRCAN_CLASSIC_DATA_SIZE)
> > > > > + return 1;
> > > > > + return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> > > > This looks strange, what is calculated here? Why is "<=
> > > > GRCAN_CLASSIC_DATA_SIZE" a special case?
> > > grcan_numbds() calculates the number of buffer descriptors needed based on the data length.
> > > The condition "len <= GRCAN_CLASSIC_DATA_SIZE" addresses cases where the data length fits within a one buffer descriptor.
> > > For data lengths greater than "GRCAN_CLASSIC_DATA_SIZE", it computes additional descriptors needed.
> > What happens if "len = GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE"?
> >
> > | return 1 + ((len - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> >
> > = 1 + ((GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE - GRCAN_CLASSIC_DATA_SIZE + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> > = 1 + (( GRCAN_MSG_SIZE - + GRCAN_MSG_SIZE) / GRCAN_MSG_SIZE);
> > = 1 + 2;
> > = 3
> >
> > Is this correct?
> >
> Thanks for pointing out.
> That's not correct. It will be addressed in the next patch series.
Please make use of DIV_ROUND_UP()
regards,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 14/15] can: grcan: Add CANFD RX support alongside legacy CAN
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (12 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 13/15] can: grcan: Add CANFD TX support alongside legacy CAN Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-22 12:10 ` [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame Arun Muthusamy
2026-01-23 14:30 ` [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Marc Kleine-Budde
15 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy
Include CANFD RX support with the legacy CAN support, enabling
support for extended data payloads to provide higher bit rates.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 98 +++++++++++++++++++++++++++--------------
1 file changed, 65 insertions(+), 33 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 508ad5320cff..39afb12c50d0 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -235,6 +235,9 @@ struct grcan_registers {
#define GRCAN_TX_BRS BIT(25)
#define GRCAN_TX_FDF BIT(26)
+#define GRCAN_RX_BRS BIT(25)
+#define GRCAN_RX_FDF BIT(26)
+
/* Hardware capabilities */
struct grcan_hwcap {
/* CAN-FD capable, indicates GRCANFD IP.
@@ -1235,18 +1238,22 @@ static int grcan_numbds(int len)
static int grcan_receive(struct net_device *dev, int budget)
{
+ struct net_device_stats *stats = &dev->stats;
struct grcan_priv *priv = netdev_priv(dev);
- struct grcan_registers __iomem *regs = priv->regs;
+ struct grcan_registers __iomem *regs;
struct grcan_dma *dma = &priv->dma;
- struct net_device_stats *stats = &dev->stats;
- struct can_frame *cf;
+ u32 bds, copy_len, payload_offset;
+ u32 wr, rd, dlc, startrd;
+ struct canfd_frame *cf;
+ int i, work_done = 0;
struct sk_buff *skb;
- u32 wr, rd, startrd;
- u32 *slot;
u32 rtr, eff;
- int work_done = 0;
+ u32 *slot;
+ u8 *data;
+ regs = priv->regs;
rd = grcan_read_reg(®s->rxrd);
+
startrd = rd;
for (work_done = 0; work_done < budget; work_done++) {
/* Check for packet to receive */
@@ -1254,43 +1261,68 @@ static int grcan_receive(struct net_device *dev, int budget)
if (rd == wr)
break;
- /* Take care of packet */
- skb = alloc_can_skb(dev, &cf);
- if (skb == NULL) {
+ slot = dma->rx.buf + rd;
+
+ if (slot[1] & GRCAN_RX_FDF)
+ skb = alloc_canfd_skb(dev, &cf);
+ else
+ skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf);
+
+ if (unlikely(!skb)) {
netdev_err(dev,
"dropping frame: skb allocation failed\n");
stats->rx_dropped++;
continue;
}
- slot = dma->rx.buf + rd;
- eff = slot[0] & GRCAN_MSG_IDE;
- rtr = slot[0] & GRCAN_MSG_RTR;
- if (eff) {
- cf->can_id = ((slot[0] & GRCAN_MSG_EID)
- >> GRCAN_MSG_EID_BIT);
- cf->can_id |= CAN_EFF_FLAG;
- } else {
- cf->can_id = ((slot[0] & GRCAN_MSG_BID)
- >> GRCAN_MSG_BID_BIT);
+ dlc = FIELD_GET(GRCAN_MSG_DLC_MASK, slot[1]);
+ if (slot[1] & GRCAN_RX_FDF)
+ cf->len = can_fd_dlc2len(dlc);
+ else
+ cf->len = can_cc_dlc2len(dlc);
+
+ bds = grcan_numbds(cf->len);
+ payload_offset = 0;
+ data = cf->data;
+
+ for (i = 0; i < bds; i++) {
+ slot = dma->rx.buf + rd;
+
+ if (i == 0) {
+ eff = slot[0] & GRCAN_MSG_IDE;
+ rtr = slot[0] & GRCAN_MSG_RTR;
+ if (eff) {
+ cf->can_id = FIELD_GET(GRCAN_MSG_EID_MASK, slot[0]);
+ cf->can_id |= CAN_EFF_FLAG;
+ } else {
+ cf->can_id = FIELD_GET(GRCAN_MSG_BID_MASK, slot[0]);
+ }
+ if (rtr)
+ cf->can_id |= CAN_RTR_FLAG;
+
+ dlc = FIELD_GET(GRCAN_MSG_DLC_MASK, slot[1]);
+ if (slot[1] & GRCAN_RX_FDF)
+ cf->len = can_fd_dlc2len(dlc);
+ else
+ cf->len = can_cc_dlc2len(dlc);
+
+ copy_len = min(cf->len, GRCAN_CLASSIC_DATA_SIZE);
+ memcpy(data, &slot[2], copy_len);
+ payload_offset += copy_len;
+ } else {
+ copy_len = min(cf->len - payload_offset, GRCAN_MSG_SIZE);
+ memcpy(data + payload_offset, slot, copy_len);
+ payload_offset += copy_len;
+ }
+ rd += GRCAN_MSG_SIZE;
+ if (rd >= dma->rx.size)
+ rd -= dma->rx.size;
}
- cf->len = can_cc_dlc2len((slot[1] & GRCAN_MSG_DLC)
- >> GRCAN_MSG_DLC_BIT);
- if (rtr) {
- cf->can_id |= CAN_RTR_FLAG;
- } else {
- if (cf->can_dlc > 0)
- memcpy(cf->data, &slot[2], sizeof(u32));
- if (cf->can_dlc > 4)
- memcpy(cf->data + 4, &slot[3], sizeof(u32));
- stats->rx_bytes += cf->len;
- }
+ /* Update statistics and read pointer */
stats->rx_packets++;
-
+ stats->rx_bytes += cf->len;
netif_receive_skb(skb);
-
- rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
}
/* Make sure everything is read before allowing hardware to
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (13 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 14/15] can: grcan: Add CANFD RX " Arun Muthusamy
@ 2026-01-22 12:10 ` Arun Muthusamy
2026-01-23 14:12 ` Marc Kleine-Budde
2026-01-23 14:17 ` Marc Kleine-Budde
2026-01-23 14:30 ` [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Marc Kleine-Budde
15 siblings, 2 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-22 12:10 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, mkl, mailhol
Cc: devicetree, linux-kernel, linux-can, Arun Muthusamy
Refactor echo socket buffer management by introducing dedicated indices
for current and next echo slots.
- Introduce "echo_skb_idx" to keep track of the current packet index in
the echo buffer, and "next_echo_idx" for the next available slot.
- Adjust memory allocation for echo skb to calculate the number of slots
based on slot size.
- Enhance logic in catch_up_echo_skb() to correctly process and free echo
skbs.
- Initialize "next_echo_idx" in grcan_set_mode() to ensure proper starting
conditions when the device enters proper modes.
- Improve memory and index handling in grcan_start_xmit() and
added a check to stop the network queue when necessary.
Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
---
drivers/net/can/grcan.c | 51 ++++++++++++++++++++++++++++++-----------
1 file changed, 38 insertions(+), 13 deletions(-)
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 39afb12c50d0..22c86e5d7002 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -298,6 +298,15 @@ struct grcan_priv {
struct sk_buff **echo_skb; /* We allocate this on our own */
+ /*
+ * Since the CAN FD frame has a variable length, this variable is used
+ * to keep track of the index of the CAN echo skb (socket buffer) frame.
+ */
+ u32 echo_skb_idx;
+
+ /* Next echo skb free slot index */
+ u32 next_echo_idx;
+
/* The echo skb pointer, pointing into echo_skb and indicating which
* frames can be echoed back. See the "Notes on the tx cyclic buffer
* handling"-comment for grcan_start_xmit for more details.
@@ -578,7 +587,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
struct grcan_registers __iomem *regs = priv->regs;
struct grcan_dma *dma = &priv->dma;
struct net_device_stats *stats = &dev->stats;
- int i, work_done;
+ int work_done;
/* Updates to priv->eskbp and wake-ups of the queue needs to
* be atomic towards the reads of priv->eskbp and shut-downs
@@ -589,19 +598,22 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
for (work_done = 0; work_done < budget || budget < 0; work_done++) {
if (priv->eskbp == txrd)
break;
- i = priv->eskbp / GRCAN_MSG_SIZE;
- if (echo) {
- /* Normal echo of messages */
- stats->tx_packets++;
- stats->tx_bytes += can_get_echo_skb(dev, i, NULL);
- } else {
- /* For cleanup of untransmitted messages */
- can_free_echo_skb(dev, i, NULL);
- }
priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
dma->tx.size);
txrd = grcan_read_reg(®s->txrd);
+
+ /* Grab the packet once the packet is send or free untransmitted packet*/
+ if (priv->eskbp == txrd) {
+ if (echo) {
+ /* Normal echo of messages */
+ stats->tx_packets++;
+ stats->tx_bytes += can_get_echo_skb(dev, priv->echo_skb_idx, NULL);
+ } else {
+ /* For cleanup of untransmitted messages */
+ can_free_echo_skb(dev, priv->echo_skb_idx, NULL);
+ }
+ }
}
return work_done;
}
@@ -1109,6 +1121,7 @@ static int grcan_set_mode(struct net_device *dev, enum can_mode mode)
if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
netif_wake_queue(dev);
}
+ priv->next_echo_idx = 0;
spin_unlock_irqrestore(&priv->lock, flags);
return err;
}
@@ -1120,6 +1133,7 @@ static int grcan_open(struct net_device *dev)
struct grcan_priv *priv = netdev_priv(dev);
struct grcan_dma *dma = &priv->dma;
unsigned long flags;
+ u32 nr_echo_slots;
int err;
/* Allocate memory */
@@ -1130,13 +1144,15 @@ static int grcan_open(struct net_device *dev)
return err;
}
- priv->echo_skb = kcalloc(dma->tx.size, sizeof(*priv->echo_skb),
+ nr_echo_slots = dma->tx.size / GRCAN_MSG_SIZE;
+
+ priv->echo_skb = kcalloc(nr_echo_slots, sizeof(*priv->echo_skb),
GFP_KERNEL);
if (!priv->echo_skb) {
err = -ENOMEM;
goto exit_free_dma_buffers;
}
- priv->can.echo_skb_max = dma->tx.size;
+ priv->can.echo_skb_max = nr_echo_slots;
priv->can.echo_skb = priv->echo_skb;
/* Get can device up */
@@ -1575,7 +1591,16 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
* can_put_echo_skb would be an error unless other measures are
* taken.
*/
- can_put_echo_skb(skb, dev, slotindex, 0);
+
+ priv->echo_skb_idx = priv->next_echo_idx;
+
+ can_put_echo_skb(skb, dev, priv->next_echo_idx, 0);
+
+ /* Move to the next index in the echo skb buffer */
+ priv->next_echo_idx = (priv->next_echo_idx + 1) % priv->can.echo_skb_max;
+
+ if (priv->can.echo_skb[priv->echo_skb_idx])
+ netif_stop_queue(dev);
/* Make sure everything is written before allowing hardware to
* read from the memory
--
2.51.0
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame
2026-01-22 12:10 ` [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame Arun Muthusamy
@ 2026-01-23 14:12 ` Marc Kleine-Budde
2026-01-23 14:17 ` Marc Kleine-Budde
1 sibling, 0 replies; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 14:12 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
[-- Attachment #1: Type: text/plain, Size: 4540 bytes --]
On 22.01.2026 13:10:38, Arun Muthusamy wrote:
> Refactor echo socket buffer management by introducing dedicated indices
> for current and next echo slots.
>
> - Introduce "echo_skb_idx" to keep track of the current packet index in
> the echo buffer, and "next_echo_idx" for the next available slot.
> - Adjust memory allocation for echo skb to calculate the number of slots
> based on slot size.
> - Enhance logic in catch_up_echo_skb() to correctly process and free echo
> skbs.
> - Initialize "next_echo_idx" in grcan_set_mode() to ensure proper starting
> conditions when the device enters proper modes.
> - Improve memory and index handling in grcan_start_xmit() and
> added a check to stop the network queue when necessary.
consider using
netif_subqueue_maybe_stop()/netif_subqueue_completed_wake() from
netdev_queues.h
> Signed-off-by: Arun Muthusamy <arun.muthusamy@gaisler.com>
> ---
> drivers/net/can/grcan.c | 51 ++++++++++++++++++++++++++++++-----------
> 1 file changed, 38 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
> index 39afb12c50d0..22c86e5d7002 100644
> --- a/drivers/net/can/grcan.c
> +++ b/drivers/net/can/grcan.c
> @@ -298,6 +298,15 @@ struct grcan_priv {
>
> struct sk_buff **echo_skb; /* We allocate this on our own */
>
> + /*
> + * Since the CAN FD frame has a variable length, this variable is used
> + * to keep track of the index of the CAN echo skb (socket buffer) frame.
> + */
> + u32 echo_skb_idx;
> +
> + /* Next echo skb free slot index */
> + u32 next_echo_idx;
> +
> /* The echo skb pointer, pointing into echo_skb and indicating which
> * frames can be echoed back. See the "Notes on the tx cyclic buffer
> * handling"-comment for grcan_start_xmit for more details.
> @@ -578,7 +587,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
> struct grcan_registers __iomem *regs = priv->regs;
> struct grcan_dma *dma = &priv->dma;
> struct net_device_stats *stats = &dev->stats;
> - int i, work_done;
> + int work_done;
>
> /* Updates to priv->eskbp and wake-ups of the queue needs to
> * be atomic towards the reads of priv->eskbp and shut-downs
> @@ -589,19 +598,22 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
> for (work_done = 0; work_done < budget || budget < 0; work_done++) {
> if (priv->eskbp == txrd)
> break;
> - i = priv->eskbp / GRCAN_MSG_SIZE;
> - if (echo) {
> - /* Normal echo of messages */
> - stats->tx_packets++;
> - stats->tx_bytes += can_get_echo_skb(dev, i, NULL);
> - } else {
> - /* For cleanup of untransmitted messages */
> - can_free_echo_skb(dev, i, NULL);
> - }
>
> priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
> dma->tx.size);
> txrd = grcan_read_reg(®s->txrd);
> +
> + /* Grab the packet once the packet is send or free untransmitted packet*/
^^
one space is enough
> + if (priv->eskbp == txrd) {
> + if (echo) {
> + /* Normal echo of messages */
> + stats->tx_packets++;
> + stats->tx_bytes += can_get_echo_skb(dev, priv->echo_skb_idx, NULL);
> + } else {
> + /* For cleanup of untransmitted messages */
> + can_free_echo_skb(dev, priv->echo_skb_idx, NULL);
> + }
> + }
> }
> return work_done;
> }
> @@ -1109,6 +1121,7 @@ static int grcan_set_mode(struct net_device *dev, enum can_mode mode)
> if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
> netif_wake_queue(dev);
> }
> + priv->next_echo_idx = 0;
> spin_unlock_irqrestore(&priv->lock, flags);
> return err;
> }
> @@ -1120,6 +1133,7 @@ static int grcan_open(struct net_device *dev)
> struct grcan_priv *priv = netdev_priv(dev);
> struct grcan_dma *dma = &priv->dma;
> unsigned long flags;
> + u32 nr_echo_slots;
> int err;
>
> /* Allocate memory */
> @@ -1130,13 +1144,15 @@ static int grcan_open(struct net_device *dev)
> return err;
> }
>
> - priv->echo_skb = kcalloc(dma->tx.size, sizeof(*priv->echo_skb),
> + nr_echo_slots = dma->tx.size / GRCAN_MSG_SIZE;
^^
one space is enough
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame
2026-01-22 12:10 ` [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame Arun Muthusamy
2026-01-23 14:12 ` Marc Kleine-Budde
@ 2026-01-23 14:17 ` Marc Kleine-Budde
2026-01-28 8:14 ` Arun Muthusamy
1 sibling, 1 reply; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 14:17 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]
On 22.01.2026 13:10:38, Arun Muthusamy wrote:
[...]
> @@ -1575,7 +1591,16 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
> * can_put_echo_skb would be an error unless other measures are
> * taken.
> */
> - can_put_echo_skb(skb, dev, slotindex, 0);
> +
> + priv->echo_skb_idx = priv->next_echo_idx;
> +
> + can_put_echo_skb(skb, dev, priv->next_echo_idx, 0);
> +
> + /* Move to the next index in the echo skb buffer */
> + priv->next_echo_idx = (priv->next_echo_idx + 1) % priv->can.echo_skb_max;
> +
> + if (priv->can.echo_skb[priv->echo_skb_idx])
> + netif_stop_queue(dev);
You also use "if (unlikely(space == 1)) netif_stop_queue(dev);", that
looks suspicious. Why have 2 independent ways to check if the TX queue
is full?
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame
2026-01-23 14:17 ` Marc Kleine-Budde
@ 2026-01-28 8:14 ` Arun Muthusamy
0 siblings, 0 replies; 31+ messages in thread
From: Arun Muthusamy @ 2026-01-28 8:14 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
On 1/23/26 15:17, Marc Kleine-Budde wrote:
> On 22.01.2026 13:10:38, Arun Muthusamy wrote:
> [...]
>
>> @@ -1575,7 +1591,16 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
>> * can_put_echo_skb would be an error unless other measures are
>> * taken.
>> */
>> - can_put_echo_skb(skb, dev, slotindex, 0);
>> +
>> + priv->echo_skb_idx = priv->next_echo_idx;
>> +
>> + can_put_echo_skb(skb, dev, priv->next_echo_idx, 0);
>> +
>> + /* Move to the next index in the echo skb buffer */
>> + priv->next_echo_idx = (priv->next_echo_idx + 1) % priv->can.echo_skb_max;
>> +
>> + if (priv->can.echo_skb[priv->echo_skb_idx])
>> + netif_stop_queue(dev);
> You also use "if (unlikely(space == 1)) netif_stop_queue(dev);", that
> looks suspicious. Why have 2 independent ways to check if the TX queue
> is full?
That's correct.
Current implementation introduces two independent checks where space reflects hardware TX descriptor availability and echo slot availability.
I’ll rework this to use a single check, covering both TX ring space and echo slot availability.
--
--
BR,
Arun Muthusamy
Software Engineer
Frontgrade Gaisler
T : +46 (0) 700 558 528
arun.muthusamy@gaisler.com
Frontgrade Gaisler AB, Kungsgatan 12, SE-411 19 GÖTEBORG, Sweden.
+46 (0) 31 775 8650, www.gaisler.com
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens
2026-01-22 12:10 [PATCH v3 00/15] can: grcan: Enhance driver with CANFD Support and Improvemens Arun Muthusamy
` (14 preceding siblings ...)
2026-01-22 12:10 ` [PATCH v3 15/15] can: grcan: Update echo skb handling to match variable length CANFD frame Arun Muthusamy
@ 2026-01-23 14:30 ` Marc Kleine-Budde
15 siblings, 0 replies; 31+ messages in thread
From: Marc Kleine-Budde @ 2026-01-23 14:30 UTC (permalink / raw)
To: Arun Muthusamy
Cc: robh, krzk+dt, conor+dt, mailhol, devicetree, linux-kernel,
linux-can
[-- Attachment #1: Type: text/plain, Size: 1373 bytes --]
On 22.01.2026 13:10:23, Arun Muthusamy wrote:
> This patch series updates the GRCAN driver to support the GRCANFD core
> from the GRLIB IP core library.
>
> In addition to GRCANFD support, the updates include enhancements for
> compatibility with NOEL-V (RISC-V) systems, such as matching drivers
> using the 'compatible' identifier and adding support for reading clock
> frequency via the common clock framework where available. The series
> also includes improvements like functions for configuring
> nominal bit-timing and optimizations for DMA operations.
>
> This series also updates the driver documentation and bindings.
> The old text binding is converted to YAML, a new vendor prefix
> is added to reflect the updated ownership and an entry for the
> driver is added to the MAINTAINERS file.
The order of patches is strange.
In #12 you claim to support CAN-FD, but actual support is added in
#13...15.
The kernel should be functional on every commit. Please change the order
of patches, that CAN-FD support can only be enabled if the driver really
supports it.
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread