2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 static void ath6kl_recovery_work(struct work_struct
*work
)
23 struct ath6kl
*ar
= container_of(work
, struct ath6kl
,
24 fw_recovery
.recovery_work
);
26 ar
->state
= ATH6KL_STATE_RECOVERY
;
28 del_timer_sync(&ar
->fw_recovery
.hb_timer
);
30 ath6kl_init_hw_restart(ar
);
32 ar
->state
= ATH6KL_STATE_ON
;
33 clear_bit(WMI_CTRL_EP_FULL
, &ar
->flag
);
35 ar
->fw_recovery
.err_reason
= 0;
37 if (ar
->fw_recovery
.hb_poll
)
38 mod_timer(&ar
->fw_recovery
.hb_timer
, jiffies
+
39 msecs_to_jiffies(ar
->fw_recovery
.hb_poll
));
42 void ath6kl_recovery_err_notify(struct ath6kl
*ar
, enum ath6kl_fw_err reason
)
44 if (!ar
->fw_recovery
.enable
)
47 ath6kl_dbg(ATH6KL_DBG_RECOVERY
, "Fw error detected, reason:%d\n",
50 set_bit(reason
, &ar
->fw_recovery
.err_reason
);
52 if (!test_bit(RECOVERY_CLEANUP
, &ar
->flag
) &&
53 ar
->state
!= ATH6KL_STATE_RECOVERY
)
54 queue_work(ar
->ath6kl_wq
, &ar
->fw_recovery
.recovery_work
);
57 void ath6kl_recovery_hb_event(struct ath6kl
*ar
, u32 cookie
)
59 if (cookie
== ar
->fw_recovery
.seq_num
)
60 ar
->fw_recovery
.hb_pending
= false;
63 static void ath6kl_recovery_hb_timer(unsigned long data
)
65 struct ath6kl
*ar
= (struct ath6kl
*) data
;
68 if (test_bit(RECOVERY_CLEANUP
, &ar
->flag
) ||
69 (ar
->state
== ATH6KL_STATE_RECOVERY
))
72 if (ar
->fw_recovery
.hb_pending
)
73 ar
->fw_recovery
.hb_misscnt
++;
75 ar
->fw_recovery
.hb_misscnt
= 0;
77 if (ar
->fw_recovery
.hb_misscnt
> ATH6KL_HB_RESP_MISS_THRES
) {
78 ar
->fw_recovery
.hb_misscnt
= 0;
79 ar
->fw_recovery
.seq_num
= 0;
80 ar
->fw_recovery
.hb_pending
= false;
81 ath6kl_recovery_err_notify(ar
, ATH6KL_FW_HB_RESP_FAILURE
);
85 ar
->fw_recovery
.seq_num
++;
86 ar
->fw_recovery
.hb_pending
= true;
88 err
= ath6kl_wmi_get_challenge_resp_cmd(ar
->wmi
,
89 ar
->fw_recovery
.seq_num
, 0);
91 ath6kl_warn("Failed to send hb challenge request, err:%d\n",
94 mod_timer(&ar
->fw_recovery
.hb_timer
, jiffies
+
95 msecs_to_jiffies(ar
->fw_recovery
.hb_poll
));
98 void ath6kl_recovery_init(struct ath6kl
*ar
)
100 struct ath6kl_fw_recovery
*recovery
= &ar
->fw_recovery
;
102 clear_bit(RECOVERY_CLEANUP
, &ar
->flag
);
103 INIT_WORK(&recovery
->recovery_work
, ath6kl_recovery_work
);
104 recovery
->seq_num
= 0;
105 recovery
->hb_misscnt
= 0;
106 ar
->fw_recovery
.hb_pending
= false;
107 ar
->fw_recovery
.hb_timer
.function
= ath6kl_recovery_hb_timer
;
108 ar
->fw_recovery
.hb_timer
.data
= (unsigned long) ar
;
109 init_timer_deferrable(&ar
->fw_recovery
.hb_timer
);
111 if (ar
->fw_recovery
.hb_poll
)
112 mod_timer(&ar
->fw_recovery
.hb_timer
, jiffies
+
113 msecs_to_jiffies(ar
->fw_recovery
.hb_poll
));
116 void ath6kl_recovery_cleanup(struct ath6kl
*ar
)
118 if (!ar
->fw_recovery
.enable
)
121 set_bit(RECOVERY_CLEANUP
, &ar
->flag
);
123 del_timer_sync(&ar
->fw_recovery
.hb_timer
);
124 cancel_work_sync(&ar
->fw_recovery
.recovery_work
);
127 void ath6kl_recovery_suspend(struct ath6kl
*ar
)
129 if (!ar
->fw_recovery
.enable
)
132 ath6kl_recovery_cleanup(ar
);
134 if (!ar
->fw_recovery
.err_reason
)
137 /* Process pending fw error detection */
138 ar
->fw_recovery
.err_reason
= 0;
139 WARN_ON(ar
->state
!= ATH6KL_STATE_ON
);
140 ar
->state
= ATH6KL_STATE_RECOVERY
;
141 ath6kl_init_hw_restart(ar
);
142 ar
->state
= ATH6KL_STATE_ON
;
145 void ath6kl_recovery_resume(struct ath6kl
*ar
)
147 if (!ar
->fw_recovery
.enable
)
150 clear_bit(RECOVERY_CLEANUP
, &ar
->flag
);
152 if (!ar
->fw_recovery
.hb_poll
)
155 ar
->fw_recovery
.hb_pending
= false;
156 ar
->fw_recovery
.seq_num
= 0;
157 ar
->fw_recovery
.hb_misscnt
= 0;
158 mod_timer(&ar
->fw_recovery
.hb_timer
,
159 jiffies
+ msecs_to_jiffies(ar
->fw_recovery
.hb_poll
));