From a75c03126f93713e121ea90fbaa2eaf55063c236 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Thu, 18 Aug 2016 15:28:27 +0200 Subject: [PATCH] staging: most: aim-network: fix interrupt unsafe spinlocks The networking AIM does not use the *_irqsave and *_irqrestore flavored spinlock functions. The rx_completion callback, however, can be called from an interrupt context. This patch is needed to fix this problem. Signed-off-by: Andrey Shvetsov Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-network/networking.c | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 2f42de44d051..4659a6450c04 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -298,15 +298,16 @@ static struct net_dev_context *get_net_dev_context( struct most_interface *iface) { struct net_dev_context *nd, *tmp; + unsigned long flags; - spin_lock(&list_lock); + spin_lock_irqsave(&list_lock, flags); list_for_each_entry_safe(nd, tmp, &net_devices, list) { if (nd->iface == iface) { - spin_unlock(&list_lock); + spin_unlock_irqrestore(&list_lock, flags); return nd; } } - spin_unlock(&list_lock); + spin_unlock_irqrestore(&list_lock, flags); return NULL; } @@ -316,6 +317,7 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, { struct net_dev_context *nd; struct net_dev_channel *ch; + unsigned long flags; if (!iface) return -EINVAL; @@ -332,9 +334,9 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, nd->iface = iface; - spin_lock(&list_lock); + spin_lock_irqsave(&list_lock, flags); list_add(&nd->list, &net_devices); - spin_unlock(&list_lock); + spin_unlock_irqrestore(&list_lock, flags); } ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; @@ -377,6 +379,7 @@ static int aim_disconnect_channel(struct most_interface *iface, { struct net_dev_context *nd; struct net_dev_channel *ch; + unsigned long flags; nd = get_net_dev_context(iface); if (!nd) @@ -398,9 +401,9 @@ static int aim_disconnect_channel(struct most_interface *iface, most_net_rm_netdev_safe(nd); if (!nd->rx.linked && !nd->tx.linked) { - spin_lock(&list_lock); + spin_lock_irqsave(&list_lock, flags); list_del(&nd->list); - spin_unlock(&list_lock); + spin_unlock_irqrestore(&list_lock, flags); kfree(nd); } @@ -514,20 +517,21 @@ static int __init most_net_init(void) static void __exit most_net_exit(void) { struct net_dev_context *nd, *tmp; + unsigned long flags; - spin_lock(&list_lock); + spin_lock_irqsave(&list_lock, flags); list_for_each_entry_safe(nd, tmp, &net_devices, list) { list_del(&nd->list); - spin_unlock(&list_lock); + spin_unlock_irqrestore(&list_lock, flags); /* * do not call most_stop_channel() here, because channels are * going to be closed in ndo_stop() after unregister_netdev() */ most_net_rm_netdev_safe(nd); kfree(nd); - spin_lock(&list_lock); + spin_lock_irqsave(&list_lock, flags); } - spin_unlock(&list_lock); + spin_unlock_irqrestore(&list_lock, flags); most_deregister_aim(&aim); pr_info("most_net_exit()\n"); -- 2.20.1