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