Skip to content

Commit

Permalink
fix race condition at the start-up when pinmux is set
Browse files Browse the repository at this point in the history
Race condition cased a kernel deadlock message at bootup when
canbus was enabled.

For details see victronenergy/venus#24

Patch is made by someone at Denx, and will be submitted to upstream
  • Loading branch information
mpvader committed Sep 5, 2016
1 parent b85f59d commit 0f6681e
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 11 deletions.
27 changes: 17 additions & 10 deletions drivers/net/can/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/workqueue.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/skb.h>
Expand Down Expand Up @@ -471,9 +472,8 @@ EXPORT_SYMBOL_GPL(can_free_echo_skb);
/*
* CAN device restart for bus-off recovery
*/
static void can_restart(unsigned long data)
static void can_restart(struct net_device *dev)
{
struct net_device *dev = (struct net_device *)data;
struct can_priv *priv = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb;
Expand Down Expand Up @@ -513,6 +513,14 @@ static void can_restart(unsigned long data)
netdev_err(dev, "Error %d during restart", err);
}

static void can_restart_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct can_priv *priv = container_of(dwork, struct can_priv, restart_work);

can_restart(priv->dev);
}

int can_restart_now(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
Expand All @@ -526,8 +534,8 @@ int can_restart_now(struct net_device *dev)
if (priv->state != CAN_STATE_BUS_OFF)
return -EBUSY;

/* Runs as soon as possible in the timer context */
mod_timer(&priv->restart_timer, jiffies);
cancel_delayed_work_sync(&priv->restart_work);
can_restart(dev);

return 0;
}
Expand All @@ -548,8 +556,8 @@ void can_bus_off(struct net_device *dev)
netif_carrier_off(dev);

if (priv->restart_ms)
mod_timer(&priv->restart_timer,
jiffies + (priv->restart_ms * HZ) / 1000);
schedule_delayed_work(&priv->restart_work,
msecs_to_jiffies(priv->restart_ms));
}
EXPORT_SYMBOL_GPL(can_bus_off);

Expand Down Expand Up @@ -658,6 +666,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
return NULL;

priv = netdev_priv(dev);
priv->dev = dev;

if (echo_skb_max) {
priv->echo_skb_max = echo_skb_max;
Expand All @@ -667,7 +676,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)

priv->state = CAN_STATE_STOPPED;

init_timer(&priv->restart_timer);
INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);

return dev;
}
Expand Down Expand Up @@ -742,8 +751,6 @@ int open_candev(struct net_device *dev)
if (!netif_carrier_ok(dev))
netif_carrier_on(dev);

setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);

return 0;
}
EXPORT_SYMBOL_GPL(open_candev);
Expand All @@ -758,7 +765,7 @@ void close_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);

del_timer_sync(&priv->restart_timer);
cancel_delayed_work_sync(&priv->restart_work);
can_flush_echo_skb(dev);
}
EXPORT_SYMBOL_GPL(close_candev);
Expand Down
3 changes: 2 additions & 1 deletion include/linux/can/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ enum can_mode {
* CAN common private data
*/
struct can_priv {
struct net_device *dev;
struct can_device_stats can_stats;

struct can_bittiming bittiming, data_bittiming;
Expand All @@ -43,7 +44,7 @@ struct can_priv {
u32 ctrlmode_supported;

int restart_ms;
struct timer_list restart_timer;
struct delayed_work restart_work;

int (*do_set_bittiming)(struct net_device *dev);
int (*do_set_data_bittiming)(struct net_device *dev);
Expand Down

1 comment on commit 0f6681e

@jhofstee
Copy link

@jhofstee jhofstee commented on 0f6681e Sep 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whatever the patch does, make sure to checkpatch it before posting, it has whitespace issues...

Please sign in to comment.