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