18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
38c2ecf20Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/********************************************\
208c2ecf20Sopenharmony_ciQueue Control Unit, DCF Control Unit Functions
218c2ecf20Sopenharmony_ci\********************************************/
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "ath5k.h"
268c2ecf20Sopenharmony_ci#include "reg.h"
278c2ecf20Sopenharmony_ci#include "debug.h"
288c2ecf20Sopenharmony_ci#include <linux/log2.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/**
318c2ecf20Sopenharmony_ci * DOC: Queue Control Unit (QCU)/DCF Control Unit (DCU) functions
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * Here we setup parameters for the 12 available TX queues. Note that
348c2ecf20Sopenharmony_ci * on the various registers we can usually only map the first 10 of them so
358c2ecf20Sopenharmony_ci * basically we have 10 queues to play with. Each queue has a matching
368c2ecf20Sopenharmony_ci * QCU that controls when the queue will get triggered and multiple QCUs
378c2ecf20Sopenharmony_ci * can be mapped to a single DCU that controls the various DFS parameters
388c2ecf20Sopenharmony_ci * for the various queues. In our setup we have a 1:1 mapping between QCUs
398c2ecf20Sopenharmony_ci * and DCUs allowing us to have different DFS settings for each queue.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * When a frame goes into a TX queue, QCU decides when it'll trigger a
428c2ecf20Sopenharmony_ci * transmission based on various criteria (such as how many data we have inside
438c2ecf20Sopenharmony_ci * it's buffer or -if it's a beacon queue- if it's time to fire up the queue
448c2ecf20Sopenharmony_ci * based on TSF etc), DCU adds backoff, IFSes etc and then a scheduler
458c2ecf20Sopenharmony_ci * (arbitrator) decides the priority of each QCU based on it's configuration
468c2ecf20Sopenharmony_ci * (e.g. beacons are always transmitted when they leave DCU bypassing all other
478c2ecf20Sopenharmony_ci * frames from other queues waiting to be transmitted). After a frame leaves
488c2ecf20Sopenharmony_ci * the DCU it goes to PCU for further processing and then to PHY for
498c2ecf20Sopenharmony_ci * the actual transmission.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/******************\
548c2ecf20Sopenharmony_ci* Helper functions *
558c2ecf20Sopenharmony_ci\******************/
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/**
588c2ecf20Sopenharmony_ci * ath5k_hw_num_tx_pending() - Get number of pending frames for a  given queue
598c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
608c2ecf20Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_ciu32
638c2ecf20Sopenharmony_ciath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	u32 pending;
668c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* Return if queue is declared inactive */
698c2ecf20Sopenharmony_ci	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
708c2ecf20Sopenharmony_ci		return false;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* XXX: How about AR5K_CFG_TXCNT ? */
738c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210)
748c2ecf20Sopenharmony_ci		return false;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
778c2ecf20Sopenharmony_ci	pending &= AR5K_QCU_STS_FRMPENDCNT;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* It's possible to have no frames pending even if TXE
808c2ecf20Sopenharmony_ci	 * is set. To indicate that q has not stopped return
818c2ecf20Sopenharmony_ci	 * true */
828c2ecf20Sopenharmony_ci	if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
838c2ecf20Sopenharmony_ci		return true;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return pending;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/**
898c2ecf20Sopenharmony_ci * ath5k_hw_release_tx_queue() - Set a transmit queue inactive
908c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
918c2ecf20Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_civoid
948c2ecf20Sopenharmony_ciath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
978c2ecf20Sopenharmony_ci		return;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* This queue will be skipped in further operations */
1008c2ecf20Sopenharmony_ci	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
1018c2ecf20Sopenharmony_ci	/*For SIMR setup*/
1028c2ecf20Sopenharmony_ci	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/**
1068c2ecf20Sopenharmony_ci * ath5k_cw_validate() - Make sure the given cw is valid
1078c2ecf20Sopenharmony_ci * @cw_req: The contention window value to check
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * Make sure cw is a power of 2 minus 1 and smaller than 1024
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_cistatic u16
1128c2ecf20Sopenharmony_ciath5k_cw_validate(u16 cw_req)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	cw_req = min(cw_req, (u16)1023);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* Check if cw_req + 1 a power of 2 */
1178c2ecf20Sopenharmony_ci	if (is_power_of_2(cw_req + 1))
1188c2ecf20Sopenharmony_ci		return cw_req;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* Check if cw_req is a power of 2 */
1218c2ecf20Sopenharmony_ci	if (is_power_of_2(cw_req))
1228c2ecf20Sopenharmony_ci		return cw_req - 1;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* If none of the above is correct
1258c2ecf20Sopenharmony_ci	 * find the closest power of 2 */
1268c2ecf20Sopenharmony_ci	cw_req = (u16) roundup_pow_of_two(cw_req) - 1;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return cw_req;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/**
1328c2ecf20Sopenharmony_ci * ath5k_hw_get_tx_queueprops() - Get properties for a transmit queue
1338c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
1348c2ecf20Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
1358c2ecf20Sopenharmony_ci * @queue_info: The &struct ath5k_txq_info to fill
1368c2ecf20Sopenharmony_ci */
1378c2ecf20Sopenharmony_ciint
1388c2ecf20Sopenharmony_ciath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
1398c2ecf20Sopenharmony_ci		struct ath5k_txq_info *queue_info)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
1428c2ecf20Sopenharmony_ci	return 0;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/**
1468c2ecf20Sopenharmony_ci * ath5k_hw_set_tx_queueprops() - Set properties for a transmit queue
1478c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
1488c2ecf20Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
1498c2ecf20Sopenharmony_ci * @qinfo: The &struct ath5k_txq_info to use
1508c2ecf20Sopenharmony_ci *
1518c2ecf20Sopenharmony_ci * Returns 0 on success or -EIO if queue is inactive
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_ciint
1548c2ecf20Sopenharmony_ciath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
1558c2ecf20Sopenharmony_ci				const struct ath5k_txq_info *qinfo)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct ath5k_txq_info *qi;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	qi = &ah->ah_txq[queue];
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE)
1648c2ecf20Sopenharmony_ci		return -EIO;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* copy and validate values */
1678c2ecf20Sopenharmony_ci	qi->tqi_type = qinfo->tqi_type;
1688c2ecf20Sopenharmony_ci	qi->tqi_subtype = qinfo->tqi_subtype;
1698c2ecf20Sopenharmony_ci	qi->tqi_flags = qinfo->tqi_flags;
1708c2ecf20Sopenharmony_ci	/*
1718c2ecf20Sopenharmony_ci	 * According to the docs: Although the AIFS field is 8 bit wide,
1728c2ecf20Sopenharmony_ci	 * the maximum supported value is 0xFC. Setting it higher than that
1738c2ecf20Sopenharmony_ci	 * will cause the DCU to hang.
1748c2ecf20Sopenharmony_ci	 */
1758c2ecf20Sopenharmony_ci	qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC);
1768c2ecf20Sopenharmony_ci	qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min);
1778c2ecf20Sopenharmony_ci	qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max);
1788c2ecf20Sopenharmony_ci	qi->tqi_cbr_period = qinfo->tqi_cbr_period;
1798c2ecf20Sopenharmony_ci	qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit;
1808c2ecf20Sopenharmony_ci	qi->tqi_burst_time = qinfo->tqi_burst_time;
1818c2ecf20Sopenharmony_ci	qi->tqi_ready_time = qinfo->tqi_ready_time;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/*XXX: Is this supported on 5210 ?*/
1848c2ecf20Sopenharmony_ci	/*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/
1858c2ecf20Sopenharmony_ci	if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA &&
1868c2ecf20Sopenharmony_ci		((qinfo->tqi_subtype == AR5K_WME_AC_VI) ||
1878c2ecf20Sopenharmony_ci		 (qinfo->tqi_subtype == AR5K_WME_AC_VO))) ||
1888c2ecf20Sopenharmony_ci	     qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD)
1898c2ecf20Sopenharmony_ci		qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return 0;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/**
1958c2ecf20Sopenharmony_ci * ath5k_hw_setup_tx_queue() - Initialize a transmit queue
1968c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
1978c2ecf20Sopenharmony_ci * @queue_type: One of enum ath5k_tx_queue
1988c2ecf20Sopenharmony_ci * @queue_info: The &struct ath5k_txq_info to use
1998c2ecf20Sopenharmony_ci *
2008c2ecf20Sopenharmony_ci * Returns 0 on success, -EINVAL on invalid arguments
2018c2ecf20Sopenharmony_ci */
2028c2ecf20Sopenharmony_ciint
2038c2ecf20Sopenharmony_ciath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
2048c2ecf20Sopenharmony_ci		struct ath5k_txq_info *queue_info)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	unsigned int queue;
2078c2ecf20Sopenharmony_ci	int ret;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/*
2108c2ecf20Sopenharmony_ci	 * Get queue by type
2118c2ecf20Sopenharmony_ci	 */
2128c2ecf20Sopenharmony_ci	/* 5210 only has 2 queues */
2138c2ecf20Sopenharmony_ci	if (ah->ah_capabilities.cap_queues.q_tx_num == 2) {
2148c2ecf20Sopenharmony_ci		switch (queue_type) {
2158c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
2168c2ecf20Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
2178c2ecf20Sopenharmony_ci			break;
2188c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
2198c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
2208c2ecf20Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
2218c2ecf20Sopenharmony_ci			break;
2228c2ecf20Sopenharmony_ci		default:
2238c2ecf20Sopenharmony_ci			return -EINVAL;
2248c2ecf20Sopenharmony_ci		}
2258c2ecf20Sopenharmony_ci	} else {
2268c2ecf20Sopenharmony_ci		switch (queue_type) {
2278c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_DATA:
2288c2ecf20Sopenharmony_ci			queue = queue_info->tqi_subtype;
2298c2ecf20Sopenharmony_ci			break;
2308c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_UAPSD:
2318c2ecf20Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_UAPSD;
2328c2ecf20Sopenharmony_ci			break;
2338c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_BEACON:
2348c2ecf20Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_BEACON;
2358c2ecf20Sopenharmony_ci			break;
2368c2ecf20Sopenharmony_ci		case AR5K_TX_QUEUE_CAB:
2378c2ecf20Sopenharmony_ci			queue = AR5K_TX_QUEUE_ID_CAB;
2388c2ecf20Sopenharmony_ci			break;
2398c2ecf20Sopenharmony_ci		default:
2408c2ecf20Sopenharmony_ci			return -EINVAL;
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/*
2458c2ecf20Sopenharmony_ci	 * Setup internal queue structure
2468c2ecf20Sopenharmony_ci	 */
2478c2ecf20Sopenharmony_ci	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
2488c2ecf20Sopenharmony_ci	ah->ah_txq[queue].tqi_type = queue_type;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (queue_info != NULL) {
2518c2ecf20Sopenharmony_ci		queue_info->tqi_type = queue_type;
2528c2ecf20Sopenharmony_ci		ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
2538c2ecf20Sopenharmony_ci		if (ret)
2548c2ecf20Sopenharmony_ci			return ret;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	 * We use ah_txq_status to hold a temp value for
2598c2ecf20Sopenharmony_ci	 * the Secondary interrupt mask registers on 5211+
2608c2ecf20Sopenharmony_ci	 * check out ath5k_hw_reset_tx_queue
2618c2ecf20Sopenharmony_ci	 */
2628c2ecf20Sopenharmony_ci	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return queue;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/*******************************\
2698c2ecf20Sopenharmony_ci* Single QCU/DCU initialization *
2708c2ecf20Sopenharmony_ci\*******************************/
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci/**
2738c2ecf20Sopenharmony_ci * ath5k_hw_set_tx_retry_limits() - Set tx retry limits on DCU
2748c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
2758c2ecf20Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
2768c2ecf20Sopenharmony_ci *
2778c2ecf20Sopenharmony_ci * This function is used when initializing a queue, to set
2788c2ecf20Sopenharmony_ci * retry limits based on ah->ah_retry_* and the chipset used.
2798c2ecf20Sopenharmony_ci */
2808c2ecf20Sopenharmony_civoid
2818c2ecf20Sopenharmony_ciath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
2828c2ecf20Sopenharmony_ci				  unsigned int queue)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	/* Single data queue on AR5210 */
2858c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
2868c2ecf20Sopenharmony_ci		struct ath5k_txq_info *tq = &ah->ah_txq[queue];
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		if (queue > 0)
2898c2ecf20Sopenharmony_ci			return;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah,
2928c2ecf20Sopenharmony_ci			(tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
2938c2ecf20Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_long,
2948c2ecf20Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_SLG_RETRY)
2958c2ecf20Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_short,
2968c2ecf20Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_SSH_RETRY)
2978c2ecf20Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_long,
2988c2ecf20Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_LG_RETRY)
2998c2ecf20Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_short,
3008c2ecf20Sopenharmony_ci				      AR5K_NODCU_RETRY_LMT_SH_RETRY),
3018c2ecf20Sopenharmony_ci			AR5K_NODCU_RETRY_LMT);
3028c2ecf20Sopenharmony_ci	/* DCU on AR5211+ */
3038c2ecf20Sopenharmony_ci	} else {
3048c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah,
3058c2ecf20Sopenharmony_ci			AR5K_REG_SM(ah->ah_retry_long,
3068c2ecf20Sopenharmony_ci				    AR5K_DCU_RETRY_LMT_RTS)
3078c2ecf20Sopenharmony_ci			| AR5K_REG_SM(ah->ah_retry_long,
3088c2ecf20Sopenharmony_ci				      AR5K_DCU_RETRY_LMT_STA_RTS)
3098c2ecf20Sopenharmony_ci			| AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short),
3108c2ecf20Sopenharmony_ci				      AR5K_DCU_RETRY_LMT_STA_DATA),
3118c2ecf20Sopenharmony_ci			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/**
3168c2ecf20Sopenharmony_ci * ath5k_hw_reset_tx_queue() - Initialize a single hw queue
3178c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
3188c2ecf20Sopenharmony_ci * @queue: One of enum ath5k_tx_queue_id
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * Set DCF properties for the given transmit queue on DCU
3218c2ecf20Sopenharmony_ci * and configures all queue-specific parameters.
3228c2ecf20Sopenharmony_ci */
3238c2ecf20Sopenharmony_ciint
3248c2ecf20Sopenharmony_ciath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* Skip if queue inactive or if we are on AR5210
3318c2ecf20Sopenharmony_ci	 * that doesn't have QCU/DCU */
3328c2ecf20Sopenharmony_ci	if ((ah->ah_version == AR5K_AR5210) ||
3338c2ecf20Sopenharmony_ci	(tq->tqi_type == AR5K_TX_QUEUE_INACTIVE))
3348c2ecf20Sopenharmony_ci		return 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/*
3378c2ecf20Sopenharmony_ci	 * Set contention window (cw_min/cw_max)
3388c2ecf20Sopenharmony_ci	 * and arbitrated interframe space (aifs)...
3398c2ecf20Sopenharmony_ci	 */
3408c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah,
3418c2ecf20Sopenharmony_ci		AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
3428c2ecf20Sopenharmony_ci		AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
3438c2ecf20Sopenharmony_ci		AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
3448c2ecf20Sopenharmony_ci		AR5K_QUEUE_DFS_LOCAL_IFS(queue));
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/*
3478c2ecf20Sopenharmony_ci	 * Set tx retry limits for this queue
3488c2ecf20Sopenharmony_ci	 */
3498c2ecf20Sopenharmony_ci	ath5k_hw_set_tx_retry_limits(ah, queue);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * Set misc registers
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/* Enable DCU to wait for next fragment from QCU */
3578c2ecf20Sopenharmony_ci	AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
3588c2ecf20Sopenharmony_ci				AR5K_DCU_MISC_FRAG_WAIT);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* On Maui and Spirit use the global seqnum on DCU */
3618c2ecf20Sopenharmony_ci	if (ah->ah_mac_version < AR5K_SREV_AR5211)
3628c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
3638c2ecf20Sopenharmony_ci					AR5K_DCU_MISC_SEQNUM_CTL);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* Constant bit rate period */
3668c2ecf20Sopenharmony_ci	if (tq->tqi_cbr_period) {
3678c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
3688c2ecf20Sopenharmony_ci					AR5K_QCU_CBRCFG_INTVAL) |
3698c2ecf20Sopenharmony_ci					AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
3708c2ecf20Sopenharmony_ci					AR5K_QCU_CBRCFG_ORN_THRES),
3718c2ecf20Sopenharmony_ci					AR5K_QUEUE_CBRCFG(queue));
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
3748c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_FRSHED_CBR);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		if (tq->tqi_cbr_overflow_limit)
3778c2ecf20Sopenharmony_ci			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
3788c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_CBR_THRES_ENABLE);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* Ready time interval */
3828c2ecf20Sopenharmony_ci	if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB))
3838c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
3848c2ecf20Sopenharmony_ci					AR5K_QCU_RDYTIMECFG_INTVAL) |
3858c2ecf20Sopenharmony_ci					AR5K_QCU_RDYTIMECFG_ENABLE,
3868c2ecf20Sopenharmony_ci					AR5K_QUEUE_RDYTIMECFG(queue));
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (tq->tqi_burst_time) {
3898c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
3908c2ecf20Sopenharmony_ci					AR5K_DCU_CHAN_TIME_DUR) |
3918c2ecf20Sopenharmony_ci					AR5K_DCU_CHAN_TIME_ENABLE,
3928c2ecf20Sopenharmony_ci					AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
3958c2ecf20Sopenharmony_ci			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
3968c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_RDY_VEOL_POLICY);
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/* Enable/disable Post frame backoff */
4008c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
4018c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
4028c2ecf20Sopenharmony_ci					AR5K_QUEUE_DFS_MISC(queue));
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* Enable/disable fragmentation burst backoff */
4058c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
4068c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
4078c2ecf20Sopenharmony_ci					AR5K_QUEUE_DFS_MISC(queue));
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/*
4108c2ecf20Sopenharmony_ci	 * Set registers by queue type
4118c2ecf20Sopenharmony_ci	 */
4128c2ecf20Sopenharmony_ci	switch (tq->tqi_type) {
4138c2ecf20Sopenharmony_ci	case AR5K_TX_QUEUE_BEACON:
4148c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
4158c2ecf20Sopenharmony_ci				AR5K_QCU_MISC_FRSHED_DBA_GT |
4168c2ecf20Sopenharmony_ci				AR5K_QCU_MISC_CBREXP_BCN_DIS |
4178c2ecf20Sopenharmony_ci				AR5K_QCU_MISC_BCN_ENABLE);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
4208c2ecf20Sopenharmony_ci				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
4218c2ecf20Sopenharmony_ci				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
4228c2ecf20Sopenharmony_ci				AR5K_DCU_MISC_ARBLOCK_IGNORE |
4238c2ecf20Sopenharmony_ci				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
4248c2ecf20Sopenharmony_ci				AR5K_DCU_MISC_BCN_ENABLE);
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	case AR5K_TX_QUEUE_CAB:
4288c2ecf20Sopenharmony_ci		/* XXX: use BCN_SENT_GT, if we can figure out how */
4298c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
4308c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_FRSHED_DBA_GT |
4318c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_CBREXP_DIS |
4328c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_CBREXP_BCN_DIS);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
4358c2ecf20Sopenharmony_ci					(AR5K_TUNE_SW_BEACON_RESP -
4368c2ecf20Sopenharmony_ci					AR5K_TUNE_DMA_BEACON_RESP) -
4378c2ecf20Sopenharmony_ci				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
4388c2ecf20Sopenharmony_ci					AR5K_QCU_RDYTIMECFG_ENABLE,
4398c2ecf20Sopenharmony_ci					AR5K_QUEUE_RDYTIMECFG(queue));
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
4428c2ecf20Sopenharmony_ci					(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
4438c2ecf20Sopenharmony_ci					AR5K_DCU_MISC_ARBLOCK_CTL_S));
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	case AR5K_TX_QUEUE_UAPSD:
4478c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
4488c2ecf20Sopenharmony_ci					AR5K_QCU_MISC_CBREXP_DIS);
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	case AR5K_TX_QUEUE_DATA:
4528c2ecf20Sopenharmony_ci	default:
4538c2ecf20Sopenharmony_ci			break;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* TODO: Handle frame compression */
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/*
4598c2ecf20Sopenharmony_ci	 * Enable interrupts for this tx queue
4608c2ecf20Sopenharmony_ci	 * in the secondary interrupt mask registers
4618c2ecf20Sopenharmony_ci	 */
4628c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
4638c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
4668c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
4698c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
4728c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
4758c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
4788c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
4818c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
4848c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
4878c2ecf20Sopenharmony_ci		AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* Update secondary interrupt mask registers */
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* Filter out inactive queues */
4928c2ecf20Sopenharmony_ci	ah->ah_txq_imr_txok &= ah->ah_txq_status;
4938c2ecf20Sopenharmony_ci	ah->ah_txq_imr_txerr &= ah->ah_txq_status;
4948c2ecf20Sopenharmony_ci	ah->ah_txq_imr_txurn &= ah->ah_txq_status;
4958c2ecf20Sopenharmony_ci	ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
4968c2ecf20Sopenharmony_ci	ah->ah_txq_imr_txeol &= ah->ah_txq_status;
4978c2ecf20Sopenharmony_ci	ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
4988c2ecf20Sopenharmony_ci	ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
4998c2ecf20Sopenharmony_ci	ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
5008c2ecf20Sopenharmony_ci	ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
5038c2ecf20Sopenharmony_ci					AR5K_SIMR0_QCU_TXOK) |
5048c2ecf20Sopenharmony_ci					AR5K_REG_SM(ah->ah_txq_imr_txdesc,
5058c2ecf20Sopenharmony_ci					AR5K_SIMR0_QCU_TXDESC),
5068c2ecf20Sopenharmony_ci					AR5K_SIMR0);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
5098c2ecf20Sopenharmony_ci					AR5K_SIMR1_QCU_TXERR) |
5108c2ecf20Sopenharmony_ci					AR5K_REG_SM(ah->ah_txq_imr_txeol,
5118c2ecf20Sopenharmony_ci					AR5K_SIMR1_QCU_TXEOL),
5128c2ecf20Sopenharmony_ci					AR5K_SIMR1);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* Update SIMR2 but don't overwrite rest simr2 settings */
5158c2ecf20Sopenharmony_ci	AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
5168c2ecf20Sopenharmony_ci	AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
5178c2ecf20Sopenharmony_ci				AR5K_REG_SM(ah->ah_txq_imr_txurn,
5188c2ecf20Sopenharmony_ci				AR5K_SIMR2_QCU_TXURN));
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
5218c2ecf20Sopenharmony_ci				AR5K_SIMR3_QCBRORN) |
5228c2ecf20Sopenharmony_ci				AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
5238c2ecf20Sopenharmony_ci				AR5K_SIMR3_QCBRURN),
5248c2ecf20Sopenharmony_ci				AR5K_SIMR3);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
5278c2ecf20Sopenharmony_ci				AR5K_SIMR4_QTRIG), AR5K_SIMR4);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
5308c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
5318c2ecf20Sopenharmony_ci				AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* No queue has TXNOFRM enabled, disable the interrupt
5348c2ecf20Sopenharmony_ci	 * by setting AR5K_TXNOFRM to zero */
5358c2ecf20Sopenharmony_ci	if (ah->ah_txq_imr_nofrm == 0)
5368c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/* Set QCU mask for this DCU to save power */
5398c2ecf20Sopenharmony_ci	AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return 0;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci/**************************\
5468c2ecf20Sopenharmony_ci* Global QCU/DCU functions *
5478c2ecf20Sopenharmony_ci\**************************/
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci/**
5508c2ecf20Sopenharmony_ci * ath5k_hw_set_ifs_intervals()  - Set global inter-frame spaces on DCU
5518c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
5528c2ecf20Sopenharmony_ci * @slot_time: Slot time in us
5538c2ecf20Sopenharmony_ci *
5548c2ecf20Sopenharmony_ci * Sets the global IFS intervals on DCU (also works on AR5210) for
5558c2ecf20Sopenharmony_ci * the given slot time and the current bwmode.
5568c2ecf20Sopenharmony_ci */
5578c2ecf20Sopenharmony_ciint ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	struct ieee80211_channel *channel = ah->ah_current_channel;
5608c2ecf20Sopenharmony_ci	enum nl80211_band band;
5618c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
5628c2ecf20Sopenharmony_ci	struct ieee80211_rate *rate;
5638c2ecf20Sopenharmony_ci	u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
5648c2ecf20Sopenharmony_ci	u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
5658c2ecf20Sopenharmony_ci	u32 rate_flags, i;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
5688c2ecf20Sopenharmony_ci		return -EINVAL;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	sifs = ath5k_hw_get_default_sifs(ah);
5718c2ecf20Sopenharmony_ci	sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* EIFS
5748c2ecf20Sopenharmony_ci	 * Txtime of ack at lowest rate + SIFS + DIFS
5758c2ecf20Sopenharmony_ci	 * (DIFS = SIFS + 2 * Slot time)
5768c2ecf20Sopenharmony_ci	 *
5778c2ecf20Sopenharmony_ci	 * Note: HAL has some predefined values for EIFS
5788c2ecf20Sopenharmony_ci	 * Turbo:   (37 + 2 * 6)
5798c2ecf20Sopenharmony_ci	 * Default: (74 + 2 * 9)
5808c2ecf20Sopenharmony_ci	 * Half:    (149 + 2 * 13)
5818c2ecf20Sopenharmony_ci	 * Quarter: (298 + 2 * 21)
5828c2ecf20Sopenharmony_ci	 *
5838c2ecf20Sopenharmony_ci	 * (74 + 2 * 6) for AR5210 default and turbo !
5848c2ecf20Sopenharmony_ci	 *
5858c2ecf20Sopenharmony_ci	 * According to the formula we have
5868c2ecf20Sopenharmony_ci	 * ack_tx_time = 25 for turbo and
5878c2ecf20Sopenharmony_ci	 * ack_tx_time = 42.5 * clock multiplier
5888c2ecf20Sopenharmony_ci	 * for default/half/quarter.
5898c2ecf20Sopenharmony_ci	 *
5908c2ecf20Sopenharmony_ci	 * This can't be right, 42 is what we would get
5918c2ecf20Sopenharmony_ci	 * from ath5k_hw_get_frame_dur_for_bwmode or
5928c2ecf20Sopenharmony_ci	 * ieee80211_generic_frame_duration for zero frame
5938c2ecf20Sopenharmony_ci	 * length and without SIFS !
5948c2ecf20Sopenharmony_ci	 *
5958c2ecf20Sopenharmony_ci	 * Also we have different lowest rate for 802.11a
5968c2ecf20Sopenharmony_ci	 */
5978c2ecf20Sopenharmony_ci	if (channel->band == NL80211_BAND_5GHZ)
5988c2ecf20Sopenharmony_ci		band = NL80211_BAND_5GHZ;
5998c2ecf20Sopenharmony_ci	else
6008c2ecf20Sopenharmony_ci		band = NL80211_BAND_2GHZ;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	switch (ah->ah_bwmode) {
6038c2ecf20Sopenharmony_ci	case AR5K_BWMODE_5MHZ:
6048c2ecf20Sopenharmony_ci		rate_flags = IEEE80211_RATE_SUPPORTS_5MHZ;
6058c2ecf20Sopenharmony_ci		break;
6068c2ecf20Sopenharmony_ci	case AR5K_BWMODE_10MHZ:
6078c2ecf20Sopenharmony_ci		rate_flags = IEEE80211_RATE_SUPPORTS_10MHZ;
6088c2ecf20Sopenharmony_ci		break;
6098c2ecf20Sopenharmony_ci	default:
6108c2ecf20Sopenharmony_ci		rate_flags = 0;
6118c2ecf20Sopenharmony_ci		break;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	sband = &ah->sbands[band];
6148c2ecf20Sopenharmony_ci	rate = NULL;
6158c2ecf20Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++) {
6168c2ecf20Sopenharmony_ci		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
6178c2ecf20Sopenharmony_ci			continue;
6188c2ecf20Sopenharmony_ci		rate = &sband->bitrates[i];
6198c2ecf20Sopenharmony_ci		break;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci	if (WARN_ON(!rate))
6228c2ecf20Sopenharmony_ci		return -EINVAL;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/* ack_tx_time includes an SIFS already */
6278c2ecf20Sopenharmony_ci	eifs = ack_tx_time + sifs + 2 * slot_time;
6288c2ecf20Sopenharmony_ci	eifs_clock = ath5k_hw_htoclock(ah, eifs);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	/* Set IFS settings on AR5210 */
6318c2ecf20Sopenharmony_ci	if (ah->ah_version == AR5K_AR5210) {
6328c2ecf20Sopenharmony_ci		u32 pifs, pifs_clock, difs, difs_clock;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci		/* Set slot time */
6358c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		/* Set EIFS */
6388c2ecf20Sopenharmony_ci		eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		/* PIFS = Slot time + SIFS */
6418c2ecf20Sopenharmony_ci		pifs = slot_time + sifs;
6428c2ecf20Sopenharmony_ci		pifs_clock = ath5k_hw_htoclock(ah, pifs);
6438c2ecf20Sopenharmony_ci		pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		/* DIFS = SIFS + 2 * Slot time */
6468c2ecf20Sopenharmony_ci		difs = sifs + 2 * slot_time;
6478c2ecf20Sopenharmony_ci		difs_clock = ath5k_hw_htoclock(ah, difs);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		/* Set SIFS/DIFS */
6508c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, (difs_clock <<
6518c2ecf20Sopenharmony_ci				AR5K_IFS0_DIFS_S) | sifs_clock,
6528c2ecf20Sopenharmony_ci				AR5K_IFS0);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		/* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */
6558c2ecf20Sopenharmony_ci		ath5k_hw_reg_write(ah, pifs_clock | eifs_clock |
6568c2ecf20Sopenharmony_ci				(AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S),
6578c2ecf20Sopenharmony_ci				AR5K_IFS1);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		return 0;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* Set IFS slot time */
6638c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/* Set EIFS interval */
6668c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	/* Set SIFS interval in usecs */
6698c2ecf20Sopenharmony_ci	AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
6708c2ecf20Sopenharmony_ci				AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC,
6718c2ecf20Sopenharmony_ci				sifs);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	/* Set SIFS interval in clock cycles */
6748c2ecf20Sopenharmony_ci	ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	return 0;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci/**
6818c2ecf20Sopenharmony_ci * ath5k_hw_init_queues() - Initialize tx queues
6828c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw
6838c2ecf20Sopenharmony_ci *
6848c2ecf20Sopenharmony_ci * Initializes all tx queues based on information on
6858c2ecf20Sopenharmony_ci * ah->ah_txq* set by the driver
6868c2ecf20Sopenharmony_ci */
6878c2ecf20Sopenharmony_ciint
6888c2ecf20Sopenharmony_ciath5k_hw_init_queues(struct ath5k_hw *ah)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	int i, ret;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	/* TODO: HW Compression support for data queues */
6938c2ecf20Sopenharmony_ci	/* TODO: Burst prefetch for data queues */
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/*
6968c2ecf20Sopenharmony_ci	 * Reset queues and start beacon timers at the end of the reset routine
6978c2ecf20Sopenharmony_ci	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
6988c2ecf20Sopenharmony_ci	 * Note: If we want we can assign multiple qcus on one dcu.
6998c2ecf20Sopenharmony_ci	 */
7008c2ecf20Sopenharmony_ci	if (ah->ah_version != AR5K_AR5210)
7018c2ecf20Sopenharmony_ci		for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
7028c2ecf20Sopenharmony_ci			ret = ath5k_hw_reset_tx_queue(ah, i);
7038c2ecf20Sopenharmony_ci			if (ret) {
7048c2ecf20Sopenharmony_ci				ATH5K_ERR(ah,
7058c2ecf20Sopenharmony_ci					"failed to reset TX queue #%d\n", i);
7068c2ecf20Sopenharmony_ci				return ret;
7078c2ecf20Sopenharmony_ci			}
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci	else
7108c2ecf20Sopenharmony_ci		/* No QCU/DCU on AR5210, just set tx
7118c2ecf20Sopenharmony_ci		 * retry limits. We set IFS parameters
7128c2ecf20Sopenharmony_ci		 * on ath5k_hw_set_ifs_intervals */
7138c2ecf20Sopenharmony_ci		ath5k_hw_set_tx_retry_limits(ah, 0);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* Set the turbo flag when operating on 40MHz */
7168c2ecf20Sopenharmony_ci	if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
7178c2ecf20Sopenharmony_ci		AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
7188c2ecf20Sopenharmony_ci				AR5K_DCU_GBL_IFS_MISC_TURBO_MODE);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	/* If we didn't set IFS timings through
7218c2ecf20Sopenharmony_ci	 * ath5k_hw_set_coverage_class make sure
7228c2ecf20Sopenharmony_ci	 * we set them here */
7238c2ecf20Sopenharmony_ci	if (!ah->ah_coverage_class) {
7248c2ecf20Sopenharmony_ci		unsigned int slot_time = ath5k_hw_get_default_slottime(ah);
7258c2ecf20Sopenharmony_ci		ath5k_hw_set_ifs_intervals(ah, slot_time);
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return 0;
7298c2ecf20Sopenharmony_ci}
730