mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
linux-can-fixes-for-7.0-20260302
-----BEGIN PGP SIGNATURE----- iIkEABYKADEWIQSl+MghEFFAdY3pYJLMOmT6rpmt0gUCaaVwehMcbWtsQHBlbmd1 dHJvbml4LmRlAAoJEMw6ZPquma3SqFUA/ihDNaZuD1HDNZ6tFugz4gcvytH4LT+R CRZXS+a1FRLyAQCuTiN1k080l4pj0sVDNlkymjxcn7a8RZ+Dk/Wy3b7JDg== =e56S -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-7.0-20260302' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2026-03-02 The first 2 patches are by Oliver Hartkopp. The first fixes the locking for CAN Broadcast Manager op runtime updates, the second fixes the packet statisctics for the CAN dummy driver. Alban Bedel's patch fixes a potential problem in the error path of the mcp251x's ndo_open callback. A patch by Ziyi Guo add USB endpoint type validation to the esd_usb driver. The next 6 patches are by Greg Kroah-Hartman and fix URB data parsing for the ems_usb and ucan driver, fix URB anchoring in the etas_es58x, and in the f81604 driver fix URB data parsing, add URB error handling and fix URB anchoring. A patch by me targets the gs_usb driver and fixes interoperability with the CANable-2.5 firmware by always configuring the bit rate before starting the device. The last patch is by Frank Li and fixes a CHECK_DTBS warning for the nxp,sja1000 dt-binding. * tag 'linux-can-fixes-for-7.0-20260302' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: dt-bindings: net: can: nxp,sja1000: add reference to mc-peripheral-props.yaml can: gs_usb: gs_can_open(): always configure bitrates before starting device can: usb: f81604: correctly anchor the urb in the read bulk callback can: usb: f81604: handle bulk write errors properly can: usb: f81604: handle short interrupt urb messages properly can: usb: etas_es58x: correctly anchor the urb in the read bulk callback can: ucan: Fix infinite loop from zero-length messages can: ems_usb: ems_usb_read_bulk_callback(): check the proper length of a message can: esd_usb: add endpoint type validation can: mcp251x: fix deadlock in error path of mcp251x_open can: dummy_can: dummy_can_init(): fix packet statistics can: bcm: fix locking for bcm_op runtime updates ==================== Link: https://patch.msgid.link/20260302152755.1700177-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c649e99764
10 changed files with 104 additions and 28 deletions
|
|
@ -87,6 +87,7 @@ required:
|
|||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
- $ref: /schemas/memory-controllers/mc-peripheral-props.yaml
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ static int __init dummy_can_init(void)
|
|||
|
||||
dev->netdev_ops = &dummy_can_netdev_ops;
|
||||
dev->ethtool_ops = &dummy_can_ethtool_ops;
|
||||
dev->flags |= IFF_ECHO; /* enable echo handling */
|
||||
priv = netdev_priv(dev);
|
||||
priv->can.bittiming_const = &dummy_can_bittiming_const;
|
||||
priv->can.bitrate_max = 20 * MEGA /* BPS */;
|
||||
|
|
|
|||
|
|
@ -1214,6 +1214,7 @@ static int mcp251x_open(struct net_device *net)
|
|||
{
|
||||
struct mcp251x_priv *priv = netdev_priv(net);
|
||||
struct spi_device *spi = priv->spi;
|
||||
bool release_irq = false;
|
||||
unsigned long flags = 0;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1257,12 +1258,24 @@ static int mcp251x_open(struct net_device *net)
|
|||
return 0;
|
||||
|
||||
out_free_irq:
|
||||
free_irq(spi->irq, priv);
|
||||
/* The IRQ handler might be running, and if so it will be waiting
|
||||
* for the lock. But free_irq() must wait for the handler to finish
|
||||
* so calling it here would deadlock.
|
||||
*
|
||||
* Setting priv->force_quit will let the handler exit right away
|
||||
* without any access to the hardware. This make it safe to call
|
||||
* free_irq() after the lock is released.
|
||||
*/
|
||||
priv->force_quit = 1;
|
||||
release_irq = true;
|
||||
|
||||
mcp251x_hw_sleep(spi);
|
||||
out_close:
|
||||
mcp251x_power_enable(priv->transceiver, 0);
|
||||
close_candev(net);
|
||||
mutex_unlock(&priv->mcp_lock);
|
||||
if (release_irq)
|
||||
free_irq(spi->irq, priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -445,6 +445,11 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
|
|||
start = CPC_HEADER_SIZE;
|
||||
|
||||
while (msg_count) {
|
||||
if (start + CPC_MSG_HEADER_LEN > urb->actual_length) {
|
||||
netdev_err(netdev, "format error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
msg = (struct ems_cpc_msg *)&ibuf[start];
|
||||
|
||||
switch (msg->type) {
|
||||
|
|
@ -474,7 +479,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
|
|||
start += CPC_MSG_HEADER_LEN + msg->length;
|
||||
msg_count--;
|
||||
|
||||
if (start > urb->transfer_buffer_length) {
|
||||
if (start > urb->actual_length) {
|
||||
netdev_err(netdev, "format error\n");
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,9 @@ struct esd_usb {
|
|||
|
||||
struct usb_anchor rx_submitted;
|
||||
|
||||
unsigned int rx_pipe;
|
||||
unsigned int tx_pipe;
|
||||
|
||||
int net_count;
|
||||
u32 version;
|
||||
int rxinitdone;
|
||||
|
|
@ -537,7 +540,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb)
|
|||
}
|
||||
|
||||
resubmit_urb:
|
||||
usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
|
||||
usb_fill_bulk_urb(urb, dev->udev, dev->rx_pipe,
|
||||
urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE,
|
||||
esd_usb_read_bulk_callback, dev);
|
||||
|
||||
|
|
@ -626,9 +629,7 @@ static int esd_usb_send_msg(struct esd_usb *dev, union esd_usb_msg *msg)
|
|||
{
|
||||
int actual_length;
|
||||
|
||||
return usb_bulk_msg(dev->udev,
|
||||
usb_sndbulkpipe(dev->udev, 2),
|
||||
msg,
|
||||
return usb_bulk_msg(dev->udev, dev->tx_pipe, msg,
|
||||
msg->hdr.len * sizeof(u32), /* convert to # of bytes */
|
||||
&actual_length,
|
||||
1000);
|
||||
|
|
@ -639,12 +640,8 @@ static int esd_usb_wait_msg(struct esd_usb *dev,
|
|||
{
|
||||
int actual_length;
|
||||
|
||||
return usb_bulk_msg(dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, 1),
|
||||
msg,
|
||||
sizeof(*msg),
|
||||
&actual_length,
|
||||
1000);
|
||||
return usb_bulk_msg(dev->udev, dev->rx_pipe, msg,
|
||||
sizeof(*msg), &actual_length, 1000);
|
||||
}
|
||||
|
||||
static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
|
||||
|
|
@ -677,8 +674,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
|
|||
|
||||
urb->transfer_dma = buf_dma;
|
||||
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, 1),
|
||||
usb_fill_bulk_urb(urb, dev->udev, dev->rx_pipe,
|
||||
buf, ESD_USB_RX_BUFFER_SIZE,
|
||||
esd_usb_read_bulk_callback, dev);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
|
@ -903,7 +899,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
|
|||
/* hnd must not be 0 - MSB is stripped in txdone handling */
|
||||
msg->tx.hnd = BIT(31) | i; /* returned in TX done message */
|
||||
|
||||
usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
|
||||
usb_fill_bulk_urb(urb, dev->udev, dev->tx_pipe, buf,
|
||||
msg->hdr.len * sizeof(u32), /* convert to # of bytes */
|
||||
esd_usb_write_bulk_callback, context);
|
||||
|
||||
|
|
@ -1298,10 +1294,16 @@ done:
|
|||
static int esd_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_in, *ep_out;
|
||||
struct esd_usb *dev;
|
||||
union esd_usb_msg *msg;
|
||||
int i, err;
|
||||
|
||||
err = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev = kzalloc_obj(*dev);
|
||||
if (!dev) {
|
||||
err = -ENOMEM;
|
||||
|
|
@ -1309,6 +1311,8 @@ static int esd_usb_probe(struct usb_interface *intf,
|
|||
}
|
||||
|
||||
dev->udev = interface_to_usbdev(intf);
|
||||
dev->rx_pipe = usb_rcvbulkpipe(dev->udev, ep_in->bEndpointAddress);
|
||||
dev->tx_pipe = usb_sndbulkpipe(dev->udev, ep_out->bEndpointAddress);
|
||||
|
||||
init_usb_anchor(&dev->rx_submitted);
|
||||
|
||||
|
|
|
|||
|
|
@ -1461,12 +1461,18 @@ static void es58x_read_bulk_callback(struct urb *urb)
|
|||
}
|
||||
|
||||
resubmit_urb:
|
||||
usb_anchor_urb(urb, &es58x_dev->rx_urbs);
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
usb_unanchor_urb(urb);
|
||||
|
||||
if (ret == -ENODEV) {
|
||||
for (i = 0; i < es58x_dev->num_can_ch; i++)
|
||||
if (es58x_dev->netdev[i])
|
||||
netif_device_detach(es58x_dev->netdev[i]);
|
||||
} else if (ret)
|
||||
} else
|
||||
dev_err_ratelimited(dev,
|
||||
"Failed resubmitting read bulk urb: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
|
|
|
|||
|
|
@ -413,6 +413,7 @@ static void f81604_read_bulk_callback(struct urb *urb)
|
|||
{
|
||||
struct f81604_can_frame *frame = urb->transfer_buffer;
|
||||
struct net_device *netdev = urb->context;
|
||||
struct f81604_port_priv *priv = netdev_priv(netdev);
|
||||
int ret;
|
||||
|
||||
if (!netif_device_present(netdev))
|
||||
|
|
@ -445,10 +446,15 @@ static void f81604_read_bulk_callback(struct urb *urb)
|
|||
f81604_process_rx_packet(netdev, frame);
|
||||
|
||||
resubmit_urb:
|
||||
usb_anchor_urb(urb, &priv->urbs_anchor);
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (!ret)
|
||||
return;
|
||||
usb_unanchor_urb(urb);
|
||||
|
||||
if (ret == -ENODEV)
|
||||
netif_device_detach(netdev);
|
||||
else if (ret)
|
||||
else
|
||||
netdev_err(netdev,
|
||||
"%s: failed to resubmit read bulk urb: %pe\n",
|
||||
__func__, ERR_PTR(ret));
|
||||
|
|
@ -620,6 +626,12 @@ static void f81604_read_int_callback(struct urb *urb)
|
|||
netdev_info(netdev, "%s: Int URB aborted: %pe\n", __func__,
|
||||
ERR_PTR(urb->status));
|
||||
|
||||
if (urb->actual_length < sizeof(*data)) {
|
||||
netdev_warn(netdev, "%s: short int URB: %u < %zu\n",
|
||||
__func__, urb->actual_length, sizeof(*data));
|
||||
goto resubmit_urb;
|
||||
}
|
||||
|
||||
switch (urb->status) {
|
||||
case 0: /* success */
|
||||
break;
|
||||
|
|
@ -646,10 +658,15 @@ static void f81604_read_int_callback(struct urb *urb)
|
|||
f81604_handle_tx(priv, data);
|
||||
|
||||
resubmit_urb:
|
||||
usb_anchor_urb(urb, &priv->urbs_anchor);
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (!ret)
|
||||
return;
|
||||
usb_unanchor_urb(urb);
|
||||
|
||||
if (ret == -ENODEV)
|
||||
netif_device_detach(netdev);
|
||||
else if (ret)
|
||||
else
|
||||
netdev_err(netdev, "%s: failed to resubmit int urb: %pe\n",
|
||||
__func__, ERR_PTR(ret));
|
||||
}
|
||||
|
|
@ -874,9 +891,27 @@ static void f81604_write_bulk_callback(struct urb *urb)
|
|||
if (!netif_device_present(netdev))
|
||||
return;
|
||||
|
||||
if (urb->status)
|
||||
netdev_info(netdev, "%s: Tx URB error: %pe\n", __func__,
|
||||
ERR_PTR(urb->status));
|
||||
if (!urb->status)
|
||||
return;
|
||||
|
||||
switch (urb->status) {
|
||||
case -ENOENT:
|
||||
case -ECONNRESET:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (net_ratelimit())
|
||||
netdev_err(netdev, "%s: Tx URB error: %pe\n", __func__,
|
||||
ERR_PTR(urb->status));
|
||||
|
||||
can_free_echo_skb(netdev, 0, NULL);
|
||||
netdev->stats.tx_dropped++;
|
||||
netdev->stats.tx_errors++;
|
||||
|
||||
netif_wake_queue(netdev);
|
||||
}
|
||||
|
||||
static void f81604_clear_reg_work(struct work_struct *work)
|
||||
|
|
|
|||
|
|
@ -772,9 +772,8 @@ device_detach:
|
|||
}
|
||||
}
|
||||
|
||||
static int gs_usb_set_bittiming(struct net_device *netdev)
|
||||
static int gs_usb_set_bittiming(struct gs_can *dev)
|
||||
{
|
||||
struct gs_can *dev = netdev_priv(netdev);
|
||||
struct can_bittiming *bt = &dev->can.bittiming;
|
||||
struct gs_device_bittiming dbt = {
|
||||
.prop_seg = cpu_to_le32(bt->prop_seg),
|
||||
|
|
@ -791,9 +790,8 @@ static int gs_usb_set_bittiming(struct net_device *netdev)
|
|||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int gs_usb_set_data_bittiming(struct net_device *netdev)
|
||||
static int gs_usb_set_data_bittiming(struct gs_can *dev)
|
||||
{
|
||||
struct gs_can *dev = netdev_priv(netdev);
|
||||
struct can_bittiming *bt = &dev->can.fd.data_bittiming;
|
||||
struct gs_device_bittiming dbt = {
|
||||
.prop_seg = cpu_to_le32(bt->prop_seg),
|
||||
|
|
@ -1057,6 +1055,20 @@ static int gs_can_open(struct net_device *netdev)
|
|||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
flags |= GS_CAN_MODE_HW_TIMESTAMP;
|
||||
|
||||
rc = gs_usb_set_bittiming(dev);
|
||||
if (rc) {
|
||||
netdev_err(netdev, "failed to set bittiming: %pe\n", ERR_PTR(rc));
|
||||
goto out_usb_kill_anchored_urbs;
|
||||
}
|
||||
|
||||
if (ctrlmode & CAN_CTRLMODE_FD) {
|
||||
rc = gs_usb_set_data_bittiming(dev);
|
||||
if (rc) {
|
||||
netdev_err(netdev, "failed to set data bittiming: %pe\n", ERR_PTR(rc));
|
||||
goto out_usb_kill_anchored_urbs;
|
||||
}
|
||||
}
|
||||
|
||||
/* finally start device */
|
||||
dev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
dm.flags = cpu_to_le32(flags);
|
||||
|
|
@ -1370,7 +1382,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
|
|||
dev->can.state = CAN_STATE_STOPPED;
|
||||
dev->can.clock.freq = le32_to_cpu(bt_const.fclk_can);
|
||||
dev->can.bittiming_const = &dev->bt_const;
|
||||
dev->can.do_set_bittiming = gs_usb_set_bittiming;
|
||||
|
||||
dev->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC;
|
||||
|
||||
|
|
@ -1394,7 +1405,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
|
|||
* GS_CAN_FEATURE_BT_CONST_EXT is set.
|
||||
*/
|
||||
dev->can.fd.data_bittiming_const = &dev->bt_const;
|
||||
dev->can.fd.do_set_data_bittiming = gs_usb_set_data_bittiming;
|
||||
}
|
||||
|
||||
if (feature & GS_CAN_FEATURE_TERMINATION) {
|
||||
|
|
|
|||
|
|
@ -748,7 +748,7 @@ static void ucan_read_bulk_callback(struct urb *urb)
|
|||
len = le16_to_cpu(m->len);
|
||||
|
||||
/* check sanity (length of content) */
|
||||
if (urb->actual_length - pos < len) {
|
||||
if ((len == 0) || (urb->actual_length - pos < len)) {
|
||||
netdev_warn(up->netdev,
|
||||
"invalid message (short; no data; l:%d)\n",
|
||||
urb->actual_length);
|
||||
|
|
|
|||
|
|
@ -1176,6 +1176,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
|||
if (!op)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&op->bcm_tx_lock);
|
||||
op->can_id = msg_head->can_id;
|
||||
op->nframes = msg_head->nframes;
|
||||
op->cfsiz = CFSIZ(msg_head->flags);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue