int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid)
{
	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
	u8 txq_id = trans_pcie->agg_txq[sta_id][tid];

	if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) {
		IWL_ERR(trans,
			"queue number out of range: %d, must be %d to %d\n",
			txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
			IWLAGN_FIRST_AMPDU_QUEUE +
			hw_params(trans).num_ampdu_queues - 1);
		return -EINVAL;
	}

	iwlagn_tx_queue_stop_scheduler(trans, txq_id);

	iwl_clear_bits_prph(trans, SCD_AGGR_SEL, (1 << txq_id));

	trans_pcie->agg_txq[sta_id][tid] = 0;
	trans_pcie->txq[txq_id].q.read_ptr = 0;
	trans_pcie->txq[txq_id].q.write_ptr = 0;
	/* supposes that ssn_idx is valid (!= 0xFFF) */
	iwl_trans_set_wr_ptrs(trans, txq_id, 0);

	iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id));
	iwl_txq_ctx_deactivate(trans_pcie, txq_id);
	iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0);
	return 0;
}
void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
				 enum iwl_rxon_context_id ctx, int sta_id,
				 int tid, int frame_limit, u16 ssn)
{
	int tx_fifo, txq_id;
	u16 ra_tid;
	unsigned long flags;

	struct iwl_trans_pcie *trans_pcie =
		IWL_TRANS_GET_PCIE_TRANS(trans);

	if (WARN_ON(sta_id == IWL_INVALID_STATION))
		return;
	if (WARN_ON(tid >= IWL_MAX_TID_COUNT))
		return;

	tx_fifo = get_fifo_from_tid(trans_pcie, ctx, tid);
	if (WARN_ON(tx_fifo < 0)) {
		IWL_ERR(trans, "txq_agg_setup, bad fifo: %d\n", tx_fifo);
		return;
	}

	txq_id = trans_pcie->agg_txq[sta_id][tid];
	if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) {
		IWL_ERR(trans,
			"queue number out of range: %d, must be %d to %d\n",
			txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
			IWLAGN_FIRST_AMPDU_QUEUE +
			hw_params(trans).num_ampdu_queues - 1);
		return;
	}

	ra_tid = BUILD_RAxTID(sta_id, tid);

	spin_lock_irqsave(&trans_pcie->irq_lock, flags);

	/* Stop this Tx queue before configuring it */
	iwlagn_tx_queue_stop_scheduler(trans, txq_id);

	/* Map receiver-address / traffic-ID to this queue */
	iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);

	/* Set this queue as a chain-building queue */
	iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, (1<<txq_id));

	/* enable aggregations for the queue */
	iwl_set_bits_prph(trans, SCD_AGGR_SEL, (1<<txq_id));

	/* Place first TFD at index corresponding to start sequence number.
	 * Assumes that ssn_idx is valid (!= 0xFFF) */
	trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
	trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
	iwl_trans_set_wr_ptrs(trans, txq_id, ssn);

	/* Set up Tx window size and frame limit for this queue */
	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
			SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
			sizeof(u32),
			((frame_limit <<
			SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
			SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
			((frame_limit <<
			SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
			SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));

	iwl_set_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id));

	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
	iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
					tx_fifo, 1);

	trans_pcie->txq[txq_id].sta_id = sta_id;
	trans_pcie->txq[txq_id].tid = tid;

	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
}
void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
				 enum iwl_rxon_context_id ctx, int sta_id,
				 int tid, int frame_limit, u16 ssn)
{
	int tx_fifo, txq_id;
	u16 ra_tid;
	unsigned long flags;

	struct iwl_trans_pcie *trans_pcie =
		IWL_TRANS_GET_PCIE_TRANS(trans);

	if (WARN_ON(sta_id == IWL_INVALID_STATION))
		return;
	if (WARN_ON(tid >= IWL_MAX_TID_COUNT))
		return;

	tx_fifo = get_fifo_from_tid(trans_pcie, ctx, tid);
	if (WARN_ON(tx_fifo < 0)) {
		IWL_ERR(trans, "txq_agg_setup, bad fifo: %d\n", tx_fifo);
		return;
	}

	txq_id = trans_pcie->agg_txq[sta_id][tid];
	if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) {
		IWL_ERR(trans,
			"queue number out of range: %d, must be %d to %d\n",
			txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
			IWLAGN_FIRST_AMPDU_QUEUE +
			hw_params(trans).num_ampdu_queues - 1);
		return;
	}

	ra_tid = BUILD_RAxTID(sta_id, tid);

	spin_lock_irqsave(&trans_pcie->irq_lock, flags);

	
	iwlagn_tx_queue_stop_scheduler(trans, txq_id);

	
	iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);

	
	iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, (1<<txq_id));

	
	iwl_set_bits_prph(trans, SCD_AGGR_SEL, (1<<txq_id));

	trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
	trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
	iwl_trans_set_wr_ptrs(trans, txq_id, ssn);

	
	iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
			SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
			sizeof(u32),
			((frame_limit <<
			SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
			SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
			((frame_limit <<
			SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
			SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));

	iwl_set_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id));

	
	iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
					tx_fifo, 1);

	trans_pcie->txq[txq_id].sta_id = sta_id;
	trans_pcie->txq[txq_id].tid = tid;

	spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
}