ar9300_xmit.c revision 250008
1250003Sadrian/*
2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc.
3250003Sadrian *
4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any
5250003Sadrian * purpose with or without fee is hereby granted, provided that the above
6250003Sadrian * copyright notice and this permission notice appear in all copies.
7250003Sadrian *
8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14250003Sadrian * PERFORMANCE OF THIS SOFTWARE.
15250003Sadrian */
16250003Sadrian
17250003Sadrian#include "opt_ah.h"
18250003Sadrian
19250003Sadrian#include "ah.h"
20250003Sadrian#include "ah_desc.h"
21250003Sadrian#include "ah_internal.h"
22250003Sadrian
23250003Sadrian#include "ar9300/ar9300.h"
24250003Sadrian#include "ar9300/ar9300reg.h"
25250003Sadrian#include "ar9300/ar9300phy.h"
26250003Sadrian#include "ar9300/ar9300desc.h"
27250003Sadrian
28250008Sadrian#define TU_TO_USEC(_tu)         ((_tu) << 10)
29250008Sadrian#define ONE_EIGHTH_TU_TO_USEC(_tu8)     ((_tu8) << 7)
30250008Sadrian
31250003Sadrian/*
32250003Sadrian * Update Tx FIFO trigger level.
33250003Sadrian *
34250003Sadrian * Set b_inc_trig_level to TRUE to increase the trigger level.
35250003Sadrian * Set b_inc_trig_level to FALSE to decrease the trigger level.
36250003Sadrian *
37250003Sadrian * Returns TRUE if the trigger level was updated
38250003Sadrian */
39250003SadrianHAL_BOOL
40250003Sadrianar9300_update_tx_trig_level(struct ath_hal *ah, HAL_BOOL b_inc_trig_level)
41250003Sadrian{
42250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
43250003Sadrian    u_int32_t txcfg, cur_level, new_level;
44250003Sadrian    HAL_INT omask;
45250003Sadrian
46250008Sadrian    if (AH9300(ah)->ah_tx_trig_level >= MAX_TX_FIFO_THRESHOLD &&
47250003Sadrian        b_inc_trig_level)
48250003Sadrian    {
49250003Sadrian        return AH_FALSE;
50250003Sadrian    }
51250003Sadrian
52250003Sadrian    /*
53250003Sadrian     * Disable interrupts while futzing with the fifo level.
54250003Sadrian     */
55250003Sadrian    omask = ar9300_set_interrupts(ah, ahp->ah_mask_reg &~ HAL_INT_GLOBAL, 0);
56250003Sadrian
57250003Sadrian    txcfg = OS_REG_READ(ah, AR_TXCFG);
58250003Sadrian    cur_level = MS(txcfg, AR_FTRIG);
59250003Sadrian    new_level = cur_level;
60250003Sadrian
61250003Sadrian    if (b_inc_trig_level)  {   /* increase the trigger level */
62250003Sadrian        if (cur_level < MAX_TX_FIFO_THRESHOLD) {
63250003Sadrian            new_level++;
64250003Sadrian        }
65250003Sadrian    } else if (cur_level > MIN_TX_FIFO_THRESHOLD) {
66250003Sadrian        new_level--;
67250003Sadrian    }
68250003Sadrian
69250003Sadrian    if (new_level != cur_level) {
70250003Sadrian        /* Update the trigger level */
71250003Sadrian        OS_REG_WRITE(ah,
72250003Sadrian            AR_TXCFG, (txcfg &~ AR_FTRIG) | SM(new_level, AR_FTRIG));
73250003Sadrian    }
74250003Sadrian
75250003Sadrian    /* re-enable chip interrupts */
76250003Sadrian    ar9300_set_interrupts(ah, omask, 0);
77250003Sadrian
78250008Sadrian    AH9300(ah)->ah_tx_trig_level = new_level;
79250003Sadrian
80250003Sadrian    return (new_level != cur_level);
81250003Sadrian}
82250003Sadrian
83250003Sadrian/*
84250003Sadrian * Returns the value of Tx Trigger Level
85250003Sadrian */
86250003Sadrianu_int16_t
87250003Sadrianar9300_get_tx_trig_level(struct ath_hal *ah)
88250003Sadrian{
89250008Sadrian    return (AH9300(ah)->ah_tx_trig_level);
90250003Sadrian}
91250003Sadrian
92250003Sadrian/*
93250003Sadrian * Set the properties of the tx queue with the parameters
94250003Sadrian * from q_info.
95250003Sadrian */
96250003SadrianHAL_BOOL
97250003Sadrianar9300_set_tx_queue_props(struct ath_hal *ah, int q, const HAL_TXQ_INFO *q_info)
98250003Sadrian{
99250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
100250003Sadrian    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
101250003Sadrian
102250008Sadrian    if (q >= p_cap->halTotalQueues) {
103250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);
104250003Sadrian        return AH_FALSE;
105250003Sadrian    }
106250008Sadrian    return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], q_info);
107250003Sadrian}
108250003Sadrian
109250003Sadrian/*
110250003Sadrian * Return the properties for the specified tx queue.
111250003Sadrian */
112250003SadrianHAL_BOOL
113250003Sadrianar9300_get_tx_queue_props(struct ath_hal *ah, int q, HAL_TXQ_INFO *q_info)
114250003Sadrian{
115250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
116250003Sadrian    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
117250003Sadrian
118250003Sadrian
119250008Sadrian    if (q >= p_cap->halTotalQueues) {
120250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);
121250003Sadrian        return AH_FALSE;
122250003Sadrian    }
123250008Sadrian    return ath_hal_getTxQProps(ah, q_info, &ahp->ah_txq[q]);
124250003Sadrian}
125250003Sadrian
126250003Sadrianenum {
127250003Sadrian    AH_TX_QUEUE_MINUS_OFFSET_BEACON = 1,
128250003Sadrian    AH_TX_QUEUE_MINUS_OFFSET_CAB    = 2,
129250003Sadrian    AH_TX_QUEUE_MINUS_OFFSET_UAPSD  = 3,
130250003Sadrian    AH_TX_QUEUE_MINUS_OFFSET_PAPRD  = 4,
131250003Sadrian};
132250003Sadrian
133250003Sadrian/*
134250003Sadrian * Allocate and initialize a tx DCU/QCU combination.
135250003Sadrian */
136250003Sadrianint
137250003Sadrianar9300_setup_tx_queue(struct ath_hal *ah, HAL_TX_QUEUE type,
138250003Sadrian        const HAL_TXQ_INFO *q_info)
139250003Sadrian{
140250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
141250003Sadrian    HAL_TX_QUEUE_INFO *qi;
142250003Sadrian    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
143250003Sadrian    int q;
144250003Sadrian
145250003Sadrian    /* XXX move queue assignment to driver */
146250003Sadrian    switch (type) {
147250003Sadrian    case HAL_TX_QUEUE_BEACON:
148250003Sadrian        /* highest priority */
149250008Sadrian        q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_BEACON;
150250003Sadrian        break;
151250003Sadrian    case HAL_TX_QUEUE_CAB:
152250003Sadrian        /* next highest priority */
153250008Sadrian        q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_CAB;
154250003Sadrian        break;
155250003Sadrian    case HAL_TX_QUEUE_UAPSD:
156250008Sadrian        q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_UAPSD;
157250003Sadrian        break;
158250003Sadrian    case HAL_TX_QUEUE_PAPRD:
159250008Sadrian        q = p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_PAPRD;
160250003Sadrian        break;
161250003Sadrian    case HAL_TX_QUEUE_DATA:
162250003Sadrian        /*
163250003Sadrian         * don't infringe on top 4 queues, reserved for:
164250003Sadrian         * beacon, CAB, UAPSD, PAPRD
165250003Sadrian         */
166250003Sadrian        for (q = 0;
167250008Sadrian             q < p_cap->halTotalQueues - AH_TX_QUEUE_MINUS_OFFSET_PAPRD;
168250003Sadrian             q++)
169250003Sadrian        {
170250003Sadrian            if (ahp->ah_txq[q].tqi_type == HAL_TX_QUEUE_INACTIVE) {
171250003Sadrian                break;
172250003Sadrian            }
173250003Sadrian        }
174250008Sadrian        if (q == p_cap->halTotalQueues - 3) {
175250003Sadrian            HALDEBUG(ah, HAL_DEBUG_QUEUE,
176250003Sadrian                "%s: no available tx queue\n", __func__);
177250003Sadrian            return -1;
178250003Sadrian        }
179250003Sadrian        break;
180250003Sadrian    default:
181250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
182250003Sadrian            "%s: bad tx queue type %u\n", __func__, type);
183250003Sadrian        return -1;
184250003Sadrian    }
185250003Sadrian
186250003Sadrian    HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: queue %u\n", __func__, q);
187250003Sadrian
188250003Sadrian    qi = &ahp->ah_txq[q];
189250003Sadrian    if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
190250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
191250003Sadrian            "%s: tx queue %u already active\n", __func__, q);
192250003Sadrian        return -1;
193250003Sadrian    }
194250003Sadrian
195250003Sadrian    OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
196250003Sadrian    qi->tqi_type = type;
197250003Sadrian
198250003Sadrian    if (q_info == AH_NULL) {
199250003Sadrian        /* by default enable OK+ERR+DESC+URN interrupts */
200250008Sadrian        qi->tqi_qflags = HAL_TXQ_TXOKINT_ENABLE
201250008Sadrian                        | HAL_TXQ_TXERRINT_ENABLE
202250008Sadrian                        | HAL_TXQ_TXDESCINT_ENABLE
203250008Sadrian                        | HAL_TXQ_TXURNINT_ENABLE;
204250003Sadrian        qi->tqi_aifs = INIT_AIFS;
205250003Sadrian        qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;     /* NB: do at reset */
206250003Sadrian        qi->tqi_cwmax = INIT_CWMAX;
207250003Sadrian        qi->tqi_shretry = INIT_SH_RETRY;
208250003Sadrian        qi->tqi_lgretry = INIT_LG_RETRY;
209250008Sadrian        qi->tqi_physCompBuf = 0;
210250003Sadrian    } else {
211250008Sadrian        qi->tqi_physCompBuf = q_info->tqi_compBuf;
212250003Sadrian        (void) ar9300_set_tx_queue_props(ah, q, q_info);
213250003Sadrian    }
214250003Sadrian    /* NB: must be followed by ar9300_reset_tx_queue */
215250003Sadrian    return q;
216250003Sadrian}
217250003Sadrian
218250003Sadrian/*
219250003Sadrian * Update the h/w interrupt registers to reflect a tx q's configuration.
220250003Sadrian */
221250003Sadrianstatic void
222250003Sadrianset_tx_q_interrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)
223250003Sadrian{
224250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
225250003Sadrian
226250003Sadrian    HALDEBUG(ah, HAL_DEBUG_INTERRUPT,
227250003Sadrian            "%s: tx ok 0x%x err 0x%x eol 0x%x urn 0x%x\n",
228250003Sadrian            __func__,
229250003Sadrian            ahp->ah_tx_ok_interrupt_mask,
230250003Sadrian            ahp->ah_tx_err_interrupt_mask,
231250003Sadrian            ahp->ah_tx_eol_interrupt_mask,
232250003Sadrian            ahp->ah_tx_urn_interrupt_mask);
233250003Sadrian
234250003Sadrian    OS_REG_WRITE(ah, AR_IMR_S0,
235250003Sadrian              SM(ahp->ah_tx_ok_interrupt_mask, AR_IMR_S0_QCU_TXOK));
236250003Sadrian    OS_REG_WRITE(ah, AR_IMR_S1,
237250003Sadrian              SM(ahp->ah_tx_err_interrupt_mask, AR_IMR_S1_QCU_TXERR)
238250003Sadrian            | SM(ahp->ah_tx_eol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
239250003Sadrian    OS_REG_RMW_FIELD(ah,
240250003Sadrian        AR_IMR_S2, AR_IMR_S2_QCU_TXURN, ahp->ah_tx_urn_interrupt_mask);
241250003Sadrian    ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2);
242250003Sadrian}
243250003Sadrian
244250003Sadrian/*
245250003Sadrian * Free a tx DCU/QCU combination.
246250003Sadrian */
247250003SadrianHAL_BOOL
248250003Sadrianar9300_release_tx_queue(struct ath_hal *ah, u_int q)
249250003Sadrian{
250250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
251250003Sadrian    HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps;
252250003Sadrian    HAL_TX_QUEUE_INFO *qi;
253250003Sadrian
254250008Sadrian    if (q >= p_cap->halTotalQueues) {
255250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);
256250003Sadrian        return AH_FALSE;
257250003Sadrian    }
258250003Sadrian
259250003Sadrian    qi = &ahp->ah_txq[q];
260250003Sadrian    if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
261250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: inactive queue %u\n", __func__, q);
262250003Sadrian        return AH_FALSE;
263250003Sadrian    }
264250003Sadrian
265250003Sadrian    HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: release queue %u\n", __func__, q);
266250003Sadrian
267250003Sadrian    qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
268250003Sadrian    ahp->ah_tx_ok_interrupt_mask &= ~(1 << q);
269250003Sadrian    ahp->ah_tx_err_interrupt_mask &= ~(1 << q);
270250003Sadrian    ahp->ah_tx_eol_interrupt_mask &= ~(1 << q);
271250003Sadrian    ahp->ah_tx_urn_interrupt_mask &= ~(1 << q);
272250003Sadrian    set_tx_q_interrupts(ah, qi);
273250003Sadrian
274250003Sadrian    return AH_TRUE;
275250003Sadrian}
276250003Sadrian
277250003Sadrian/*
278250003Sadrian * Set the retry, aifs, cwmin/max, ready_time regs for specified queue
279250003Sadrian * Assumes:
280250003Sadrian *  phw_channel has been set to point to the current channel
281250003Sadrian */
282250003SadrianHAL_BOOL
283250003Sadrianar9300_reset_tx_queue(struct ath_hal *ah, u_int q)
284250003Sadrian{
285250003Sadrian    struct ath_hal_9300     *ahp  = AH9300(ah);
286250008Sadrian//    struct ath_hal_private  *ap   = AH_PRIVATE(ah);
287250003Sadrian    HAL_CAPABILITIES        *p_cap = &AH_PRIVATE(ah)->ah_caps;
288250008Sadrian    const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
289250003Sadrian    HAL_TX_QUEUE_INFO       *qi;
290250003Sadrian    u_int32_t               cw_min, chan_cw_min, value;
291250003Sadrian
292250008Sadrian    if (q >= p_cap->halTotalQueues) {
293250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: invalid queue num %u\n", __func__, q);
294250003Sadrian        return AH_FALSE;
295250003Sadrian    }
296250003Sadrian
297250003Sadrian    qi = &ahp->ah_txq[q];
298250003Sadrian    if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
299250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: inactive queue %u\n", __func__, q);
300250003Sadrian        return AH_TRUE;         /* XXX??? */
301250003Sadrian    }
302250003Sadrian
303250003Sadrian    HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: reset queue %u\n", __func__, q);
304250003Sadrian
305250003Sadrian    if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) {
306250003Sadrian        /*
307250003Sadrian         * Select cwmin according to channel type.
308250003Sadrian         * NB: chan can be NULL during attach
309250003Sadrian         */
310250008Sadrian        if (chan && IEEE80211_IS_CHAN_B(chan)) {
311250003Sadrian            chan_cw_min = INIT_CWMIN_11B;
312250003Sadrian        } else {
313250003Sadrian            chan_cw_min = INIT_CWMIN;
314250003Sadrian        }
315250003Sadrian        /* make sure that the CWmin is of the form (2^n - 1) */
316250003Sadrian        for (cw_min = 1; cw_min < chan_cw_min; cw_min = (cw_min << 1) | 1) {}
317250003Sadrian    } else {
318250003Sadrian        cw_min = qi->tqi_cwmin;
319250003Sadrian    }
320250003Sadrian
321250003Sadrian    /* set cw_min/Max and AIFS values */
322250008Sadrian    if (q > 3 || (!AH9300(ah)->ah_fccaifs))
323250003Sadrian       /* values should not be overwritten if domain is FCC and manual rate
324250003Sadrian         less than 24Mb is set, this check  is making sure this */
325250003Sadrian    {
326250003Sadrian        OS_REG_WRITE(ah, AR_DLCL_IFS(q), SM(cw_min, AR_D_LCL_IFS_CWMIN)
327250003Sadrian                | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
328250003Sadrian                | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
329250003Sadrian    }
330250003Sadrian
331250003Sadrian    /* Set retry limit values */
332250003Sadrian    OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q),
333250003Sadrian        SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
334250003Sadrian        SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
335250003Sadrian        SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
336250003Sadrian
337250003Sadrian    /* enable early termination on the QCU */
338250003Sadrian    OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
339250003Sadrian
340250003Sadrian    /* enable DCU to wait for next fragment from QCU  */
341250003Sadrian    if (AR_SREV_WASP(ah) && (AH_PRIVATE((ah))->ah_macRev <= AR_SREV_REVISION_WASP_12)) {
342250003Sadrian        /* WAR for EV#85395: Wasp Rx overrun issue - reduces Tx queue backoff
343250003Sadrian         * threshold to 1 to avoid Rx overruns - Fixed in Wasp 1.3 */
344250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q),
345250003Sadrian            AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
346250003Sadrian    } else {
347250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q),
348250003Sadrian            AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
349250003Sadrian    }
350250003Sadrian
351250003Sadrian    /* multiqueue support */
352250008Sadrian    if (qi->tqi_cbrPeriod) {
353250003Sadrian        OS_REG_WRITE(ah,
354250003Sadrian            AR_QCBRCFG(q),
355250008Sadrian            SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
356250008Sadrian                SM(qi->tqi_cbrOverflowLimit,
357250003Sadrian            AR_Q_CBRCFG_OVF_THRESH));
358250003Sadrian        OS_REG_WRITE(ah, AR_QMISC(q),
359250003Sadrian            OS_REG_READ(ah, AR_QMISC(q)) |
360250003Sadrian            AR_Q_MISC_FSP_CBR |
361250008Sadrian            (qi->tqi_cbrOverflowLimit ?
362250003Sadrian                AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
363250003Sadrian    }
364250003Sadrian
365250008Sadrian    if (qi->tqi_readyTime && (qi->tqi_type != HAL_TX_QUEUE_CAB)) {
366250003Sadrian        OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
367250008Sadrian            SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
368250003Sadrian            AR_Q_RDYTIMECFG_EN);
369250003Sadrian    }
370250003Sadrian
371250008Sadrian    OS_REG_WRITE(ah, AR_DCHNTIME(q), SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
372250008Sadrian                (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
373250003Sadrian
374250008Sadrian    if (qi->tqi_burstTime &&
375250008Sadrian        (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE))
376250003Sadrian    {
377250003Sadrian        OS_REG_WRITE(ah, AR_QMISC(q), OS_REG_READ(ah, AR_QMISC(q)) |
378250003Sadrian                     AR_Q_MISC_RDYTIME_EXP_POLICY);
379250003Sadrian    }
380250003Sadrian
381250008Sadrian    if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) {
382250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q)) |
383250003Sadrian                    AR_D_MISC_POST_FR_BKOFF_DIS);
384250003Sadrian    }
385250003Sadrian
386250008Sadrian    if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) {
387250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q)) |
388250003Sadrian                    AR_D_MISC_FRAG_BKOFF_EN);
389250003Sadrian    }
390250003Sadrian
391250003Sadrian    switch (qi->tqi_type) {
392250003Sadrian    case HAL_TX_QUEUE_BEACON:               /* beacon frames */
393250003Sadrian        OS_REG_WRITE(ah, AR_QMISC(q),
394250003Sadrian                    OS_REG_READ(ah, AR_QMISC(q))
395250003Sadrian                    | AR_Q_MISC_FSP_DBA_GATED
396250003Sadrian                    | AR_Q_MISC_BEACON_USE
397250003Sadrian                    | AR_Q_MISC_CBR_INCR_DIS1);
398250003Sadrian
399250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q),
400250003Sadrian                    OS_REG_READ(ah, AR_DMISC(q))
401250003Sadrian                    | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
402250003Sadrian                    AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
403250003Sadrian                    | AR_D_MISC_BEACON_USE
404250003Sadrian                    | AR_D_MISC_POST_FR_BKOFF_DIS);
405250003Sadrian        /* XXX cwmin and cwmax should be 0 for beacon queue */
406250003Sadrian        if (AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS) {
407250003Sadrian            OS_REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
408250003Sadrian                        | SM(0, AR_D_LCL_IFS_CWMAX)
409250003Sadrian                        | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
410250003Sadrian        }
411250003Sadrian        break;
412250003Sadrian    case HAL_TX_QUEUE_CAB:                  /* CAB  frames */
413250003Sadrian        /*
414250003Sadrian         * No longer Enable AR_Q_MISC_RDYTIME_EXP_POLICY,
415250003Sadrian         * bug #6079.  There is an issue with the CAB Queue
416250003Sadrian         * not properly refreshing the Tx descriptor if
417250003Sadrian         * the TXE clear setting is used.
418250003Sadrian         */
419250003Sadrian        OS_REG_WRITE(ah, AR_QMISC(q),
420250003Sadrian                        OS_REG_READ(ah, AR_QMISC(q))
421250003Sadrian                        | AR_Q_MISC_FSP_DBA_GATED
422250003Sadrian                        | AR_Q_MISC_CBR_INCR_DIS1
423250003Sadrian                        | AR_Q_MISC_CBR_INCR_DIS0);
424250003Sadrian
425250008Sadrian        value = TU_TO_USEC(qi->tqi_readyTime)
426250008Sadrian                - (ah->ah_config.ah_sw_beacon_response_time
427250008Sadrian                -  ah->ah_config.ah_dma_beacon_response_time)
428250008Sadrian                - ah->ah_config.ah_additional_swba_backoff;
429250003Sadrian        OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN);
430250003Sadrian
431250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q))
432250003Sadrian                    | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
433250003Sadrian                                AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
434250003Sadrian        break;
435250003Sadrian    case HAL_TX_QUEUE_PSPOLL:
436250003Sadrian        /*
437250003Sadrian         * We may configure ps_poll QCU to be TIM-gated in the
438250003Sadrian         * future; TIM_GATED bit is not enabled currently because
439250003Sadrian         * of a hardware problem in Oahu that overshoots the TIM
440250003Sadrian         * bitmap in beacon and may find matching associd bit in
441250003Sadrian         * non-TIM elements and send PS-poll PS poll processing
442250003Sadrian         * will be done in software
443250003Sadrian         */
444250003Sadrian        OS_REG_WRITE(ah, AR_QMISC(q),
445250003Sadrian                        OS_REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
446250003Sadrian        break;
447250003Sadrian    case HAL_TX_QUEUE_UAPSD:
448250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q))
449250003Sadrian                    | AR_D_MISC_POST_FR_BKOFF_DIS);
450250003Sadrian        break;
451250003Sadrian    default:                        /* NB: silence compiler */
452250003Sadrian        break;
453250003Sadrian    }
454250003Sadrian
455250003Sadrian#ifndef AH_DISABLE_WME
456250003Sadrian    /*
457250003Sadrian     * Yes, this is a hack and not the right way to do it, but
458250003Sadrian     * it does get the lockout bits and backoff set for the
459250003Sadrian     * high-pri WME queues for testing.  We need to either extend
460250003Sadrian     * the meaning of queue_info->mode, or create something like
461250003Sadrian     * queue_info->dcumode.
462250003Sadrian     */
463250008Sadrian    if (qi->tqi_intFlags & HAL_TXQ_USE_LOCKOUT_BKOFF_DIS) {
464250003Sadrian        OS_REG_WRITE(ah, AR_DMISC(q),
465250003Sadrian            OS_REG_READ(ah, AR_DMISC(q)) |
466250003Sadrian                SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
467250003Sadrian                    AR_D_MISC_ARB_LOCKOUT_CNTRL) |
468250003Sadrian                AR_D_MISC_POST_FR_BKOFF_DIS);
469250003Sadrian    }
470250003Sadrian#endif
471250003Sadrian
472250003Sadrian    OS_REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
473250003Sadrian
474250003Sadrian    /*
475250003Sadrian     * Always update the secondary interrupt mask registers - this
476250003Sadrian     * could be a new queue getting enabled in a running system or
477250003Sadrian     * hw getting re-initialized during a reset!
478250003Sadrian     *
479250003Sadrian     * Since we don't differentiate between tx interrupts corresponding
480250003Sadrian     * to individual queues - secondary tx mask regs are always unmasked;
481250003Sadrian     * tx interrupts are enabled/disabled for all queues collectively
482250003Sadrian     * using the primary mask reg
483250003Sadrian     */
484250008Sadrian    if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) {
485250003Sadrian        ahp->ah_tx_ok_interrupt_mask |=  (1 << q);
486250003Sadrian    } else {
487250003Sadrian        ahp->ah_tx_ok_interrupt_mask &= ~(1 << q);
488250003Sadrian    }
489250008Sadrian    if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) {
490250003Sadrian        ahp->ah_tx_err_interrupt_mask |=  (1 << q);
491250003Sadrian    } else {
492250003Sadrian        ahp->ah_tx_err_interrupt_mask &= ~(1 << q);
493250003Sadrian    }
494250008Sadrian    if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) {
495250003Sadrian        ahp->ah_tx_eol_interrupt_mask |=  (1 << q);
496250003Sadrian    } else {
497250003Sadrian        ahp->ah_tx_eol_interrupt_mask &= ~(1 << q);
498250003Sadrian    }
499250008Sadrian    if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) {
500250003Sadrian        ahp->ah_tx_urn_interrupt_mask |=  (1 << q);
501250003Sadrian    } else {
502250003Sadrian        ahp->ah_tx_urn_interrupt_mask &= ~(1 << q);
503250003Sadrian    }
504250003Sadrian    set_tx_q_interrupts(ah, qi);
505250003Sadrian
506250003Sadrian    return AH_TRUE;
507250003Sadrian}
508250003Sadrian
509250003Sadrian/*
510250003Sadrian * Get the TXDP for the specified queue
511250003Sadrian */
512250003Sadrianu_int32_t
513250003Sadrianar9300_get_tx_dp(struct ath_hal *ah, u_int q)
514250003Sadrian{
515250008Sadrian    HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);
516250003Sadrian    return OS_REG_READ(ah, AR_QTXDP(q));
517250003Sadrian}
518250003Sadrian
519250003Sadrian/*
520250003Sadrian * Set the tx_dp for the specified queue
521250003Sadrian */
522250003SadrianHAL_BOOL
523250003Sadrianar9300_set_tx_dp(struct ath_hal *ah, u_int q, u_int32_t txdp)
524250003Sadrian{
525250008Sadrian    HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);
526250003Sadrian    HALASSERT(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
527250003Sadrian    HALASSERT(txdp != 0);
528250003Sadrian
529250003Sadrian    OS_REG_WRITE(ah, AR_QTXDP(q), txdp);
530250003Sadrian
531250003Sadrian    return AH_TRUE;
532250003Sadrian}
533250003Sadrian
534250003Sadrian/*
535250003Sadrian * Transmit Enable is read-only now
536250003Sadrian */
537250003SadrianHAL_BOOL
538250003Sadrianar9300_start_tx_dma(struct ath_hal *ah, u_int q)
539250003Sadrian{
540250003Sadrian    return AH_TRUE;
541250003Sadrian}
542250003Sadrian
543250003Sadrian/*
544250003Sadrian * Return the number of pending frames or 0 if the specified
545250003Sadrian * queue is stopped.
546250003Sadrian */
547250003Sadrianu_int32_t
548250003Sadrianar9300_num_tx_pending(struct ath_hal *ah, u_int q)
549250003Sadrian{
550250003Sadrian    u_int32_t npend;
551250003Sadrian
552250008Sadrian    HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues);
553250003Sadrian
554250003Sadrian    npend = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
555250003Sadrian    if (npend == 0) {
556250003Sadrian        /*
557250003Sadrian         * Pending frame count (PFC) can momentarily go to zero
558250003Sadrian         * while TXE remains asserted.  In other words a PFC of
559250003Sadrian         * zero is not sufficient to say that the queue has stopped.
560250003Sadrian         */
561250003Sadrian        if (OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) {
562250003Sadrian            npend = 1;              /* arbitrarily return 1 */
563250003Sadrian        }
564250003Sadrian    }
565250003Sadrian#ifdef DEBUG
566250003Sadrian    if (npend && (AH9300(ah)->ah_txq[q].tqi_type == HAL_TX_QUEUE_CAB)) {
567250003Sadrian        if (OS_REG_READ(ah, AR_Q_RDYTIMESHDN) & (1 << q)) {
568250003Sadrian            HALDEBUG(ah, HAL_DEBUG_QUEUE, "RTSD on CAB queue\n");
569250003Sadrian            /* Clear the ready_time shutdown status bits */
570250003Sadrian            OS_REG_WRITE(ah, AR_Q_RDYTIMESHDN, 1 << q);
571250003Sadrian        }
572250003Sadrian    }
573250003Sadrian#endif
574250003Sadrian    HALASSERT((npend == 0) ||
575250003Sadrian        (AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE));
576250003Sadrian
577250003Sadrian    return npend;
578250003Sadrian}
579250003Sadrian
580250003Sadrian/*
581250003Sadrian * Stop transmit on the specified queue
582250003Sadrian */
583250003SadrianHAL_BOOL
584250003Sadrianar9300_stop_tx_dma(struct ath_hal *ah, u_int q, u_int timeout)
585250003Sadrian{
586250003Sadrian    /*
587250003Sadrian     * Directly call abort.  It is better, hardware-wise, to stop all
588250003Sadrian     * queues at once than individual ones.
589250003Sadrian     */
590250003Sadrian    return ar9300_abort_tx_dma(ah);
591250003Sadrian
592250003Sadrian#if 0
593250003Sadrian#define AH_TX_STOP_DMA_TIMEOUT 4000    /* usec */
594250003Sadrian#define AH_TIME_QUANTUM        100     /* usec */
595250003Sadrian    u_int wait;
596250003Sadrian
597250003Sadrian    HALASSERT(q < AH_PRIVATE(ah)->ah_caps.hal_total_queues);
598250003Sadrian
599250003Sadrian    HALASSERT(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
600250003Sadrian
601250003Sadrian    if (timeout == 0) {
602250003Sadrian        timeout = AH_TX_STOP_DMA_TIMEOUT;
603250003Sadrian    }
604250003Sadrian
605250003Sadrian    OS_REG_WRITE(ah, AR_Q_TXD, 1 << q);
606250003Sadrian
607250003Sadrian    for (wait = timeout / AH_TIME_QUANTUM; wait != 0; wait--) {
608250003Sadrian        if (ar9300_num_tx_pending(ah, q) == 0) {
609250003Sadrian            break;
610250003Sadrian        }
611250003Sadrian        OS_DELAY(AH_TIME_QUANTUM);        /* XXX get actual value */
612250003Sadrian    }
613250003Sadrian
614250003Sadrian#ifdef AH_DEBUG
615250003Sadrian    if (wait == 0) {
616250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
617250003Sadrian            "%s: queue %u DMA did not stop in 100 msec\n", __func__, q);
618250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
619250003Sadrian            "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n",
620250003Sadrian            __func__,
621250003Sadrian            OS_REG_READ(ah, AR_QSTS(q)),
622250003Sadrian            OS_REG_READ(ah, AR_Q_TXE),
623250003Sadrian            OS_REG_READ(ah, AR_Q_TXD),
624250003Sadrian            OS_REG_READ(ah, AR_QCBRCFG(q)));
625250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
626250003Sadrian            "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n",
627250003Sadrian            __func__,
628250003Sadrian            OS_REG_READ(ah, AR_QMISC(q)),
629250003Sadrian            OS_REG_READ(ah, AR_QRDYTIMECFG(q)),
630250003Sadrian            OS_REG_READ(ah, AR_Q_RDYTIMESHDN));
631250003Sadrian    }
632250003Sadrian#endif /* AH_DEBUG */
633250003Sadrian
634250003Sadrian    /* 2413+ and up can kill packets at the PCU level */
635250003Sadrian    if (ar9300_num_tx_pending(ah, q)) {
636250003Sadrian        u_int32_t tsf_low, j;
637250003Sadrian
638250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: Num of pending TX Frames %d on Q %d\n",
639250003Sadrian                 __func__, ar9300_num_tx_pending(ah, q), q);
640250003Sadrian
641250003Sadrian        /* Kill last PCU Tx Frame */
642250003Sadrian        /* TODO - save off and restore current values of Q1/Q2? */
643250003Sadrian        for (j = 0; j < 2; j++) {
644250003Sadrian            tsf_low = OS_REG_READ(ah, AR_TSF_L32);
645250003Sadrian            OS_REG_WRITE(ah, AR_QUIET2, SM(10, AR_QUIET2_QUIET_DUR));
646250003Sadrian            OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100);
647250003Sadrian            OS_REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsf_low >> 10);
648250003Sadrian            OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
649250003Sadrian
650250003Sadrian            if ((OS_REG_READ(ah, AR_TSF_L32) >> 10) == (tsf_low >> 10)) {
651250003Sadrian                break;
652250003Sadrian            }
653250003Sadrian
654250003Sadrian            HALDEBUG(ah, HAL_DEBUG_QUEUE,
655250003Sadrian                "%s: TSF have moved while trying to set "
656250003Sadrian                "quiet time TSF: 0x%08x\n",
657250003Sadrian                __func__, tsf_low);
658250003Sadrian            /* TSF shouldn't count twice or reg access is taking forever */
659250003Sadrian            HALASSERT(j < 1);
660250003Sadrian        }
661250003Sadrian
662250003Sadrian        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
663250003Sadrian
664250003Sadrian        /* Allow the quiet mechanism to do its work */
665250003Sadrian        OS_DELAY(200);
666250003Sadrian        OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
667250003Sadrian
668250003Sadrian        /* Verify all transmit is dead */
669250003Sadrian        wait = timeout / AH_TIME_QUANTUM;
670250003Sadrian        while (ar9300_num_tx_pending(ah, q)) {
671250003Sadrian            if ((--wait) == 0) {
672250003Sadrian                HALDEBUG(ah, HAL_DEBUG_TX,
673250003Sadrian                    "%s: Failed to stop Tx DMA in %d msec "
674250003Sadrian                    "after killing last frame\n",
675250003Sadrian                    __func__, timeout / 1000);
676250003Sadrian                break;
677250003Sadrian            }
678250003Sadrian            OS_DELAY(AH_TIME_QUANTUM);
679250003Sadrian        }
680250003Sadrian
681250003Sadrian        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
682250003Sadrian    }
683250003Sadrian
684250003Sadrian    OS_REG_WRITE(ah, AR_Q_TXD, 0);
685250003Sadrian    return (wait != 0);
686250003Sadrian
687250003Sadrian#undef AH_TX_STOP_DMA_TIMEOUT
688250003Sadrian#undef AH_TIME_QUANTUM
689250003Sadrian#endif
690250003Sadrian}
691250003Sadrian
692250003Sadrian/*
693250003Sadrian * Really Stop transmit on the specified queue
694250003Sadrian */
695250003SadrianHAL_BOOL
696250003Sadrianar9300_stop_tx_dma_indv_que(struct ath_hal *ah, u_int q, u_int timeout)
697250003Sadrian{
698250003Sadrian#define AH_TX_STOP_DMA_TIMEOUT 4000    /* usec */
699250003Sadrian#define AH_TIME_QUANTUM        100     /* usec */
700250003Sadrian    u_int wait;
701250003Sadrian
702250003Sadrian    HALASSERT(q < AH_PRIVATE(ah)->ah_caps.hal_total_queues);
703250003Sadrian
704250003Sadrian    HALASSERT(AH9300(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
705250003Sadrian
706250003Sadrian    if (timeout == 0) {
707250003Sadrian        timeout = AH_TX_STOP_DMA_TIMEOUT;
708250003Sadrian    }
709250003Sadrian
710250003Sadrian    OS_REG_WRITE(ah, AR_Q_TXD, 1 << q);
711250003Sadrian
712250003Sadrian    for (wait = timeout / AH_TIME_QUANTUM; wait != 0; wait--) {
713250003Sadrian        if (ar9300_num_tx_pending(ah, q) == 0) {
714250003Sadrian            break;
715250003Sadrian        }
716250003Sadrian        OS_DELAY(AH_TIME_QUANTUM);        /* XXX get actual value */
717250003Sadrian    }
718250003Sadrian
719250003Sadrian#ifdef AH_DEBUG
720250003Sadrian    if (wait == 0) {
721250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
722250003Sadrian            "%s: queue %u DMA did not stop in 100 msec\n", __func__, q);
723250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
724250003Sadrian            "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n",
725250003Sadrian            __func__,
726250003Sadrian            OS_REG_READ(ah, AR_QSTS(q)),
727250003Sadrian            OS_REG_READ(ah, AR_Q_TXE),
728250003Sadrian            OS_REG_READ(ah, AR_Q_TXD),
729250003Sadrian            OS_REG_READ(ah, AR_QCBRCFG(q)));
730250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE,
731250003Sadrian            "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n",
732250003Sadrian            __func__,
733250003Sadrian            OS_REG_READ(ah, AR_QMISC(q)),
734250003Sadrian            OS_REG_READ(ah, AR_QRDYTIMECFG(q)),
735250003Sadrian            OS_REG_READ(ah, AR_Q_RDYTIMESHDN));
736250003Sadrian    }
737250003Sadrian#endif /* AH_DEBUG */
738250003Sadrian
739250003Sadrian    /* 2413+ and up can kill packets at the PCU level */
740250003Sadrian    if (ar9300_num_tx_pending(ah, q)) {
741250003Sadrian        u_int32_t tsf_low, j;
742250003Sadrian
743250003Sadrian        HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: Num of pending TX Frames %d on Q %d\n",
744250003Sadrian                 __func__, ar9300_num_tx_pending(ah, q), q);
745250003Sadrian
746250003Sadrian        /* Kill last PCU Tx Frame */
747250003Sadrian        /* TODO - save off and restore current values of Q1/Q2? */
748250003Sadrian        for (j = 0; j < 2; j++) {
749250003Sadrian            tsf_low = OS_REG_READ(ah, AR_TSF_L32);
750250003Sadrian            OS_REG_WRITE(ah, AR_QUIET2, SM(10, AR_QUIET2_QUIET_DUR));
751250003Sadrian            OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100);
752250003Sadrian            OS_REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsf_low >> 10);
753250003Sadrian            OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
754250003Sadrian
755250003Sadrian            if ((OS_REG_READ(ah, AR_TSF_L32) >> 10) == (tsf_low >> 10)) {
756250003Sadrian                break;
757250003Sadrian            }
758250003Sadrian
759250003Sadrian            HALDEBUG(ah, HAL_DEBUG_QUEUE,
760250003Sadrian                "%s: TSF have moved while trying to set "
761250003Sadrian                "quiet time TSF: 0x%08x\n",
762250003Sadrian                __func__, tsf_low);
763250003Sadrian            /* TSF shouldn't count twice or reg access is taking forever */
764250003Sadrian            HALASSERT(j < 1);
765250003Sadrian        }
766250003Sadrian
767250003Sadrian        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
768250003Sadrian
769250003Sadrian        /* Allow the quiet mechanism to do its work */
770250003Sadrian        OS_DELAY(200);
771250003Sadrian        OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
772250003Sadrian
773250003Sadrian        /* Verify all transmit is dead */
774250003Sadrian        wait = timeout / AH_TIME_QUANTUM;
775250003Sadrian        while (ar9300_num_tx_pending(ah, q)) {
776250003Sadrian            if ((--wait) == 0) {
777250003Sadrian                HALDEBUG(ah, HAL_DEBUG_TX,
778250003Sadrian                    "%s: Failed to stop Tx DMA in %d msec "
779250003Sadrian                    "after killing last frame\n",
780250003Sadrian                    __func__, timeout / 1000);
781250003Sadrian                break;
782250003Sadrian            }
783250003Sadrian            OS_DELAY(AH_TIME_QUANTUM);
784250003Sadrian        }
785250003Sadrian
786250003Sadrian        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
787250003Sadrian    }
788250003Sadrian
789250003Sadrian    OS_REG_WRITE(ah, AR_Q_TXD, 0);
790250003Sadrian    return (wait != 0);
791250003Sadrian
792250003Sadrian#undef AH_TX_STOP_DMA_TIMEOUT
793250003Sadrian#undef AH_TIME_QUANTUM
794250003Sadrian}
795250003Sadrian
796250003Sadrian/*
797250003Sadrian * Abort transmit on all queues
798250003Sadrian */
799250003Sadrian#define AR9300_ABORT_LOOPS     1000
800250003Sadrian#define AR9300_ABORT_WAIT      5
801250003SadrianHAL_BOOL
802250003Sadrianar9300_abort_tx_dma(struct ath_hal *ah)
803250003Sadrian{
804250003Sadrian    int i, q;
805250003Sadrian
806250003Sadrian    /*
807250003Sadrian     * set txd on all queues
808250003Sadrian     */
809250003Sadrian    OS_REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
810250003Sadrian
811250003Sadrian    /*
812250003Sadrian     * set tx abort bits (also disable rx)
813250003Sadrian     */
814250003Sadrian    OS_REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
815250003Sadrian    OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS |
816250003Sadrian                   AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR));
817250003Sadrian    OS_REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
818250003Sadrian
819250003Sadrian    /* Let TXE (all queues) clear before waiting on any pending frames */
820250003Sadrian    for (i = 0; i < AR9300_ABORT_LOOPS; i++) {
821250003Sadrian        if (OS_REG_READ(ah, AR_Q_TXE) == 0) {
822250003Sadrian            break;
823250003Sadrian        }
824250003Sadrian        OS_DELAY(AR9300_ABORT_WAIT);
825250003Sadrian    }
826250003Sadrian    if (i == AR9300_ABORT_LOOPS) {
827250003Sadrian        HALDEBUG(ah, HAL_DEBUG_TX, "%s[%d] reached max wait on TXE\n",
828250003Sadrian                 __func__, __LINE__);
829250003Sadrian    }
830250003Sadrian
831250003Sadrian    /*
832250003Sadrian     * wait on all tx queues
833250003Sadrian     */
834250003Sadrian    for (q = 0; q < AR_NUM_QCU; q++) {
835250003Sadrian        for (i = 0; i < AR9300_ABORT_LOOPS; i++) {
836250003Sadrian            if (!ar9300_num_tx_pending(ah, q)) {
837250003Sadrian                break;
838250003Sadrian            }
839250003Sadrian            OS_DELAY(AR9300_ABORT_WAIT);
840250003Sadrian        }
841250003Sadrian        if (i == AR9300_ABORT_LOOPS) {
842250003Sadrian            HALDEBUG(ah, HAL_DEBUG_TX,
843250003Sadrian                     "%s[%d] reached max wait on pending tx, q %d\n",
844250003Sadrian                     __func__, __LINE__, q);
845250003Sadrian            return AH_FALSE;
846250003Sadrian        }
847250003Sadrian    }
848250003Sadrian
849250003Sadrian    /*
850250003Sadrian     * clear tx abort bits
851250003Sadrian     */
852250003Sadrian    OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
853250003Sadrian    OS_REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_FORCE_CH_IDLE_HIGH | AR_DIAG_RX_DIS |
854250003Sadrian                   AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR));
855250003Sadrian    OS_REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
856250003Sadrian
857250003Sadrian    /*
858250003Sadrian     * clear txd
859250003Sadrian     */
860250003Sadrian    OS_REG_WRITE(ah, AR_Q_TXD, 0);
861250003Sadrian
862250003Sadrian    return AH_TRUE;
863250003Sadrian}
864250003Sadrian
865250003Sadrian/*
866250003Sadrian * Determine which tx queues need interrupt servicing.
867250003Sadrian */
868250003Sadrianvoid
869250003Sadrianar9300_get_tx_intr_queue(struct ath_hal *ah, u_int32_t *txqs)
870250003Sadrian{
871250003Sadrian    HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
872250003Sadrian                 "ar9300_get_tx_intr_queue: Should not be called\n");
873250003Sadrian#if 0
874250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
875250003Sadrian    *txqs &= ahp->ah_intr_txqs;
876250003Sadrian    ahp->ah_intr_txqs &= ~(*txqs);
877250003Sadrian#endif
878250003Sadrian}
879250003Sadrian
880250003Sadrianvoid
881250003Sadrianar9300_reset_tx_status_ring(struct ath_hal *ah)
882250003Sadrian{
883250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
884250003Sadrian
885250003Sadrian    ahp->ts_tail = 0;
886250003Sadrian
887250003Sadrian    /* Zero out the status descriptors */
888250003Sadrian    OS_MEMZERO((void *)ahp->ts_ring, ahp->ts_size * sizeof(struct ar9300_txs));
889250003Sadrian    HALDEBUG(ah, HAL_DEBUG_QUEUE,
890250003Sadrian        "%s: TS Start 0x%x End 0x%x Virt %p, Size %d\n", __func__,
891250003Sadrian        ahp->ts_paddr_start, ahp->ts_paddr_end, ahp->ts_ring, ahp->ts_size);
892250003Sadrian
893250003Sadrian    OS_REG_WRITE(ah, AR_Q_STATUS_RING_START, ahp->ts_paddr_start);
894250003Sadrian    OS_REG_WRITE(ah, AR_Q_STATUS_RING_END, ahp->ts_paddr_end);
895250003Sadrian}
896250003Sadrian
897250003Sadrianvoid
898250003Sadrianar9300_setup_tx_status_ring(struct ath_hal *ah, void *ts_start,
899250003Sadrian    u_int32_t ts_paddr_start, u_int16_t size)
900250003Sadrian{
901250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
902250003Sadrian
903250003Sadrian    ahp->ts_paddr_start = ts_paddr_start;
904250003Sadrian    ahp->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9300_txs));
905250003Sadrian    ahp->ts_size = size;
906250003Sadrian    ahp->ts_ring = (struct ar9300_txs *)ts_start;
907250003Sadrian
908250003Sadrian    ar9300_reset_tx_status_ring(ah);
909250003Sadrian}
910