/* * iwl_pcie_gen2_txq_unmap - Unmap any remaining DMA mappings and free skb's */ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txq[txq_id]; spin_lock_bh(&txq->lock); while (txq->write_ptr != txq->read_ptr) { IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, txq->read_ptr); if (txq_id != trans_pcie->cmd_queue) { int idx = iwl_pcie_get_cmd_index(txq, txq->read_ptr); struct sk_buff *skb = txq->entries[idx].skb; if (WARN_ON_ONCE(!skb)) continue; iwl_pcie_free_tso_page(trans_pcie, skb); } iwl_pcie_gen2_free_tfd(trans, txq); txq->read_ptr = iwl_queue_inc_wrap(trans, txq->read_ptr); if (txq->read_ptr == txq->write_ptr) { unsigned long flags; spin_lock_irqsave(&trans_pcie->reg_lock, flags); if (txq_id != trans_pcie->cmd_queue) { IWL_DEBUG_RPM(trans, "Q %d - last tx freed\n", txq->id); iwl_trans_unref(trans); } else if (trans_pcie->ref_cmd_in_flight) { trans_pcie->ref_cmd_in_flight = false; IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight\n"); iwl_trans_unref(trans); } spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } } while (!skb_queue_empty(&txq->overflow_q)) { struct sk_buff *skb = __skb_dequeue(&txq->overflow_q); iwl_op_mode_free_skb(trans->op_mode, skb); } spin_unlock_bh(&txq->lock); /* just in case - this queue may have been stopped */ iwl_wake_queue(trans, txq); }
static void iwl5000_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_info *info; struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le16_to_cpu(tx_resp->status.status); int tid; int sta_id; int freed; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d " "is out of range [0-%d] %d %d\n", txq_id, index, txq->q.n_bd, txq->q.write_ptr, txq->q.read_ptr); return; } info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); memset(&info->status, 0, sizeof(info->status)); tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS; if (txq->sched_retry) { const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; agg = &priv->stations[sta_id].tid[tid].agg; iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); /* check if BAR is needed */ if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim " "scd_ssn=%d idx=%d txq=%d swq=%d\n", scd_ssn , index, txq_id, txq->swq_id); freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark) && (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) iwl_wake_queue(priv, txq_id); else iwl_wake_queue(priv, txq->swq_id); } } } else { BUG_ON(txq_id != txq->swq_id); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " "0x%x retries %d\n", txq_id, iwl_get_tx_fail_reason(status), status, le32_to_cpu(tx_resp->rate_n_flags), tx_resp->failure_frame); freed = iwl_tx_queue_reclaim(priv, txq_id, index); if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; if (priv->mac80211_registered && (iwl_queue_space(&txq->q) > txq->q.low_mark)) iwl_wake_queue(priv, txq_id); } if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) iwl_txq_check_empty(priv, sta_id, tid, txq_id); if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n"); }