aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNishant Sarmukadam <nishants@marvell.com>2011-03-17 14:58:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-03-30 14:15:14 -0400
commit3aefc37ee789188f0d4488cae04ff618f4c4ddf6 (patch)
treeec41b4de5ecdea63f4056996e7c94b76ff88dfae
parent65f3ddcd08fe24490359274a8c9bf526e81357a5 (diff)
mwl8k: Handle the watchdog event from the firmware
When an ampdu stream is on, if the firmware rate adaptation logic decides that the outgoing packet rate to the station needs to go below 6.5Mbps (non HT rate), it sends an event indicating that the ampdu stream needs to be destroyed. Handle this event in the driver and destroy the ampdu stream so that the rate can go below 6.5Mbps Signed-off-by: Nishant Sarmukadam <nishants@marvell.com> Signed-off-by: Brian Cavagnolo <brian@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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);