diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/rx.c')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/rx.c | 66 |
1 files changed, 66 insertions, 0 deletions
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 | ||
1090 | static 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 | |||
1090 | static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, | 1155 | static 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 | }; |