linux-can-fixes-for-5.10-20201115
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEK3kIWJt9yTYMP3ehqclaivrt76kFAl+xZoMTHG1rbEBwZW5n dXRyb25peC5kZQAKCRCpyVqK+u3vqX8lB/4gQq9MTczYjSxVGgqaEyToftX7rokl EiP6RcpXKvAY8p0IJHEWHeCGOqsD5am4xo6M/Z5nMAinBdywweSvQRdU8ZDdCb84 AxJEbrkU7JTNqHbQnLp3wzl5sHPAwvRavf9plFwnPosMM2nS0HcPnjaj9kgO3cLI E/fMa+WmPwDjMEIBM2TJCgFh9pH5Fs8I3SRHC/TUYwigXKVtgIuIm1o6t4evBk9w zBW+5HX++r2FSt0164vVZyBCOCK/z2tEMCEO8l3mrUKdjBy3jAFqXfWxcQbaFy8f Oy8Nx1vgNZYVH7RqYJ6JuQO6/wQIPAWb6KOgDrDWaM6jl3ZdA7/gBdiR =Ed6S -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-5.10-20201115' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2020-11-15 Anant Thazhemadam contributed two patches for the AF_CAN that prevent potential access of uninitialized member in can_rcv() and canfd_rcv(). The next patch is by Alejandro Concepcion Rodriguez and changes can_restart() to use the correct function to push a skb into the networking stack from process context. Zhang Qilong's patch fixes a memory leak in the error path of the ti_hecc's probe function. A patch by me fixes mcba_usb_start_xmit() function in the mcba_usb driver, to first fill the skb and then pass it to can_put_echo_skb(). Colin Ian King's patch fixes a potential integer overflow on shift in the peak_usb driver. The next two patches target the flexcan driver, a patch by me adds the missing "req_bit" to the stop mode property comment (which was broken during net-next for v5.10). Zhang Qilong's patch fixes the failure handling of pm_runtime_get_sync(). The next seven patches target the m_can driver including the tcan4x5x spi driver glue code. Enric Balletbo i Serra's patch for the tcan4x5x Kconfig fix the REGMAP_SPI dependency handling. A patch by me for the tcan4x5x driver's probe() function adds missing error handling to for devm_regmap_init(), and in tcan4x5x_can_remove() the order of deregistration is fixed. Wu Bo's patch for the m_can driver fixes the state change handling in m_can_handle_state_change(). Two patches by Dan Murphy first introduce m_can_class_free_dev() and then make use of it to fix the freeing of the can device. A patch by Faiz Abbas add a missing shutdown of the CAN controller in the m_can_stop() function. * tag 'linux-can-fixes-for-5.10-20201115' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: m_can: m_can_stop(): set device to software init mode before closing can: m_can: Fix freeing of can device from peripherials can: m_can: m_can_class_free_dev(): introduce new function can: m_can: m_can_handle_state_change(): fix state change can: tcan4x5x: tcan4x5x_can_remove(): fix order of deregistration can: tcan4x5x: tcan4x5x_can_probe(): add missing error checking for devm_regmap_init() can: tcan4x5x: replace depends on REGMAP_SPI with depends on SPI can: flexcan: fix failure handling of pm_runtime_get_sync() can: flexcan: flexcan_setup_stop_mode(): add missing "req_bit" to stop mode property comment can: peak_usb: fix potential integer overflow on shift of a int can: mcba_usb: mcba_usb_start_xmit(): first fill skb, then pass to can_put_echo_skb() can: ti_hecc: Fix memleak in ti_hecc_probe can: dev: can_restart(): post buffer from the right context can: af_can: prevent potential access of uninitialized member in canfd_rcv() can: af_can: prevent potential access of uninitialized member in can_rcv() ==================== Link: https://lore.kernel.org/r/20201115174131.2089251-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Коммит
e2142ef266
|
@ -592,7 +592,7 @@ static void can_restart(struct net_device *dev)
|
|||
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
|
||||
netif_rx(skb);
|
||||
netif_rx_ni(skb);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
|
|
|
@ -728,8 +728,10 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
|
|||
int err;
|
||||
|
||||
err = pm_runtime_get_sync(priv->dev);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
pm_runtime_put_noidle(priv->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = __flexcan_get_berr_counter(dev, bec);
|
||||
|
||||
|
@ -1654,8 +1656,10 @@ static int flexcan_open(struct net_device *dev)
|
|||
}
|
||||
|
||||
err = pm_runtime_get_sync(priv->dev);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
pm_runtime_put_noidle(priv->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = open_candev(dev);
|
||||
if (err)
|
||||
|
@ -1852,7 +1856,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
|
||||
/* stop mode property format is:
|
||||
* <&gpr req_gpr>.
|
||||
* <&gpr req_gpr req_bit>.
|
||||
*/
|
||||
ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
|
||||
ARRAY_SIZE(out_val));
|
||||
|
|
|
@ -16,7 +16,8 @@ config CAN_M_CAN_PLATFORM
|
|||
|
||||
config CAN_M_CAN_TCAN4X5X
|
||||
depends on CAN_M_CAN
|
||||
depends on REGMAP_SPI
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
tristate "TCAN4X5X M_CAN device"
|
||||
help
|
||||
Say Y here if you want support for Texas Instruments TCAN4x5x
|
||||
|
|
|
@ -665,7 +665,7 @@ static int m_can_handle_state_change(struct net_device *dev,
|
|||
unsigned int ecr;
|
||||
|
||||
switch (new_state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
/* error warning state */
|
||||
cdev->can.can_stats.error_warning++;
|
||||
cdev->can.state = CAN_STATE_ERROR_WARNING;
|
||||
|
@ -694,7 +694,7 @@ 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:
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
/* error warning state */
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = (bec.txerr > bec.rxerr) ?
|
||||
|
@ -1414,6 +1414,9 @@ static void m_can_stop(struct net_device *dev)
|
|||
/* disable all interrupts */
|
||||
m_can_disable_all_interrupts(cdev);
|
||||
|
||||
/* Set init mode to disengage from the network */
|
||||
m_can_config_endisable(cdev, true);
|
||||
|
||||
/* set the state as STOPPED */
|
||||
cdev->can.state = CAN_STATE_STOPPED;
|
||||
}
|
||||
|
@ -1812,6 +1815,12 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
|
||||
|
||||
void m_can_class_free_dev(struct net_device *net)
|
||||
{
|
||||
free_candev(net);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_free_dev);
|
||||
|
||||
int m_can_class_register(struct m_can_classdev *m_can_dev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1850,7 +1859,6 @@ pm_runtime_fail:
|
|||
if (ret) {
|
||||
if (m_can_dev->pm_clock_support)
|
||||
pm_runtime_disable(m_can_dev->dev);
|
||||
free_candev(m_can_dev->net);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1908,8 +1916,6 @@ void m_can_class_unregister(struct m_can_classdev *m_can_dev)
|
|||
unregister_candev(m_can_dev->net);
|
||||
|
||||
m_can_clk_stop(m_can_dev);
|
||||
|
||||
free_candev(m_can_dev->net);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_unregister);
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ struct m_can_classdev {
|
|||
};
|
||||
|
||||
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev);
|
||||
void m_can_class_free_dev(struct net_device *net);
|
||||
int m_can_class_register(struct m_can_classdev *cdev);
|
||||
void m_can_class_unregister(struct m_can_classdev *cdev);
|
||||
int m_can_class_get_clocks(struct m_can_classdev *cdev);
|
||||
|
|
|
@ -67,32 +67,36 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
mcan_class->device_data = priv;
|
||||
|
||||
m_can_class_get_clocks(mcan_class);
|
||||
ret = m_can_class_get_clocks(mcan_class);
|
||||
if (ret)
|
||||
goto probe_fail;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
irq = platform_get_irq_byname(pdev, "int0");
|
||||
if (IS_ERR(addr) || irq < 0) {
|
||||
ret = -EINVAL;
|
||||
goto failed_ret;
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
/* message ram could be shared */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
goto failed_ret;
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!mram_addr) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_ret;
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
priv->base = addr;
|
||||
|
@ -111,9 +115,10 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
|||
|
||||
m_can_init_ram(mcan_class);
|
||||
|
||||
ret = m_can_class_register(mcan_class);
|
||||
return m_can_class_register(mcan_class);
|
||||
|
||||
failed_ret:
|
||||
probe_fail:
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -134,6 +139,8 @@ static int m_can_plat_remove(struct platform_device *pdev)
|
|||
|
||||
m_can_class_unregister(mcan_class);
|
||||
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -440,14 +440,18 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
|||
return -ENOMEM;
|
||||
|
||||
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out_m_can_class_free_dev;
|
||||
}
|
||||
|
||||
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
|
||||
if (PTR_ERR(priv->power) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
else
|
||||
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto out_m_can_class_free_dev;
|
||||
} else {
|
||||
priv->power = NULL;
|
||||
}
|
||||
|
||||
mcan_class->device_data = priv;
|
||||
|
||||
|
@ -460,8 +464,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
|||
}
|
||||
|
||||
/* Sanity check */
|
||||
if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF)
|
||||
return -ERANGE;
|
||||
if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF) {
|
||||
ret = -ERANGE;
|
||||
goto out_m_can_class_free_dev;
|
||||
}
|
||||
|
||||
priv->reg_offset = TCAN4X5X_MCAN_OFFSET;
|
||||
priv->mram_start = TCAN4X5X_MRAM_START;
|
||||
|
@ -487,6 +493,10 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
|||
|
||||
priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
|
||||
&spi->dev, &tcan4x5x_regmap);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
ret = PTR_ERR(priv->regmap);
|
||||
goto out_clk;
|
||||
}
|
||||
|
||||
ret = tcan4x5x_power_enable(priv->power, 1);
|
||||
if (ret)
|
||||
|
@ -514,8 +524,10 @@ out_clk:
|
|||
clk_disable_unprepare(mcan_class->cclk);
|
||||
clk_disable_unprepare(mcan_class->hclk);
|
||||
}
|
||||
|
||||
out_m_can_class_free_dev:
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
dev_err(&spi->dev, "Probe failed, err=%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -523,9 +535,11 @@ static int tcan4x5x_can_remove(struct spi_device *spi)
|
|||
{
|
||||
struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
|
||||
|
||||
m_can_class_unregister(priv->mcan_dev);
|
||||
|
||||
tcan4x5x_power_enable(priv->power, 0);
|
||||
|
||||
m_can_class_unregister(priv->mcan_dev);
|
||||
m_can_class_free_dev(priv->mcan_dev->net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -881,7 +881,8 @@ static int ti_hecc_probe(struct platform_device *pdev)
|
|||
priv->base = devm_platform_ioremap_resource_byname(pdev, "hecc");
|
||||
if (IS_ERR(priv->base)) {
|
||||
dev_err(&pdev->dev, "hecc ioremap failed\n");
|
||||
return PTR_ERR(priv->base);
|
||||
err = PTR_ERR(priv->base);
|
||||
goto probe_exit_candev;
|
||||
}
|
||||
|
||||
/* handle hecc-ram memory */
|
||||
|
@ -889,20 +890,22 @@ static int ti_hecc_probe(struct platform_device *pdev)
|
|||
"hecc-ram");
|
||||
if (IS_ERR(priv->hecc_ram)) {
|
||||
dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
|
||||
return PTR_ERR(priv->hecc_ram);
|
||||
err = PTR_ERR(priv->hecc_ram);
|
||||
goto probe_exit_candev;
|
||||
}
|
||||
|
||||
/* handle mbx memory */
|
||||
priv->mbx = devm_platform_ioremap_resource_byname(pdev, "mbx");
|
||||
if (IS_ERR(priv->mbx)) {
|
||||
dev_err(&pdev->dev, "mbx ioremap failed\n");
|
||||
return PTR_ERR(priv->mbx);
|
||||
err = PTR_ERR(priv->mbx);
|
||||
goto probe_exit_candev;
|
||||
}
|
||||
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "No irq resource\n");
|
||||
goto probe_exit;
|
||||
goto probe_exit_candev;
|
||||
}
|
||||
|
||||
priv->ndev = ndev;
|
||||
|
@ -966,7 +969,7 @@ probe_exit_release_clk:
|
|||
clk_put(priv->clk);
|
||||
probe_exit_candev:
|
||||
free_candev(ndev);
|
||||
probe_exit:
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -326,8 +326,6 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
|
|||
if (!ctx)
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
|
||||
|
||||
if (cf->can_id & CAN_EFF_FLAG) {
|
||||
/* SIDH | SIDL | EIDH | EIDL
|
||||
* 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0
|
||||
|
@ -357,6 +355,8 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
|
|||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
usb_msg.dlc |= MCBA_DLC_RTR_MASK;
|
||||
|
||||
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
|
||||
|
||||
err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx);
|
||||
if (err)
|
||||
goto xmit_failed;
|
||||
|
|
|
@ -156,7 +156,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
|
|||
if (time_ref->ts_dev_1 < time_ref->ts_dev_2) {
|
||||
/* case when event time (tsw) wraps */
|
||||
if (ts < time_ref->ts_dev_1)
|
||||
delta_ts = 1 << time_ref->adapter->ts_used_bits;
|
||||
delta_ts = BIT_ULL(time_ref->adapter->ts_used_bits);
|
||||
|
||||
/* Otherwise, sync time counter (ts_dev_2) has wrapped:
|
||||
* handle case when event time (tsn) hasn't.
|
||||
|
@ -168,7 +168,7 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
|
|||
* tsn ts
|
||||
*/
|
||||
} else if (time_ref->ts_dev_1 < ts) {
|
||||
delta_ts = -(1 << time_ref->adapter->ts_used_bits);
|
||||
delta_ts = -BIT_ULL(time_ref->adapter->ts_used_bits);
|
||||
}
|
||||
|
||||
/* add delay between last sync and event timestamps */
|
||||
|
|
|
@ -677,16 +677,25 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, datalen %d\n",
|
||||
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
|
||||
dev->type, skb->len);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
|
||||
if (unlikely(cfd->len > CAN_MAX_DLEN)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d, datalen %d\n",
|
||||
dev->type, skb->len, cfd->len);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
|
@ -694,16 +703,25 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuf: dev type %d, len %d, datalen %d\n",
|
||||
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
|
||||
dev->type, skb->len);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
|
||||
if (unlikely(cfd->len > CANFD_MAX_DLEN)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d, datalen %d\n",
|
||||
dev->type, skb->len, cfd->len);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
/* af_can protocol functions */
|
||||
|
|
Загрузка…
Ссылка в новой задаче