162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
362306a36Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
662306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
762306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1062306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1162306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1262306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1362306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1462306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1562306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/********************************************\
2062306a36Sopenharmony_ciQueue Control Unit, DCF Control Unit Functions
2162306a36Sopenharmony_ci\********************************************/
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "ath5k.h"
2662306a36Sopenharmony_ci#include "reg.h"
2762306a36Sopenharmony_ci#include "debug.h"
2862306a36Sopenharmony_ci#include <linux/log2.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/**
3162306a36Sopenharmony_ci * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Here we setup parameters for the 12 available TX queues. Note that
3462306a36Sopenharmony_ci * on the various registers we can usually only map the first 10 of them so
3562306a36Sopenharmony_ci * basically we have 10 queues to play with. Each queue has a matching
3662306a36Sopenharmony_ci * QCU that controls when the queue will get triggered and multiple QCUs
3762306a36Sopenharmony_ci * can be mapped to a single DCU that controls the various DFS parameters
3862306a36Sopenharmony_ci * for the various queues. In our setup we have a 1:1 mapping between QCUs
3962306a36Sopenharmony_ci * and DCUs allowing us to have different DFS settings for each queue.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * When a frame goes into a TX queue, QCU decides when it'll trigger a
4262306a36Sopenharmony_ci * transmission based on various criteria (such as how many data we have inside
4362306a36Sopenharmony_ci * it's buffer or -if it's a beacon queue- if it's time to fire up the queue
4462306a36Sopenharmony_ci * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler
4562306a36Sopenharmony_ci * (arbitrator) decides the priority of each QCU based on it's configuration
4662306a36Sopenharmony_ci * (e.g. beacons are always transmitted when they leave DCU bypassing all other
4762306a36Sopenharmony_ci * frames from other queues waiting to be transmitted). After a frame leaves
4862306a36Sopenharmony_ci * the DCU it goes to PCU for further processing and then to PHY for
4962306a36Sopenharmony_ci * the actual transmission.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/******************\
5462306a36Sopenharmony_ci* Helper functions *
5562306a36Sopenharmony_ci\******************/
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/**
5862306a36Sopenharmony_ci * ath5k_hw_num_tx_pending() - Get number of pending frames for a  given queue
5962306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
6062306a36Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ciu32
6362306a36Sopenharmony_ciath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	u32 pending;
6662306a36Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* Return if queue is declared inactive */
6962306a36Sopenharmony_ci	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
7062306a36Sopenharmony_ci		return false;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* XXX: How about AR5K_CFG_TXCNT ? */
7362306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210)
7462306a36Sopenharmony_ci		return false;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
7762306a36Sopenharmony_ci	pending &= AR5K_QCU_STS_FRMPENDCNT;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* It's possible to have no frames pending even if TXE
8062306a36Sopenharmony_ci	 * is set. To indicate that q has not stopped return
8162306a36Sopenharmony_ci	 * true */
8262306a36Sopenharmony_ci	if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
8362306a36Sopenharmony_ci		return true;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return pending;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * ath5k_hw_release_tx_queue() - Set a transmit queue inactive
9062306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
9162306a36Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_civoid
9462306a36Sopenharmony_ciath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
9762306a36Sopenharmony_ci		return;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* This queue will be skipped in further operations */
10062306a36Sopenharmony_ci	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
10162306a36Sopenharmony_ci	/*For SIMR setup*/
10262306a36Sopenharmony_ci	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/**
10662306a36Sopenharmony_ci * ath5k_cw_validate() - Make sure the given cw is valid
10762306a36Sopenharmony_ci * @cw_req: The contention window value to check
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * Make sure cw is a power of 2 minus 1 and smaller than 1024
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cistatic u16
11262306a36Sopenharmony_ciath5k_cw_validate(u16 cw_req)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	cw_req = min(cw_req, (u16)1023);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Check if cw_req + 1 a power of 2 */
11762306a36Sopenharmony_ci	if (is_power_of_2(cw_req + 1))
11862306a36Sopenharmony_ci		return cw_req;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* Check if cw_req is a power of 2 */
12162306a36Sopenharmony_ci	if (is_power_of_2(cw_req))
12262306a36Sopenharmony_ci		return cw_req - 1;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* If none of the above is correct
12562306a36Sopenharmony_ci	 * find the closest power of 2 */
12662306a36Sopenharmony_ci	cw_req = (u16) roundup_pow_of_two(cw_req) - 1;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return cw_req;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/**
13262306a36Sopenharmony_ci * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue
13362306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
13462306a36Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
13562306a36Sopenharmony_ci * @queue_info: The &struct ath5k_txq_info to fill
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_ciint
13862306a36Sopenharmony_ciath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
13962306a36Sopenharmony_ci		struct ath5k_txq_info *queue_info)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
14262306a36Sopenharmony_ci	return 0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/**
14662306a36Sopenharmony_ci * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue
14762306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
14862306a36Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
14962306a36Sopenharmony_ci * @qinfo: The &struct ath5k_txq_info to use
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * Returns 0 on success or -EIO if queue is inactive
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_ciint
15462306a36Sopenharmony_ciath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
15562306a36Sopenharmony_ci				const struct ath5k_txq_info *qinfo)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct ath5k_txq_info *qi;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	qi = &ah->ah_txq[queue];
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
16462306a36Sopenharmony_ci		return -EIO;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* copy and validate values */
16762306a36Sopenharmony_ci	qi->tqi_type = qinfo->tqi_type;
16862306a36Sopenharmony_ci	qi->tqi_subtype = qinfo->tqi_subtype;
16962306a36Sopenharmony_ci	qi->tqi_flags = qinfo->tqi_flags;
17062306a36Sopenharmony_ci	/*
17162306a36Sopenharmony_ci	 * According to the docs: Although the AIFS field is 8 bit wide,
17262306a36Sopenharmony_ci	 * the maximum supported value is 0xFC. Setting it higher than that
17362306a36Sopenharmony_ci	 * will cause the DCU to hang.
17462306a36Sopenharmony_ci	 */
17562306a36Sopenharmony_ci	qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
17662306a36Sopenharmony_ci	qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
17762306a36Sopenharmony_ci	qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
17862306a36Sopenharmony_ci	qi->tqi_cbr_period = qinfo->tqi_cbr_period;
17962306a36Sopenharmony_ci	qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
18062306a36Sopenharmony_ci	qi->tqi_burst_time = qinfo->tqi_burst_time;
18162306a36Sopenharmony_ci	qi->tqi_ready_time = qinfo->tqi_ready_time;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/*XXX: Is this supported on 5210 ?*/
18462306a36Sopenharmony_ci	/*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
18562306a36Sopenharmony_ci	if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
18662306a36Sopenharmony_ci		((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
18762306a36Sopenharmony_ci		 (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
18862306a36Sopenharmony_ci	     qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
18962306a36Sopenharmony_ci		qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/**
19562306a36Sopenharmony_ci * ath5k_hw_setup_tx_queue() - Initialize a transmit queue
19662306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
19762306a36Sopenharmony_ci * @queue_type: One of enum ath5k_tx_queue
19862306a36Sopenharmony_ci * @queue_info: The &struct ath5k_txq_info to use
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Returns 0 on success, -EINVAL on invalid arguments
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_ciint
20362306a36Sopenharmony_ciath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
20462306a36Sopenharmony_ci		struct ath5k_txq_info *queue_info)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	unsigned int queue;
20762306a36Sopenharmony_ci	int ret;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/*
21062306a36Sopenharmony_ci	 * Get queue by type
21162306a36Sopenharmony_ci	 */
21262306a36Sopenharmony_ci	/* 5210 only has 2 queues */
21362306a36Sopenharmony_ci	if (ah->ah_capabilities.cap_queues.q_tx_num == 2) {
21462306a36Sopenharmony_ci		switch (queue_type) {
21562306a36Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
21662306a36Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
21962306a36Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
22062306a36Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
22162306a36Sopenharmony_ci			break;
22262306a36Sopenharmony_ci		default:
22362306a36Sopenharmony_ci			return -EINVAL;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci	} else {
22662306a36Sopenharmony_ci		switch (queue_type) {
22762306a36Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
22862306a36Sopenharmony_ci			queue = queue_info->tqi_subtype;
22962306a36Sopenharmony_ci			break;
23062306a36Sopenharmony_ci		case AR5K_TX_QUEUE_UAPSD:
23162306a36Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_UAPSD;
23262306a36Sopenharmony_ci			break;
23362306a36Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
23462306a36Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_BEACON;
23562306a36Sopenharmony_ci			break;
23662306a36Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
23762306a36Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_CAB;
23862306a36Sopenharmony_ci			break;
23962306a36Sopenharmony_ci		default:
24062306a36Sopenharmony_ci			return -EINVAL;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * Setup internal queue structure
24662306a36Sopenharmony_ci	 */
24762306a36Sopenharmony_ci	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
24862306a36Sopenharmony_ci	ah->ah_txq[queue].tqi_type = queue_type;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (queue_info != NULL) {
25162306a36Sopenharmony_ci		queue_info->tqi_type = queue_type;
25262306a36Sopenharmony_ci		ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
25362306a36Sopenharmony_ci		if (ret)
25462306a36Sopenharmony_ci			return ret;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * We use ah_txq_status to hold a temp value for
25962306a36Sopenharmony_ci	 * the Secondary interrupt mask registers on 5211+
26062306a36Sopenharmony_ci	 * check out ath5k_hw_reset_tx_queue
26162306a36Sopenharmony_ci	 */
26262306a36Sopenharmony_ci	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return queue;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/*******************************\
26962306a36Sopenharmony_ci* Single QCU/DCU initialization *
27062306a36Sopenharmony_ci\*******************************/
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/**
27362306a36Sopenharmony_ci * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU
27462306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
27562306a36Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * This function is used when initializing a queue, to set
27862306a36Sopenharmony_ci * retry limits based on ah->ah_retry_* and the chipset used.
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_civoid
28162306a36Sopenharmony_ciath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
28262306a36Sopenharmony_ci				  unsigned int queue)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	/* Single data queue on AR5210 */
28562306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
28662306a36Sopenharmony_ci		struct ath5k_txq_info *tq = &ah->ah_txq[queue];
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		if (queue > 0)
28962306a36Sopenharmony_ci			return;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		ath5k_hw_reg_write(ah,
29262306a36Sopenharmony_ci			(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
29362306a36Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_long,
29462306a36Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_SLG_RETRY)
29562306a36Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_short,
29662306a36Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_SSH_RETRY)
29762306a36Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_long,
29862306a36Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_LG_RETRY)
29962306a36Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_short,
30062306a36Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_SH_RETRY),
30162306a36Sopenharmony_ci			AR5K_NODCU_RETRY_LMT);
30262306a36Sopenharmony_ci	/* DCU on AR5211+ */
30362306a36Sopenharmony_ci	} else {
30462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah,
30562306a36Sopenharmony_ci			AR5K_REG_SM(ah->ah_retry_long,
30662306a36Sopenharmony_ci				    AR5K_DCU_RETRY_LMT_RTS)
30762306a36Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_long,
30862306a36Sopenharmony_ci				      AR5K_DCU_RETRY_LMT_STA_RTS)
30962306a36Sopenharmony_ci			| AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short),
31062306a36Sopenharmony_ci				      AR5K_DCU_RETRY_LMT_STA_DATA),
31162306a36Sopenharmony_ci			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/**
31662306a36Sopenharmony_ci * ath5k_hw_reset_tx_queue() - Initialize a single hw queue
31762306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
31862306a36Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * Set DCF properties for the given transmit queue on DCU
32162306a36Sopenharmony_ci * and configures all queue-specific parameters.
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_ciint
32462306a36Sopenharmony_ciath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Skip if queue inactive or if we are on AR5210
33162306a36Sopenharmony_ci	 * that doesn't have QCU/DCU */
33262306a36Sopenharmony_ci	if ((ah->ah_version == AR5K_AR5210) ||
33362306a36Sopenharmony_ci	(tq->tqi_type == AR5K_TX_QUEUE_INACTIVE))
33462306a36Sopenharmony_ci		return 0;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/*
33762306a36Sopenharmony_ci	 * Set contention window (cw_min/cw_max)
33862306a36Sopenharmony_ci	 * and arbitrated interframe space (aifs)...
33962306a36Sopenharmony_ci	 */
34062306a36Sopenharmony_ci	ath5k_hw_reg_write(ah,
34162306a36Sopenharmony_ci		AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
34262306a36Sopenharmony_ci		AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
34362306a36Sopenharmony_ci		AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
34462306a36Sopenharmony_ci		AR5K_QUEUE_DFS_LOCAL_IFS(queue));
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/*
34762306a36Sopenharmony_ci	 * Set tx retry limits for this queue
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	ath5k_hw_set_tx_retry_limits(ah, queue);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/*
35362306a36Sopenharmony_ci	 * Set misc registers
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Enable DCU to wait for next fragment from QCU */
35762306a36Sopenharmony_ci	AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
35862306a36Sopenharmony_ci				AR5K_DCU_MISC_FRAG_WAIT);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* On Maui and Spirit use the global seqnum on DCU */
36162306a36Sopenharmony_ci	if (ah->ah_mac_version < AR5K_SREV_AR5211)
36262306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
36362306a36Sopenharmony_ci					AR5K_DCU_MISC_SEQNUM_CTL);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Constant bit rate period */
36662306a36Sopenharmony_ci	if (tq->tqi_cbr_period) {
36762306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
36862306a36Sopenharmony_ci					AR5K_QCU_CBRCFG_INTVAL) |
36962306a36Sopenharmony_ci					AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
37062306a36Sopenharmony_ci					AR5K_QCU_CBRCFG_ORN_THRES),
37162306a36Sopenharmony_ci					AR5K_QUEUE_CBRCFG(queue));
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
37462306a36Sopenharmony_ci					AR5K_QCU_MISC_FRSHED_CBR);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		if (tq->tqi_cbr_overflow_limit)
37762306a36Sopenharmony_ci			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
37862306a36Sopenharmony_ci					AR5K_QCU_MISC_CBR_THRES_ENABLE);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Ready time interval */
38262306a36Sopenharmony_ci	if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB))
38362306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
38462306a36Sopenharmony_ci					AR5K_QCU_RDYTIMECFG_INTVAL) |
38562306a36Sopenharmony_ci					AR5K_QCU_RDYTIMECFG_ENABLE,
38662306a36Sopenharmony_ci					AR5K_QUEUE_RDYTIMECFG(queue));
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (tq->tqi_burst_time) {
38962306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
39062306a36Sopenharmony_ci					AR5K_DCU_CHAN_TIME_DUR) |
39162306a36Sopenharmony_ci					AR5K_DCU_CHAN_TIME_ENABLE,
39262306a36Sopenharmony_ci					AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
39562306a36Sopenharmony_ci			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
39662306a36Sopenharmony_ci					AR5K_QCU_MISC_RDY_VEOL_POLICY);
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Enable/disable Post frame backoff */
40062306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
40162306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
40262306a36Sopenharmony_ci					AR5K_QUEUE_DFS_MISC(queue));
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* Enable/disable fragmentation burst backoff */
40562306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
40662306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
40762306a36Sopenharmony_ci					AR5K_QUEUE_DFS_MISC(queue));
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Set registers by queue type
41162306a36Sopenharmony_ci	 */
41262306a36Sopenharmony_ci	switch (tq->tqi_type) {
41362306a36Sopenharmony_ci	case AR5K_TX_QUEUE_BEACON:
41462306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
41562306a36Sopenharmony_ci				AR5K_QCU_MISC_FRSHED_DBA_GT |
41662306a36Sopenharmony_ci				AR5K_QCU_MISC_CBREXP_BCN_DIS |
41762306a36Sopenharmony_ci				AR5K_QCU_MISC_BCN_ENABLE);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
42062306a36Sopenharmony_ci				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
42162306a36Sopenharmony_ci				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
42262306a36Sopenharmony_ci				AR5K_DCU_MISC_ARBLOCK_IGNORE |
42362306a36Sopenharmony_ci				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
42462306a36Sopenharmony_ci				AR5K_DCU_MISC_BCN_ENABLE);
42562306a36Sopenharmony_ci		break;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	case AR5K_TX_QUEUE_CAB:
42862306a36Sopenharmony_ci		/* XXX: use BCN_SENT_GT, if we can figure out how */
42962306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
43062306a36Sopenharmony_ci					AR5K_QCU_MISC_FRSHED_DBA_GT |
43162306a36Sopenharmony_ci					AR5K_QCU_MISC_CBREXP_DIS |
43262306a36Sopenharmony_ci					AR5K_QCU_MISC_CBREXP_BCN_DIS);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
43562306a36Sopenharmony_ci					(AR5K_TUNE_SW_BEACON_RESP -
43662306a36Sopenharmony_ci					AR5K_TUNE_DMA_BEACON_RESP) -
43762306a36Sopenharmony_ci				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
43862306a36Sopenharmony_ci					AR5K_QCU_RDYTIMECFG_ENABLE,
43962306a36Sopenharmony_ci					AR5K_QUEUE_RDYTIMECFG(queue));
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
44262306a36Sopenharmony_ci					(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
44362306a36Sopenharmony_ci					AR5K_DCU_MISC_ARBLOCK_CTL_S));
44462306a36Sopenharmony_ci		break;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	case AR5K_TX_QUEUE_UAPSD:
44762306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
44862306a36Sopenharmony_ci					AR5K_QCU_MISC_CBREXP_DIS);
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	case AR5K_TX_QUEUE_DATA:
45262306a36Sopenharmony_ci	default:
45362306a36Sopenharmony_ci			break;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* TODO: Handle frame compression */
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/*
45962306a36Sopenharmony_ci	 * Enable interrupts for this tx queue
46062306a36Sopenharmony_ci	 * in the secondary interrupt mask registers
46162306a36Sopenharmony_ci	 */
46262306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
46362306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
46662306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
46962306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
47262306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
47562306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
47862306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
48162306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
48462306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
48762306a36Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* Update secondary interrupt mask registers */
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Filter out inactive queues */
49262306a36Sopenharmony_ci	ah->ah_txq_imr_txok &= ah->ah_txq_status;
49362306a36Sopenharmony_ci	ah->ah_txq_imr_txerr &= ah->ah_txq_status;
49462306a36Sopenharmony_ci	ah->ah_txq_imr_txurn &= ah->ah_txq_status;
49562306a36Sopenharmony_ci	ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
49662306a36Sopenharmony_ci	ah->ah_txq_imr_txeol &= ah->ah_txq_status;
49762306a36Sopenharmony_ci	ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
49862306a36Sopenharmony_ci	ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
49962306a36Sopenharmony_ci	ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
50062306a36Sopenharmony_ci	ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
50362306a36Sopenharmony_ci					AR5K_SIMR0_QCU_TXOK) |
50462306a36Sopenharmony_ci					AR5K_REG_SM(ah->ah_txq_imr_txdesc,
50562306a36Sopenharmony_ci					AR5K_SIMR0_QCU_TXDESC),
50662306a36Sopenharmony_ci					AR5K_SIMR0);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
50962306a36Sopenharmony_ci					AR5K_SIMR1_QCU_TXERR) |
51062306a36Sopenharmony_ci					AR5K_REG_SM(ah->ah_txq_imr_txeol,
51162306a36Sopenharmony_ci					AR5K_SIMR1_QCU_TXEOL),
51262306a36Sopenharmony_ci					AR5K_SIMR1);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/* Update SIMR2 but don't overwrite rest simr2 settings */
51562306a36Sopenharmony_ci	AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
51662306a36Sopenharmony_ci	AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
51762306a36Sopenharmony_ci				AR5K_REG_SM(ah->ah_txq_imr_txurn,
51862306a36Sopenharmony_ci				AR5K_SIMR2_QCU_TXURN));
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
52162306a36Sopenharmony_ci				AR5K_SIMR3_QCBRORN) |
52262306a36Sopenharmony_ci				AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
52362306a36Sopenharmony_ci				AR5K_SIMR3_QCBRURN),
52462306a36Sopenharmony_ci				AR5K_SIMR3);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
52762306a36Sopenharmony_ci				AR5K_SIMR4_QTRIG), AR5K_SIMR4);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
53062306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
53162306a36Sopenharmony_ci				AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* No queue has TXNOFRM enabled, disable the interrupt
53462306a36Sopenharmony_ci	 * by setting AR5K_TXNOFRM to zero */
53562306a36Sopenharmony_ci	if (ah->ah_txq_imr_nofrm == 0)
53662306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* Set QCU mask for this DCU to save power */
53962306a36Sopenharmony_ci	AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	return 0;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/**************************\
54662306a36Sopenharmony_ci* Global QCU/DCU functions *
54762306a36Sopenharmony_ci\**************************/
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/**
55062306a36Sopenharmony_ci * ath5k_hw_set_ifs_intervals()  - Set global inter-frame spaces on DCU
55162306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
55262306a36Sopenharmony_ci * @slot_time: Slot time in us
55362306a36Sopenharmony_ci *
55462306a36Sopenharmony_ci * Sets the global IFS intervals on DCU (also works on AR5210) for
55562306a36Sopenharmony_ci * the given slot time and the current bwmode.
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_ciint ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct ieee80211_channel *channel = ah->ah_current_channel;
56062306a36Sopenharmony_ci	enum nl80211_band band;
56162306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
56262306a36Sopenharmony_ci	struct ieee80211_rate *rate;
56362306a36Sopenharmony_ci	u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
56462306a36Sopenharmony_ci	u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
56562306a36Sopenharmony_ci	u32 rate_flags, i;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
56862306a36Sopenharmony_ci		return -EINVAL;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	sifs = ath5k_hw_get_default_sifs(ah);
57162306a36Sopenharmony_ci	sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* EIFS
57462306a36Sopenharmony_ci	 * Txtime of ack at lowest rate + SIFS + DIFS
57562306a36Sopenharmony_ci	 * (DIFS = SIFS + 2 * Slot time)
57662306a36Sopenharmony_ci	 *
57762306a36Sopenharmony_ci	 * Note: HAL has some predefined values for EIFS
57862306a36Sopenharmony_ci	 * Turbo:   (37 + 2 * 6)
57962306a36Sopenharmony_ci	 * Default: (74 + 2 * 9)
58062306a36Sopenharmony_ci	 * Half:    (149 + 2 * 13)
58162306a36Sopenharmony_ci	 * Quarter: (298 + 2 * 21)
58262306a36Sopenharmony_ci	 *
58362306a36Sopenharmony_ci	 * (74 + 2 * 6) for AR5210 default and turbo !
58462306a36Sopenharmony_ci	 *
58562306a36Sopenharmony_ci	 * According to the formula we have
58662306a36Sopenharmony_ci	 * ack_tx_time = 25 for turbo and
58762306a36Sopenharmony_ci	 * ack_tx_time = 42.5 * clock multiplier
58862306a36Sopenharmony_ci	 * for default/half/quarter.
58962306a36Sopenharmony_ci	 *
59062306a36Sopenharmony_ci	 * This can't be right, 42 is what we would get
59162306a36Sopenharmony_ci	 * from ath5k_hw_get_frame_dur_for_bwmode or
59262306a36Sopenharmony_ci	 * ieee80211_generic_frame_duration for zero frame
59362306a36Sopenharmony_ci	 * length and without SIFS !
59462306a36Sopenharmony_ci	 *
59562306a36Sopenharmony_ci	 * Also we have different lowest rate for 802.11a
59662306a36Sopenharmony_ci	 */
59762306a36Sopenharmony_ci	if (channel->band == NL80211_BAND_5GHZ)
59862306a36Sopenharmony_ci		band = NL80211_BAND_5GHZ;
59962306a36Sopenharmony_ci	else
60062306a36Sopenharmony_ci		band = NL80211_BAND_2GHZ;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	switch (ah->ah_bwmode) {
60362306a36Sopenharmony_ci	case AR5K_BWMODE_5MHZ:
60462306a36Sopenharmony_ci		rate_flags = IEEE80211_RATE_SUPPORTS_5MHZ;
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci	case AR5K_BWMODE_10MHZ:
60762306a36Sopenharmony_ci		rate_flags = IEEE80211_RATE_SUPPORTS_10MHZ;
60862306a36Sopenharmony_ci		break;
60962306a36Sopenharmony_ci	default:
61062306a36Sopenharmony_ci		rate_flags = 0;
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci	sband = &ah->sbands[band];
61462306a36Sopenharmony_ci	rate = NULL;
61562306a36Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++) {
61662306a36Sopenharmony_ci		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
61762306a36Sopenharmony_ci			continue;
61862306a36Sopenharmony_ci		rate = &sband->bitrates[i];
61962306a36Sopenharmony_ci		break;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci	if (WARN_ON(!rate))
62262306a36Sopenharmony_ci		return -EINVAL;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* ack_tx_time includes an SIFS already */
62762306a36Sopenharmony_ci	eifs = ack_tx_time + sifs + 2 * slot_time;
62862306a36Sopenharmony_ci	eifs_clock = ath5k_hw_htoclock(ah, eifs);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* Set IFS settings on AR5210 */
63162306a36Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
63262306a36Sopenharmony_ci		u32 pifs, pifs_clock, difs, difs_clock;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		/* Set slot time */
63562306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		/* Set EIFS */
63862306a36Sopenharmony_ci		eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		/* PIFS = Slot time + SIFS */
64162306a36Sopenharmony_ci		pifs = slot_time + sifs;
64262306a36Sopenharmony_ci		pifs_clock = ath5k_hw_htoclock(ah, pifs);
64362306a36Sopenharmony_ci		pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		/* DIFS = SIFS + 2 * Slot time */
64662306a36Sopenharmony_ci		difs = sifs + 2 * slot_time;
64762306a36Sopenharmony_ci		difs_clock = ath5k_hw_htoclock(ah, difs);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		/* Set SIFS/DIFS */
65062306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, (difs_clock <<
65162306a36Sopenharmony_ci				AR5K_IFS0_DIFS_S) | sifs_clock,
65262306a36Sopenharmony_ci				AR5K_IFS0);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		/* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */
65562306a36Sopenharmony_ci		ath5k_hw_reg_write(ah, pifs_clock | eifs_clock |
65662306a36Sopenharmony_ci				(AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S),
65762306a36Sopenharmony_ci				AR5K_IFS1);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		return 0;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* Set IFS slot time */
66362306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* Set EIFS interval */
66662306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Set SIFS interval in usecs */
66962306a36Sopenharmony_ci	AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
67062306a36Sopenharmony_ci				AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC,
67162306a36Sopenharmony_ci				sifs);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Set SIFS interval in clock cycles */
67462306a36Sopenharmony_ci	ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return 0;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci/**
68162306a36Sopenharmony_ci * ath5k_hw_init_queues() - Initialize tx queues
68262306a36Sopenharmony_ci * @ah: The &struct ath5k_hw
68362306a36Sopenharmony_ci *
68462306a36Sopenharmony_ci * Initializes all tx queues based on information on
68562306a36Sopenharmony_ci * ah->ah_txq* set by the driver
68662306a36Sopenharmony_ci */
68762306a36Sopenharmony_ciint
68862306a36Sopenharmony_ciath5k_hw_init_queues(struct ath5k_hw *ah)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	int i, ret;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* TODO: HW Compression support for data queues */
69362306a36Sopenharmony_ci	/* TODO: Burst prefetch for data queues */
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/*
69662306a36Sopenharmony_ci	 * Reset queues and start beacon timers at the end of the reset routine
69762306a36Sopenharmony_ci	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
69862306a36Sopenharmony_ci	 * Note: If we want we can assign multiple qcus on one dcu.
69962306a36Sopenharmony_ci	 */
70062306a36Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210)
70162306a36Sopenharmony_ci		for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
70262306a36Sopenharmony_ci			ret = ath5k_hw_reset_tx_queue(ah, i);
70362306a36Sopenharmony_ci			if (ret) {
70462306a36Sopenharmony_ci				ATH5K_ERR(ah,
70562306a36Sopenharmony_ci					"failed to reset TX queue #%d\n", i);
70662306a36Sopenharmony_ci				return ret;
70762306a36Sopenharmony_ci			}
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci	else
71062306a36Sopenharmony_ci		/* No QCU/DCU on AR5210, just set tx
71162306a36Sopenharmony_ci		 * retry limits. We set IFS parameters
71262306a36Sopenharmony_ci		 * on ath5k_hw_set_ifs_intervals */
71362306a36Sopenharmony_ci		ath5k_hw_set_tx_retry_limits(ah, 0);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* Set the turbo flag when operating on 40MHz */
71662306a36Sopenharmony_ci	if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
71762306a36Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
71862306a36Sopenharmony_ci				AR5K_DCU_GBL_IFS_MISC_TURBO_MODE);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	/* If we didn't set IFS timings through
72162306a36Sopenharmony_ci	 * ath5k_hw_set_coverage_class make sure
72262306a36Sopenharmony_ci	 * we set them here */
72362306a36Sopenharmony_ci	if (!ah->ah_coverage_class) {
72462306a36Sopenharmony_ci		unsigned int slot_time = ath5k_hw_get_default_slottime(ah);
72562306a36Sopenharmony_ci		ath5k_hw_set_ifs_intervals(ah, slot_time);
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	return 0;
72962306a36Sopenharmony_ci}
730