mirror of https://github.com/torvalds/linux.git
linux-can-fixes-for-6.18-20251014
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEn/sM2K9nqF/8FWzzDHRl3/mQkZwFAmjuAZATHG1rbEBwZW5n dXRyb25peC5kZQAKCRAMdGXf+ZCRnPeECACtwzFozRla2Y+WTR7+BZiBlRtcWZ8d aNHrvtjefaX4TkgEVgC9Qt+VI7Wzv2TDlVWIWZnm3lotufmQsbRdDdEyfeRHPR7m 9yZcqRvLGQ17LDnC13W66YaZXhhz263rvCTwzcLyuB7tnO+zyYfakTZfR+xtfJ3x LBT6yNVlujy+/I4NCRNwlLzJc5fdGTKaSbt8ECf7qygcbQfZ/AcLUV9/AIjweVP1 Tcp2qumrM+HIU0lPQzfyiEGJn/weLRfajVbzcsv7NNc9vtlP2Ayi0LnLoXl98Pfk 00nJVXmV6rAJCm/LqDKoWvP98jEL4B41+06RRwsm5sJQ7caRS+knuVVn =Wml2 -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-6.18-20251014' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2025-10-14 The first 2 paches are by Celeste Liu and target the gS_usb driver. The first patch remove the limitation to 3 CAN interface per USB device. The second patch adds the missing population of net_device->dev_port. The next 4 patches are by me and fix the m_can driver. They add a missing pm_runtime_disable(), fix the CAN state transition back to Error Active and fix the state after ifup and suspend/resume. Another patch by me targets the m_can driver, too and replaces Dong Aisheng's old email address. The next 2 patches are by Vincent Mailhol and update the CAN networking Documentation. Tetsuo Handa contributes the last patch that add missing cleanup calls in the NETDEV_UNREGISTER notification handler. * tag 'linux-can-fixes-for-6.18-20251014' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: j1939: add missing calls in NETDEV_UNREGISTER notification handler can: add Transmitter Delay Compensation (TDC) documentation can: remove false statement about 1:1 mapping between DLC and length can: m_can: replace Dong Aisheng's old email address can: m_can: fix CAN state in system PM can: m_can: m_can_chip_config(): bring up interface in correct state can: m_can: m_can_handle_state_errors(): fix CAN state transition to Error Active can: m_can: m_can_plat_remove(): add missing pm_runtime_disable() can: gs_usb: gs_make_candev(): populate net_device->dev_port can: gs_usb: increase max interface to U8_MAX ==================== Link: https://patch.msgid.link/20251014122140.990472-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
5e655aadda
1
.mailmap
1
.mailmap
|
|
@ -227,6 +227,7 @@ Dmitry Safonov <0x7f454c46@gmail.com> <dima@arista.com>
|
|||
Dmitry Safonov <0x7f454c46@gmail.com> <d.safonov@partner.samsung.com>
|
||||
Dmitry Safonov <0x7f454c46@gmail.com> <dsafonov@virtuozzo.com>
|
||||
Domen Puncer <domen@coderock.org>
|
||||
Dong Aisheng <aisheng.dong@nxp.com> <b29396@freescale.com>
|
||||
Douglas Gilbert <dougg@torque.net>
|
||||
Drew Fustini <fustini@kernel.org> <drew@pdp7.com>
|
||||
<duje@dujemihanovic.xyz> <duje.mihanovic@skole.hr>
|
||||
|
|
|
|||
|
|
@ -1398,10 +1398,9 @@ second bit timing has to be specified in order to enable the CAN FD bitrate.
|
|||
Additionally CAN FD capable CAN controllers support up to 64 bytes of
|
||||
payload. The representation of this length in can_frame.len and
|
||||
canfd_frame.len for userspace applications and inside the Linux network
|
||||
layer is a plain value from 0 .. 64 instead of the CAN 'data length code'.
|
||||
The data length code was a 1:1 mapping to the payload length in the Classical
|
||||
CAN frames anyway. The payload length to the bus-relevant DLC mapping is
|
||||
only performed inside the CAN drivers, preferably with the helper
|
||||
layer is a plain value from 0 .. 64 instead of the Classical CAN length
|
||||
which ranges from 0 to 8. The payload length to the bus-relevant DLC mapping
|
||||
is only performed inside the CAN drivers, preferably with the helper
|
||||
functions can_fd_dlc2len() and can_fd_len2dlc().
|
||||
|
||||
The CAN netdevice driver capabilities can be distinguished by the network
|
||||
|
|
@ -1465,6 +1464,70 @@ Example when 'fd-non-iso on' is added on this switchable CAN FD adapter::
|
|||
can <FD,FD-NON-ISO> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0
|
||||
|
||||
|
||||
Transmitter Delay Compensation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
At high bit rates, the propagation delay from the TX pin to the RX pin of
|
||||
the transceiver might become greater than the actual bit time causing
|
||||
measurement errors: the RX pin would still be measuring the previous bit.
|
||||
|
||||
The Transmitter Delay Compensation (thereafter, TDC) resolves this problem
|
||||
by introducing a Secondary Sample Point (SSP) equal to the distance, in
|
||||
minimum time quantum, from the start of the bit time on the TX pin to the
|
||||
actual measurement on the RX pin. The SSP is calculated as the sum of two
|
||||
configurable values: the TDC Value (TDCV) and the TDC offset (TDCO).
|
||||
|
||||
TDC, if supported by the device, can be configured together with CAN-FD
|
||||
using the ip tool's "tdc-mode" argument as follow:
|
||||
|
||||
**omitted**
|
||||
When no "tdc-mode" option is provided, the kernel will automatically
|
||||
decide whether TDC should be turned on, in which case it will
|
||||
calculate a default TDCO and use the TDCV as measured by the
|
||||
device. This is the recommended method to use TDC.
|
||||
|
||||
**"tdc-mode off"**
|
||||
TDC is explicitly disabled.
|
||||
|
||||
**"tdc-mode auto"**
|
||||
The user must provide the "tdco" argument. The TDCV will be
|
||||
automatically calculated by the device. This option is only
|
||||
available if the device supports the TDC-AUTO CAN controller mode.
|
||||
|
||||
**"tdc-mode manual"**
|
||||
The user must provide both the "tdco" and "tdcv" arguments. This
|
||||
option is only available if the device supports the TDC-MANUAL CAN
|
||||
controller mode.
|
||||
|
||||
Note that some devices may offer an additional parameter: "tdcf" (TDC Filter
|
||||
window). If supported by your device, this can be added as an optional
|
||||
argument to either "tdc-mode auto" or "tdc-mode manual".
|
||||
|
||||
Example configuring a 500 kbit/s arbitration bitrate, a 5 Mbit/s data
|
||||
bitrate, a TDCO of 15 minimum time quantum and a TDCV automatically measured
|
||||
by the device::
|
||||
|
||||
$ ip link set can0 up type can bitrate 500000 \
|
||||
fd on dbitrate 4000000 \
|
||||
tdc-mode auto tdco 15
|
||||
$ ip -details link show can0
|
||||
5: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UP \
|
||||
mode DEFAULT group default qlen 10
|
||||
link/can promiscuity 0 allmulti 0 minmtu 72 maxmtu 72
|
||||
can <FD,TDC-AUTO> state ERROR-ACTIVE restart-ms 0
|
||||
bitrate 500000 sample-point 0.875
|
||||
tq 12 prop-seg 69 phase-seg1 70 phase-seg2 20 sjw 10 brp 1
|
||||
ES582.1/ES584.1: tseg1 2..256 tseg2 2..128 sjw 1..128 brp 1..512 \
|
||||
brp_inc 1
|
||||
dbitrate 4000000 dsample-point 0.750
|
||||
dtq 12 dprop-seg 7 dphase-seg1 7 dphase-seg2 5 dsjw 2 dbrp 1
|
||||
tdco 15 tdcf 0
|
||||
ES582.1/ES584.1: dtseg1 2..32 dtseg2 1..16 dsjw 1..8 dbrp 1..32 \
|
||||
dbrp_inc 1
|
||||
tdco 0..127 tdcf 0..127
|
||||
clock 80000000
|
||||
|
||||
|
||||
Supported CAN Hardware
|
||||
----------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// CAN bus driver for Bosch M_CAN controller
|
||||
// Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
// Dong Aisheng <b29396@freescale.com>
|
||||
// Dong Aisheng <aisheng.dong@nxp.com>
|
||||
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
/* Bosch M_CAN user manual can be obtained from:
|
||||
|
|
@ -812,6 +812,9 @@ static int m_can_handle_state_change(struct net_device *dev,
|
|||
u32 timestamp = 0;
|
||||
|
||||
switch (new_state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
break;
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
/* error warning state */
|
||||
cdev->can.can_stats.error_warning++;
|
||||
|
|
@ -841,6 +844,12 @@ static int m_can_handle_state_change(struct net_device *dev,
|
|||
__m_can_get_berr_counter(dev, &bec);
|
||||
|
||||
switch (new_state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
|
||||
cf->data[1] = CAN_ERR_CRTL_ACTIVE;
|
||||
cf->data[6] = bec.txerr;
|
||||
cf->data[7] = bec.rxerr;
|
||||
break;
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
/* error warning state */
|
||||
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
|
||||
|
|
@ -877,30 +886,33 @@ static int m_can_handle_state_change(struct net_device *dev,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
|
||||
static enum can_state
|
||||
m_can_state_get_by_psr(struct m_can_classdev *cdev)
|
||||
{
|
||||
u32 reg_psr;
|
||||
|
||||
reg_psr = m_can_read(cdev, M_CAN_PSR);
|
||||
|
||||
if (reg_psr & PSR_BO)
|
||||
return CAN_STATE_BUS_OFF;
|
||||
if (reg_psr & PSR_EP)
|
||||
return CAN_STATE_ERROR_PASSIVE;
|
||||
if (reg_psr & PSR_EW)
|
||||
return CAN_STATE_ERROR_WARNING;
|
||||
|
||||
return CAN_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
|
||||
static int m_can_handle_state_errors(struct net_device *dev)
|
||||
{
|
||||
struct m_can_classdev *cdev = netdev_priv(dev);
|
||||
int work_done = 0;
|
||||
enum can_state new_state;
|
||||
|
||||
if (psr & PSR_EW && cdev->can.state != CAN_STATE_ERROR_WARNING) {
|
||||
netdev_dbg(dev, "entered error warning state\n");
|
||||
work_done += m_can_handle_state_change(dev,
|
||||
CAN_STATE_ERROR_WARNING);
|
||||
}
|
||||
new_state = m_can_state_get_by_psr(cdev);
|
||||
if (new_state == cdev->can.state)
|
||||
return 0;
|
||||
|
||||
if (psr & PSR_EP && cdev->can.state != CAN_STATE_ERROR_PASSIVE) {
|
||||
netdev_dbg(dev, "entered error passive state\n");
|
||||
work_done += m_can_handle_state_change(dev,
|
||||
CAN_STATE_ERROR_PASSIVE);
|
||||
}
|
||||
|
||||
if (psr & PSR_BO && cdev->can.state != CAN_STATE_BUS_OFF) {
|
||||
netdev_dbg(dev, "entered error bus off state\n");
|
||||
work_done += m_can_handle_state_change(dev,
|
||||
CAN_STATE_BUS_OFF);
|
||||
}
|
||||
|
||||
return work_done;
|
||||
return m_can_handle_state_change(dev, new_state);
|
||||
}
|
||||
|
||||
static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
|
||||
|
|
@ -1031,8 +1043,7 @@ static int m_can_rx_handler(struct net_device *dev, int quota, u32 irqstatus)
|
|||
}
|
||||
|
||||
if (irqstatus & IR_ERR_STATE)
|
||||
work_done += m_can_handle_state_errors(dev,
|
||||
m_can_read(cdev, M_CAN_PSR));
|
||||
work_done += m_can_handle_state_errors(dev);
|
||||
|
||||
if (irqstatus & IR_ERR_BUS_30X)
|
||||
work_done += m_can_handle_bus_errors(dev, irqstatus,
|
||||
|
|
@ -1606,7 +1617,7 @@ static int m_can_start(struct net_device *dev)
|
|||
netdev_queue_set_dql_min_limit(netdev_get_tx_queue(cdev->net, 0),
|
||||
cdev->tx_max_coalesced_frames);
|
||||
|
||||
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
cdev->can.state = m_can_state_get_by_psr(cdev);
|
||||
|
||||
m_can_enable_all_interrupts(cdev);
|
||||
|
||||
|
|
@ -2492,12 +2503,11 @@ int m_can_class_suspend(struct device *dev)
|
|||
}
|
||||
|
||||
m_can_clk_stop(cdev);
|
||||
cdev->can.state = CAN_STATE_SLEEPING;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
cdev->can.state = CAN_STATE_SLEEPING;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_suspend);
|
||||
|
|
@ -2510,8 +2520,6 @@ int m_can_class_resume(struct device *dev)
|
|||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
if (netif_running(ndev)) {
|
||||
ret = m_can_clk_start(cdev);
|
||||
if (ret)
|
||||
|
|
@ -2529,6 +2537,8 @@ int m_can_class_resume(struct device *dev)
|
|||
if (cdev->ops->init)
|
||||
ret = cdev->ops->init(cdev);
|
||||
|
||||
cdev->can.state = m_can_state_get_by_psr(cdev);
|
||||
|
||||
m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);
|
||||
} else {
|
||||
ret = m_can_start(ndev);
|
||||
|
|
@ -2546,7 +2556,7 @@ int m_can_class_resume(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_resume);
|
||||
|
||||
MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
|
||||
MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
|
||||
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// IOMapped CAN bus driver for Bosch M_CAN controller
|
||||
// Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||
// Dong Aisheng <b29396@freescale.com>
|
||||
// Dong Aisheng <aisheng.dong@nxp.com>
|
||||
//
|
||||
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ static void m_can_plat_remove(struct platform_device *pdev)
|
|||
struct m_can_classdev *mcan_class = &priv->cdev;
|
||||
|
||||
m_can_class_unregister(mcan_class);
|
||||
|
||||
pm_runtime_disable(mcan_class->dev);
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ static struct platform_driver m_can_plat_driver = {
|
|||
|
||||
module_platform_driver(m_can_plat_driver);
|
||||
|
||||
MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
|
||||
MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
|
||||
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("M_CAN driver for IO Mapped Bosch controllers");
|
||||
|
|
|
|||
|
|
@ -289,11 +289,6 @@ struct gs_host_frame {
|
|||
#define GS_MAX_RX_URBS 30
|
||||
#define GS_NAPI_WEIGHT 32
|
||||
|
||||
/* Maximum number of interfaces the driver supports per device.
|
||||
* Current hardware only supports 3 interfaces. The future may vary.
|
||||
*/
|
||||
#define GS_MAX_INTF 3
|
||||
|
||||
struct gs_tx_context {
|
||||
struct gs_can *dev;
|
||||
unsigned int echo_id;
|
||||
|
|
@ -324,7 +319,6 @@ struct gs_can {
|
|||
|
||||
/* usb interface struct */
|
||||
struct gs_usb {
|
||||
struct gs_can *canch[GS_MAX_INTF];
|
||||
struct usb_anchor rx_submitted;
|
||||
struct usb_device *udev;
|
||||
|
||||
|
|
@ -336,9 +330,11 @@ struct gs_usb {
|
|||
|
||||
unsigned int hf_size_rx;
|
||||
u8 active_channels;
|
||||
u8 channel_cnt;
|
||||
|
||||
unsigned int pipe_in;
|
||||
unsigned int pipe_out;
|
||||
struct gs_can *canch[] __counted_by(channel_cnt);
|
||||
};
|
||||
|
||||
/* 'allocate' a tx context.
|
||||
|
|
@ -599,7 +595,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
|||
}
|
||||
|
||||
/* device reports out of range channel id */
|
||||
if (hf->channel >= GS_MAX_INTF)
|
||||
if (hf->channel >= parent->channel_cnt)
|
||||
goto device_detach;
|
||||
|
||||
dev = parent->canch[hf->channel];
|
||||
|
|
@ -699,7 +695,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
|||
/* USB failure take down all interfaces */
|
||||
if (rc == -ENODEV) {
|
||||
device_detach:
|
||||
for (rc = 0; rc < GS_MAX_INTF; rc++) {
|
||||
for (rc = 0; rc < parent->channel_cnt; rc++) {
|
||||
if (parent->canch[rc])
|
||||
netif_device_detach(parent->canch[rc]->netdev);
|
||||
}
|
||||
|
|
@ -1249,6 +1245,7 @@ static struct gs_can *gs_make_candev(unsigned int channel,
|
|||
|
||||
netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */
|
||||
netdev->dev_id = channel;
|
||||
netdev->dev_port = channel;
|
||||
|
||||
/* dev setup */
|
||||
strcpy(dev->bt_const.name, KBUILD_MODNAME);
|
||||
|
|
@ -1460,17 +1457,19 @@ static int gs_usb_probe(struct usb_interface *intf,
|
|||
icount = dconf.icount + 1;
|
||||
dev_info(&intf->dev, "Configuring for %u interfaces\n", icount);
|
||||
|
||||
if (icount > GS_MAX_INTF) {
|
||||
if (icount > type_max(parent->channel_cnt)) {
|
||||
dev_err(&intf->dev,
|
||||
"Driver cannot handle more that %u CAN interfaces\n",
|
||||
GS_MAX_INTF);
|
||||
type_max(parent->channel_cnt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
|
||||
parent = kzalloc(struct_size(parent, canch, icount), GFP_KERNEL);
|
||||
if (!parent)
|
||||
return -ENOMEM;
|
||||
|
||||
parent->channel_cnt = icount;
|
||||
|
||||
init_usb_anchor(&parent->rx_submitted);
|
||||
|
||||
usb_set_intfdata(intf, parent);
|
||||
|
|
@ -1531,7 +1530,7 @@ static void gs_usb_disconnect(struct usb_interface *intf)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < GS_MAX_INTF; i++)
|
||||
for (i = 0; i < parent->channel_cnt; i++)
|
||||
if (parent->canch[i])
|
||||
gs_destroy_candev(parent->canch[i]);
|
||||
|
||||
|
|
|
|||
|
|
@ -378,6 +378,8 @@ static int j1939_netdev_notify(struct notifier_block *nb,
|
|||
j1939_ecu_unmap_all(priv);
|
||||
break;
|
||||
case NETDEV_UNREGISTER:
|
||||
j1939_cancel_active_session(priv, NULL);
|
||||
j1939_sk_netdev_event_netdown(priv);
|
||||
j1939_sk_netdev_event_unregister(priv);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue