staging: most: aim-network: fix interrupt unsafe spinlocks
authorChristian Gromm <christian.gromm@microchip.com>
Thu, 18 Aug 2016 13:28:27 +0000 (15:28 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Aug 2016 15:24:00 +0000 (17:24 +0200)
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 <andrey.shvetsov@k2l.de>
Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/most/aim-network/networking.c

index 2f42de44d05137cf9e894675c71759934832b345..4659a6450c04f1c30c0695f473ba9875c0c08bbc 100644 (file)
@@ -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");