Commit 731c6531 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

p54spi: fix locking warning in p54spi_op_tx

This patch fixes the following waring:
> ------------[ cut here ]------------
>WARNING: at kernel/softirq.c:138 local_bh_enable+0x54/0xbc()
>Modules linked in: p54spi
>[<c0034ff8>] (dump_stack+0x0/0x14)
>[<c005b1a4>] (warn_on_slowpath+0x0/0x68)
>[<c00604c8>] (local_bh_enable+0x0/0xbc)
>[<bf000000>] (p54spi_op_tx+0x0/0x4c [p54spi])
>[<c01a4d34>] (p54_sta_unlock+0x0/0x78)

p54spi_op_tx needs to be called from different locking contexts.
Therefore we have to protect the linked list with irqsave spinlocks.
Reported-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 54082819
...@@ -457,9 +457,10 @@ static int p54spi_wq_tx(struct p54s_priv *priv) ...@@ -457,9 +457,10 @@ static int p54spi_wq_tx(struct p54s_priv *priv)
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
struct p54_tx_info *minfo; struct p54_tx_info *minfo;
struct p54s_tx_info *dinfo; struct p54s_tx_info *dinfo;
unsigned long flags;
int ret = 0; int ret = 0;
spin_lock_bh(&priv->tx_lock); spin_lock_irqsave(&priv->tx_lock, flags);
while (!list_empty(&priv->tx_pending)) { while (!list_empty(&priv->tx_pending)) {
entry = list_entry(priv->tx_pending.next, entry = list_entry(priv->tx_pending.next,
...@@ -467,7 +468,7 @@ static int p54spi_wq_tx(struct p54s_priv *priv) ...@@ -467,7 +468,7 @@ static int p54spi_wq_tx(struct p54s_priv *priv)
list_del_init(&entry->tx_list); list_del_init(&entry->tx_list);
spin_unlock_bh(&priv->tx_lock); spin_unlock_irqrestore(&priv->tx_lock, flags);
dinfo = container_of((void *) entry, struct p54s_tx_info, dinfo = container_of((void *) entry, struct p54s_tx_info,
tx_list); tx_list);
...@@ -479,16 +480,14 @@ static int p54spi_wq_tx(struct p54s_priv *priv) ...@@ -479,16 +480,14 @@ static int p54spi_wq_tx(struct p54s_priv *priv)
ret = p54spi_tx_frame(priv, skb); ret = p54spi_tx_frame(priv, skb);
spin_lock_bh(&priv->tx_lock);
if (ret < 0) { if (ret < 0) {
p54_free_skb(priv->hw, skb); p54_free_skb(priv->hw, skb);
goto out; return ret;
}
} }
out: spin_lock_irqsave(&priv->tx_lock, flags);
spin_unlock_bh(&priv->tx_lock); }
spin_unlock_irqrestore(&priv->tx_lock, flags);
return ret; return ret;
} }
...@@ -498,12 +497,13 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -498,12 +497,13 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct p54_tx_info *mi = (struct p54_tx_info *) info->rate_driver_data; struct p54_tx_info *mi = (struct p54_tx_info *) info->rate_driver_data;
struct p54s_tx_info *di = (struct p54s_tx_info *) mi->data; struct p54s_tx_info *di = (struct p54s_tx_info *) mi->data;
unsigned long flags;
BUILD_BUG_ON(sizeof(*di) > sizeof((mi->data))); BUILD_BUG_ON(sizeof(*di) > sizeof((mi->data)));
spin_lock_bh(&priv->tx_lock); spin_lock_irqsave(&priv->tx_lock, flags);
list_add_tail(&di->tx_list, &priv->tx_pending); list_add_tail(&di->tx_list, &priv->tx_pending);
spin_unlock_bh(&priv->tx_lock); spin_unlock_irqrestore(&priv->tx_lock, flags);
queue_work(priv->hw->workqueue, &priv->work); queue_work(priv->hw->workqueue, &priv->work);
} }
...@@ -604,6 +604,7 @@ static int p54spi_op_start(struct ieee80211_hw *dev) ...@@ -604,6 +604,7 @@ static int p54spi_op_start(struct ieee80211_hw *dev)
static void p54spi_op_stop(struct ieee80211_hw *dev) static void p54spi_op_stop(struct ieee80211_hw *dev)
{ {
struct p54s_priv *priv = dev->priv; struct p54s_priv *priv = dev->priv;
unsigned long flags;
if (mutex_lock_interruptible(&priv->mutex)) { if (mutex_lock_interruptible(&priv->mutex)) {
/* FIXME: how to handle this error? */ /* FIXME: how to handle this error? */
...@@ -615,9 +616,9 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) ...@@ -615,9 +616,9 @@ static void p54spi_op_stop(struct ieee80211_hw *dev)
cancel_work_sync(&priv->work); cancel_work_sync(&priv->work);
p54spi_power_off(priv); p54spi_power_off(priv);
spin_lock_bh(&priv->tx_lock); spin_lock_irqsave(&priv->tx_lock, flags);
INIT_LIST_HEAD(&priv->tx_pending); INIT_LIST_HEAD(&priv->tx_pending);
spin_unlock_bh(&priv->tx_lock); spin_unlock_irqrestore(&priv->tx_lock, flags);
priv->fw_state = FW_STATE_OFF; priv->fw_state = FW_STATE_OFF;
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
......
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