Path: blob/main/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_xmit.c
48525 views
/*1* Copyright (c) 2013 Qualcomm Atheros, Inc.2*3* Permission to use, copy, modify, and/or distribute this software for any4* purpose with or without fee is hereby granted, provided that the above5* copyright notice and this permission notice appear in all copies.6*7* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH8* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY9* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,10* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM11* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR12* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR13* PERFORMANCE OF THIS SOFTWARE.14*/1516#include "opt_ah.h"1718#include "ah.h"19#include "ah_desc.h"20#include "ah_internal.h"2122#include "ar9300/ar9300.h"23#include "ar9300/ar9300reg.h"24#include "ar9300/ar9300phy.h"25#include "ar9300/ar9300desc.h"2627#define TU_TO_USEC(_tu) ((_tu) << 10)28#define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7)2930/*31* Update Tx FIFO trigger level.32*33* Set b_inc_trig_level to TRUE to increase the trigger level.34* Set b_inc_trig_level to FALSE to decrease the trigger level.35*36* Returns TRUE if the trigger level was updated37*/38HAL_BOOL39ar9300_update_tx_trig_level(struct ath_hal *ah, HAL_BOOL b_inc_trig_level)40{41struct ath_hal_9300 *ahp = AH9300(ah);42u_int32_t txcfg, cur_level, new_level;43HAL_INT omask;4445if (AH9300(ah)->ah_tx_trig_level >= MAX_TX_FIFO_THRESHOLD &&46b_inc_trig_level)47{48return AH_FALSE;49}5051/*52* Disable interrupts while futzing with the fifo level.53*/54omask = ar9300_set_interrupts(ah, ahp->ah_mask_reg &~ HAL_INT_GLOBAL, 0);5556txcfg = OS_REG_READ(ah, AR_TXCFG);57cur_level = MS(txcfg, AR_FTRIG);58new_level = cur_level;5960if (b_inc_trig_level) { /* increase the trigger level */61if (cur_level < MAX_TX_FIFO_THRESHOLD) {62new_level++;63}64} else if (cur_level > MIN_TX_FIFO_THRESHOLD) {65new_level--;66}6768if (new_level != cur_level) {69/* Update the trigger level */70OS_REG_WRITE(ah,71AR_TXCFG, (txcfg &~ AR_FTRIG) | SM(new_level, AR_FTRIG));72}7374/* re-enable chip interrupts */75ar9300_set_interrupts(ah, omask, 0);7677AH9300(ah)->ah_tx_trig_level = new_level;7879return (new_level != cur_level);80}8182/*83* Returns the value of Tx Trigger Level84*/85u_int16_t86ar9300_get_tx_trig_level(struct ath_hal *ah)87{88return (AH9300(ah)->ah_tx_trig_level);89}9091/*92* Set the properties of the tx queue with the parameters93* from q_info.94*/95HAL_BOOL96ar9300_set_tx_queue_props(struct ath_hal *ah, int q, const HAL_TXQ_INFO *q_info)97{98struct ath_hal_9300 *ahp = AH9300(ah);99HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;100101if (q >= p_cap->halTotalQueues) {102HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);103return AH_FALSE;104}105return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], q_info);106}107108/*109* Return the properties for the specified tx queue.110*/111HAL_BOOL112ar9300_get_tx_queue_props(struct ath_hal *ah, int q, HAL_TXQ_INFO *q_info)113{114struct ath_hal_9300 *ahp = AH9300(ah);115HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;116117118if (q >= p_cap->halTotalQueues) {119HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);120return AH_FALSE;121}122return ath_hal_getTxQProps(ah, q_info, &ahp->ah_txq[q]);123}124125enum {126AH_TX_QUEUE_MINUS_OFFSET_BEACON = 1,127AH_TX_QUEUE_MINUS_OFFSET_CAB = 2,128AH_TX_QUEUE_MINUS_OFFSET_UAPSD = 3,129AH_TX_QUEUE_MINUS_OFFSET_PAPRD = 4,130};131132/*133* Allocate and initialize a tx DCU/QCU combination.134*/135int136ar9300_setup_tx_queue(struct ath_hal *ah, HAL_TX_QUEUE type,137const HAL_TXQ_INFO *q_info)138{139struct ath_hal_9300 *ahp = AH9300(ah);140HAL_TX_QUEUE_INFO *qi;141HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;142int q;143144/* XXX move queue assignment to driver */145switch (type) {146case HAL_TX_QUEUE_BEACON:147/* highest priority */148q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_BEACON;149break;150case HAL_TX_QUEUE_CAB:151/* next highest priority */152q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_CAB;153break;154case HAL_TX_QUEUE_UAPSD:155q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_UAPSD;156break;157case HAL_TX_QUEUE_PAPRD:158q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_PAPRD;159break;160case HAL_TX_QUEUE_DATA:161/*162* don't infringe on top 4 queues, reserved for:163* beacon, CAB, UAPSD, PAPRD164*/165for (q = 0;166q < p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_PAPRD;167q++)168{169if (ahp->ah_txq[q].tqi_type == HAL_TX_QUEUE_INACTIVE) {170break;171}172}173if (q == p_cap->halTotalQueues - 3) {174HALDEBUG(ah, HAL_DEBUG_QUEUE,175"%s: no available tx queue\n", __func__);176return -1;177}178break;179default:180HALDEBUG(ah, HAL_DEBUG_QUEUE,181"%s: bad tx queue type %u\n", __func__, type);182return -1;183}184185HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: queue %u\n", __func__, q);186187qi = &ahp->ah_txq[q];188if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {189HALDEBUG(ah, HAL_DEBUG_QUEUE,190"%s: tx queue %u already active\n", __func__, q);191return -1;192}193194OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));195qi->tqi_type = type;196197if (q_info == AH_NULL) {198/* by default enable OK+ERR+DESC+URN interrupts */199qi->tqi_qflags = HAL_TXQ_TXOKINT_ENABLE200| HAL_TXQ_TXERRINT_ENABLE201| HAL_TXQ_TXDESCINT_ENABLE202| HAL_TXQ_TXURNINT_ENABLE;203qi->tqi_aifs = INIT_AIFS;204qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */205qi->tqi_cwmax = INIT_CWMAX;206qi->tqi_shretry = INIT_SH_RETRY;207qi->tqi_lgretry = INIT_LG_RETRY;208qi->tqi_physCompBuf = 0;209} else {210qi->tqi_physCompBuf = q_info->tqi_compBuf;211(void) ar9300_set_tx_queue_props(ah, q, q_info);212}213/* NB: must be followed by ar9300_reset_tx_queue */214return q;215}216217/*218* Update the h/w interrupt registers to reflect a tx q's configuration.219*/220static void221set_tx_q_interrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)222{223struct ath_hal_9300 *ahp = AH9300(ah);224225HALDEBUG(ah, HAL_DEBUG_INTERRUPT,226"%s: tx ok 0x%x err 0x%x eol 0x%x urn 0x%x\n",227__func__,228ahp->ah_tx_ok_interrupt_mask,229ahp->ah_tx_err_interrupt_mask,230ahp->ah_tx_eol_interrupt_mask,231ahp->ah_tx_urn_interrupt_mask);232233OS_REG_WRITE(ah, AR_IMR_S0,234SM(ahp->ah_tx_ok_interrupt_mask, AR_IMR_S0_QCU_TXOK));235OS_REG_WRITE(ah, AR_IMR_S1,236SM(ahp->ah_tx_err_interrupt_mask, AR_IMR_S1_QCU_TXERR)237| SM(ahp->ah_tx_eol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));238OS_REG_RMW_FIELD(ah,239AR_IMR_S2, AR_IMR_S2_QCU_TXURN, ahp->ah_tx_urn_interrupt_mask);240ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2);241}242243/*244* Free a tx DCU/QCU combination.245*/246HAL_BOOL247ar9300_release_tx_queue(struct ath_hal *ah, u_int q)248{249struct ath_hal_9300 *ahp = AH9300(ah);250HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;251HAL_TX_QUEUE_INFO *qi;252253if (q >= p_cap->halTotalQueues) {254HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);255return AH_FALSE;256}257258qi = &ahp->ah_txq[q];259if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {260HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: inactive queue %u\n", __func__, q);261return AH_FALSE;262}263264HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: release queue %u\n", __func__, q);265266qi->tqi_type = HAL_TX_QUEUE_INACTIVE;267ahp->ah_tx_ok_interrupt_mask &= ~(1 << q);268ahp->ah_tx_err_interrupt_mask &= ~(1 << q);269ahp->ah_tx_eol_interrupt_mask &= ~(1 << q);270ahp->ah_tx_urn_interrupt_mask &= ~(1 << q);271set_tx_q_interrupts(ah, qi);272273return AH_TRUE;274}275276/*277* Set the retry, aifs, cwmin/max, ready_time regs for specified queue278* Assumes:279* phw_channel has been set to point to the current channel280*/281HAL_BOOL282ar9300_reset_tx_queue(struct ath_hal *ah, u_int q)283{284struct ath_hal_9300 *ahp = AH9300(ah);285// struct ath_hal_private *ap = AH_PRIVATE(ah);286HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;287const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;288HAL_TX_QUEUE_INFO *qi;289u_int32_t cw_min, chan_cw_min, value;290uint32_t qmisc, dmisc;291292if (q >= p_cap->halTotalQueues) {293HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);294return AH_FALSE;295}296297qi = &ahp->ah_txq[q];298if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {299HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: inactive queue %u\n", __func__, q);300return AH_TRUE; /* XXX??? */301}302303HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: reset queue %u\n", __func__, q);304305if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) {306/*307* Select cwmin according to channel type.308* NB: chan can be NULL during attach309*/310if (chan && IEEE80211_IS_CHAN_B(chan)) {311chan_cw_min = INIT_CWMIN_11B;312} else {313chan_cw_min = INIT_CWMIN;314}315/* make sure that the CWmin is of the form (2^n - 1) */316for (cw_min = 1; cw_min < chan_cw_min; cw_min = (cw_min << 1) | 1) {}317} else {318cw_min = qi->tqi_cwmin;319}320321/* set cw_min/Max and AIFS values */322if (q > 3 || (!AH9300(ah)->ah_fccaifs))323/* values should not be overwritten if domain is FCC and manual rate324less than 24Mb is set, this check is making sure this */325{326OS_REG_WRITE(ah, AR_DLCL_IFS(q), SM(cw_min, AR_D_LCL_IFS_CWMIN)327| SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)328| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));329}330331/* Set retry limit values */332OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q),333SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |334SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |335SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));336337/* enable early termination on the QCU */338qmisc = AR_Q_MISC_DCU_EARLY_TERM_REQ;339340/* enable DCU to wait for next fragment from QCU */341if (AR_SREV_WASP(ah) && (AH_PRIVATE((ah))->ah_macRev <= AR_SREV_REVISION_WASP_12)) {342/* WAR for EV#85395: Wasp Rx overrun issue - reduces Tx queue backoff343* threshold to 1 to avoid Rx overruns - Fixed in Wasp 1.3 */344dmisc = AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1;345} else {346dmisc = AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2;347}348349/* multiqueue support */350if (qi->tqi_cbrPeriod) {351OS_REG_WRITE(ah,352AR_QCBRCFG(q),353SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |354SM(qi->tqi_cbrOverflowLimit,355AR_Q_CBRCFG_OVF_THRESH));356qmisc |= AR_Q_MISC_FSP_CBR |357(qi->tqi_cbrOverflowLimit ?358AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0);359}360361if (qi->tqi_readyTime && (qi->tqi_type != HAL_TX_QUEUE_CAB)) {362OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),363SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |364AR_Q_RDYTIMECFG_EN);365}366367OS_REG_WRITE(ah, AR_DCHNTIME(q), SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |368(qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));369370if (qi->tqi_readyTime &&371(qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE))372qmisc |= AR_Q_MISC_RDYTIME_EXP_POLICY;373if (qi->tqi_qflags & HAL_TXQ_DBA_GATED)374qmisc = (qmisc &~ AR_Q_MISC_FSP) | AR_Q_MISC_FSP_DBA_GATED;375if (MS(qmisc, AR_Q_MISC_FSP) != AR_Q_MISC_FSP_ASAP) {376/*377* These are meangingful only when not scheduled asap.378*/379if (qi->tqi_qflags & HAL_TXQ_CBR_DIS_BEMPTY)380qmisc |= AR_Q_MISC_CBR_INCR_DIS0;381else382qmisc &= ~AR_Q_MISC_CBR_INCR_DIS0;383if (qi->tqi_qflags & HAL_TXQ_CBR_DIS_QEMPTY)384qmisc |= AR_Q_MISC_CBR_INCR_DIS1;385else386qmisc &= ~AR_Q_MISC_CBR_INCR_DIS1;387}388389if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE)390dmisc |= AR_D_MISC_POST_FR_BKOFF_DIS;391if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE)392dmisc |= AR_D_MISC_FRAG_BKOFF_EN;393if (qi->tqi_qflags & HAL_TXQ_ARB_LOCKOUT_GLOBAL)394dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,395AR_D_MISC_ARB_LOCKOUT_CNTRL);396else if (qi->tqi_qflags & HAL_TXQ_ARB_LOCKOUT_INTRA)397dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR,398AR_D_MISC_ARB_LOCKOUT_CNTRL);399if (qi->tqi_qflags & HAL_TXQ_IGNORE_VIRTCOL)400dmisc |= SM(AR_D_MISC_VIR_COL_HANDLING_IGNORE,401AR_D_MISC_VIR_COL_HANDLING);402if (qi->tqi_qflags & HAL_TXQ_SEQNUM_INC_DIS)403dmisc |= AR_D_MISC_SEQ_NUM_INCR_DIS;404405switch (qi->tqi_type) {406case HAL_TX_QUEUE_BEACON: /* beacon frames */407qmisc |= AR_Q_MISC_FSP_DBA_GATED408| AR_Q_MISC_BEACON_USE409| AR_Q_MISC_CBR_INCR_DIS1;410411dmisc |= (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<412AR_D_MISC_ARB_LOCKOUT_CNTRL_S)413| AR_D_MISC_BEACON_USE414| AR_D_MISC_POST_FR_BKOFF_DIS;415/* XXX cwmin and cwmax should be 0 for beacon queue */416if (AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS) {417OS_REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)418| SM(0, AR_D_LCL_IFS_CWMAX)419| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));420}421break;422case HAL_TX_QUEUE_CAB: /* CAB frames */423/*424* No longer Enable AR_Q_MISC_RDYTIME_EXP_POLICY,425* bug #6079. There is an issue with the CAB Queue426* not properly refreshing the Tx descriptor if427* the TXE clear setting is used.428*/429qmisc |= AR_Q_MISC_FSP_DBA_GATED430| AR_Q_MISC_CBR_INCR_DIS1431| AR_Q_MISC_CBR_INCR_DIS0;432433if (qi->tqi_readyTime) {434OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),435SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |436AR_Q_RDYTIMECFG_EN);437} else {438439value = (ahp->ah_beaconInterval * 50 / 100)440- ah->ah_config.ah_additional_swba_backoff441- ah->ah_config.ah_sw_beacon_response_time442+ ah->ah_config.ah_dma_beacon_response_time;443/*444* XXX Ensure it isn't too low - nothing lower445* XXX than 10 TU446*/447if (value < 10)448value = 10;449if (value < 0)450value = 10;451HALDEBUG(ah, HAL_DEBUG_TXQUEUE,452"%s: defaulting to rdytime = %d uS\n",453__func__, value);454OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),455SM(TU_TO_USEC(value), AR_Q_RDYTIMECFG_DURATION) |456AR_Q_RDYTIMECFG_EN);457}458dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,459AR_D_MISC_ARB_LOCKOUT_CNTRL);460break;461case HAL_TX_QUEUE_PSPOLL:462/*463* We may configure ps_poll QCU to be TIM-gated in the464* future; TIM_GATED bit is not enabled currently because465* of a hardware problem in Oahu that overshoots the TIM466* bitmap in beacon and may find matching associd bit in467* non-TIM elements and send PS-poll PS poll processing468* will be done in software469*/470qmisc |= AR_Q_MISC_CBR_INCR_DIS1;471break;472case HAL_TX_QUEUE_UAPSD:473dmisc |= AR_D_MISC_POST_FR_BKOFF_DIS;474break;475default: /* NB: silence compiler */476break;477}478479#ifndef AH_DISABLE_WME480/*481* Yes, this is a hack and not the right way to do it, but482* it does get the lockout bits and backoff set for the483* high-pri WME queues for testing. We need to either extend484* the meaning of queue_info->mode, or create something like485* queue_info->dcumode.486*/487if (qi->tqi_intFlags & HAL_TXQ_USE_LOCKOUT_BKOFF_DIS) {488dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,489AR_D_MISC_ARB_LOCKOUT_CNTRL) |490AR_D_MISC_POST_FR_BKOFF_DIS;491}492#endif493494OS_REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);495OS_REG_WRITE(ah, AR_QMISC(q), qmisc);496OS_REG_WRITE(ah, AR_DMISC(q), dmisc);497498/*499* Always update the secondary interrupt mask registers - this500* could be a new queue getting enabled in a running system or501* hw getting re-initialized during a reset!502*503* Since we don't differentiate between tx interrupts corresponding504* to individual queues - secondary tx mask regs are always unmasked;505* tx interrupts are enabled/disabled for all queues collectively506* using the primary mask reg507*/508if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) {509ahp->ah_tx_ok_interrupt_mask |= (1 << q);510} else {511ahp->ah_tx_ok_interrupt_mask &= ~(1 << q);512}513if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) {514ahp->ah_tx_err_interrupt_mask |= (1 << q);515} else {516ahp->ah_tx_err_interrupt_mask &= ~(1 << q);517}518if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) {519ahp->ah_tx_eol_interrupt_mask |= (1 << q);520} else {521ahp->ah_tx_eol_interrupt_mask &= ~(1 << q);522}523if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) {524ahp->ah_tx_urn_interrupt_mask |= (1 << q);525} else {526ahp->ah_tx_urn_interrupt_mask &= ~(1 << q);527}528set_tx_q_interrupts(ah, qi);529530return AH_TRUE;531}532533/*534* Get the TXDP for the specified queue535*/536u_int32_t537ar9300_get_tx_dp(struct ath_hal *ah, u_int q)538{539HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);540return OS_REG_READ(ah, AR_QTXDP(q));541}542543/*544* Set the tx_dp for the specified queue545*/546HAL_BOOL547ar9300_set_tx_dp(struct ath_hal *ah, u_int q, u_int32_t txdp)548{549HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);550HALASSERT(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);551HALASSERT(txdp != 0);552553OS_REG_WRITE(ah, AR_QTXDP(q), txdp);554555return AH_TRUE;556}557558/*559* Transmit Enable is read-only now560*/561HAL_BOOL562ar9300_start_tx_dma(struct ath_hal *ah, u_int q)563{564return AH_TRUE;565}566567/*568* Return the number of pending frames or 0 if the specified569* queue is stopped.570*/571u_int32_t572ar9300_num_tx_pending(struct ath_hal *ah, u_int q)573{574u_int32_t npend;575576HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);577578npend = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;579if (npend == 0) {580/*581* Pending frame count (PFC) can momentarily go to zero582* while TXE remains asserted. In other words a PFC of583* zero is not sufficient to say that the queue has stopped.584*/585if (OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) {586npend = 1; /* arbitrarily return 1 */587}588}589#ifdef DEBUG590if (npend && (AH9300(ah)->ah_txq[q].tqi_type == HAL_TX_QUEUE_CAB)) {591if (OS_REG_READ(ah, AR_Q_RDYTIMESHDN) & (1 << q)) {592HALDEBUG(ah, HAL_DEBUG_QUEUE, "RTSD on CAB queue\n");593/* Clear the ready_time shutdown status bits */594OS_REG_WRITE(ah, AR_Q_RDYTIMESHDN, 1 << q);595}596}597#endif598HALASSERT((npend == 0) ||599(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE));600601return npend;602}603604/*605* Stop transmit on the specified queue606*/607HAL_BOOL608ar9300_stop_tx_dma(struct ath_hal *ah, u_int q, u_int timeout)609{610struct ath_hal_9300 *ahp = AH9300(ah);611612/*613* If we call abort txdma instead, no need to stop RX.614* Otherwise, the RX logic might not be restarted properly.615*/616ahp->ah_abort_txdma_norx = AH_FALSE;617618/*619* Directly call abort. It is better, hardware-wise, to stop all620* queues at once than individual ones.621*/622return ar9300_abort_tx_dma(ah);623624#if 0625#define AH_TX_STOP_DMA_TIMEOUT 4000 /* usec */626#define AH_TIME_QUANTUM 100 /* usec */627u_int wait;628629HALASSERT(q < AH_PRIVATE(ah)->ah_caps.hal_total_queues);630631HALASSERT(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);632633if (timeout == 0) {634timeout = AH_TX_STOP_DMA_TIMEOUT;635}636637OS_REG_WRITE(ah, AR_Q_TXD, 1 << q);638639for (wait = timeout / AH_TIME_QUANTUM; wait != 0; wait--) {640if (ar9300_num_tx_pending(ah, q) == 0) {641break;642}643OS_DELAY(AH_TIME_QUANTUM); /* XXX get actual value */644}645646#ifdef AH_DEBUG647if (wait == 0) {648HALDEBUG(ah, HAL_DEBUG_QUEUE,649"%s: queue %u DMA did not stop in 100 msec\n", __func__, q);650HALDEBUG(ah, HAL_DEBUG_QUEUE,651"%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n",652__func__,653OS_REG_READ(ah, AR_QSTS(q)),654OS_REG_READ(ah, AR_Q_TXE),655OS_REG_READ(ah, AR_Q_TXD),656OS_REG_READ(ah, AR_QCBRCFG(q)));657HALDEBUG(ah, HAL_DEBUG_QUEUE,658"%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n",659__func__,660OS_REG_READ(ah, AR_QMISC(q)),661OS_REG_READ(ah, AR_QRDYTIMECFG(q)),662OS_REG_READ(ah, AR_Q_RDYTIMESHDN));663}664#endif /* AH_DEBUG */665666/* 2413+ and up can kill packets at the PCU level */667if (ar9300_num_tx_pending(ah, q)) {668u_int32_t tsf_low, j;669670HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: Num of pending TX Frames %d on Q %d\n",671__func__, ar9300_num_tx_pending(ah, q), q);672673/* Kill last PCU Tx Frame */674/* TODO - save off and restore current values of Q1/Q2? */675for (j = 0; j < 2; j++) {676tsf_low = OS_REG_READ(ah, AR_TSF_L32);677OS_REG_WRITE(ah, AR_QUIET2, SM(10, AR_QUIET2_QUIET_DUR));678OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100);679OS_REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsf_low >> 10);680OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);681682if ((OS_REG_READ(ah, AR_TSF_L32) >> 10) == (tsf_low >> 10)) {683break;684}685686HALDEBUG(ah, HAL_DEBUG_QUEUE,687"%s: TSF have moved while trying to set "688"quiet time TSF: 0x%08x\n",689__func__, tsf_low);690/* TSF shouldn't count twice or reg access is taking forever */691HALASSERT(j < 1);692}693694OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);695696/* Allow the quiet mechanism to do its work */697OS_DELAY(200);698OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);699700/* Verify all transmit is dead */701wait = timeout / AH_TIME_QUANTUM;702while (ar9300_num_tx_pending(ah, q)) {703if ((--wait) == 0) {704HALDEBUG(ah, HAL_DEBUG_TX,705"%s: Failed to stop Tx DMA in %d msec "706"after killing last frame\n",707__func__, timeout / 1000);708break;709}710OS_DELAY(AH_TIME_QUANTUM);711}712713OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);714}715716OS_REG_WRITE(ah, AR_Q_TXD, 0);717return (wait != 0);718719#undef AH_TX_STOP_DMA_TIMEOUT720#undef AH_TIME_QUANTUM721#endif722}723724/*725* Really Stop transmit on the specified queue726*/727HAL_BOOL728ar9300_stop_tx_dma_indv_que(struct ath_hal *ah, u_int q, u_int timeout)729{730#define AH_TX_STOP_DMA_TIMEOUT 4000 /* usec */731#define AH_TIME_QUANTUM 100 /* usec */732u_int wait;733734HALASSERT(q < AH_PRIVATE(ah)->ah_caps.hal_total_queues);735736HALASSERT(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);737738if (timeout == 0) {739timeout = AH_TX_STOP_DMA_TIMEOUT;740}741742OS_REG_WRITE(ah, AR_Q_TXD, 1 << q);743744for (wait = timeout / AH_TIME_QUANTUM; wait != 0; wait--) {745if (ar9300_num_tx_pending(ah, q) == 0) {746break;747}748OS_DELAY(AH_TIME_QUANTUM); /* XXX get actual value */749}750751#ifdef AH_DEBUG752if (wait == 0) {753HALDEBUG(ah, HAL_DEBUG_QUEUE,754"%s: queue %u DMA did not stop in 100 msec\n", __func__, q);755HALDEBUG(ah, HAL_DEBUG_QUEUE,756"%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n",757__func__,758OS_REG_READ(ah, AR_QSTS(q)),759OS_REG_READ(ah, AR_Q_TXE),760OS_REG_READ(ah, AR_Q_TXD),761OS_REG_READ(ah, AR_QCBRCFG(q)));762HALDEBUG(ah, HAL_DEBUG_QUEUE,763"%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n",764__func__,765OS_REG_READ(ah, AR_QMISC(q)),766OS_REG_READ(ah, AR_QRDYTIMECFG(q)),767OS_REG_READ(ah, AR_Q_RDYTIMESHDN));768}769#endif /* AH_DEBUG */770771/* 2413+ and up can kill packets at the PCU level */772if (ar9300_num_tx_pending(ah, q)) {773u_int32_t tsf_low, j;774775HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: Num of pending TX Frames %d on Q %d\n",776__func__, ar9300_num_tx_pending(ah, q), q);777778/* Kill last PCU Tx Frame */779/* TODO - save off and restore current values of Q1/Q2? */780for (j = 0; j < 2; j++) {781tsf_low = OS_REG_READ(ah, AR_TSF_L32);782OS_REG_WRITE(ah, AR_QUIET2, SM(10, AR_QUIET2_QUIET_DUR));783OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100);784OS_REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsf_low >> 10);785OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);786787if ((OS_REG_READ(ah, AR_TSF_L32) >> 10) == (tsf_low >> 10)) {788break;789}790791HALDEBUG(ah, HAL_DEBUG_QUEUE,792"%s: TSF have moved while trying to set "793"quiet time TSF: 0x%08x\n",794__func__, tsf_low);795/* TSF shouldn't count twice or reg access is taking forever */796HALASSERT(j < 1);797}798799OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);800801/* Allow the quiet mechanism to do its work */802OS_DELAY(200);803OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);804805/* Verify all transmit is dead */806wait = timeout / AH_TIME_QUANTUM;807while (ar9300_num_tx_pending(ah, q)) {808if ((--wait) == 0) {809HALDEBUG(ah, HAL_DEBUG_TX,810"%s: Failed to stop Tx DMA in %d msec "811"after killing last frame\n",812__func__, timeout / 1000);813break;814}815OS_DELAY(AH_TIME_QUANTUM);816}817818OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);819}820821OS_REG_WRITE(ah, AR_Q_TXD, 0);822return (wait != 0);823824#undef AH_TX_STOP_DMA_TIMEOUT825#undef AH_TIME_QUANTUM826}827828/*829* Abort transmit on all queues830*/831#define AR9300_ABORT_LOOPS 1000832#define AR9300_ABORT_WAIT 5833#define NEXT_TBTT_NOW 10834HAL_BOOL835ar9300_abort_tx_dma(struct ath_hal *ah)836{837struct ath_hal_9300 *ahp = AH9300(ah);838int i, q;839u_int32_t nexttbtt, nextdba, tsf_tbtt, tbtt, dba;840HAL_BOOL stopped;841HAL_BOOL status = AH_TRUE;842843if (ahp->ah_abort_txdma_norx) {844/*845* First of all, make sure RX has been stopped846*/847if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) {848/* Need to stop RX DMA before reset otherwise chip might hang */849stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */850ar9300_set_rx_filter(ah, 0);851stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */852if (!stopped) {853/*854* During the transition from full sleep to reset,855* recv DMA regs are not available to be read856*/857HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,858"%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__);859//We still continue to stop TX dma860//return AH_FALSE;861}862} else {863HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,864"%s[%d]: Chip is already in full sleep\n", __func__, __LINE__);865}866}867868/*869* set txd on all queues870*/871OS_REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);872873/*874* set tx abort bits (also disable rx)875*/876OS_REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);877/* Add a new receipe from K31 code */878OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS |879AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR);880/* beacon Q flush */881nexttbtt = OS_REG_READ(ah, AR_NEXT_TBTT_TIMER);882nextdba = OS_REG_READ(ah, AR_NEXT_DMA_BEACON_ALERT);883//printk("%s[%d]:dba: %d, nt: %d \n", __func__, __LINE__, nextdba, nexttbtt);884tsf_tbtt = OS_REG_READ(ah, AR_TSF_L32);885tbtt = tsf_tbtt + NEXT_TBTT_NOW;886dba = tsf_tbtt;887OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, dba);888OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, tbtt);889OS_REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);890891/*892* Let TXE (all queues) clear before waiting for any pending frames893* This is needed before starting the RF_BUS GRANT sequence other wise causes kernel894* panic895*/896for(i = 0; i < AR9300_ABORT_LOOPS; i++) {897if(OS_REG_READ(ah, AR_Q_TXE) == 0) {898break;899}900OS_DELAY(AR9300_ABORT_WAIT);901}902if (i == AR9300_ABORT_LOOPS) {903HALDEBUG(ah, HAL_DEBUG_TX, "%s[%d] reached max wait on TXE\n",904__func__, __LINE__);905}906907/*908* wait on all tx queues909* This need to be checked in the last to gain extra 50 usec. on avg.910* Currently checked first since we dont have a previous channel information currently.911* Which is needed to revert the rf changes.912*/913for (q = AR_NUM_QCU - 1; q >= 0; q--) {914for (i = 0; i < AR9300_ABORT_LOOPS; i++) {915if (!(ar9300_num_tx_pending(ah, q))) {916break;917}918OS_DELAY(AR9300_ABORT_WAIT);919}920if (i == AR9300_ABORT_LOOPS) {921status = AH_FALSE;922HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,923"ABORT LOOP finsihsed for Q: %d, num_pending: %d \n",924q, ar9300_num_tx_pending(ah, q));925goto exit;926}927}928929/* Updating the beacon alert register with correct value */930OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, nextdba);931OS_REG_WRITE(ah, AR_NEXT_TBTT_TIMER, nexttbtt);932933exit:934/*935* clear tx abort bits936*/937OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);938/* Added a new receipe from K31 code */939OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS |940AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR);941OS_REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);942943/*944* clear txd945*/946OS_REG_WRITE(ah, AR_Q_TXD, 0);947948ahp->ah_abort_txdma_norx = AH_TRUE;949950return status;951}952953/*954* Determine which tx queues need interrupt servicing.955*/956void957ar9300_get_tx_intr_queue(struct ath_hal *ah, u_int32_t *txqs)958{959HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,960"ar9300_get_tx_intr_queue: Should not be called\n");961#if 0962struct ath_hal_9300 *ahp = AH9300(ah);963*txqs &= ahp->ah_intr_txqs;964ahp->ah_intr_txqs &= ~(*txqs);965#endif966}967968void969ar9300_reset_tx_status_ring(struct ath_hal *ah)970{971struct ath_hal_9300 *ahp = AH9300(ah);972973ahp->ts_tail = 0;974975/* Zero out the status descriptors */976OS_MEMZERO((void *)ahp->ts_ring, ahp->ts_size * sizeof(struct ar9300_txs));977HALDEBUG(ah, HAL_DEBUG_QUEUE,978"%s: TS Start 0x%x End 0x%x Virt %p, Size %d\n", __func__,979ahp->ts_paddr_start, ahp->ts_paddr_end, ahp->ts_ring, ahp->ts_size);980981OS_REG_WRITE(ah, AR_Q_STATUS_RING_START, ahp->ts_paddr_start);982OS_REG_WRITE(ah, AR_Q_STATUS_RING_END, ahp->ts_paddr_end);983}984985void986ar9300_setup_tx_status_ring(struct ath_hal *ah, void *ts_start,987u_int32_t ts_paddr_start, u_int16_t size)988{989struct ath_hal_9300 *ahp = AH9300(ah);990991ahp->ts_paddr_start = ts_paddr_start;992ahp->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9300_txs));993ahp->ts_size = size;994ahp->ts_ring = (struct ar9300_txs *)ts_start;995996ar9300_reset_tx_status_ring(ah);997}9989991000