diff options
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 77 |
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 | */ | ||
3330 | struct mwl8k_cmd_get_watchdog_bitmap { | ||
3331 | struct mwl8k_cmd_pkt header; | ||
3332 | u8 bitmap; | ||
3333 | } __packed; | ||
3334 | |||
3335 | static 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 | ||
3357 | static 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 | */ |
3325 | struct mwl8k_cmd_bss_start { | 3389 | struct 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); |