aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2010-12-28 03:58:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-04 14:43:00 -0500
commit73908674c6957082e8ab57daed57d2bb97a1ebba (patch)
treeab265ea89903ad81486622ae9a71534f63dcd300 /drivers/net/wireless
parent66e3547431a8738416b508badfb9f326d11dabcc (diff)
ath9k_htc: Handle FATAL events
The device has to be reset when a FATAL event is received. Not doing so would leave the card in a non-working state. Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c57
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h3
5 files changed, 84 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index e6c2f0aad28f..10622740dc76 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -377,7 +377,7 @@ struct ath9k_htc_priv {
377 struct ieee80211_vif *vif; 377 struct ieee80211_vif *vif;
378 struct htc_beacon_config cur_beacon_conf; 378 struct htc_beacon_config cur_beacon_conf;
379 unsigned int rxfilter; 379 unsigned int rxfilter;
380 struct tasklet_struct wmi_tasklet; 380 struct tasklet_struct swba_tasklet;
381 struct tasklet_struct rx_tasklet; 381 struct tasklet_struct rx_tasklet;
382 struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; 382 struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
383 struct ath9k_htc_rx rx; 383 struct ath9k_htc_rx rx;
@@ -385,6 +385,7 @@ struct ath9k_htc_priv {
385 struct sk_buff_head tx_queue; 385 struct sk_buff_head tx_queue;
386 struct delayed_work ath9k_ani_work; 386 struct delayed_work ath9k_ani_work;
387 struct work_struct ps_work; 387 struct work_struct ps_work;
388 struct work_struct fatal_work;
388 389
389 struct mutex htc_pm_lock; 390 struct mutex htc_pm_lock;
390 unsigned long ps_usecount; 391 unsigned long ps_usecount;
@@ -419,6 +420,8 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
419 common->bus_ops->read_cachesize(common, csz); 420 common->bus_ops->read_cachesize(common, csz);
420} 421}
421 422
423void ath9k_htc_reset(struct ath9k_htc_priv *priv);
424
422void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); 425void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
423void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, 426void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
424 struct ieee80211_vif *vif); 427 struct ieee80211_vif *vif);
@@ -434,6 +437,7 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
434void ath9k_htc_station_work(struct work_struct *work); 437void ath9k_htc_station_work(struct work_struct *work);
435void ath9k_htc_aggr_work(struct work_struct *work); 438void ath9k_htc_aggr_work(struct work_struct *work);
436void ath9k_ani_work(struct work_struct *work);; 439void ath9k_ani_work(struct work_struct *work);;
440void ath_start_ani(struct ath9k_htc_priv *priv);
437 441
438int ath9k_tx_init(struct ath9k_htc_priv *priv); 442int ath9k_tx_init(struct ath9k_htc_priv *priv);
439void ath9k_tx_tasklet(unsigned long data); 443void ath9k_tx_tasklet(unsigned long data);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 724f5451a415..9150ca665367 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -142,7 +142,7 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
142{ 142{
143 ath9k_htc_exit_debug(priv->ah); 143 ath9k_htc_exit_debug(priv->ah);
144 ath9k_hw_deinit(priv->ah); 144 ath9k_hw_deinit(priv->ah);
145 tasklet_kill(&priv->wmi_tasklet); 145 tasklet_kill(&priv->swba_tasklet);
146 tasklet_kill(&priv->rx_tasklet); 146 tasklet_kill(&priv->rx_tasklet);
147 tasklet_kill(&priv->tx_tasklet); 147 tasklet_kill(&priv->tx_tasklet);
148 kfree(priv->ah); 148 kfree(priv->ah);
@@ -647,13 +647,15 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
647 spin_lock_init(&priv->tx_lock); 647 spin_lock_init(&priv->tx_lock);
648 mutex_init(&priv->mutex); 648 mutex_init(&priv->mutex);
649 mutex_init(&priv->htc_pm_lock); 649 mutex_init(&priv->htc_pm_lock);
650 tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, 650 tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
651 (unsigned long)priv); 651 (unsigned long)priv);
652 tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, 652 tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
653 (unsigned long)priv); 653 (unsigned long)priv);
654 tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); 654 tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
655 (unsigned long)priv);
655 INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); 656 INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
656 INIT_WORK(&priv->ps_work, ath9k_ps_work); 657 INIT_WORK(&priv->ps_work, ath9k_ps_work);
658 INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
657 659
658 /* 660 /*
659 * Cache line size is used to size and align various 661 * Cache line size is used to size and align various
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 5f75f70db5a7..07f10ddee6a5 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -116,6 +116,60 @@ void ath9k_ps_work(struct work_struct *work)
116 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); 116 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
117} 117}
118 118
119void ath9k_htc_reset(struct ath9k_htc_priv *priv)
120{
121 struct ath_hw *ah = priv->ah;
122 struct ath_common *common = ath9k_hw_common(ah);
123 struct ieee80211_channel *channel = priv->hw->conf.channel;
124 struct ath9k_hw_cal_data *caldata;
125 enum htc_phymode mode;
126 __be16 htc_mode;
127 u8 cmd_rsp;
128 int ret;
129
130 mutex_lock(&priv->mutex);
131 ath9k_htc_ps_wakeup(priv);
132
133 if (priv->op_flags & OP_ASSOCIATED)
134 cancel_delayed_work_sync(&priv->ath9k_ani_work);
135
136 ieee80211_stop_queues(priv->hw);
137 htc_stop(priv->htc);
138 WMI_CMD(WMI_DISABLE_INTR_CMDID);
139 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
140 WMI_CMD(WMI_STOP_RECV_CMDID);
141
142 caldata = &priv->caldata[channel->hw_value];
143 ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
144 if (ret) {
145 ath_err(common,
146 "Unable to reset device (%u Mhz) reset status %d\n",
147 channel->center_freq, ret);
148 }
149
150 ath_update_txpow(priv);
151
152 WMI_CMD(WMI_START_RECV_CMDID);
153 ath9k_host_rx_init(priv);
154
155 mode = ath9k_htc_get_curmode(priv, ah->curchan);
156 htc_mode = cpu_to_be16(mode);
157 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
158
159 WMI_CMD(WMI_ENABLE_INTR_CMDID);
160 htc_start(priv->htc);
161
162 if (priv->op_flags & OP_ASSOCIATED) {
163 ath9k_htc_beacon_config(priv, priv->vif);
164 ath_start_ani(priv);
165 }
166
167 ieee80211_wake_queues(priv->hw);
168
169 ath9k_htc_ps_restore(priv);
170 mutex_unlock(&priv->mutex);
171}
172
119static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, 173static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
120 struct ieee80211_hw *hw, 174 struct ieee80211_hw *hw,
121 struct ath9k_channel *hchan) 175 struct ath9k_channel *hchan)
@@ -690,7 +744,7 @@ void ath9k_htc_debug_remove_root(void)
690/* ANI */ 744/* ANI */
691/*******/ 745/*******/
692 746
693static void ath_start_ani(struct ath9k_htc_priv *priv) 747void ath_start_ani(struct ath9k_htc_priv *priv)
694{ 748{
695 struct ath_common *common = ath9k_hw_common(priv->ah); 749 struct ath_common *common = ath9k_hw_common(priv->ah);
696 unsigned long timestamp = jiffies_to_msecs(jiffies); 750 unsigned long timestamp = jiffies_to_msecs(jiffies);
@@ -1219,6 +1273,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
1219 u8 cmd_rsp; 1273 u8 cmd_rsp;
1220 1274
1221 /* Cancel all the running timers/work .. */ 1275 /* Cancel all the running timers/work .. */
1276 cancel_work_sync(&priv->fatal_work);
1222 cancel_work_sync(&priv->ps_work); 1277 cancel_work_sync(&priv->ps_work);
1223 cancel_delayed_work_sync(&priv->ath9k_led_blink_work); 1278 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1224 ath9k_led_stop_brightness(priv); 1279 ath9k_led_stop_brightness(priv);
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 573daca135fd..dc862f5e1162 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -120,7 +120,7 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
120 kfree(priv->wmi); 120 kfree(priv->wmi);
121} 121}
122 122
123void ath9k_wmi_tasklet(unsigned long data) 123void ath9k_swba_tasklet(unsigned long data)
124{ 124{
125 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 125 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
126 struct ath_common *common = ath9k_hw_common(priv->ah); 126 struct ath_common *common = ath9k_hw_common(priv->ah);
@@ -131,6 +131,16 @@ void ath9k_wmi_tasklet(unsigned long data)
131 131
132} 132}
133 133
134void ath9k_fatal_work(struct work_struct *work)
135{
136 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
137 fatal_work);
138 struct ath_common *common = ath9k_hw_common(priv->ah);
139
140 ath_dbg(common, ATH_DBG_FATAL, "FATAL Event received, resetting device\n");
141 ath9k_htc_reset(priv);
142}
143
134static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) 144static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
135{ 145{
136 skb_pull(skb, sizeof(struct wmi_cmd_hdr)); 146 skb_pull(skb, sizeof(struct wmi_cmd_hdr));
@@ -163,7 +173,11 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
163 switch (cmd_id) { 173 switch (cmd_id) {
164 case WMI_SWBA_EVENTID: 174 case WMI_SWBA_EVENTID:
165 wmi->beacon_pending = *(u8 *)wmi_event; 175 wmi->beacon_pending = *(u8 *)wmi_event;
166 tasklet_schedule(&wmi->drv_priv->wmi_tasklet); 176 tasklet_schedule(&wmi->drv_priv->swba_tasklet);
177 break;
178 case WMI_FATAL_EVENTID:
179 ieee80211_queue_work(wmi->drv_priv->hw,
180 &wmi->drv_priv->fatal_work);
167 break; 181 break;
168 case WMI_TXRATE_EVENTID: 182 case WMI_TXRATE_EVENTID:
169#ifdef CONFIG_ATH9K_HTC_DEBUGFS 183#ifdef CONFIG_ATH9K_HTC_DEBUGFS
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index ac61074af8ac..42084277522d 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -117,7 +117,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
117 u8 *cmd_buf, u32 cmd_len, 117 u8 *cmd_buf, u32 cmd_len,
118 u8 *rsp_buf, u32 rsp_len, 118 u8 *rsp_buf, u32 rsp_len,
119 u32 timeout); 119 u32 timeout);
120void ath9k_wmi_tasklet(unsigned long data); 120void ath9k_swba_tasklet(unsigned long data);
121void ath9k_fatal_work(struct work_struct *work);
121 122
122#define WMI_CMD(_wmi_cmd) \ 123#define WMI_CMD(_wmi_cmd) \
123 do { \ 124 do { \