aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k/mac.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2013-07-16 03:54:35 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2013-07-30 11:01:20 -0400
commitaffd321733eebc92b12cd329505f63e94ae80c93 (patch)
tree2e743c8a0a89f6e6057cd2c8f4b96769dfcdde17 /drivers/net/wireless/ath/ath10k/mac.c
parent87571bf0b8b27d4a97848ce48de34fa6d3b12db8 (diff)
ath10k: implement device recovery
Restart the hardware if FW crashes. If FW crashes during recovery we leave the hardware in a "wedged" state to avoid recursive recoveries. When in "wedged" state userspace may bring interfaces down (to issue stop()) and then bring one interface (to issue start()) to reload hardware manually. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/mac.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c101
1 files changed, 82 insertions, 19 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2dfd446251b1..b1bb318d153f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1738,7 +1738,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
1738/* 1738/*
1739 * Initialize various parameters with default vaules. 1739 * Initialize various parameters with default vaules.
1740 */ 1740 */
1741static void ath10k_halt(struct ath10k *ar) 1741void ath10k_halt(struct ath10k *ar)
1742{ 1742{
1743 lockdep_assert_held(&ar->conf_mutex); 1743 lockdep_assert_held(&ar->conf_mutex);
1744 1744
@@ -1764,7 +1764,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
1764 1764
1765 mutex_lock(&ar->conf_mutex); 1765 mutex_lock(&ar->conf_mutex);
1766 1766
1767 if (ar->state != ATH10K_STATE_OFF) { 1767 if (ar->state != ATH10K_STATE_OFF &&
1768 ar->state != ATH10K_STATE_RESTARTING) {
1768 ret = -EINVAL; 1769 ret = -EINVAL;
1769 goto exit; 1770 goto exit;
1770 } 1771 }
@@ -1784,6 +1785,11 @@ static int ath10k_start(struct ieee80211_hw *hw)
1784 goto exit; 1785 goto exit;
1785 } 1786 }
1786 1787
1788 if (ar->state == ATH10K_STATE_OFF)
1789 ar->state = ATH10K_STATE_ON;
1790 else if (ar->state == ATH10K_STATE_RESTARTING)
1791 ar->state = ATH10K_STATE_RESTARTED;
1792
1787 ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1); 1793 ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1);
1788 if (ret) 1794 if (ret)
1789 ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n", 1795 ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
@@ -1806,22 +1812,47 @@ static void ath10k_stop(struct ieee80211_hw *hw)
1806 struct ath10k *ar = hw->priv; 1812 struct ath10k *ar = hw->priv;
1807 1813
1808 mutex_lock(&ar->conf_mutex); 1814 mutex_lock(&ar->conf_mutex);
1809 if (ar->state == ATH10K_STATE_ON) 1815 if (ar->state == ATH10K_STATE_ON ||
1816 ar->state == ATH10K_STATE_RESTARTED ||
1817 ar->state == ATH10K_STATE_WEDGED)
1810 ath10k_halt(ar); 1818 ath10k_halt(ar);
1811 1819
1812 ar->state = ATH10K_STATE_OFF; 1820 ar->state = ATH10K_STATE_OFF;
1813 mutex_unlock(&ar->conf_mutex); 1821 mutex_unlock(&ar->conf_mutex);
1814 1822
1815 cancel_work_sync(&ar->offchan_tx_work); 1823 cancel_work_sync(&ar->offchan_tx_work);
1824 cancel_work_sync(&ar->restart_work);
1816} 1825}
1817 1826
1818static int ath10k_config(struct ieee80211_hw *hw, u32 changed) 1827static void ath10k_config_ps(struct ath10k *ar)
1819{ 1828{
1820 struct ath10k_generic_iter ar_iter; 1829 struct ath10k_generic_iter ar_iter;
1830
1831 lockdep_assert_held(&ar->conf_mutex);
1832
1833 /* During HW reconfiguration mac80211 reports all interfaces that were
1834 * running until reconfiguration was started. Since FW doesn't have any
1835 * vdevs at this point we must not iterate over this interface list.
1836 * This setting will be updated upon add_interface(). */
1837 if (ar->state == ATH10K_STATE_RESTARTED)
1838 return;
1839
1840 memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
1841 ar_iter.ar = ar;
1842
1843 ieee80211_iterate_active_interfaces_atomic(
1844 ar->hw, IEEE80211_IFACE_ITER_NORMAL,
1845 ath10k_ps_iter, &ar_iter);
1846
1847 if (ar_iter.ret)
1848 ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret);
1849}
1850
1851static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
1852{
1821 struct ath10k *ar = hw->priv; 1853 struct ath10k *ar = hw->priv;
1822 struct ieee80211_conf *conf = &hw->conf; 1854 struct ieee80211_conf *conf = &hw->conf;
1823 int ret = 0; 1855 int ret = 0;
1824 u32 flags;
1825 1856
1826 mutex_lock(&ar->conf_mutex); 1857 mutex_lock(&ar->conf_mutex);
1827 1858
@@ -1833,18 +1864,8 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
1833 spin_unlock_bh(&ar->data_lock); 1864 spin_unlock_bh(&ar->data_lock);
1834 } 1865 }
1835 1866
1836 if (changed & IEEE80211_CONF_CHANGE_PS) { 1867 if (changed & IEEE80211_CONF_CHANGE_PS)
1837 memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); 1868 ath10k_config_ps(ar);
1838 ar_iter.ar = ar;
1839 flags = IEEE80211_IFACE_ITER_RESUME_ALL;
1840
1841 ieee80211_iterate_active_interfaces_atomic(hw,
1842 flags,
1843 ath10k_ps_iter,
1844 &ar_iter);
1845
1846 ret = ar_iter.ret;
1847 }
1848 1869
1849 if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 1870 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1850 if (conf->flags & IEEE80211_CONF_MONITOR) 1871 if (conf->flags & IEEE80211_CONF_MONITOR)
@@ -1853,6 +1874,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
1853 ret = ath10k_monitor_destroy(ar); 1874 ret = ath10k_monitor_destroy(ar);
1854 } 1875 }
1855 1876
1877 ath10k_wmi_flush_tx(ar);
1856 mutex_unlock(&ar->conf_mutex); 1878 mutex_unlock(&ar->conf_mutex);
1857 return ret; 1879 return ret;
1858} 1880}
@@ -2695,6 +2717,13 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
2695 2717
2696 lockdep_assert_held(&arvif->ar->conf_mutex); 2718 lockdep_assert_held(&arvif->ar->conf_mutex);
2697 2719
2720 /* During HW reconfiguration mac80211 reports all interfaces that were
2721 * running until reconfiguration was started. Since FW doesn't have any
2722 * vdevs at this point we must not iterate over this interface list.
2723 * This setting will be updated upon add_interface(). */
2724 if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
2725 return;
2726
2698 rts = min_t(u32, rts, ATH10K_RTS_MAX); 2727 rts = min_t(u32, rts, ATH10K_RTS_MAX);
2699 2728
2700 ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id, 2729 ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id,
@@ -2735,6 +2764,13 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
2735 2764
2736 lockdep_assert_held(&arvif->ar->conf_mutex); 2765 lockdep_assert_held(&arvif->ar->conf_mutex);
2737 2766
2767 /* During HW reconfiguration mac80211 reports all interfaces that were
2768 * running until reconfiguration was started. Since FW doesn't have any
2769 * vdevs at this point we must not iterate over this interface list.
2770 * This setting will be updated upon add_interface(). */
2771 if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
2772 return;
2773
2738 frag = clamp_t(u32, frag, 2774 frag = clamp_t(u32, frag,
2739 ATH10K_FRAGMT_THRESHOLD_MIN, 2775 ATH10K_FRAGMT_THRESHOLD_MIN,
2740 ATH10K_FRAGMT_THRESHOLD_MAX); 2776 ATH10K_FRAGMT_THRESHOLD_MAX);
@@ -2773,6 +2809,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2773static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) 2809static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
2774{ 2810{
2775 struct ath10k *ar = hw->priv; 2811 struct ath10k *ar = hw->priv;
2812 bool skip;
2776 int ret; 2813 int ret;
2777 2814
2778 /* mac80211 doesn't care if we really xmit queued frames or not 2815 /* mac80211 doesn't care if we really xmit queued frames or not
@@ -2782,17 +2819,26 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
2782 2819
2783 mutex_lock(&ar->conf_mutex); 2820 mutex_lock(&ar->conf_mutex);
2784 2821
2822 if (ar->state == ATH10K_STATE_WEDGED)
2823 goto skip;
2824
2785 ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ 2825 ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
2786 bool empty; 2826 bool empty;
2827
2787 spin_lock_bh(&ar->htt.tx_lock); 2828 spin_lock_bh(&ar->htt.tx_lock);
2788 empty = bitmap_empty(ar->htt.used_msdu_ids, 2829 empty = bitmap_empty(ar->htt.used_msdu_ids,
2789 ar->htt.max_num_pending_tx); 2830 ar->htt.max_num_pending_tx);
2790 spin_unlock_bh(&ar->htt.tx_lock); 2831 spin_unlock_bh(&ar->htt.tx_lock);
2791 (empty); 2832
2833 skip = (ar->state == ATH10K_STATE_WEDGED);
2834
2835 (empty || skip);
2792 }), ATH10K_FLUSH_TIMEOUT_HZ); 2836 }), ATH10K_FLUSH_TIMEOUT_HZ);
2793 if (ret <= 0) 2837
2838 if (ret <= 0 || skip)
2794 ath10k_warn("tx not flushed\n"); 2839 ath10k_warn("tx not flushed\n");
2795 2840
2841skip:
2796 mutex_unlock(&ar->conf_mutex); 2842 mutex_unlock(&ar->conf_mutex);
2797} 2843}
2798 2844
@@ -2866,6 +2912,22 @@ static int ath10k_resume(struct ieee80211_hw *hw)
2866} 2912}
2867#endif 2913#endif
2868 2914
2915static void ath10k_restart_complete(struct ieee80211_hw *hw)
2916{
2917 struct ath10k *ar = hw->priv;
2918
2919 mutex_lock(&ar->conf_mutex);
2920
2921 /* If device failed to restart it will be in a different state, e.g.
2922 * ATH10K_STATE_WEDGED */
2923 if (ar->state == ATH10K_STATE_RESTARTED) {
2924 ath10k_info("device successfully recovered\n");
2925 ar->state = ATH10K_STATE_ON;
2926 }
2927
2928 mutex_unlock(&ar->conf_mutex);
2929}
2930
2869static const struct ieee80211_ops ath10k_ops = { 2931static const struct ieee80211_ops ath10k_ops = {
2870 .tx = ath10k_tx, 2932 .tx = ath10k_tx,
2871 .start = ath10k_start, 2933 .start = ath10k_start,
@@ -2886,6 +2948,7 @@ static const struct ieee80211_ops ath10k_ops = {
2886 .set_frag_threshold = ath10k_set_frag_threshold, 2948 .set_frag_threshold = ath10k_set_frag_threshold,
2887 .flush = ath10k_flush, 2949 .flush = ath10k_flush,
2888 .tx_last_beacon = ath10k_tx_last_beacon, 2950 .tx_last_beacon = ath10k_tx_last_beacon,
2951 .restart_complete = ath10k_restart_complete,
2889#ifdef CONFIG_PM 2952#ifdef CONFIG_PM
2890 .suspend = ath10k_suspend, 2953 .suspend = ath10k_suspend,
2891 .resume = ath10k_resume, 2954 .resume = ath10k_resume,