aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c31
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c11
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c66
-rw-r--r--drivers/net/wireless/iwmc3200wifi/tx.c57
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h34
8 files changed, 217 insertions, 10 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 7e12438551ba..46ca7c58f5ac 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -929,3 +929,34 @@ int iwm_target_reset(struct iwm_priv *iwm)
929 929
930 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); 930 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
931} 931}
932
933int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
934 struct iwm_umac_notif_stop_resume_tx *ntf)
935{
936 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
937 struct iwm_umac_cmd umac_cmd;
938 struct iwm_umac_cmd_stop_resume_tx stp_res_cmd;
939 struct iwm_sta_info *sta_info;
940 u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id);
941 int i;
942
943 sta_info = &iwm->sta_table[sta_id];
944 if (!sta_info->valid) {
945 IWM_ERR(iwm, "Invalid STA: %d\n", sta_id);
946 return -EINVAL;
947 }
948
949 umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX;
950 umac_cmd.resp = 0;
951
952 stp_res_cmd.flags = ntf->flags;
953 stp_res_cmd.sta_id = ntf->sta_id;
954 stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk;
955 for (i = 0; i < IWM_UMAC_TID_NR; i++)
956 stp_res_cmd.last_seq_num[i] =
957 sta_info->tid_info[i].last_seq_num;
958
959 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd,
960 sizeof(struct iwm_umac_cmd_stop_resume_tx));
961
962}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index b36be2b23a3c..95cdf941b222 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -450,6 +450,14 @@ struct iwm_umac_cmd_stats_req {
450 __le32 flags; 450 __le32 flags;
451} __attribute__ ((packed)); 451} __attribute__ ((packed));
452 452
453struct iwm_umac_cmd_stop_resume_tx {
454 u8 flags;
455 u8 sta_id;
456 __le16 stop_resume_tid_msk;
457 __le16 last_seq_num[IWM_UMAC_TID_NR];
458 u16 reserved;
459} __attribute__ ((packed));
460
453/* LMAC commands */ 461/* LMAC commands */
454int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); 462int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
455int iwm_send_prio_table(struct iwm_priv *iwm); 463int iwm_send_prio_table(struct iwm_priv *iwm);
@@ -478,6 +486,8 @@ int iwm_send_umac_channel_list(struct iwm_priv *iwm);
478int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, 486int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
479 int ssid_num); 487 int ssid_num);
480int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); 488int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
489int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
490 struct iwm_umac_notif_stop_resume_tx *ntf);
481 491
482/* UDMA commands */ 492/* UDMA commands */
483int iwm_target_reset(struct iwm_priv *iwm); 493int iwm_target_reset(struct iwm_priv *iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index a9bf6bc97bea..8d091f918f33 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -131,11 +131,18 @@ struct iwm_notif {
131 unsigned long buf_size; 131 unsigned long buf_size;
132}; 132};
133 133
134struct iwm_tid_info {
135 __le16 last_seq_num;
136 bool stopped;
137 struct mutex mutex;
138};
139
134struct iwm_sta_info { 140struct iwm_sta_info {
135 u8 addr[ETH_ALEN]; 141 u8 addr[ETH_ALEN];
136 bool valid; 142 bool valid;
137 bool qos; 143 bool qos;
138 u8 color; 144 u8 color;
145 struct iwm_tid_info tid_info[IWM_UMAC_TID_NR];
139}; 146};
140 147
141struct iwm_tx_info { 148struct iwm_tx_info {
@@ -185,6 +192,8 @@ struct iwm_key {
185struct iwm_tx_queue { 192struct iwm_tx_queue {
186 int id; 193 int id;
187 struct sk_buff_head queue; 194 struct sk_buff_head queue;
195 struct sk_buff_head stopped_queue;
196 spinlock_t lock;
188 struct workqueue_struct *wq; 197 struct workqueue_struct *wq;
189 struct work_struct worker; 198 struct work_struct worker;
190 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; 199 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
@@ -341,6 +350,7 @@ int iwm_up(struct iwm_priv *iwm);
341int iwm_down(struct iwm_priv *iwm); 350int iwm_down(struct iwm_priv *iwm);
342 351
343/* TX API */ 352/* TX API */
353u16 iwm_tid_to_queue(u16 tid);
344void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); 354void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
345void iwm_tx_worker(struct work_struct *work); 355void iwm_tx_worker(struct work_struct *work);
346int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); 356int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 92e4eaf32ff2..087f04355c1b 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -248,7 +248,7 @@ static void iwm_watchdog(unsigned long data)
248 248
249int iwm_priv_init(struct iwm_priv *iwm) 249int iwm_priv_init(struct iwm_priv *iwm)
250{ 250{
251 int i; 251 int i, j;
252 char name[32]; 252 char name[32];
253 253
254 iwm->status = 0; 254 iwm->status = 0;
@@ -292,6 +292,8 @@ int iwm_priv_init(struct iwm_priv *iwm)
292 return -EAGAIN; 292 return -EAGAIN;
293 293
294 skb_queue_head_init(&iwm->txq[i].queue); 294 skb_queue_head_init(&iwm->txq[i].queue);
295 skb_queue_head_init(&iwm->txq[i].stopped_queue);
296 spin_lock_init(&iwm->txq[i].lock);
295 } 297 }
296 298
297 for (i = 0; i < IWM_NUM_KEYS; i++) 299 for (i = 0; i < IWM_NUM_KEYS; i++)
@@ -299,6 +301,12 @@ int iwm_priv_init(struct iwm_priv *iwm)
299 301
300 iwm->default_key = -1; 302 iwm->default_key = -1;
301 303
304 for (i = 0; i < IWM_STA_TABLE_NUM; i++)
305 for (j = 0; j < IWM_UMAC_TID_NR; j++) {
306 mutex_init(&iwm->sta_table[i].tid_info[j].mutex);
307 iwm->sta_table[i].tid_info[j].stopped = false;
308 }
309
302 init_timer(&iwm->watchdog); 310 init_timer(&iwm->watchdog);
303 iwm->watchdog.function = iwm_watchdog; 311 iwm->watchdog.function = iwm_watchdog;
304 iwm->watchdog.data = (unsigned long)iwm; 312 iwm->watchdog.data = (unsigned long)iwm;
@@ -572,6 +580,7 @@ void iwm_link_off(struct iwm_priv *iwm)
572 580
573 for (i = 0; i < IWM_TX_QUEUES; i++) { 581 for (i = 0; i < IWM_TX_QUEUES; i++) {
574 skb_queue_purge(&iwm->txq[i].queue); 582 skb_queue_purge(&iwm->txq[i].queue);
583 skb_queue_purge(&iwm->txq[i].stopped_queue);
575 584
576 iwm->txq[i].concat_count = 0; 585 iwm->txq[i].concat_count = 0;
577 iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; 586 iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 4f8dbdd7b917..e4f0f8705f65 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -76,6 +76,14 @@ static int iwm_stop(struct net_device *ndev)
76 */ 76 */
77static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; 77static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
78 78
79u16 iwm_tid_to_queue(u16 tid)
80{
81 if (tid > IWM_UMAC_TID_NR - 2)
82 return -EINVAL;
83
84 return iwm_1d_to_queue[tid];
85}
86
79static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) 87static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
80{ 88{
81 skb->priority = cfg80211_classify8021d(skb); 89 skb->priority = cfg80211_classify8021d(skb);
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index bdb1d7e7979d..72c27a3e5528 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1087,6 +1087,71 @@ static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf,
1087 return 0; 1087 return 0;
1088} 1088}
1089 1089
1090static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf,
1091 unsigned long buf_size,
1092 struct iwm_wifi_cmd *cmd)
1093{
1094 struct iwm_umac_notif_stop_resume_tx *stp_res_tx =
1095 (struct iwm_umac_notif_stop_resume_tx *)buf;
1096 struct iwm_sta_info *sta_info;
1097 struct iwm_tid_info *tid_info;
1098 u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id);
1099 u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk);
1100 int bit, ret = 0;
1101 bool stop = false;
1102
1103 IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n"
1104 "\tflags: 0x%x\n"
1105 "\tSTA id: %d\n"
1106 "\tTID bitmask: 0x%x\n",
1107 stp_res_tx->flags, stp_res_tx->sta_id,
1108 stp_res_tx->stop_resume_tid_msk);
1109
1110 if (stp_res_tx->flags & UMAC_STOP_TX_FLAG)
1111 stop = true;
1112
1113 sta_info = &iwm->sta_table[sta_id];
1114 if (!sta_info->valid) {
1115 IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n",
1116 sta_id, stp_res_tx->sta_id);
1117 return -EINVAL;
1118 }
1119
1120 for_each_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) {
1121 tid_info = &sta_info->tid_info[bit];
1122
1123 mutex_lock(&tid_info->mutex);
1124 tid_info->stopped = stop;
1125 mutex_unlock(&tid_info->mutex);
1126
1127 if (!stop) {
1128 struct iwm_tx_queue *txq;
1129 u16 queue = iwm_tid_to_queue(bit);
1130
1131 if (queue < 0)
1132 continue;
1133
1134 txq = &iwm->txq[queue];
1135 /*
1136 * If we resume, we have to move our SKBs
1137 * back to the tx queue and queue some work.
1138 */
1139 spin_lock_bh(&txq->lock);
1140 skb_queue_splice_init(&txq->queue, &txq->stopped_queue);
1141 spin_unlock_bh(&txq->lock);
1142
1143 queue_work(txq->wq, &txq->worker);
1144 }
1145
1146 }
1147
1148 /* We send an ACK only for the stop case */
1149 if (stop)
1150 ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx);
1151
1152 return ret;
1153}
1154
1090static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, 1155static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
1091 unsigned long buf_size, 1156 unsigned long buf_size,
1092 struct iwm_wifi_cmd *cmd) 1157 struct iwm_wifi_cmd *cmd)
@@ -1371,6 +1436,7 @@ static const iwm_handler iwm_umac_handlers[] =
1371 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, 1436 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics,
1372 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, 1437 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy,
1373 [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, 1438 [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list,
1439 [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx,
1374 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, 1440 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet,
1375 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, 1441 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper,
1376}; 1442};
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c
index e3b4f7902daf..01cc2101e682 100644
--- a/drivers/net/wireless/iwmc3200wifi/tx.c
+++ b/drivers/net/wireless/iwmc3200wifi/tx.c
@@ -329,7 +329,7 @@ static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
329 329
330 memcpy(buf + sizeof(*hdr), skb->data, skb->len); 330 memcpy(buf + sizeof(*hdr), skb->data, skb->len);
331 331
332 return 0; 332 return umac_cmd.seq_num;
333} 333}
334 334
335static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, 335static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
@@ -361,9 +361,10 @@ void iwm_tx_worker(struct work_struct *work)
361 struct iwm_priv *iwm; 361 struct iwm_priv *iwm;
362 struct iwm_tx_info *tx_info = NULL; 362 struct iwm_tx_info *tx_info = NULL;
363 struct sk_buff *skb; 363 struct sk_buff *skb;
364 int cmdlen, ret;
365 struct iwm_tx_queue *txq; 364 struct iwm_tx_queue *txq;
366 int pool_id; 365 struct iwm_sta_info *sta_info;
366 struct iwm_tid_info *tid_info;
367 int cmdlen, ret, pool_id;
367 368
368 txq = container_of(work, struct iwm_tx_queue, worker); 369 txq = container_of(work, struct iwm_tx_queue, worker);
369 iwm = container_of(txq, struct iwm_priv, txq[txq->id]); 370 iwm = container_of(txq, struct iwm_priv, txq[txq->id]);
@@ -373,8 +374,40 @@ void iwm_tx_worker(struct work_struct *work)
373 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && 374 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
374 !skb_queue_empty(&txq->queue)) { 375 !skb_queue_empty(&txq->queue)) {
375 376
377 spin_lock_bh(&txq->lock);
376 skb = skb_dequeue(&txq->queue); 378 skb = skb_dequeue(&txq->queue);
379 spin_unlock_bh(&txq->lock);
380
377 tx_info = skb_to_tx_info(skb); 381 tx_info = skb_to_tx_info(skb);
382 sta_info = &iwm->sta_table[tx_info->sta];
383 if (!sta_info->valid) {
384 IWM_ERR(iwm, "Trying to send a frame to unknown STA\n");
385 kfree_skb(skb);
386 continue;
387 }
388
389 tid_info = &sta_info->tid_info[tx_info->tid];
390
391 mutex_lock(&tid_info->mutex);
392
393 /*
394 * If the RAxTID is stopped, we queue the skb to the stopped
395 * queue.
396 * Whenever we'll get a UMAC notification to resume the tx flow
397 * for this RAxTID, we'll merge back the stopped queue into the
398 * regular queue. See iwm_ntf_stop_resume_tx() from rx.c.
399 */
400 if (tid_info->stopped) {
401 IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n",
402 tx_info->sta, tx_info->tid);
403 spin_lock_bh(&txq->lock);
404 skb_queue_tail(&txq->stopped_queue, skb);
405 spin_unlock_bh(&txq->lock);
406
407 mutex_unlock(&tid_info->mutex);
408 continue;
409 }
410
378 cmdlen = IWM_UDMA_HDR_LEN + skb->len; 411 cmdlen = IWM_UDMA_HDR_LEN + skb->len;
379 412
380 IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " 413 IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: "
@@ -393,13 +426,20 @@ void iwm_tx_worker(struct work_struct *work)
393 if (ret) { 426 if (ret) {
394 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " 427 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue "
395 "%d, Tx worker stopped\n", txq->id); 428 "%d, Tx worker stopped\n", txq->id);
429 spin_lock_bh(&txq->lock);
396 skb_queue_head(&txq->queue, skb); 430 skb_queue_head(&txq->queue, skb);
431 spin_unlock_bh(&txq->lock);
432
433 mutex_unlock(&tid_info->mutex);
397 break; 434 break;
398 } 435 }
399 436
400 txq->concat_ptr = txq->concat_buf + txq->concat_count; 437 txq->concat_ptr = txq->concat_buf + txq->concat_count;
401 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); 438 tid_info->last_seq_num =
439 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
402 txq->concat_count += ALIGN(cmdlen, 16); 440 txq->concat_count += ALIGN(cmdlen, 16);
441
442 mutex_unlock(&tid_info->mutex);
403#endif 443#endif
404 kfree_skb(skb); 444 kfree_skb(skb);
405 } 445 }
@@ -419,14 +459,14 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
419 struct iwm_priv *iwm = ndev_to_iwm(netdev); 459 struct iwm_priv *iwm = ndev_to_iwm(netdev);
420 struct net_device *ndev = iwm_to_ndev(iwm); 460 struct net_device *ndev = iwm_to_ndev(iwm);
421 struct wireless_dev *wdev = iwm_to_wdev(iwm); 461 struct wireless_dev *wdev = iwm_to_wdev(iwm);
422 u8 *dst_addr;
423 struct iwm_tx_info *tx_info; 462 struct iwm_tx_info *tx_info;
424 struct iwm_tx_queue *txq; 463 struct iwm_tx_queue *txq;
425 struct iwm_sta_info *sta_info; 464 struct iwm_sta_info *sta_info;
426 u8 sta_id; 465 u8 *dst_addr, sta_id;
427 u16 queue; 466 u16 queue;
428 int ret; 467 int ret;
429 468
469
430 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { 470 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
431 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " 471 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
432 "not associated\n"); 472 "not associated\n");
@@ -440,7 +480,8 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
440 txq = &iwm->txq[queue]; 480 txq = &iwm->txq[queue];
441 481
442 /* No free space for Tx, tx_worker is too slow */ 482 /* No free space for Tx, tx_worker is too slow */
443 if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { 483 if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) ||
484 (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) {
444 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); 485 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
445 netif_stop_subqueue(netdev, queue); 486 netif_stop_subqueue(netdev, queue);
446 return NETDEV_TX_BUSY; 487 return NETDEV_TX_BUSY;
@@ -477,7 +518,9 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
477 else 518 else
478 tx_info->tid = IWM_UMAC_MGMT_TID; 519 tx_info->tid = IWM_UMAC_MGMT_TID;
479 520
521 spin_lock_bh(&iwm->txq[queue].lock);
480 skb_queue_tail(&iwm->txq[queue].queue, skb); 522 skb_queue_tail(&iwm->txq[queue].queue, skb);
523 spin_unlock_bh(&iwm->txq[queue].lock);
481 524
482 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); 525 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
483 526
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index be903543bb47..70094bfe7c91 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -83,6 +83,20 @@ struct iwm_udma_out_wifi_hdr {
83 ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ 83 ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
84 (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) 84 (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
85 85
86/* STA ID and color */
87#define STA_ID_SEED (0x0f)
88#define STA_ID_POS (0)
89#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS)
90
91#define STA_COLOR_SEED (0x7)
92#define STA_COLOR_POS (4)
93#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS)
94
95#define STA_ID_N_COLOR_COLOR(id_n_color) \
96 (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS)
97#define STA_ID_N_COLOR_ID(id_n_color) \
98 (((id_n_color) & STA_ID_MSK) >> STA_ID_POS)
99
86/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ 100/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */
87#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 101#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0
88#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF 102#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF
@@ -260,6 +274,9 @@ struct iwm_udma_out_wifi_hdr {
260#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 274#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16
261#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 275#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17
262#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 276#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18
277#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19
278#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A
279
263#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA 280#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA
264#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB 281#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB
265#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC 282#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC
@@ -691,13 +708,13 @@ struct iwm_umac_notif_rx_ticket {
691#define UMAC_PHY_NUM_CHAINS 3 708#define UMAC_PHY_NUM_CHAINS 3
692 709
693#define IWM_UMAC_MGMT_TID 8 710#define IWM_UMAC_MGMT_TID 8
694#define IWM_UMAC_TID_NR 8 711#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */
695 712
696struct iwm_umac_notif_stats { 713struct iwm_umac_notif_stats {
697 struct iwm_umac_wifi_in_hdr hdr; 714 struct iwm_umac_wifi_in_hdr hdr;
698 __le32 flags; 715 __le32 flags;
699 __le32 timestamp; 716 __le32 timestamp;
700 __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ 717 __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */
701 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; 718 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
702 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; 719 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
703 __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; 720 __le32 chain_energy[UMAC_PHY_NUM_CHAINS];
@@ -742,6 +759,19 @@ struct iwm_umac_notif_stats {
742 __le32 roam_ap_loadblance; 759 __le32 roam_ap_loadblance;
743} __attribute__ ((packed)); 760} __attribute__ ((packed));
744 761
762#define UMAC_STOP_TX_FLAG 0x1
763#define UMAC_RESUME_TX_FLAG 0x2
764
765#define LAST_SEQ_NUM_INVALID 0xFFFF
766
767struct iwm_umac_notif_stop_resume_tx {
768 struct iwm_umac_wifi_in_hdr hdr;
769 u8 flags; /* UMAC_*_TX_FLAG_* */
770 u8 sta_id;
771 __le16 stop_resume_tid_msk; /* tid bitmask */
772} __attribute__ ((packed));
773
774
745/* WiFi interface wrapper header */ 775/* WiFi interface wrapper header */
746struct iwm_umac_wifi_if { 776struct iwm_umac_wifi_if {
747 u8 oid; 777 u8 oid;