* [PATCH can-next v7 0/6] gs_usb: fixes
@ 2026-11-14 15:17 Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 1/6] can: gs_usb: gs_make_candev(): check can_rx_offload_add_manual() return value Marc Kleine-Budde
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde,
Ciprian Marian Costea, stable, Shuangpeng Bai, Vadim Fedorenko
Hello,
this series contains fixes for issues found by sashiko. Also picked up the
patches by Ciprian Marian Costea and Shuangpeng Bai and integrated them
into the series.
regards,
Marc
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
Changes in v7:
- patch #1: update patch description (sashiko)
- patch #2: moved to linux-can
- patch #5: update function's locking annotation
- patch #5: drop active_timestamp_channels, use active_channels again
- patch #5: remove testing against IFF_UP (sashiko)
- patch #5: annotate that driver relied on RTNL for synchronization
(sashiko)
- patch #6: new: move use of new {enable,disable}_delayed_work() API here
- Link to v6: https://patch.msgid.link/20261113-gs_usb-fixes-v6-0-0c039e1bfd74@pengutronix.de
Changes in v6:
- patch #5: add missing initialization hw_ts_supported in
gs_usb_probe() (sashiko)
- patch #5: work around race window in gs_usb_timestamp_start() (sashiko)
- patch #5: start time stamping worker if the device supports HW time
stamping, if least one interface is brought up
- Link to v5: https://patch.msgid.link/20261108-gs_usb-fixes-v5-0-d52dd4940d46@pengutronix.de
Changes in v5:
- patch #1: add new patch
- patch #3: gs_usb_disconnect(): first unregister_candev() all CAN
interfaces, then call gs_destroy_candev()
- patch #4: update Fixes tag (sashiko)
- patch #4: use stats pointer directly (sashiko)
- patch #5: add new patch
- Link to v4: https://patch.msgid.link/20261026-gs_usb-fixes-v4-0-59e3b6360053@pengutronix.de
Changes in v4:
- patch #2: fix cleanup if register_candev() fails (sashiko)
- Link to v3: https://patch.msgid.link/20261026-gs_usb-fixes-v3-0-3a68f1f62813@pengutronix.de
Changes in v3:
- patch #2: fix cleanup if register_candev() fails (sashiko)
- Link to v2: https://patch.msgid.link/20261025-gs_usb-fixes-v2-0-535d45097f72@pengutronix.de
Changes in v2:
- patch #2: add missing cleanup if register_candev() fails (sashiko)
- patch #3: do not increase rx_errors during OOM (sashiko)
- Link to v1: https://patch.msgid.link/20261025-gs_usb-fixes-v1-0-f74ebbd4da36@pengutronix.de
---
Ciprian Marian Costea (1):
can: gs_usb: gs_make_candev(): check can_rx_offload_add_manual() return value
Marc Kleine-Budde (4):
can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails
can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish
can: gs_usb: properly shut down timestamp worker
Shuangpeng Bai (1):
can: gs_usb: fix hardware timestamp state for mixed channels
drivers/net/can/usb/gs_usb.c | 170 ++++++++++++++++++++++++++++++++-----------
1 file changed, 128 insertions(+), 42 deletions(-)
---
base-commit: 573af801552999954caa8347e4490b04cf4763f0
base-tree: git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git master
change-id: 20261025-gs_usb-fixes-250f38833107
Best regards,
--
Marc Kleine-Budde <mkl@pengutronix.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH can-next v7 1/6] can: gs_usb: gs_make_candev(): check can_rx_offload_add_manual() return value
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
@ 2026-11-14 15:17 ` Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 2/6] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde,
Ciprian Marian Costea
From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
gs_make_candev() ignores the return value of can_rx_offload_add_manual().
In an upcoming series can_rx_offload will be improved and
can_rx_offload_add_manual() can fail.
Check the return value and exit via the existing free_candev() on error
path.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Link: https://patch.msgid.link/20260907104942.17089-4-ciprianmarian.costea@oss.nxp.com
[mkl: update patch description]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 3b9b2f104d86..cac4ce323a1d 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -1487,7 +1487,10 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->can.fd.data_bittiming_const = &dev->data_bt_const;
}
- can_rx_offload_add_manual(netdev, &dev->offload, GS_NAPI_WEIGHT);
+ rc = can_rx_offload_add_manual(netdev, &dev->offload, GS_NAPI_WEIGHT);
+ if (rc)
+ goto out_free_candev;
+
SET_NETDEV_DEV(netdev, &intf->dev);
rc = register_candev(dev->netdev);
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH can-next v7 2/6] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 1/6] can: gs_usb: gs_make_candev(): check can_rx_offload_add_manual() return value Marc Kleine-Budde
@ 2026-11-14 15:17 ` Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 3/6] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
In gs_usb_probe(), gs_make_candev() is called to allocate and set up the
CAN channel, as well as to call register_candev(). However, gs_usb_probe()
defers the assignment of dev->parent and parent->hf_size_rx until after
gs_make_candev() returns. This opens a race window for the user space to
bring up the CAN interface, while it's not completely setup.
To close the race window, initialize all CAN interfaces in a first loop and
then register them in a second loop: Don't call register_candev() from
gs_make_candev() but explicitly from gs_usb_probe(). Adjust
gs_destroy_candev() likewise, move unregister_candev() to
gs_usb_disconnect() and the error paths in gs_usb_probe(), to keep it
inverse to symmetric to gs_make_candev().
Closes: https://sashiko.dev/#/bug/linux-be54de7d-0b75-408c-b3ee-dd90c9756857
Closes: https://sashiko.dev/#/bug/linux-71076d59-0843-4749-a5ab-fdd98a08582f
Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 64 +++++++++++++++++++++++++++-----------------
1 file changed, 40 insertions(+), 24 deletions(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index cac4ce323a1d..6997cc8a6b2d 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -1493,18 +1493,8 @@ static struct gs_can *gs_make_candev(unsigned int channel,
SET_NETDEV_DEV(netdev, &intf->dev);
- rc = register_candev(dev->netdev);
- if (rc) {
- dev_err(&intf->dev,
- "Couldn't register candev for channel %d (%pe)\n",
- channel, ERR_PTR(rc));
- goto out_can_rx_offload_del;
- }
-
return dev;
-out_can_rx_offload_del:
- can_rx_offload_del(&dev->offload);
out_free_candev:
free_candev(dev->netdev);
return ERR_PTR(rc);
@@ -1512,7 +1502,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
static void gs_destroy_candev(struct gs_can *dev)
{
- unregister_candev(dev->netdev);
can_rx_offload_del(&dev->offload);
free_candev(dev->netdev);
}
@@ -1590,21 +1579,16 @@ static int gs_usb_probe(struct usb_interface *intf,
for (i = 0; i < icount; i++) {
unsigned int hf_size_rx = 0;
+ struct gs_can *dev;
- parent->canch[i] = gs_make_candev(i, intf, &dconf);
- if (IS_ERR_OR_NULL(parent->canch[i])) {
+ dev = gs_make_candev(i, intf, &dconf);
+ if (IS_ERR_OR_NULL(dev)) {
/* save error code to return later */
- rc = PTR_ERR(parent->canch[i]);
+ rc = PTR_ERR(dev);
- /* on failure destroy previously created candevs */
- icount = i;
- for (i = 0; i < icount; i++)
- gs_destroy_candev(parent->canch[i]);
-
- usb_kill_anchored_urbs(&parent->rx_submitted);
- kfree(parent);
- return rc;
+ goto out_gs_destroy_candev;
}
+ parent->canch[i] = dev;
parent->canch[i]->parent = parent;
/* set RX packet size based on FD and if hardware
@@ -1624,7 +1608,37 @@ static int gs_usb_probe(struct usb_interface *intf,
parent->hf_size_rx = max(parent->hf_size_rx, hf_size_rx);
}
+ for (i = 0; i < icount; i++) {
+ struct gs_can *dev = parent->canch[i];
+
+ rc = register_candev(dev->netdev);
+ if (rc) {
+ const unsigned int cur = i;
+
+ dev_err(&intf->dev,
+ "Couldn't register candev for channel %d (%pe)\n",
+ i, ERR_PTR(rc));
+
+ for (i = 0; i < cur; i++)
+ unregister_candev(parent->canch[i]->netdev);
+
+ goto out_gs_destroy_candev;
+ }
+ }
+
return 0;
+
+out_gs_destroy_candev:
+ for (i = 0; i < parent->channel_cnt; i++) {
+ if (!parent->canch[i])
+ continue;
+
+ gs_destroy_candev(parent->canch[i]);
+ }
+
+ kfree(parent);
+
+ return rc;
}
static void gs_usb_disconnect(struct usb_interface *intf)
@@ -1640,8 +1654,10 @@ static void gs_usb_disconnect(struct usb_interface *intf)
}
for (i = 0; i < parent->channel_cnt; i++)
- if (parent->canch[i])
- gs_destroy_candev(parent->canch[i]);
+ unregister_candev(parent->canch[i]->netdev);
+
+ for (i = 0; i < parent->channel_cnt; i++)
+ gs_destroy_candev(parent->canch[i]);
kfree(parent);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH can-next v7 3/6] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 1/6] can: gs_usb: gs_make_candev(): check can_rx_offload_add_manual() return value Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 2/6] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
@ 2026-11-14 15:17 ` Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 4/6] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish Marc Kleine-Budde
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
If the allocation of an SKB fails in gs_usb_receive_bulk_callback(), the
function neither updates the statistics nor checks whether an overflow flag
is set in the host frame.
Instead of directly resubmitting the URB, first update the dropped RX
statistics then check if an overflow flag is set.
Closes: https://sashiko.dev/#/bug/linux-7b3fe6a0-4628-4d0e-aec0-69f4bf8ad5d4
Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices")
Fixes: 26949ac935e3 ("can: gs_usb: add CAN-FD support")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 6997cc8a6b2d..1db2d660355d 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -673,8 +673,11 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX) { /* normal rx */
if (hf->flags & GS_CAN_FLAG_FD) {
skb = alloc_canfd_skb(netdev, &cfd);
- if (!skb)
- goto resubmit_urb;
+ if (!skb) {
+ stats->rx_dropped++;
+
+ goto check_overflow;
+ }
cfd->can_id = le32_to_cpu(hf->can_id);
cfd->len = data_length;
@@ -686,8 +689,11 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
memcpy(cfd->data, hf->canfd->data, data_length);
} else {
skb = alloc_can_skb(netdev, &cf);
- if (!skb)
- goto resubmit_urb;
+ if (!skb) {
+ stats->rx_dropped++;
+
+ goto check_overflow;
+ }
cf->can_id = le32_to_cpu(hf->can_id);
can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
@@ -728,6 +734,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
netif_wake_queue(netdev);
}
+check_overflow:
if (hf->flags & GS_CAN_FLAG_OVERFLOW) {
stats->rx_over_errors++;
stats->rx_errors++;
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH can-next v7 4/6] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
` (2 preceding siblings ...)
2026-11-14 15:17 ` [PATCH can-next v7 3/6] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
@ 2026-11-14 15:17 ` Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 5/6] can: gs_usb: fix hardware timestamp state for mixed channels Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 6/6] can: gs_usb: properly shut down timestamp worker Marc Kleine-Budde
5 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
If the overflow flag is set for a host frame and the allocation of the
error SKB fails, the URB should not be resubmitted immediately.
Instead, call can_rx_offload_irq_finish(), since an SKB may have been added
to rx-offload.
Closes: https://sashiko.dev/#/bug/linux-441137e2-cd75-411f-9ff5-dc4d473c5ddb
Fixes: 24bc41b45583 ("can: gs_usb: convert to NAPI/rx-offload to avoid OoO reception")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 1db2d660355d..980c4a748c94 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -741,7 +741,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
skb = alloc_can_err_skb(netdev, &cf);
if (!skb)
- goto resubmit_urb;
+ goto can_rx_offload_irq_finish;
cf->can_id |= CAN_ERR_CRTL;
cf->len = CAN_ERR_DLC;
@@ -750,6 +750,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
gs_usb_rx_offload(dev, skb, hf);
}
+can_rx_offload_irq_finish:
can_rx_offload_irq_finish(&dev->offload);
resubmit_urb:
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH can-next v7 5/6] can: gs_usb: fix hardware timestamp state for mixed channels
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
` (3 preceding siblings ...)
2026-11-14 15:17 ` [PATCH can-next v7 4/6] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish Marc Kleine-Budde
@ 2026-11-14 15:17 ` Marc Kleine-Budde
2026-11-14 15:31 ` sashiko-bot
2026-11-14 15:17 ` [PATCH can-next v7 6/6] can: gs_usb: properly shut down timestamp worker Marc Kleine-Budde
5 siblings, 1 reply; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde,
Shuangpeng Bai, stable, Vadim Fedorenko
From: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
For hardware timestamping, the driver manages the infrastructure
(cyclecounter/timecounter) for the entire USB interface, for now assuming
that all channels share a common time base, even though each channel
individually indicates support for hardware timestamping via the
GS_CAN_FEATURE_HW_TIMESTAMP flag.
Currently both the initialization and shutdown of the HW timestamping
infrastructure is tied to the flags of the first channel opened
respectively last channel closed. This leads to problems if the first
channel opened doesn't have the timestamping feature, but the second
channel has.
Keep the initialization of the HW timestamping infrastructure in
gs_usb_timestamp_init(), and move initial time init and the initial
scheduling of the delayed worker into gs_usb_timestamp_start().
Initialize the HW timestamping infrastructure in gs_usb_probe() using
gs_usb_timestamp_init() if at least one channel has the
GS_CAN_FEATURE_HW_TIMESTAMP flag set.
Start and sync the timestamping infrastructure when opening the first
channel of a device that supports HW timestamps and stop it if the last
channel closes. Avoid the race window during timecounter_init()
(gs_usb_timestamp_read() drops the struct gs_usb::tc_lock) by reading the
initial time stamp prior taking the lock.
To simplify backporting, this change is not yet implemented in this patch,
but the next patch will switch to the new {enable,disable}_delayed_work()
API to avoid self-rescheduling the timestamp worker.
That API has been added with v6.10, commit 86898fa6b8cd ("workqueue:
Implement disable/enable for (delayed) work items").
Reported-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
Closes: https://sashiko.dev/#/bug/linux-b39360f9-6cd8-4f47-83bb-f0f78331f308
Closes: https://sashiko.dev/#/bug/linux-5f8ecd4e-344e-4ceb-9b46-886f4942a5f6
Fixes: 5886e4d5ecec ("can: gs_usb: fix time stamp counter initialization")
Cc: stable@vger.kernel.org
Cc: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
Cc: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
Co-developed-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 79 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 68 insertions(+), 11 deletions(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 980c4a748c94..b7780a23eff3 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -324,6 +324,10 @@ struct gs_can {
atomic_t active_tx_urbs;
};
+enum gs_usb_parent_flags {
+ GS_USB_PARENT_FLAGS_HW_TIMESTAMP = BIT(0),
+};
+
/* usb interface struct */
struct gs_usb {
struct usb_anchor rx_submitted;
@@ -332,11 +336,13 @@ struct gs_usb {
/* time counter for hardware timestamps */
struct cyclecounter cc;
struct timecounter tc;
- spinlock_t tc_lock; /* spinlock to guard access tc->cycle_last */
+ u32 timestamp_initial;
+ spinlock_t tc_lock; /* spinlock to guard access cc, tc, timestamp_initial */
struct delayed_work timestamp;
unsigned int hf_size_rx;
u8 active_channels;
+ u8 flags;
u8 channel_cnt;
unsigned int pipe_in;
@@ -405,6 +411,7 @@ static int gs_cmd_reset(struct gs_can *dev)
static inline int gs_usb_get_timestamp(const struct gs_usb *parent,
u32 *timestamp_p)
+ __must_not_hold(parent->tc_lock)
{
__le32 timestamp;
int rc;
@@ -423,7 +430,16 @@ static inline int gs_usb_get_timestamp(const struct gs_usb *parent,
return 0;
}
-static u64 gs_usb_timestamp_read(struct cyclecounter *cc) __must_hold(&dev->tc_lock)
+static u64 gs_usb_timestamp_read_initial(struct cyclecounter *cc)
+ __must_hold(&container_of(cc, struct gs_usb, cc)->tc_lock)
+{
+ const struct gs_usb *parent = container_of(cc, struct gs_usb, cc);
+
+ return parent->timestamp_initial;
+}
+
+static u64 gs_usb_timestamp_read(struct cyclecounter *cc)
+ __must_hold(&container_of(cc, struct gs_usb, cc)->tc_lock)
{
struct gs_usb *parent = container_of(cc, struct gs_usb, cc);
u32 timestamp = 0;
@@ -475,19 +491,44 @@ static void gs_usb_timestamp_init(struct gs_usb *parent)
{
struct cyclecounter *cc = &parent->cc;
- cc->read = gs_usb_timestamp_read;
cc->mask = CYCLECOUNTER_MASK(32);
cc->shift = 32 - bits_per(NSEC_PER_SEC / GS_USB_TIMESTAMP_TIMER_HZ);
cc->mult = clocksource_hz2mult(GS_USB_TIMESTAMP_TIMER_HZ, cc->shift);
spin_lock_init(&parent->tc_lock);
- spin_lock_bh(&parent->tc_lock);
- timecounter_init(&parent->tc, &parent->cc, ktime_get_real_ns());
- spin_unlock_bh(&parent->tc_lock);
INIT_DELAYED_WORK(&parent->timestamp, gs_usb_timestamp_work);
+
+ parent->flags |= GS_USB_PARENT_FLAGS_HW_TIMESTAMP;
+}
+
+static int gs_usb_timestamp_start(struct gs_usb *parent)
+{
+ u32 timestamp = 0;
+ int err;
+
+ /* read current timestamp, might be used later for initial time stamp */
+ err = gs_usb_get_timestamp(parent, ×tamp);
+ if (err)
+ return err;
+
+ scoped_guard(spinlock_bh, &parent->tc_lock) {
+ struct cyclecounter *cc = &parent->cc;
+
+ /* gs_usb_timestamp_read() will drop the struct gs_usb::tc_lock. Avoid the race
+ * window by using gs_usb_timestamp_read_initial() to read the initial timestamp in
+ * timecounter_init(), switch to gs_usb_timestamp_read() afterwards.
+ */
+ parent->timestamp_initial = timestamp;
+ cc->read = gs_usb_timestamp_read_initial;
+ timecounter_init(&parent->tc, &parent->cc, ktime_get_real_ns());
+ cc->read = gs_usb_timestamp_read;
+ }
+
schedule_delayed_work(&parent->timestamp,
GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
+
+ return 0;
}
static void gs_usb_timestamp_stop(struct gs_usb *parent)
@@ -988,9 +1029,15 @@ static int gs_can_open(struct net_device *netdev)
can_rx_offload_enable(&dev->offload);
+ /* rely on RTNL to serialize concurrent ifup/ifdown */
+ ASSERT_RTNL();
+
if (!parent->active_channels) {
- if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
- gs_usb_timestamp_init(parent);
+ if (parent->flags & GS_USB_PARENT_FLAGS_HW_TIMESTAMP) {
+ rc = gs_usb_timestamp_start(parent);
+ if (rc)
+ goto out_can_rx_offload_disable;
+ }
for (i = 0; i < GS_MAX_RX_URBS; i++) {
u8 *buf;
@@ -1105,10 +1152,10 @@ static int gs_can_open(struct net_device *netdev)
if (!parent->active_channels) {
usb_kill_anchored_urbs(&parent->rx_submitted);
- if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+ if (parent->flags & GS_USB_PARENT_FLAGS_HW_TIMESTAMP)
gs_usb_timestamp_stop(parent);
}
-
+out_can_rx_offload_disable:
can_rx_offload_disable(&dev->offload);
close_candev(netdev);
@@ -1158,12 +1205,15 @@ static int gs_can_close(struct net_device *netdev)
netif_stop_queue(netdev);
+ /* rely on RTNL to serialize concurrent ifup/ifdown */
+ ASSERT_RTNL();
+
/* Stop polling */
parent->active_channels--;
if (!parent->active_channels) {
usb_kill_anchored_urbs(&parent->rx_submitted);
- if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+ if (parent->flags & GS_USB_PARENT_FLAGS_HW_TIMESTAMP)
gs_usb_timestamp_stop(parent);
}
@@ -1525,6 +1575,7 @@ static int gs_usb_probe(struct usb_interface *intf,
.byte_order = cpu_to_le32(0x0000beef),
};
struct gs_device_config dconf;
+ bool hw_ts_supported = false;
unsigned int icount, i;
int rc;
@@ -1599,6 +1650,9 @@ static int gs_usb_probe(struct usb_interface *intf,
parent->canch[i] = dev;
parent->canch[i]->parent = parent;
+ if (parent->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
+ hw_ts_supported = true;
+
/* set RX packet size based on FD and if hardware
* timestamps are supported.
*/
@@ -1616,6 +1670,9 @@ static int gs_usb_probe(struct usb_interface *intf,
parent->hf_size_rx = max(parent->hf_size_rx, hf_size_rx);
}
+ if (hw_ts_supported)
+ gs_usb_timestamp_init(parent);
+
for (i = 0; i < icount; i++) {
struct gs_can *dev = parent->canch[i];
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH can-next v7 6/6] can: gs_usb: properly shut down timestamp worker
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
` (4 preceding siblings ...)
2026-11-14 15:17 ` [PATCH can-next v7 5/6] can: gs_usb: fix hardware timestamp state for mixed channels Marc Kleine-Budde
@ 2026-11-14 15:17 ` Marc Kleine-Budde
5 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-11-14 15:17 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick, Maximilian Schneider,
Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde
To avoid self-rescheduling of the timestamp worker, shut it down using
disable_delayed_work_sync() instead of cancel_delayed_work_sync().
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index b7780a23eff3..b9ba3775eb60 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -498,6 +498,7 @@ static void gs_usb_timestamp_init(struct gs_usb *parent)
spin_lock_init(&parent->tc_lock);
INIT_DELAYED_WORK(&parent->timestamp, gs_usb_timestamp_work);
+ disable_delayed_work(&parent->timestamp);
parent->flags |= GS_USB_PARENT_FLAGS_HW_TIMESTAMP;
}
@@ -525,6 +526,7 @@ static int gs_usb_timestamp_start(struct gs_usb *parent)
cc->read = gs_usb_timestamp_read;
}
+ enable_delayed_work(&parent->timestamp);
schedule_delayed_work(&parent->timestamp,
GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
@@ -533,7 +535,7 @@ static int gs_usb_timestamp_start(struct gs_usb *parent)
static void gs_usb_timestamp_stop(struct gs_usb *parent)
{
- cancel_delayed_work_sync(&parent->timestamp);
+ disable_delayed_work_sync(&parent->timestamp);
}
static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH can-next v7 5/6] can: gs_usb: fix hardware timestamp state for mixed channels
2026-11-14 15:17 ` [PATCH can-next v7 5/6] can: gs_usb: fix hardware timestamp state for mixed channels Marc Kleine-Budde
@ 2026-11-14 15:31 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-11-14 15:31 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: linux-can, Oliver Hartkopp, Vincent Mailhol, Oleksij Rempel
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] can: gs_usb: invalid context-analysis lock annotations in
timestamp helpers
--
commit ac918b2b251bb4e9c64c17ed5a99e1135d686016
Author: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
can: gs_usb: fix hardware timestamp state for mixed channels
This commit initializes the hardware timestamping infrastructure during probe
whenever any channel supports GS_CAN_FEATURE_HW_TIMESTAMP, and starts or stops
it when the first or last channel is opened or closed.
> diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
> index 980c4a748c946..b7780a23eff3b 100644
> --- a/drivers/net/can/usb/gs_usb.c
> +++ b/drivers/net/can/usb/gs_usb.c
[ ... ]
> @@ -405,6 +411,7 @@ static int gs_cmd_reset(struct gs_can *dev)
>
> static inline int gs_usb_get_timestamp(const struct gs_usb *parent,
> u32 *timestamp_p)
> + __must_not_hold(parent->tc_lock)
> {
> __le32 timestamp;
> int rc;
> @@ -423,7 +430,16 @@ static inline int gs_usb_get_timestamp(const struct gs_usb *parent,
> return 0;
> }
>
> -static u64 gs_usb_timestamp_read(struct cyclecounter *cc) __must_hold(&dev->tc_lock)
> +static u64 gs_usb_timestamp_read_initial(struct cyclecounter *cc)
> + __must_hold(&container_of(cc, struct gs_usb, cc)->tc_lock)
> +{
> + const struct gs_usb *parent = container_of(cc, struct gs_usb, cc);
> +
> + return parent->timestamp_initial;
> +}
> +
> +static u64 gs_usb_timestamp_read(struct cyclecounter *cc)
> + __must_hold(&container_of(cc, struct gs_usb, cc)->tc_lock)
[Severity: Low]
Does building with CONFIG_WARN_CONTEXT_ANALYSIS_ALL=y fail on these lock
annotations?
When WARN_CONTEXT_ANALYSIS is enabled, __must_hold() expands to a Clang
requires_capability attribute on the function declarator at file scope, where
the statement expression inside container_of() is rejected as a compile error.
Calling lockdep_assert_held(&parent->tc_lock) inside the function body avoids
this, and gs_usb_get_timestamp() also needs a pointer
(__must_not_hold(&parent->tc_lock)) rather than passing parent->tc_lock by
value.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261114-gs_usb-fixes-v7-0-58b6341b1c08@pengutronix.de?part=5
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-14 15:31 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-14 15:17 [PATCH can-next v7 0/6] gs_usb: fixes Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 1/6] can: gs_usb: gs_make_candev(): check can_rx_offload_add_manual() return value Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 2/6] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 3/6] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 4/6] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish Marc Kleine-Budde
2026-11-14 15:17 ` [PATCH can-next v7 5/6] can: gs_usb: fix hardware timestamp state for mixed channels Marc Kleine-Budde
2026-11-14 15:31 ` sashiko-bot
2026-11-14 15:17 ` [PATCH can-next v7 6/6] can: gs_usb: properly shut down timestamp worker Marc Kleine-Budde
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.