linux-can-fixes-for-5.3-20190724
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEmvEkXzgOfc881GuFWsYho5HknSAFAl04JHsTHG1rbEBwZW5n dXRyb25peC5kZQAKCRBaxiGjkeSdIB52B/9S17IKTEpoNwM5KvrR+ZMqWZTx6zng iKNef14uuAemHzThMoSAJoJBGGzcgmZeu/nd0fyGg0f51kXVkapU4TsvYa2azkt9 WcTZQG3N4uUuW3D8hEbY2+au8e8ubNR+NnWQEqeoa5yuDGg7nSjD3wYd7rcY6jF5 veSGoZFQ9+MpjuYBHqtwiAauPAUqj8pHPAawGsaT/eNvsTHa7y43Iy38VbS2XTrF Ds6mwp8unE0cuBUFD49YLs3JrYsbuQRf5q2kX3/qvIO9QtJ/GQ6Dt/Sy3iC7Eo9Y PAVLK90sNb+LlRBKhfCAKUdgZsxdJ/kv6RfVDOiCoQDMVl/Ukv9UWB9Y =1E76 -----END PGP SIGNATURE----- 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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
09ea26792a
|
@ -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, ®s->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(®s->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(®s->mcr);
|
||||
reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
|
||||
priv->write(reg_mcr, ®s->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);
|
||||
|
|
46
net/can/gw.c
46
net/can/gw.c
|
@ -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(¬ifier);
|
||||
ret = register_netdevice_notifier(¬ifier);
|
||||
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(¬ifier);
|
||||
kmem_cache_destroy(cgw_cache);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (ret)
|
||||
goto out_rtnl_register1;
|
||||
|
||||
/* 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);
|
||||
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(¬ifier);
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue