diff options
author | Eyal Shapira <eyal@wizery.com> | 2012-03-13 14:03:21 -0400 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2012-04-10 05:13:58 -0400 |
commit | c56dbd57f3627203f2384ae1a5e71cf41904370e (patch) | |
tree | eef330174723ebad94d1cbce5cc1284cd71b3f7d | |
parent | ec414c7c78d6d81c31d77a892fed0b5f691a6d4e (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.c | 29 |
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 | ||
1674 | out_unlock: | 1671 | out: |
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); |
1697 | out_unlock: | 1691 | out: |
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); |
1742 | out: | ||
1743 | mutex_unlock(&wl->mutex); | ||
1744 | } | 1734 | } |
1745 | 1735 | ||
1746 | static int wl1271_op_suspend(struct ieee80211_hw *hw, | 1736 | static 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 | } |