aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEyal Shapira <eyal@wizery.com>2012-03-13 14:03:21 -0400
committerLuciano Coelho <coelho@ti.com>2012-04-10 05:13:58 -0400
commitc56dbd57f3627203f2384ae1a5e71cf41904370e (patch)
treeeef330174723ebad94d1cbce5cc1284cd71b3f7d
parentec414c7c78d6d81c31d77a892fed0b5f691a6d4e (diff)
wl12xx: fix race between suspend/resume and recovery
The iteration on the wlvif list in wl1271_op_resume/suspend was perfomed before locking wl->mutex which would lead to a kernel panic in case a recovery was queued at the same time and would delete the wlvifs from the list. Signed-off-by: Eyal Shapira <eyal@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
-rw-r--r--drivers/net/wireless/wl12xx/main.c29
1 files changed, 12 insertions, 17 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index a1ede7b48270..13820437806e 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1652,14 +1652,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1652{ 1652{
1653 int ret = 0; 1653 int ret = 0;
1654 1654
1655 mutex_lock(&wl->mutex);
1656
1657 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) 1655 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1658 goto out_unlock; 1656 goto out;
1659 1657
1660 ret = wl1271_ps_elp_wakeup(wl); 1658 ret = wl1271_ps_elp_wakeup(wl);
1661 if (ret < 0) 1659 if (ret < 0)
1662 goto out_unlock; 1660 goto out;
1663 1661
1664 ret = wl1271_acx_wake_up_conditions(wl, wlvif, 1662 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1665 wl->conf.conn.suspend_wake_up_event, 1663 wl->conf.conn.suspend_wake_up_event,
@@ -1668,11 +1666,9 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1668 if (ret < 0) 1666 if (ret < 0)
1669 wl1271_error("suspend: set wake up conditions failed: %d", ret); 1667 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1670 1668
1671
1672 wl1271_ps_elp_sleep(wl); 1669 wl1271_ps_elp_sleep(wl);
1673 1670
1674out_unlock: 1671out:
1675 mutex_unlock(&wl->mutex);
1676 return ret; 1672 return ret;
1677 1673
1678} 1674}
@@ -1682,20 +1678,17 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1682{ 1678{
1683 int ret = 0; 1679 int ret = 0;
1684 1680
1685 mutex_lock(&wl->mutex);
1686
1687 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) 1681 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
1688 goto out_unlock; 1682 goto out;
1689 1683
1690 ret = wl1271_ps_elp_wakeup(wl); 1684 ret = wl1271_ps_elp_wakeup(wl);
1691 if (ret < 0) 1685 if (ret < 0)
1692 goto out_unlock; 1686 goto out;
1693 1687
1694 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); 1688 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
1695 1689
1696 wl1271_ps_elp_sleep(wl); 1690 wl1271_ps_elp_sleep(wl);
1697out_unlock: 1691out:
1698 mutex_unlock(&wl->mutex);
1699 return ret; 1692 return ret;
1700 1693
1701} 1694}
@@ -1720,10 +1713,9 @@ static void wl1271_configure_resume(struct wl1271 *wl,
1720 if ((!is_ap) && (!is_sta)) 1713 if ((!is_ap) && (!is_sta))
1721 return; 1714 return;
1722 1715
1723 mutex_lock(&wl->mutex);
1724 ret = wl1271_ps_elp_wakeup(wl); 1716 ret = wl1271_ps_elp_wakeup(wl);
1725 if (ret < 0) 1717 if (ret < 0)
1726 goto out; 1718 return;
1727 1719
1728 if (is_sta) { 1720 if (is_sta) {
1729 ret = wl1271_acx_wake_up_conditions(wl, wlvif, 1721 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
@@ -1739,8 +1731,6 @@ static void wl1271_configure_resume(struct wl1271 *wl,
1739 } 1731 }
1740 1732
1741 wl1271_ps_elp_sleep(wl); 1733 wl1271_ps_elp_sleep(wl);
1742out:
1743 mutex_unlock(&wl->mutex);
1744} 1734}
1745 1735
1746static int wl1271_op_suspend(struct ieee80211_hw *hw, 1736static int wl1271_op_suspend(struct ieee80211_hw *hw,
@@ -1755,6 +1745,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
1755 1745
1756 wl1271_tx_flush(wl); 1746 wl1271_tx_flush(wl);
1757 1747
1748 mutex_lock(&wl->mutex);
1758 wl->wow_enabled = true; 1749 wl->wow_enabled = true;
1759 wl12xx_for_each_wlvif(wl, wlvif) { 1750 wl12xx_for_each_wlvif(wl, wlvif) {
1760 ret = wl1271_configure_suspend(wl, wlvif); 1751 ret = wl1271_configure_suspend(wl, wlvif);
@@ -1763,6 +1754,7 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
1763 return ret; 1754 return ret;
1764 } 1755 }
1765 } 1756 }
1757 mutex_unlock(&wl->mutex);
1766 /* flush any remaining work */ 1758 /* flush any remaining work */
1767 wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); 1759 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1768 1760
@@ -1812,10 +1804,13 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
1812 wl1271_irq(0, wl); 1804 wl1271_irq(0, wl);
1813 wl1271_enable_interrupts(wl); 1805 wl1271_enable_interrupts(wl);
1814 } 1806 }
1807
1808 mutex_lock(&wl->mutex);
1815 wl12xx_for_each_wlvif(wl, wlvif) { 1809 wl12xx_for_each_wlvif(wl, wlvif) {
1816 wl1271_configure_resume(wl, wlvif); 1810 wl1271_configure_resume(wl, wlvif);
1817 } 1811 }
1818 wl->wow_enabled = false; 1812 wl->wow_enabled = false;
1813 mutex_unlock(&wl->mutex);
1819 1814
1820 return 0; 1815 return 0;
1821} 1816}