Commit 09ea2679 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-fixes-for-5.3-20190724' of...

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

Marc Kleine-Budde says:

====================
pull-request: can 2019-07-24

this is a pull reqeust of 7 patches for net/master.

The first patch is by Rasmus Villemoes add a missing netif_carrier_off() to
register_candev() so that generic netdev trigger based LEDs are initially off.

Nikita Yushchenko's patch for the rcar_canfd driver fixes a possible IRQ storm
on high load.

The patch by Weitao Hou for the mcp251x driver add missing error checking to
the work queue allocation.

Both Wen Yang's and Joakim Zhang's patch for the flexcan driver fix a problem
with the stop-mode.

Stephane Grosjean contributes a patch for the peak_usb driver to fix a
potential double kfree_skb().

The last patch is by YueHaibing and fixes the error path in can-gw's
cgw_module_init() function.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3bc817d6 b7a14297
......@@ -1249,6 +1249,8 @@ int register_candev(struct net_device *dev)
return -EINVAL;
dev->rtnl_link_ops = &can_link_ops;
netif_carrier_off(dev);
return register_netdev(dev);
}
EXPORT_SYMBOL_GPL(register_candev);
......
......@@ -400,9 +400,10 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
priv->write(reg_mcr, &regs->mcr);
}
static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int ackval;
u32 reg_mcr;
reg_mcr = priv->read(&regs->mcr);
......@@ -412,20 +413,37 @@ static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
/* enable stop request */
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
/* get stop acknowledgment */
if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr,
ackval, ackval & (1 << priv->stm.ack_bit),
0, FLEXCAN_TIMEOUT_US))
return -ETIMEDOUT;
return 0;
}
static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->regs;
unsigned int ackval;
u32 reg_mcr;
/* remove stop request */
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 0);
/* get stop acknowledgment */
if (regmap_read_poll_timeout(priv->stm.gpr, priv->stm.ack_gpr,
ackval, !(ackval & (1 << priv->stm.ack_bit)),
0, FLEXCAN_TIMEOUT_US))
return -ETIMEDOUT;
reg_mcr = priv->read(&regs->mcr);
reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
priv->write(reg_mcr, &regs->mcr);
return 0;
}
static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv)
......@@ -1437,10 +1455,10 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
priv = netdev_priv(dev);
priv->stm.gpr = syscon_node_to_regmap(gpr_np);
of_node_put(gpr_np);
if (IS_ERR(priv->stm.gpr)) {
dev_dbg(&pdev->dev, "could not find gpr regmap\n");
return PTR_ERR(priv->stm.gpr);
ret = PTR_ERR(priv->stm.gpr);
goto out_put_node;
}
priv->stm.req_gpr = out_val[1];
......@@ -1455,7 +1473,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
return 0;
out_put_node:
of_node_put(gpr_np);
return ret;
}
static const struct of_device_id flexcan_of_match[] = {
......@@ -1612,7 +1632,9 @@ static int __maybe_unused flexcan_suspend(struct device *device)
*/
if (device_may_wakeup(device)) {
enable_irq_wake(dev->irq);
flexcan_enter_stop_mode(priv);
err = flexcan_enter_stop_mode(priv);
if (err)
return err;
} else {
err = flexcan_chip_disable(priv);
if (err)
......@@ -1662,10 +1684,13 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
int err;
if (netif_running(dev) && device_may_wakeup(device)) {
flexcan_enable_wakeup_irq(priv, false);
flexcan_exit_stop_mode(priv);
err = flexcan_exit_stop_mode(priv);
if (err)
return err;
}
return 0;
......
......@@ -1508,10 +1508,11 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota)
/* All packets processed */
if (num_pkts < quota) {
napi_complete_done(napi, num_pkts);
/* Enable Rx FIFO interrupts */
rcar_canfd_set_bit(priv->base, RCANFD_RFCC(ridx),
RCANFD_RFCC_RFIE);
if (napi_complete_done(napi, num_pkts)) {
/* Enable Rx FIFO interrupts */
rcar_canfd_set_bit(priv->base, RCANFD_RFCC(ridx),
RCANFD_RFCC_RFIE);
}
}
return num_pkts;
}
......
......@@ -664,17 +664,6 @@ static int mcp251x_power_enable(struct regulator *reg, int enable)
return regulator_disable(reg);
}
static void mcp251x_open_clean(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
free_irq(spi->irq, priv);
mcp251x_hw_sleep(spi);
mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
}
static int mcp251x_stop(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
......@@ -940,37 +929,43 @@ static int mcp251x_open(struct net_device *net)
flags | IRQF_ONESHOT, DEVICE_NAME, priv);
if (ret) {
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
goto open_unlock;
goto out_close;
}
priv->wq = alloc_workqueue("mcp251x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
0);
if (!priv->wq) {
ret = -ENOMEM;
goto out_clean;
}
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
ret = mcp251x_hw_reset(spi);
if (ret) {
mcp251x_open_clean(net);
goto open_unlock;
}
if (ret)
goto out_free_wq;
ret = mcp251x_setup(net, spi);
if (ret) {
mcp251x_open_clean(net);
goto open_unlock;
}
if (ret)
goto out_free_wq;
ret = mcp251x_set_normal_mode(spi);
if (ret) {
mcp251x_open_clean(net);
goto open_unlock;
}
if (ret)
goto out_free_wq;
can_led_event(net, CAN_LED_EVENT_OPEN);
netif_wake_queue(net);
mutex_unlock(&priv->mcp_lock);
open_unlock:
return 0;
out_free_wq:
destroy_workqueue(priv->wq);
out_clean:
free_irq(spi->irq, priv);
mcp251x_hw_sleep(spi);
out_close:
mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
mutex_unlock(&priv->mcp_lock);
return ret;
}
......
......@@ -568,16 +568,16 @@ static int peak_usb_ndo_stop(struct net_device *netdev)
dev->state &= ~PCAN_USB_STATE_STARTED;
netif_stop_queue(netdev);
close_candev(netdev);
dev->can.state = CAN_STATE_STOPPED;
/* unlink all pending urbs and free used memory */
peak_usb_unlink_all_urbs(dev);
if (dev->adapter->dev_stop)
dev->adapter->dev_stop(dev);
close_candev(netdev);
dev->can.state = CAN_STATE_STOPPED;
/* can set bus off now */
if (dev->adapter->dev_set_bus) {
int err = dev->adapter->dev_set_bus(dev, 0);
......
......@@ -1046,32 +1046,50 @@ static __init int cgw_module_init(void)
pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
max_hops);
register_pernet_subsys(&cangw_pernet_ops);
ret = register_pernet_subsys(&cangw_pernet_ops);
if (ret)
return ret;
ret = -ENOMEM;
cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
0, 0, NULL);
if (!cgw_cache)
return -ENOMEM;
goto out_cache_create;
/* set notifier */
notifier.notifier_call = cgw_notifier;
register_netdevice_notifier(&notifier);
ret = register_netdevice_notifier(&notifier);
if (ret)
goto out_register_notifier;
ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_GETROUTE,
NULL, cgw_dump_jobs, 0);
if (ret) {
unregister_netdevice_notifier(&notifier);
kmem_cache_destroy(cgw_cache);
return -ENOBUFS;
}
/* Only the first call to rtnl_register_module can fail */
rtnl_register_module(THIS_MODULE, PF_CAN, RTM_NEWROUTE,
cgw_create_job, NULL, 0);
rtnl_register_module(THIS_MODULE, PF_CAN, RTM_DELROUTE,
cgw_remove_job, NULL, 0);
if (ret)
goto out_rtnl_register1;
ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_NEWROUTE,
cgw_create_job, NULL, 0);
if (ret)
goto out_rtnl_register2;
ret = rtnl_register_module(THIS_MODULE, PF_CAN, RTM_DELROUTE,
cgw_remove_job, NULL, 0);
if (ret)
goto out_rtnl_register3;
return 0;
out_rtnl_register3:
rtnl_unregister(PF_CAN, RTM_NEWROUTE);
out_rtnl_register2:
rtnl_unregister(PF_CAN, RTM_GETROUTE);
out_rtnl_register1:
unregister_netdevice_notifier(&notifier);
out_register_notifier:
kmem_cache_destroy(cgw_cache);
out_cache_create:
unregister_pernet_subsys(&cangw_pernet_ops);
return ret;
}
static __exit void cgw_module_exit(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment