16e778a7eSPedro F. Giffuni /*-
26e778a7eSPedro F. Giffuni * SPDX-License-Identifier: ISC
36e778a7eSPedro F. Giffuni *
414779705SSam Leffler * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
514779705SSam Leffler * Copyright (c) 2002-2006 Atheros Communications, Inc.
614779705SSam Leffler *
714779705SSam Leffler * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler *
1114779705SSam Leffler * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler #include "ah_desc.h"
2414779705SSam Leffler
2514779705SSam Leffler #include "ar5211/ar5211.h"
2614779705SSam Leffler #include "ar5211/ar5211reg.h"
2714779705SSam Leffler #include "ar5211/ar5211desc.h"
2814779705SSam Leffler
2914779705SSam Leffler /*
3014779705SSam Leffler * Get the RXDP.
3114779705SSam Leffler */
3214779705SSam Leffler uint32_t
ar5211GetRxDP(struct ath_hal * ah,HAL_RX_QUEUE qtype)33d60a0680SAdrian Chadd ar5211GetRxDP(struct ath_hal *ah, HAL_RX_QUEUE qtype)
3414779705SSam Leffler {
35d60a0680SAdrian Chadd
36d60a0680SAdrian Chadd HALASSERT(qtype == HAL_RX_QUEUE_HP);
3714779705SSam Leffler return OS_REG_READ(ah, AR_RXDP);
3814779705SSam Leffler }
3914779705SSam Leffler
4014779705SSam Leffler /*
4114779705SSam Leffler * Set the RxDP.
4214779705SSam Leffler */
4314779705SSam Leffler void
ar5211SetRxDP(struct ath_hal * ah,uint32_t rxdp,HAL_RX_QUEUE qtype)44d60a0680SAdrian Chadd ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
4514779705SSam Leffler {
46d60a0680SAdrian Chadd
47d60a0680SAdrian Chadd HALASSERT(qtype == HAL_RX_QUEUE_HP);
4814779705SSam Leffler OS_REG_WRITE(ah, AR_RXDP, rxdp);
4914779705SSam Leffler HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
5014779705SSam Leffler }
5114779705SSam Leffler
5214779705SSam Leffler /*
5314779705SSam Leffler * Set Receive Enable bits.
5414779705SSam Leffler */
5514779705SSam Leffler void
ar5211EnableReceive(struct ath_hal * ah)5614779705SSam Leffler ar5211EnableReceive(struct ath_hal *ah)
5714779705SSam Leffler {
5814779705SSam Leffler OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
5914779705SSam Leffler }
6014779705SSam Leffler
6114779705SSam Leffler /*
6214779705SSam Leffler * Stop Receive at the DMA engine
6314779705SSam Leffler */
6414779705SSam Leffler HAL_BOOL
ar5211StopDmaReceive(struct ath_hal * ah)6514779705SSam Leffler ar5211StopDmaReceive(struct ath_hal *ah)
6614779705SSam Leffler {
6714779705SSam Leffler OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */
6814779705SSam Leffler if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
6914779705SSam Leffler #ifdef AH_DEBUG
7014779705SSam Leffler ath_hal_printf(ah, "%s failed to stop in 10ms\n"
7114779705SSam Leffler "AR_CR=0x%08X\nAR_DIAG_SW=0x%08X\n"
7214779705SSam Leffler , __func__
7314779705SSam Leffler , OS_REG_READ(ah, AR_CR)
7414779705SSam Leffler , OS_REG_READ(ah, AR_DIAG_SW)
7514779705SSam Leffler );
7614779705SSam Leffler #endif
7714779705SSam Leffler return AH_FALSE;
7814779705SSam Leffler } else {
7914779705SSam Leffler return AH_TRUE;
8014779705SSam Leffler }
8114779705SSam Leffler }
8214779705SSam Leffler
8314779705SSam Leffler /*
8414779705SSam Leffler * Start Transmit at the PCU engine (unpause receive)
8514779705SSam Leffler */
8614779705SSam Leffler void
ar5211StartPcuReceive(struct ath_hal * ah,HAL_BOOL is_scanning)87*a8083b9cSAdrian Chadd ar5211StartPcuReceive(struct ath_hal *ah, HAL_BOOL is_scanning)
8814779705SSam Leffler {
8914779705SSam Leffler OS_REG_WRITE(ah, AR_DIAG_SW,
9014779705SSam Leffler OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX));
9114779705SSam Leffler }
9214779705SSam Leffler
9314779705SSam Leffler /*
9414779705SSam Leffler * Stop Transmit at the PCU engine (pause receive)
9514779705SSam Leffler */
9614779705SSam Leffler void
ar5211StopPcuReceive(struct ath_hal * ah)9714779705SSam Leffler ar5211StopPcuReceive(struct ath_hal *ah)
9814779705SSam Leffler {
9914779705SSam Leffler OS_REG_WRITE(ah, AR_DIAG_SW,
10014779705SSam Leffler OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX);
10114779705SSam Leffler }
10214779705SSam Leffler
10314779705SSam Leffler /*
10414779705SSam Leffler * Set multicast filter 0 (lower 32-bits)
10514779705SSam Leffler * filter 1 (upper 32-bits)
10614779705SSam Leffler */
10714779705SSam Leffler void
ar5211SetMulticastFilter(struct ath_hal * ah,uint32_t filter0,uint32_t filter1)10814779705SSam Leffler ar5211SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
10914779705SSam Leffler {
11014779705SSam Leffler OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
11114779705SSam Leffler OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
11214779705SSam Leffler }
11314779705SSam Leffler
11414779705SSam Leffler /*
11514779705SSam Leffler * Clear multicast filter by index
11614779705SSam Leffler */
11714779705SSam Leffler HAL_BOOL
ar5211ClrMulticastFilterIndex(struct ath_hal * ah,uint32_t ix)11814779705SSam Leffler ar5211ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
11914779705SSam Leffler {
12014779705SSam Leffler uint32_t val;
12114779705SSam Leffler
12214779705SSam Leffler if (ix >= 64)
12314779705SSam Leffler return AH_FALSE;
12414779705SSam Leffler if (ix >= 32) {
12514779705SSam Leffler val = OS_REG_READ(ah, AR_MCAST_FIL1);
12614779705SSam Leffler OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
12714779705SSam Leffler } else {
12814779705SSam Leffler val = OS_REG_READ(ah, AR_MCAST_FIL0);
12914779705SSam Leffler OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
13014779705SSam Leffler }
13114779705SSam Leffler return AH_TRUE;
13214779705SSam Leffler }
13314779705SSam Leffler
13414779705SSam Leffler /*
13514779705SSam Leffler * Set multicast filter by index
13614779705SSam Leffler */
13714779705SSam Leffler HAL_BOOL
ar5211SetMulticastFilterIndex(struct ath_hal * ah,uint32_t ix)13814779705SSam Leffler ar5211SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
13914779705SSam Leffler {
14014779705SSam Leffler uint32_t val;
14114779705SSam Leffler
14214779705SSam Leffler if (ix >= 64)
14314779705SSam Leffler return AH_FALSE;
14414779705SSam Leffler if (ix >= 32) {
14514779705SSam Leffler val = OS_REG_READ(ah, AR_MCAST_FIL1);
14614779705SSam Leffler OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
14714779705SSam Leffler } else {
14814779705SSam Leffler val = OS_REG_READ(ah, AR_MCAST_FIL0);
14914779705SSam Leffler OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
15014779705SSam Leffler }
15114779705SSam Leffler return AH_TRUE;
15214779705SSam Leffler }
15314779705SSam Leffler
15414779705SSam Leffler /*
15514779705SSam Leffler * Get receive filter.
15614779705SSam Leffler */
15714779705SSam Leffler uint32_t
ar5211GetRxFilter(struct ath_hal * ah)15814779705SSam Leffler ar5211GetRxFilter(struct ath_hal *ah)
15914779705SSam Leffler {
16014779705SSam Leffler return OS_REG_READ(ah, AR_RX_FILTER);
16114779705SSam Leffler }
16214779705SSam Leffler
16314779705SSam Leffler /*
16414779705SSam Leffler * Set receive filter.
16514779705SSam Leffler */
16614779705SSam Leffler void
ar5211SetRxFilter(struct ath_hal * ah,uint32_t bits)16714779705SSam Leffler ar5211SetRxFilter(struct ath_hal *ah, uint32_t bits)
16814779705SSam Leffler {
16914779705SSam Leffler OS_REG_WRITE(ah, AR_RX_FILTER, bits);
17014779705SSam Leffler }
17114779705SSam Leffler
17214779705SSam Leffler /*
17314779705SSam Leffler * Initialize RX descriptor, by clearing the status and clearing
17414779705SSam Leffler * the size. This is not strictly HW dependent, but we want the
17514779705SSam Leffler * control and status words to be opaque above the hal.
17614779705SSam Leffler */
17714779705SSam Leffler HAL_BOOL
ar5211SetupRxDesc(struct ath_hal * ah,struct ath_desc * ds,uint32_t size,u_int flags)17814779705SSam Leffler ar5211SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
17914779705SSam Leffler uint32_t size, u_int flags)
18014779705SSam Leffler {
18114779705SSam Leffler struct ar5211_desc *ads = AR5211DESC(ds);
18214779705SSam Leffler
18314779705SSam Leffler ads->ds_ctl0 = 0;
18414779705SSam Leffler ads->ds_ctl1 = size & AR_BufLen;
18514779705SSam Leffler if (ads->ds_ctl1 != size) {
18614779705SSam Leffler HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n",
18714779705SSam Leffler __func__, size);
18814779705SSam Leffler return AH_FALSE;
18914779705SSam Leffler }
19014779705SSam Leffler if (flags & HAL_RXDESC_INTREQ)
19114779705SSam Leffler ads->ds_ctl1 |= AR_RxInterReq;
19214779705SSam Leffler ads->ds_status0 = ads->ds_status1 = 0;
19314779705SSam Leffler
19414779705SSam Leffler return AH_TRUE;
19514779705SSam Leffler }
19614779705SSam Leffler
19714779705SSam Leffler /*
19814779705SSam Leffler * Process an RX descriptor, and return the status to the caller.
19914779705SSam Leffler * Copy some hardware specific items into the software portion
20014779705SSam Leffler * of the descriptor.
20114779705SSam Leffler *
20214779705SSam Leffler * NB: the caller is responsible for validating the memory contents
20314779705SSam Leffler * of the descriptor (e.g. flushing any cached copy).
20414779705SSam Leffler */
20514779705SSam Leffler HAL_STATUS
ar5211ProcRxDesc(struct ath_hal * ah,struct ath_desc * ds,uint32_t pa,struct ath_desc * nds,uint64_t tsf,struct ath_rx_status * rs)20614779705SSam Leffler ar5211ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
20714779705SSam Leffler uint32_t pa, struct ath_desc *nds, uint64_t tsf,
20814779705SSam Leffler struct ath_rx_status *rs)
20914779705SSam Leffler {
21014779705SSam Leffler struct ar5211_desc *ads = AR5211DESC(ds);
21114779705SSam Leffler struct ar5211_desc *ands = AR5211DESC(nds);
21214779705SSam Leffler
21314779705SSam Leffler if ((ads->ds_status1 & AR_Done) == 0)
21414779705SSam Leffler return HAL_EINPROGRESS;
21514779705SSam Leffler /*
21614779705SSam Leffler * Given the use of a self-linked tail be very sure that the hw is
21714779705SSam Leffler * done with this descriptor; the hw may have done this descriptor
21814779705SSam Leffler * once and picked it up again...make sure the hw has moved on.
21914779705SSam Leffler */
22014779705SSam Leffler if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
22114779705SSam Leffler return HAL_EINPROGRESS;
22214779705SSam Leffler
22314779705SSam Leffler rs->rs_datalen = ads->ds_status0 & AR_DataLen;
22414779705SSam Leffler rs->rs_tstamp = MS(ads->ds_status1, AR_RcvTimestamp);
22514779705SSam Leffler rs->rs_status = 0;
22614779705SSam Leffler if ((ads->ds_status1 & AR_FrmRcvOK) == 0) {
22714779705SSam Leffler if (ads->ds_status1 & AR_CRCErr)
22814779705SSam Leffler rs->rs_status |= HAL_RXERR_CRC;
22914779705SSam Leffler else if (ads->ds_status1 & AR_DecryptCRCErr)
23014779705SSam Leffler rs->rs_status |= HAL_RXERR_DECRYPT;
23114779705SSam Leffler else {
23214779705SSam Leffler rs->rs_status |= HAL_RXERR_PHY;
23314779705SSam Leffler rs->rs_phyerr = MS(ads->ds_status1, AR_PHYErr);
23414779705SSam Leffler }
23514779705SSam Leffler }
23614779705SSam Leffler /* XXX what about KeyCacheMiss? */
23714779705SSam Leffler rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength);
23814779705SSam Leffler if (ads->ds_status1 & AR_KeyIdxValid)
23914779705SSam Leffler rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx);
24014779705SSam Leffler else
24114779705SSam Leffler rs->rs_keyix = HAL_RXKEYIX_INVALID;
24214779705SSam Leffler /* NB: caller expected to do rate table mapping */
24314779705SSam Leffler rs->rs_rate = MS(ads->ds_status0, AR_RcvRate);
24414779705SSam Leffler rs->rs_antenna = MS(ads->ds_status0, AR_RcvAntenna);
24514779705SSam Leffler rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0;
24614779705SSam Leffler
24714779705SSam Leffler return HAL_OK;
24814779705SSam Leffler }
249