xref: /freebsd/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
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-2004 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 "ar5210/ar5210.h"
2614779705SSam Leffler #include "ar5210/ar5210reg.h"
2714779705SSam Leffler #include "ar5210/ar5210desc.h"
2814779705SSam Leffler 
2914779705SSam Leffler /*
3014779705SSam Leffler  * Get the RXDP.
3114779705SSam Leffler  */
3214779705SSam Leffler uint32_t
ar5210GetRxDP(struct ath_hal * ah,HAL_RX_QUEUE qtype)33d60a0680SAdrian Chadd ar5210GetRxDP(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
ar5210SetRxDP(struct ath_hal * ah,uint32_t rxdp,HAL_RX_QUEUE qtype)44d60a0680SAdrian Chadd ar5210SetRxDP(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 }
5014779705SSam Leffler 
5114779705SSam Leffler /*
5214779705SSam Leffler  * Set Receive Enable bits.
5314779705SSam Leffler  */
5414779705SSam Leffler void
ar5210EnableReceive(struct ath_hal * ah)5514779705SSam Leffler ar5210EnableReceive(struct ath_hal *ah)
5614779705SSam Leffler {
5714779705SSam Leffler 	OS_REG_WRITE(ah, AR_CR, AR_CR_RXE);
5814779705SSam Leffler }
5914779705SSam Leffler 
6014779705SSam Leffler /*
6114779705SSam Leffler  * Stop Receive at the DMA engine
6214779705SSam Leffler  */
6314779705SSam Leffler HAL_BOOL
ar5210StopDmaReceive(struct ath_hal * ah)6414779705SSam Leffler ar5210StopDmaReceive(struct ath_hal *ah)
6514779705SSam Leffler {
6614779705SSam Leffler 	int i;
6714779705SSam Leffler 
6814779705SSam Leffler 	OS_REG_WRITE(ah, AR_CR, AR_CR_RXD);	/* Set receive disable bit */
6914779705SSam Leffler 	for (i = 0; i < 1000; i++) {
7014779705SSam Leffler 		if ((OS_REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
7114779705SSam Leffler 			return AH_TRUE;
7214779705SSam Leffler 		OS_DELAY(10);
7314779705SSam Leffler 	}
7414779705SSam Leffler #ifdef AH_DEBUG
7514779705SSam Leffler 	ath_hal_printf(ah, "ar5210: dma receive failed to stop in 10ms\n");
7614779705SSam Leffler 	ath_hal_printf(ah, "AR_CR=0x%x\n", OS_REG_READ(ah, AR_CR));
7714779705SSam Leffler 	ath_hal_printf(ah, "AR_DIAG_SW=0x%x\n", OS_REG_READ(ah, AR_DIAG_SW));
7814779705SSam Leffler #endif
7914779705SSam Leffler 	return AH_FALSE;
8014779705SSam Leffler }
8114779705SSam Leffler 
8214779705SSam Leffler /*
8314779705SSam Leffler  * Start Transmit at the PCU engine (unpause receive)
8414779705SSam Leffler  */
8514779705SSam Leffler void
ar5210StartPcuReceive(struct ath_hal * ah,HAL_BOOL is_scanning)86*a8083b9cSAdrian Chadd ar5210StartPcuReceive(struct ath_hal *ah, HAL_BOOL is_scanning)
8714779705SSam Leffler {
88143cfad7SAdrian Chadd 	ar5210UpdateDiagReg(ah,
8914779705SSam Leffler 		OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX));
9014779705SSam Leffler }
9114779705SSam Leffler 
9214779705SSam Leffler /*
9314779705SSam Leffler  * Stop Transmit at the PCU engine (pause receive)
9414779705SSam Leffler  */
9514779705SSam Leffler void
ar5210StopPcuReceive(struct ath_hal * ah)9614779705SSam Leffler ar5210StopPcuReceive(struct ath_hal *ah)
9714779705SSam Leffler {
98143cfad7SAdrian Chadd 	ar5210UpdateDiagReg(ah,
9914779705SSam Leffler 		OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX);
10014779705SSam Leffler }
10114779705SSam Leffler 
10214779705SSam Leffler /*
10314779705SSam Leffler  * Set multicast filter 0 (lower 32-bits)
10414779705SSam Leffler  *			   filter 1 (upper 32-bits)
10514779705SSam Leffler  */
10614779705SSam Leffler void
ar5210SetMulticastFilter(struct ath_hal * ah,uint32_t filter0,uint32_t filter1)10714779705SSam Leffler ar5210SetMulticastFilter(struct ath_hal *ah, uint32_t filter0, uint32_t filter1)
10814779705SSam Leffler {
10914779705SSam Leffler 	OS_REG_WRITE(ah, AR_MCAST_FIL0, filter0);
11014779705SSam Leffler 	OS_REG_WRITE(ah, AR_MCAST_FIL1, filter1);
11114779705SSam Leffler }
11214779705SSam Leffler 
11314779705SSam Leffler /*
11414779705SSam Leffler  * Clear multicast filter by index
11514779705SSam Leffler  */
11614779705SSam Leffler HAL_BOOL
ar5210ClrMulticastFilterIndex(struct ath_hal * ah,uint32_t ix)11714779705SSam Leffler ar5210ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
11814779705SSam Leffler {
11914779705SSam Leffler 	uint32_t val;
12014779705SSam Leffler 
12114779705SSam Leffler 	if (ix >= 64)
12214779705SSam Leffler 		return AH_FALSE;
12314779705SSam Leffler 	if (ix >= 32) {
12414779705SSam Leffler 		val = OS_REG_READ(ah, AR_MCAST_FIL1);
12514779705SSam Leffler 		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32))));
12614779705SSam Leffler 	} else {
12714779705SSam Leffler 		val = OS_REG_READ(ah, AR_MCAST_FIL0);
12814779705SSam Leffler 		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<<ix)));
12914779705SSam Leffler 	}
13014779705SSam Leffler 	return AH_TRUE;
13114779705SSam Leffler }
13214779705SSam Leffler 
13314779705SSam Leffler /*
13414779705SSam Leffler  * Set multicast filter by index
13514779705SSam Leffler  */
13614779705SSam Leffler HAL_BOOL
ar5210SetMulticastFilterIndex(struct ath_hal * ah,uint32_t ix)13714779705SSam Leffler ar5210SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix)
13814779705SSam Leffler {
13914779705SSam Leffler 	uint32_t val;
14014779705SSam Leffler 
14114779705SSam Leffler 	if (ix >= 64)
14214779705SSam Leffler 		return AH_FALSE;
14314779705SSam Leffler 	if (ix >= 32) {
14414779705SSam Leffler 		val = OS_REG_READ(ah, AR_MCAST_FIL1);
14514779705SSam Leffler 		OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32))));
14614779705SSam Leffler 	} else {
14714779705SSam Leffler 		val = OS_REG_READ(ah, AR_MCAST_FIL0);
14814779705SSam Leffler 		OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<<ix)));
14914779705SSam Leffler 	}
15014779705SSam Leffler 	return AH_TRUE;
15114779705SSam Leffler }
15214779705SSam Leffler 
15314779705SSam Leffler /*
15414779705SSam Leffler  * Return the receive packet filter.
15514779705SSam Leffler  */
15614779705SSam Leffler uint32_t
ar5210GetRxFilter(struct ath_hal * ah)15714779705SSam Leffler ar5210GetRxFilter(struct ath_hal *ah)
15814779705SSam Leffler {
15914779705SSam Leffler 	/* XXX can't be sure if promiscuous mode is set because of PHYRADAR */
16014779705SSam Leffler 	return OS_REG_READ(ah, AR_RX_FILTER);
16114779705SSam Leffler }
16214779705SSam Leffler 
16314779705SSam Leffler /*
16414779705SSam Leffler  * Turn off/on bits in the receive packet filter.
16514779705SSam Leffler  */
16614779705SSam Leffler void
ar5210SetRxFilter(struct ath_hal * ah,uint32_t bits)16714779705SSam Leffler ar5210SetRxFilter(struct ath_hal *ah, uint32_t bits)
16814779705SSam Leffler {
16914779705SSam Leffler 	if (bits & HAL_RX_FILTER_PHYRADAR) {
17014779705SSam Leffler 		/* must enable promiscuous mode to get radar */
17114779705SSam Leffler 		bits = (bits &~ HAL_RX_FILTER_PHYRADAR) | AR_RX_FILTER_PROMISCUOUS;
17214779705SSam Leffler 	}
17314779705SSam Leffler 	OS_REG_WRITE(ah, AR_RX_FILTER, bits);
17414779705SSam Leffler }
17514779705SSam Leffler 
17614779705SSam Leffler /*
17714779705SSam Leffler  * Initialize RX descriptor, by clearing the status and clearing
17814779705SSam Leffler  * the size.  This is not strictly HW dependent, but we want the
17914779705SSam Leffler  * control and status words to be opaque above the hal.
18014779705SSam Leffler  */
18114779705SSam Leffler HAL_BOOL
ar5210SetupRxDesc(struct ath_hal * ah,struct ath_desc * ds,uint32_t size,u_int flags)18214779705SSam Leffler ar5210SetupRxDesc(struct ath_hal *ah, struct ath_desc *ds,
18314779705SSam Leffler 	uint32_t size, u_int flags)
18414779705SSam Leffler {
18514779705SSam Leffler 	struct ar5210_desc *ads = AR5210DESC(ds);
18614779705SSam Leffler 
18714779705SSam Leffler 	(void) flags;
18814779705SSam Leffler 
18914779705SSam Leffler 	ads->ds_ctl0 = 0;
19014779705SSam Leffler 	ads->ds_ctl1 = size & AR_BufLen;
19114779705SSam Leffler 	if (ads->ds_ctl1 != size) {
19214779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: buffer size %u too large\n",
19314779705SSam Leffler 		    __func__, size);
19414779705SSam Leffler 		return AH_FALSE;
19514779705SSam Leffler 	}
19614779705SSam Leffler 	if (flags & HAL_RXDESC_INTREQ)
19714779705SSam Leffler 		ads->ds_ctl1 |= AR_RxInterReq;
19814779705SSam Leffler 	ads->ds_status0 = ads->ds_status1 = 0;
19914779705SSam Leffler 
20014779705SSam Leffler 	return AH_TRUE;
20114779705SSam Leffler }
20214779705SSam Leffler 
20314779705SSam Leffler /*
20414779705SSam Leffler  * Process an RX descriptor, and return the status to the caller.
20514779705SSam Leffler  * Copy some hardware specific items into the software portion
20614779705SSam Leffler  * of the descriptor.
20714779705SSam Leffler  *
20814779705SSam Leffler  * NB: the caller is responsible for validating the memory contents
20914779705SSam Leffler  *     of the descriptor (e.g. flushing any cached copy).
21014779705SSam Leffler  */
21114779705SSam Leffler HAL_STATUS
ar5210ProcRxDesc(struct ath_hal * ah,struct ath_desc * ds,uint32_t pa,struct ath_desc * nds,uint64_t tsf,struct ath_rx_status * rs)21214779705SSam Leffler ar5210ProcRxDesc(struct ath_hal *ah, struct ath_desc *ds,
21314779705SSam Leffler 	uint32_t pa, struct ath_desc *nds, uint64_t tsf,
21414779705SSam Leffler 	struct ath_rx_status *rs)
21514779705SSam Leffler {
21614779705SSam Leffler 	struct ar5210_desc *ads = AR5210DESC(ds);
21714779705SSam Leffler 	struct ar5210_desc *ands = AR5210DESC(nds);
21814779705SSam Leffler 	uint32_t now, rstamp;
21914779705SSam Leffler 
22014779705SSam Leffler 	if ((ads->ds_status1 & AR_Done) == 0)
22114779705SSam Leffler 		return HAL_EINPROGRESS;
22214779705SSam Leffler 	/*
22314779705SSam Leffler 	 * Given the use of a self-linked tail be very sure that the hw is
22414779705SSam Leffler 	 * done with this descriptor; the hw may have done this descriptor
22514779705SSam Leffler 	 * once and picked it up again...make sure the hw has moved on.
22614779705SSam Leffler 	 */
22714779705SSam Leffler 	if ((ands->ds_status1 & AR_Done) == 0 && OS_REG_READ(ah, AR_RXDP) == pa)
22814779705SSam Leffler 		return HAL_EINPROGRESS;
22914779705SSam Leffler 
23014779705SSam Leffler 	rs->rs_datalen = ads->ds_status0 & AR_DataLen;
23114779705SSam Leffler 	rstamp = MS(ads->ds_status1, AR_RcvTimestamp);
23214779705SSam Leffler 	/*
23314779705SSam Leffler 	 * Convert timestamp.  The value in the
23414779705SSam Leffler 	 * descriptor is bits [10..22] of the TSF.
23514779705SSam Leffler 	 */
23614779705SSam Leffler 	now = (OS_REG_READ(ah, AR_TSF_L32) >> 10) & 0xffff;
23714779705SSam Leffler 	if ((now & 0x1fff) < rstamp)
23814779705SSam Leffler 		rstamp |= (now - 0x2000) & 0xffff;
23914779705SSam Leffler 	else
24014779705SSam Leffler 		rstamp |= now;
24114779705SSam Leffler 	/* NB: keep only 15 bits for consistency w/ other chips */
24214779705SSam Leffler 	rs->rs_tstamp = rstamp & 0x7fff;
24314779705SSam Leffler 	rs->rs_status = 0;
24414779705SSam Leffler 	if ((ads->ds_status1 & AR_FrmRcvOK) == 0) {
24514779705SSam Leffler 		if (ads->ds_status1 & AR_CRCErr)
24614779705SSam Leffler 			rs->rs_status |= HAL_RXERR_CRC;
24714779705SSam Leffler 		else if (ads->ds_status1 & AR_DecryptCRCErr)
24814779705SSam Leffler 			rs->rs_status |= HAL_RXERR_DECRYPT;
24914779705SSam Leffler 		else if (ads->ds_status1 & AR_FIFOOverrun)
25014779705SSam Leffler 			rs->rs_status |= HAL_RXERR_FIFO;
25114779705SSam Leffler 		else {
25214779705SSam Leffler 			rs->rs_status |= HAL_RXERR_PHY;
25314779705SSam Leffler 			rs->rs_phyerr =
25414779705SSam Leffler 				(ads->ds_status1 & AR_PHYErr) >> AR_PHYErr_S;
25514779705SSam Leffler 		}
25614779705SSam Leffler 	}
25714779705SSam Leffler 	/* XXX what about KeyCacheMiss? */
25814779705SSam Leffler 	rs->rs_rssi = MS(ads->ds_status0, AR_RcvSigStrength);
25914779705SSam Leffler 	if (ads->ds_status1 & AR_KeyIdxValid)
26014779705SSam Leffler 		rs->rs_keyix = MS(ads->ds_status1, AR_KeyIdx);
26114779705SSam Leffler 	else
26214779705SSam Leffler 		rs->rs_keyix = HAL_RXKEYIX_INVALID;
26314779705SSam Leffler 	/* NB: caller expected to do rate table mapping */
26414779705SSam Leffler 	rs->rs_rate = MS(ads->ds_status0, AR_RcvRate);
26514779705SSam Leffler 	rs->rs_antenna  = (ads->ds_status0 & AR_RcvAntenna) ? 1 : 0;
26614779705SSam Leffler 	rs->rs_more = (ads->ds_status0 & AR_More) ? 1 : 0;
26714779705SSam Leffler 
26814779705SSam Leffler 	return HAL_OK;
26914779705SSam Leffler }
270