aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r--drivers/net/wireless/mwl8k.c77
1 files changed, 75 insertions, 2 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index ec1190ab0f8e..b90178da5a27 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default,
63#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 63#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38
64#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c 64#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c
65#define MWL8K_A2H_INT_DUMMY (1 << 20) 65#define MWL8K_A2H_INT_DUMMY (1 << 20)
66#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14)
66#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) 67#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11)
67#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) 68#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10)
68#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) 69#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7)
@@ -82,7 +83,8 @@ MODULE_PARM_DESC(ap_mode_default,
82 MWL8K_A2H_INT_MAC_EVENT | \ 83 MWL8K_A2H_INT_MAC_EVENT | \
83 MWL8K_A2H_INT_OPC_DONE | \ 84 MWL8K_A2H_INT_OPC_DONE | \
84 MWL8K_A2H_INT_RX_READY | \ 85 MWL8K_A2H_INT_RX_READY | \
85 MWL8K_A2H_INT_TX_DONE) 86 MWL8K_A2H_INT_TX_DONE | \
87 MWL8K_A2H_INT_BA_WATCHDOG)
86 88
87#define MWL8K_RX_QUEUES 1 89#define MWL8K_RX_QUEUES 1
88#define MWL8K_TX_WMM_QUEUES 4 90#define MWL8K_TX_WMM_QUEUES 4
@@ -181,6 +183,7 @@ struct mwl8k_priv {
181 u8 num_ampdu_queues; 183 u8 num_ampdu_queues;
182 spinlock_t stream_lock; 184 spinlock_t stream_lock;
183 struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; 185 struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES];
186 struct work_struct watchdog_ba_handle;
184 187
185 /* firmware access */ 188 /* firmware access */
186 struct mutex fw_mutex; 189 struct mutex fw_mutex;
@@ -375,6 +378,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
375#define MWL8K_CMD_ENABLE_SNIFFER 0x0150 378#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
376#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ 379#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */
377#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 380#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
381#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205
378#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ 382#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */
379#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ 383#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */
380#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ 384#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */
@@ -420,6 +424,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
420 MWL8K_CMDNAME(UPDATE_ENCRYPTION); 424 MWL8K_CMDNAME(UPDATE_ENCRYPTION);
421 MWL8K_CMDNAME(UPDATE_STADB); 425 MWL8K_CMDNAME(UPDATE_STADB);
422 MWL8K_CMDNAME(BASTREAM); 426 MWL8K_CMDNAME(BASTREAM);
427 MWL8K_CMDNAME(GET_WATCHDOG_BITMAP);
423 default: 428 default:
424 snprintf(buf, bufsize, "0x%x", cmd); 429 snprintf(buf, bufsize, "0x%x", cmd);
425 } 430 }
@@ -3320,6 +3325,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
3320} 3325}
3321 3326
3322/* 3327/*
3328 * CMD_GET_WATCHDOG_BITMAP.
3329 */
3330struct mwl8k_cmd_get_watchdog_bitmap {
3331 struct mwl8k_cmd_pkt header;
3332 u8 bitmap;
3333} __packed;
3334
3335static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap)
3336{
3337 struct mwl8k_cmd_get_watchdog_bitmap *cmd;
3338 int rc;
3339
3340 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
3341 if (cmd == NULL)
3342 return -ENOMEM;
3343
3344 cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP);
3345 cmd->header.length = cpu_to_le16(sizeof(*cmd));
3346
3347 rc = mwl8k_post_cmd(hw, &cmd->header);
3348 if (!rc)
3349 *bitmap = cmd->bitmap;
3350
3351 kfree(cmd);
3352
3353 return rc;
3354}
3355
3356#define INVALID_BA 0xAA
3357static void mwl8k_watchdog_ba_events(struct work_struct *work)
3358{
3359 int rc;
3360 u8 bitmap = 0, stream_index;
3361 struct mwl8k_ampdu_stream *streams;
3362 struct mwl8k_priv *priv =
3363 container_of(work, struct mwl8k_priv, watchdog_ba_handle);
3364
3365 rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
3366 if (rc)
3367 return;
3368
3369 if (bitmap == INVALID_BA)
3370 return;
3371
3372 /* the bitmap is the hw queue number. Map it to the ampdu queue. */
3373 stream_index = bitmap - MWL8K_TX_WMM_QUEUES;
3374
3375 BUG_ON(stream_index >= priv->num_ampdu_queues);
3376
3377 streams = &priv->ampdu[stream_index];
3378
3379 if (streams->state == AMPDU_STREAM_ACTIVE)
3380 ieee80211_stop_tx_ba_session(streams->sta, streams->tid);
3381
3382 return;
3383}
3384
3385
3386/*
3323 * CMD_BSS_START. 3387 * CMD_BSS_START.
3324 */ 3388 */
3325struct mwl8k_cmd_bss_start { 3389struct mwl8k_cmd_bss_start {
@@ -4014,6 +4078,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
4014 tasklet_schedule(&priv->poll_rx_task); 4078 tasklet_schedule(&priv->poll_rx_task);
4015 } 4079 }
4016 4080
4081 if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
4082 status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
4083 ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
4084 }
4085
4017 if (status) 4086 if (status)
4018 iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 4087 iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
4019 4088
@@ -4166,6 +4235,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
4166 4235
4167 /* Stop finalize join worker */ 4236 /* Stop finalize join worker */
4168 cancel_work_sync(&priv->finalize_join_worker); 4237 cancel_work_sync(&priv->finalize_join_worker);
4238 cancel_work_sync(&priv->watchdog_ba_handle);
4169 if (priv->beacon_skb != NULL) 4239 if (priv->beacon_skb != NULL)
4170 dev_kfree_skb(priv->beacon_skb); 4240 dev_kfree_skb(priv->beacon_skb);
4171 4241
@@ -5100,7 +5170,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
5100 5170
5101 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); 5171 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
5102 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); 5172 iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
5103 iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, 5173 iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY|
5174 MWL8K_A2H_INT_BA_WATCHDOG,
5104 priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); 5175 priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
5105 iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); 5176 iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
5106 5177
@@ -5258,6 +5329,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
5258 5329
5259 /* Finalize join worker */ 5330 /* Finalize join worker */
5260 INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); 5331 INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
5332 /* Handle watchdog ba events */
5333 INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events);
5261 5334
5262 /* TX reclaim and RX tasklets. */ 5335 /* TX reclaim and RX tasklets. */
5263 tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); 5336 tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);