Commit 8ec205e8 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'linux-can-fixes-for-6.18-20251126' of...

Merge tag 'linux-can-fixes-for-6.18-20251126' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2025-11-26

this is a pull request of 8 patches for net/main.

Seungjin Bae provides a patch for the kvaser_usb driver to fix a
potential infinite loop in the USB data stream command parser.

Thomas Mühlbacher's patch for the sja1000 driver IRQ handler's max
loop handling, that might lead to unhandled interrupts.

3 patches by me for the gs_usb driver fix handling of failed transmit
URBs and add checking of the actual length of received URBs before
accessing the data.

The next patch is by me and is a port of Thomas Mühlbacher's patch
(fix IRQ handler's max loop handling, that might lead to unhandled
interrupts.) to the sun4i_can driver.

Biju Das provides a patch for the rcar_canfd driver to fix the CAN-FD
mode setting.

The last patch is by Shaurya Rane for the em_canid filter to ensure
that the complete CAN frame is present in the linear data buffer
before accessing it.

* tag 'linux-can-fixes-for-6.18-20251126' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  net/sched: em_canid: fix uninit-value in em_canid_match
  can: rcar_canfd: Fix CAN-FD mode as default
  can: sun4i_can: sun4i_can_interrupt(): fix max irq loop handling
  can: gs_usb: gs_usb_receive_bulk_callback(): check actual_length before accessing data
  can: gs_usb: gs_usb_receive_bulk_callback(): check actual_length before accessing header
  can: gs_usb: gs_usb_xmit_callback(): fix handling of failed transmitted URBs
  can: sja1000: fix max irq loop handling
  can: kvaser_usb: leaf: Fix potential infinite loop in command parsers
====================

Link: https://patch.msgid.link/20251126155713.217105-1-mkl@pengutronix.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 5ffcb7b8 0c922106
Loading
Loading
Loading
Loading
+31 −22
Original line number Diff line number Diff line
@@ -709,6 +709,11 @@ static void rcar_canfd_set_bit_reg(void __iomem *addr, u32 val)
	rcar_canfd_update(val, val, addr);
}

static void rcar_canfd_clear_bit_reg(void __iomem *addr, u32 val)
{
	rcar_canfd_update(val, 0, addr);
}

static void rcar_canfd_update_bit_reg(void __iomem *addr, u32 mask, u32 val)
{
	rcar_canfd_update(mask, val, addr);
@@ -755,25 +760,6 @@ static void rcar_canfd_set_rnc(struct rcar_canfd_global *gpriv, unsigned int ch,
	rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG(w), rnc);
}

static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv)
{
	if (gpriv->info->ch_interface_mode) {
		u32 ch, val = gpriv->fdmode ? RCANFD_GEN4_FDCFG_FDOE
					    : RCANFD_GEN4_FDCFG_CLOE;

		for_each_set_bit(ch, &gpriv->channels_mask,
				 gpriv->info->max_channels)
			rcar_canfd_set_bit_reg(&gpriv->fcbase[ch].cfdcfg, val);
	} else {
		if (gpriv->fdmode)
			rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
					   RCANFD_GRMCFG_RCMC);
		else
			rcar_canfd_clear_bit(gpriv->base, RCANFD_GRMCFG,
					     RCANFD_GRMCFG_RCMC);
	}
}

static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
{
	struct device *dev = &gpriv->pdev->dev;
@@ -806,6 +792,16 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
	/* Reset Global error flags */
	rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0);

	/* Set the controller into appropriate mode */
	if (!gpriv->info->ch_interface_mode) {
		if (gpriv->fdmode)
			rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
					   RCANFD_GRMCFG_RCMC);
		else
			rcar_canfd_clear_bit(gpriv->base, RCANFD_GRMCFG,
					     RCANFD_GRMCFG_RCMC);
	}

	/* Transition all Channels to reset mode */
	for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
		rcar_canfd_clear_bit(gpriv->base,
@@ -823,10 +819,23 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
			dev_dbg(dev, "channel %u reset failed\n", ch);
			return err;
		}
	}

		/* Set the controller into appropriate mode */
	rcar_canfd_set_mode(gpriv);
		if (gpriv->info->ch_interface_mode) {
			/* Do not set CLOE and FDOE simultaneously */
			if (!gpriv->fdmode) {
				rcar_canfd_clear_bit_reg(&gpriv->fcbase[ch].cfdcfg,
							 RCANFD_GEN4_FDCFG_FDOE);
				rcar_canfd_set_bit_reg(&gpriv->fcbase[ch].cfdcfg,
						       RCANFD_GEN4_FDCFG_CLOE);
			} else {
				rcar_canfd_clear_bit_reg(&gpriv->fcbase[ch].cfdcfg,
							 RCANFD_GEN4_FDCFG_FDOE);
				rcar_canfd_clear_bit_reg(&gpriv->fcbase[ch].cfdcfg,
							 RCANFD_GEN4_FDCFG_CLOE);
			}
		}
	}

	return 0;
}
+2 −2
Original line number Diff line number Diff line
@@ -548,8 +548,8 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
	if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
		goto out;

	while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
	       (n < SJA1000_MAX_IRQ)) {
	while ((n < SJA1000_MAX_IRQ) &&
	       (isrc = priv->read_reg(priv, SJA1000_IR))) {

		status = priv->read_reg(priv, SJA1000_SR);
		/* check for absent controller due to hw unplug */
+2 −2
Original line number Diff line number Diff line
@@ -657,8 +657,8 @@ static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id)
	u8 isrc, status;
	int n = 0;

	while ((isrc = readl(priv->base + SUN4I_REG_INT_ADDR)) &&
	       (n < SUN4I_CAN_MAX_IRQ)) {
	while ((n < SUN4I_CAN_MAX_IRQ) &&
	       (isrc = readl(priv->base + SUN4I_REG_INT_ADDR))) {
		n++;
		status = readl(priv->base + SUN4I_REG_STA_ADDR);

+87 −13
Original line number Diff line number Diff line
@@ -261,7 +261,13 @@ struct canfd_quirk {
	u8 quirk;
} __packed;

/* struct gs_host_frame::echo_id == GS_HOST_FRAME_ECHO_ID_RX indicates
 * a regular RX'ed CAN frame
 */
#define GS_HOST_FRAME_ECHO_ID_RX 0xffffffff

struct gs_host_frame {
	struct_group(header,
		u32 echo_id;
		__le32 can_id;

@@ -269,6 +275,7 @@ struct gs_host_frame {
		u8 channel;
		u8 flags;
		u8 reserved;
	);

	union {
		DECLARE_FLEX_ARRAY(struct classic_can, classic_can);
@@ -568,6 +575,37 @@ gs_usb_get_echo_skb(struct gs_can *dev, struct sk_buff *skb,
	return len;
}

static unsigned int
gs_usb_get_minimum_rx_length(const struct gs_can *dev, const struct gs_host_frame *hf,
			     unsigned int *data_length_p)
{
	unsigned int minimum_length, data_length = 0;

	if (hf->flags & GS_CAN_FLAG_FD) {
		if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX)
			data_length = can_fd_dlc2len(hf->can_dlc);

		if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
			/* timestamp follows data field of max size */
			minimum_length = struct_size(hf, canfd_ts, 1);
		else
			minimum_length = sizeof(hf->header) + data_length;
	} else {
		if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX &&
		    !(hf->can_id & cpu_to_le32(CAN_RTR_FLAG)))
			data_length = can_cc_dlc2len(hf->can_dlc);

		if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
			/* timestamp follows data field of max size */
			minimum_length = struct_size(hf, classic_can_ts, 1);
		else
			minimum_length = sizeof(hf->header) + data_length;
	}

	*data_length_p = data_length;
	return minimum_length;
}

static void gs_usb_receive_bulk_callback(struct urb *urb)
{
	struct gs_usb *parent = urb->context;
@@ -576,6 +614,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
	int rc;
	struct net_device_stats *stats;
	struct gs_host_frame *hf = urb->transfer_buffer;
	unsigned int minimum_length, data_length;
	struct gs_tx_context *txc;
	struct can_frame *cf;
	struct canfd_frame *cfd;
@@ -594,6 +633,15 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
		return;
	}

	minimum_length = sizeof(hf->header);
	if (urb->actual_length < minimum_length) {
		dev_err_ratelimited(&parent->udev->dev,
				    "short read (actual_length=%u, minimum_length=%u)\n",
				    urb->actual_length, minimum_length);

		goto resubmit_urb;
	}

	/* device reports out of range channel id */
	if (hf->channel >= parent->channel_cnt)
		goto device_detach;
@@ -609,20 +657,33 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
	if (!netif_running(netdev))
		goto resubmit_urb;

	if (hf->echo_id == -1) { /* normal rx */
	minimum_length = gs_usb_get_minimum_rx_length(dev, hf, &data_length);
	if (urb->actual_length < minimum_length) {
		stats->rx_errors++;
		stats->rx_length_errors++;

		if (net_ratelimit())
			netdev_err(netdev,
				   "short read (actual_length=%u, minimum_length=%u)\n",
				   urb->actual_length, minimum_length);

		goto resubmit_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)
				return;

			cfd->can_id = le32_to_cpu(hf->can_id);
			cfd->len = can_fd_dlc2len(hf->can_dlc);
			cfd->len = data_length;
			if (hf->flags & GS_CAN_FLAG_BRS)
				cfd->flags |= CANFD_BRS;
			if (hf->flags & GS_CAN_FLAG_ESI)
				cfd->flags |= CANFD_ESI;

			memcpy(cfd->data, hf->canfd->data, cfd->len);
			memcpy(cfd->data, hf->canfd->data, data_length);
		} else {
			skb = alloc_can_skb(netdev, &cf);
			if (!skb)
@@ -631,7 +692,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
			cf->can_id = le32_to_cpu(hf->can_id);
			can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);

			memcpy(cf->data, hf->classic_can->data, 8);
			memcpy(cf->data, hf->classic_can->data, data_length);

			/* ERROR frames tell us information about the controller */
			if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG)
@@ -687,7 +748,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
resubmit_urb:
	usb_fill_bulk_urb(urb, parent->udev,
			  parent->pipe_in,
			  hf, dev->parent->hf_size_rx,
			  hf, parent->hf_size_rx,
			  gs_usb_receive_bulk_callback, parent);

	rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -750,8 +811,21 @@ static void gs_usb_xmit_callback(struct urb *urb)
	struct gs_can *dev = txc->dev;
	struct net_device *netdev = dev->netdev;

	if (urb->status)
		netdev_info(netdev, "usb xmit fail %u\n", txc->echo_id);
	if (!urb->status)
		return;

	if (urb->status != -ESHUTDOWN && net_ratelimit())
		netdev_info(netdev, "failed to xmit URB %u: %pe\n",
			    txc->echo_id, ERR_PTR(urb->status));

	netdev->stats.tx_dropped++;
	netdev->stats.tx_errors++;

	can_free_echo_skb(netdev, txc->echo_id, NULL);
	gs_free_tx_context(txc);
	atomic_dec(&dev->active_tx_urbs);

	netif_wake_queue(netdev);
}

static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
+2 −2
Original line number Diff line number Diff line
@@ -685,7 +685,7 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
			 * for further details.
			 */
			if (tmp->len == 0) {
				pos = round_up(pos,
				pos = round_up(pos + 1,
					       le16_to_cpu
						(dev->bulk_in->wMaxPacketSize));
				continue;
@@ -1732,7 +1732,7 @@ static void kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb *dev,
		 * number of events in case of a heavy rx load on the bus.
		 */
		if (cmd->len == 0) {
			pos = round_up(pos, le16_to_cpu
			pos = round_up(pos + 1, le16_to_cpu
						(dev->bulk_in->wMaxPacketSize));
			continue;
		}
Loading