Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2012 Qualcomm Atheros, Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include "core.h"
0018 #include "cfg80211.h"
0019 #include "debug.h"
0020 
0021 static void ath6kl_recovery_work(struct work_struct *work)
0022 {
0023     struct ath6kl *ar = container_of(work, struct ath6kl,
0024                      fw_recovery.recovery_work);
0025 
0026     ar->state = ATH6KL_STATE_RECOVERY;
0027 
0028     del_timer_sync(&ar->fw_recovery.hb_timer);
0029 
0030     ath6kl_init_hw_restart(ar);
0031 
0032     ar->state = ATH6KL_STATE_ON;
0033     clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
0034 
0035     ar->fw_recovery.err_reason = 0;
0036 
0037     if (ar->fw_recovery.hb_poll)
0038         mod_timer(&ar->fw_recovery.hb_timer, jiffies +
0039               msecs_to_jiffies(ar->fw_recovery.hb_poll));
0040 }
0041 
0042 void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason)
0043 {
0044     if (!ar->fw_recovery.enable)
0045         return;
0046 
0047     ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n",
0048            reason);
0049 
0050     set_bit(reason, &ar->fw_recovery.err_reason);
0051 
0052     if (!test_bit(RECOVERY_CLEANUP, &ar->flag) &&
0053         ar->state != ATH6KL_STATE_RECOVERY)
0054         queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work);
0055 }
0056 
0057 void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie)
0058 {
0059     if (cookie == ar->fw_recovery.seq_num)
0060         ar->fw_recovery.hb_pending = false;
0061 }
0062 
0063 static void ath6kl_recovery_hb_timer(struct timer_list *t)
0064 {
0065     struct ath6kl *ar = from_timer(ar, t, fw_recovery.hb_timer);
0066     int err;
0067 
0068     if (test_bit(RECOVERY_CLEANUP, &ar->flag) ||
0069         (ar->state == ATH6KL_STATE_RECOVERY))
0070         return;
0071 
0072     if (ar->fw_recovery.hb_pending)
0073         ar->fw_recovery.hb_misscnt++;
0074     else
0075         ar->fw_recovery.hb_misscnt = 0;
0076 
0077     if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) {
0078         ar->fw_recovery.hb_misscnt = 0;
0079         ar->fw_recovery.seq_num = 0;
0080         ar->fw_recovery.hb_pending = false;
0081         ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE);
0082         return;
0083     }
0084 
0085     ar->fw_recovery.seq_num++;
0086     ar->fw_recovery.hb_pending = true;
0087 
0088     err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi,
0089                         ar->fw_recovery.seq_num, 0);
0090     if (err)
0091         ath6kl_warn("Failed to send hb challenge request, err:%d\n",
0092                 err);
0093 
0094     mod_timer(&ar->fw_recovery.hb_timer, jiffies +
0095           msecs_to_jiffies(ar->fw_recovery.hb_poll));
0096 }
0097 
0098 void ath6kl_recovery_init(struct ath6kl *ar)
0099 {
0100     struct ath6kl_fw_recovery *recovery = &ar->fw_recovery;
0101 
0102     clear_bit(RECOVERY_CLEANUP, &ar->flag);
0103     INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work);
0104     recovery->seq_num = 0;
0105     recovery->hb_misscnt = 0;
0106     ar->fw_recovery.hb_pending = false;
0107     timer_setup(&ar->fw_recovery.hb_timer, ath6kl_recovery_hb_timer,
0108             TIMER_DEFERRABLE);
0109 
0110     if (ar->fw_recovery.hb_poll)
0111         mod_timer(&ar->fw_recovery.hb_timer, jiffies +
0112               msecs_to_jiffies(ar->fw_recovery.hb_poll));
0113 }
0114 
0115 void ath6kl_recovery_cleanup(struct ath6kl *ar)
0116 {
0117     if (!ar->fw_recovery.enable)
0118         return;
0119 
0120     set_bit(RECOVERY_CLEANUP, &ar->flag);
0121 
0122     del_timer_sync(&ar->fw_recovery.hb_timer);
0123     cancel_work_sync(&ar->fw_recovery.recovery_work);
0124 }
0125 
0126 void ath6kl_recovery_suspend(struct ath6kl *ar)
0127 {
0128     if (!ar->fw_recovery.enable)
0129         return;
0130 
0131     ath6kl_recovery_cleanup(ar);
0132 
0133     if (!ar->fw_recovery.err_reason)
0134         return;
0135 
0136     /* Process pending fw error detection */
0137     ar->fw_recovery.err_reason = 0;
0138     WARN_ON(ar->state != ATH6KL_STATE_ON);
0139     ar->state = ATH6KL_STATE_RECOVERY;
0140     ath6kl_init_hw_restart(ar);
0141     ar->state = ATH6KL_STATE_ON;
0142 }
0143 
0144 void ath6kl_recovery_resume(struct ath6kl *ar)
0145 {
0146     if (!ar->fw_recovery.enable)
0147         return;
0148 
0149     clear_bit(RECOVERY_CLEANUP, &ar->flag);
0150 
0151     if (!ar->fw_recovery.hb_poll)
0152         return;
0153 
0154     ar->fw_recovery.hb_pending = false;
0155     ar->fw_recovery.seq_num = 0;
0156     ar->fw_recovery.hb_misscnt = 0;
0157     mod_timer(&ar->fw_recovery.hb_timer,
0158           jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll));
0159 }