Skip to content

Commit a38b800

Browse files
committed
Merge tag 'linux-can-fixes-for-6.10-20240621' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says: ==================== pull-request: can 2024-06-21 The first patch is by Oleksij Rempel, it enhances the error handling for tightly received RTS message in the j1939 protocol. Shigeru Yoshida's patch fixes a kernel information leak in j1939_send_one() in the j1939 protocol. Followed by a patch by Oleksij Rempel for the j1939 protocol, to properly recover from a CAN bus error during BAM transmission. A patch by Chen Ni properly propagates errors in the kvaser_usb driver. The last patch is by Vitor Soares, that fixes an infinite loop in the mcp251xfd driver is SPI async sending fails during xmit. * tag 'linux-can-fixes-for-6.10-20240621' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: mcp251xfd: fix infinite loop when xmit fails can: kvaser_usb: fix return value for hif_usb_send_regout net: can: j1939: recover socket queue on CAN bus error during BAM transmission net: can: j1939: Initialize unused data in j1939_send_one() net: can: j1939: enhanced error handling for tightly received RTS messages in xtp_rx_rts_session_new ==================== Link: https://patch.msgid.link/20240621121739.434355-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 3139204 + d8fb63e commit a38b800

6 files changed

Lines changed: 86 additions & 17 deletions

File tree

drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1618,11 +1618,20 @@ static int mcp251xfd_open(struct net_device *ndev)
16181618
clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
16191619
can_rx_offload_enable(&priv->offload);
16201620

1621+
priv->wq = alloc_ordered_workqueue("%s-mcp251xfd_wq",
1622+
WQ_FREEZABLE | WQ_MEM_RECLAIM,
1623+
dev_name(&spi->dev));
1624+
if (!priv->wq) {
1625+
err = -ENOMEM;
1626+
goto out_can_rx_offload_disable;
1627+
}
1628+
INIT_WORK(&priv->tx_work, mcp251xfd_tx_obj_write_sync);
1629+
16211630
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
16221631
IRQF_SHARED | IRQF_ONESHOT,
16231632
dev_name(&spi->dev), priv);
16241633
if (err)
1625-
goto out_can_rx_offload_disable;
1634+
goto out_destroy_workqueue;
16261635

16271636
err = mcp251xfd_chip_interrupts_enable(priv);
16281637
if (err)
@@ -1634,6 +1643,8 @@ static int mcp251xfd_open(struct net_device *ndev)
16341643

16351644
out_free_irq:
16361645
free_irq(spi->irq, priv);
1646+
out_destroy_workqueue:
1647+
destroy_workqueue(priv->wq);
16371648
out_can_rx_offload_disable:
16381649
can_rx_offload_disable(&priv->offload);
16391650
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
@@ -1661,6 +1672,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
16611672
hrtimer_cancel(&priv->tx_irq_timer);
16621673
mcp251xfd_chip_interrupts_disable(priv);
16631674
free_irq(ndev->irq, priv);
1675+
destroy_workqueue(priv->wq);
16641676
can_rx_offload_disable(&priv->offload);
16651677
mcp251xfd_timestamp_stop(priv);
16661678
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);

drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,39 @@ mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv,
131131
tx_obj->xfer[0].len = len;
132132
}
133133

134+
static void mcp251xfd_tx_failure_drop(const struct mcp251xfd_priv *priv,
135+
struct mcp251xfd_tx_ring *tx_ring,
136+
int err)
137+
{
138+
struct net_device *ndev = priv->ndev;
139+
struct net_device_stats *stats = &ndev->stats;
140+
unsigned int frame_len = 0;
141+
u8 tx_head;
142+
143+
tx_ring->head--;
144+
stats->tx_dropped++;
145+
tx_head = mcp251xfd_get_tx_head(tx_ring);
146+
can_free_echo_skb(ndev, tx_head, &frame_len);
147+
netdev_completed_queue(ndev, 1, frame_len);
148+
netif_wake_queue(ndev);
149+
150+
if (net_ratelimit())
151+
netdev_err(priv->ndev, "ERROR in %s: %d\n", __func__, err);
152+
}
153+
154+
void mcp251xfd_tx_obj_write_sync(struct work_struct *work)
155+
{
156+
struct mcp251xfd_priv *priv = container_of(work, struct mcp251xfd_priv,
157+
tx_work);
158+
struct mcp251xfd_tx_obj *tx_obj = priv->tx_work_obj;
159+
struct mcp251xfd_tx_ring *tx_ring = priv->tx;
160+
int err;
161+
162+
err = spi_sync(priv->spi, &tx_obj->msg);
163+
if (err)
164+
mcp251xfd_tx_failure_drop(priv, tx_ring, err);
165+
}
166+
134167
static int mcp251xfd_tx_obj_write(const struct mcp251xfd_priv *priv,
135168
struct mcp251xfd_tx_obj *tx_obj)
136169
{
@@ -162,6 +195,11 @@ static bool mcp251xfd_tx_busy(const struct mcp251xfd_priv *priv,
162195
return false;
163196
}
164197

198+
static bool mcp251xfd_work_busy(struct work_struct *work)
199+
{
200+
return work_busy(work);
201+
}
202+
165203
netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
166204
struct net_device *ndev)
167205
{
@@ -175,7 +213,8 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
175213
if (can_dev_dropped_skb(ndev, skb))
176214
return NETDEV_TX_OK;
177215

178-
if (mcp251xfd_tx_busy(priv, tx_ring))
216+
if (mcp251xfd_tx_busy(priv, tx_ring) ||
217+
mcp251xfd_work_busy(&priv->tx_work))
179218
return NETDEV_TX_BUSY;
180219

181220
tx_obj = mcp251xfd_get_tx_obj_next(tx_ring);
@@ -193,13 +232,13 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
193232
netdev_sent_queue(priv->ndev, frame_len);
194233

195234
err = mcp251xfd_tx_obj_write(priv, tx_obj);
196-
if (err)
197-
goto out_err;
198-
199-
return NETDEV_TX_OK;
200-
201-
out_err:
202-
netdev_err(priv->ndev, "ERROR in %s: %d\n", __func__, err);
235+
if (err == -EBUSY) {
236+
netif_stop_queue(ndev);
237+
priv->tx_work_obj = tx_obj;
238+
queue_work(priv->wq, &priv->tx_work);
239+
} else if (err) {
240+
mcp251xfd_tx_failure_drop(priv, tx_ring, err);
241+
}
203242

204243
return NETDEV_TX_OK;
205244
}

drivers/net/can/spi/mcp251xfd/mcp251xfd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,10 @@ struct mcp251xfd_priv {
633633
struct mcp251xfd_rx_ring *rx[MCP251XFD_FIFO_RX_NUM];
634634
struct mcp251xfd_tx_ring tx[MCP251XFD_FIFO_TX_NUM];
635635

636+
struct workqueue_struct *wq;
637+
struct work_struct tx_work;
638+
struct mcp251xfd_tx_obj *tx_work_obj;
639+
636640
DECLARE_BITMAP(flags, __MCP251XFD_FLAGS_SIZE__);
637641

638642
u8 rx_ring_num;
@@ -952,6 +956,7 @@ void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
952956
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
953957
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
954958

959+
void mcp251xfd_tx_obj_write_sync(struct work_struct *work);
955960
netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
956961
struct net_device *ndev);
957962

drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
294294
}
295295
usb_free_urb(urb);
296296

297-
return 0;
297+
return err;
298298
}
299299

300300
int kvaser_usb_can_rx_over_error(struct net_device *netdev)

net/can/j1939/main.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ MODULE_ALIAS("can-proto-" __stringify(CAN_J1939));
3030
/* CAN_HDR: #bytes before can_frame data part */
3131
#define J1939_CAN_HDR (offsetof(struct can_frame, data))
3232

33-
/* CAN_FTR: #bytes beyond data part */
34-
#define J1939_CAN_FTR (sizeof(struct can_frame) - J1939_CAN_HDR - \
35-
sizeof(((struct can_frame *)0)->data))
36-
3733
/* lowest layer */
3834
static void j1939_can_recv(struct sk_buff *iskb, void *data)
3935
{
@@ -342,7 +338,7 @@ int j1939_send_one(struct j1939_priv *priv, struct sk_buff *skb)
342338
memset(cf, 0, J1939_CAN_HDR);
343339

344340
/* make it a full can frame again */
345-
skb_put(skb, J1939_CAN_FTR + (8 - dlc));
341+
skb_put_zero(skb, 8 - dlc);
346342

347343
canid = CAN_EFF_FLAG |
348344
(skcb->priority << 26) |

net/can/j1939/transport.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,8 +1593,8 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
15931593
struct j1939_sk_buff_cb skcb = *j1939_skb_to_cb(skb);
15941594
struct j1939_session *session;
15951595
const u8 *dat;
1596+
int len, ret;
15961597
pgn_t pgn;
1597-
int len;
15981598

15991599
netdev_dbg(priv->ndev, "%s\n", __func__);
16001600

@@ -1653,7 +1653,22 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
16531653
session->tskey = priv->rx_tskey++;
16541654
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_RTS);
16551655

1656-
WARN_ON_ONCE(j1939_session_activate(session));
1656+
ret = j1939_session_activate(session);
1657+
if (ret) {
1658+
/* Entering this scope indicates an issue with the J1939 bus.
1659+
* Possible scenarios include:
1660+
* - A time lapse occurred, and a new session was initiated
1661+
* due to another packet being sent correctly. This could
1662+
* have been caused by too long interrupt, debugger, or being
1663+
* out-scheduled by another task.
1664+
* - The bus is receiving numerous erroneous packets, either
1665+
* from a malfunctioning device or during a test scenario.
1666+
*/
1667+
netdev_alert(priv->ndev, "%s: 0x%p: concurrent session with same addr (%02x %02x) is already active.\n",
1668+
__func__, session, skcb.addr.sa, skcb.addr.da);
1669+
j1939_session_put(session);
1670+
return NULL;
1671+
}
16571672

16581673
return session;
16591674
}
@@ -1681,6 +1696,8 @@ static int j1939_xtp_rx_rts_session_active(struct j1939_session *session,
16811696

16821697
j1939_session_timers_cancel(session);
16831698
j1939_session_cancel(session, J1939_XTP_ABORT_BUSY);
1699+
if (session->transmission)
1700+
j1939_session_deactivate_activate_next(session);
16841701

16851702
return -EBUSY;
16861703
}

0 commit comments

Comments
 (0)