Commit d509d129 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge tag 'linux-can-fixes-for-6.14-20250314' of...

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

Marc Kleine-Budde says:

====================
pull-request: can 2025-03-14

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

The first patch is by Vincent Mailhol and fixes an out of bound read
in strscpy() in the ucan driver.

Oliver Hartkopp contributes a patch for the af_can statistics to use
atomic access in the hot path.

The next 2 patches are by Biju Das, target the rcar_canfd driver and
fix the page entries in the AFL list.

The 2 patches by Haibo Chen for the flexcan driver fix the suspend and
resume functions.

linux-can-fixes-for-6.14-20250314

* tag 'linux-can-fixes-for-6.14-20250314' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: flexcan: disable transceiver during system PM
  can: flexcan: only change CAN state when link up in system PM
  can: rcar_canfd: Fix page entries in the AFL list
  dt-bindings: can: renesas,rcar-canfd: Fix typo in pattern properties for R-Car V4M
  can: statistics: use atomic access in hot path
  can: ucan: fix out of bound read in strscpy() source
====================

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


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents daa624d3 52d48a3d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -170,7 +170,7 @@ allOf:
            const: renesas,r8a779h0-canfd
    then:
      patternProperties:
        "^channel[5-7]$": false
        "^channel[4-7]$": false
    else:
      if:
        not:
+15 −3
Original line number Diff line number Diff line
@@ -2260,14 +2260,19 @@ static int __maybe_unused flexcan_suspend(struct device *device)

			flexcan_chip_interrupts_disable(dev);

			err = flexcan_transceiver_disable(priv);
			if (err)
				return err;

			err = pinctrl_pm_select_sleep_state(device);
			if (err)
				return err;
		}
		netif_stop_queue(dev);
		netif_device_detach(dev);
	}

		priv->can.state = CAN_STATE_SLEEPING;
	}

	return 0;
}
@@ -2278,7 +2283,6 @@ static int __maybe_unused flexcan_resume(struct device *device)
	struct flexcan_priv *priv = netdev_priv(dev);
	int err;

	priv->can.state = CAN_STATE_ERROR_ACTIVE;
	if (netif_running(dev)) {
		netif_device_attach(dev);
		netif_start_queue(dev);
@@ -2292,12 +2296,20 @@ static int __maybe_unused flexcan_resume(struct device *device)
			if (err)
				return err;

			err = flexcan_chip_start(dev);
			err = flexcan_transceiver_enable(priv);
			if (err)
				return err;

			err = flexcan_chip_start(dev);
			if (err) {
				flexcan_transceiver_disable(priv);
				return err;
			}

			flexcan_chip_interrupts_enable(dev);
		}

		priv->can.state = CAN_STATE_ERROR_ACTIVE;
	}

	return 0;
+11 −17
Original line number Diff line number Diff line
@@ -787,22 +787,14 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
}

static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
					   u32 ch)
					   u32 ch, u32 rule_entry)
{
	u32 cfg;
	int offset, start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
	int offset, page, num_rules = RCANFD_CHANNEL_NUMRULES;
	u32 rule_entry_index = rule_entry % 16;
	u32 ridx = ch + RCANFD_RFFIFO_IDX;

	if (ch == 0) {
		start = 0; /* Channel 0 always starts from 0th rule */
	} else {
		/* Get number of Channel 0 rules and adjust */
		cfg = rcar_canfd_read(gpriv->base, RCANFD_GAFLCFG(ch));
		start = RCANFD_GAFLCFG_GETRNC(gpriv, 0, cfg);
	}

	/* Enable write access to entry */
	page = RCANFD_GAFL_PAGENUM(start);
	page = RCANFD_GAFL_PAGENUM(rule_entry);
	rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLECTR,
			   (RCANFD_GAFLECTR_AFLPN(gpriv, page) |
			    RCANFD_GAFLECTR_AFLDAE));
@@ -818,13 +810,13 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
		offset = RCANFD_C_GAFL_OFFSET;

	/* Accept all IDs */
	rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, start), 0);
	rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, rule_entry_index), 0);
	/* IDE or RTR is not considered for matching */
	rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, start), 0);
	rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, rule_entry_index), 0);
	/* Any data length accepted */
	rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, start), 0);
	rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, rule_entry_index), 0);
	/* Place the msg in corresponding Rx FIFO entry */
	rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, start),
	rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, rule_entry_index),
			   RCANFD_GAFLP1_GAFLFDP(ridx));

	/* Disable write access to page */
@@ -1851,6 +1843,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
	unsigned long channels_mask = 0;
	int err, ch_irq, g_irq;
	int g_err_irq, g_recc_irq;
	u32 rule_entry = 0;
	bool fdmode = true;			/* CAN FD only mode - default */
	char name[9] = "channelX";
	int i;
@@ -2023,7 +2016,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
		rcar_canfd_configure_tx(gpriv, ch);

		/* Configure receive rules */
		rcar_canfd_configure_afl_rules(gpriv, ch);
		rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
		rule_entry += RCANFD_CHANNEL_NUMRULES;
	}

	/* Configure common interrupts */
+18 −25
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ union ucan_ctl_payload {
	 */
	struct ucan_ctl_cmd_get_protocol_version cmd_get_protocol_version;

	u8 raw[128];
	u8 fw_str[128];
} __packed;

enum {
@@ -424,18 +424,20 @@ static int ucan_ctrl_command_out(struct ucan_priv *up,
			       UCAN_USB_CTL_PIPE_TIMEOUT);
}

static int ucan_device_request_in(struct ucan_priv *up,
				  u8 cmd, u16 subcmd, u16 datalen)
static void ucan_get_fw_str(struct ucan_priv *up, char *fw_str, size_t size)
{
	return usb_control_msg(up->udev,
			       usb_rcvctrlpipe(up->udev, 0),
			       cmd,
			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       subcmd,
			       0,
			       up->ctl_msg_buffer,
			       datalen,
	int ret;

	ret = usb_control_msg(up->udev, usb_rcvctrlpipe(up->udev, 0),
			      UCAN_DEVICE_GET_FW_STRING,
			      USB_DIR_IN | USB_TYPE_VENDOR |
			      USB_RECIP_DEVICE,
			      0, 0, fw_str, size - 1,
			      UCAN_USB_CTL_PIPE_TIMEOUT);
	if (ret > 0)
		fw_str[ret] = '\0';
	else
		strscpy(fw_str, "unknown", size);
}

/* Parse the device information structure reported by the device and
@@ -1314,7 +1316,6 @@ static int ucan_probe(struct usb_interface *intf,
	u8 in_ep_addr;
	u8 out_ep_addr;
	union ucan_ctl_payload *ctl_msg_buffer;
	char firmware_str[sizeof(union ucan_ctl_payload) + 1];

	udev = interface_to_usbdev(intf);

@@ -1527,17 +1528,6 @@ static int ucan_probe(struct usb_interface *intf,
	 */
	ucan_parse_device_info(up, &ctl_msg_buffer->cmd_get_device_info);

	/* just print some device information - if available */
	ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
				     sizeof(union ucan_ctl_payload));
	if (ret > 0) {
		/* copy string while ensuring zero termination */
		strscpy(firmware_str, up->ctl_msg_buffer->raw,
			sizeof(union ucan_ctl_payload) + 1);
	} else {
		strcpy(firmware_str, "unknown");
	}

	/* device is compatible, reset it */
	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
	if (ret < 0)
@@ -1555,7 +1545,10 @@ static int ucan_probe(struct usb_interface *intf,

	/* initialisation complete, log device info */
	netdev_info(up->netdev, "registered device\n");
	netdev_info(up->netdev, "firmware string: %s\n", firmware_str);
	ucan_get_fw_str(up, up->ctl_msg_buffer->fw_str,
			sizeof(up->ctl_msg_buffer->fw_str));
	netdev_info(up->netdev, "firmware string: %s\n",
		    up->ctl_msg_buffer->fw_str);

	/* success */
	return 0;
+6 −6
Original line number Diff line number Diff line
@@ -287,8 +287,8 @@ int can_send(struct sk_buff *skb, int loop)
		netif_rx(newskb);

	/* update statistics */
	pkg_stats->tx_frames++;
	pkg_stats->tx_frames_delta++;
	atomic_long_inc(&pkg_stats->tx_frames);
	atomic_long_inc(&pkg_stats->tx_frames_delta);

	return 0;

@@ -647,8 +647,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
	int matches;

	/* update statistics */
	pkg_stats->rx_frames++;
	pkg_stats->rx_frames_delta++;
	atomic_long_inc(&pkg_stats->rx_frames);
	atomic_long_inc(&pkg_stats->rx_frames_delta);

	/* create non-zero unique skb identifier together with *skb */
	while (!(can_skb_prv(skb)->skbcnt))
@@ -669,8 +669,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
	consume_skb(skb);

	if (matches > 0) {
		pkg_stats->matches++;
		pkg_stats->matches_delta++;
		atomic_long_inc(&pkg_stats->matches);
		atomic_long_inc(&pkg_stats->matches_delta);
	}
}

Loading