Commit a38b800d authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-fixes-for-6.10-20240621' of...

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.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 31392048 d8fb63e4
...@@ -1618,11 +1618,20 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -1618,11 +1618,20 @@ static int mcp251xfd_open(struct net_device *ndev)
clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags); clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
can_rx_offload_enable(&priv->offload); can_rx_offload_enable(&priv->offload);
priv->wq = alloc_ordered_workqueue("%s-mcp251xfd_wq",
WQ_FREEZABLE | WQ_MEM_RECLAIM,
dev_name(&spi->dev));
if (!priv->wq) {
err = -ENOMEM;
goto out_can_rx_offload_disable;
}
INIT_WORK(&priv->tx_work, mcp251xfd_tx_obj_write_sync);
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq, err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
IRQF_SHARED | IRQF_ONESHOT, IRQF_SHARED | IRQF_ONESHOT,
dev_name(&spi->dev), priv); dev_name(&spi->dev), priv);
if (err) if (err)
goto out_can_rx_offload_disable; goto out_destroy_workqueue;
err = mcp251xfd_chip_interrupts_enable(priv); err = mcp251xfd_chip_interrupts_enable(priv);
if (err) if (err)
...@@ -1634,6 +1643,8 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -1634,6 +1643,8 @@ static int mcp251xfd_open(struct net_device *ndev)
out_free_irq: out_free_irq:
free_irq(spi->irq, priv); free_irq(spi->irq, priv);
out_destroy_workqueue:
destroy_workqueue(priv->wq);
out_can_rx_offload_disable: out_can_rx_offload_disable:
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags); set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
...@@ -1661,6 +1672,7 @@ static int mcp251xfd_stop(struct net_device *ndev) ...@@ -1661,6 +1672,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
hrtimer_cancel(&priv->tx_irq_timer); hrtimer_cancel(&priv->tx_irq_timer);
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
free_irq(ndev->irq, priv); free_irq(ndev->irq, priv);
destroy_workqueue(priv->wq);
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv); mcp251xfd_timestamp_stop(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
......
...@@ -131,6 +131,39 @@ mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv, ...@@ -131,6 +131,39 @@ mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv,
tx_obj->xfer[0].len = len; tx_obj->xfer[0].len = len;
} }
static void mcp251xfd_tx_failure_drop(const struct mcp251xfd_priv *priv,
struct mcp251xfd_tx_ring *tx_ring,
int err)
{
struct net_device *ndev = priv->ndev;
struct net_device_stats *stats = &ndev->stats;
unsigned int frame_len = 0;
u8 tx_head;
tx_ring->head--;
stats->tx_dropped++;
tx_head = mcp251xfd_get_tx_head(tx_ring);
can_free_echo_skb(ndev, tx_head, &frame_len);
netdev_completed_queue(ndev, 1, frame_len);
netif_wake_queue(ndev);
if (net_ratelimit())
netdev_err(priv->ndev, "ERROR in %s: %d\n", __func__, err);
}
void mcp251xfd_tx_obj_write_sync(struct work_struct *work)
{
struct mcp251xfd_priv *priv = container_of(work, struct mcp251xfd_priv,
tx_work);
struct mcp251xfd_tx_obj *tx_obj = priv->tx_work_obj;
struct mcp251xfd_tx_ring *tx_ring = priv->tx;
int err;
err = spi_sync(priv->spi, &tx_obj->msg);
if (err)
mcp251xfd_tx_failure_drop(priv, tx_ring, err);
}
static int mcp251xfd_tx_obj_write(const struct mcp251xfd_priv *priv, static int mcp251xfd_tx_obj_write(const struct mcp251xfd_priv *priv,
struct mcp251xfd_tx_obj *tx_obj) struct mcp251xfd_tx_obj *tx_obj)
{ {
...@@ -162,6 +195,11 @@ static bool mcp251xfd_tx_busy(const struct mcp251xfd_priv *priv, ...@@ -162,6 +195,11 @@ static bool mcp251xfd_tx_busy(const struct mcp251xfd_priv *priv,
return false; return false;
} }
static bool mcp251xfd_work_busy(struct work_struct *work)
{
return work_busy(work);
}
netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb, netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
struct net_device *ndev) struct net_device *ndev)
{ {
...@@ -175,7 +213,8 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb, ...@@ -175,7 +213,8 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
if (can_dev_dropped_skb(ndev, skb)) if (can_dev_dropped_skb(ndev, skb))
return NETDEV_TX_OK; return NETDEV_TX_OK;
if (mcp251xfd_tx_busy(priv, tx_ring)) if (mcp251xfd_tx_busy(priv, tx_ring) ||
mcp251xfd_work_busy(&priv->tx_work))
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
tx_obj = mcp251xfd_get_tx_obj_next(tx_ring); tx_obj = mcp251xfd_get_tx_obj_next(tx_ring);
...@@ -193,13 +232,13 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb, ...@@ -193,13 +232,13 @@ netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
netdev_sent_queue(priv->ndev, frame_len); netdev_sent_queue(priv->ndev, frame_len);
err = mcp251xfd_tx_obj_write(priv, tx_obj); err = mcp251xfd_tx_obj_write(priv, tx_obj);
if (err) if (err == -EBUSY) {
goto out_err; netif_stop_queue(ndev);
priv->tx_work_obj = tx_obj;
return NETDEV_TX_OK; queue_work(priv->wq, &priv->tx_work);
} else if (err) {
out_err: mcp251xfd_tx_failure_drop(priv, tx_ring, err);
netdev_err(priv->ndev, "ERROR in %s: %d\n", __func__, err); }
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -633,6 +633,10 @@ struct mcp251xfd_priv { ...@@ -633,6 +633,10 @@ struct mcp251xfd_priv {
struct mcp251xfd_rx_ring *rx[MCP251XFD_FIFO_RX_NUM]; struct mcp251xfd_rx_ring *rx[MCP251XFD_FIFO_RX_NUM];
struct mcp251xfd_tx_ring tx[MCP251XFD_FIFO_TX_NUM]; struct mcp251xfd_tx_ring tx[MCP251XFD_FIFO_TX_NUM];
struct workqueue_struct *wq;
struct work_struct tx_work;
struct mcp251xfd_tx_obj *tx_work_obj;
DECLARE_BITMAP(flags, __MCP251XFD_FLAGS_SIZE__); DECLARE_BITMAP(flags, __MCP251XFD_FLAGS_SIZE__);
u8 rx_ring_num; u8 rx_ring_num;
...@@ -952,6 +956,7 @@ void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv, ...@@ -952,6 +956,7 @@ void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv); void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv); void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
void mcp251xfd_tx_obj_write_sync(struct work_struct *work);
netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb, netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
struct net_device *ndev); struct net_device *ndev);
......
...@@ -294,7 +294,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd, ...@@ -294,7 +294,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
} }
usb_free_urb(urb); usb_free_urb(urb);
return 0; return err;
} }
int kvaser_usb_can_rx_over_error(struct net_device *netdev) int kvaser_usb_can_rx_over_error(struct net_device *netdev)
......
...@@ -30,10 +30,6 @@ MODULE_ALIAS("can-proto-" __stringify(CAN_J1939)); ...@@ -30,10 +30,6 @@ MODULE_ALIAS("can-proto-" __stringify(CAN_J1939));
/* CAN_HDR: #bytes before can_frame data part */ /* CAN_HDR: #bytes before can_frame data part */
#define J1939_CAN_HDR (offsetof(struct can_frame, data)) #define J1939_CAN_HDR (offsetof(struct can_frame, data))
/* CAN_FTR: #bytes beyond data part */
#define J1939_CAN_FTR (sizeof(struct can_frame) - J1939_CAN_HDR - \
sizeof(((struct can_frame *)0)->data))
/* lowest layer */ /* lowest layer */
static void j1939_can_recv(struct sk_buff *iskb, void *data) static void j1939_can_recv(struct sk_buff *iskb, void *data)
{ {
...@@ -342,7 +338,7 @@ int j1939_send_one(struct j1939_priv *priv, struct sk_buff *skb) ...@@ -342,7 +338,7 @@ int j1939_send_one(struct j1939_priv *priv, struct sk_buff *skb)
memset(cf, 0, J1939_CAN_HDR); memset(cf, 0, J1939_CAN_HDR);
/* make it a full can frame again */ /* make it a full can frame again */
skb_put(skb, J1939_CAN_FTR + (8 - dlc)); skb_put_zero(skb, 8 - dlc);
canid = CAN_EFF_FLAG | canid = CAN_EFF_FLAG |
(skcb->priority << 26) | (skcb->priority << 26) |
......
...@@ -1593,8 +1593,8 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv, ...@@ -1593,8 +1593,8 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
struct j1939_sk_buff_cb skcb = *j1939_skb_to_cb(skb); struct j1939_sk_buff_cb skcb = *j1939_skb_to_cb(skb);
struct j1939_session *session; struct j1939_session *session;
const u8 *dat; const u8 *dat;
int len, ret;
pgn_t pgn; pgn_t pgn;
int len;
netdev_dbg(priv->ndev, "%s\n", __func__); netdev_dbg(priv->ndev, "%s\n", __func__);
...@@ -1653,7 +1653,22 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv, ...@@ -1653,7 +1653,22 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
session->tskey = priv->rx_tskey++; session->tskey = priv->rx_tskey++;
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_RTS); j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_RTS);
WARN_ON_ONCE(j1939_session_activate(session)); ret = j1939_session_activate(session);
if (ret) {
/* Entering this scope indicates an issue with the J1939 bus.
* Possible scenarios include:
* - A time lapse occurred, and a new session was initiated
* due to another packet being sent correctly. This could
* have been caused by too long interrupt, debugger, or being
* out-scheduled by another task.
* - The bus is receiving numerous erroneous packets, either
* from a malfunctioning device or during a test scenario.
*/
netdev_alert(priv->ndev, "%s: 0x%p: concurrent session with same addr (%02x %02x) is already active.\n",
__func__, session, skcb.addr.sa, skcb.addr.da);
j1939_session_put(session);
return NULL;
}
return session; return session;
} }
...@@ -1681,6 +1696,8 @@ static int j1939_xtp_rx_rts_session_active(struct j1939_session *session, ...@@ -1681,6 +1696,8 @@ static int j1939_xtp_rx_rts_session_active(struct j1939_session *session,
j1939_session_timers_cancel(session); j1939_session_timers_cancel(session);
j1939_session_cancel(session, J1939_XTP_ABORT_BUSY); j1939_session_cancel(session, J1939_XTP_ABORT_BUSY);
if (session->transmission)
j1939_session_deactivate_activate_next(session);
return -EBUSY; return -EBUSY;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment