diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl3945-base.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 188 |
1 files changed, 33 insertions, 155 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 39fd5440a248..ecf749c2dc0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -2063,34 +2063,6 @@ int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *h | |||
2063 | return 1; | 2063 | return 1; |
2064 | } | 2064 | } |
2065 | 2065 | ||
2066 | #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x | ||
2067 | |||
2068 | static const char *iwl3945_get_tx_fail_reason(u32 status) | ||
2069 | { | ||
2070 | switch (status & TX_STATUS_MSK) { | ||
2071 | case TX_STATUS_SUCCESS: | ||
2072 | return "SUCCESS"; | ||
2073 | TX_STATUS_ENTRY(SHORT_LIMIT); | ||
2074 | TX_STATUS_ENTRY(LONG_LIMIT); | ||
2075 | TX_STATUS_ENTRY(FIFO_UNDERRUN); | ||
2076 | TX_STATUS_ENTRY(MGMNT_ABORT); | ||
2077 | TX_STATUS_ENTRY(NEXT_FRAG); | ||
2078 | TX_STATUS_ENTRY(LIFE_EXPIRE); | ||
2079 | TX_STATUS_ENTRY(DEST_PS); | ||
2080 | TX_STATUS_ENTRY(ABORTED); | ||
2081 | TX_STATUS_ENTRY(BT_RETRY); | ||
2082 | TX_STATUS_ENTRY(STA_INVALID); | ||
2083 | TX_STATUS_ENTRY(FRAG_DROPPED); | ||
2084 | TX_STATUS_ENTRY(TID_DISABLE); | ||
2085 | TX_STATUS_ENTRY(FRAME_FLUSHED); | ||
2086 | TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL); | ||
2087 | TX_STATUS_ENTRY(TX_LOCKED); | ||
2088 | TX_STATUS_ENTRY(NO_BEACON_ON_RADAR); | ||
2089 | } | ||
2090 | |||
2091 | return "UNKNOWN"; | ||
2092 | } | ||
2093 | |||
2094 | /** | 2066 | /** |
2095 | * iwl3945_scan_cancel - Cancel any currently executing HW scan | 2067 | * iwl3945_scan_cancel - Cancel any currently executing HW scan |
2096 | * | 2068 | * |
@@ -3138,125 +3110,6 @@ static int iwl3945_get_measurement(struct iwl3945_priv *priv, | |||
3138 | } | 3110 | } |
3139 | #endif | 3111 | #endif |
3140 | 3112 | ||
3141 | static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv, | ||
3142 | struct iwl3945_tx_info *tx_sta) | ||
3143 | { | ||
3144 | |||
3145 | tx_sta->status.ack_signal = 0; | ||
3146 | tx_sta->status.excessive_retries = 0; | ||
3147 | tx_sta->status.queue_length = 0; | ||
3148 | tx_sta->status.queue_number = 0; | ||
3149 | |||
3150 | if (in_interrupt()) | ||
3151 | ieee80211_tx_status_irqsafe(priv->hw, | ||
3152 | tx_sta->skb[0], &(tx_sta->status)); | ||
3153 | else | ||
3154 | ieee80211_tx_status(priv->hw, | ||
3155 | tx_sta->skb[0], &(tx_sta->status)); | ||
3156 | |||
3157 | tx_sta->skb[0] = NULL; | ||
3158 | } | ||
3159 | |||
3160 | /** | ||
3161 | * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd | ||
3162 | * | ||
3163 | * When FW advances 'R' index, all entries between old and new 'R' index | ||
3164 | * need to be reclaimed. As result, some free space forms. If there is | ||
3165 | * enough free space (> low mark), wake the stack that feeds us. | ||
3166 | */ | ||
3167 | static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index) | ||
3168 | { | ||
3169 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
3170 | struct iwl3945_queue *q = &txq->q; | ||
3171 | int nfreed = 0; | ||
3172 | |||
3173 | if ((index >= q->n_bd) || (iwl3945_x2_queue_used(q, index) == 0)) { | ||
3174 | IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " | ||
3175 | "is out of range [0-%d] %d %d.\n", txq_id, | ||
3176 | index, q->n_bd, q->write_ptr, q->read_ptr); | ||
3177 | return 0; | ||
3178 | } | ||
3179 | |||
3180 | for (index = iwl_queue_inc_wrap(index, q->n_bd); | ||
3181 | q->read_ptr != index; | ||
3182 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
3183 | if (txq_id != IWL_CMD_QUEUE_NUM) { | ||
3184 | iwl3945_txstatus_to_ieee(priv, | ||
3185 | &(txq->txb[txq->q.read_ptr])); | ||
3186 | iwl3945_hw_txq_free_tfd(priv, txq); | ||
3187 | } else if (nfreed > 1) { | ||
3188 | IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, | ||
3189 | q->write_ptr, q->read_ptr); | ||
3190 | queue_work(priv->workqueue, &priv->restart); | ||
3191 | } | ||
3192 | nfreed++; | ||
3193 | } | ||
3194 | |||
3195 | if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && | ||
3196 | (txq_id != IWL_CMD_QUEUE_NUM) && | ||
3197 | priv->mac80211_registered) | ||
3198 | ieee80211_wake_queue(priv->hw, txq_id); | ||
3199 | |||
3200 | |||
3201 | return nfreed; | ||
3202 | } | ||
3203 | |||
3204 | static int iwl3945_is_tx_success(u32 status) | ||
3205 | { | ||
3206 | return (status & 0xFF) == 0x1; | ||
3207 | } | ||
3208 | |||
3209 | /****************************************************************************** | ||
3210 | * | ||
3211 | * Generic RX handler implementations | ||
3212 | * | ||
3213 | ******************************************************************************/ | ||
3214 | /** | ||
3215 | * iwl3945_rx_reply_tx - Handle Tx response | ||
3216 | */ | ||
3217 | static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, | ||
3218 | struct iwl3945_rx_mem_buffer *rxb) | ||
3219 | { | ||
3220 | struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; | ||
3221 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | ||
3222 | int txq_id = SEQ_TO_QUEUE(sequence); | ||
3223 | int index = SEQ_TO_INDEX(sequence); | ||
3224 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
3225 | struct ieee80211_tx_status *tx_status; | ||
3226 | struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | ||
3227 | u32 status = le32_to_cpu(tx_resp->status); | ||
3228 | |||
3229 | if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) { | ||
3230 | IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " | ||
3231 | "is out of range [0-%d] %d %d\n", txq_id, | ||
3232 | index, txq->q.n_bd, txq->q.write_ptr, | ||
3233 | txq->q.read_ptr); | ||
3234 | return; | ||
3235 | } | ||
3236 | |||
3237 | tx_status = &(txq->txb[txq->q.read_ptr].status); | ||
3238 | |||
3239 | tx_status->retry_count = tx_resp->failure_frame; | ||
3240 | tx_status->queue_number = status; | ||
3241 | tx_status->queue_length = tx_resp->bt_kill_count; | ||
3242 | tx_status->queue_length |= tx_resp->failure_rts; | ||
3243 | |||
3244 | tx_status->flags = | ||
3245 | iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; | ||
3246 | |||
3247 | IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", | ||
3248 | txq_id, iwl3945_get_tx_fail_reason(status), status, | ||
3249 | tx_resp->rate, tx_resp->failure_frame); | ||
3250 | |||
3251 | IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); | ||
3252 | if (index != -1) | ||
3253 | iwl3945_tx_queue_reclaim(priv, txq_id, index); | ||
3254 | |||
3255 | if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) | ||
3256 | IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); | ||
3257 | } | ||
3258 | |||
3259 | |||
3260 | static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, | 3113 | static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, |
3261 | struct iwl3945_rx_mem_buffer *rxb) | 3114 | struct iwl3945_rx_mem_buffer *rxb) |
3262 | { | 3115 | { |
@@ -3603,13 +3456,44 @@ static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv) | |||
3603 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = | 3456 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = |
3604 | iwl3945_rx_scan_complete_notif; | 3457 | iwl3945_rx_scan_complete_notif; |
3605 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; | 3458 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; |
3606 | priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; | ||
3607 | 3459 | ||
3608 | /* Set up hardware specific Rx handlers */ | 3460 | /* Set up hardware specific Rx handlers */ |
3609 | iwl3945_hw_rx_handler_setup(priv); | 3461 | iwl3945_hw_rx_handler_setup(priv); |
3610 | } | 3462 | } |
3611 | 3463 | ||
3612 | /** | 3464 | /** |
3465 | * iwl3945_cmd_queue_reclaim - Reclaim CMD queue entries | ||
3466 | * When FW advances 'R' index, all entries between old and new 'R' index | ||
3467 | * need to be reclaimed. | ||
3468 | */ | ||
3469 | static void iwl3945_cmd_queue_reclaim(struct iwl3945_priv *priv, | ||
3470 | int txq_id, int index) | ||
3471 | { | ||
3472 | struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; | ||
3473 | struct iwl3945_queue *q = &txq->q; | ||
3474 | int nfreed = 0; | ||
3475 | |||
3476 | if ((index >= q->n_bd) || (iwl3945_x2_queue_used(q, index) == 0)) { | ||
3477 | IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " | ||
3478 | "is out of range [0-%d] %d %d.\n", txq_id, | ||
3479 | index, q->n_bd, q->write_ptr, q->read_ptr); | ||
3480 | return; | ||
3481 | } | ||
3482 | |||
3483 | for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index; | ||
3484 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
3485 | if (nfreed > 1) { | ||
3486 | IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, | ||
3487 | q->write_ptr, q->read_ptr); | ||
3488 | queue_work(priv->workqueue, &priv->restart); | ||
3489 | break; | ||
3490 | } | ||
3491 | nfreed++; | ||
3492 | } | ||
3493 | } | ||
3494 | |||
3495 | |||
3496 | /** | ||
3613 | * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them | 3497 | * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them |
3614 | * @rxb: Rx buffer to reclaim | 3498 | * @rxb: Rx buffer to reclaim |
3615 | * | 3499 | * |
@@ -3628,12 +3512,6 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, | |||
3628 | int cmd_index; | 3512 | int cmd_index; |
3629 | struct iwl3945_cmd *cmd; | 3513 | struct iwl3945_cmd *cmd; |
3630 | 3514 | ||
3631 | /* If a Tx command is being handled and it isn't in the actual | ||
3632 | * command queue then there a command routing bug has been introduced | ||
3633 | * in the queue management code. */ | ||
3634 | if (txq_id != IWL_CMD_QUEUE_NUM) | ||
3635 | IWL_ERROR("Error wrong command queue %d command id 0x%X\n", | ||
3636 | txq_id, pkt->hdr.cmd); | ||
3637 | BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); | 3515 | BUG_ON(txq_id != IWL_CMD_QUEUE_NUM); |
3638 | 3516 | ||
3639 | cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); | 3517 | cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); |
@@ -3647,7 +3525,7 @@ static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, | |||
3647 | !cmd->meta.u.callback(priv, cmd, rxb->skb)) | 3525 | !cmd->meta.u.callback(priv, cmd, rxb->skb)) |
3648 | rxb->skb = NULL; | 3526 | rxb->skb = NULL; |
3649 | 3527 | ||
3650 | iwl3945_tx_queue_reclaim(priv, txq_id, index); | 3528 | iwl3945_cmd_queue_reclaim(priv, txq_id, index); |
3651 | 3529 | ||
3652 | if (!(cmd->meta.flags & CMD_ASYNC)) { | 3530 | if (!(cmd->meta.flags & CMD_ASYNC)) { |
3653 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 3531 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |