[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree
zrouter-src-freebsd at zrouter.org
zrouter-src-freebsd at zrouter.org
Wed Jul 25 14:36:29 UTC 2012
details: http://zrouter.org/hg/FreeBSD/head//rev/8f13631d24de
changeset: 504:8f13631d24de
user: Aleksandr Rybalko <ray at ddteam.net>
date: Wed Jul 25 17:07:47 2012 +0300
description:
Lazy update
diffstat:
head/sys/dev/ath/ah_osdep.c | 5 +-
head/sys/dev/ath/ah_osdep.h | 21 +-
head/sys/dev/ath/ath_dfs/null/dfs_null.c | 25 +-
head/sys/dev/ath/ath_hal/ah.c | 31 +-
head/sys/dev/ath/ath_hal/ah.h | 246 ++-
head/sys/dev/ath/ath_hal/ah_debug.h | 9 +-
head/sys/dev/ath/ath_hal/ah_desc.h | 29 +-
head/sys/dev/ath/ath_hal/ah_internal.h | 73 +-
head/sys/dev/ath/ath_hal/ar5210/ar5210.h | 17 +-
head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c | 20 +-
head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c | 33 +-
head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c | 10 +-
head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c | 35 +-
head/sys/dev/ath/ath_hal/ar5211/ar5211.h | 17 +-
head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c | 20 +-
head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c | 33 +-
head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c | 10 +-
head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c | 26 +-
head/sys/dev/ath/ath_hal/ar5212/ar5212.h | 15 +-
head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c | 17 +-
head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c | 17 +-
head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c | 10 +-
head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c | 5 +-
head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c | 26 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416.h | 45 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c | 79 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c | 73 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c | 385 +++
head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h | 31 +
head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c | 38 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c | 69 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c | 75 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c | 5 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h | 38 +-
head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h | 55 +-
head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c | 67 +-
head/sys/dev/ath/ath_hal/ar9002/ar9285.h | 7 +-
head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c | 89 +-
head/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c | 135 +
head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c | 18 +-
head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c | 150 +-
head/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h | 59 +
head/sys/dev/ath/ath_rate/amrr/amrr.c | 11 +-
head/sys/dev/ath/ath_rate/onoe/onoe.c | 11 +-
head/sys/dev/ath/ath_rate/sample/sample.c | 98 +-
head/sys/dev/ath/ath_rate/sample/sample.h | 18 +-
head/sys/dev/ath/if_ath.c | 2496 +++-------------------
head/sys/dev/ath/if_ath_ahb.c | 10 +-
head/sys/dev/ath/if_ath_beacon.c | 844 +++++++
head/sys/dev/ath/if_ath_beacon.h | 51 +
head/sys/dev/ath/if_ath_debug.c | 21 +-
head/sys/dev/ath/if_ath_debug.h | 73 +-
head/sys/dev/ath/if_ath_led.c | 8 +-
head/sys/dev/ath/if_ath_misc.h | 48 +-
head/sys/dev/ath/if_ath_pci.c | 8 +-
head/sys/dev/ath/if_ath_rx.c | 1113 ++++++++++
head/sys/dev/ath/if_ath_rx.h | 65 +
head/sys/dev/ath/if_ath_rx_edma.c | 849 +++++++
head/sys/dev/ath/if_ath_rx_edma.h | 36 +
head/sys/dev/ath/if_ath_sysctl.c | 26 +-
head/sys/dev/ath/if_ath_tdma.c | 476 ++++
head/sys/dev/ath/if_ath_tdma.h | 55 +
head/sys/dev/ath/if_ath_tsf.h | 81 +
head/sys/dev/ath/if_ath_tx.c | 581 ++--
head/sys/dev/ath/if_ath_tx.h | 13 +-
head/sys/dev/ath/if_ath_tx_edma.c | 162 +
head/sys/dev/ath/if_ath_tx_edma.h | 36 +
head/sys/dev/ath/if_ath_tx_ht.c | 118 +-
head/sys/dev/ath/if_athdfs.h | 4 +-
head/sys/dev/ath/if_athioctl.h | 147 +-
head/sys/dev/ath/if_athrate.h | 14 +-
head/sys/dev/ath/if_athvar.h | 220 +-
72 files changed, 7005 insertions(+), 2856 deletions(-)
diffs (13118 lines):
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ah_osdep.c
--- a/head/sys/dev/ath/ah_osdep.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ah_osdep.c Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/ah_osdep.c 234450 2012-04-19 03:26:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ah_osdep.c 237864 2012-07-01 02:34:32Z adrian $
*/
#include "opt_ah.h"
@@ -47,6 +47,7 @@
#include <net/ethernet.h> /* XXX for ether_sprintf */
#include <dev/ath/ath_hal/ah.h>
+#include <dev/ath/ath_hal/ah_debug.h>
/*
* WiSoC boards overload the bus tag with information about the
@@ -137,8 +138,6 @@
#ifdef AH_DEBUG
-/* This must match the definition in ath_hal/ah_debug.h */
-#define HAL_DEBUG_UNMASKABLE 0xf0000000
void
DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
{
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ah_osdep.h
--- a/head/sys/dev/ath/ah_osdep.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ah_osdep.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/ah_osdep.h 234450 2012-04-19 03:26:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ah_osdep.h 237865 2012-07-01 02:37:04Z adrian $
*/
#ifndef _ATH_AH_OSDEP_H_
#define _ATH_AH_OSDEP_H_
@@ -63,6 +63,7 @@
#define OS_INLINE __inline
#define OS_MEMZERO(_a, _n) bzero((_a), (_n))
#define OS_MEMCPY(_d, _s, _n) memcpy(_d,_s,_n)
+#define OS_MEMCMP(_a, _b, _l) memcmp((_a), (_b), (_l))
#define abs(_a) __builtin_abs(_a)
@@ -75,6 +76,10 @@
* domain registers are not byte swapped! Thus, on big-endian
* platforms we have to explicitly byte-swap those registers.
* OS_REG_UNSWAPPED identifies the registers that need special handling.
+ *
+ * This is not currently used by the FreeBSD HAL osdep code; the HAL
+ * currently does not configure hardware byteswapping for register space
+ * accesses and instead does it through the FreeBSD bus space code.
*/
#if _BYTE_ORDER == _BIG_ENDIAN
#define OS_REG_UNSWAPPED(_reg) \
@@ -85,6 +90,20 @@
#endif /* _BYTE_ORDER */
/*
+ * For USB/SDIO support (where access latencies are quite high);
+ * some write accesses may be buffered and then flushed when
+ * either a read is done, or an explicit flush is done.
+ *
+ * These are simply placeholders for now.
+ */
+#define OS_REG_WRITE_BUFFER_ENABLE(_ah) \
+ do { } while (0)
+#define OS_REG_WRITE_BUFFER_DISABLE(_ah) \
+ do { } while (0)
+#define OS_REG_WRITE_BUFFER_FLUSH(_ah) \
+ do { } while (0)
+
+/*
* Register read/write operations are either handled through
* platform-dependent routines (or when debugging is enabled
* with AH_DEBUG); or they are inline expanded using the macros
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_dfs/null/dfs_null.c
--- a/head/sys/dev/ath/ath_dfs/null/dfs_null.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_dfs/null/dfs_null.c Wed Jul 25 17:07:47 2012 +0300
@@ -26,14 +26,15 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/ath_dfs/null/dfs_null.c 231099 2012-02-06 20:23:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_dfs/null/dfs_null.c 237529 2012-06-24 08:47:19Z adrian $
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/ath_dfs/null/dfs_null.c 231099 2012-02-06 20:23:21Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/ath_dfs/null/dfs_null.c 237529 2012-06-24 08:47:19Z adrian $");
/*
* This implements an empty DFS module.
*/
+#include "opt_ath.h"
#include "opt_inet.h"
#include "opt_wlan.h"
@@ -102,7 +103,7 @@
int
ath_dfs_attach(struct ath_softc *sc)
{
- return 1;
+ return (1);
}
/*
@@ -111,11 +112,12 @@
int
ath_dfs_detach(struct ath_softc *sc)
{
- return 1;
+ return (1);
}
/*
- * Enable radar check
+ * Enable radar check. Return 1 if the driver should
+ * enable radar PHY errors, or 0 if not.
*/
int
ath_dfs_radar_enable(struct ath_softc *sc, struct ieee80211_channel *chan)
@@ -163,9 +165,12 @@
/*
* Process DFS related PHY errors
+ *
+ * The mbuf is not "ours" and if we want a copy, we have
+ * to take a copy. It'll be freed after this function returns.
*/
void
-ath_dfs_process_phy_err(struct ath_softc *sc, const char *buf,
+ath_dfs_process_phy_err(struct ath_softc *sc, struct mbuf *m,
uint64_t tsf, struct ath_rx_status *rxstat)
{
@@ -182,7 +187,7 @@
ath_dfs_process_radar_event(struct ath_softc *sc,
struct ieee80211_channel *chan)
{
- return 0;
+ return (0);
}
/*
@@ -195,7 +200,7 @@
int
ath_dfs_tasklet_needed(struct ath_softc *sc, struct ieee80211_channel *chan)
{
- return 0;
+ return (0);
}
/*
@@ -272,7 +277,7 @@
free(indata, M_TEMP);
if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
free(outdata, M_TEMP);
- return error;
+ return (error);
}
/*
@@ -282,5 +287,5 @@
ath_dfs_get_thresholds(struct ath_softc *sc, HAL_PHYERR_PARAM *param)
{
ath_hal_getdfsthresh(sc->sc_ah, param);
- return 1;
+ return (1);
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ah.c
--- a/head/sys/dev/ath/ath_hal/ah.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 230147 2012-01-15 19:22:34Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 238333 2012-07-10 03:48:07Z adrian $
*/
#include "opt_ah.h"
@@ -630,6 +630,34 @@
case HAL_CAP_REG_FLAG:
*result = AH_PRIVATE(ah)->ah_currentRDext;
return HAL_OK;
+ case HAL_CAP_ENHANCED_DMA_SUPPORT:
+ return pCap->halEnhancedDmaSupport ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_NUM_TXMAPS:
+ *result = pCap->halNumTxMaps;
+ return HAL_OK;
+ case HAL_CAP_TXDESCLEN:
+ *result = pCap->halTxDescLen;
+ return HAL_OK;
+ case HAL_CAP_TXSTATUSLEN:
+ *result = pCap->halTxStatusLen;
+ return HAL_OK;
+ case HAL_CAP_RXSTATUSLEN:
+ *result = pCap->halRxStatusLen;
+ return HAL_OK;
+ case HAL_CAP_RXFIFODEPTH:
+ switch (capability) {
+ case HAL_RX_QUEUE_HP:
+ *result = pCap->halRxHpFifoDepth;
+ return HAL_OK;
+ case HAL_RX_QUEUE_LP:
+ *result = pCap->halRxLpFifoDepth;
+ return HAL_OK;
+ default:
+ return HAL_ENOTSUPP;
+ }
+ case HAL_CAP_RXBUFSIZE:
+ case HAL_CAP_NUM_MR_RETRIES:
+ return HAL_EINVAL; /* XXX not yet */
case HAL_CAP_BT_COEX:
return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_HT20_SGI:
@@ -667,6 +695,7 @@
return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_SERIALISE_WAR: /* PCI register serialisation */
return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP;
+
default:
return HAL_EINVAL;
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ah.h
--- a/head/sys/dev/ath/ath_hal/ah.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah.h 234088 2012-04-10 07:11:33Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah.h 238731 2012-07-24 01:18:19Z adrian $
*/
#ifndef _ATH_AH_H_
@@ -73,6 +73,7 @@
HAL_EINPROGRESS = 15, /* Operation incomplete */
HAL_EEBADREG = 16, /* EEPROM invalid regulatory contents */
HAL_EEBADCC = 17, /* EEPROM invalid country code */
+ HAL_INV_PMODE = 18, /* Couldn't bring out of sleep state */
} HAL_STATUS;
typedef enum {
@@ -109,7 +110,7 @@
HAL_CAP_TPC_ACK = 26, /* ack txpower with per-packet tpc */
HAL_CAP_TPC_CTS = 27, /* cts txpower with per-packet tpc */
HAL_CAP_11D = 28, /* 11d beacon support for changing cc */
-
+ HAL_CAP_PCIE_PS = 29,
HAL_CAP_HT = 30, /* hardware can support HT */
HAL_CAP_GTXTO = 31, /* hardware supports global tx timeout */
HAL_CAP_FAST_CC = 32, /* hardware supports fast channel change */
@@ -119,6 +120,9 @@
HAL_CAP_CST = 38, /* hardware supports carrier sense timeout */
+ HAL_CAP_RIFS_RX = 39,
+ HAL_CAP_RIFS_TX = 40,
+ HAL_CAP_FORCE_PPM = 41,
HAL_CAP_RTS_AGGR_LIMIT = 42, /* aggregation limit with RTS */
HAL_CAP_4ADDR_AGGR = 43, /* hardware is capable of 4addr aggregation */
HAL_CAP_DFS_DMN = 44, /* current DFS domain */
@@ -130,8 +134,32 @@
HAL_CAP_MBSSID_AGGR_SUPPORT = 49, /* Support for mBSSID Aggregation */
HAL_CAP_SPLIT_4KB_TRANS = 50, /* hardware supports descriptors straddling a 4k page boundary */
HAL_CAP_REG_FLAG = 51, /* Regulatory domain flags */
+ HAL_CAP_BB_RIFS_HANG = 52,
+ HAL_CAP_RIFS_RX_ENABLED = 53,
+ HAL_CAP_BB_DFS_HANG = 54,
HAL_CAP_BT_COEX = 60, /* hardware is capable of bluetooth coexistence */
+ HAL_CAP_DYNAMIC_SMPS = 61, /* Dynamic MIMO Power Save hardware support */
+
+ HAL_CAP_DS = 67, /* 2 stream */
+ HAL_CAP_BB_RX_CLEAR_STUCK_HANG = 68,
+ HAL_CAP_MAC_HANG = 69, /* can MAC hang */
+ HAL_CAP_MFP = 70, /* Management Frame Protection in hardware */
+
+ HAL_CAP_TS = 72, /* 3 stream */
+
+ HAL_CAP_ENHANCED_DMA_SUPPORT = 75, /* DMA FIFO support */
+ HAL_CAP_NUM_TXMAPS = 76, /* Number of buffers in a transmit descriptor */
+ HAL_CAP_TXDESCLEN = 77, /* Length of transmit descriptor */
+ HAL_CAP_TXSTATUSLEN = 78, /* Length of transmit status descriptor */
+ HAL_CAP_RXSTATUSLEN = 79, /* Length of transmit status descriptor */
+ HAL_CAP_RXFIFODEPTH = 80, /* Receive hardware FIFO depth */
+ HAL_CAP_RXBUFSIZE = 81, /* Receive Buffer Length */
+ HAL_CAP_NUM_MR_RETRIES = 82, /* limit on multirate retries */
+
+ HAL_CAP_OL_PWRCTRL = 84, /* Open loop TX power control */
+
+ HAL_CAP_BB_PANIC_WATCHDOG = 92,
HAL_CAP_HT20_SGI = 96, /* hardware supports HT20 short GI */
@@ -143,7 +171,6 @@
HAL_CAP_INTMIT = 229, /* interference mitigation */
HAL_CAP_RXORN_FATAL = 230, /* HAL_INT_RXORN treated as fatal */
HAL_CAP_BB_HANG = 235, /* can baseband hang */
- HAL_CAP_MAC_HANG = 236, /* can MAC hang */
HAL_CAP_INTRMASK = 237, /* bitmask of supported interrupts */
HAL_CAP_BSSIDMATCH = 238, /* hardware has disable bssid match */
HAL_CAP_STREAMS = 239, /* how many 802.11n spatial streams are available */
@@ -180,10 +207,19 @@
HAL_TX_QUEUE_CAB = 3, /* "crap after beacon" xmit q */
HAL_TX_QUEUE_UAPSD = 4, /* u-apsd power save xmit q */
HAL_TX_QUEUE_PSPOLL = 5, /* power save poll xmit q */
+ HAL_TX_QUEUE_CFEND = 6,
+ HAL_TX_QUEUE_PAPRD = 7,
} HAL_TX_QUEUE;
#define HAL_NUM_TX_QUEUES 10 /* max possible # of queues */
+typedef enum {
+ HAL_RX_QUEUE_HP = 0, /* high priority recv queue */
+ HAL_RX_QUEUE_LP = 1, /* low priority recv queue */
+} HAL_RX_QUEUE;
+
+#define HAL_NUM_RX_QUEUES 2 /* max possible # of queues */
+
/*
* Transmit queue subtype. These map directly to
* WME Access Categories (except for UPSD). Refer
@@ -373,7 +409,10 @@
*/
typedef enum {
HAL_INT_RX = 0x00000001, /* Non-common mapping */
- HAL_INT_RXDESC = 0x00000002,
+ HAL_INT_RXDESC = 0x00000002, /* Legacy mapping */
+ HAL_INT_RXHP = 0x00000001, /* EDMA */
+ HAL_INT_RXLP = 0x00000002, /* EDMA */
+ HAL_INT_RXERR = 0x00000004,
HAL_INT_RXNOFRM = 0x00000008,
HAL_INT_RXEOL = 0x00000010,
HAL_INT_RXORN = 0x00000020,
@@ -420,14 +459,38 @@
| HAL_INT_GPIO,
} HAL_INT;
+/*
+ * MSI vector assignments
+ */
typedef enum {
- HAL_GPIO_MUX_OUTPUT = 0,
- HAL_GPIO_MUX_PCIE_ATTENTION_LED = 1,
- HAL_GPIO_MUX_PCIE_POWER_LED = 2,
- HAL_GPIO_MUX_TX_FRAME = 3,
- HAL_GPIO_MUX_RX_CLEAR_EXTERNAL = 4,
- HAL_GPIO_MUX_MAC_NETWORK_LED = 5,
- HAL_GPIO_MUX_MAC_POWER_LED = 6
+ HAL_MSIVEC_MISC = 0,
+ HAL_MSIVEC_TX = 1,
+ HAL_MSIVEC_RXLP = 2,
+ HAL_MSIVEC_RXHP = 3,
+} HAL_MSIVEC;
+
+typedef enum {
+ HAL_INT_LINE = 0,
+ HAL_INT_MSI = 1,
+} HAL_INT_TYPE;
+
+/* For interrupt mitigation registers */
+typedef enum {
+ HAL_INT_RX_FIRSTPKT=0,
+ HAL_INT_RX_LASTPKT,
+ HAL_INT_TX_FIRSTPKT,
+ HAL_INT_TX_LASTPKT,
+ HAL_INT_THRESHOLD
+} HAL_INT_MITIGATION;
+
+typedef enum {
+ HAL_GPIO_OUTPUT_MUX_AS_OUTPUT = 0,
+ HAL_GPIO_OUTPUT_MUX_PCIE_ATTENTION_LED = 1,
+ HAL_GPIO_OUTPUT_MUX_PCIE_POWER_LED = 2,
+ HAL_GPIO_OUTPUT_MUX_MAC_NETWORK_LED = 3,
+ HAL_GPIO_OUTPUT_MUX_MAC_POWER_LED = 4,
+ HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE = 5,
+ HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME = 6
} HAL_GPIO_MUX_TYPE;
typedef enum {
@@ -568,7 +631,7 @@
typedef struct {
uint8_t kv_type; /* one of HAL_CIPHER */
- uint8_t kv_pad;
+ uint8_t kv_apsd; /* Mask for APSD enabled ACs */
uint16_t kv_len; /* length in bits */
uint8_t kv_val[16]; /* enough for 128-bit keys */
uint8_t kv_mic[8]; /* TKIP MIC key */
@@ -660,7 +723,11 @@
uint32_t tx_busy;
uint32_t rx_busy;
uint32_t chan_busy;
+ uint32_t ext_chan_busy;
uint32_t cycle_count;
+ /* XXX TODO */
+ uint32_t ofdm_phyerr_count;
+ uint32_t cck_phyerr_count;
} HAL_SURVEY_SAMPLE;
/*
@@ -693,6 +760,7 @@
HAL_ANI_SPUR_IMMUNITY_LEVEL = 5, /* set level */
HAL_ANI_MODE = 6, /* 0 => manual, 1 => auto (XXX do not change) */
HAL_ANI_PHYERR_RESET = 7, /* reset phy error stats */
+ HAL_ANI_MRC_CCK = 8,
} HAL_ANI_CMD;
/*
@@ -710,6 +778,7 @@
HAL_CAP_INTMIT_SPUR_IMMUNITY_LEVEL = 6
} HAL_CAP_INTMIT_CMD;
+/* DFS defines */
typedef struct {
int32_t pe_firpwr; /* FIR pwr out threshold */
int32_t pe_rrssi; /* Radar rssi thresh */
@@ -773,6 +842,139 @@
};
typedef struct hal_dfs_event HAL_DFS_EVENT;
+/*
+ * BT Co-existence definitions
+ */
+typedef enum {
+ HAL_BT_MODULE_CSR_BC4 = 0, /* CSR BlueCore v4 */
+ HAL_BT_MODULE_JANUS = 1, /* Kite + Valkyrie combo */
+ HAL_BT_MODULE_HELIUS = 2, /* Kiwi + Valkyrie combo */
+ HAL_MAX_BT_MODULES
+} HAL_BT_MODULE;
+
+typedef struct {
+ HAL_BT_MODULE bt_module;
+ u_int8_t bt_coex_config;
+ u_int8_t bt_gpio_bt_active;
+ u_int8_t bt_gpio_bt_priority;
+ u_int8_t bt_gpio_wlan_active;
+ u_int8_t bt_active_polarity;
+ HAL_BOOL bt_single_ant;
+ u_int8_t bt_dutyCycle;
+ u_int8_t bt_isolation;
+ u_int8_t bt_period;
+} HAL_BT_COEX_INFO;
+
+typedef enum {
+ HAL_BT_COEX_MODE_LEGACY = 0, /* legacy rx_clear mode */
+ HAL_BT_COEX_MODE_UNSLOTTED = 1, /* untimed/unslotted mode */
+ HAL_BT_COEX_MODE_SLOTTED = 2, /* slotted mode */
+ HAL_BT_COEX_MODE_DISALBED = 3, /* coexistence disabled */
+} HAL_BT_COEX_MODE;
+
+typedef enum {
+ HAL_BT_COEX_CFG_NONE, /* No bt coex enabled */
+ HAL_BT_COEX_CFG_2WIRE_2CH, /* 2-wire with 2 chains */
+ HAL_BT_COEX_CFG_2WIRE_CH1, /* 2-wire with ch1 */
+ HAL_BT_COEX_CFG_2WIRE_CH0, /* 2-wire with ch0 */
+ HAL_BT_COEX_CFG_3WIRE, /* 3-wire */
+ HAL_BT_COEX_CFG_MCI /* MCI */
+} HAL_BT_COEX_CFG;
+
+typedef enum {
+ HAL_BT_COEX_SET_ACK_PWR = 0, /* Change ACK power setting */
+ HAL_BT_COEX_LOWER_TX_PWR, /* Change transmit power */
+ HAL_BT_COEX_ANTENNA_DIVERSITY, /* Enable RX diversity for Kite */
+} HAL_BT_COEX_SET_PARAMETER;
+
+#define HAL_BT_COEX_FLAG_LOW_ACK_PWR 0x00000001
+#define HAL_BT_COEX_FLAG_LOWER_TX_PWR 0x00000002
+/* Check Rx Diversity is allowed */
+#define HAL_BT_COEX_FLAG_ANT_DIV_ALLOW 0x00000004
+/* Check Diversity is on or off */
+#define HAL_BT_COEX_FLAG_ANT_DIV_ENABLE 0x00000008
+
+#define HAL_BT_COEX_ANTDIV_CONTROL1_ENABLE 0x0b
+/* main: LNA1, alt: LNA2 */
+#define HAL_BT_COEX_ANTDIV_CONTROL2_ENABLE 0x09
+#define HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_A 0x04
+#define HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_A 0x09
+#define HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_B 0x02
+#define HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_B 0x06
+
+#define HAL_BT_COEX_ISOLATION_FOR_NO_COEX 30
+
+#define HAL_BT_COEX_ANT_DIV_SWITCH_COM 0x66666666
+
+#define HAL_BT_COEX_HELIUS_CHAINMASK 0x02
+
+#define HAL_BT_COEX_LOW_ACK_POWER 0x0
+#define HAL_BT_COEX_HIGH_ACK_POWER 0x3f3f3f
+
+typedef enum {
+ HAL_BT_COEX_NO_STOMP = 0,
+ HAL_BT_COEX_STOMP_ALL,
+ HAL_BT_COEX_STOMP_LOW,
+ HAL_BT_COEX_STOMP_NONE,
+ HAL_BT_COEX_STOMP_ALL_FORCE,
+ HAL_BT_COEX_STOMP_LOW_FORCE,
+} HAL_BT_COEX_STOMP_TYPE;
+
+typedef struct {
+ /* extend rx_clear after tx/rx to protect the burst (in usec). */
+ u_int8_t bt_time_extend;
+
+ /*
+ * extend rx_clear as long as txsm is
+ * transmitting or waiting for ack.
+ */
+ HAL_BOOL bt_txstate_extend;
+
+ /*
+ * extend rx_clear so that when tx_frame
+ * is asserted, rx_clear will drop.
+ */
+ HAL_BOOL bt_txframe_extend;
+
+ /*
+ * coexistence mode
+ */
+ HAL_BT_COEX_MODE bt_mode;
+
+ /*
+ * treat BT high priority traffic as
+ * a quiet collision
+ */
+ HAL_BOOL bt_quiet_collision;
+
+ /*
+ * invert rx_clear as WLAN_ACTIVE
+ */
+ HAL_BOOL bt_rxclear_polarity;
+
+ /*
+ * slotted mode only. indicate the time in usec
+ * from the rising edge of BT_ACTIVE to the time
+ * BT_PRIORITY can be sampled to indicate priority.
+ */
+ u_int8_t bt_priority_time;
+
+ /*
+ * slotted mode only. indicate the time in usec
+ * from the rising edge of BT_ACTIVE to the time
+ * BT_PRIORITY can be sampled to indicate tx/rx and
+ * BT_FREQ is sampled.
+ */
+ u_int8_t bt_first_slot_time;
+
+ /*
+ * slotted mode only. rx_clear and bt_ant decision
+ * will be held the entire time that BT_ACTIVE is asserted,
+ * otherwise the decision is made before every slot boundry.
+ */
+ HAL_BOOL bt_hold_rxclear;
+} HAL_BT_COEX_CONFIG;
+
typedef struct
{
int ah_debug; /* only used if AH_DEBUG is defined */
@@ -828,7 +1030,8 @@
HAL_BOOL bChannelChange, HAL_STATUS *status);
HAL_BOOL __ahdecl(*ah_phyDisable)(struct ath_hal *);
HAL_BOOL __ahdecl(*ah_disable)(struct ath_hal *);
- void __ahdecl(*ah_configPCIE)(struct ath_hal *, HAL_BOOL restore);
+ void __ahdecl(*ah_configPCIE)(struct ath_hal *, HAL_BOOL restore,
+ HAL_BOOL power_off);
void __ahdecl(*ah_disablePCIE)(struct ath_hal *);
void __ahdecl(*ah_setPCUConfig)(struct ath_hal *);
HAL_BOOL __ahdecl(*ah_perCalibration)(struct ath_hal*,
@@ -881,10 +1084,19 @@
void __ahdecl(*ah_reqTxIntrDesc)(struct ath_hal *, struct ath_desc*);
HAL_BOOL __ahdecl(*ah_getTxCompletionRates)(struct ath_hal *,
const struct ath_desc *ds, int *rates, int *tries);
+ void __ahdecl(*ah_setTxDescLink)(struct ath_hal *ah, void *ds,
+ uint32_t link);
+ void __ahdecl(*ah_getTxDescLink)(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+ void __ahdecl(*ah_getTxDescLinkPtr)(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
+ void __ahdecl(*ah_setupTxStatusRing)(struct ath_hal *,
+ void *ts_start, uint32_t ts_paddr_start,
+ uint16_t size);
/* Receive Functions */
- uint32_t __ahdecl(*ah_getRxDP)(struct ath_hal*);
- void __ahdecl(*ah_setRxDP)(struct ath_hal*, uint32_t rxdp);
+ uint32_t __ahdecl(*ah_getRxDP)(struct ath_hal*, HAL_RX_QUEUE);
+ void __ahdecl(*ah_setRxDP)(struct ath_hal*, uint32_t rxdp, HAL_RX_QUEUE);
void __ahdecl(*ah_enableReceive)(struct ath_hal*);
HAL_BOOL __ahdecl(*ah_stopDmaReceive)(struct ath_hal*);
void __ahdecl(*ah_startPcuReceive)(struct ath_hal*);
@@ -1030,8 +1242,8 @@
struct ath_desc *);
void __ahdecl(*ah_set11nBurstDuration)(struct ath_hal *,
struct ath_desc *, u_int);
- uint32_t __ahdecl(*ah_get_mib_cycle_counts_pct) (struct ath_hal *,
- uint32_t *, uint32_t *, uint32_t *, uint32_t *);
+ HAL_BOOL __ahdecl(*ah_getMibCycleCounts) (struct ath_hal *,
+ HAL_SURVEY_SAMPLE *);
uint32_t __ahdecl(*ah_get11nExtBusy)(struct ath_hal *);
void __ahdecl(*ah_set11nMac2040)(struct ath_hal *,
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ah_debug.h
--- a/head/sys/dev/ath/ath_hal/ah_debug.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah_debug.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah_debug.h 221776 2011-05-11 13:22:41Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah_debug.h 238276 2012-07-09 06:41:18Z adrian $
*/
#ifndef _ATH_AH_DEBUG_H_
#define _ATH_AH_DEBUG_H_
@@ -47,8 +47,13 @@
HAL_DEBUG_DIVERSITY = 0x00100000, /* diversity debugging */
HAL_DEBUG_DFS = 0x00200000, /* DFS debugging */
HAL_DEBUG_HANG = 0x00400000, /* BB/MAC hang debugging */
+ HAL_DEBUG_CALIBRATE = 0x00800000, /* setup calibration */
+ HAL_DEBUG_POWER_MGMT = 0x01000000, /* power calibration */
+ HAL_DEBUG_CHANNEL = 0x02000000,
+ HAL_DEBUG_QUEUE = 0x04000000,
+ HAL_DEBUG_PRINT_REG = 0x08000000,
- HAL_DEBUG_UNMASKABLE = 0xf0000000, /* always printed */
+ HAL_DEBUG_UNMASKABLE = 0x80000000, /* always printed */
HAL_DEBUG_ANY = 0xffffffff
};
#endif /* _ATH_AH_DEBUG_H_ */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ah_desc.h
--- a/head/sys/dev/ath/ath_hal/ah_desc.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah_desc.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah_desc.h 229791 2012-01-07 20:23:05Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah_desc.h 238314 2012-07-09 23:58:22Z adrian $
*/
#ifndef _DEV_ATH_DESC_H
@@ -122,11 +122,12 @@
int8_t rs_rssi_ext[3]; /* rx frame RSSI [ext, chain 0-2] */
uint8_t rs_isaggr; /* is part of the aggregate */
uint8_t rs_moreaggr; /* more frames in aggr to follow */
+ uint16_t rs_flags; /* misc flags */
uint8_t rs_num_delims; /* number of delims in aggr */
- uint8_t rs_flags; /* misc flags */
+ uint8_t rs_spare0; /* padding */
uint32_t rs_evm0; /* evm bytes */
uint32_t rs_evm1;
- uint32_t rs_evm2;
+ uint32_t rs_evm2;
uint32_t rs_evm3; /* needed for ar9300 and later */
uint32_t rs_evm4; /* needed for ar9300 and later */
#endif /* AH_SUPPORT_AR5416 */
@@ -138,16 +139,19 @@
#define HAL_RXERR_FIFO 0x04 /* fifo overrun */
#define HAL_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */
#define HAL_RXERR_MIC 0x10 /* Michael MIC decrypt error */
+#define HAL_RXERR_INCOMP 0x20 /* Rx Desc processing is incomplete */
+#define HAL_RXERR_KEYMISS 0x40 /* Key not found in keycache */
/* bits found in rs_flags */
-#define HAL_RX_MORE 0x01 /* more descriptors follow */
-#define HAL_RX_MORE_AGGR 0x02 /* more frames in aggr */
-#define HAL_RX_GI 0x04 /* full gi */
-#define HAL_RX_2040 0x08 /* 40 Mhz */
-#define HAL_RX_DELIM_CRC_PRE 0x10 /* crc error in delimiter pre */
-#define HAL_RX_DELIM_CRC_POST 0x20 /* crc error in delim after */
-#define HAL_RX_DECRYPT_BUSY 0x40 /* decrypt was too slow */
-#define HAL_RX_HI_RX_CHAIN 0x80 /* SM power save: hi Rx chain control */
+#define HAL_RX_MORE 0x0001 /* more descriptors follow */
+#define HAL_RX_MORE_AGGR 0x0002 /* more frames in aggr */
+#define HAL_RX_GI 0x0004 /* full gi */
+#define HAL_RX_2040 0x0008 /* 40 Mhz */
+#define HAL_RX_DELIM_CRC_PRE 0x0010 /* crc error in delimiter pre */
+#define HAL_RX_DELIM_CRC_POST 0x0020 /* crc error in delim after */
+#define HAL_RX_DECRYPT_BUSY 0x0040 /* decrypt was too slow */
+#define HAL_RX_HI_RX_CHAIN 0x0080 /* SM power save: hi Rx chain control */
+#define HAL_RX_IS_APSD 0x0100 /* Is ASPD trigger frame */
enum {
HAL_PHYERR_UNDERRUN = 0, /* Transmit underrun */
@@ -178,6 +182,8 @@
HAL_PHYERR_HT_CRC_ERROR = 34, /* */
HAL_PHYERR_HT_LENGTH_ILLEGAL = 35, /* */
HAL_PHYERR_HT_RATE_ILLEGAL = 36, /* */
+
+ HAL_PHYERR_SPECTRAL = 38,
};
/* value found in rs_keyix to mark invalid entries */
@@ -225,6 +231,7 @@
#define ds_rxstat ds_us.rx
/* flags passed to tx descriptor setup methods */
+/* This is a uint16_t field in ath_buf, just be warned! */
#define HAL_TXDESC_CLRDMASK 0x0001 /* clear destination filter mask */
#define HAL_TXDESC_NOACK 0x0002 /* don't wait for ACK */
#define HAL_TXDESC_RTSENA 0x0004 /* enable RTS */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ah_internal.h
--- a/head/sys/dev/ath/ath_hal/ah_internal.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah_internal.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah_internal.h 229791 2012-01-07 20:23:05Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah_internal.h 237868 2012-07-01 03:15:18Z adrian $
*/
#ifndef _ATH_AH_INTERAL_H_
#define _ATH_AH_INTERAL_H_
@@ -212,10 +212,24 @@
halBssidMatchSupport : 1,
hal4kbSplitTransSupport : 1,
halHasRxSelfLinkedTail : 1,
- halSupportsFastClock5GHz : 1, /* Hardware supports 5ghz fast clock; check eeprom/channel before using */
+ halSupportsFastClock5GHz : 1,
halHasLongRxDescTsf : 1,
halHasBBReadWar : 1,
- halSerialiseRegWar : 1;
+ halSerialiseRegWar : 1,
+ halMciSupport : 1,
+ halRxTxAbortSupport : 1,
+ halPaprdEnabled : 1,
+ halHasUapsdSupport : 1,
+ halWpsPushButtonSupport : 1,
+ halBtCoexApsmWar : 1,
+ halGenTimerSupport : 1,
+ halLDPCSupport : 1,
+ halHwBeaconProcSupport : 1,
+ halEnhancedDmaSupport : 1;
+ uint32_t halIsrRacSupport : 1,
+ halApmEnable : 1,
+ halIntrMitigation : 1;
+
uint32_t halWirelessModes;
uint16_t halTotalQueues;
uint16_t halKeyCacheSize;
@@ -231,6 +245,13 @@
uint32_t halIntrMask;
uint8_t halTxStreams;
uint8_t halRxStreams;
+
+ int halNumTxMaps;
+ int halTxDescLen;
+ int halTxStatusLen;
+ int halRxStatusLen;
+ int halRxHpFifoDepth;
+ int halRxLpFifoDepth;
} HAL_CAPABILITIES;
struct regDomain;
@@ -355,8 +376,8 @@
AH_PRIVATE(_ah)->ah_getNfAdjust(_ah, _c)
#define ath_hal_getNoiseFloor(_ah, _nfArray) \
AH_PRIVATE(_ah)->ah_getNoiseFloor(_ah, _nfArray)
-#define ath_hal_configPCIE(_ah, _reset) \
- (_ah)->ah_configPCIE(_ah, _reset)
+#define ath_hal_configPCIE(_ah, _reset, _poweroff) \
+ (_ah)->ah_configPCIE(_ah, _reset, _poweroff)
#define ath_hal_disablePCIE(_ah) \
(_ah)->ah_disablePCIE(_ah)
#define ath_hal_setInterrupts(_ah, _mask) \
@@ -484,6 +505,8 @@
/* Analog register writes may require a delay between each one (eg Merlin?) */
#define OS_A_REG_RMW_FIELD(_a, _r, _f, _v) \
do { OS_REG_WRITE(_a, _r, (OS_REG_READ(_a, _r) &~ (_f)) | (((_v) << _f##_S) & (_f))) ; OS_DELAY(100); } while (0)
+#define OS_A_REG_WRITE(_a, _r, _v) \
+ do { OS_REG_WRITE(_a, _r, _v); OS_DELAY(100); } while (0)
/* wait for the register contents to have the specified value */
extern HAL_BOOL ath_hal_wait(struct ath_hal *, u_int reg,
@@ -626,6 +649,46 @@
/* The diagnostic codes used to be internally defined here -adrian */
#include "ah_diagcodes.h"
+/*
+ * The AR5416 and later HALs have MAC and baseband hang checking.
+ */
+typedef struct {
+ uint32_t hang_reg_offset;
+ uint32_t hang_val;
+ uint32_t hang_mask;
+ uint32_t hang_offset;
+} hal_hw_hang_check_t;
+
+typedef struct {
+ uint32_t dma_dbg_3;
+ uint32_t dma_dbg_4;
+ uint32_t dma_dbg_5;
+ uint32_t dma_dbg_6;
+} mac_dbg_regs_t;
+
+typedef enum {
+ dcu_chain_state = 0x1,
+ dcu_complete_state = 0x2,
+ qcu_state = 0x4,
+ qcu_fsp_ok = 0x8,
+ qcu_fsp_state = 0x10,
+ qcu_stitch_state = 0x20,
+ qcu_fetch_state = 0x40,
+ qcu_complete_state = 0x80
+} hal_mac_hangs_t;
+
+typedef struct {
+ int states;
+ uint8_t dcu_chain_state;
+ uint8_t dcu_complete_state;
+ uint8_t qcu_state;
+ uint8_t qcu_fsp_ok;
+ uint8_t qcu_fsp_state;
+ uint8_t qcu_stitch_state;
+ uint8_t qcu_fetch_state;
+ uint8_t qcu_complete_state;
+} hal_mac_hang_check_t;
+
enum {
HAL_BB_HANG_DFS = 0x0001,
HAL_BB_HANG_RIFS = 0x0002,
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5210/ar5210.h
--- a/head/sys/dev/ath/ath_hal/ar5210/ar5210.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5210/ar5210.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210.h 225444 2011-09-08 01:23:05Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210.h 238607 2012-07-19 02:25:14Z adrian $
*/
#ifndef _ATH_AR5210_H_
#define _ATH_AR5210_H_
@@ -179,9 +179,15 @@
extern void ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
extern HAL_BOOL ar5210GetTxCompletionRates(struct ath_hal *ah,
const struct ath_desc *, int *rates, int *tries);
+extern void ar5210SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5210GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
-extern uint32_t ar5210GetRxDP(struct ath_hal *);
-extern void ar5210SetRxDP(struct ath_hal *, uint32_t rxdp);
+extern uint32_t ar5210GetRxDP(struct ath_hal *, HAL_RX_QUEUE);
+extern void ar5210SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE);
extern void ar5210EnableReceive(struct ath_hal *);
extern HAL_BOOL ar5210StopDmaReceive(struct ath_hal *);
extern void ar5210StartPcuReceive(struct ath_hal *);
@@ -249,6 +255,11 @@
extern HAL_BOOL ar5210GetDiagState(struct ath_hal *ah, int request,
const void *args, uint32_t argsize,
void **result, uint32_t *resultsize);
+extern uint32_t ar5210Get11nExtBusy(struct ath_hal *);
+extern HAL_BOOL ar5210GetMibCycleCounts(struct ath_hal *,
+ HAL_SURVEY_SAMPLE *);
+extern void ar5210EnableDfs(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5210GetDfsThresh(struct ath_hal *, HAL_PHYERR_PARAM *);
extern u_int ar5210GetKeyCacheSize(struct ath_hal *);
extern HAL_BOOL ar5210IsKeyCacheEntryValid(struct ath_hal *, uint16_t);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
--- a/head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c 230791 2012-01-30 23:07:27Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c 238607 2012-07-19 02:25:14Z adrian $
*/
#include "opt_ah.h"
@@ -33,7 +33,8 @@
static HAL_BOOL ar5210GetChipPowerLimits(struct ath_hal *ah,
struct ieee80211_channel *chan);
-static void ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_on);
static void ar5210DisablePCIE(struct ath_hal *ah);
static const struct ath_hal_private ar5210hal = {{
@@ -74,6 +75,9 @@
.ah_getTxIntrQueue = ar5210GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5210IntrReqTxDesc,
.ah_getTxCompletionRates = ar5210GetTxCompletionRates,
+ .ah_setTxDescLink = ar5210SetTxDescLink,
+ .ah_getTxDescLink = ar5210GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5210GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5210GetRxDP,
@@ -129,8 +133,14 @@
.ah_getAckCTSRate = ar5210GetAckCTSRate,
.ah_setCTSTimeout = ar5210SetCTSTimeout,
.ah_getCTSTimeout = ar5210GetCTSTimeout,
- .ah_setDecompMask = ar5210SetDecompMask,
- .ah_setCoverageClass = ar5210SetCoverageClass,
+ .ah_setDecompMask = ar5210SetDecompMask,
+ .ah_setCoverageClass = ar5210SetCoverageClass,
+ .ah_get11nExtBusy = ar5210Get11nExtBusy,
+ .ah_getMibCycleCounts = ar5210GetMibCycleCounts,
+ .ah_enableDfs = ar5210EnableDfs,
+ .ah_getDfsThresh = ar5210GetDfsThresh,
+ /* XXX procRadarEvent */
+ /* XXX isFastClockEnabled */
/* Key Cache Functions */
.ah_getKeyCacheSize = ar5210GetKeyCacheSize,
@@ -326,7 +336,7 @@
}
static void
-ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
--- a/head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c 217684 2011-01-21 05:21:00Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c 235206 2012-05-09 18:17:01Z adrian $
*/
#include "opt_ah.h"
@@ -646,3 +646,34 @@
return ath_hal_getdiagstate(ah, request,
args, argsize, result, resultsize);
}
+
+/*
+ * Return what percentage of the extension channel is busy.
+ * This is always disabled for AR5210 series NICs.
+ */
+uint32_t
+ar5210Get11nExtBusy(struct ath_hal *ah)
+{
+
+ return (0);
+}
+
+/*
+ * There's no channel survey support for the AR5210.
+ */
+HAL_BOOL
+ar5210GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+
+ return (AH_FALSE);
+}
+
+void
+ar5210EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+void
+ar5210GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c
--- a/head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 204644 2010-03-03 17:32:32Z rpaulo $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 238278 2012-07-09 07:19:11Z adrian $
*/
#include "opt_ah.h"
@@ -30,8 +30,10 @@
* Get the RXDP.
*/
uint32_t
-ar5210GetRxDP(struct ath_hal *ah)
+ar5210GetRxDP(struct ath_hal *ah, HAL_RX_QUEUE qtype)
{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
return OS_REG_READ(ah, AR_RXDP);
}
@@ -39,8 +41,10 @@
* Set the RxDP.
*/
void
-ar5210SetRxDP(struct ath_hal *ah, uint32_t rxdp)
+ar5210SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
OS_REG_WRITE(ah, AR_RXDP, rxdp);
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
--- a/head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c 217621 2011-01-20 05:49:15Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c 238607 2012-07-19 02:25:14Z adrian $
*/
#include "opt_ah.h"
@@ -630,3 +630,36 @@
{
return AH_FALSE;
}
+
+/*
+ * Set the TX descriptor link pointer
+ */
+void
+ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ ads->ds_link = link;
+}
+
+/*
+ * Get the TX descriptor link pointer
+ */
+void
+ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+/*
+ * Get a pointer to the TX descriptor link pointer
+ */
+void
+ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5210_desc *ads = AR5210DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5211/ar5211.h
--- a/head/sys/dev/ath/ath_hal/ar5211/ar5211.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5211/ar5211.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211.h 225444 2011-09-08 01:23:05Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211.h 238607 2012-07-19 02:25:14Z adrian $
*/
#ifndef _ATH_AR5211_H_
#define _ATH_AR5211_H_
@@ -204,9 +204,15 @@
extern void ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
extern HAL_BOOL ar5211GetTxCompletionRates(struct ath_hal *ah,
const struct ath_desc *ds0, int *rates, int *tries);
+extern void ar5211SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5211GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
-extern uint32_t ar5211GetRxDP(struct ath_hal *);
-extern void ar5211SetRxDP(struct ath_hal *, uint32_t rxdp);
+extern uint32_t ar5211GetRxDP(struct ath_hal *, HAL_RX_QUEUE);
+extern void ar5211SetRxDP(struct ath_hal *, uint32_t rxdp, HAL_RX_QUEUE);
extern void ar5211EnableReceive(struct ath_hal *);
extern HAL_BOOL ar5211StopDmaReceive(struct ath_hal *);
extern void ar5211StartPcuReceive(struct ath_hal *);
@@ -276,6 +282,11 @@
extern HAL_BOOL ar5211GetDiagState(struct ath_hal *ah, int request,
const void *args, uint32_t argsize,
void **result, uint32_t *resultsize);
+extern uint32_t ar5211Get11nExtBusy(struct ath_hal *);
+extern HAL_BOOL ar5211GetMibCycleCounts(struct ath_hal *,
+ HAL_SURVEY_SAMPLE *);
+extern void ar5211EnableDfs(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5211GetDfsThresh(struct ath_hal *, HAL_PHYERR_PARAM *);
extern u_int ar5211GetKeyCacheSize(struct ath_hal *);
extern HAL_BOOL ar5211IsKeyCacheEntryValid(struct ath_hal *, uint16_t);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
--- a/head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c 230791 2012-01-30 23:07:27Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c 238607 2012-07-19 02:25:14Z adrian $
*/
#include "opt_ah.h"
@@ -33,7 +33,8 @@
static HAL_BOOL ar5211GetChipPowerLimits(struct ath_hal *ah,
struct ieee80211_channel *chan);
-static void ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
static void ar5211DisablePCIE(struct ath_hal *ah);
static const struct ath_hal_private ar5211hal = {{
@@ -74,6 +75,9 @@
.ah_getTxIntrQueue = ar5211GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5211IntrReqTxDesc,
.ah_getTxCompletionRates = ar5211GetTxCompletionRates,
+ .ah_setTxDescLink = ar5211SetTxDescLink,
+ .ah_getTxDescLink = ar5211GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5211GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5211GetRxDP,
@@ -129,8 +133,14 @@
.ah_getAckCTSRate = ar5211GetAckCTSRate,
.ah_setCTSTimeout = ar5211SetCTSTimeout,
.ah_getCTSTimeout = ar5211GetCTSTimeout,
- .ah_setDecompMask = ar5211SetDecompMask,
- .ah_setCoverageClass = ar5211SetCoverageClass,
+ .ah_setDecompMask = ar5211SetDecompMask,
+ .ah_setCoverageClass = ar5211SetCoverageClass,
+ .ah_get11nExtBusy = ar5211Get11nExtBusy,
+ .ah_getMibCycleCounts = ar5211GetMibCycleCounts,
+ .ah_enableDfs = ar5211EnableDfs,
+ .ah_getDfsThresh = ar5211GetDfsThresh,
+ /* XXX procRadarEvent */
+ /* XXX isFastClockEnabled */
/* Key Cache Functions */
.ah_getKeyCacheSize = ar5211GetKeyCacheSize,
@@ -449,7 +459,7 @@
}
static void
-ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c
--- a/head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c 217684 2011-01-21 05:21:00Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c 235206 2012-05-09 18:17:01Z adrian $
*/
#include "opt_ah.h"
@@ -688,3 +688,34 @@
}
return AH_FALSE;
}
+
+/*
+ * Return what percentage of the extension channel is busy.
+ * This is always disabled for AR5211 series NICs.
+ */
+uint32_t
+ar5211Get11nExtBusy(struct ath_hal *ah)
+{
+ return (0);
+}
+
+
+/*
+ * There's no channel survey support for the AR5211.
+ */
+HAL_BOOL
+ar5211GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+
+ return (AH_FALSE);
+}
+
+void
+ar5211EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+void
+ar5211GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c
--- a/head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c 204644 2010-03-03 17:32:32Z rpaulo $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c 238278 2012-07-09 07:19:11Z adrian $
*/
#include "opt_ah.h"
@@ -30,8 +30,10 @@
* Get the RXDP.
*/
uint32_t
-ar5211GetRxDP(struct ath_hal *ah)
+ar5211GetRxDP(struct ath_hal *ah, HAL_RX_QUEUE qtype)
{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
return OS_REG_READ(ah, AR_RXDP);
}
@@ -39,8 +41,10 @@
* Set the RxDP.
*/
void
-ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp)
+ar5211SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
OS_REG_WRITE(ah, AR_RXDP, rxdp);
HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
--- a/head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 223459 2011-06-23 02:38:36Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 238607 2012-07-19 02:25:14Z adrian $
*/
#include "opt_ah.h"
@@ -671,3 +671,27 @@
return AH_FALSE;
}
+
+void
+ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ ads->ds_link = link;
+}
+
+void
+ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+void
+ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5211_desc *ads = AR5211DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5212/ar5212.h
--- a/head/sys/dev/ath/ath_hal/ar5212/ar5212.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5212/ar5212.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212.h 230791 2012-01-30 23:07:27Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212.h 238607 2012-07-19 02:25:14Z adrian $
*/
#ifndef _ATH_AR5212_H_
#define _ATH_AR5212_H_
@@ -320,6 +320,7 @@
struct ar5212AniParams ah_aniParams5; /* 5GHz parameters */
struct ar5212AniState *ah_curani; /* cached last reference */
struct ar5212AniState ah_ani[AH_MAXCHAN]; /* per-channel state */
+ HAL_CHANNEL_SURVEY ah_chansurvey; /* channel survey */
/* AR5416 uses some of the AR5212 ANI code; these are the ANI methods */
HAL_BOOL (*ah_aniControl) (struct ath_hal *, HAL_ANI_CMD cmd, int param);
@@ -510,14 +511,16 @@
void **result, uint32_t *resultsize);
extern HAL_STATUS ar5212SetQuiet(struct ath_hal *ah, uint32_t period,
uint32_t duration, uint32_t nextStart, HAL_QUIET_FLAG flag);
+extern HAL_BOOL ar5212GetMibCycleCounts(struct ath_hal *,
+ HAL_SURVEY_SAMPLE *);
extern HAL_BOOL ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode,
int setChip);
extern HAL_POWER_MODE ar5212GetPowerMode(struct ath_hal *ah);
extern HAL_BOOL ar5212GetPowerStatus(struct ath_hal *ah);
-extern uint32_t ar5212GetRxDP(struct ath_hal *ath);
-extern void ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp);
+extern uint32_t ar5212GetRxDP(struct ath_hal *ath, HAL_RX_QUEUE);
+extern void ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE);
extern void ar5212EnableReceive(struct ath_hal *ah);
extern HAL_BOOL ar5212StopDmaReceive(struct ath_hal *ah);
extern void ar5212StartPcuReceive(struct ath_hal *ah);
@@ -599,6 +602,12 @@
extern void ar5212IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *);
extern HAL_BOOL ar5212GetTxCompletionRates(struct ath_hal *ah,
const struct ath_desc *ds0, int *rates, int *tries);
+extern void ar5212SetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t link);
+extern void ar5212GetTxDescLink(struct ath_hal *ah, void *ds,
+ uint32_t *link);
+extern void ar5212GetTxDescLinkPtr(struct ath_hal *ah, void *ds,
+ uint32_t **linkptr);
extern const HAL_RATE_TABLE *ar5212GetRateTable(struct ath_hal *, u_int mode);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
--- a/head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c 230791 2012-01-30 23:07:27Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c 238607 2012-07-19 02:25:14Z adrian $
*/
#include "opt_ah.h"
@@ -29,7 +29,8 @@
#define AH_5212_COMMON
#include "ar5212/ar5212.ini"
-static void ar5212ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar5212ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
static void ar5212DisablePCIE(struct ath_hal *ah);
static const struct ath_hal_private ar5212hal = {{
@@ -70,6 +71,9 @@
.ah_getTxIntrQueue = ar5212GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5212IntrReqTxDesc,
.ah_getTxCompletionRates = ar5212GetTxCompletionRates,
+ .ah_setTxDescLink = ar5212SetTxDescLink,
+ .ah_getTxDescLink = ar5212GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5212GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5212GetRxDP,
@@ -125,9 +129,10 @@
.ah_getAckCTSRate = ar5212GetAckCTSRate,
.ah_setCTSTimeout = ar5212SetCTSTimeout,
.ah_getCTSTimeout = ar5212GetCTSTimeout,
- .ah_setDecompMask = ar5212SetDecompMask,
- .ah_setCoverageClass = ar5212SetCoverageClass,
+ .ah_setDecompMask = ar5212SetDecompMask,
+ .ah_setCoverageClass = ar5212SetCoverageClass,
.ah_setQuiet = ar5212SetQuiet,
+ .ah_getMibCycleCounts = ar5212GetMibCycleCounts,
/* DFS Functions */
.ah_enableDfs = ar5212EnableDfs,
@@ -369,7 +374,7 @@
if (AH_PRIVATE(ah)->ah_ispcie) {
/* XXX: build flag to disable this? */
- ath_hal_configPCIE(ah, AH_FALSE);
+ ath_hal_configPCIE(ah, AH_FALSE, AH_FALSE);
}
if (!ar5212ChipTest(ah)) {
@@ -665,7 +670,7 @@
* XXX Clean up the magic numbers.
*/
static void
-ar5212ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar5212ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
--- a/head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 230791 2012-01-30 23:07:27Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 234873 2012-05-01 14:48:51Z adrian $
*/
#include "opt_ah.h"
@@ -1090,6 +1090,11 @@
return AH_FALSE;
return ar5212AniSetParams(ah, args, args);
}
+ break;
+ case HAL_DIAG_CHANSURVEY:
+ *result = &ahp->ah_chansurvey;
+ *resultsize = sizeof(HAL_CHANNEL_SURVEY);
+ return AH_TRUE;
}
return AH_FALSE;
}
@@ -1243,3 +1248,13 @@
{
return 0;
}
+
+/*
+ * There's no channel survey support for the AR5211.
+ */
+HAL_BOOL
+ar5212GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+
+ return (AH_FALSE);
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c
--- a/head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 220423 2011-04-07 13:14:51Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 238278 2012-07-09 07:19:11Z adrian $
*/
#include "opt_ah.h"
@@ -29,8 +29,10 @@
* Get the RXDP.
*/
uint32_t
-ar5212GetRxDP(struct ath_hal *ath)
+ar5212GetRxDP(struct ath_hal *ath, HAL_RX_QUEUE qtype)
{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
return OS_REG_READ(ath, AR_RXDP);
}
@@ -38,8 +40,10 @@
* Set the RxDP.
*/
void
-ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp)
+ar5212SetRxDP(struct ath_hal *ah, uint32_t rxdp, HAL_RX_QUEUE qtype)
{
+
+ HALASSERT(qtype == HAL_RX_QUEUE_HP);
OS_REG_WRITE(ah, AR_RXDP, rxdp);
HALASSERT(OS_REG_READ(ah, AR_RXDP) == rxdp);
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
--- a/head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c 234450 2012-04-19 03:26:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c 234774 2012-04-28 22:03:19Z adrian $
*/
#include "opt_ah.h"
@@ -195,6 +195,9 @@
saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM);
} else
saveFrameSeqCount = 0; /* NB: silence compiler */
+
+ /* Blank the channel survey statistics */
+ OS_MEMZERO(&ahp->ah_chansurvey, sizeof(ahp->ah_chansurvey));
#if 0
/*
* XXX disable for now; this appears to sometimes cause OFDM
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
--- a/head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c 226765 2011-10-25 23:28:16Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c 238607 2012-07-19 02:25:14Z adrian $
*/
#include "opt_ah.h"
@@ -971,3 +971,27 @@
return AH_TRUE;
}
+
+void
+ar5212SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ ads->ds_link = link;
+}
+
+void
+ar5212GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ *link = ads->ds_link;
+}
+
+void
+ar5212GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
+{
+ struct ar5212_desc *ads = AR5212DESC(ds);
+
+ *linkptr = &ads->ds_link;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416.h
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416.h 233895 2012-04-04 21:49:49Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416.h 237611 2012-06-26 22:16:53Z adrian $
*/
#ifndef _ATH_AR5416_H_
#define _ATH_AR5416_H_
@@ -132,6 +132,28 @@
int initPDADC;
int ah_need_an_top2_fixup; /* merlin or later chips that may need this workaround */
+
+ /*
+ * Bluetooth coexistence static setup according to the registry
+ */
+ HAL_BT_MODULE ah_btModule; /* Bluetooth module identifier */
+ uint8_t ah_btCoexConfigType; /* BT coex configuration */
+ uint8_t ah_btActiveGpioSelect; /* GPIO pin for BT_ACTIVE */
+ uint8_t ah_btPriorityGpioSelect; /* GPIO pin for BT_PRIORITY */
+ uint8_t ah_wlanActiveGpioSelect; /* GPIO pin for WLAN_ACTIVE */
+ uint8_t ah_btActivePolarity; /* Polarity of BT_ACTIVE */
+ HAL_BOOL ah_btCoexSingleAnt; /* Single or dual antenna configuration */
+ uint8_t ah_btWlanIsolation; /* Isolation between BT and WLAN in dB */
+
+ /*
+ * Bluetooth coexistence runtime settings
+ */
+ HAL_BOOL ah_btCoexEnabled; /* If Bluetooth coexistence is enabled */
+ uint32_t ah_btCoexMode; /* Register setting for AR_BT_COEX_MODE */
+ uint32_t ah_btCoexBTWeight; /* Register setting for AR_BT_COEX_WEIGHT */
+ uint32_t ah_btCoexWLANWeight; /* Register setting for AR_BT_COEX_WEIGHT */
+ uint32_t ah_btCoexMode2; /* Register setting for AR_BT_COEX_MODE2 */
+ uint32_t ah_btCoexFlag; /* Special tuning flags for BT coex */
};
#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
@@ -173,6 +195,21 @@
const HAL_BEACON_STATE *);
extern uint64_t ar5416GetNextTBTT(struct ath_hal *);
+/* ar5416_btcoex.c */
+extern void ar5416SetBTCoexInfo(struct ath_hal *ah,
+ HAL_BT_COEX_INFO *btinfo);
+extern void ar5416BTCoexConfig(struct ath_hal *ah,
+ HAL_BT_COEX_CONFIG *btconf);
+extern void ar5416BTCoexSetQcuThresh(struct ath_hal *ah, int qnum);
+extern void ar5416BTCoexSetWeights(struct ath_hal *ah, uint32_t stompType);
+extern void ar5416BTCoexSetupBmissThresh(struct ath_hal *ah,
+ uint32_t thresh);
+extern void ar5416BTCoexSetParameter(struct ath_hal *ah, uint32_t type,
+ uint32_t value);
+extern void ar5416BTCoexDisable(struct ath_hal *ah);
+extern int ar5416BTCoexEnable(struct ath_hal *ah);
+extern void ar5416InitBTCoex(struct ath_hal *ah);
+
extern HAL_BOOL ar5416EepromRead(struct ath_hal *, u_int off, uint16_t *data);
extern HAL_BOOL ar5416EepromWrite(struct ath_hal *, u_int off, uint16_t data);
@@ -196,9 +233,8 @@
extern HAL_BOOL ar5416SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING);
extern HAL_BOOL ar5416SetDecompMask(struct ath_hal *, uint16_t, int);
extern void ar5416SetCoverageClass(struct ath_hal *, uint8_t, int);
-extern uint32_t ar5416GetMibCycleCountsPct(struct ath_hal *ah,
- uint32_t *rxc_pcnt, uint32_t *rxextc_pcnt, uint32_t *rxf_pcnt,
- uint32_t *txf_pcnt);
+extern HAL_BOOL ar5416GetMibCycleCounts(struct ath_hal *ah,
+ HAL_SURVEY_SAMPLE *hsample);
extern uint32_t ar5416Get11nExtBusy(struct ath_hal *ah);
extern void ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode);
extern HAL_HT_RXCLEAR ar5416Get11nRxClear(struct ath_hal *ah);
@@ -234,6 +270,7 @@
extern uint32_t ar5416GetRxFilter(struct ath_hal *ah);
extern void ar5416SetRxFilter(struct ath_hal *ah, uint32_t bits);
+extern HAL_BOOL ar5416StopDmaReceive(struct ath_hal *ah);
extern void ar5416StartPcuReceive(struct ath_hal *ah);
extern void ar5416StopPcuReceive(struct ath_hal *ah);
extern HAL_BOOL ar5416SetupRxDesc(struct ath_hal *,
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c 227468 2011-11-12 16:47:23Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c 234873 2012-05-01 14:48:51Z adrian $
*/
#include "opt_ah.h"
@@ -804,21 +804,50 @@
* deducting the cycles spent tx'ing and rx'ing from the total
* cycle count since our last call. A return value <0 indicates
* an invalid/inconsistent time.
+ *
+ * This may be called with ANI disabled; in which case simply keep
+ * the statistics and don't write to the aniState pointer.
+ *
+ * XXX TODO: Make this cleaner!
*/
static int32_t
ar5416AniGetListenTime(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
- struct ar5212AniState *aniState;
- uint32_t rxc_pct, extc_pct, rxf_pct, txf_pct;
- int32_t listenTime;
+ struct ar5212AniState *aniState = NULL;
+ int32_t listenTime = 0;
int good;
+ HAL_SURVEY_SAMPLE hs;
+ HAL_CHANNEL_SURVEY *cs = AH_NULL;
- good = ar5416GetMibCycleCountsPct(ah,
- &rxc_pct, &extc_pct, &rxf_pct, &txf_pct);
+ /*
+ * We shouldn't see ah_curchan be NULL, but just in case..
+ */
+ if (AH_PRIVATE(ah)->ah_curchan == AH_NULL) {
+ ath_hal_printf(ah, "%s: ah_curchan = NULL?\n", __func__);
+ return (0);
+ }
- aniState = ahp->ah_curani;
- if (good == 0) {
+ cs = &ahp->ah_chansurvey;
+
+ /*
+ * Fetch the current statistics, squirrel away the current
+ * sample, bump the sequence/sample counter.
+ */
+ OS_MEMZERO(&hs, sizeof(hs));
+ good = ar5416GetMibCycleCounts(ah, &hs);
+ if (cs != AH_NULL) {
+ OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs));
+ cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
+ cs->cur_sample =
+ (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
+ cs->cur_seq++;
+ }
+
+ if (ANI_ENA(ah))
+ aniState = ahp->ah_curani;
+
+ if (good == AH_FALSE) {
/*
* Cycle counter wrap (or initial call); it's not possible
* to accurately calculate a value because the registers
@@ -826,18 +855,28 @@
*/
listenTime = 0;
ahp->ah_stats.ast_ani_lzero++;
- } else {
- int32_t ccdelta = AH5416(ah)->ah_cycleCount - aniState->cycleCount;
- int32_t rfdelta = AH5416(ah)->ah_rxBusy - aniState->rxFrameCount;
- int32_t tfdelta = AH5416(ah)->ah_txBusy - aniState->txFrameCount;
+ } else if (ANI_ENA(ah)) {
+ /*
+ * Only calculate and update the cycle count if we have
+ * an ANI state.
+ */
+ int32_t ccdelta =
+ AH5416(ah)->ah_cycleCount - aniState->cycleCount;
+ int32_t rfdelta =
+ AH5416(ah)->ah_rxBusy - aniState->rxFrameCount;
+ int32_t tfdelta =
+ AH5416(ah)->ah_txBusy - aniState->txFrameCount;
listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
}
- aniState->cycleCount = AH5416(ah)->ah_cycleCount;
- aniState->txFrameCount = AH5416(ah)->ah_rxBusy;
- aniState->rxFrameCount = AH5416(ah)->ah_txBusy;
- HALDEBUG(ah, HAL_DEBUG_ANI, "rxc=%d, extc=%d, rxf=%d, txf=%d\n",
- rxc_pct, extc_pct, rxf_pct, txf_pct);
+ /*
+ * Again, only update ANI state if we have it.
+ */
+ if (ANI_ENA(ah)) {
+ aniState->cycleCount = AH5416(ah)->ah_cycleCount;
+ aniState->txFrameCount = AH5416(ah)->ah_rxBusy;
+ aniState->rxFrameCount = AH5416(ah)->ah_txBusy;
+ }
return listenTime;
}
@@ -902,13 +941,13 @@
const struct ar5212AniParams *params;
int32_t listenTime;
+ /* Always update from the MIB, for statistics gathering */
+ listenTime = ar5416AniGetListenTime(ah);
+
/* XXX can aniState be null? */
if (aniState == AH_NULL)
return;
- /* Always update from the MIB, for statistics gathering */
- listenTime = ar5416AniGetListenTime(ah);
-
if (!ANI_ENA(ah))
return;
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c 231368 2012-02-10 09:58:20Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c 236017 2012-05-25 17:53:57Z adrian $
*/
#include "opt_ah.h"
@@ -30,7 +30,9 @@
#include "ar5416/ar5416.ini"
-static void ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
+static void ar5416DisablePCIE(struct ath_hal *ah);
static void ar5416WriteIni(struct ath_hal *ah,
const struct ieee80211_channel *chan);
static void ar5416SpurMitigate(struct ath_hal *ah,
@@ -99,6 +101,7 @@
ah->ah_phyDisable = ar5416PhyDisable;
ah->ah_disable = ar5416Disable;
ah->ah_configPCIE = ar5416ConfigPCIE;
+ ah->ah_disablePCIE = ar5416DisablePCIE;
ah->ah_perCalibration = ar5416PerCalibration;
ah->ah_perCalibrationN = ar5416PerCalibrationN,
ah->ah_resetCalValid = ar5416ResetCalValid,
@@ -119,6 +122,7 @@
/* Receive Functions */
ah->ah_getRxFilter = ar5416GetRxFilter;
ah->ah_setRxFilter = ar5416SetRxFilter;
+ ah->ah_stopDmaReceive = ar5416StopDmaReceive;
ah->ah_startPcuReceive = ar5416StartPcuReceive;
ah->ah_stopPcuReceive = ar5416StopPcuReceive;
ah->ah_setupRxDesc = ar5416SetupRxDesc;
@@ -144,6 +148,7 @@
ah->ah_setDecompMask = ar5416SetDecompMask;
ah->ah_setCoverageClass = ar5416SetCoverageClass;
ah->ah_setQuiet = ar5416SetQuiet;
+ ah->ah_getMibCycleCounts = ar5416GetMibCycleCounts;
ah->ah_resetKeyCacheEntry = ar5416ResetKeyCacheEntry;
ah->ah_setKeyCacheEntry = ar5416SetKeyCacheEntry;
@@ -455,22 +460,73 @@
ar5416AttachPCIE(struct ath_hal *ah)
{
if (AH_PRIVATE(ah)->ah_ispcie)
- ath_hal_configPCIE(ah, AH_FALSE);
+ ath_hal_configPCIE(ah, AH_FALSE, AH_FALSE);
else
ath_hal_disablePCIE(ah);
}
static void
-ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar5416ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
- if (AH_PRIVATE(ah)->ah_ispcie && !restore) {
+
+ /* This is only applicable for AR5418 (AR5416 PCIe) */
+ if (! AH_PRIVATE(ah)->ah_ispcie)
+ return;
+
+ if (! restore) {
ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0);
OS_DELAY(1000);
+ }
+
+ if (power_off) { /* Power-off */
+ /* clear bit 19 to disable L1 */
+ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+ } else { /* Power-on */
+ /* Set default WAR values for Owl */
+ OS_REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
+
+ /* set bit 19 to allow forcing of pcie core into L1 state */
OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
- OS_REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
}
}
+/*
+ * Disable PCIe PHY if PCIe isn't used.
+ */
+static void
+ar5416DisablePCIE(struct ath_hal *ah)
+{
+
+ /* PCIe? Don't */
+ if (AH_PRIVATE(ah)->ah_ispcie)
+ return;
+
+ /* .. Only applicable for AR5416v2 or later */
+ if (! (AR_SREV_OWL(ah) && AR_SREV_OWL_20_OR_LATER(ah)))
+ return;
+
+ OS_REG_WRITE_BUFFER_ENABLE(ah);
+
+ /*
+ * Disable the PCIe PHY.
+ */
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ OS_REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
+
+ /* Load the new settings */
+ OS_REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+ OS_REG_WRITE_BUFFER_FLUSH(ah);
+ OS_REG_WRITE_BUFFER_DISABLE(ah);
+}
+
static void
ar5416WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
@@ -581,6 +637,8 @@
AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+ OS_REG_WRITE_BUFFER_ENABLE(ah);
+
OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), new);
new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
@@ -765,6 +823,9 @@
| (mask_p[47] << 2) | (mask_p[46] << 0);
OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+
+ OS_REG_WRITE_BUFFER_FLUSH(ah);
+ OS_REG_WRITE_BUFFER_DISABLE(ah);
}
/*
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Atheros Communications, Inc.
+ * Copyright (c) 2008-2010, Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c 237611 2012-06-26 22:16:53Z adrian $
+ */
+
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+#ifdef AH_DEBUG
+#include "ah_desc.h" /* NB: for HAL_PHYERR* */
+#endif
+
+#include "ar5416/ar5416.h"
+#include "ar5416/ar5416reg.h"
+#include "ar5416/ar5416phy.h"
+#include "ar5416/ar5416desc.h" /* AR5416_CONTTXMODE */
+#include "ar5416/ar5416_btcoex.h"
+
+void
+ar5416SetBTCoexInfo(struct ath_hal *ah, HAL_BT_COEX_INFO *btinfo)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ahp->ah_btModule = btinfo->bt_module;
+ ahp->ah_btCoexConfigType = btinfo->bt_coex_config;
+ ahp->ah_btActiveGpioSelect = btinfo->bt_gpio_bt_active;
+ ahp->ah_btPriorityGpioSelect = btinfo->bt_gpio_bt_priority;
+ ahp->ah_wlanActiveGpioSelect = btinfo->bt_gpio_wlan_active;
+ ahp->ah_btActivePolarity = btinfo->bt_active_polarity;
+ ahp->ah_btCoexSingleAnt = btinfo->bt_single_ant;
+ ahp->ah_btWlanIsolation = btinfo->bt_isolation;
+}
+
+void
+ar5416BTCoexConfig(struct ath_hal *ah, HAL_BT_COEX_CONFIG *btconf)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ HAL_BOOL rxClearPolarity = btconf->bt_rxclear_polarity;
+
+ /*
+ * For Kiwi and Osprey, the polarity of rx_clear is active high.
+ * The bt_rxclear_polarity flag from ath(4) needs to be inverted.
+ */
+ if (AR_SREV_KIWI(ah)) {
+ rxClearPolarity = !btconf->bt_rxclear_polarity;
+ }
+
+ ahp->ah_btCoexMode = (ahp->ah_btCoexMode & AR_BT_QCU_THRESH) |
+ SM(btconf->bt_time_extend, AR_BT_TIME_EXTEND) |
+ SM(btconf->bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
+ SM(btconf->bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
+ SM(btconf->bt_mode, AR_BT_MODE) |
+ SM(btconf->bt_quiet_collision, AR_BT_QUIET) |
+ SM(rxClearPolarity, AR_BT_RX_CLEAR_POLARITY) |
+ SM(btconf->bt_priority_time, AR_BT_PRIORITY_TIME) |
+ SM(btconf->bt_first_slot_time, AR_BT_FIRST_SLOT_TIME);
+
+ ahp->ah_btCoexMode2 |= SM(btconf->bt_hold_rxclear,
+ AR_BT_HOLD_RX_CLEAR);
+
+ if (ahp->ah_btCoexSingleAnt == AH_FALSE) {
+ /* Enable ACK to go out even though BT has higher priority. */
+ ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
+ }
+}
+
+void
+ar5416BTCoexSetQcuThresh(struct ath_hal *ah, int qnum)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ahp->ah_btCoexMode |= SM(qnum, AR_BT_QCU_THRESH);
+}
+
+void
+ar5416BTCoexSetWeights(struct ath_hal *ah, u_int32_t stompType)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (AR_SREV_KIWI_10_OR_LATER(ah)) {
+ /* TODO: TX RX seperate is not enabled. */
+ switch (stompType) {
+ case HAL_BT_COEX_STOMP_ALL:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_LOW:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_ALL_FORCE:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight =
+ AR5416_STOMP_ALL_FORCE_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_LOW_FORCE:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight =
+ AR5416_STOMP_LOW_FORCE_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_NONE:
+ case HAL_BT_COEX_NO_STOMP:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT;
+ break;
+ default:
+ /* There is a forceWeight from registry */
+ ahp->ah_btCoexBTWeight = stompType & 0xffff;
+ ahp->ah_btCoexWLANWeight = stompType >> 16;
+ break;
+ }
+ } else {
+ switch (stompType) {
+ case HAL_BT_COEX_STOMP_ALL:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight = AR5416_STOMP_ALL_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_LOW:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight = AR5416_STOMP_LOW_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_ALL_FORCE:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight =
+ AR5416_STOMP_ALL_FORCE_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_LOW_FORCE:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight =
+ AR5416_STOMP_LOW_FORCE_WLAN_WGHT;
+ break;
+ case HAL_BT_COEX_STOMP_NONE:
+ case HAL_BT_COEX_NO_STOMP:
+ ahp->ah_btCoexBTWeight = AR5416_BT_WGHT;
+ ahp->ah_btCoexWLANWeight = AR5416_STOMP_NONE_WLAN_WGHT;
+ break;
+ default:
+ /* There is a forceWeight from registry */
+ ahp->ah_btCoexBTWeight = stompType & 0xffff;
+ ahp->ah_btCoexWLANWeight = stompType >> 16;
+ break;
+ }
+ }
+}
+
+void
+ar5416BTCoexSetupBmissThresh(struct ath_hal *ah, u_int32_t thresh)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ahp->ah_btCoexMode2 |= SM(thresh, AR_BT_BCN_MISS_THRESH);
+}
+
+/*
+ * There is no antenna diversity for Owl, Kiwi, etc.
+ *
+ * Kite will override this particular method.
+ */
+static void
+ar5416BTCoexAntennaDiversity(struct ath_hal *ah)
+{
+}
+
+void
+ar5416BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ switch (type) {
+ case HAL_BT_COEX_SET_ACK_PWR:
+ if (value) {
+ ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOW_ACK_PWR;
+ OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
+ } else {
+ ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOW_ACK_PWR;
+ OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
+ }
+ break;
+ case HAL_BT_COEX_ANTENNA_DIVERSITY:
+ /* This is overridden for Kite */
+ break;
+#if 0
+ case HAL_BT_COEX_LOWER_TX_PWR:
+ if (value) {
+ if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) == 0) {
+ ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_LOWER_TX_PWR;
+ AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 1;
+ ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0);
+ }
+ }
+ else {
+ if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOWER_TX_PWR) {
+ ahp->ah_btCoexFlag &= ~HAL_BT_COEX_FLAG_LOWER_TX_PWR;
+ AH_PRIVATE(ah)->ah_config.ath_hal_desc_tpc = 0;
+ ar5416SetTxPowerLimit(ah, AH_PRIVATE(ah)->ah_power_limit, AH_PRIVATE(ah)->ah_extra_txpow, 0);
+ }
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void
+ar5416BTCoexDisable(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ /* Always drive rx_clear_external output as 0 */
+ ar5416GpioSet(ah, ahp->ah_wlanActiveGpioSelect, 0);
+ ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
+ HAL_GPIO_OUTPUT_MUX_AS_OUTPUT);
+
+ if (AR_SREV_9271(ah)) {
+ /*
+ * Set wlanActiveGpio to input when disabling BT-COEX to
+ * reduce power consumption
+ */
+ ar5416GpioCfgInput(ah, ahp->ah_wlanActiveGpioSelect);
+ }
+
+ if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
+ OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE,
+ 1);
+ OS_REG_RMW_FIELD(ah, AR_MISC_MODE, AR_PCU_BT_ANT_PREVENT_RX,
+ 0);
+ }
+
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
+ OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+ if (AR_SREV_KIWI_10_OR_LATER(ah))
+ OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2, 0);
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+
+ ahp->ah_btCoexEnabled = AH_FALSE;
+}
+
+int
+ar5416BTCoexEnable(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ /* Program coex mode and weight registers to actually enable coex */
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE, ahp->ah_btCoexMode);
+ OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT,
+ SM(ahp->ah_btCoexWLANWeight & 0xFFFF, AR_BT_WL_WGHT) |
+ SM(ahp->ah_btCoexBTWeight & 0xFFFF, AR_BT_BT_WGHT));
+ if (AR_SREV_KIWI_10_OR_LATER(ah)) {
+ OS_REG_WRITE(ah, AR_BT_COEX_WEIGHT2,
+ SM(ahp->ah_btCoexWLANWeight >> 16, AR_BT_WL_WGHT));
+ }
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
+
+#if 0
+ /* Added Select GPIO5~8 instaed SPI */
+ if (AR_SREV_9271(ah)) {
+ val = OS_REG_READ(ah, AR9271_CLOCK_CONTROL);
+ val &= 0xFFFFFEFF;
+ OS_REG_WRITE(ah, AR9271_CLOCK_CONTROL, val);
+ }
+#endif
+
+ if (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_LOW_ACK_PWR)
+ OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_LOW_ACK_POWER);
+ else
+ OS_REG_WRITE(ah, AR_TPC, HAL_BT_COEX_HIGH_ACK_POWER);
+
+ if (ahp->ah_btCoexSingleAnt == AH_TRUE) {
+ OS_REG_RMW_FIELD(ah, AR_QUIET1,
+ AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+ /* XXX should update miscMode? */
+ OS_REG_RMW_FIELD(ah, AR_MISC_MODE,
+ AR_PCU_BT_ANT_PREVENT_RX, 1);
+ } else {
+ OS_REG_RMW_FIELD(ah, AR_QUIET1,
+ AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+ /* XXX should update miscMode? */
+ OS_REG_RMW_FIELD(ah, AR_MISC_MODE,
+ AR_PCU_BT_ANT_PREVENT_RX, 0);
+ }
+
+ if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) {
+ /* For 3-wire, configure the desired GPIO port for rx_clear */
+ ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
+ HAL_GPIO_OUTPUT_MUX_AS_WLAN_ACTIVE);
+ } else {
+ /*
+ * For 2-wire, configure the desired GPIO port
+ * for TX_FRAME output
+ */
+ ar5416GpioCfgOutput(ah, ahp->ah_wlanActiveGpioSelect,
+ HAL_GPIO_OUTPUT_MUX_AS_TX_FRAME);
+ }
+
+ /*
+ * Enable a weak pull down on BT_ACTIVE.
+ * When BT device is disabled, BT_ACTIVE might be floating.
+ */
+ OS_REG_RMW(ah, AR_GPIO_PDPU,
+ (0x2 << (ahp->ah_btActiveGpioSelect * 2)),
+ (0x3 << (ahp->ah_btActiveGpioSelect * 2)));
+
+ ahp->ah_btCoexEnabled = AH_TRUE;
+
+ return (0);
+}
+
+void
+ar5416InitBTCoex(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (ahp->ah_btCoexConfigType == HAL_BT_COEX_CFG_3WIRE) {
+ OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
+
+ /*
+ * Set input mux for bt_prority_async and
+ * bt_active_async to GPIO pins
+ */
+ OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ ahp->ah_btActiveGpioSelect);
+ OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_PRIORITY,
+ ahp->ah_btPriorityGpioSelect);
+
+ /*
+ * Configure the desired GPIO ports for input
+ */
+ ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
+ ar5416GpioCfgInput(ah, ahp->ah_btPriorityGpioSelect);
+
+ if (AR_SREV_KITE(ah))
+ ar5416BTCoexAntennaDiversity(ah);
+
+ if (ahp->ah_btCoexEnabled)
+ ar5416BTCoexEnable(ah);
+ else
+ ar5416BTCoexDisable(ah);
+ } else if (ahp->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE) {
+ /* 2-wire */
+ if (ahp->ah_btCoexEnabled) {
+ /* Connect bt_active_async to baseband */
+ OS_REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+ AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
+ OS_REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
+
+ /*
+ * Set input mux for bt_prority_async and
+ * bt_active_async to GPIO pins
+ */
+ OS_REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ ahp->ah_btActiveGpioSelect);
+
+ /* Configure the desired GPIO ports for input */
+ ar5416GpioCfgInput(ah, ahp->ah_btActiveGpioSelect);
+
+ /* Enable coexistence on initialization */
+ ar5416BTCoexEnable(ah);
+ }
+ }
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h 237621 2012-06-27 03:00:29Z adrian $
+ */
+
+#ifndef __ATH_AR5416_BTCOEX_H__
+#define __ATH_AR5416_BTCOEX_H__
+/*
+ * Weight table configurations.
+ */
+#define AR5416_BT_WGHT 0xff55
+#define AR5416_STOMP_ALL_WLAN_WGHT 0xfcfc
+#define AR5416_STOMP_LOW_WLAN_WGHT 0xa8a8
+#define AR5416_STOMP_NONE_WLAN_WGHT 0x0000
+#define AR5416_STOMP_ALL_FORCE_WLAN_WGHT 0xffff // Stomp BT even when WLAN is idle
+#define AR5416_STOMP_LOW_FORCE_WLAN_WGHT 0xaaaa // Stomp BT even when WLAN is idle
+
+#endif /* __ATH_AR5416_BTCOEX_H__ */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 228836 2011-12-23 08:53:22Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 237611 2012-06-26 22:16:53Z adrian $
*/
#include "opt_ah.h"
@@ -85,23 +85,49 @@
{
uint32_t gpio_shift, reg;
+#define N(a) (sizeof(a) / sizeof(a[0]))
+
HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
+ /*
+ * This table maps the HAL GPIO pins to the actual hardware
+ * values.
+ */
+ static const u_int32_t MuxSignalConversionTable[] = {
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT,
+ AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
+ AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
+ AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
+ AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
+ AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL,
+ AR_GPIO_OUTPUT_MUX_AS_TX_FRAME,
+ };
+
HALDEBUG(ah, HAL_DEBUG_GPIO,
"%s: gpio=%d, type=%d\n", __func__, gpio, type);
- /* NB: type maps directly to hardware */
- /* XXX this may not actually be the case, for anything but output */
- cfgOutputMux(ah, gpio, type);
- gpio_shift = gpio << 1; /* 2 bits per output mode */
+ /*
+ * Convert HAL signal type definitions to hardware-specific values.
+ */
+ if (type >= N(MuxSignalConversionTable)) {
+ ath_hal_printf(ah, "%s: mux %d is invalid!\n",
+ __func__,
+ type);
+ return AH_FALSE;
+ }
+ cfgOutputMux(ah, gpio, MuxSignalConversionTable[type]);
+ /* 2 bits per output mode */
+ gpio_shift = gpio << 1;
+
+ /* Always drive, rather than tristate/drive low/drive high */
reg = OS_REG_READ(ah, AR_GPIO_OE_OUT);
reg &= ~(AR_GPIO_OE_OUT_DRV << gpio_shift);
- /* Always drive, rather than tristate/drive low/drive high */
reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift;
OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg);
return AH_TRUE;
+#undef N
}
/*
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 231927 2012-02-20 03:07:07Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 237868 2012-07-01 03:15:18Z adrian $
*/
#include "opt_ah.h"
@@ -184,12 +184,11 @@
/*
* Return the busy for rx_frame, rx_clear, and tx_frame
*/
-uint32_t
-ar5416GetMibCycleCountsPct(struct ath_hal *ah, uint32_t *rxc_pcnt,
- uint32_t *extc_pcnt, uint32_t *rxf_pcnt, uint32_t *txf_pcnt)
+HAL_BOOL
+ar5416GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
{
struct ath_hal_5416 *ahp = AH5416(ah);
- u_int32_t good = 1;
+ u_int32_t good = AH_TRUE;
/* XXX freeze/unfreeze mib counters */
uint32_t rc = OS_REG_READ(ah, AR_RCCNT);
@@ -206,36 +205,34 @@
*/
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: cycle counter wrap. ExtBusy = 0\n", __func__);
- good = 0;
+ good = AH_FALSE;
} else {
- uint32_t cc_d = cc - ahp->ah_cycleCount;
- uint32_t rc_d = rc - ahp->ah_ctlBusy;
- uint32_t ec_d = ec - ahp->ah_extBusy;
- uint32_t rf_d = rf - ahp->ah_rxBusy;
- uint32_t tf_d = tf - ahp->ah_txBusy;
+ hsample->cycle_count = cc - ahp->ah_cycleCount;
+ hsample->chan_busy = rc - ahp->ah_ctlBusy;
+ hsample->ext_chan_busy = ec - ahp->ah_extBusy;
+ hsample->rx_busy = rf - ahp->ah_rxBusy;
+ hsample->tx_busy = tf - ahp->ah_txBusy;
+ }
- if (cc_d != 0) {
- *rxc_pcnt = rc_d * 100 / cc_d;
- *rxf_pcnt = rf_d * 100 / cc_d;
- *txf_pcnt = tf_d * 100 / cc_d;
- *extc_pcnt = ec_d * 100 / cc_d;
- } else {
- good = 0;
- }
- }
+ /*
+ * Keep a copy of the MIB results so the next sample has something
+ * to work from.
+ */
ahp->ah_cycleCount = cc;
ahp->ah_rxBusy = rf;
ahp->ah_ctlBusy = rc;
ahp->ah_txBusy = tf;
ahp->ah_extBusy = ec;
- return good;
+ return (good);
}
/*
* Return approximation of extension channel busy over an time interval
* 0% (clear) -> 100% (busy)
*
+ * XXX TODO: update this to correctly sample all the counters,
+ * rather than a subset of it.
*/
uint32_t
ar5416Get11nExtBusy(struct ath_hal *ah)
@@ -496,36 +493,6 @@
args, argsize, result, resultsize);
}
-typedef struct {
- uint32_t dma_dbg_3;
- uint32_t dma_dbg_4;
- uint32_t dma_dbg_5;
- uint32_t dma_dbg_6;
-} mac_dbg_regs_t;
-
-typedef enum {
- dcu_chain_state = 0x1,
- dcu_complete_state = 0x2,
- qcu_state = 0x4,
- qcu_fsp_ok = 0x8,
- qcu_fsp_state = 0x10,
- qcu_stitch_state = 0x20,
- qcu_fetch_state = 0x40,
- qcu_complete_state = 0x80
-} hal_mac_hangs_t;
-
-typedef struct {
- int states;
- uint8_t dcu_chain_state;
- uint8_t dcu_complete_state;
- uint8_t qcu_state;
- uint8_t qcu_fsp_ok;
- uint8_t qcu_fsp_state;
- uint8_t qcu_stitch_state;
- uint8_t qcu_fetch_state;
- uint8_t qcu_complete_state;
-} hal_mac_hang_check_t;
-
HAL_BOOL
ar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan,
HAL_BOOL enable)
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c 225926 2011-10-02 14:10:25Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c 237626 2012-06-27 05:23:33Z adrian $
*/
#include "opt_ah.h"
@@ -67,6 +67,40 @@
}
/*
+ * Stop Receive at the DMA engine
+ */
+HAL_BOOL
+ar5416StopDmaReceive(struct ath_hal *ah)
+{
+ HAL_BOOL status;
+
+ OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP);
+ OS_REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */
+ if (!ath_hal_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+ OS_MARK(ah, AH_MARK_RX_CTL, AH_MARK_RX_CTL_DMA_STOP_ERR);
+#ifdef AH_DEBUG
+ ath_hal_printf(ah, "%s: dma failed to stop in 10ms\n"
+ "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+ __func__,
+ OS_REG_READ(ah, AR_CR),
+ OS_REG_READ(ah, AR_DIAG_SW));
+#endif
+ status = AH_FALSE;
+ } else {
+ status = AH_TRUE;
+ }
+
+ /*
+ * XXX Is this to flush whatever is in a FIFO somewhere?
+ * XXX If so, what should the correct behaviour should be?
+ */
+ if (AR_SREV_9100(ah))
+ OS_DELAY(3000);
+
+ return (status);
+}
+
+/*
* Start receive at the PCU engine
*/
void
@@ -194,15 +228,40 @@
* Consequently we filter them out here so we don't
* confuse and/or complicate drivers.
*/
+
+ /*
+ * The AR5416 sometimes sets both AR_CRCErr and AR_PHYErr
+ * when reporting radar pulses. In this instance
+ * set HAL_RXERR_PHY as well as HAL_RXERR_CRC and
+ * let the driver layer figure out what to do.
+ *
+ * See PR kern/169362.
+ */
+ if (ads->ds_rxstatus8 & AR_PHYErr) {
+ u_int phyerr;
+
+ /*
+ * Packets with OFDM_RESTART on post delimiter are CRC OK and
+ * usable and MAC ACKs them.
+ * To avoid packet from being lost, we remove the PHY Err flag
+ * so that driver layer does not drop them.
+ */
+ phyerr = MS(ads->ds_rxstatus8, AR_PHYErrCode);
+
+ if ((phyerr == HAL_PHYERR_OFDM_RESTART) &&
+ (ads->ds_rxstatus8 & AR_PostDelimCRCErr)) {
+ ath_hal_printf(ah,
+ "%s: OFDM_RESTART on post-delim CRC error\n",
+ __func__);
+ rs->rs_phyerr = 0;
+ } else {
+ rs->rs_status |= HAL_RXERR_PHY;
+ rs->rs_phyerr = phyerr;
+ }
+ }
if (ads->ds_rxstatus8 & AR_CRCErr)
rs->rs_status |= HAL_RXERR_CRC;
- else if (ads->ds_rxstatus8 & AR_PHYErr) {
- u_int phyerr;
-
- rs->rs_status |= HAL_RXERR_PHY;
- phyerr = MS(ads->ds_rxstatus8, AR_PHYErrCode);
- rs->rs_phyerr = phyerr;
- } else if (ads->ds_rxstatus8 & AR_DecryptCRCErr)
+ else if (ads->ds_rxstatus8 & AR_DecryptCRCErr)
rs->rs_status |= HAL_RXERR_DECRYPT;
else if (ads->ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= HAL_RXERR_MIC;
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 234450 2012-04-19 03:26:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 234774 2012-04-28 22:03:19Z adrian $
*/
#include "opt_ah.h"
@@ -118,6 +118,9 @@
}
HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
+ /* Blank the channel survey statistics */
+ OS_MEMZERO(&ahp->ah_chansurvey, sizeof(ahp->ah_chansurvey));
+
/* XXX Turn on fast channel change for 5416 */
/*
* Preserve the bmiss rssi threshold and count threshold
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,13 +14,49 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h 227468 2011-11-12 16:47:23Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416phy.h 234692 2012-04-26 02:03:16Z adrian $
*/
#ifndef _DEV_ATH_AR5416PHY_H_
#define _DEV_ATH_AR5416PHY_H_
#include "ar5212/ar5212phy.h"
+#define AR_BT_COEX_MODE 0x8170
+#define AR_BT_TIME_EXTEND 0x000000ff
+#define AR_BT_TIME_EXTEND_S 0
+#define AR_BT_TXSTATE_EXTEND 0x00000100
+#define AR_BT_TXSTATE_EXTEND_S 8
+#define AR_BT_TX_FRAME_EXTEND 0x00000200
+#define AR_BT_TX_FRAME_EXTEND_S 9
+#define AR_BT_MODE 0x00000c00
+#define AR_BT_MODE_S 10
+#define AR_BT_QUIET 0x00001000
+#define AR_BT_QUIET_S 12
+#define AR_BT_QCU_THRESH 0x0001e000
+#define AR_BT_QCU_THRESH_S 13
+#define AR_BT_RX_CLEAR_POLARITY 0x00020000
+#define AR_BT_RX_CLEAR_POLARITY_S 17
+#define AR_BT_PRIORITY_TIME 0x00fc0000
+#define AR_BT_PRIORITY_TIME_S 18
+#define AR_BT_FIRST_SLOT_TIME 0xff000000
+#define AR_BT_FIRST_SLOT_TIME_S 24
+
+#define AR_BT_COEX_WEIGHT 0x8174
+#define AR_BT_BT_WGHT 0x0000ffff
+#define AR_BT_BT_WGHT_S 0
+#define AR_BT_WL_WGHT 0xffff0000
+#define AR_BT_WL_WGHT_S 16
+
+#define AR_BT_COEX_MODE2 0x817c
+#define AR_BT_BCN_MISS_THRESH 0x000000ff
+#define AR_BT_BCN_MISS_THRESH_S 0
+#define AR_BT_BCN_MISS_CNT 0x0000ff00
+#define AR_BT_BCN_MISS_CNT_S 8
+#define AR_BT_HOLD_RX_CLEAR 0x00010000
+#define AR_BT_HOLD_RX_CLEAR_S 16
+#define AR_BT_DISABLE_BT_ANT 0x00100000
+#define AR_BT_DISABLE_BT_ANT_S 20
+
/* For AR_PHY_RADAR0 */
#define AR_PHY_RADAR_0_FFT_ENA 0x80000000
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
--- a/head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h 233885 2012-04-04 20:42:32Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416reg.h 236009 2012-05-25 16:45:56Z adrian $
*/
#ifndef _DEV_ATH_AR5416REG_H
#define _DEV_ATH_AR5416REG_H
@@ -47,14 +47,58 @@
#define AR_GPIO_IN_OUT 0x4048 /* GPIO input/output register */
#define AR_GPIO_OE_OUT 0x404c /* GPIO output enable register */
#define AR_GPIO_INTR_POL 0x4050 /* GPIO interrupt polarity */
+
#define AR_GPIO_INPUT_EN_VAL 0x4054 /* GPIO input enable and value */
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2
+#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008
+#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_S 3
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_DEF 0x00000010
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10
+#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_BB 0x00000800
+#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_BB_S 11
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15
+#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000
+#define AR_GPIO_JTAG_DISABLE 0x00020000
+
#define AR_GPIO_INPUT_MUX1 0x4058
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8
+#define AR_GPIO_INPUT_MUX1_BT_FREQUENCY 0x0000f000
+#define AR_GPIO_INPUT_MUX1_BT_FREQUENCY_S 12
+#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000
+#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16
+
#define AR_GPIO_INPUT_MUX2 0x405c
+#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f
+#define AR_GPIO_INPUT_MUX2_CLK25_S 0
+#define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0
+#define AR_GPIO_INPUT_MUX2_RFSILENT_S 4
+#define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00
+#define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8
+
#define AR_GPIO_OUTPUT_MUX1 0x4060
#define AR_GPIO_OUTPUT_MUX2 0x4064
#define AR_GPIO_OUTPUT_MUX3 0x4068
+
+#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
+#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME 3
+#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
+
#define AR_EEPROM_STATUS_DATA 0x407c
#define AR_OBS 0x4080
+#define AR_GPIO_PDPU 0x4088
#ifdef AH_SUPPORT_AR9130
#define AR_RTC_BASE 0x20000
@@ -95,6 +139,7 @@
#define AR_TSFOOR_THRESHOLD 0x813c
#define AR_PHY_ERR_3 0x8168
#define AR_PHY_ERR_MASK_3 0x816c /* mask for AR_PHY_ERR_3 */
+#define AR_BT_COEX_WEIGHT2 0x81c4
#define AR_TXOP_X 0x81ec /* txop for legacy non-qos */
#define AR_TXOP_0_3 0x81f0 /* txop for various tid's */
#define AR_TXOP_4_7 0x81f4
@@ -208,11 +253,15 @@
#define AR_MAC_LED_ASSOC_PEND 0x2 /* STA is trying to associate */
#define AR_MAC_LED_ASSOC_S 10
+#define AR_WA_BIT6 0x00000040
+#define AR_WA_BIT7 0x00000080
+#define AR_WA_D3_L1_DISABLE 0x00004000 /* */
#define AR_WA_UNTIE_RESET_EN 0x00008000 /* ena PCI reset to POR */
#define AR_WA_RESET_EN 0x00040000 /* ena AR_WA_UNTIE_RESET_EN */
#define AR_WA_ANALOG_SHIFT 0x00100000
#define AR_WA_POR_SHORT 0x00200000 /* PCIE phy reset control */
-#define AR_WA_D3_L1_DISABLE 0x00800000 /* bit 23 */
+#define AR_WA_BIT22 0x00400000
+#define AR_WA_BIT23 0x00800000
#define AR_WA_DEFAULT 0x0000073f
#define AR9280_WA_DEFAULT 0x0040073b /* disable bit 2, see commit */
@@ -460,6 +509,8 @@
#define AR_PCU_MISS_BCN_IN_SLEEP 0x00004000 /* count bmiss's when sleeping */
#define AR_PCU_BUG_12306_FIX_ENA 0x00020000 /* use rx_clear to count sifs */
#define AR_PCU_FORCE_QUIET_COLL 0x00040000 /* kill xmit for channel change */
+#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000
+#define AR_PCU_BT_ANT_PREVENT_RX_S 20
#define AR_PCU_TBTT_PROTECT 0x00200000 /* no xmit upto tbtt+20 uS */
#define AR_PCU_CLEAR_VMF 0x01000000 /* clear vmf mode (fast cc)*/
#define AR_PCU_CLEAR_BA_VALID 0x04000000 /* clear ba state */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c
--- a/head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c 234510 2012-04-20 22:07:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c 236039 2012-05-26 01:36:25Z adrian $
*/
#include "opt_ah.h"
@@ -61,7 +61,9 @@
.calPostProc = ar5416AdcDcCalibration
};
-static void ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
+static void ar9280DisablePCIE(struct ath_hal *ah);
static HAL_BOOL ar9280FillCapabilityInfo(struct ath_hal *ah);
static void ar9280WriteIni(struct ath_hal *ah,
const struct ieee80211_channel *chan);
@@ -187,6 +189,7 @@
ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch;
ah->ah_configPCIE = ar9280ConfigPCIE;
+ ah->ah_disablePCIE = ar9280DisablePCIE;
AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal;
AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal;
@@ -415,17 +418,73 @@
}
static void
-ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
+ uint32_t val;
+
if (AH_PRIVATE(ah)->ah_ispcie && !restore) {
ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0);
OS_DELAY(1000);
+ }
+
+
+ /*
+ * Set PCIe workaround bits
+ *
+ * NOTE:
+ *
+ * In Merlin and Kite, bit 14 in WA register (disable L1) should only
+ * be set when device enters D3 and be cleared when device comes back
+ * to D0.
+ */
+ if (power_off) { /* Power-off */
+ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+ val = OS_REG_READ(ah, AR_WA);
+
+ /*
+ * Disable bit 6 and 7 before entering D3 to prevent
+ * system hang.
+ */
+ val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
+
+ /*
+ * XXX Not sure, is specified in the reference HAL.
+ */
+ val |= AR_WA_BIT22;
+
+ /*
+ * See above: set AR_WA_D3_L1_DISABLE when entering D3 state.
+ *
+ * XXX The reference HAL does it this way - it only sets
+ * AR_WA_D3_L1_DISABLE if it's set in AR9280_WA_DEFAULT,
+ * which it (currently) isn't. So the following statement
+ * is currently a NOP.
+ */
+ if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
+ val |= AR_WA_D3_L1_DISABLE;
+
+ OS_REG_WRITE(ah, AR_WA, val);
+ } else { /* Power-on */
+ val = AR9280_WA_DEFAULT;
+
+ /*
+ * See note above: make sure L1_DISABLE is not set.
+ */
+ val &= (~AR_WA_D3_L1_DISABLE);
+ OS_REG_WRITE(ah, AR_WA, val);
+
+ /* set bit 19 to allow forcing of pcie core into L1 state */
OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
- OS_REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
}
}
static void
+ar9280DisablePCIE(struct ath_hal *ah)
+{
+}
+
+static void
ar9280WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
u_int modesIndex, freqIndex;
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9002/ar9285.h
--- a/head/sys/dev/ath/ath_hal/ar9002/ar9285.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar9002/ar9285.h Wed Jul 25 17:07:47 2012 +0300
@@ -13,7 +13,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285.h 221694 2011-05-09 15:19:49Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285.h 237611 2012-06-26 22:16:53Z adrian $
*/
#ifndef _ATH_AR9285_H_
#define _ATH_AR9285_H_
@@ -86,4 +86,9 @@
extern HAL_BOOL ar9285SetBoardValues(struct ath_hal *,
const struct ieee80211_channel *);
+/* ar9285_btcoex.h */
+extern void ar9285BTCoexAntennaDiversity(struct ath_hal *ah);
+extern void ar9285BTCoexSetParameter(struct ath_hal *ah,
+ u_int32_t value, u_int32_t type);
+
#endif /* _ATH_AR9285_H_ */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c
--- a/head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c 234508 2012-04-20 21:56:13Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c 237183 2012-06-17 05:34:41Z adrian $
*/
#include "opt_ah.h"
@@ -66,7 +66,9 @@
.calPostProc = ar5416AdcDcCalibration
};
-static void ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
+static void ar9285DisablePCIE(struct ath_hal *ah);
static HAL_BOOL ar9285FillCapabilityInfo(struct ath_hal *ah);
static void ar9285WriteIni(struct ath_hal *ah,
const struct ieee80211_channel *chan);
@@ -152,6 +154,7 @@
ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch;
ah->ah_configPCIE = ar9285ConfigPCIE;
+ ah->ah_disablePCIE = ar9285DisablePCIE;
ah->ah_setTxPower = ar9285SetTransmitPower;
ah->ah_setBoardValues = ar9285SetBoardValues;
@@ -362,17 +365,95 @@
}
static void
-ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
+ uint32_t val;
+
+ /*
+ * This workaround needs some integration work with the HAL
+ * config parameters and the if_ath_pci.c glue.
+ * Specifically, read the value of the PCI register 0x70c
+ * (4 byte PCI config space register) and store it in ath_hal_war70c.
+ * Then if it's non-zero, the below WAR would override register
+ * 0x570c upon suspend/resume.
+ */
+#if 0
+ if (AR_SREV_9285E_20(ah)) {
+ val = AH_PRIVATE(ah)->ah_config.ath_hal_war70c;
+ if (val) {
+ val &= 0xffff00ff;
+ val |= 0x6f00;
+ OS_REG_WRITE(ah, 0x570c, val);
+ }
+ }
+#endif
+
if (AH_PRIVATE(ah)->ah_ispcie && !restore) {
ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0);
OS_DELAY(1000);
+ }
+
+ /*
+ * Set PCIe workaround bits
+ *
+ * NOTE:
+ *
+ * In Merlin and Kite, bit 14 in WA register (disable L1) should only
+ * be set when device enters D3 and be cleared when device comes back
+ * to D0.
+ */
+ if (power_off) { /* Power-off */
+ OS_REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+ val = OS_REG_READ(ah, AR_WA);
+
+ /*
+ * Disable bit 6 and 7 before entering D3 to prevent
+ * system hang.
+ */
+ val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
+
+ /*
+ * See above: set AR_WA_D3_L1_DISABLE when entering D3 state.
+ *
+ * XXX The reference HAL does it this way - it only sets
+ * AR_WA_D3_L1_DISABLE if it's set in AR9280_WA_DEFAULT,
+ * which it (currently) isn't. So the following statement
+ * is currently a NOP.
+ */
+ if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)
+ val |= AR_WA_D3_L1_DISABLE;
+
+ if (AR_SREV_9285E_20(ah))
+ val |= AR_WA_BIT23;
+
+ OS_REG_WRITE(ah, AR_WA, val);
+ } else { /* Power-on */
+ val = AR9285_WA_DEFAULT;
+ /*
+ * See note above: make sure L1_DISABLE is not set.
+ */
+ val &= (~AR_WA_D3_L1_DISABLE);
+
+ /* Software workaroud for ASPM system hang. */
+ val |= (AR_WA_BIT6 | AR_WA_BIT7);
+
+ if (AR_SREV_9285E_20(ah))
+ val |= AR_WA_BIT23;
+
+ OS_REG_WRITE(ah, AR_WA, val);
+
+ /* set bit 19 to allow forcing of pcie core into L1 state */
OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
- OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
}
}
static void
+ar9285DisablePCIE(struct ath_hal *ah)
+{
+}
+
+static void
ar9285WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
u_int modesIndex, freqIndex;
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2005 Atheros Communications, Inc.
+ * Copyright (c) 2008-2010, Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c 237611 2012-06-26 22:16:53Z adrian $
+ */
+
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+#ifdef AH_DEBUG
+#include "ah_desc.h" /* NB: for HAL_PHYERR* */
+#endif
+
+#include "ar5416/ar5416.h"
+#include "ar5416/ar5416reg.h"
+#include "ar5416/ar5416phy.h"
+#include "ar5416/ar5416desc.h" /* AR5416_CONTTXMODE */
+
+#include "ar9002/ar9285phy.h"
+#include "ar9002/ar9285.h"
+
+/*
+ * This is specific to Kite.
+ *
+ * Kiwi and others don't have antenna diversity like this.
+ */
+void
+ar9285BTCoexAntennaDiversity(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u_int32_t regVal;
+ u_int8_t ant_div_control1, ant_div_control2;
+
+ if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ALLOW) ||
+ (AH5212(ah)->ah_diversity != HAL_ANT_VARIABLE)) {
+ if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ENABLE) &&
+ (AH5212(ah)->ah_diversity == HAL_ANT_VARIABLE)) {
+ /* Enable antenna diversity */
+ ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_ENABLE;
+ ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_ENABLE;
+
+ /* Don't disable BT ant to allow BB to control SWCOM */
+ ahp->ah_btCoexMode2 &= (~(AR_BT_DISABLE_BT_ANT));
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
+
+ /* Program the correct SWCOM table */
+ OS_REG_WRITE(ah, AR_PHY_SWITCH_COM,
+ HAL_BT_COEX_ANT_DIV_SWITCH_COM);
+ OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
+ } else if (AH5212(ah)->ah_diversity == HAL_ANT_FIXED_B) {
+ /* Disable antenna diversity. Use antenna B(LNA2) only. */
+ ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_B;
+ ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_B;
+
+ /* Disable BT ant to allow concurrent BT and WLAN receive */
+ ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
+
+ /* Program SWCOM talbe to make sure RF switch always parks at WLAN side */
+ OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, HAL_BT_COEX_ANT_DIV_SWITCH_COM);
+ OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0x60000000, 0xf0000000);
+ } else {
+ /* Disable antenna diversity. Use antenna A(LNA1) only */
+ ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_A;
+ ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_A;
+
+ /* Disable BT ant to allow concurrent BT and WLAN receive */
+ ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
+ OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
+
+ /* Program SWCOM talbe to make sure RF switch always parks at BT side */
+ OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, 0);
+ OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
+ }
+
+ regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+ regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
+ /* Clear ant_fast_div_bias [14:9] since for Janus the main LNA is always LNA1. */
+ regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
+
+ regVal |= SM(ant_div_control1, AR_PHY_9285_ANT_DIV_CTL);
+ regVal |= SM(ant_div_control2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+ regVal |= SM((ant_div_control2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+ regVal |= SM((ant_div_control1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB);
+ regVal |= SM((ant_div_control1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
+ OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
+
+ regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
+ regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+ regVal |= SM((ant_div_control1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+ OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
+ }
+}
+
+void
+ar9285BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ switch (type) {
+ case HAL_BT_COEX_ANTENNA_DIVERSITY:
+ if (AR_SREV_KITE(ah)) {
+ ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_ANT_DIV_ALLOW;
+ if (value)
+ ahp->ah_btCoexFlag |=
+ HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
+ else
+ ahp->ah_btCoexFlag &=
+ ~HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
+ ar9285BTCoexAntennaDiversity(ah);
+ }
+ break;
+ default:
+ ar5416BTCoexSetParameter(ah, type, value);
+ break;
+ }
+}
+
+
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
--- a/head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c 227387 2011-11-09 14:30:58Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c 235972 2012-05-25 05:01:27Z adrian $
*/
#include "opt_ah.h"
@@ -65,7 +65,9 @@
.calPostProc = ar5416AdcDcCalibration
};
-static void ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore);
+static void ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore,
+ HAL_BOOL power_off);
+static void ar9287DisablePCIE(struct ath_hal *ah);
static HAL_BOOL ar9287FillCapabilityInfo(struct ath_hal *ah);
static void ar9287WriteIni(struct ath_hal *ah,
const struct ieee80211_channel *chan);
@@ -154,6 +156,7 @@
ah->ah_setAntennaSwitch = ar9287SetAntennaSwitch;
ah->ah_configPCIE = ar9287ConfigPCIE;
+ ah->ah_disablePCIE = ar9287DisablePCIE;
AH5416(ah)->ah_cal.iqCalData.calData = &ar9287_iq_cal;
AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9287_adc_gain_cal;
@@ -370,17 +373,24 @@
}
static void
-ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar9287ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
if (AH_PRIVATE(ah)->ah_ispcie && !restore) {
ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0);
OS_DELAY(1000);
OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
- OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); /* Yes, Kiwi uses the Kite PCIe PHY WA */
+ /* Yes, Kiwi uses the Kite PCIe PHY WA */
+ OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
}
}
static void
+ar9287DisablePCIE(struct ath_hal *ah)
+{
+ /* XXX TODO */
+}
+
+static void
ar9287WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
u_int modesIndex, freqIndex;
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c
--- a/head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c Wed Jul 25 17:07:47 2012 +0300
@@ -14,7 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 222424 2011-05-28 15:43:56Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 237184 2012-06-17 05:56:27Z adrian $
*/
#include "opt_ah.h"
@@ -45,70 +45,70 @@
ar9287SetPowerCalTable(struct ath_hal *ah,
const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
{
- struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
- uint8_t *pCalBChans = NULL;
- uint16_t pdGainOverlap_t2;
- uint16_t numPiers = 0, i;
- uint16_t numXpdGain, xpdMask;
- uint16_t xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
- uint32_t regChainOffset;
+ struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
+ uint8_t *pCalBChans = NULL;
+ uint16_t pdGainOverlap_t2;
+ uint16_t numPiers = 0, i;
+ uint16_t numXpdGain, xpdMask;
+ uint16_t xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
+ uint32_t regChainOffset;
HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom;
- struct ar9287_eeprom *pEepData = &ee->ee_base;
+ struct ar9287_eeprom *pEepData = &ee->ee_base;
- xpdMask = pEepData->modalHeader.xpdGain;
+ xpdMask = pEepData->modalHeader.xpdGain;
- if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
- AR9287_EEP_MINOR_VER_2)
- pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
- else
- pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5),
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+ if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+ AR9287_EEP_MINOR_VER_2)
+ pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
+ else
+ pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
/* Note: Kiwi should only be 2ghz.. */
- if (IEEE80211_IS_CHAN_2GHZ(chan)) {
- pCalBChans = pEepData->calFreqPier2G;
- numPiers = AR9287_NUM_2G_CAL_PIERS;
- pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
- AH5416(ah)->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
- }
- numXpdGain = 0;
+ if (IEEE80211_IS_CHAN_2GHZ(chan)) {
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR9287_NUM_2G_CAL_PIERS;
+ pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
+ AH5416(ah)->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
+ }
+ numXpdGain = 0;
- /* Calculate the value of xpdgains from the xpdGain Mask */
- for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
- if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
- if (numXpdGain >= AR5416_NUM_PD_GAINS)
- break;
- xpdGainValues[numXpdGain] =
- (uint16_t)(AR5416_PD_GAINS_IN_MASK-i);
- numXpdGain++;
- }
- }
+ /* Calculate the value of xpdgains from the xpdGain Mask */
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (uint16_t)(AR5416_PD_GAINS_IN_MASK-i);
+ numXpdGain++;
+ }
+ }
- OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
- (numXpdGain - 1) & 0x3);
- OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
- xpdGainValues[0]);
- OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
- xpdGainValues[1]);
- OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
- xpdGainValues[2]);
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
- for (i = 0; i < AR9287_MAX_CHAINS; i++) {
- regChainOffset = i * 0x1000;
+ for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+ regChainOffset = i * 0x1000;
- if (pEepData->baseEepHeader.txMask & (1 << i)) {
- int8_t txPower;
- pRawDatasetOpenLoop =
- (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
- ar9287olcGetTxGainIndex(ah, chan,
- pRawDatasetOpenLoop,
- pCalBChans, numPiers,
- &txPower);
- ar9287olcSetPDADCs(ah, txPower, i);
- }
- }
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ int8_t txPower;
+ pRawDatasetOpenLoop =
+ (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
+ ar9287olcGetTxGainIndex(ah, chan,
+ pRawDatasetOpenLoop,
+ pCalBChans, numPiers,
+ &txPower);
+ ar9287olcSetPDADCs(ah, txPower, i);
+ }
+ }
- *pTxPowerIndexOffset = 0;
+ *pTxPowerIndexOffset = 0;
}
@@ -329,20 +329,20 @@
const struct ieee80211_channel *chan, uint16_t *rfXpdGain)
{
#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
-#define N(a) (sizeof (a) / sizeof (a[0]))
+#define N(a) (sizeof (a) / sizeof (a[0]))
const struct modal_eep_ar9287_header *pModal;
struct ath_hal_5212 *ahp = AH5212(ah);
- int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
- uint8_t ht40PowerIncForPdadc = 2;
- int i;
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ uint8_t ht40PowerIncForPdadc = 2;
+ int i;
- uint16_t cfgCtl;
- uint16_t powerLimit;
- uint16_t twiceAntennaReduction;
- uint16_t twiceMaxRegulatoryPower;
- int16_t maxPower;
+ uint16_t cfgCtl;
+ uint16_t powerLimit;
+ uint16_t twiceAntennaReduction;
+ uint16_t twiceMaxRegulatoryPower;
+ int16_t maxPower;
HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom;
struct ar9287_eeprom *pEepData = &ee->ee_base;
@@ -351,7 +351,8 @@
cfgCtl = ath_hal_getctl(ah, chan);
powerLimit = chan->ic_maxregpower * 2;
twiceAntennaReduction = chan->ic_maxantgain;
- twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit);
+ twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER,
+ AH_PRIVATE(ah)->ah_powerLimit);
pModal = &pEepData->modalHeader;
HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n",
__func__,chan->ic_freq, cfgCtl );
@@ -361,9 +362,9 @@
/* Fetch per-rate power table for the given channel */
if (! ar9287SetPowerPerRateTable(ah, pEepData, chan,
- &ratesArray[0],cfgCtl,
- twiceAntennaReduction,
- twiceMaxRegulatoryPower, powerLimit)) {
+ &ratesArray[0],cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower, powerLimit)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
"%s: unable to set tx power per rate table\n", __func__);
return AH_FALSE;
@@ -476,7 +477,8 @@
pModal->antCtrlChain[i]);
OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset,
- (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset)
+ (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)
+ + regChainOffset)
& ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
SM(pModal->iqCalICh[i],
@@ -500,7 +502,6 @@
pModal->rxTxMarginCh[i]);
}
-
if (IEEE80211_IS_CHAN_HT40(chan))
OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING,
AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
@@ -539,8 +540,8 @@
SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
- OS_REG_WRITE(ah, AR9287_AN_RF2G3_CH0, regval);
- OS_DELAY(100); /* analog write */
+ /* Analog write - requires a 100usec delay */
+ OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH0, regval);
regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH1);
regval &= ~(AR9287_AN_RF2G3_DB1 |
@@ -556,8 +557,7 @@
SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
- OS_REG_WRITE(ah, AR9287_AN_RF2G3_CH1, regval);
- OS_DELAY(100); /* analog write */
+ OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH1, regval);
OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h 237611 2012-06-26 22:16:53Z adrian $
+ */
+
+#ifndef __ATH_AR9300_BTCOEX_H__
+#define __ATH_AR9300_BTCOEX_H__
+/*
+ * Weight table configurations.
+ */
+#define AR9300_BT_WGHT 0xcccc4444
+#define AR9300_STOMP_ALL_WLAN_WGHT0 0xfffffff0
+#define AR9300_STOMP_ALL_WLAN_WGHT1 0xfffffff0
+#define AR9300_STOMP_LOW_WLAN_WGHT0 0x88888880
+#define AR9300_STOMP_LOW_WLAN_WGHT1 0x88888880
+#define AR9300_STOMP_NONE_WLAN_WGHT0 0x00000000
+#define AR9300_STOMP_NONE_WLAN_WGHT1 0x00000000
+/* Stomp BT even when WLAN is idle */
+#define AR9300_STOMP_ALL_FORCE_WLAN_WGHT0 0xffffffff
+#define AR9300_STOMP_ALL_FORCE_WLAN_WGHT1 0xffffffff
+/* Stomp BT even when WLAN is idle */
+#define AR9300_STOMP_LOW_FORCE_WLAN_WGHT0 0x88888888
+#define AR9300_STOMP_LOW_FORCE_WLAN_WGHT1 0x88888888
+
+#define JUPITER_STOMP_ALL_WLAN_WGHT0 0x00007d00
+#define JUPITER_STOMP_ALL_WLAN_WGHT1 0x7d7d7d00
+#define JUPITER_STOMP_ALL_WLAN_WGHT2 0x7d7d7d00
+#define JUPITER_STOMP_ALL_WLAN_WGHT3 0x7d7d7d7d
+#define JUPITER_STOMP_LOW_WLAN_WGHT0 0x00007d00
+#define JUPITER_STOMP_LOW_WLAN_WGHT1 0x7d3b3b00
+#define JUPITER_STOMP_LOW_WLAN_WGHT2 0x3b3b3b00
+#define JUPITER_STOMP_LOW_WLAN_WGHT3 0x3b3b3b3b
+#define JUPITER_STOMP_NONE_WLAN_WGHT0 0x00007d00
+#define JUPITER_STOMP_NONE_WLAN_WGHT1 0x7d000000
+#define JUPITER_STOMP_NONE_WLAN_WGHT2 0x00000000
+#define JUPITER_STOMP_NONE_WLAN_WGHT3 0x00000000
+#define JUPITER_STOMP_ALL_FORCE_WLAN_WGHT0 0x00007d7d
+#define JUPITER_STOMP_ALL_FORCE_WLAN_WGHT1 0x7d7d7d00
+#define JUPITER_STOMP_ALL_FORCE_WLAN_WGHT2 0x7d7d7d7d
+#define JUPITER_STOMP_ALL_FORCE_WLAN_WGHT3 0x7d7d7d7d
+#define JUPITER_STOMP_LOW_FORCE_WLAN_WGHT0 0x00003b3b
+#define JUPITER_STOMP_LOW_FORCE_WLAN_WGHT1 0x3b3b3b00
+#define JUPITER_STOMP_LOW_FORCE_WLAN_WGHT2 0x3b3b3b3b
+#define JUPITER_STOMP_LOW_FORCE_WLAN_WGHT3 0x3b3b3b3b
+
+#endif /* __ATH_AR9300_BTCOEX_H__ */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_rate/amrr/amrr.c
--- a/head/sys/dev/ath/ath_rate/amrr/amrr.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/amrr/amrr.c Wed Jul 25 17:07:47 2012 +0300
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/amrr/amrr.c 227364 2011-11-08 22:43:13Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/amrr/amrr.c 238633 2012-07-20 01:36:02Z adrian $");
/*
* AMRR rate control. See:
@@ -45,6 +45,7 @@
* "IEEE 802.11 Rate Adaptation: A Practical Approach" by
* Mathieu Lacage, Hossein Manshaei, Thierry Turletti
*/
+#include "opt_ath.h"
#include "opt_inet.h"
#include "opt_wlan.h"
@@ -420,6 +421,14 @@
}
}
+static int
+ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *re)
+{
+
+ return (EINVAL);
+}
+
static void
ath_rate_sysctlattach(struct ath_softc *sc)
{
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_rate/onoe/onoe.c
--- a/head/sys/dev/ath/ath_rate/onoe/onoe.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/onoe/onoe.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,11 +28,12 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/onoe/onoe.c 227364 2011-11-08 22:43:13Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/onoe/onoe.c 238633 2012-07-20 01:36:02Z adrian $");
/*
* Atsushi Onoe's rate control algorithm.
*/
+#include "opt_ath.h"
#include "opt_inet.h"
#include "opt_wlan.h"
@@ -406,6 +407,14 @@
"rate control: # good periods before raising rate");
}
+static int
+ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *re)
+{
+
+ return (EINVAL);
+}
+
struct ath_ratectrl *
ath_rate_attach(struct ath_softc *sc)
{
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_rate/sample/sample.c
--- a/head/sys/dev/ath/ath_rate/sample/sample.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/sample/sample.c Wed Jul 25 17:07:47 2012 +0300
@@ -36,11 +36,12 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.c 232170 2012-02-26 06:04:44Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.c 238638 2012-07-20 02:17:48Z adrian $");
/*
* John Bicket's SampleRate control algorithm.
*/
+#include "opt_ath.h"
#include "opt_inet.h"
#include "opt_wlan.h"
#include "opt_ah.h"
@@ -104,8 +105,6 @@
static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
-static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 };
-
static __inline int
size_to_bin(int size)
{
@@ -127,12 +126,6 @@
return NUM_PACKET_SIZE_BINS-1;
}
-static __inline int
-bin_to_size(int index)
-{
- return packet_size_bins[index];
-}
-
void
ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
{
@@ -1197,6 +1190,93 @@
#undef DOT11RATE
}
+/*
+ * Fetch the statistics for the given node.
+ *
+ * The ieee80211 node must be referenced and unlocked, however the ath_node
+ * must be locked.
+ *
+ * The main difference here is that we convert the rate indexes
+ * to 802.11 rates, or the userland output won't make much sense
+ * as it has no access to the rix table.
+ */
+int
+ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *rs)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct ath_rateioctl_tlv av;
+ struct ath_rateioctl_rt *tv;
+ int y;
+ int o = 0;
+
+ ATH_NODE_LOCK_ASSERT(an);
+
+ /*
+ * Ensure there's enough space for the statistics.
+ */
+ if (rs->len <
+ sizeof(struct ath_rateioctl_tlv) +
+ sizeof(struct ath_rateioctl_rt) +
+ sizeof(struct ath_rateioctl_tlv) +
+ sizeof(struct sample_node)) {
+ device_printf(sc->sc_dev, "%s: len=%d, too short\n",
+ __func__,
+ rs->len);
+ return (EINVAL);
+ }
+
+ /*
+ * Take a temporary copy of the sample node state so we can
+ * modify it before we copy it.
+ */
+ tv = malloc(sizeof(struct ath_rateioctl_rt), M_TEMP,
+ M_NOWAIT | M_ZERO);
+ if (tv == NULL) {
+ return (ENOMEM);
+ }
+
+ /*
+ * Populate the rate table mapping TLV.
+ */
+ tv->nentries = rt->rateCount;
+ for (y = 0; y < rt->rateCount; y++) {
+ tv->ratecode[y] = rt->info[y].dot11Rate & IEEE80211_RATE_VAL;
+ if (rt->info[y].phy == IEEE80211_T_HT)
+ tv->ratecode[y] |= IEEE80211_RATE_MCS;
+ }
+
+ o = 0;
+ /*
+ * First TLV - rate code mapping
+ */
+ av.tlv_id = ATH_RATE_TLV_RATETABLE;
+ av.tlv_len = sizeof(struct ath_rateioctl_rt);
+ copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
+ o += sizeof(struct ath_rateioctl_tlv);
+ copyout(tv, rs->buf + o, sizeof(struct ath_rateioctl_rt));
+ o += sizeof(struct ath_rateioctl_rt);
+
+ /*
+ * Second TLV - sample node statistics
+ */
+ av.tlv_id = ATH_RATE_TLV_SAMPLENODE;
+ av.tlv_len = sizeof(struct sample_node);
+ copyout(&av, rs->buf + o, sizeof(struct ath_rateioctl_tlv));
+ o += sizeof(struct ath_rateioctl_tlv);
+
+ /*
+ * Copy the statistics over to the provided buffer.
+ */
+ copyout(sn, rs->buf + o, sizeof(struct sample_node));
+ o += sizeof(struct sample_node);
+
+ free(tv, M_TEMP);
+
+ return (0);
+}
+
static void
sample_stats(void *arg, struct ieee80211_node *ni)
{
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/ath_rate/sample/sample.h
--- a/head/sys/dev/ath/ath_rate/sample/sample.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/sample/sample.h Wed Jul 25 17:07:47 2012 +0300
@@ -33,7 +33,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.h 232170 2012-02-26 06:04:44Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.h 238636 2012-07-20 01:41:18Z adrian $
*/
/*
@@ -79,10 +79,18 @@
*/
#define NUM_PACKET_SIZE_BINS 2
+static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 };
+
+static inline int
+bin_to_size(int index)
+{
+ return packet_size_bins[index];
+}
+
/* per-node state */
struct sample_node {
int static_rix; /* rate index of fixed tx rate */
-#define SAMPLE_MAXRATES 32 /* NB: corresponds to hal info[32] */
+#define SAMPLE_MAXRATES 64 /* NB: corresponds to hal info[32] */
uint32_t ratemask; /* bit mask of valid rate indices */
const struct txschedule *sched; /* tx schedule table */
@@ -101,6 +109,9 @@
int packets_since_sample[NUM_PACKET_SIZE_BINS];
unsigned sample_tt[NUM_PACKET_SIZE_BINS];
};
+
+#ifdef _KERNEL
+
#define ATH_NODE_SAMPLE(an) ((struct sample_node *)&(an)[1])
#define IS_RATE_DEFINED(sn, rix) (((sn)->ratemask & (1<<(rix))) != 0)
@@ -225,4 +236,7 @@
}
return tt;
}
+
+#endif /* _KERNEL */
+
#endif /* _DEV_ATH_RATE_SAMPLE_H */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath.c
--- a/head/sys/dev/ath/if_ath.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath.c 234369 2012-04-17 06:02:41Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath.c 238729 2012-07-23 23:40:13Z adrian $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -102,19 +102,21 @@
#include <dev/ath/if_ath_debug.h>
#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tsf.h>
#include <dev/ath/if_ath_tx.h>
#include <dev/ath/if_ath_sysctl.h>
#include <dev/ath/if_ath_led.h>
#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_rx_edma.h>
+#include <dev/ath/if_ath_tx_edma.h>
+#include <dev/ath/if_ath_beacon.h>
#include <dev/ath/if_athdfs.h>
#ifdef ATH_TX99_DIAG
#include <dev/ath/ath_tx99/ath_tx99.h>
#endif
-#define ATH_KTR_INTR KTR_SPARE4
-#define ATH_KTR_ERR KTR_SPARE3
-
/*
* ATH_BCBUF determines the number of vap's that can transmit
* beacons and also (currently) the number of vap's that can
@@ -139,7 +141,6 @@
static void ath_init(void *);
static void ath_stop_locked(struct ifnet *);
static void ath_stop(struct ifnet *);
-static void ath_start(struct ifnet *);
static int ath_reset_vap(struct ieee80211vap *, u_long);
static int ath_media_change(struct ifnet *);
static void ath_watchdog(void *);
@@ -151,23 +152,9 @@
static void ath_key_update_end(struct ieee80211vap *);
static void ath_update_mcast(struct ifnet *);
static void ath_update_promisc(struct ifnet *);
-static void ath_mode_init(struct ath_softc *);
-static void ath_setslottime(struct ath_softc *);
static void ath_updateslot(struct ifnet *);
-static int ath_beaconq_setup(struct ath_hal *);
-static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
-static void ath_beacon_update(struct ieee80211vap *, int item);
-static void ath_beacon_setup(struct ath_softc *, struct ath_buf *);
-static void ath_beacon_proc(void *, int);
-static struct ath_buf *ath_beacon_generate(struct ath_softc *,
- struct ieee80211vap *);
static void ath_bstuck_proc(void *, int);
static void ath_reset_proc(void *, int);
-static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
-static void ath_beacon_free(struct ath_softc *);
-static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
-static void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *, ath_bufhead *);
static int ath_desc_alloc(struct ath_softc *);
static void ath_desc_free(struct ath_softc *);
static struct ieee80211_node *ath_node_alloc(struct ieee80211vap *,
@@ -176,16 +163,9 @@
static void ath_node_free(struct ieee80211_node *);
static void ath_node_getsignal(const struct ieee80211_node *,
int8_t *, int8_t *);
-static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
-static void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
- int subtype, int rssi, int nf);
-static void ath_setdefantenna(struct ath_softc *, u_int);
-static void ath_rx_proc(struct ath_softc *sc, int);
-static void ath_rx_tasklet(void *, int);
static void ath_txq_init(struct ath_softc *sc, struct ath_txq *, int);
static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype);
static int ath_tx_setup(struct ath_softc *, int, int);
-static int ath_wme_update(struct ieee80211com *);
static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);
static void ath_tx_cleanup(struct ath_softc *);
static void ath_tx_proc_q0(void *, int);
@@ -194,8 +174,6 @@
static void ath_txq_sched_tasklet(void *, int);
static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
static void ath_draintxq(struct ath_softc *, ATH_RESET_TYPE reset_type);
-static void ath_stoprecv(struct ath_softc *, int);
-static int ath_startrecv(struct ath_softc *);
static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *);
static void ath_scan_start(struct ieee80211com *);
static void ath_scan_end(struct ieee80211com *);
@@ -222,16 +200,10 @@
static void ath_dfs_tasklet(void *, int);
#ifdef IEEE80211_SUPPORT_TDMA
-static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt,
- u_int32_t bintval);
-static void ath_tdma_bintvalsetup(struct ath_softc *sc,
- const struct ieee80211_tdma_state *tdma);
-static void ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap);
-static void ath_tdma_update(struct ieee80211_node *ni,
- const struct ieee80211_tdma_param *tdma, int);
-static void ath_tdma_beacon_send(struct ath_softc *sc,
- struct ieee80211vap *vap);
-
+#include <dev/ath/if_ath_tdma.h>
+#endif
+
+#if 0
#define TDMA_EP_MULTIPLIER (1<<10) /* pow2 to optimize out * and / */
#define TDMA_LPF_LEN 6
#define TDMA_DUMMY_MARKER 0x127
@@ -263,16 +235,20 @@
SYSCTL_INT(_hw_ath, OID_AUTO, anical, CTLFLAG_RW, &ath_anicalinterval,
0, "ANI calibration (msecs)");
-static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */
+int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */
SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf,
0, "rx buffers allocated");
TUNABLE_INT("hw.ath.rxbuf", &ath_rxbuf);
-static int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */
+int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */
SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RW, &ath_txbuf,
0, "tx buffers allocated");
TUNABLE_INT("hw.ath.txbuf", &ath_txbuf);
-
-static int ath_bstuck_threshold = 4; /* max missed beacons */
+int ath_txbuf_mgmt = ATH_MGMT_TXBUF; /* # mgmt tx buffers to allocate */
+SYSCTL_INT(_hw_ath, OID_AUTO, txbuf_mgmt, CTLFLAG_RW, &ath_txbuf_mgmt,
+ 0, "tx (mgmt) buffers allocated");
+TUNABLE_INT("hw.ath.txbuf_mgmt", &ath_txbuf_mgmt);
+
+int ath_bstuck_threshold = 4; /* max missed beacons */
SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold,
0, "max missed beacon xmits before chip reset");
@@ -323,6 +299,21 @@
#endif
/*
+ * Setup the DMA/EDMA functions based on the current
+ * hardware support.
+ *
+ * This is required before the descriptors are allocated.
+ */
+ if (ath_hal_hasedma(sc->sc_ah)) {
+ sc->sc_isedma = 1;
+ ath_recv_setup_edma(sc);
+ ath_xmit_setup_edma(sc);
+ } else {
+ ath_recv_setup_legacy(sc);
+ ath_xmit_setup_legacy(sc);
+ }
+
+ /*
* Check if the MAC has multi-rate retry support.
* We do this by trying to setup a fake extended
* descriptor. MAC's that don't have support will
@@ -380,13 +371,31 @@
ath_setcurmode(sc, IEEE80211_MODE_11A);
/*
- * Allocate tx+rx descriptors and populate the lists.
+ * Allocate TX descriptors and populate the lists.
*/
error = ath_desc_alloc(sc);
if (error != 0) {
- if_printf(ifp, "failed to allocate descriptors: %d\n", error);
+ if_printf(ifp, "failed to allocate TX descriptors: %d\n",
+ error);
goto bad;
}
+ error = ath_txdma_setup(sc);
+ if (error != 0) {
+ if_printf(ifp, "failed to allocate TX descriptors: %d\n",
+ error);
+ goto bad;
+ }
+
+ /*
+ * Allocate RX descriptors and populate the lists.
+ */
+ error = ath_rxdma_setup(sc);
+ if (error != 0) {
+ if_printf(ifp, "failed to allocate RX descriptors: %d\n",
+ error);
+ goto bad;
+ }
+
callout_init_mtx(&sc->sc_cal_ch, &sc->sc_mtx, 0);
callout_init_mtx(&sc->sc_wd_ch, &sc->sc_mtx, 0);
@@ -397,7 +406,7 @@
taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
"%s taskq", ifp->if_xname);
- TASK_INIT(&sc->sc_rxtask, 0, ath_rx_tasklet, sc);
+ TASK_INIT(&sc->sc_rxtask, 0, sc->sc_rx.recv_tasklet, sc);
TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc);
TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc);
TASK_INIT(&sc->sc_resettask,0, ath_reset_proc, sc);
@@ -545,7 +554,9 @@
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+#ifndef ATH_ENABLE_11N
| IEEE80211_C_BGSCAN /* capable of bg scanning */
+#endif
| IEEE80211_C_TXFRAG /* handle tx frags */
#ifdef ATH_ENABLE_DFS
| IEEE80211_C_DFS /* Enable radar detection */
@@ -681,12 +692,6 @@
(void) ath_hal_settxchainmask(sc->sc_ah, tx_chainmask);
}
- /*
- * The if_ath 11n support is completely not ready for normal use.
- * Enabling this option will likely break everything and everything.
- * Don't think of doing that unless you know what you're doing.
- */
-
#ifdef ATH_ENABLE_11N
/*
* Query HT capabilities
@@ -748,6 +753,13 @@
#endif
/*
+ * Initial aggregation settings.
+ */
+ sc->sc_hwq_limit = ATH_AGGR_MIN_QDEPTH;
+ sc->sc_tid_hwq_lo = ATH_AGGR_SCHED_LOW;
+ sc->sc_tid_hwq_hi = ATH_AGGR_SCHED_HIGH;
+
+ /*
* Check if the hardware requires PCI register serialisation.
* Some of the Owl based MACs require this.
*/
@@ -824,11 +836,26 @@
ic->ic_update_chw = ath_update_chw;
#endif /* ATH_ENABLE_11N */
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+ /*
+ * There's one vendor bitmap entry in the RX radiotap
+ * header; make sure that's taken into account.
+ */
+ ieee80211_radiotap_attachv(ic,
+ &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), 0,
+ ATH_TX_RADIOTAP_PRESENT,
+ &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), 1,
+ ATH_RX_RADIOTAP_PRESENT);
+#else
+ /*
+ * No vendor bitmap/extensions are present.
+ */
ieee80211_radiotap_attach(ic,
&sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
ATH_TX_RADIOTAP_PRESENT,
&sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
ATH_RX_RADIOTAP_PRESENT);
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
/*
* Setup dynamic sysctl's now that country code and
@@ -845,6 +872,8 @@
bad2:
ath_tx_cleanup(sc);
ath_desc_free(sc);
+ ath_txdma_teardown(sc);
+ ath_rxdma_teardown(sc);
bad:
if (ah)
ath_hal_detach(ah);
@@ -887,6 +916,7 @@
ath_dfs_detach(sc);
ath_desc_free(sc);
+ ath_rxdma_teardown(sc);
ath_tx_cleanup(sc);
ath_hal_detach(sc->sc_ah); /* NB: sets chip in full sleep */
if_free(ifp);
@@ -1334,15 +1364,22 @@
__func__, ifp->if_flags);
sc->sc_resume_up = (ifp->if_flags & IFF_UP) != 0;
- if (ic->ic_opmode == IEEE80211_M_STA)
- ath_stop(ifp);
- else
- ieee80211_suspend_all(ic);
+
+ ieee80211_suspend_all(ic);
/*
* NB: don't worry about putting the chip in low power
* mode; pci will power off our socket on suspend and
* CardBus detaches the device.
*/
+
+ /*
+ * XXX ensure none of the taskqueues are running
+ * XXX ensure sc_invalid is 1
+ * XXX ensure the calibration callout is disabled
+ */
+
+ /* Disable the PCIe PHY, complete with workarounds */
+ ath_hal_enablepcie(sc->sc_ah, 1, 1);
}
/*
@@ -1375,6 +1412,9 @@
DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n",
__func__, ifp->if_flags);
+ /* Re-enable PCIe, re-enable the PCIe bus */
+ ath_hal_enablepcie(ah, 0, 0);
+
/*
* Must reset the chip before we reload the
* keycache as we were powered down on suspend.
@@ -1391,23 +1431,8 @@
ath_led_config(sc);
ath_hal_setledstate(ah, HAL_LED_INIT);
- if (sc->sc_resume_up) {
- if (ic->ic_opmode == IEEE80211_M_STA) {
- ath_init(sc);
- ath_hal_setledstate(ah, HAL_LED_RUN);
- /*
- * Program the beacon registers using the last rx'd
- * beacon frame and enable sync on the next beacon
- * we see. This should handle the case where we
- * wakeup and find the same AP and also the case where
- * we wakeup and need to roam. For the latter we
- * should get bmiss events that trigger a roam.
- */
- ath_beacon_config(sc, NULL);
- sc->sc_syncbeacon = 1;
- } else
- ieee80211_resume_all(ic);
- }
+ if (sc->sc_resume_up)
+ ieee80211_resume_all(ic);
/* XXX beacons ? */
}
@@ -1611,7 +1636,11 @@
/* bump tx trigger level */
ath_hal_updatetxtriglevel(ah, AH_TRUE);
}
- if (status & HAL_INT_RX) {
+ /*
+ * Handle both the legacy and RX EDMA interrupt bits.
+ * Note that HAL_INT_RXLP is also HAL_INT_RXDESC.
+ */
+ if (status & (HAL_INT_RX | HAL_INT_RXHP | HAL_INT_RXLP)) {
sc->sc_stats.ast_rx_intr++;
taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
}
@@ -1839,13 +1868,6 @@
sc->sc_beacons = 0;
/*
- * Initial aggregation settings.
- */
- sc->sc_hwq_limit = ATH_AGGR_MIN_QDEPTH;
- sc->sc_tid_hwq_lo = ATH_AGGR_SCHED_LOW;
- sc->sc_tid_hwq_hi = ATH_AGGR_SCHED_HIGH;
-
- /*
* Setup the hardware after reset: the key cache
* is filled as needed and the receive engine is
* set going. Frame transmit is handled entirely
@@ -1864,6 +1886,14 @@
sc->sc_imask = HAL_INT_RX | HAL_INT_TX
| HAL_INT_RXEOL | HAL_INT_RXORN
| HAL_INT_FATAL | HAL_INT_GLOBAL;
+
+ /*
+ * Enable RX EDMA bits. Note these overlap with
+ * HAL_INT_RX and HAL_INT_RXDESC respectively.
+ */
+ if (sc->sc_isedma)
+ sc->sc_imask |= (HAL_INT_RXHP | HAL_INT_RXLP);
+
/*
* Enable MIB interrupts when there are hardware phy counters.
* Note we only do this (at the moment) for station mode.
@@ -2115,7 +2145,7 @@
* That way frames aren't dropped which shouldn't be.
*/
ath_stoprecv(sc, (reset_type != ATH_RESET_NOLOSS));
- ath_rx_proc(sc, 0);
+ ath_rx_flush(sc);
ath_settkipmic(sc); /* configure TKIP MIC handling */
/* NB: indicate channel change so we do a full reset */
@@ -2225,13 +2255,17 @@
}
struct ath_buf *
-_ath_getbuf_locked(struct ath_softc *sc)
+_ath_getbuf_locked(struct ath_softc *sc, ath_buf_type_t btype)
{
struct ath_buf *bf;
ATH_TXBUF_LOCK_ASSERT(sc);
- bf = TAILQ_FIRST(&sc->sc_txbuf);
+ if (btype == ATH_BUFTYPE_MGMT)
+ bf = TAILQ_FIRST(&sc->sc_txbuf_mgmt);
+ else
+ bf = TAILQ_FIRST(&sc->sc_txbuf);
+
if (bf == NULL) {
sc->sc_stats.ast_tx_getnobuf++;
} else {
@@ -2241,18 +2275,43 @@
}
}
- if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0)
- TAILQ_REMOVE(&sc->sc_txbuf, bf, bf_list);
- else
+ if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0) {
+ if (btype == ATH_BUFTYPE_MGMT)
+ TAILQ_REMOVE(&sc->sc_txbuf_mgmt, bf, bf_list);
+ else {
+ TAILQ_REMOVE(&sc->sc_txbuf, bf, bf_list);
+ sc->sc_txbuf_cnt--;
+
+ /*
+ * This shuldn't happen; however just to be
+ * safe print a warning and fudge the txbuf
+ * count.
+ */
+ if (sc->sc_txbuf_cnt < 0) {
+ device_printf(sc->sc_dev,
+ "%s: sc_txbuf_cnt < 0?\n",
+ __func__);
+ sc->sc_txbuf_cnt = 0;
+ }
+ }
+ } else
bf = NULL;
if (bf == NULL) {
+ /* XXX should check which list, mgmt or otherwise */
DPRINTF(sc, ATH_DEBUG_XMIT, "%s: %s\n", __func__,
TAILQ_FIRST(&sc->sc_txbuf) == NULL ?
"out of xmit buffers" : "xmit buffer busy");
return NULL;
}
+ /* XXX TODO: should do this at buffer list initialisation */
+ /* XXX (then, ensure the buffer has the right flag set) */
+ if (btype == ATH_BUFTYPE_MGMT)
+ bf->bf_flags |= ATH_BUF_MGMT;
+ else
+ bf->bf_flags &= (~ATH_BUF_MGMT);
+
/* Valid bf here; clear some basic fields */
bf->bf_next = NULL; /* XXX just to be sure */
bf->bf_last = NULL; /* XXX again, just to be sure */
@@ -2287,7 +2346,9 @@
{
struct ath_buf *tbf;
- tbf = ath_getbuf(sc);
+ tbf = ath_getbuf(sc,
+ (bf->bf_flags & ATH_BUF_MGMT) ?
+ ATH_BUFTYPE_MGMT : ATH_BUFTYPE_NORMAL);
if (tbf == NULL)
return NULL; /* XXX failure? Why? */
@@ -2315,12 +2376,18 @@
}
struct ath_buf *
-ath_getbuf(struct ath_softc *sc)
+ath_getbuf(struct ath_softc *sc, ath_buf_type_t btype)
{
struct ath_buf *bf;
ATH_TXBUF_LOCK(sc);
- bf = _ath_getbuf_locked(sc);
+ bf = _ath_getbuf_locked(sc, btype);
+ /*
+ * If a mgmt buffer was requested but we're out of those,
+ * try requesting a normal one.
+ */
+ if (bf == NULL && btype == ATH_BUFTYPE_MGMT)
+ bf = _ath_getbuf_locked(sc, ATH_BUFTYPE_NORMAL);
ATH_TXBUF_UNLOCK(sc);
if (bf == NULL) {
struct ifnet *ifp = sc->sc_ifp;
@@ -2334,7 +2401,7 @@
return bf;
}
-static void
+void
ath_start(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
@@ -2353,6 +2420,7 @@
"%s: sc_inreset_cnt > 0; bailing\n", __func__);
ATH_PCU_UNLOCK(sc);
IF_LOCK(&ifp->if_snd);
+ sc->sc_stats.ast_tx_qstop++;
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
IF_UNLOCK(&ifp->if_snd);
return;
@@ -2361,17 +2429,28 @@
ATH_PCU_UNLOCK(sc);
for (;;) {
+ ATH_TXBUF_LOCK(sc);
+ if (sc->sc_txbuf_cnt <= sc->sc_txq_data_minfree) {
+ /* XXX increment counter? */
+ ATH_TXBUF_UNLOCK(sc);
+ IF_LOCK(&ifp->if_snd);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
+ break;
+ }
+ ATH_TXBUF_UNLOCK(sc);
+
/*
* Grab a TX buffer and associated resources.
*/
- bf = ath_getbuf(sc);
+ bf = ath_getbuf(sc, ATH_BUFTYPE_NORMAL);
if (bf == NULL)
break;
IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL) {
ATH_TXBUF_LOCK(sc);
- TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ ath_returnbuf_head(sc, bf);
ATH_TXBUF_UNLOCK(sc);
break;
}
@@ -2414,7 +2493,7 @@
bf->bf_m = NULL;
bf->bf_node = NULL;
ATH_TXBUF_LOCK(sc);
- TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ ath_returnbuf_head(sc, bf);
ath_txfrag_cleanup(sc, &frags, ni);
ATH_TXBUF_UNLOCK(sc);
if (ni != NULL)
@@ -2485,102 +2564,6 @@
taskqueue_unblock(sc->sc_tq);
}
-/*
- * Calculate the receive filter according to the
- * operating mode and state:
- *
- * o always accept unicast, broadcast, and multicast traffic
- * o accept PHY error frames when hardware doesn't have MIB support
- * to count and we need them for ANI (sta mode only until recently)
- * and we are not scanning (ANI is disabled)
- * NB: older hal's add rx filter bits out of sight and we need to
- * blindly preserve them
- * o probe request frames are accepted only when operating in
- * hostap, adhoc, mesh, or monitor modes
- * o enable promiscuous mode
- * - when in monitor mode
- * - if interface marked PROMISC (assumes bridge setting is filtered)
- * o accept beacons:
- * - when operating in station mode for collecting rssi data when
- * the station is otherwise quiet, or
- * - when operating in adhoc mode so the 802.11 layer creates
- * node table entries for peers,
- * - when scanning
- * - when doing s/w beacon miss (e.g. for ap+sta)
- * - when operating in ap mode in 11g to detect overlapping bss that
- * require protection
- * - when operating in mesh mode to detect neighbors
- * o accept control frames:
- * - when in monitor mode
- * XXX HT protection for 11n
- */
-static u_int32_t
-ath_calcrxfilter(struct ath_softc *sc)
-{
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
- u_int32_t rfilt;
-
- rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
- if (!sc->sc_needmib && !sc->sc_scanning)
- rfilt |= HAL_RX_FILTER_PHYERR;
- if (ic->ic_opmode != IEEE80211_M_STA)
- rfilt |= HAL_RX_FILTER_PROBEREQ;
- /* XXX ic->ic_monvaps != 0? */
- if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC))
- rfilt |= HAL_RX_FILTER_PROM;
- if (ic->ic_opmode == IEEE80211_M_STA ||
- ic->ic_opmode == IEEE80211_M_IBSS ||
- sc->sc_swbmiss || sc->sc_scanning)
- rfilt |= HAL_RX_FILTER_BEACON;
- /*
- * NB: We don't recalculate the rx filter when
- * ic_protmode changes; otherwise we could do
- * this only when ic_protmode != NONE.
- */
- if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
- IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
- rfilt |= HAL_RX_FILTER_BEACON;
-
- /*
- * Enable hardware PS-POLL RX only for hostap mode;
- * STA mode sends PS-POLL frames but never
- * receives them.
- */
- if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_PSPOLL,
- 0, NULL) == HAL_OK &&
- ic->ic_opmode == IEEE80211_M_HOSTAP)
- rfilt |= HAL_RX_FILTER_PSPOLL;
-
- if (sc->sc_nmeshvaps) {
- rfilt |= HAL_RX_FILTER_BEACON;
- if (sc->sc_hasbmatch)
- rfilt |= HAL_RX_FILTER_BSSID;
- else
- rfilt |= HAL_RX_FILTER_PROM;
- }
- if (ic->ic_opmode == IEEE80211_M_MONITOR)
- rfilt |= HAL_RX_FILTER_CONTROL;
-
- /*
- * Enable RX of compressed BAR frames only when doing
- * 802.11n. Required for A-MPDU.
- */
- if (IEEE80211_IS_CHAN_HT(ic->ic_curchan))
- rfilt |= HAL_RX_FILTER_COMPBAR;
-
- /*
- * Enable radar PHY errors if requested by the
- * DFS module.
- */
- if (sc->sc_dodfs)
- rfilt |= HAL_RX_FILTER_PHYRADAR;
-
- DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n",
- __func__, rfilt, ieee80211_opmode_name[ic->ic_opmode], ifp->if_flags);
- return rfilt;
-}
-
static void
ath_update_promisc(struct ifnet *ifp)
{
@@ -2630,7 +2613,7 @@
__func__, mfilt[0], mfilt[1]);
}
-static void
+void
ath_mode_init(struct ath_softc *sc)
{
struct ifnet *ifp = sc->sc_ifp;
@@ -2644,6 +2627,13 @@
/* configure operational mode */
ath_hal_setopmode(ah);
+ DPRINTF(sc, ATH_DEBUG_STATE | ATH_DEBUG_MODE,
+ "%s: ah=%p, ifp=%p, if_addr=%p\n",
+ __func__,
+ ah,
+ ifp,
+ (ifp == NULL) ? NULL : ifp->if_addr);
+
/* handle any link-level address change */
ath_hal_setmac(ah, IF_LLADDR(ifp));
@@ -2654,7 +2644,7 @@
/*
* Set the slot time based on the current setting.
*/
-static void
+void
ath_setslottime(struct ath_softc *sc)
{
struct ieee80211com *ic = sc->sc_ifp->if_l2com;
@@ -2707,248 +2697,10 @@
}
/*
- * Setup a h/w transmit queue for beacons.
- */
-static int
-ath_beaconq_setup(struct ath_hal *ah)
-{
- HAL_TXQ_INFO qi;
-
- memset(&qi, 0, sizeof(qi));
- qi.tqi_aifs = HAL_TXQ_USEDEFAULT;
- qi.tqi_cwmin = HAL_TXQ_USEDEFAULT;
- qi.tqi_cwmax = HAL_TXQ_USEDEFAULT;
- /* NB: for dynamic turbo, don't enable any other interrupts */
- qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE;
- return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi);
-}
-
-/*
- * Setup the transmit queue parameters for the beacon queue.
- */
-static int
-ath_beaconq_config(struct ath_softc *sc)
-{
-#define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1)
- struct ieee80211com *ic = sc->sc_ifp->if_l2com;
- struct ath_hal *ah = sc->sc_ah;
- HAL_TXQ_INFO qi;
-
- ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi);
- if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
- ic->ic_opmode == IEEE80211_M_MBSS) {
- /*
- * Always burst out beacon and CAB traffic.
- */
- qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT;
- qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT;
- qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT;
- } else {
- struct wmeParams *wmep =
- &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE];
- /*
- * Adhoc mode; important thing is to use 2x cwmin.
- */
- qi.tqi_aifs = wmep->wmep_aifsn;
- qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
- qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
- }
-
- if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) {
- device_printf(sc->sc_dev, "unable to update parameters for "
- "beacon hardware queue!\n");
- return 0;
- } else {
- ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */
- return 1;
- }
-#undef ATH_EXPONENT_TO_VALUE
-}
-
-/*
- * Allocate and setup an initial beacon frame.
- */
-static int
-ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
-{
- struct ieee80211vap *vap = ni->ni_vap;
- struct ath_vap *avp = ATH_VAP(vap);
- struct ath_buf *bf;
- struct mbuf *m;
- int error;
-
- bf = avp->av_bcbuf;
- DPRINTF(sc, ATH_DEBUG_NODE, "%s: bf_m=%p, bf_node=%p\n",
- __func__, bf->bf_m, bf->bf_node);
- if (bf->bf_m != NULL) {
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
- }
- if (bf->bf_node != NULL) {
- ieee80211_free_node(bf->bf_node);
- bf->bf_node = NULL;
- }
-
- /*
- * NB: the beacon data buffer must be 32-bit aligned;
- * we assume the mbuf routines will return us something
- * with this alignment (perhaps should assert).
- */
- m = ieee80211_beacon_alloc(ni, &avp->av_boff);
- if (m == NULL) {
- device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__);
- sc->sc_stats.ast_be_nombuf++;
- return ENOMEM;
- }
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- device_printf(sc->sc_dev,
- "%s: cannot map mbuf, bus_dmamap_load_mbuf_sg returns %d\n",
- __func__, error);
- m_freem(m);
- return error;
- }
-
- /*
- * Calculate a TSF adjustment factor required for staggered
- * beacons. Note that we assume the format of the beacon
- * frame leaves the tstamp field immediately following the
- * header.
- */
- if (sc->sc_stagbeacons && avp->av_bslot > 0) {
- uint64_t tsfadjust;
- struct ieee80211_frame *wh;
-
- /*
- * The beacon interval is in TU's; the TSF is in usecs.
- * We figure out how many TU's to add to align the timestamp
- * then convert to TSF units and handle byte swapping before
- * inserting it in the frame. The hardware will then add this
- * each time a beacon frame is sent. Note that we align vap's
- * 1..N and leave vap 0 untouched. This means vap 0 has a
- * timestamp in one beacon interval while the others get a
- * timstamp aligned to the next interval.
- */
- tsfadjust = ni->ni_intval *
- (ATH_BCBUF - avp->av_bslot) / ATH_BCBUF;
- tsfadjust = htole64(tsfadjust << 10); /* TU -> TSF */
-
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: %s beacons bslot %d intval %u tsfadjust %llu\n",
- __func__, sc->sc_stagbeacons ? "stagger" : "burst",
- avp->av_bslot, ni->ni_intval,
- (long long unsigned) le64toh(tsfadjust));
-
- wh = mtod(m, struct ieee80211_frame *);
- memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust));
- }
- bf->bf_m = m;
- bf->bf_node = ieee80211_ref_node(ni);
-
- return 0;
-}
-
-/*
- * Setup the beacon frame for transmit.
- */
-static void
-ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
-{
-#define USE_SHPREAMBLE(_ic) \
- (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\
- == IEEE80211_F_SHPREAMBLE)
- struct ieee80211_node *ni = bf->bf_node;
- struct ieee80211com *ic = ni->ni_ic;
- struct mbuf *m = bf->bf_m;
- struct ath_hal *ah = sc->sc_ah;
- struct ath_desc *ds;
- int flags, antenna;
- const HAL_RATE_TABLE *rt;
- u_int8_t rix, rate;
-
- DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n",
- __func__, m, m->m_len);
-
- /* setup descriptors */
- ds = bf->bf_desc;
- bf->bf_last = bf;
- bf->bf_lastds = ds;
-
- flags = HAL_TXDESC_NOACK;
- if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) {
- ds->ds_link = bf->bf_daddr; /* self-linked */
- flags |= HAL_TXDESC_VEOL;
- /*
- * Let hardware handle antenna switching.
- */
- antenna = sc->sc_txantenna;
- } else {
- ds->ds_link = 0;
- /*
- * Switch antenna every 4 beacons.
- * XXX assumes two antenna
- */
- if (sc->sc_txantenna != 0)
- antenna = sc->sc_txantenna;
- else if (sc->sc_stagbeacons && sc->sc_nbcnvaps != 0)
- antenna = ((sc->sc_stats.ast_be_xmit / sc->sc_nbcnvaps) & 4 ? 2 : 1);
- else
- antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1);
- }
-
- KASSERT(bf->bf_nseg == 1,
- ("multi-segment beacon frame; nseg %u", bf->bf_nseg));
- ds->ds_data = bf->bf_segs[0].ds_addr;
- /*
- * Calculate rate code.
- * XXX everything at min xmit rate
- */
- rix = 0;
- rt = sc->sc_currates;
- rate = rt->info[rix].rateCode;
- if (USE_SHPREAMBLE(ic))
- rate |= rt->info[rix].shortPreamble;
- ath_hal_setuptxdesc(ah, ds
- , m->m_len + IEEE80211_CRC_LEN /* frame length */
- , sizeof(struct ieee80211_frame)/* header length */
- , HAL_PKT_TYPE_BEACON /* Atheros packet type */
- , ni->ni_txpower /* txpower XXX */
- , rate, 1 /* series 0 rate/tries */
- , HAL_TXKEYIX_INVALID /* no encryption */
- , antenna /* antenna mode */
- , flags /* no ack, veol for beacons */
- , 0 /* rts/cts rate */
- , 0 /* rts/cts duration */
- );
- /* NB: beacon's BufLen must be a multiple of 4 bytes */
- ath_hal_filltxdesc(ah, ds
- , roundup(m->m_len, 4) /* buffer length */
- , AH_TRUE /* first segment */
- , AH_TRUE /* last segment */
- , ds /* first descriptor */
- );
-#if 0
- ath_desc_swap(ds);
-#endif
-#undef USE_SHPREAMBLE
-}
-
-static void
-ath_beacon_update(struct ieee80211vap *vap, int item)
-{
- struct ieee80211_beacon_offsets *bo = &ATH_VAP(vap)->av_boff;
-
- setbit(bo->bo_flags, item);
-}
-
-/*
* Append the contents of src to dst; both queues
* are assumed to be locked.
*/
-static void
+void
ath_txqmove(struct ath_txq *dst, struct ath_txq *src)
{
@@ -2965,255 +2717,6 @@
}
/*
- * Transmit a beacon frame at SWBA. Dynamic updates to the
- * frame contents are done as needed and the slot time is
- * also adjusted based on current state.
- */
-static void
-ath_beacon_proc(void *arg, int pending)
-{
- struct ath_softc *sc = arg;
- struct ath_hal *ah = sc->sc_ah;
- struct ieee80211vap *vap;
- struct ath_buf *bf;
- int slot, otherant;
- uint32_t bfaddr;
-
- DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n",
- __func__, pending);
- /*
- * Check if the previous beacon has gone out. If
- * not don't try to post another, skip this period
- * and wait for the next. Missed beacons indicate
- * a problem and should not occur. If we miss too
- * many consecutive beacons reset the device.
- */
- if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
- sc->sc_bmisscount++;
- sc->sc_stats.ast_be_missed++;
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: missed %u consecutive beacons\n",
- __func__, sc->sc_bmisscount);
- if (sc->sc_bmisscount >= ath_bstuck_threshold)
- taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask);
- return;
- }
- if (sc->sc_bmisscount != 0) {
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: resume beacon xmit after %u misses\n",
- __func__, sc->sc_bmisscount);
- sc->sc_bmisscount = 0;
- }
-
- if (sc->sc_stagbeacons) { /* staggered beacons */
- struct ieee80211com *ic = sc->sc_ifp->if_l2com;
- uint32_t tsftu;
-
- tsftu = ath_hal_gettsf32(ah) >> 10;
- /* XXX lintval */
- slot = ((tsftu % ic->ic_lintval) * ATH_BCBUF) / ic->ic_lintval;
- vap = sc->sc_bslot[(slot+1) % ATH_BCBUF];
- bfaddr = 0;
- if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) {
- bf = ath_beacon_generate(sc, vap);
- if (bf != NULL)
- bfaddr = bf->bf_daddr;
- }
- } else { /* burst'd beacons */
- uint32_t *bflink = &bfaddr;
-
- for (slot = 0; slot < ATH_BCBUF; slot++) {
- vap = sc->sc_bslot[slot];
- if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) {
- bf = ath_beacon_generate(sc, vap);
- if (bf != NULL) {
- *bflink = bf->bf_daddr;
- bflink = &bf->bf_desc->ds_link;
- }
- }
- }
- *bflink = 0; /* terminate list */
- }
-
- /*
- * Handle slot time change when a non-ERP station joins/leaves
- * an 11g network. The 802.11 layer notifies us via callback,
- * we mark updateslot, then wait one beacon before effecting
- * the change. This gives associated stations at least one
- * beacon interval to note the state change.
- */
- /* XXX locking */
- if (sc->sc_updateslot == UPDATE) {
- sc->sc_updateslot = COMMIT; /* commit next beacon */
- sc->sc_slotupdate = slot;
- } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
- ath_setslottime(sc); /* commit change to h/w */
-
- /*
- * Check recent per-antenna transmit statistics and flip
- * the default antenna if noticeably more frames went out
- * on the non-default antenna.
- * XXX assumes 2 anntenae
- */
- if (!sc->sc_diversity && (!sc->sc_stagbeacons || slot == 0)) {
- otherant = sc->sc_defant & 1 ? 2 : 1;
- if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
- ath_setdefantenna(sc, otherant);
- sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
- }
-
- if (bfaddr != 0) {
- /*
- * Stop any current dma and put the new frame on the queue.
- * This should never fail since we check above that no frames
- * are still pending on the queue.
- */
- if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
- DPRINTF(sc, ATH_DEBUG_ANY,
- "%s: beacon queue %u did not stop?\n",
- __func__, sc->sc_bhalq);
- }
- /* NB: cabq traffic should already be queued and primed */
- ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr);
- ath_hal_txstart(ah, sc->sc_bhalq);
-
- sc->sc_stats.ast_be_xmit++;
- }
-}
-
-static struct ath_buf *
-ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
-{
- struct ath_vap *avp = ATH_VAP(vap);
- struct ath_txq *cabq = sc->sc_cabq;
- struct ath_buf *bf;
- struct mbuf *m;
- int nmcastq, error;
-
- KASSERT(vap->iv_state >= IEEE80211_S_RUN,
- ("not running, state %d", vap->iv_state));
- KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
-
- /*
- * Update dynamic beacon contents. If this returns
- * non-zero then we need to remap the memory because
- * the beacon frame changed size (probably because
- * of the TIM bitmap).
- */
- bf = avp->av_bcbuf;
- m = bf->bf_m;
- /* XXX lock mcastq? */
- nmcastq = avp->av_mcastq.axq_depth;
-
- if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, nmcastq)) {
- /* XXX too conservative? */
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- if_printf(vap->iv_ifp,
- "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
- __func__, error);
- return NULL;
- }
- }
- if ((avp->av_boff.bo_tim[4] & 1) && cabq->axq_depth) {
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: cabq did not drain, mcastq %u cabq %u\n",
- __func__, nmcastq, cabq->axq_depth);
- sc->sc_stats.ast_cabq_busy++;
- if (sc->sc_nvaps > 1 && sc->sc_stagbeacons) {
- /*
- * CABQ traffic from a previous vap is still pending.
- * We must drain the q before this beacon frame goes
- * out as otherwise this vap's stations will get cab
- * frames from a different vap.
- * XXX could be slow causing us to miss DBA
- */
- ath_tx_draintxq(sc, cabq);
- }
- }
- ath_beacon_setup(sc, bf);
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
-
- /*
- * Enable the CAB queue before the beacon queue to
- * insure cab frames are triggered by this beacon.
- */
- if (avp->av_boff.bo_tim[4] & 1) {
- struct ath_hal *ah = sc->sc_ah;
-
- /* NB: only at DTIM */
- ATH_TXQ_LOCK(cabq);
- ATH_TXQ_LOCK(&avp->av_mcastq);
- if (nmcastq) {
- struct ath_buf *bfm;
-
- /*
- * Move frames from the s/w mcast q to the h/w cab q.
- * XXX MORE_DATA bit
- */
- bfm = TAILQ_FIRST(&avp->av_mcastq.axq_q);
- if (cabq->axq_link != NULL) {
- *cabq->axq_link = bfm->bf_daddr;
- } else
- ath_hal_puttxbuf(ah, cabq->axq_qnum,
- bfm->bf_daddr);
- ath_txqmove(cabq, &avp->av_mcastq);
-
- sc->sc_stats.ast_cabq_xmit += nmcastq;
- }
- /* NB: gated by beacon so safe to start here */
- if (! TAILQ_EMPTY(&(cabq->axq_q)))
- ath_hal_txstart(ah, cabq->axq_qnum);
- ATH_TXQ_UNLOCK(&avp->av_mcastq);
- ATH_TXQ_UNLOCK(cabq);
- }
- return bf;
-}
-
-static void
-ath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211vap *vap)
-{
- struct ath_vap *avp = ATH_VAP(vap);
- struct ath_hal *ah = sc->sc_ah;
- struct ath_buf *bf;
- struct mbuf *m;
- int error;
-
- KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
-
- /*
- * Update dynamic beacon contents. If this returns
- * non-zero then we need to remap the memory because
- * the beacon frame changed size (probably because
- * of the TIM bitmap).
- */
- bf = avp->av_bcbuf;
- m = bf->bf_m;
- if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, 0)) {
- /* XXX too conservative? */
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- if_printf(vap->iv_ifp,
- "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
- __func__, error);
- return;
- }
- }
- ath_beacon_setup(sc, bf);
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
-
- /* NB: caller is known to have already stopped tx dma */
- ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
- ath_hal_txstart(ah, sc->sc_bhalq);
-}
-
-/*
* Reset the hardware, with no loss.
*
* This can't be used for a general case reset.
@@ -3253,255 +2756,6 @@
ath_reset(ifp, ATH_RESET_NOLOSS);
}
-/*
- * Reclaim beacon resources and return buffer to the pool.
- */
-static void
-ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf)
-{
-
- DPRINTF(sc, ATH_DEBUG_NODE, "%s: free bf=%p, bf_m=%p, bf_node=%p\n",
- __func__, bf, bf->bf_m, bf->bf_node);
- if (bf->bf_m != NULL) {
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
- }
- if (bf->bf_node != NULL) {
- ieee80211_free_node(bf->bf_node);
- bf->bf_node = NULL;
- }
- TAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list);
-}
-
-/*
- * Reclaim beacon resources.
- */
-static void
-ath_beacon_free(struct ath_softc *sc)
-{
- struct ath_buf *bf;
-
- TAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) {
- DPRINTF(sc, ATH_DEBUG_NODE,
- "%s: free bf=%p, bf_m=%p, bf_node=%p\n",
- __func__, bf, bf->bf_m, bf->bf_node);
- if (bf->bf_m != NULL) {
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
- }
- if (bf->bf_node != NULL) {
- ieee80211_free_node(bf->bf_node);
- bf->bf_node = NULL;
- }
- }
-}
-
-/*
- * Configure the beacon and sleep timers.
- *
- * When operating as an AP this resets the TSF and sets
- * up the hardware to notify us when we need to issue beacons.
- *
- * When operating in station mode this sets up the beacon
- * timers according to the timestamp of the last received
- * beacon and the current TSF, configures PCF and DTIM
- * handling, programs the sleep registers so the hardware
- * will wakeup in time to receive beacons, and configures
- * the beacon miss handling so we'll receive a BMISS
- * interrupt when we stop seeing beacons from the AP
- * we've associated with.
- */
-static void
-ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
-{
-#define TSF_TO_TU(_h,_l) \
- ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
-#define FUDGE 2
- struct ath_hal *ah = sc->sc_ah;
- struct ieee80211com *ic = sc->sc_ifp->if_l2com;
- struct ieee80211_node *ni;
- u_int32_t nexttbtt, intval, tsftu;
- u_int64_t tsf;
-
- if (vap == NULL)
- vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
- ni = ieee80211_ref_node(vap->iv_bss);
-
- /* extract tstamp from last beacon and convert to TU */
- nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4),
- LE_READ_4(ni->ni_tstamp.data));
- if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
- ic->ic_opmode == IEEE80211_M_MBSS) {
- /*
- * For multi-bss ap/mesh support beacons are either staggered
- * evenly over N slots or burst together. For the former
- * arrange for the SWBA to be delivered for each slot.
- * Slots that are not occupied will generate nothing.
- */
- /* NB: the beacon interval is kept internally in TU's */
- intval = ni->ni_intval & HAL_BEACON_PERIOD;
- if (sc->sc_stagbeacons)
- intval /= ATH_BCBUF;
- } else {
- /* NB: the beacon interval is kept internally in TU's */
- intval = ni->ni_intval & HAL_BEACON_PERIOD;
- }
- if (nexttbtt == 0) /* e.g. for ap mode */
- nexttbtt = intval;
- else if (intval) /* NB: can be 0 for monitor mode */
- nexttbtt = roundup(nexttbtt, intval);
- DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
- __func__, nexttbtt, intval, ni->ni_intval);
- if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) {
- HAL_BEACON_STATE bs;
- int dtimperiod, dtimcount;
- int cfpperiod, cfpcount;
-
- /*
- * Setup dtim and cfp parameters according to
- * last beacon we received (which may be none).
- */
- dtimperiod = ni->ni_dtim_period;
- if (dtimperiod <= 0) /* NB: 0 if not known */
- dtimperiod = 1;
- dtimcount = ni->ni_dtim_count;
- if (dtimcount >= dtimperiod) /* NB: sanity check */
- dtimcount = 0; /* XXX? */
- cfpperiod = 1; /* NB: no PCF support yet */
- cfpcount = 0;
- /*
- * Pull nexttbtt forward to reflect the current
- * TSF and calculate dtim+cfp state for the result.
- */
- tsf = ath_hal_gettsf64(ah);
- tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
- do {
- nexttbtt += intval;
- if (--dtimcount < 0) {
- dtimcount = dtimperiod - 1;
- if (--cfpcount < 0)
- cfpcount = cfpperiod - 1;
- }
- } while (nexttbtt < tsftu);
- memset(&bs, 0, sizeof(bs));
- bs.bs_intval = intval;
- bs.bs_nexttbtt = nexttbtt;
- bs.bs_dtimperiod = dtimperiod*intval;
- bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
- bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
- bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
- bs.bs_cfpmaxduration = 0;
-#if 0
- /*
- * The 802.11 layer records the offset to the DTIM
- * bitmap while receiving beacons; use it here to
- * enable h/w detection of our AID being marked in
- * the bitmap vector (to indicate frames for us are
- * pending at the AP).
- * XXX do DTIM handling in s/w to WAR old h/w bugs
- * XXX enable based on h/w rev for newer chips
- */
- bs.bs_timoffset = ni->ni_timoff;
-#endif
- /*
- * Calculate the number of consecutive beacons to miss
- * before taking a BMISS interrupt.
- * Note that we clamp the result to at most 10 beacons.
- */
- bs.bs_bmissthreshold = vap->iv_bmissthreshold;
- if (bs.bs_bmissthreshold > 10)
- bs.bs_bmissthreshold = 10;
- else if (bs.bs_bmissthreshold <= 0)
- bs.bs_bmissthreshold = 1;
-
- /*
- * Calculate sleep duration. The configuration is
- * given in ms. We insure a multiple of the beacon
- * period is used. Also, if the sleep duration is
- * greater than the DTIM period then it makes senses
- * to make it a multiple of that.
- *
- * XXX fixed at 100ms
- */
- bs.bs_sleepduration =
- roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval);
- if (bs.bs_sleepduration > bs.bs_dtimperiod)
- bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
-
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n"
- , __func__
- , tsf, tsftu
- , bs.bs_intval
- , bs.bs_nexttbtt
- , bs.bs_dtimperiod
- , bs.bs_nextdtim
- , bs.bs_bmissthreshold
- , bs.bs_sleepduration
- , bs.bs_cfpperiod
- , bs.bs_cfpmaxduration
- , bs.bs_cfpnext
- , bs.bs_timoffset
- );
- ath_hal_intrset(ah, 0);
- ath_hal_beacontimers(ah, &bs);
- sc->sc_imask |= HAL_INT_BMISS;
- ath_hal_intrset(ah, sc->sc_imask);
- } else {
- ath_hal_intrset(ah, 0);
- if (nexttbtt == intval)
- intval |= HAL_BEACON_RESET_TSF;
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- /*
- * In IBSS mode enable the beacon timers but only
- * enable SWBA interrupts if we need to manually
- * prepare beacon frames. Otherwise we use a
- * self-linked tx descriptor and let the hardware
- * deal with things.
- */
- intval |= HAL_BEACON_ENA;
- if (!sc->sc_hasveol)
- sc->sc_imask |= HAL_INT_SWBA;
- if ((intval & HAL_BEACON_RESET_TSF) == 0) {
- /*
- * Pull nexttbtt forward to reflect
- * the current TSF.
- */
- tsf = ath_hal_gettsf64(ah);
- tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
- do {
- nexttbtt += intval;
- } while (nexttbtt < tsftu);
- }
- ath_beaconq_config(sc);
- } else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
- ic->ic_opmode == IEEE80211_M_MBSS) {
- /*
- * In AP/mesh mode we enable the beacon timers
- * and SWBA interrupts to prepare beacon frames.
- */
- intval |= HAL_BEACON_ENA;
- sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */
- ath_beaconq_config(sc);
- }
- ath_hal_beaconinit(ah, nexttbtt, intval);
- sc->sc_bmisscount = 0;
- ath_hal_intrset(ah, sc->sc_imask);
- /*
- * When using a self-linked beacon descriptor in
- * ibss mode load it once here.
- */
- if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol)
- ath_beacon_start_adhoc(sc, vap);
- }
- sc->sc_syncbeacon = 0;
- ieee80211_free_node(ni);
-#undef FUDGE
-#undef TSF_TO_TU
-}
-
static void
ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
@@ -3510,10 +2764,10 @@
*paddr = segs->ds_addr;
}
-static int
+int
ath_descdma_setup(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head,
- const char *name, int nbuf, int ndesc)
+ const char *name, int ds_size, int nbuf, int ndesc)
{
#define DS2PHYS(_dd, _ds) \
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
@@ -3523,15 +2777,15 @@
uint8_t *ds;
struct ath_buf *bf;
int i, bsize, error;
- int desc_len;
-
- desc_len = sizeof(struct ath_desc);
-
- DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n",
- __func__, name, nbuf, ndesc);
+
+ dd->dd_descsize = ds_size;
+
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: %s DMA: %u buffers %u desc/buf, %d bytes per descriptor\n",
+ __func__, name, nbuf, ndesc, dd->dd_descsize);
dd->dd_name = name;
- dd->dd_desc_len = desc_len * nbuf * ndesc;
+ dd->dd_desc_len = dd->dd_descsize * nbuf * ndesc;
/*
* Merlin work-around:
@@ -3539,7 +2793,7 @@
* Assume one skipped descriptor per 4KB page.
*/
if (! ath_hal_split4ktrans(sc->sc_ah)) {
- int numdescpage = 4096 / (desc_len * ndesc);
+ int numdescpage = 4096 / (dd->dd_descsize * ndesc);
dd->dd_desc_len = (nbuf / numdescpage + 1) * 4096;
}
@@ -3606,7 +2860,7 @@
dd->dd_bufptr = bf;
TAILQ_INIT(head);
- for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) {
+ for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * dd->dd_descsize)) {
bf->bf_desc = (struct ath_desc *) ds;
bf->bf_daddr = DS2PHYS(dd, ds);
if (! ath_hal_split4ktrans(sc->sc_ah)) {
@@ -3616,7 +2870,7 @@
* in the descriptor.
*/
if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr,
- desc_len * ndesc)) {
+ dd->dd_descsize * ndesc)) {
/* Start at the next page */
ds += 0x1000 - (bf->bf_daddr & 0xFFF);
bf->bf_desc = (struct ath_desc *) ds;
@@ -3649,17 +2903,82 @@
#undef ATH_DESC_4KB_BOUND_CHECK
}
-static void
+/*
+ * Allocate ath_buf entries but no descriptor contents.
+ *
+ * This is for RX EDMA where the descriptors are the header part of
+ * the RX buffer.
+ */
+int
+ath_descdma_setup_rx_edma(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head,
+ const char *name, int nbuf, int rx_status_len)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers\n",
+ __func__, name, nbuf);
+
+ dd->dd_name = name;
+ /*
+ * This is (mostly) purely for show. We're not allocating any actual
+ * descriptors here as EDMA RX has the descriptor be part
+ * of the RX buffer.
+ *
+ * However, dd_desc_len is used by ath_descdma_free() to determine
+ * whether we have already freed this DMA mapping.
+ */
+ dd->dd_desc_len = rx_status_len * nbuf;
+ dd->dd_descsize = rx_status_len;
+
+ /* allocate rx buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
+ if (bf == NULL) {
+ if_printf(ifp, "malloc of %s buffers failed, size %u\n",
+ dd->dd_name, bsize);
+ error = ENOMEM;
+ goto fail3;
+ }
+ dd->dd_bufptr = bf;
+
+ TAILQ_INIT(head);
+ for (i = 0; i < nbuf; i++, bf++) {
+ bf->bf_desc = NULL;
+ bf->bf_daddr = 0;
+ bf->bf_lastds = NULL; /* Just an initial value */
+
+ error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
+ &bf->bf_dmamap);
+ if (error != 0) {
+ if_printf(ifp, "unable to create dmamap for %s "
+ "buffer %u, error %u\n", dd->dd_name, i, error);
+ ath_descdma_cleanup(sc, dd, head);
+ return error;
+ }
+ TAILQ_INSERT_TAIL(head, bf, bf_list);
+ }
+ return 0;
+fail3:
+ memset(dd, 0, sizeof(*dd));
+ return error;
+}
+
+void
ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head)
{
struct ath_buf *bf;
struct ieee80211_node *ni;
- bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
- bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
- bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
- bus_dma_tag_destroy(dd->dd_dmat);
+ if (dd->dd_dmamap != 0) {
+ bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+ bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
+ bus_dma_tag_destroy(dd->dd_dmat);
+ }
TAILQ_FOREACH(bf, head, bf_list) {
if (bf->bf_m) {
@@ -3690,23 +3009,32 @@
{
int error;
- error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
- "rx", ath_rxbuf, 1);
- if (error != 0)
- return error;
-
error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
- "tx", ath_txbuf, ATH_TXDESC);
+ "tx", sc->sc_tx_desclen, ath_txbuf, ATH_TXDESC);
if (error != 0) {
- ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
return error;
}
-
- error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
- "beacon", ATH_BCBUF, 1);
+ sc->sc_txbuf_cnt = ath_txbuf;
+
+ error = ath_descdma_setup(sc, &sc->sc_txdma_mgmt, &sc->sc_txbuf_mgmt,
+ "tx_mgmt", sc->sc_tx_desclen, ath_txbuf_mgmt,
+ ATH_TXDESC);
if (error != 0) {
ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
- ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return error;
+ }
+
+ /*
+ * XXX mark txbuf_mgmt frames with ATH_BUF_MGMT, so the
+ * flag doesn't have to be set in ath_getbuf_locked().
+ */
+
+ error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+ "beacon", sc->sc_tx_desclen, ATH_BCBUF, 1);
+ if (error != 0) {
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+ ath_descdma_cleanup(sc, &sc->sc_txdma_mgmt,
+ &sc->sc_txbuf_mgmt);
return error;
}
return 0;
@@ -3720,8 +3048,9 @@
ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf);
if (sc->sc_txdma.dd_desc_len != 0)
ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
- if (sc->sc_rxdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ if (sc->sc_txdma_mgmt.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_txdma_mgmt,
+ &sc->sc_txbuf_mgmt);
}
static struct ieee80211_node *
@@ -3788,197 +3117,10 @@
*noise = -95; /* nominally correct */
}
-static int
-ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
-{
- struct ath_hal *ah = sc->sc_ah;
- int error;
- struct mbuf *m;
- struct ath_desc *ds;
-
- m = bf->bf_m;
- if (m == NULL) {
- /*
- * NB: by assigning a page to the rx dma buffer we
- * implicitly satisfy the Atheros requirement that
- * this buffer be cache-line-aligned and sized to be
- * multiple of the cache line size. Not doing this
- * causes weird stuff to happen (for the 5210 at least).
- */
- m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
- if (m == NULL) {
- DPRINTF(sc, ATH_DEBUG_ANY,
- "%s: no mbuf/cluster\n", __func__);
- sc->sc_stats.ast_rx_nombuf++;
- return ENOMEM;
- }
- m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
-
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat,
- bf->bf_dmamap, m,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- DPRINTF(sc, ATH_DEBUG_ANY,
- "%s: bus_dmamap_load_mbuf_sg failed; error %d\n",
- __func__, error);
- sc->sc_stats.ast_rx_busdma++;
- m_freem(m);
- return error;
- }
- KASSERT(bf->bf_nseg == 1,
- ("multi-segment packet; nseg %u", bf->bf_nseg));
- bf->bf_m = m;
- }
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD);
-
- /*
- * Setup descriptors. For receive we always terminate
- * the descriptor list with a self-linked entry so we'll
- * not get overrun under high load (as can happen with a
- * 5212 when ANI processing enables PHY error frames).
- *
- * To insure the last descriptor is self-linked we create
- * each descriptor as self-linked and add it to the end. As
- * each additional descriptor is added the previous self-linked
- * entry is ``fixed'' naturally. This should be safe even
- * if DMA is happening. When processing RX interrupts we
- * never remove/process the last, self-linked, entry on the
- * descriptor list. This insures the hardware always has
- * someplace to write a new frame.
- */
- /*
- * 11N: we can no longer afford to self link the last descriptor.
- * MAC acknowledges BA status as long as it copies frames to host
- * buffer (or rx fifo). This can incorrectly acknowledge packets
- * to a sender if last desc is self-linked.
- */
- ds = bf->bf_desc;
- if (sc->sc_rxslink)
- ds->ds_link = bf->bf_daddr; /* link to self */
- else
- ds->ds_link = 0; /* terminate the list */
- ds->ds_data = bf->bf_segs[0].ds_addr;
- ath_hal_setuprxdesc(ah, ds
- , m->m_len /* buffer size */
- , 0
- );
-
- if (sc->sc_rxlink != NULL)
- *sc->sc_rxlink = bf->bf_daddr;
- sc->sc_rxlink = &ds->ds_link;
- return 0;
-}
-
-/*
- * Extend 15-bit time stamp from rx descriptor to
- * a full 64-bit TSF using the specified TSF.
- */
-static __inline u_int64_t
-ath_extend_tsf15(u_int32_t rstamp, u_int64_t tsf)
-{
- if ((tsf & 0x7fff) < rstamp)
- tsf -= 0x8000;
-
- return ((tsf &~ 0x7fff) | rstamp);
-}
-
-/*
- * Extend 32-bit time stamp from rx descriptor to
- * a full 64-bit TSF using the specified TSF.
- */
-static __inline u_int64_t
-ath_extend_tsf32(u_int32_t rstamp, u_int64_t tsf)
-{
- u_int32_t tsf_low = tsf & 0xffffffff;
- u_int64_t tsf64 = (tsf & ~0xffffffffULL) | rstamp;
-
- if (rstamp > tsf_low && (rstamp - tsf_low > 0x10000000))
- tsf64 -= 0x100000000ULL;
-
- if (rstamp < tsf_low && (tsf_low - rstamp > 0x10000000))
- tsf64 += 0x100000000ULL;
-
- return tsf64;
-}
-
-/*
- * Extend the TSF from the RX descriptor to a full 64 bit TSF.
- * Earlier hardware versions only wrote the low 15 bits of the
- * TSF into the RX descriptor; later versions (AR5416 and up)
- * include the 32 bit TSF value.
- */
-static __inline u_int64_t
-ath_extend_tsf(struct ath_softc *sc, u_int32_t rstamp, u_int64_t tsf)
-{
- if (sc->sc_rxtsf32)
- return ath_extend_tsf32(rstamp, tsf);
- else
- return ath_extend_tsf15(rstamp, tsf);
-}
-
-/*
- * Intercept management frames to collect beacon rssi data
- * and to do ibss merges.
- */
-static void
-ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
- int subtype, int rssi, int nf)
-{
- struct ieee80211vap *vap = ni->ni_vap;
- struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
-
- /*
- * Call up first so subsequent work can use information
- * potentially stored in the node (e.g. for ibss merge).
- */
- ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, nf);
- switch (subtype) {
- case IEEE80211_FC0_SUBTYPE_BEACON:
- /* update rssi statistics for use by the hal */
- /* XXX unlocked check against vap->iv_bss? */
- ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi);
- if (sc->sc_syncbeacon &&
- ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) {
- /*
- * Resync beacon timers using the tsf of the beacon
- * frame we just received.
- */
- ath_beacon_config(sc, vap);
- }
- /* fall thru... */
- case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
- if (vap->iv_opmode == IEEE80211_M_IBSS &&
- vap->iv_state == IEEE80211_S_RUN) {
- uint32_t rstamp = sc->sc_lastrs->rs_tstamp;
- uint64_t tsf = ath_extend_tsf(sc, rstamp,
- ath_hal_gettsf64(sc->sc_ah));
- /*
- * Handle ibss merge as needed; check the tsf on the
- * frame before attempting the merge. The 802.11 spec
- * says the station should change it's bssid to match
- * the oldest station with the same ssid, where oldest
- * is determined by the tsf. Note that hardware
- * reconfiguration happens through callback to
- * ath_newstate as the state machine will go from
- * RUN -> RUN when this happens.
- */
- if (le64toh(ni->ni_tstamp.tsf) >= tsf) {
- DPRINTF(sc, ATH_DEBUG_STATE,
- "ibss merge, rstamp %u tsf %ju "
- "tstamp %ju\n", rstamp, (uintmax_t)tsf,
- (uintmax_t)ni->ni_tstamp.tsf);
- (void) ieee80211_ibss_merge(ni);
- }
- }
- break;
- }
-}
-
/*
* Set the default antenna.
*/
-static void
+void
ath_setdefantenna(struct ath_softc *sc, u_int antenna)
{
struct ath_hal *ah = sc->sc_ah;
@@ -3992,538 +3134,6 @@
}
static void
-ath_rx_tap(struct ifnet *ifp, struct mbuf *m,
- const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
-{
-#define CHAN_HT20 htole32(IEEE80211_CHAN_HT20)
-#define CHAN_HT40U htole32(IEEE80211_CHAN_HT40U)
-#define CHAN_HT40D htole32(IEEE80211_CHAN_HT40D)
-#define CHAN_HT (CHAN_HT20|CHAN_HT40U|CHAN_HT40D)
- struct ath_softc *sc = ifp->if_softc;
- const HAL_RATE_TABLE *rt;
- uint8_t rix;
-
- rt = sc->sc_currates;
- KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
- rix = rt->rateCodeToIndex[rs->rs_rate];
- sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate;
- sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags;
-#ifdef AH_SUPPORT_AR5416
- sc->sc_rx_th.wr_chan_flags &= ~CHAN_HT;
- if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */
- struct ieee80211com *ic = ifp->if_l2com;
-
- if ((rs->rs_flags & HAL_RX_2040) == 0)
- sc->sc_rx_th.wr_chan_flags |= CHAN_HT20;
- else if (IEEE80211_IS_CHAN_HT40U(ic->ic_curchan))
- sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U;
- else
- sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D;
- if ((rs->rs_flags & HAL_RX_GI) == 0)
- sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI;
- }
-#endif
- sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf));
- if (rs->rs_status & HAL_RXERR_CRC)
- sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
- /* XXX propagate other error flags from descriptor */
- sc->sc_rx_th.wr_antnoise = nf;
- sc->sc_rx_th.wr_antsignal = nf + rs->rs_rssi;
- sc->sc_rx_th.wr_antenna = rs->rs_antenna;
-#undef CHAN_HT
-#undef CHAN_HT20
-#undef CHAN_HT40U
-#undef CHAN_HT40D
-}
-
-static void
-ath_handle_micerror(struct ieee80211com *ic,
- struct ieee80211_frame *wh, int keyix)
-{
- struct ieee80211_node *ni;
-
- /* XXX recheck MIC to deal w/ chips that lie */
- /* XXX discard MIC errors on !data frames */
- ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh);
- if (ni != NULL) {
- ieee80211_notify_michael_failure(ni->ni_vap, wh, keyix);
- ieee80211_free_node(ni);
- }
-}
-
-/*
- * Only run the RX proc if it's not already running.
- * Since this may get run as part of the reset/flush path,
- * the task can't clash with an existing, running tasklet.
- */
-static void
-ath_rx_tasklet(void *arg, int npending)
-{
- struct ath_softc *sc = arg;
-
- CTR1(ATH_KTR_INTR, "ath_rx_proc: pending=%d", npending);
- DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending);
- ATH_PCU_LOCK(sc);
- if (sc->sc_inreset_cnt > 0) {
- device_printf(sc->sc_dev,
- "%s: sc_inreset_cnt > 0; skipping\n", __func__);
- ATH_PCU_UNLOCK(sc);
- return;
- }
- ATH_PCU_UNLOCK(sc);
- ath_rx_proc(sc, 1);
-}
-
-static void
-ath_rx_proc(struct ath_softc *sc, int resched)
-{
-#define PA2DESC(_sc, _pa) \
- ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
- ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
- struct ath_buf *bf;
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
- struct ath_hal *ah = sc->sc_ah;
- struct ath_desc *ds;
- struct ath_rx_status *rs;
- struct mbuf *m;
- struct ieee80211_node *ni;
- int len, type, ngood;
- HAL_STATUS status;
- int16_t nf;
- u_int64_t tsf, rstamp;
- int npkts = 0;
-
- /* XXX we must not hold the ATH_LOCK here */
- ATH_UNLOCK_ASSERT(sc);
- ATH_PCU_UNLOCK_ASSERT(sc);
-
- ATH_PCU_LOCK(sc);
- sc->sc_rxproc_cnt++;
- ATH_PCU_UNLOCK(sc);
-
- DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: called\n", __func__);
- ngood = 0;
- nf = ath_hal_getchannoise(ah, sc->sc_curchan);
- sc->sc_stats.ast_rx_noise = nf;
- tsf = ath_hal_gettsf64(ah);
- do {
- bf = TAILQ_FIRST(&sc->sc_rxbuf);
- if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */
- if_printf(ifp, "%s: no buffer!\n", __func__);
- break;
- } else if (bf == NULL) {
- /*
- * End of List:
- * this can happen for non-self-linked RX chains
- */
- sc->sc_stats.ast_rx_hitqueueend++;
- break;
- }
- m = bf->bf_m;
- if (m == NULL) { /* NB: shouldn't happen */
- /*
- * If mbuf allocation failed previously there
- * will be no mbuf; try again to re-populate it.
- */
- /* XXX make debug msg */
- if_printf(ifp, "%s: no mbuf!\n", __func__);
- TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
- goto rx_next;
- }
- ds = bf->bf_desc;
- if (ds->ds_link == bf->bf_daddr) {
- /* NB: never process the self-linked entry at the end */
- sc->sc_stats.ast_rx_hitqueueend++;
- break;
- }
- /* XXX sync descriptor memory */
- /*
- * Must provide the virtual address of the current
- * descriptor, the physical address, and the virtual
- * address of the next descriptor in the h/w chain.
- * This allows the HAL to look ahead to see if the
- * hardware is done with a descriptor by checking the
- * done bit in the following descriptor and the address
- * of the current descriptor the DMA engine is working
- * on. All this is necessary because of our use of
- * a self-linked list to avoid rx overruns.
- */
- rs = &bf->bf_status.ds_rxstat;
- status = ath_hal_rxprocdesc(ah, ds,
- bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs);
-#ifdef ATH_DEBUG
- if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
- ath_printrxbuf(sc, bf, 0, status == HAL_OK);
-#endif
- if (status == HAL_EINPROGRESS)
- break;
-
- TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
- npkts++;
-
- /*
- * Calculate the correct 64 bit TSF given
- * the TSF64 register value and rs_tstamp.
- */
- rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf);
-
- /* These aren't specifically errors */
-#ifdef AH_SUPPORT_AR5416
- if (rs->rs_flags & HAL_RX_GI)
- sc->sc_stats.ast_rx_halfgi++;
- if (rs->rs_flags & HAL_RX_2040)
- sc->sc_stats.ast_rx_2040++;
- if (rs->rs_flags & HAL_RX_DELIM_CRC_PRE)
- sc->sc_stats.ast_rx_pre_crc_err++;
- if (rs->rs_flags & HAL_RX_DELIM_CRC_POST)
- sc->sc_stats.ast_rx_post_crc_err++;
- if (rs->rs_flags & HAL_RX_DECRYPT_BUSY)
- sc->sc_stats.ast_rx_decrypt_busy_err++;
- if (rs->rs_flags & HAL_RX_HI_RX_CHAIN)
- sc->sc_stats.ast_rx_hi_rx_chain++;
-#endif /* AH_SUPPORT_AR5416 */
-
- if (rs->rs_status != 0) {
- if (rs->rs_status & HAL_RXERR_CRC)
- sc->sc_stats.ast_rx_crcerr++;
- if (rs->rs_status & HAL_RXERR_FIFO)
- sc->sc_stats.ast_rx_fifoerr++;
- if (rs->rs_status & HAL_RXERR_PHY) {
- sc->sc_stats.ast_rx_phyerr++;
- /* Process DFS radar events */
- if ((rs->rs_phyerr == HAL_PHYERR_RADAR) ||
- (rs->rs_phyerr == HAL_PHYERR_FALSE_RADAR_EXT)) {
- /* Since we're touching the frame data, sync it */
- bus_dmamap_sync(sc->sc_dmat,
- bf->bf_dmamap,
- BUS_DMASYNC_POSTREAD);
- /* Now pass it to the radar processing code */
- ath_dfs_process_phy_err(sc, mtod(m, char *), rstamp, rs);
- }
-
- /* Be suitably paranoid about receiving phy errors out of the stats array bounds */
- if (rs->rs_phyerr < 64)
- sc->sc_stats.ast_rx_phy[rs->rs_phyerr]++;
- goto rx_error; /* NB: don't count in ierrors */
- }
- if (rs->rs_status & HAL_RXERR_DECRYPT) {
- /*
- * Decrypt error. If the error occurred
- * because there was no hardware key, then
- * let the frame through so the upper layers
- * can process it. This is necessary for 5210
- * parts which have no way to setup a ``clear''
- * key cache entry.
- *
- * XXX do key cache faulting
- */
- if (rs->rs_keyix == HAL_RXKEYIX_INVALID)
- goto rx_accept;
- sc->sc_stats.ast_rx_badcrypt++;
- }
- if (rs->rs_status & HAL_RXERR_MIC) {
- sc->sc_stats.ast_rx_badmic++;
- /*
- * Do minimal work required to hand off
- * the 802.11 header for notification.
- */
- /* XXX frag's and qos frames */
- len = rs->rs_datalen;
- if (len >= sizeof (struct ieee80211_frame)) {
- bus_dmamap_sync(sc->sc_dmat,
- bf->bf_dmamap,
- BUS_DMASYNC_POSTREAD);
- ath_handle_micerror(ic,
- mtod(m, struct ieee80211_frame *),
- sc->sc_splitmic ?
- rs->rs_keyix-32 : rs->rs_keyix);
- }
- }
- ifp->if_ierrors++;
-rx_error:
- /*
- * Cleanup any pending partial frame.
- */
- if (sc->sc_rxpending != NULL) {
- m_freem(sc->sc_rxpending);
- sc->sc_rxpending = NULL;
- }
- /*
- * When a tap is present pass error frames
- * that have been requested. By default we
- * pass decrypt+mic errors but others may be
- * interesting (e.g. crc).
- */
- if (ieee80211_radiotap_active(ic) &&
- (rs->rs_status & sc->sc_monpass)) {
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
- BUS_DMASYNC_POSTREAD);
- /* NB: bpf needs the mbuf length setup */
- len = rs->rs_datalen;
- m->m_pkthdr.len = m->m_len = len;
- bf->bf_m = NULL;
- ath_rx_tap(ifp, m, rs, rstamp, nf);
- ieee80211_radiotap_rx_all(ic, m);
- m_freem(m);
- }
- /* XXX pass MIC errors up for s/w reclaculation */
- goto rx_next;
- }
-rx_accept:
- /*
- * Sync and unmap the frame. At this point we're
- * committed to passing the mbuf somewhere so clear
- * bf_m; this means a new mbuf must be allocated
- * when the rx descriptor is setup again to receive
- * another frame.
- */
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
- BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- bf->bf_m = NULL;
-
- len = rs->rs_datalen;
- m->m_len = len;
-
- if (rs->rs_more) {
- /*
- * Frame spans multiple descriptors; save
- * it for the next completed descriptor, it
- * will be used to construct a jumbogram.
- */
- if (sc->sc_rxpending != NULL) {
- /* NB: max frame size is currently 2 clusters */
- sc->sc_stats.ast_rx_toobig++;
- m_freem(sc->sc_rxpending);
- }
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = len;
- sc->sc_rxpending = m;
- goto rx_next;
- } else if (sc->sc_rxpending != NULL) {
- /*
- * This is the second part of a jumbogram,
- * chain it to the first mbuf, adjust the
- * frame length, and clear the rxpending state.
- */
- sc->sc_rxpending->m_next = m;
- sc->sc_rxpending->m_pkthdr.len += len;
- m = sc->sc_rxpending;
- sc->sc_rxpending = NULL;
- } else {
- /*
- * Normal single-descriptor receive; setup
- * the rcvif and packet length.
- */
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = len;
- }
-
- /*
- * Validate rs->rs_antenna.
- *
- * Some users w/ AR9285 NICs have reported crashes
- * here because rs_antenna field is bogusly large.
- * Let's enforce the maximum antenna limit of 8
- * (and it shouldn't be hard coded, but that's a
- * separate problem) and if there's an issue, print
- * out an error and adjust rs_antenna to something
- * sensible.
- *
- * This code should be removed once the actual
- * root cause of the issue has been identified.
- * For example, it may be that the rs_antenna
- * field is only valid for the lsat frame of
- * an aggregate and it just happens that it is
- * "mostly" right. (This is a general statement -
- * the majority of the statistics are only valid
- * for the last frame in an aggregate.
- */
- if (rs->rs_antenna > 7) {
- device_printf(sc->sc_dev, "%s: rs_antenna > 7 (%d)\n",
- __func__, rs->rs_antenna);
-#ifdef ATH_DEBUG
- ath_printrxbuf(sc, bf, 0, status == HAL_OK);
-#endif /* ATH_DEBUG */
- rs->rs_antenna = 0; /* XXX better than nothing */
- }
-
- ifp->if_ipackets++;
- sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
-
- /*
- * Populate the rx status block. When there are bpf
- * listeners we do the additional work to provide
- * complete status. Otherwise we fill in only the
- * material required by ieee80211_input. Note that
- * noise setting is filled in above.
- */
- if (ieee80211_radiotap_active(ic))
- ath_rx_tap(ifp, m, rs, rstamp, nf);
-
- /*
- * From this point on we assume the frame is at least
- * as large as ieee80211_frame_min; verify that.
- */
- if (len < IEEE80211_MIN_LEN) {
- if (!ieee80211_radiotap_active(ic)) {
- DPRINTF(sc, ATH_DEBUG_RECV,
- "%s: short packet %d\n", __func__, len);
- sc->sc_stats.ast_rx_tooshort++;
- } else {
- /* NB: in particular this captures ack's */
- ieee80211_radiotap_rx_all(ic, m);
- }
- m_freem(m);
- goto rx_next;
- }
-
- if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) {
- const HAL_RATE_TABLE *rt = sc->sc_currates;
- uint8_t rix = rt->rateCodeToIndex[rs->rs_rate];
-
- ieee80211_dump_pkt(ic, mtod(m, caddr_t), len,
- sc->sc_hwmap[rix].ieeerate, rs->rs_rssi);
- }
-
- m_adj(m, -IEEE80211_CRC_LEN);
-
- /*
- * Locate the node for sender, track state, and then
- * pass the (referenced) node up to the 802.11 layer
- * for its use.
- */
- ni = ieee80211_find_rxnode_withkey(ic,
- mtod(m, const struct ieee80211_frame_min *),
- rs->rs_keyix == HAL_RXKEYIX_INVALID ?
- IEEE80211_KEYIX_NONE : rs->rs_keyix);
- sc->sc_lastrs = rs;
-
-#ifdef AH_SUPPORT_AR5416
- if (rs->rs_isaggr)
- sc->sc_stats.ast_rx_agg++;
-#endif /* AH_SUPPORT_AR5416 */
-
- if (ni != NULL) {
- /*
- * Only punt packets for ampdu reorder processing for
- * 11n nodes; net80211 enforces that M_AMPDU is only
- * set for 11n nodes.
- */
- if (ni->ni_flags & IEEE80211_NODE_HT)
- m->m_flags |= M_AMPDU;
-
- /*
- * Sending station is known, dispatch directly.
- */
- type = ieee80211_input(ni, m, rs->rs_rssi, nf);
- ieee80211_free_node(ni);
- /*
- * Arrange to update the last rx timestamp only for
- * frames from our ap when operating in station mode.
- * This assumes the rx key is always setup when
- * associated.
- */
- if (ic->ic_opmode == IEEE80211_M_STA &&
- rs->rs_keyix != HAL_RXKEYIX_INVALID)
- ngood++;
- } else {
- type = ieee80211_input_all(ic, m, rs->rs_rssi, nf);
- }
- /*
- * Track rx rssi and do any rx antenna management.
- */
- ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi);
- if (sc->sc_diversity) {
- /*
- * When using fast diversity, change the default rx
- * antenna if diversity chooses the other antenna 3
- * times in a row.
- */
- if (sc->sc_defant != rs->rs_antenna) {
- if (++sc->sc_rxotherant >= 3)
- ath_setdefantenna(sc, rs->rs_antenna);
- } else
- sc->sc_rxotherant = 0;
- }
-
- /* Newer school diversity - kite specific for now */
- /* XXX perhaps migrate the normal diversity code to this? */
- if ((ah)->ah_rxAntCombDiversity)
- (*(ah)->ah_rxAntCombDiversity)(ah, rs, ticks, hz);
-
- if (sc->sc_softled) {
- /*
- * Blink for any data frame. Otherwise do a
- * heartbeat-style blink when idle. The latter
- * is mainly for station mode where we depend on
- * periodic beacon frames to trigger the poll event.
- */
- if (type == IEEE80211_FC0_TYPE_DATA) {
- const HAL_RATE_TABLE *rt = sc->sc_currates;
- ath_led_event(sc,
- rt->rateCodeToIndex[rs->rs_rate]);
- } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle)
- ath_led_event(sc, 0);
- }
-rx_next:
- TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
- } while (ath_rxbuf_init(sc, bf) == 0);
-
- /* rx signal state monitoring */
- ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan);
- if (ngood)
- sc->sc_lastrx = tsf;
-
- CTR2(ATH_KTR_INTR, "ath_rx_proc: npkts=%d, ngood=%d", npkts, ngood);
- /* Queue DFS tasklet if needed */
- if (resched && ath_dfs_tasklet_needed(sc, sc->sc_curchan))
- taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask);
-
- /*
- * Now that all the RX frames were handled that
- * need to be handled, kick the PCU if there's
- * been an RXEOL condition.
- */
- ATH_PCU_LOCK(sc);
- if (resched && sc->sc_kickpcu) {
- CTR0(ATH_KTR_ERR, "ath_rx_proc: kickpcu");
- device_printf(sc->sc_dev, "%s: kickpcu; handled %d packets\n",
- __func__, npkts);
-
- /* XXX rxslink? */
- /*
- * XXX can we hold the PCU lock here?
- * Are there any net80211 buffer calls involved?
- */
- bf = TAILQ_FIRST(&sc->sc_rxbuf);
- ath_hal_putrxbuf(ah, bf->bf_daddr);
- ath_hal_rxena(ah); /* enable recv descriptors */
- ath_mode_init(sc); /* set filters, etc. */
- ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */
-
- ath_hal_intrset(ah, sc->sc_imask);
- sc->sc_kickpcu = 0;
- }
- ATH_PCU_UNLOCK(sc);
-
- /* XXX check this inside of IF_LOCK? */
- if (resched && (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
-#ifdef IEEE80211_SUPPORT_SUPERG
- ieee80211_ff_age_all(ic, 100);
-#endif
- if (!IFQ_IS_EMPTY(&ifp->if_snd))
- ath_start(ifp);
- }
-#undef PA2DESC
-
- ATH_PCU_LOCK(sc);
- sc->sc_rxproc_cnt--;
- ATH_PCU_UNLOCK(sc);
-}
-
-static void
ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum)
{
txq->axq_qnum = qnum;
@@ -4700,7 +3310,7 @@
/*
* Callback from the 802.11 layer to update WME parameters.
*/
-static int
+int
ath_wme_update(struct ieee80211com *ic)
{
struct ath_softc *sc = ic->ic_ifp->if_softc;
@@ -4887,12 +3497,14 @@
* descriptor.
*/
ATH_TXBUF_LOCK_ASSERT(sc);
+ last = TAILQ_LAST(&sc->sc_txbuf_mgmt, ath_bufhead_s);
+ if (last != NULL)
+ last->bf_flags &= ~ATH_BUF_BUSY;
last = TAILQ_LAST(&sc->sc_txbuf, ath_bufhead_s);
if (last != NULL)
last->bf_flags &= ~ATH_BUF_BUSY;
}
-
/*
* Process completed xmit descriptors from the specified queue.
* Kick the packet scheduler if needed. This can occur from this
@@ -5063,7 +3675,7 @@
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
- ath_start(ifp);
+ ath_tx_kick(sc);
}
/*
@@ -5113,7 +3725,7 @@
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
- ath_start(ifp);
+ ath_tx_kick(sc);
}
/*
@@ -5156,7 +3768,7 @@
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
- ath_start(ifp);
+ ath_tx_kick(sc);
}
#undef TXQACTIVE
@@ -5195,6 +3807,48 @@
ATH_PCU_UNLOCK(sc);
}
+void
+ath_returnbuf_tail(struct ath_softc *sc, struct ath_buf *bf)
+{
+
+ ATH_TXBUF_LOCK_ASSERT(sc);
+
+ if (bf->bf_flags & ATH_BUF_MGMT)
+ TAILQ_INSERT_TAIL(&sc->sc_txbuf_mgmt, bf, bf_list);
+ else {
+ TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ sc->sc_txbuf_cnt++;
+ if (sc->sc_txbuf_cnt > ath_txbuf) {
+ device_printf(sc->sc_dev,
+ "%s: sc_txbuf_cnt > %d?\n",
+ __func__,
+ ath_txbuf);
+ sc->sc_txbuf_cnt = ath_txbuf;
+ }
+ }
+}
+
+void
+ath_returnbuf_head(struct ath_softc *sc, struct ath_buf *bf)
+{
+
+ ATH_TXBUF_LOCK_ASSERT(sc);
+
+ if (bf->bf_flags & ATH_BUF_MGMT)
+ TAILQ_INSERT_HEAD(&sc->sc_txbuf_mgmt, bf, bf_list);
+ else {
+ TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ sc->sc_txbuf_cnt++;
+ if (sc->sc_txbuf_cnt > ATH_TXBUF) {
+ device_printf(sc->sc_dev,
+ "%s: sc_txbuf_cnt > %d?\n",
+ __func__,
+ ATH_TXBUF);
+ sc->sc_txbuf_cnt = ATH_TXBUF;
+ }
+ }
+}
+
/*
* Return a buffer to the pool and update the 'busy' flag on the
* previous 'tail' entry.
@@ -5217,7 +3871,7 @@
ATH_TXBUF_LOCK(sc);
ath_tx_update_busy(sc);
- TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ath_returnbuf_tail(sc, bf);
ATH_TXBUF_UNLOCK(sc);
}
@@ -5273,6 +3927,9 @@
bf = TAILQ_LAST(&sc->sc_txbuf, ath_bufhead_s);
if (bf != NULL)
bf->bf_flags &= ~ATH_BUF_BUSY;
+ bf = TAILQ_LAST(&sc->sc_txbuf_mgmt, ath_bufhead_s);
+ if (bf != NULL)
+ bf->bf_flags &= ~ATH_BUF_BUSY;
ATH_TXBUF_UNLOCK(sc);
for (ix = 0;; ix++) {
@@ -5404,81 +4061,6 @@
}
/*
- * Disable the receive h/w in preparation for a reset.
- */
-static void
-ath_stoprecv(struct ath_softc *sc, int dodelay)
-{
-#define PA2DESC(_sc, _pa) \
- ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
- ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
- struct ath_hal *ah = sc->sc_ah;
-
- ath_hal_stoppcurecv(ah); /* disable PCU */
- ath_hal_setrxfilter(ah, 0); /* clear recv filter */
- ath_hal_stopdmarecv(ah); /* disable DMA engine */
- if (dodelay)
- DELAY(3000); /* 3ms is long enough for 1 frame */
-#ifdef ATH_DEBUG
- if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) {
- struct ath_buf *bf;
- u_int ix;
-
- device_printf(sc->sc_dev,
- "%s: rx queue %p, link %p\n",
- __func__,
- (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah),
- sc->sc_rxlink);
- ix = 0;
- TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
- struct ath_desc *ds = bf->bf_desc;
- struct ath_rx_status *rs = &bf->bf_status.ds_rxstat;
- HAL_STATUS status = ath_hal_rxprocdesc(ah, ds,
- bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs);
- if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL))
- ath_printrxbuf(sc, bf, ix, status == HAL_OK);
- ix++;
- }
- }
-#endif
- if (sc->sc_rxpending != NULL) {
- m_freem(sc->sc_rxpending);
- sc->sc_rxpending = NULL;
- }
- sc->sc_rxlink = NULL; /* just in case */
-#undef PA2DESC
-}
-
-/*
- * Enable the receive h/w following a reset.
- */
-static int
-ath_startrecv(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
- struct ath_buf *bf;
-
- sc->sc_rxlink = NULL;
- sc->sc_rxpending = NULL;
- TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
- int error = ath_rxbuf_init(sc, bf);
- if (error != 0) {
- DPRINTF(sc, ATH_DEBUG_RECV,
- "%s: ath_rxbuf_init failed %d\n",
- __func__, error);
- return error;
- }
- }
-
- bf = TAILQ_FIRST(&sc->sc_rxbuf);
- ath_hal_putrxbuf(ah, bf->bf_daddr);
- ath_hal_rxena(ah); /* enable recv descriptors */
- ath_mode_init(sc); /* set filters, etc. */
- ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */
- return 0;
-}
-
-/*
* Update internal state after a channel change.
*/
static void
@@ -5544,7 +4126,7 @@
/*
* First, handle completed TX/RX frames.
*/
- ath_rx_proc(sc, 0);
+ ath_rx_flush(sc);
ath_draintxq(sc, ATH_RESET_NOLOSS);
/*
* Next, flush the non-scheduled frames.
@@ -6360,6 +4942,43 @@
callout_schedule(&sc->sc_wd_ch, hz);
}
+/*
+ * Fetch the rate control statistics for the given node.
+ */
+static int
+ath_ioctl_ratestats(struct ath_softc *sc, struct ath_rateioctl *rs)
+{
+ struct ath_node *an;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_node *ni;
+ int error = 0;
+
+ /* Perform a lookup on the given node */
+ ni = ieee80211_find_node(&ic->ic_sta, rs->is_u.macaddr);
+ if (ni == NULL) {
+ error = EINVAL;
+ goto bad;
+ }
+
+ /* Lock the ath_node */
+ an = ATH_NODE(ni);
+ ATH_NODE_LOCK(an);
+
+ /* Fetch the rate control stats for this node */
+ error = ath_rate_fetch_node_stats(sc, an, rs);
+
+ /* No matter what happens here, just drop through */
+
+ /* Unlock the ath_node */
+ ATH_NODE_UNLOCK(an);
+
+ /* Unref the node */
+ ieee80211_node_decref(ni);
+
+bad:
+ return (error);
+}
+
#ifdef ATH_DIAGAPI
/*
* Diagnostic interface to the HAL. This is used by various
@@ -6487,6 +5106,9 @@
sc->sc_stats.ast_tx_rate |= IEEE80211_RATE_MCS;
return copyout(&sc->sc_stats,
ifr->ifr_data, sizeof (sc->sc_stats));
+ case SIOCGATHAGSTATS:
+ return copyout(&sc->sc_aggr_stats,
+ ifr->ifr_data, sizeof (sc->sc_aggr_stats));
case SIOCZATHSTATS:
error = priv_check(curthread, PRIV_DRIVER);
if (error == 0) {
@@ -6505,6 +5127,9 @@
error = ath_ioctl_phyerr(sc,(struct ath_diag*) ifr);
break;
#endif
+ case SIOCGATHNODERATESTATS:
+ error = ath_ioctl_ratestats(sc, (struct ath_rateioctl *) ifr);
+ break;
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
@@ -6549,357 +5174,6 @@
if_printf(ifp, "using multicast key search\n");
}
-#ifdef IEEE80211_SUPPORT_TDMA
-static void
-ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval)
-{
- struct ath_hal *ah = sc->sc_ah;
- HAL_BEACON_TIMERS bt;
-
- bt.bt_intval = bintval | HAL_BEACON_ENA;
- bt.bt_nexttbtt = nexttbtt;
- bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep;
- bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep;
- bt.bt_nextatim = nexttbtt+1;
- /* Enables TBTT, DBA, SWBA timers by default */
- bt.bt_flags = 0;
- ath_hal_beaconsettimers(ah, &bt);
-}
-
-/*
- * Calculate the beacon interval. This is periodic in the
- * superframe for the bss. We assume each station is configured
- * identically wrt transmit rate so the guard time we calculate
- * above will be the same on all stations. Note we need to
- * factor in the xmit time because the hardware will schedule
- * a frame for transmit if the start of the frame is within
- * the burst time. When we get hardware that properly kills
- * frames in the PCU we can reduce/eliminate the guard time.
- *
- * Roundup to 1024 is so we have 1 TU buffer in the guard time
- * to deal with the granularity of the nexttbtt timer. 11n MAC's
- * with 1us timer granularity should allow us to reduce/eliminate
- * this.
- */
-static void
-ath_tdma_bintvalsetup(struct ath_softc *sc,
- const struct ieee80211_tdma_state *tdma)
-{
- /* copy from vap state (XXX check all vaps have same value?) */
- sc->sc_tdmaslotlen = tdma->tdma_slotlen;
-
- sc->sc_tdmabintval = roundup((sc->sc_tdmaslotlen+sc->sc_tdmaguard) *
- tdma->tdma_slotcnt, 1024);
- sc->sc_tdmabintval >>= 10; /* TSF -> TU */
- if (sc->sc_tdmabintval & 1)
- sc->sc_tdmabintval++;
-
- if (tdma->tdma_slot == 0) {
- /*
- * Only slot 0 beacons; other slots respond.
- */
- sc->sc_imask |= HAL_INT_SWBA;
- sc->sc_tdmaswba = 0; /* beacon immediately */
- } else {
- /* XXX all vaps must be slot 0 or slot !0 */
- sc->sc_imask &= ~HAL_INT_SWBA;
- }
-}
-
-/*
- * Max 802.11 overhead. This assumes no 4-address frames and
- * the encapsulation done by ieee80211_encap (llc). We also
- * include potential crypto overhead.
- */
-#define IEEE80211_MAXOVERHEAD \
- (sizeof(struct ieee80211_qosframe) \
- + sizeof(struct llc) \
- + IEEE80211_ADDR_LEN \
- + IEEE80211_WEP_IVLEN \
- + IEEE80211_WEP_KIDLEN \
- + IEEE80211_WEP_CRCLEN \
- + IEEE80211_WEP_MICLEN \
- + IEEE80211_CRC_LEN)
-
-/*
- * Setup initially for tdma operation. Start the beacon
- * timers and enable SWBA if we are slot 0. Otherwise
- * we wait for slot 0 to arrive so we can sync up before
- * starting to transmit.
- */
-static void
-ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap)
-{
- struct ath_hal *ah = sc->sc_ah;
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
- const struct ieee80211_txparam *tp;
- const struct ieee80211_tdma_state *tdma = NULL;
- int rix;
-
- if (vap == NULL) {
- vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
- if (vap == NULL) {
- if_printf(ifp, "%s: no vaps?\n", __func__);
- return;
- }
- }
- /* XXX should take a locked ref to iv_bss */
- tp = vap->iv_bss->ni_txparms;
- /*
- * Calculate the guard time for each slot. This is the
- * time to send a maximal-size frame according to the
- * fixed/lowest transmit rate. Note that the interface
- * mtu does not include the 802.11 overhead so we must
- * tack that on (ath_hal_computetxtime includes the
- * preamble and plcp in it's calculation).
- */
- tdma = vap->iv_tdma;
- if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
- rix = ath_tx_findrix(sc, tp->ucastrate);
- else
- rix = ath_tx_findrix(sc, tp->mcastrate);
- /* XXX short preamble assumed */
- sc->sc_tdmaguard = ath_hal_computetxtime(ah, sc->sc_currates,
- ifp->if_mtu + IEEE80211_MAXOVERHEAD, rix, AH_TRUE);
-
- ath_hal_intrset(ah, 0);
-
- ath_beaconq_config(sc); /* setup h/w beacon q */
- if (sc->sc_setcca)
- ath_hal_setcca(ah, AH_FALSE); /* disable CCA */
- ath_tdma_bintvalsetup(sc, tdma); /* calculate beacon interval */
- ath_tdma_settimers(sc, sc->sc_tdmabintval,
- sc->sc_tdmabintval | HAL_BEACON_RESET_TSF);
- sc->sc_syncbeacon = 0;
-
- sc->sc_avgtsfdeltap = TDMA_DUMMY_MARKER;
- sc->sc_avgtsfdeltam = TDMA_DUMMY_MARKER;
-
- ath_hal_intrset(ah, sc->sc_imask);
-
- DPRINTF(sc, ATH_DEBUG_TDMA, "%s: slot %u len %uus cnt %u "
- "bsched %u guard %uus bintval %u TU dba prep %u\n", __func__,
- tdma->tdma_slot, tdma->tdma_slotlen, tdma->tdma_slotcnt,
- tdma->tdma_bintval, sc->sc_tdmaguard, sc->sc_tdmabintval,
- sc->sc_tdmadbaprep);
-}
-
-/*
- * Update tdma operation. Called from the 802.11 layer
- * when a beacon is received from the TDMA station operating
- * in the slot immediately preceding us in the bss. Use
- * the rx timestamp for the beacon frame to update our
- * beacon timers so we follow their schedule. Note that
- * by using the rx timestamp we implicitly include the
- * propagation delay in our schedule.
- */
-static void
-ath_tdma_update(struct ieee80211_node *ni,
- const struct ieee80211_tdma_param *tdma, int changed)
-{
-#define TSF_TO_TU(_h,_l) \
- ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
-#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10)
- struct ieee80211vap *vap = ni->ni_vap;
- struct ieee80211com *ic = ni->ni_ic;
- struct ath_softc *sc = ic->ic_ifp->if_softc;
- struct ath_hal *ah = sc->sc_ah;
- const HAL_RATE_TABLE *rt = sc->sc_currates;
- u_int64_t tsf, rstamp, nextslot, nexttbtt;
- u_int32_t txtime, nextslottu;
- int32_t tudelta, tsfdelta;
- const struct ath_rx_status *rs;
- int rix;
-
- sc->sc_stats.ast_tdma_update++;
-
- /*
- * Check for and adopt configuration changes.
- */
- if (changed != 0) {
- const struct ieee80211_tdma_state *ts = vap->iv_tdma;
-
- ath_tdma_bintvalsetup(sc, ts);
- if (changed & TDMA_UPDATE_SLOTLEN)
- ath_wme_update(ic);
-
- DPRINTF(sc, ATH_DEBUG_TDMA,
- "%s: adopt slot %u slotcnt %u slotlen %u us "
- "bintval %u TU\n", __func__,
- ts->tdma_slot, ts->tdma_slotcnt, ts->tdma_slotlen,
- sc->sc_tdmabintval);
-
- /* XXX right? */
- ath_hal_intrset(ah, sc->sc_imask);
- /* NB: beacon timers programmed below */
- }
-
- /* extend rx timestamp to 64 bits */
- rs = sc->sc_lastrs;
- tsf = ath_hal_gettsf64(ah);
- rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf);
- /*
- * The rx timestamp is set by the hardware on completing
- * reception (at the point where the rx descriptor is DMA'd
- * to the host). To find the start of our next slot we
- * must adjust this time by the time required to send
- * the packet just received.
- */
- rix = rt->rateCodeToIndex[rs->rs_rate];
- txtime = ath_hal_computetxtime(ah, rt, rs->rs_datalen, rix,
- rt->info[rix].shortPreamble);
- /* NB: << 9 is to cvt to TU and /2 */
- nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9);
- nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD;
-
- /*
- * Retrieve the hardware NextTBTT in usecs
- * and calculate the difference between what the
- * other station thinks and what we have programmed. This
- * lets us figure how to adjust our timers to match. The
- * adjustments are done by pulling the TSF forward and possibly
- * rewriting the beacon timers.
- */
- nexttbtt = ath_hal_getnexttbtt(ah);
- tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt);
-
- DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
- "tsfdelta %d avg +%d/-%d\n", tsfdelta,
- TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam));
-
- if (tsfdelta < 0) {
- TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0);
- TDMA_SAMPLE(sc->sc_avgtsfdeltam, -tsfdelta);
- tsfdelta = -tsfdelta % 1024;
- nextslottu++;
- } else if (tsfdelta > 0) {
- TDMA_SAMPLE(sc->sc_avgtsfdeltap, tsfdelta);
- TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0);
- tsfdelta = 1024 - (tsfdelta % 1024);
- nextslottu++;
- } else {
- TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0);
- TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0);
- }
- tudelta = nextslottu - TSF_TO_TU(nexttbtt >> 32, nexttbtt);
-
- /*
- * Copy sender's timetstamp into tdma ie so they can
- * calculate roundtrip time. We submit a beacon frame
- * below after any timer adjustment. The frame goes out
- * at the next TBTT so the sender can calculate the
- * roundtrip by inspecting the tdma ie in our beacon frame.
- *
- * NB: This tstamp is subtlely preserved when
- * IEEE80211_BEACON_TDMA is marked (e.g. when the
- * slot position changes) because ieee80211_add_tdma
- * skips over the data.
- */
- memcpy(ATH_VAP(vap)->av_boff.bo_tdma +
- __offsetof(struct ieee80211_tdma_param, tdma_tstamp),
- &ni->ni_tstamp.data, 8);
-#if 0
- DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
- "tsf %llu nextslot %llu (%d, %d) nextslottu %u nexttbtt %llu (%d)\n",
- (unsigned long long) tsf, (unsigned long long) nextslot,
- (int)(nextslot - tsf), tsfdelta, nextslottu, nexttbtt, tudelta);
-#endif
- /*
- * Adjust the beacon timers only when pulling them forward
- * or when going back by less than the beacon interval.
- * Negative jumps larger than the beacon interval seem to
- * cause the timers to stop and generally cause instability.
- * This basically filters out jumps due to missed beacons.
- */
- if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) {
- ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval);
- sc->sc_stats.ast_tdma_timers++;
- }
- if (tsfdelta > 0) {
- ath_hal_adjusttsf(ah, tsfdelta);
- sc->sc_stats.ast_tdma_tsf++;
- }
- ath_tdma_beacon_send(sc, vap); /* prepare response */
-#undef TU_TO_TSF
-#undef TSF_TO_TU
-}
-
-/*
- * Transmit a beacon frame at SWBA. Dynamic updates
- * to the frame contents are done as needed.
- */
-static void
-ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap)
-{
- struct ath_hal *ah = sc->sc_ah;
- struct ath_buf *bf;
- int otherant;
-
- /*
- * Check if the previous beacon has gone out. If
- * not don't try to post another, skip this period
- * and wait for the next. Missed beacons indicate
- * a problem and should not occur. If we miss too
- * many consecutive beacons reset the device.
- */
- if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
- sc->sc_bmisscount++;
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: missed %u consecutive beacons\n",
- __func__, sc->sc_bmisscount);
- if (sc->sc_bmisscount >= ath_bstuck_threshold)
- taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask);
- return;
- }
- if (sc->sc_bmisscount != 0) {
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: resume beacon xmit after %u misses\n",
- __func__, sc->sc_bmisscount);
- sc->sc_bmisscount = 0;
- }
-
- /*
- * Check recent per-antenna transmit statistics and flip
- * the default antenna if noticeably more frames went out
- * on the non-default antenna.
- * XXX assumes 2 anntenae
- */
- if (!sc->sc_diversity) {
- otherant = sc->sc_defant & 1 ? 2 : 1;
- if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
- ath_setdefantenna(sc, otherant);
- sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
- }
-
- bf = ath_beacon_generate(sc, vap);
- if (bf != NULL) {
- /*
- * Stop any current dma and put the new frame on the queue.
- * This should never fail since we check above that no frames
- * are still pending on the queue.
- */
- if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
- DPRINTF(sc, ATH_DEBUG_ANY,
- "%s: beacon queue %u did not stop?\n",
- __func__, sc->sc_bhalq);
- /* NB: the HAL still stops DMA, so proceed */
- }
- ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
- ath_hal_txstart(ah, sc->sc_bhalq);
-
- sc->sc_stats.ast_be_xmit++; /* XXX per-vap? */
-
- /*
- * Record local TSF for our last send for use
- * in arbitrating slot collisions.
- */
- /* XXX should take a locked ref to iv_bss */
- vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah);
- }
-}
-#endif /* IEEE80211_SUPPORT_TDMA */
-
static void
ath_dfs_tasklet(void *p, int npending)
{
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_ahb.c
--- a/head/sys/dev/ath/if_ath_ahb.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_ahb.c Wed Jul 25 17:07:47 2012 +0300
@@ -29,12 +29,14 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_ahb.c 227328 2011-11-08 02:12:11Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_ahb.c 238709 2012-07-23 02:49:25Z adrian $");
/*
* AHB bus front-end for the Atheros Wireless LAN controller driver.
*/
+#include "opt_ath.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/module.h>
@@ -192,11 +194,15 @@
ATH_LOCK_INIT(sc);
ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TXSTATUS_LOCK_INIT(sc);
error = ath_attach(AR9130_DEVID, sc);
if (error == 0) /* success */
return 0;
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
bus_dma_tag_destroy(sc->sc_dmat);
@@ -235,6 +241,8 @@
if (sc->sc_eepromdata)
free(sc->sc_eepromdata, M_TEMP);
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_beacon.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_beacon.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,844 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_beacon.c 238609 2012-07-19 03:51:16Z adrian $");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h> /* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_beacon.h>
+
+#ifdef ATH_TX99_DIAG
+#include <dev/ath/ath_tx99/ath_tx99.h>
+#endif
+
+/*
+ * Setup a h/w transmit queue for beacons.
+ */
+int
+ath_beaconq_setup(struct ath_hal *ah)
+{
+ HAL_TXQ_INFO qi;
+
+ memset(&qi, 0, sizeof(qi));
+ qi.tqi_aifs = HAL_TXQ_USEDEFAULT;
+ qi.tqi_cwmin = HAL_TXQ_USEDEFAULT;
+ qi.tqi_cwmax = HAL_TXQ_USEDEFAULT;
+ /* NB: for dynamic turbo, don't enable any other interrupts */
+ qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE;
+ return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi);
+}
+
+/*
+ * Setup the transmit queue parameters for the beacon queue.
+ */
+int
+ath_beaconq_config(struct ath_softc *sc)
+{
+#define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1)
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_TXQ_INFO qi;
+
+ ath_hal_gettxqueueprops(ah, sc->sc_bhalq, &qi);
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_MBSS) {
+ /*
+ * Always burst out beacon and CAB traffic.
+ */
+ qi.tqi_aifs = ATH_BEACON_AIFS_DEFAULT;
+ qi.tqi_cwmin = ATH_BEACON_CWMIN_DEFAULT;
+ qi.tqi_cwmax = ATH_BEACON_CWMAX_DEFAULT;
+ } else {
+ struct wmeParams *wmep =
+ &ic->ic_wme.wme_chanParams.cap_wmeParams[WME_AC_BE];
+ /*
+ * Adhoc mode; important thing is to use 2x cwmin.
+ */
+ qi.tqi_aifs = wmep->wmep_aifsn;
+ qi.tqi_cwmin = 2*ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
+ qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
+ }
+
+ if (!ath_hal_settxqueueprops(ah, sc->sc_bhalq, &qi)) {
+ device_printf(sc->sc_dev, "unable to update parameters for "
+ "beacon hardware queue!\n");
+ return 0;
+ } else {
+ ath_hal_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */
+ return 1;
+ }
+#undef ATH_EXPONENT_TO_VALUE
+}
+
+/*
+ * Allocate and setup an initial beacon frame.
+ */
+int
+ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_vap *avp = ATH_VAP(vap);
+ struct ath_buf *bf;
+ struct mbuf *m;
+ int error;
+
+ bf = avp->av_bcbuf;
+ DPRINTF(sc, ATH_DEBUG_NODE, "%s: bf_m=%p, bf_node=%p\n",
+ __func__, bf->bf_m, bf->bf_node);
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_node != NULL) {
+ ieee80211_free_node(bf->bf_node);
+ bf->bf_node = NULL;
+ }
+
+ /*
+ * NB: the beacon data buffer must be 32-bit aligned;
+ * we assume the mbuf routines will return us something
+ * with this alignment (perhaps should assert).
+ */
+ m = ieee80211_beacon_alloc(ni, &avp->av_boff);
+ if (m == NULL) {
+ device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__);
+ sc->sc_stats.ast_be_nombuf++;
+ return ENOMEM;
+ }
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: cannot map mbuf, bus_dmamap_load_mbuf_sg returns %d\n",
+ __func__, error);
+ m_freem(m);
+ return error;
+ }
+
+ /*
+ * Calculate a TSF adjustment factor required for staggered
+ * beacons. Note that we assume the format of the beacon
+ * frame leaves the tstamp field immediately following the
+ * header.
+ */
+ if (sc->sc_stagbeacons && avp->av_bslot > 0) {
+ uint64_t tsfadjust;
+ struct ieee80211_frame *wh;
+
+ /*
+ * The beacon interval is in TU's; the TSF is in usecs.
+ * We figure out how many TU's to add to align the timestamp
+ * then convert to TSF units and handle byte swapping before
+ * inserting it in the frame. The hardware will then add this
+ * each time a beacon frame is sent. Note that we align vap's
+ * 1..N and leave vap 0 untouched. This means vap 0 has a
+ * timestamp in one beacon interval while the others get a
+ * timstamp aligned to the next interval.
+ */
+ tsfadjust = ni->ni_intval *
+ (ATH_BCBUF - avp->av_bslot) / ATH_BCBUF;
+ tsfadjust = htole64(tsfadjust << 10); /* TU -> TSF */
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: %s beacons bslot %d intval %u tsfadjust %llu\n",
+ __func__, sc->sc_stagbeacons ? "stagger" : "burst",
+ avp->av_bslot, ni->ni_intval,
+ (long long unsigned) le64toh(tsfadjust));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust));
+ }
+ bf->bf_m = m;
+ bf->bf_node = ieee80211_ref_node(ni);
+
+ return 0;
+}
+
+/*
+ * Setup the beacon frame for transmit.
+ */
+static void
+ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
+{
+#define USE_SHPREAMBLE(_ic) \
+ (((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\
+ == IEEE80211_F_SHPREAMBLE)
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ieee80211com *ic = ni->ni_ic;
+ struct mbuf *m = bf->bf_m;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_desc *ds;
+ int flags, antenna;
+ const HAL_RATE_TABLE *rt;
+ u_int8_t rix, rate;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n",
+ __func__, m, m->m_len);
+
+ /* setup descriptors */
+ ds = bf->bf_desc;
+ bf->bf_last = bf;
+ bf->bf_lastds = ds;
+
+ flags = HAL_TXDESC_NOACK;
+ if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) {
+ /* self-linked descriptor */
+ ath_hal_settxdesclink(sc->sc_ah, ds, bf->bf_daddr);
+ flags |= HAL_TXDESC_VEOL;
+ /*
+ * Let hardware handle antenna switching.
+ */
+ antenna = sc->sc_txantenna;
+ } else {
+ ath_hal_settxdesclink(sc->sc_ah, ds, 0);
+ /*
+ * Switch antenna every 4 beacons.
+ * XXX assumes two antenna
+ */
+ if (sc->sc_txantenna != 0)
+ antenna = sc->sc_txantenna;
+ else if (sc->sc_stagbeacons && sc->sc_nbcnvaps != 0)
+ antenna = ((sc->sc_stats.ast_be_xmit / sc->sc_nbcnvaps) & 4 ? 2 : 1);
+ else
+ antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1);
+ }
+
+ KASSERT(bf->bf_nseg == 1,
+ ("multi-segment beacon frame; nseg %u", bf->bf_nseg));
+ ds->ds_data = bf->bf_segs[0].ds_addr;
+ /*
+ * Calculate rate code.
+ * XXX everything at min xmit rate
+ */
+ rix = 0;
+ rt = sc->sc_currates;
+ rate = rt->info[rix].rateCode;
+ if (USE_SHPREAMBLE(ic))
+ rate |= rt->info[rix].shortPreamble;
+ ath_hal_setuptxdesc(ah, ds
+ , m->m_len + IEEE80211_CRC_LEN /* frame length */
+ , sizeof(struct ieee80211_frame)/* header length */
+ , HAL_PKT_TYPE_BEACON /* Atheros packet type */
+ , ni->ni_txpower /* txpower XXX */
+ , rate, 1 /* series 0 rate/tries */
+ , HAL_TXKEYIX_INVALID /* no encryption */
+ , antenna /* antenna mode */
+ , flags /* no ack, veol for beacons */
+ , 0 /* rts/cts rate */
+ , 0 /* rts/cts duration */
+ );
+ /* NB: beacon's BufLen must be a multiple of 4 bytes */
+ ath_hal_filltxdesc(ah, ds
+ , roundup(m->m_len, 4) /* buffer length */
+ , AH_TRUE /* first segment */
+ , AH_TRUE /* last segment */
+ , ds /* first descriptor */
+ );
+#if 0
+ ath_desc_swap(ds);
+#endif
+#undef USE_SHPREAMBLE
+}
+
+void
+ath_beacon_update(struct ieee80211vap *vap, int item)
+{
+ struct ieee80211_beacon_offsets *bo = &ATH_VAP(vap)->av_boff;
+
+ setbit(bo->bo_flags, item);
+}
+
+/*
+ * Transmit a beacon frame at SWBA. Dynamic updates to the
+ * frame contents are done as needed and the slot time is
+ * also adjusted based on current state.
+ */
+void
+ath_beacon_proc(void *arg, int pending)
+{
+ struct ath_softc *sc = arg;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211vap *vap;
+ struct ath_buf *bf;
+ int slot, otherant;
+ uint32_t bfaddr;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n",
+ __func__, pending);
+ /*
+ * Check if the previous beacon has gone out. If
+ * not don't try to post another, skip this period
+ * and wait for the next. Missed beacons indicate
+ * a problem and should not occur. If we miss too
+ * many consecutive beacons reset the device.
+ */
+ if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
+ sc->sc_bmisscount++;
+ sc->sc_stats.ast_be_missed++;
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: missed %u consecutive beacons\n",
+ __func__, sc->sc_bmisscount);
+ if (sc->sc_bmisscount >= ath_bstuck_threshold)
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask);
+ return;
+ }
+ if (sc->sc_bmisscount != 0) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: resume beacon xmit after %u misses\n",
+ __func__, sc->sc_bmisscount);
+ sc->sc_bmisscount = 0;
+ }
+
+ if (sc->sc_stagbeacons) { /* staggered beacons */
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint32_t tsftu;
+
+ tsftu = ath_hal_gettsf32(ah) >> 10;
+ /* XXX lintval */
+ slot = ((tsftu % ic->ic_lintval) * ATH_BCBUF) / ic->ic_lintval;
+ vap = sc->sc_bslot[(slot+1) % ATH_BCBUF];
+ bfaddr = 0;
+ if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) {
+ bf = ath_beacon_generate(sc, vap);
+ if (bf != NULL)
+ bfaddr = bf->bf_daddr;
+ }
+ } else { /* burst'd beacons */
+ uint32_t *bflink = &bfaddr;
+
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ vap = sc->sc_bslot[slot];
+ if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) {
+ bf = ath_beacon_generate(sc, vap);
+ if (bf != NULL) {
+ /* XXX should do this using the ds */
+ *bflink = bf->bf_daddr;
+ ath_hal_gettxdesclinkptr(sc->sc_ah,
+ bf->bf_desc, &bflink);
+ }
+ }
+ }
+ *bflink = 0; /* terminate list */
+ }
+
+ /*
+ * Handle slot time change when a non-ERP station joins/leaves
+ * an 11g network. The 802.11 layer notifies us via callback,
+ * we mark updateslot, then wait one beacon before effecting
+ * the change. This gives associated stations at least one
+ * beacon interval to note the state change.
+ */
+ /* XXX locking */
+ if (sc->sc_updateslot == UPDATE) {
+ sc->sc_updateslot = COMMIT; /* commit next beacon */
+ sc->sc_slotupdate = slot;
+ } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
+ ath_setslottime(sc); /* commit change to h/w */
+
+ /*
+ * Check recent per-antenna transmit statistics and flip
+ * the default antenna if noticeably more frames went out
+ * on the non-default antenna.
+ * XXX assumes 2 anntenae
+ */
+ if (!sc->sc_diversity && (!sc->sc_stagbeacons || slot == 0)) {
+ otherant = sc->sc_defant & 1 ? 2 : 1;
+ if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
+ ath_setdefantenna(sc, otherant);
+ sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
+ }
+
+ if (bfaddr != 0) {
+ /*
+ * Stop any current dma and put the new frame on the queue.
+ * This should never fail since we check above that no frames
+ * are still pending on the queue.
+ */
+ if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: beacon queue %u did not stop?\n",
+ __func__, sc->sc_bhalq);
+ }
+ /* NB: cabq traffic should already be queued and primed */
+ ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr);
+ ath_hal_txstart(ah, sc->sc_bhalq);
+
+ sc->sc_stats.ast_be_xmit++;
+ }
+}
+
+struct ath_buf *
+ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+ struct ath_vap *avp = ATH_VAP(vap);
+ struct ath_txq *cabq = sc->sc_cabq;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ int nmcastq, error;
+
+ KASSERT(vap->iv_state >= IEEE80211_S_RUN,
+ ("not running, state %d", vap->iv_state));
+ KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
+
+ /*
+ * Update dynamic beacon contents. If this returns
+ * non-zero then we need to remap the memory because
+ * the beacon frame changed size (probably because
+ * of the TIM bitmap).
+ */
+ bf = avp->av_bcbuf;
+ m = bf->bf_m;
+ /* XXX lock mcastq? */
+ nmcastq = avp->av_mcastq.axq_depth;
+
+ if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, nmcastq)) {
+ /* XXX too conservative? */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(vap->iv_ifp,
+ "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
+ __func__, error);
+ return NULL;
+ }
+ }
+ if ((avp->av_boff.bo_tim[4] & 1) && cabq->axq_depth) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: cabq did not drain, mcastq %u cabq %u\n",
+ __func__, nmcastq, cabq->axq_depth);
+ sc->sc_stats.ast_cabq_busy++;
+ if (sc->sc_nvaps > 1 && sc->sc_stagbeacons) {
+ /*
+ * CABQ traffic from a previous vap is still pending.
+ * We must drain the q before this beacon frame goes
+ * out as otherwise this vap's stations will get cab
+ * frames from a different vap.
+ * XXX could be slow causing us to miss DBA
+ */
+ ath_tx_draintxq(sc, cabq);
+ }
+ }
+ ath_beacon_setup(sc, bf);
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Enable the CAB queue before the beacon queue to
+ * insure cab frames are triggered by this beacon.
+ */
+ if (avp->av_boff.bo_tim[4] & 1) {
+ struct ath_hal *ah = sc->sc_ah;
+
+ /* NB: only at DTIM */
+ ATH_TXQ_LOCK(cabq);
+ ATH_TXQ_LOCK(&avp->av_mcastq);
+ if (nmcastq) {
+ struct ath_buf *bfm;
+
+ /*
+ * Move frames from the s/w mcast q to the h/w cab q.
+ * XXX MORE_DATA bit
+ */
+ bfm = TAILQ_FIRST(&avp->av_mcastq.axq_q);
+ if (cabq->axq_link != NULL) {
+ *cabq->axq_link = bfm->bf_daddr;
+ } else
+ ath_hal_puttxbuf(ah, cabq->axq_qnum,
+ bfm->bf_daddr);
+ ath_txqmove(cabq, &avp->av_mcastq);
+
+ sc->sc_stats.ast_cabq_xmit += nmcastq;
+ }
+ /* NB: gated by beacon so safe to start here */
+ if (! TAILQ_EMPTY(&(cabq->axq_q)))
+ ath_hal_txstart(ah, cabq->axq_qnum);
+ ATH_TXQ_UNLOCK(&avp->av_mcastq);
+ ATH_TXQ_UNLOCK(cabq);
+ }
+ return bf;
+}
+
+void
+ath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+ struct ath_vap *avp = ATH_VAP(vap);
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ int error;
+
+ KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
+
+ /*
+ * Update dynamic beacon contents. If this returns
+ * non-zero then we need to remap the memory because
+ * the beacon frame changed size (probably because
+ * of the TIM bitmap).
+ */
+ bf = avp->av_bcbuf;
+ m = bf->bf_m;
+ if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, 0)) {
+ /* XXX too conservative? */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(vap->iv_ifp,
+ "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
+ __func__, error);
+ return;
+ }
+ }
+ ath_beacon_setup(sc, bf);
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+
+ /* NB: caller is known to have already stopped tx dma */
+ ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
+ ath_hal_txstart(ah, sc->sc_bhalq);
+}
+
+/*
+ * Reclaim beacon resources and return buffer to the pool.
+ */
+void
+ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf)
+{
+
+ DPRINTF(sc, ATH_DEBUG_NODE, "%s: free bf=%p, bf_m=%p, bf_node=%p\n",
+ __func__, bf, bf->bf_m, bf->bf_node);
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_node != NULL) {
+ ieee80211_free_node(bf->bf_node);
+ bf->bf_node = NULL;
+ }
+ TAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list);
+}
+
+/*
+ * Reclaim beacon resources.
+ */
+void
+ath_beacon_free(struct ath_softc *sc)
+{
+ struct ath_buf *bf;
+
+ TAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) {
+ DPRINTF(sc, ATH_DEBUG_NODE,
+ "%s: free bf=%p, bf_m=%p, bf_node=%p\n",
+ __func__, bf, bf->bf_m, bf->bf_node);
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_node != NULL) {
+ ieee80211_free_node(bf->bf_node);
+ bf->bf_node = NULL;
+ }
+ }
+}
+
+/*
+ * Configure the beacon and sleep timers.
+ *
+ * When operating as an AP this resets the TSF and sets
+ * up the hardware to notify us when we need to issue beacons.
+ *
+ * When operating in station mode this sets up the beacon
+ * timers according to the timestamp of the last received
+ * beacon and the current TSF, configures PCF and DTIM
+ * handling, programs the sleep registers so the hardware
+ * will wakeup in time to receive beacons, and configures
+ * the beacon miss handling so we'll receive a BMISS
+ * interrupt when we stop seeing beacons from the AP
+ * we've associated with.
+ */
+void
+ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+#define TSF_TO_TU(_h,_l) \
+ ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
+#define FUDGE 2
+ struct ath_hal *ah = sc->sc_ah;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_node *ni;
+ u_int32_t nexttbtt, intval, tsftu;
+ u_int64_t tsf;
+
+ if (vap == NULL)
+ vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
+ ni = ieee80211_ref_node(vap->iv_bss);
+
+ /* extract tstamp from last beacon and convert to TU */
+ nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4),
+ LE_READ_4(ni->ni_tstamp.data));
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_MBSS) {
+ /*
+ * For multi-bss ap/mesh support beacons are either staggered
+ * evenly over N slots or burst together. For the former
+ * arrange for the SWBA to be delivered for each slot.
+ * Slots that are not occupied will generate nothing.
+ */
+ /* NB: the beacon interval is kept internally in TU's */
+ intval = ni->ni_intval & HAL_BEACON_PERIOD;
+ if (sc->sc_stagbeacons)
+ intval /= ATH_BCBUF;
+ } else {
+ /* NB: the beacon interval is kept internally in TU's */
+ intval = ni->ni_intval & HAL_BEACON_PERIOD;
+ }
+ if (nexttbtt == 0) /* e.g. for ap mode */
+ nexttbtt = intval;
+ else if (intval) /* NB: can be 0 for monitor mode */
+ nexttbtt = roundup(nexttbtt, intval);
+ DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
+ __func__, nexttbtt, intval, ni->ni_intval);
+ if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) {
+ HAL_BEACON_STATE bs;
+ int dtimperiod, dtimcount;
+ int cfpperiod, cfpcount;
+
+ /*
+ * Setup dtim and cfp parameters according to
+ * last beacon we received (which may be none).
+ */
+ dtimperiod = ni->ni_dtim_period;
+ if (dtimperiod <= 0) /* NB: 0 if not known */
+ dtimperiod = 1;
+ dtimcount = ni->ni_dtim_count;
+ if (dtimcount >= dtimperiod) /* NB: sanity check */
+ dtimcount = 0; /* XXX? */
+ cfpperiod = 1; /* NB: no PCF support yet */
+ cfpcount = 0;
+ /*
+ * Pull nexttbtt forward to reflect the current
+ * TSF and calculate dtim+cfp state for the result.
+ */
+ tsf = ath_hal_gettsf64(ah);
+ tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
+ do {
+ nexttbtt += intval;
+ if (--dtimcount < 0) {
+ dtimcount = dtimperiod - 1;
+ if (--cfpcount < 0)
+ cfpcount = cfpperiod - 1;
+ }
+ } while (nexttbtt < tsftu);
+ memset(&bs, 0, sizeof(bs));
+ bs.bs_intval = intval;
+ bs.bs_nexttbtt = nexttbtt;
+ bs.bs_dtimperiod = dtimperiod*intval;
+ bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
+ bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
+ bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
+ bs.bs_cfpmaxduration = 0;
+#if 0
+ /*
+ * The 802.11 layer records the offset to the DTIM
+ * bitmap while receiving beacons; use it here to
+ * enable h/w detection of our AID being marked in
+ * the bitmap vector (to indicate frames for us are
+ * pending at the AP).
+ * XXX do DTIM handling in s/w to WAR old h/w bugs
+ * XXX enable based on h/w rev for newer chips
+ */
+ bs.bs_timoffset = ni->ni_timoff;
+#endif
+ /*
+ * Calculate the number of consecutive beacons to miss
+ * before taking a BMISS interrupt.
+ * Note that we clamp the result to at most 10 beacons.
+ */
+ bs.bs_bmissthreshold = vap->iv_bmissthreshold;
+ if (bs.bs_bmissthreshold > 10)
+ bs.bs_bmissthreshold = 10;
+ else if (bs.bs_bmissthreshold <= 0)
+ bs.bs_bmissthreshold = 1;
+
+ /*
+ * Calculate sleep duration. The configuration is
+ * given in ms. We insure a multiple of the beacon
+ * period is used. Also, if the sleep duration is
+ * greater than the DTIM period then it makes senses
+ * to make it a multiple of that.
+ *
+ * XXX fixed at 100ms
+ */
+ bs.bs_sleepduration =
+ roundup(IEEE80211_MS_TO_TU(100), bs.bs_intval);
+ if (bs.bs_sleepduration > bs.bs_dtimperiod)
+ bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n"
+ , __func__
+ , tsf, tsftu
+ , bs.bs_intval
+ , bs.bs_nexttbtt
+ , bs.bs_dtimperiod
+ , bs.bs_nextdtim
+ , bs.bs_bmissthreshold
+ , bs.bs_sleepduration
+ , bs.bs_cfpperiod
+ , bs.bs_cfpmaxduration
+ , bs.bs_cfpnext
+ , bs.bs_timoffset
+ );
+ ath_hal_intrset(ah, 0);
+ ath_hal_beacontimers(ah, &bs);
+ sc->sc_imask |= HAL_INT_BMISS;
+ ath_hal_intrset(ah, sc->sc_imask);
+ } else {
+ ath_hal_intrset(ah, 0);
+ if (nexttbtt == intval)
+ intval |= HAL_BEACON_RESET_TSF;
+ if (ic->ic_opmode == IEEE80211_M_IBSS) {
+ /*
+ * In IBSS mode enable the beacon timers but only
+ * enable SWBA interrupts if we need to manually
+ * prepare beacon frames. Otherwise we use a
+ * self-linked tx descriptor and let the hardware
+ * deal with things.
+ */
+ intval |= HAL_BEACON_ENA;
+ if (!sc->sc_hasveol)
+ sc->sc_imask |= HAL_INT_SWBA;
+ if ((intval & HAL_BEACON_RESET_TSF) == 0) {
+ /*
+ * Pull nexttbtt forward to reflect
+ * the current TSF.
+ */
+ tsf = ath_hal_gettsf64(ah);
+ tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
+ do {
+ nexttbtt += intval;
+ } while (nexttbtt < tsftu);
+ }
+ ath_beaconq_config(sc);
+ } else if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_MBSS) {
+ /*
+ * In AP/mesh mode we enable the beacon timers
+ * and SWBA interrupts to prepare beacon frames.
+ */
+ intval |= HAL_BEACON_ENA;
+ sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */
+ ath_beaconq_config(sc);
+ }
+ ath_hal_beaconinit(ah, nexttbtt, intval);
+ sc->sc_bmisscount = 0;
+ ath_hal_intrset(ah, sc->sc_imask);
+ /*
+ * When using a self-linked beacon descriptor in
+ * ibss mode load it once here.
+ */
+ if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol)
+ ath_beacon_start_adhoc(sc, vap);
+ }
+ sc->sc_syncbeacon = 0;
+ ieee80211_free_node(ni);
+#undef FUDGE
+#undef TSF_TO_TU
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_beacon.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_beacon.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: head/sys/dev/ath/if_ath_beacon.h 235680 2012-05-20 04:14:29Z adrian $
+ */
+#ifndef __IF_ATH_BEACON_H__
+#define __IF_ATH_BEACON_H__
+
+extern int ath_bstuck_threshold;
+
+extern int ath_beaconq_setup(struct ath_hal *ah);
+extern int ath_beaconq_config(struct ath_softc *sc);
+extern void ath_beacon_config(struct ath_softc *sc,
+ struct ieee80211vap *vap);
+extern struct ath_buf * ath_beacon_generate(struct ath_softc *sc,
+ struct ieee80211vap *vap);
+extern int ath_wme_update(struct ieee80211com *ic);
+extern void ath_beacon_update(struct ieee80211vap *vap, int item);
+extern void ath_beacon_start_adhoc(struct ath_softc *sc,
+ struct ieee80211vap *vap);
+extern int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni);
+extern void ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf);
+extern void ath_beacon_free(struct ath_softc *sc);
+extern void ath_beacon_proc(void *arg, int pending);
+
+#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_debug.c
--- a/head/sys/dev/ath/if_ath_debug.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_debug.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_debug.c 233966 2012-04-07 02:01:26Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_debug.c 238275 2012-07-09 06:39:46Z adrian $");
#include "opt_inet.h"
#include "opt_ath.h"
@@ -89,12 +89,12 @@
#ifdef ATH_DEBUG
#include <dev/ath/if_ath_debug.h>
-int ath_debug = 0;
+uint64_t ath_debug = 0;
SYSCTL_DECL(_hw_ath);
-SYSCTL_INT(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug,
+SYSCTL_QUAD(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug,
0, "control debugging printfs");
-TUNABLE_INT("hw.ath.debug", &ath_debug);
+TUNABLE_QUAD("hw.ath.debug", &ath_debug);
void
ath_printrxbuf(struct ath_softc *sc, const struct ath_buf *bf,
@@ -118,6 +118,16 @@
ds->ds_hw[2], ds->ds_hw[3], ds->ds_hw[4],
ds->ds_hw[5], ds->ds_hw[6], ds->ds_hw[7],
ds->ds_hw[8]);
+ } else if (ah->ah_magic == 0x19741014) {
+ printf(" %08x %08x %08x %08x %08x %08x %08x\n",
+ ds->ds_hw[2], ds->ds_hw[3], ds->ds_hw[4],
+ ds->ds_hw[5], ds->ds_hw[6], ds->ds_hw[7],
+ ds->ds_hw[8]);
+
+ printf(" %08x %08x %08x %08x %08x %08x %08x\n",
+ ds->ds_hw[9], ds->ds_hw[10], ds->ds_hw[11],
+ ds->ds_hw[12], ds->ds_hw[13], ds->ds_hw[14],
+ ds->ds_hw[15]);
}
}
}
@@ -144,9 +154,6 @@
bf->bf_state.bfs_retries,
bf->bf_state.bfs_addedbaw,
bf->bf_state.bfs_dobaw);
- printf(" SEQNO_ASSIGNED: %d, NEED_SEQNO: %d\n",
- bf->bf_state.bfs_seqno_assigned,
- bf->bf_state.bfs_need_seqno);
printf(" %08x %08x %08x %08x %08x %08x\n",
ds->ds_ctl0, ds->ds_ctl1,
ds->ds_hw[0], ds->ds_hw[1],
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_debug.h
--- a/head/sys/dev/ath/if_ath_debug.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_debug.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_ath_debug.h 226900 2011-10-29 07:17:47Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_ath_debug.h 238364 2012-07-11 12:10:13Z jhb $
*/
#ifndef __IF_ATH_DEBUG_H__
#define __IF_ATH_DEBUG_H__
@@ -34,39 +34,45 @@
#ifdef ATH_DEBUG
enum {
- ATH_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
- ATH_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */
- ATH_DEBUG_RECV = 0x00000004, /* basic recv operation */
- ATH_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */
- ATH_DEBUG_RATE = 0x00000010, /* rate control */
- ATH_DEBUG_RESET = 0x00000020, /* reset processing */
- ATH_DEBUG_MODE = 0x00000040, /* mode init/setup */
- ATH_DEBUG_BEACON = 0x00000080, /* beacon handling */
- ATH_DEBUG_WATCHDOG = 0x00000100, /* watchdog timeout */
- ATH_DEBUG_INTR = 0x00001000, /* ISR */
- ATH_DEBUG_TX_PROC = 0x00002000, /* tx ISR proc */
- ATH_DEBUG_RX_PROC = 0x00004000, /* rx ISR proc */
- ATH_DEBUG_BEACON_PROC = 0x00008000, /* beacon ISR proc */
- ATH_DEBUG_CALIBRATE = 0x00010000, /* periodic calibration */
- ATH_DEBUG_KEYCACHE = 0x00020000, /* key cache management */
- ATH_DEBUG_STATE = 0x00040000, /* 802.11 state transitions */
- ATH_DEBUG_NODE = 0x00080000, /* node management */
- ATH_DEBUG_LED = 0x00100000, /* led management */
- ATH_DEBUG_FF = 0x00200000, /* fast frames */
- ATH_DEBUG_DFS = 0x00400000, /* DFS processing */
- ATH_DEBUG_TDMA = 0x00800000, /* TDMA processing */
- ATH_DEBUG_TDMA_TIMER = 0x01000000, /* TDMA timer processing */
- ATH_DEBUG_REGDOMAIN = 0x02000000, /* regulatory processing */
- ATH_DEBUG_SW_TX = 0x04000000, /* per-packet software TX */
- ATH_DEBUG_SW_TX_BAW = 0x08000000, /* BAW handling */
- ATH_DEBUG_SW_TX_CTRL = 0x10000000, /* queue control */
- ATH_DEBUG_SW_TX_AGGR = 0x20000000, /* aggregate TX */
- ATH_DEBUG_SW_TX_RETRIES = 0x40000000, /* software TX retries */
- ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */
- ATH_DEBUG_ANY = 0xffffffff
+ ATH_DEBUG_XMIT = 0x000000001ULL, /* basic xmit operation */
+ ATH_DEBUG_XMIT_DESC = 0x000000002ULL, /* xmit descriptors */
+ ATH_DEBUG_RECV = 0x000000004ULL, /* basic recv operation */
+ ATH_DEBUG_RECV_DESC = 0x000000008ULL, /* recv descriptors */
+ ATH_DEBUG_RATE = 0x000000010ULL, /* rate control */
+ ATH_DEBUG_RESET = 0x000000020ULL, /* reset processing */
+ ATH_DEBUG_MODE = 0x000000040ULL, /* mode init/setup */
+ ATH_DEBUG_BEACON = 0x000000080ULL, /* beacon handling */
+ ATH_DEBUG_WATCHDOG = 0x000000100ULL, /* watchdog timeout */
+ ATH_DEBUG_INTR = 0x000001000ULL, /* ISR */
+ ATH_DEBUG_TX_PROC = 0x000002000ULL, /* tx ISR proc */
+ ATH_DEBUG_RX_PROC = 0x000004000ULL, /* rx ISR proc */
+ ATH_DEBUG_BEACON_PROC = 0x000008000ULL, /* beacon ISR proc */
+ ATH_DEBUG_CALIBRATE = 0x000010000ULL, /* periodic calibration */
+ ATH_DEBUG_KEYCACHE = 0x000020000ULL, /* key cache management */
+ ATH_DEBUG_STATE = 0x000040000ULL, /* 802.11 state transitions */
+ ATH_DEBUG_NODE = 0x000080000ULL, /* node management */
+ ATH_DEBUG_LED = 0x000100000ULL, /* led management */
+ ATH_DEBUG_FF = 0x000200000ULL, /* fast frames */
+ ATH_DEBUG_DFS = 0x000400000ULL, /* DFS processing */
+ ATH_DEBUG_TDMA = 0x000800000ULL, /* TDMA processing */
+ ATH_DEBUG_TDMA_TIMER = 0x001000000ULL, /* TDMA timer processing */
+ ATH_DEBUG_REGDOMAIN = 0x002000000ULL, /* regulatory processing */
+ ATH_DEBUG_SW_TX = 0x004000000ULL, /* per-packet software TX */
+ ATH_DEBUG_SW_TX_BAW = 0x008000000ULL, /* BAW handling */
+ ATH_DEBUG_SW_TX_CTRL = 0x010000000ULL, /* queue control */
+ ATH_DEBUG_SW_TX_AGGR = 0x020000000ULL, /* aggregate TX */
+ ATH_DEBUG_SW_TX_RETRIES = 0x040000000ULL, /* software TX retries */
+ ATH_DEBUG_FATAL = 0x080000000ULL, /* fatal errors */
+ ATH_DEBUG_SW_TX_BAR = 0x100000000ULL, /* BAR TX */
+ ATH_DEBUG_EDMA_RX = 0x200000000ULL, /* RX EDMA state */
+
+ ATH_DEBUG_ANY = 0xffffffffffffffffULL
};
-extern int ath_debug;
+#define ATH_KTR_INTR KTR_SPARE4
+#define ATH_KTR_ERR KTR_SPARE3
+
+extern uint64_t ath_debug;
#define IFF_DUMPPKTS(sc, m) \
((sc->sc_debug & (m)) || \
@@ -85,6 +91,9 @@
extern void ath_printtxbuf(struct ath_softc *, const struct ath_buf *bf,
u_int qnum, u_int ix, int done);
#else /* ATH_DEBUG */
+#define ATH_KTR_INTR 0
+#define ATH_KTR_ERR 0
+
#define IFF_DUMPPKTS(sc, m) \
((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
#define DPRINTF(sc, m, fmt, ...) do { \
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_led.c
--- a/head/sys/dev/ath/if_ath_led.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_led.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_led.c 228892 2011-12-26 07:48:29Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_led.c 237611 2012-06-26 22:16:53Z adrian $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -125,7 +125,7 @@
/* Software LED blinking - GPIO controlled LED */
if (sc->sc_softled) {
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
- HAL_GPIO_MUX_OUTPUT);
+ HAL_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
}
@@ -139,10 +139,10 @@
*/
if (sc->sc_led_pwr_pin > 0)
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_pwr_pin,
- HAL_GPIO_MUX_MAC_POWER_LED);
+ HAL_GPIO_OUTPUT_MUX_MAC_POWER_LED);
if (sc->sc_led_net_pin > 0)
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_net_pin,
- HAL_GPIO_MUX_MAC_NETWORK_LED);
+ HAL_GPIO_OUTPUT_MUX_MAC_NETWORK_LED);
}
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_misc.h
--- a/head/sys/dev/ath/if_ath_misc.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_misc.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_ath_misc.h 227364 2011-11-08 22:43:13Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_ath_misc.h 238729 2012-07-23 23:40:13Z adrian $
*/
#ifndef __IF_ATH_MISC_H__
#define __IF_ATH_MISC_H__
@@ -48,13 +48,22 @@
((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \
(((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))
+extern int ath_rxbuf;
+extern int ath_txbuf;
+extern int ath_txbuf_mgmt;
+
extern int ath_tx_findrix(const struct ath_softc *sc, uint8_t rate);
-extern struct ath_buf * ath_getbuf(struct ath_softc *sc);
-extern struct ath_buf * _ath_getbuf_locked(struct ath_softc *sc);
+extern struct ath_buf * ath_getbuf(struct ath_softc *sc,
+ ath_buf_type_t btype);
+extern struct ath_buf * _ath_getbuf_locked(struct ath_softc *sc,
+ ath_buf_type_t btype);
extern struct ath_buf * ath_buf_clone(struct ath_softc *sc,
const struct ath_buf *bf);
+/* XXX change this to NULL the buffer pointer? */
extern void ath_freebuf(struct ath_softc *sc, struct ath_buf *bf);
+extern void ath_returnbuf_head(struct ath_softc *sc, struct ath_buf *bf);
+extern void ath_returnbuf_tail(struct ath_softc *sc, struct ath_buf *bf);
extern int ath_reset(struct ifnet *, ATH_RESET_TYPE);
extern void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq);
@@ -67,4 +76,37 @@
extern void ath_tx_freebuf(struct ath_softc *sc, struct ath_buf *bf,
int status);
+extern void ath_txqmove(struct ath_txq *dst, struct ath_txq *src);
+
+extern void ath_mode_init(struct ath_softc *sc);
+
+extern void ath_setdefantenna(struct ath_softc *sc, u_int antenna);
+
+extern void ath_setslottime(struct ath_softc *sc);
+
+extern int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+ ath_bufhead *head, const char *name, int ds_size, int nbuf,
+ int ndesc);
+extern int ath_descdma_setup_rx_edma(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head, const char *name,
+ int nbuf, int desclen);
+extern void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head);
+
+/*
+ * This is only here so that the RX proc function can call it.
+ * It's very likely that the "start TX after RX" call should be
+ * done via something in if_ath.c, moving "rx tasklet" into
+ * if_ath.c and do the ath_start() call there. Once that's done,
+ * we can kill this.
+ */
+extern void ath_start(struct ifnet *ifp);
+
+static inline void
+ath_tx_kick(struct ath_softc *sc)
+{
+
+ ath_start(sc->sc_ifp);
+}
+
#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_pci.c
--- a/head/sys/dev/ath/if_ath_pci.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_pci.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_pci.c 234304 2012-04-15 00:04:23Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_pci.c 238709 2012-07-23 02:49:25Z adrian $");
/*
* PCI/Cardbus front-end for the Atheros Wireless LAN controller driver.
@@ -249,12 +249,16 @@
ATH_LOCK_INIT(sc);
ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TXSTATUS_LOCK_INIT(sc);
error = ath_attach(pci_get_device(dev), sc);
if (error == 0) /* success */
return 0;
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
bus_dma_tag_destroy(sc->sc_dmat);
bad3:
@@ -293,7 +297,9 @@
if (sc->sc_eepromdata)
free(sc->sc_eepromdata, M_TEMP);
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
ATH_PCU_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
return (0);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_rx.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_rx.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,1113 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_rx.c 238729 2012-07-23 23:40:13Z adrian $");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h> /* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tsf.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_sysctl.h>
+#include <dev/ath/if_ath_led.h>
+#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_beacon.h>
+#include <dev/ath/if_athdfs.h>
+
+#ifdef ATH_TX99_DIAG
+#include <dev/ath/ath_tx99/ath_tx99.h>
+#endif
+
+/*
+ * Calculate the receive filter according to the
+ * operating mode and state:
+ *
+ * o always accept unicast, broadcast, and multicast traffic
+ * o accept PHY error frames when hardware doesn't have MIB support
+ * to count and we need them for ANI (sta mode only until recently)
+ * and we are not scanning (ANI is disabled)
+ * NB: older hal's add rx filter bits out of sight and we need to
+ * blindly preserve them
+ * o probe request frames are accepted only when operating in
+ * hostap, adhoc, mesh, or monitor modes
+ * o enable promiscuous mode
+ * - when in monitor mode
+ * - if interface marked PROMISC (assumes bridge setting is filtered)
+ * o accept beacons:
+ * - when operating in station mode for collecting rssi data when
+ * the station is otherwise quiet, or
+ * - when operating in adhoc mode so the 802.11 layer creates
+ * node table entries for peers,
+ * - when scanning
+ * - when doing s/w beacon miss (e.g. for ap+sta)
+ * - when operating in ap mode in 11g to detect overlapping bss that
+ * require protection
+ * - when operating in mesh mode to detect neighbors
+ * o accept control frames:
+ * - when in monitor mode
+ * XXX HT protection for 11n
+ */
+u_int32_t
+ath_calcrxfilter(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ u_int32_t rfilt;
+
+ rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
+ if (!sc->sc_needmib && !sc->sc_scanning)
+ rfilt |= HAL_RX_FILTER_PHYERR;
+ if (ic->ic_opmode != IEEE80211_M_STA)
+ rfilt |= HAL_RX_FILTER_PROBEREQ;
+ /* XXX ic->ic_monvaps != 0? */
+ if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC))
+ rfilt |= HAL_RX_FILTER_PROM;
+ if (ic->ic_opmode == IEEE80211_M_STA ||
+ ic->ic_opmode == IEEE80211_M_IBSS ||
+ sc->sc_swbmiss || sc->sc_scanning)
+ rfilt |= HAL_RX_FILTER_BEACON;
+ /*
+ * NB: We don't recalculate the rx filter when
+ * ic_protmode changes; otherwise we could do
+ * this only when ic_protmode != NONE.
+ */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
+ rfilt |= HAL_RX_FILTER_BEACON;
+
+ /*
+ * Enable hardware PS-POLL RX only for hostap mode;
+ * STA mode sends PS-POLL frames but never
+ * receives them.
+ */
+ if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_PSPOLL,
+ 0, NULL) == HAL_OK &&
+ ic->ic_opmode == IEEE80211_M_HOSTAP)
+ rfilt |= HAL_RX_FILTER_PSPOLL;
+
+ if (sc->sc_nmeshvaps) {
+ rfilt |= HAL_RX_FILTER_BEACON;
+ if (sc->sc_hasbmatch)
+ rfilt |= HAL_RX_FILTER_BSSID;
+ else
+ rfilt |= HAL_RX_FILTER_PROM;
+ }
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ rfilt |= HAL_RX_FILTER_CONTROL;
+
+ /*
+ * Enable RX of compressed BAR frames only when doing
+ * 802.11n. Required for A-MPDU.
+ */
+ if (IEEE80211_IS_CHAN_HT(ic->ic_curchan))
+ rfilt |= HAL_RX_FILTER_COMPBAR;
+
+ /*
+ * Enable radar PHY errors if requested by the
+ * DFS module.
+ */
+ if (sc->sc_dodfs)
+ rfilt |= HAL_RX_FILTER_PHYRADAR;
+
+ DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n",
+ __func__, rfilt, ieee80211_opmode_name[ic->ic_opmode], ifp->if_flags);
+ return rfilt;
+}
+
+static int
+ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int error;
+ struct mbuf *m;
+ struct ath_desc *ds;
+
+ m = bf->bf_m;
+ if (m == NULL) {
+ /*
+ * NB: by assigning a page to the rx dma buffer we
+ * implicitly satisfy the Atheros requirement that
+ * this buffer be cache-line-aligned and sized to be
+ * multiple of the cache line size. Not doing this
+ * causes weird stuff to happen (for the 5210 at least).
+ */
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: no mbuf/cluster\n", __func__);
+ sc->sc_stats.ast_rx_nombuf++;
+ return ENOMEM;
+ }
+ m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
+
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat,
+ bf->bf_dmamap, m,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: bus_dmamap_load_mbuf_sg failed; error %d\n",
+ __func__, error);
+ sc->sc_stats.ast_rx_busdma++;
+ m_freem(m);
+ return error;
+ }
+ KASSERT(bf->bf_nseg == 1,
+ ("multi-segment packet; nseg %u", bf->bf_nseg));
+ bf->bf_m = m;
+ }
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD);
+
+ /*
+ * Setup descriptors. For receive we always terminate
+ * the descriptor list with a self-linked entry so we'll
+ * not get overrun under high load (as can happen with a
+ * 5212 when ANI processing enables PHY error frames).
+ *
+ * To insure the last descriptor is self-linked we create
+ * each descriptor as self-linked and add it to the end. As
+ * each additional descriptor is added the previous self-linked
+ * entry is ``fixed'' naturally. This should be safe even
+ * if DMA is happening. When processing RX interrupts we
+ * never remove/process the last, self-linked, entry on the
+ * descriptor list. This insures the hardware always has
+ * someplace to write a new frame.
+ */
+ /*
+ * 11N: we can no longer afford to self link the last descriptor.
+ * MAC acknowledges BA status as long as it copies frames to host
+ * buffer (or rx fifo). This can incorrectly acknowledge packets
+ * to a sender if last desc is self-linked.
+ */
+ ds = bf->bf_desc;
+ if (sc->sc_rxslink)
+ ds->ds_link = bf->bf_daddr; /* link to self */
+ else
+ ds->ds_link = 0; /* terminate the list */
+ ds->ds_data = bf->bf_segs[0].ds_addr;
+ ath_hal_setuprxdesc(ah, ds
+ , m->m_len /* buffer size */
+ , 0
+ );
+
+ if (sc->sc_rxlink != NULL)
+ *sc->sc_rxlink = bf->bf_daddr;
+ sc->sc_rxlink = &ds->ds_link;
+ return 0;
+}
+
+/*
+ * Intercept management frames to collect beacon rssi data
+ * and to do ibss merges.
+ */
+void
+ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
+ int subtype, int rssi, int nf)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+
+ /*
+ * Call up first so subsequent work can use information
+ * potentially stored in the node (e.g. for ibss merge).
+ */
+ ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, nf);
+ switch (subtype) {
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ /* update rssi statistics for use by the hal */
+ /* XXX unlocked check against vap->iv_bss? */
+ ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi);
+ if (sc->sc_syncbeacon &&
+ ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) {
+ /*
+ * Resync beacon timers using the tsf of the beacon
+ * frame we just received.
+ */
+ ath_beacon_config(sc, vap);
+ }
+ /* fall thru... */
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ if (vap->iv_opmode == IEEE80211_M_IBSS &&
+ vap->iv_state == IEEE80211_S_RUN) {
+ uint32_t rstamp = sc->sc_lastrs->rs_tstamp;
+ uint64_t tsf = ath_extend_tsf(sc, rstamp,
+ ath_hal_gettsf64(sc->sc_ah));
+ /*
+ * Handle ibss merge as needed; check the tsf on the
+ * frame before attempting the merge. The 802.11 spec
+ * says the station should change it's bssid to match
+ * the oldest station with the same ssid, where oldest
+ * is determined by the tsf. Note that hardware
+ * reconfiguration happens through callback to
+ * ath_newstate as the state machine will go from
+ * RUN -> RUN when this happens.
+ */
+ if (le64toh(ni->ni_tstamp.tsf) >= tsf) {
+ DPRINTF(sc, ATH_DEBUG_STATE,
+ "ibss merge, rstamp %u tsf %ju "
+ "tstamp %ju\n", rstamp, (uintmax_t)tsf,
+ (uintmax_t)ni->ni_tstamp.tsf);
+ (void) ieee80211_ibss_merge(ni);
+ }
+ }
+ break;
+ }
+}
+
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+static void
+ath_rx_tap_vendor(struct ifnet *ifp, struct mbuf *m,
+ const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
+{
+ struct ath_softc *sc = ifp->if_softc;
+
+ /* Fill in the extension bitmap */
+ sc->sc_rx_th.wr_ext_bitmap = htole32(1 << ATH_RADIOTAP_VENDOR_HEADER);
+
+ /* Fill in the vendor header */
+ sc->sc_rx_th.wr_vh.vh_oui[0] = 0x7f;
+ sc->sc_rx_th.wr_vh.vh_oui[1] = 0x03;
+ sc->sc_rx_th.wr_vh.vh_oui[2] = 0x00;
+
+ /* XXX what should this be? */
+ sc->sc_rx_th.wr_vh.vh_sub_ns = 0;
+ sc->sc_rx_th.wr_vh.vh_skip_len =
+ htole16(sizeof(struct ath_radiotap_vendor_hdr));
+
+ /* General version info */
+ sc->sc_rx_th.wr_v.vh_version = 1;
+
+ sc->sc_rx_th.wr_v.vh_rx_chainmask = sc->sc_rxchainmask;
+
+ /* rssi */
+ sc->sc_rx_th.wr_v.rssi_ctl[0] = rs->rs_rssi_ctl[0];
+ sc->sc_rx_th.wr_v.rssi_ctl[1] = rs->rs_rssi_ctl[1];
+ sc->sc_rx_th.wr_v.rssi_ctl[2] = rs->rs_rssi_ctl[2];
+ sc->sc_rx_th.wr_v.rssi_ext[0] = rs->rs_rssi_ext[0];
+ sc->sc_rx_th.wr_v.rssi_ext[1] = rs->rs_rssi_ext[1];
+ sc->sc_rx_th.wr_v.rssi_ext[2] = rs->rs_rssi_ext[2];
+
+ /* evm */
+ sc->sc_rx_th.wr_v.evm[0] = rs->rs_evm0;
+ sc->sc_rx_th.wr_v.evm[1] = rs->rs_evm1;
+ sc->sc_rx_th.wr_v.evm[2] = rs->rs_evm2;
+ /* XXX TODO: extend this to include 3-stream EVM */
+
+ /* phyerr info */
+ if (rs->rs_status & HAL_RXERR_PHY)
+ sc->sc_rx_th.wr_v.vh_phyerr_code = rs->rs_phyerr;
+ else
+ sc->sc_rx_th.wr_v.vh_phyerr_code = 0xff;
+ sc->sc_rx_th.wr_v.vh_rs_status = rs->rs_status;
+ sc->sc_rx_th.wr_v.vh_rssi = rs->rs_rssi;
+}
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
+
+static void
+ath_rx_tap(struct ifnet *ifp, struct mbuf *m,
+ const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
+{
+#define CHAN_HT20 htole32(IEEE80211_CHAN_HT20)
+#define CHAN_HT40U htole32(IEEE80211_CHAN_HT40U)
+#define CHAN_HT40D htole32(IEEE80211_CHAN_HT40D)
+#define CHAN_HT (CHAN_HT20|CHAN_HT40U|CHAN_HT40D)
+ struct ath_softc *sc = ifp->if_softc;
+ const HAL_RATE_TABLE *rt;
+ uint8_t rix;
+
+ rt = sc->sc_currates;
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+ rix = rt->rateCodeToIndex[rs->rs_rate];
+ sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate;
+ sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags;
+#ifdef AH_SUPPORT_AR5416
+ sc->sc_rx_th.wr_chan_flags &= ~CHAN_HT;
+ if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ if ((rs->rs_flags & HAL_RX_2040) == 0)
+ sc->sc_rx_th.wr_chan_flags |= CHAN_HT20;
+ else if (IEEE80211_IS_CHAN_HT40U(ic->ic_curchan))
+ sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U;
+ else
+ sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D;
+ if ((rs->rs_flags & HAL_RX_GI) == 0)
+ sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI;
+ }
+#endif
+ sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf));
+ if (rs->rs_status & HAL_RXERR_CRC)
+ sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
+ /* XXX propagate other error flags from descriptor */
+ sc->sc_rx_th.wr_antnoise = nf;
+ sc->sc_rx_th.wr_antsignal = nf + rs->rs_rssi;
+ sc->sc_rx_th.wr_antenna = rs->rs_antenna;
+#undef CHAN_HT
+#undef CHAN_HT20
+#undef CHAN_HT40U
+#undef CHAN_HT40D
+}
+
+static void
+ath_handle_micerror(struct ieee80211com *ic,
+ struct ieee80211_frame *wh, int keyix)
+{
+ struct ieee80211_node *ni;
+
+ /* XXX recheck MIC to deal w/ chips that lie */
+ /* XXX discard MIC errors on !data frames */
+ ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh);
+ if (ni != NULL) {
+ ieee80211_notify_michael_failure(ni->ni_vap, wh, keyix);
+ ieee80211_free_node(ni);
+ }
+}
+
+int
+ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status,
+ uint64_t tsf, int nf, HAL_RX_QUEUE qtype, struct ath_buf *bf)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct mbuf *m = bf->bf_m;
+ uint64_t rstamp;
+ int len, type;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211_node *ni;
+ int is_good = 0;
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+
+ /*
+ * Calculate the correct 64 bit TSF given
+ * the TSF64 register value and rs_tstamp.
+ */
+ rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf);
+
+ /* These aren't specifically errors */
+#ifdef AH_SUPPORT_AR5416
+ if (rs->rs_flags & HAL_RX_GI)
+ sc->sc_stats.ast_rx_halfgi++;
+ if (rs->rs_flags & HAL_RX_2040)
+ sc->sc_stats.ast_rx_2040++;
+ if (rs->rs_flags & HAL_RX_DELIM_CRC_PRE)
+ sc->sc_stats.ast_rx_pre_crc_err++;
+ if (rs->rs_flags & HAL_RX_DELIM_CRC_POST)
+ sc->sc_stats.ast_rx_post_crc_err++;
+ if (rs->rs_flags & HAL_RX_DECRYPT_BUSY)
+ sc->sc_stats.ast_rx_decrypt_busy_err++;
+ if (rs->rs_flags & HAL_RX_HI_RX_CHAIN)
+ sc->sc_stats.ast_rx_hi_rx_chain++;
+#endif /* AH_SUPPORT_AR5416 */
+
+ if (rs->rs_status != 0) {
+ if (rs->rs_status & HAL_RXERR_CRC)
+ sc->sc_stats.ast_rx_crcerr++;
+ if (rs->rs_status & HAL_RXERR_FIFO)
+ sc->sc_stats.ast_rx_fifoerr++;
+ if (rs->rs_status & HAL_RXERR_PHY) {
+ sc->sc_stats.ast_rx_phyerr++;
+ /* Process DFS radar events */
+ if ((rs->rs_phyerr == HAL_PHYERR_RADAR) ||
+ (rs->rs_phyerr == HAL_PHYERR_FALSE_RADAR_EXT)) {
+ /* Since we're touching the frame data, sync it */
+ bus_dmamap_sync(sc->sc_dmat,
+ bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ /* Now pass it to the radar processing code */
+ ath_dfs_process_phy_err(sc, m, rstamp, rs);
+ }
+
+ /* Be suitably paranoid about receiving phy errors out of the stats array bounds */
+ if (rs->rs_phyerr < 64)
+ sc->sc_stats.ast_rx_phy[rs->rs_phyerr]++;
+ goto rx_error; /* NB: don't count in ierrors */
+ }
+ if (rs->rs_status & HAL_RXERR_DECRYPT) {
+ /*
+ * Decrypt error. If the error occurred
+ * because there was no hardware key, then
+ * let the frame through so the upper layers
+ * can process it. This is necessary for 5210
+ * parts which have no way to setup a ``clear''
+ * key cache entry.
+ *
+ * XXX do key cache faulting
+ */
+ if (rs->rs_keyix == HAL_RXKEYIX_INVALID)
+ goto rx_accept;
+ sc->sc_stats.ast_rx_badcrypt++;
+ }
+ /*
+ * Similar as above - if the failure was a keymiss
+ * just punt it up to the upper layers for now.
+ */
+ if (rs->rs_status & HAL_RXERR_KEYMISS) {
+ sc->sc_stats.ast_rx_keymiss++;
+ goto rx_accept;
+ }
+ if (rs->rs_status & HAL_RXERR_MIC) {
+ sc->sc_stats.ast_rx_badmic++;
+ /*
+ * Do minimal work required to hand off
+ * the 802.11 header for notification.
+ */
+ /* XXX frag's and qos frames */
+ len = rs->rs_datalen;
+ if (len >= sizeof (struct ieee80211_frame)) {
+ bus_dmamap_sync(sc->sc_dmat,
+ bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ ath_handle_micerror(ic,
+ mtod(m, struct ieee80211_frame *),
+ sc->sc_splitmic ?
+ rs->rs_keyix-32 : rs->rs_keyix);
+ }
+ }
+ ifp->if_ierrors++;
+rx_error:
+ /*
+ * Cleanup any pending partial frame.
+ */
+ if (re->m_rxpending != NULL) {
+ m_freem(re->m_rxpending);
+ re->m_rxpending = NULL;
+ }
+ /*
+ * When a tap is present pass error frames
+ * that have been requested. By default we
+ * pass decrypt+mic errors but others may be
+ * interesting (e.g. crc).
+ */
+ if (ieee80211_radiotap_active(ic) &&
+ (rs->rs_status & sc->sc_monpass)) {
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ /* NB: bpf needs the mbuf length setup */
+ len = rs->rs_datalen;
+ m->m_pkthdr.len = m->m_len = len;
+ bf->bf_m = NULL;
+ ath_rx_tap(ifp, m, rs, rstamp, nf);
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+ ath_rx_tap_vendor(ifp, m, rs, rstamp, nf);
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
+ ieee80211_radiotap_rx_all(ic, m);
+ m_freem(m);
+ }
+ /* XXX pass MIC errors up for s/w reclaculation */
+ goto rx_next;
+ }
+rx_accept:
+ /*
+ * Sync and unmap the frame. At this point we're
+ * committed to passing the mbuf somewhere so clear
+ * bf_m; this means a new mbuf must be allocated
+ * when the rx descriptor is setup again to receive
+ * another frame.
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ bf->bf_m = NULL;
+
+ len = rs->rs_datalen;
+ m->m_len = len;
+
+ if (rs->rs_more) {
+ /*
+ * Frame spans multiple descriptors; save
+ * it for the next completed descriptor, it
+ * will be used to construct a jumbogram.
+ */
+ if (re->m_rxpending != NULL) {
+ /* NB: max frame size is currently 2 clusters */
+ sc->sc_stats.ast_rx_toobig++;
+ m_freem(re->m_rxpending);
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ re->m_rxpending = m;
+ goto rx_next;
+ } else if (re->m_rxpending != NULL) {
+ /*
+ * This is the second part of a jumbogram,
+ * chain it to the first mbuf, adjust the
+ * frame length, and clear the rxpending state.
+ */
+ re->m_rxpending->m_next = m;
+ re->m_rxpending->m_pkthdr.len += len;
+ m = re->m_rxpending;
+ re->m_rxpending = NULL;
+ } else {
+ /*
+ * Normal single-descriptor receive; setup
+ * the rcvif and packet length.
+ */
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ }
+
+ /*
+ * Validate rs->rs_antenna.
+ *
+ * Some users w/ AR9285 NICs have reported crashes
+ * here because rs_antenna field is bogusly large.
+ * Let's enforce the maximum antenna limit of 8
+ * (and it shouldn't be hard coded, but that's a
+ * separate problem) and if there's an issue, print
+ * out an error and adjust rs_antenna to something
+ * sensible.
+ *
+ * This code should be removed once the actual
+ * root cause of the issue has been identified.
+ * For example, it may be that the rs_antenna
+ * field is only valid for the lsat frame of
+ * an aggregate and it just happens that it is
+ * "mostly" right. (This is a general statement -
+ * the majority of the statistics are only valid
+ * for the last frame in an aggregate.
+ */
+ if (rs->rs_antenna > 7) {
+ device_printf(sc->sc_dev, "%s: rs_antenna > 7 (%d)\n",
+ __func__, rs->rs_antenna);
+#ifdef ATH_DEBUG
+ ath_printrxbuf(sc, bf, 0, status == HAL_OK);
+#endif /* ATH_DEBUG */
+ rs->rs_antenna = 0; /* XXX better than nothing */
+ }
+
+ ifp->if_ipackets++;
+ sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
+
+ /*
+ * Populate the rx status block. When there are bpf
+ * listeners we do the additional work to provide
+ * complete status. Otherwise we fill in only the
+ * material required by ieee80211_input. Note that
+ * noise setting is filled in above.
+ */
+ if (ieee80211_radiotap_active(ic)) {
+ ath_rx_tap(ifp, m, rs, rstamp, nf);
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+ ath_rx_tap_vendor(ifp, m, rs, rstamp, nf);
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
+ }
+
+ /*
+ * From this point on we assume the frame is at least
+ * as large as ieee80211_frame_min; verify that.
+ */
+ if (len < IEEE80211_MIN_LEN) {
+ if (!ieee80211_radiotap_active(ic)) {
+ DPRINTF(sc, ATH_DEBUG_RECV,
+ "%s: short packet %d\n", __func__, len);
+ sc->sc_stats.ast_rx_tooshort++;
+ } else {
+ /* NB: in particular this captures ack's */
+ ieee80211_radiotap_rx_all(ic, m);
+ }
+ m_freem(m);
+ goto rx_next;
+ }
+
+ if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) {
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ uint8_t rix = rt->rateCodeToIndex[rs->rs_rate];
+
+ ieee80211_dump_pkt(ic, mtod(m, caddr_t), len,
+ sc->sc_hwmap[rix].ieeerate, rs->rs_rssi);
+ }
+
+ m_adj(m, -IEEE80211_CRC_LEN);
+
+ /*
+ * Locate the node for sender, track state, and then
+ * pass the (referenced) node up to the 802.11 layer
+ * for its use.
+ */
+ ni = ieee80211_find_rxnode_withkey(ic,
+ mtod(m, const struct ieee80211_frame_min *),
+ rs->rs_keyix == HAL_RXKEYIX_INVALID ?
+ IEEE80211_KEYIX_NONE : rs->rs_keyix);
+ sc->sc_lastrs = rs;
+
+#ifdef AH_SUPPORT_AR5416
+ if (rs->rs_isaggr)
+ sc->sc_stats.ast_rx_agg++;
+#endif /* AH_SUPPORT_AR5416 */
+
+ if (ni != NULL) {
+ /*
+ * Only punt packets for ampdu reorder processing for
+ * 11n nodes; net80211 enforces that M_AMPDU is only
+ * set for 11n nodes.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ m->m_flags |= M_AMPDU;
+
+ /*
+ * Sending station is known, dispatch directly.
+ */
+ type = ieee80211_input(ni, m, rs->rs_rssi, nf);
+ ieee80211_free_node(ni);
+ /*
+ * Arrange to update the last rx timestamp only for
+ * frames from our ap when operating in station mode.
+ * This assumes the rx key is always setup when
+ * associated.
+ */
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ rs->rs_keyix != HAL_RXKEYIX_INVALID)
+ is_good = 1;
+ } else {
+ type = ieee80211_input_all(ic, m, rs->rs_rssi, nf);
+ }
+ /*
+ * Track rx rssi and do any rx antenna management.
+ */
+ ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi);
+ if (sc->sc_diversity) {
+ /*
+ * When using fast diversity, change the default rx
+ * antenna if diversity chooses the other antenna 3
+ * times in a row.
+ */
+ if (sc->sc_defant != rs->rs_antenna) {
+ if (++sc->sc_rxotherant >= 3)
+ ath_setdefantenna(sc, rs->rs_antenna);
+ } else
+ sc->sc_rxotherant = 0;
+ }
+
+ /* Newer school diversity - kite specific for now */
+ /* XXX perhaps migrate the normal diversity code to this? */
+ if ((ah)->ah_rxAntCombDiversity)
+ (*(ah)->ah_rxAntCombDiversity)(ah, rs, ticks, hz);
+
+ if (sc->sc_softled) {
+ /*
+ * Blink for any data frame. Otherwise do a
+ * heartbeat-style blink when idle. The latter
+ * is mainly for station mode where we depend on
+ * periodic beacon frames to trigger the poll event.
+ */
+ if (type == IEEE80211_FC0_TYPE_DATA) {
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ ath_led_event(sc,
+ rt->rateCodeToIndex[rs->rs_rate]);
+ } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle)
+ ath_led_event(sc, 0);
+ }
+rx_next:
+ return (is_good);
+}
+
+static void
+ath_rx_proc(struct ath_softc *sc, int resched)
+{
+#define PA2DESC(_sc, _pa) \
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+ struct ath_buf *bf;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ath_hal *ah = sc->sc_ah;
+#ifdef IEEE80211_SUPPORT_SUPERG
+ struct ieee80211com *ic = ifp->if_l2com;
+#endif
+ struct ath_desc *ds;
+ struct ath_rx_status *rs;
+ struct mbuf *m;
+ int ngood;
+ HAL_STATUS status;
+ int16_t nf;
+ u_int64_t tsf;
+ int npkts = 0;
+
+ /* XXX we must not hold the ATH_LOCK here */
+ ATH_UNLOCK_ASSERT(sc);
+ ATH_PCU_UNLOCK_ASSERT(sc);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: called\n", __func__);
+ ngood = 0;
+ nf = ath_hal_getchannoise(ah, sc->sc_curchan);
+ sc->sc_stats.ast_rx_noise = nf;
+ tsf = ath_hal_gettsf64(ah);
+ do {
+ bf = TAILQ_FIRST(&sc->sc_rxbuf);
+ if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */
+ if_printf(ifp, "%s: no buffer!\n", __func__);
+ break;
+ } else if (bf == NULL) {
+ /*
+ * End of List:
+ * this can happen for non-self-linked RX chains
+ */
+ sc->sc_stats.ast_rx_hitqueueend++;
+ break;
+ }
+ m = bf->bf_m;
+ if (m == NULL) { /* NB: shouldn't happen */
+ /*
+ * If mbuf allocation failed previously there
+ * will be no mbuf; try again to re-populate it.
+ */
+ /* XXX make debug msg */
+ if_printf(ifp, "%s: no mbuf!\n", __func__);
+ TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
+ goto rx_proc_next;
+ }
+ ds = bf->bf_desc;
+ if (ds->ds_link == bf->bf_daddr) {
+ /* NB: never process the self-linked entry at the end */
+ sc->sc_stats.ast_rx_hitqueueend++;
+ break;
+ }
+ /* XXX sync descriptor memory */
+ /*
+ * Must provide the virtual address of the current
+ * descriptor, the physical address, and the virtual
+ * address of the next descriptor in the h/w chain.
+ * This allows the HAL to look ahead to see if the
+ * hardware is done with a descriptor by checking the
+ * done bit in the following descriptor and the address
+ * of the current descriptor the DMA engine is working
+ * on. All this is necessary because of our use of
+ * a self-linked list to avoid rx overruns.
+ */
+ rs = &bf->bf_status.ds_rxstat;
+ status = ath_hal_rxprocdesc(ah, ds,
+ bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs);
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
+ ath_printrxbuf(sc, bf, 0, status == HAL_OK);
+#endif
+ if (status == HAL_EINPROGRESS)
+ break;
+
+ TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
+ npkts++;
+
+ /*
+ * Process a single frame.
+ */
+ if (ath_rx_pkt(sc, rs, status, tsf, nf, HAL_RX_QUEUE_HP, bf))
+ ngood++;
+rx_proc_next:
+ TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+ } while (ath_rxbuf_init(sc, bf) == 0);
+
+ /* rx signal state monitoring */
+ ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan);
+ if (ngood)
+ sc->sc_lastrx = tsf;
+
+ CTR2(ATH_KTR_INTR, "ath_rx_proc: npkts=%d, ngood=%d", npkts, ngood);
+ /* Queue DFS tasklet if needed */
+ if (resched && ath_dfs_tasklet_needed(sc, sc->sc_curchan))
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask);
+
+ /*
+ * Now that all the RX frames were handled that
+ * need to be handled, kick the PCU if there's
+ * been an RXEOL condition.
+ */
+ ATH_PCU_LOCK(sc);
+ if (resched && sc->sc_kickpcu) {
+ CTR0(ATH_KTR_ERR, "ath_rx_proc: kickpcu");
+ device_printf(sc->sc_dev, "%s: kickpcu; handled %d packets\n",
+ __func__, npkts);
+
+ /* XXX rxslink? */
+ /*
+ * XXX can we hold the PCU lock here?
+ * Are there any net80211 buffer calls involved?
+ */
+ bf = TAILQ_FIRST(&sc->sc_rxbuf);
+ ath_hal_putrxbuf(ah, bf->bf_daddr, HAL_RX_QUEUE_HP);
+ ath_hal_rxena(ah); /* enable recv descriptors */
+ ath_mode_init(sc); /* set filters, etc. */
+ ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */
+
+ ath_hal_intrset(ah, sc->sc_imask);
+ sc->sc_kickpcu = 0;
+ }
+ ATH_PCU_UNLOCK(sc);
+
+ /* XXX check this inside of IF_LOCK? */
+ if (resched && (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
+#ifdef IEEE80211_SUPPORT_SUPERG
+ ieee80211_ff_age_all(ic, 100);
+#endif
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ ath_tx_kick(sc);
+ }
+#undef PA2DESC
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+}
+
+/*
+ * Only run the RX proc if it's not already running.
+ * Since this may get run as part of the reset/flush path,
+ * the task can't clash with an existing, running tasklet.
+ */
+static void
+ath_legacy_rx_tasklet(void *arg, int npending)
+{
+ struct ath_softc *sc = arg;
+
+ CTR1(ATH_KTR_INTR, "ath_rx_proc: pending=%d", npending);
+ DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending);
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt > 0) {
+ device_printf(sc->sc_dev,
+ "%s: sc_inreset_cnt > 0; skipping\n", __func__);
+ ATH_PCU_UNLOCK(sc);
+ return;
+ }
+ ATH_PCU_UNLOCK(sc);
+
+ ath_rx_proc(sc, 1);
+}
+
+static void
+ath_legacy_flushrecv(struct ath_softc *sc)
+{
+
+ ath_rx_proc(sc, 0);
+}
+
+/*
+ * Disable the receive h/w in preparation for a reset.
+ */
+static void
+ath_legacy_stoprecv(struct ath_softc *sc, int dodelay)
+{
+#define PA2DESC(_sc, _pa) \
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+ struct ath_hal *ah = sc->sc_ah;
+
+ ath_hal_stoppcurecv(ah); /* disable PCU */
+ ath_hal_setrxfilter(ah, 0); /* clear recv filter */
+ ath_hal_stopdmarecv(ah); /* disable DMA engine */
+ /*
+ * TODO: see if this particular DELAY() is required; it may be
+ * masking some missing FIFO flush or DMA sync.
+ */
+#if 0
+ if (dodelay)
+#endif
+ DELAY(3000); /* 3ms is long enough for 1 frame */
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & (ATH_DEBUG_RESET | ATH_DEBUG_FATAL)) {
+ struct ath_buf *bf;
+ u_int ix;
+
+ device_printf(sc->sc_dev,
+ "%s: rx queue %p, link %p\n",
+ __func__,
+ (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah, HAL_RX_QUEUE_HP),
+ sc->sc_rxlink);
+ ix = 0;
+ TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+ struct ath_desc *ds = bf->bf_desc;
+ struct ath_rx_status *rs = &bf->bf_status.ds_rxstat;
+ HAL_STATUS status = ath_hal_rxprocdesc(ah, ds,
+ bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs);
+ if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL))
+ ath_printrxbuf(sc, bf, ix, status == HAL_OK);
+ ix++;
+ }
+ }
+#endif
+ /*
+ * Free both high/low RX pending, just in case.
+ */
+ if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) {
+ m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending);
+ sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
+ }
+ if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) {
+ m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending);
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL;
+ }
+ sc->sc_rxlink = NULL; /* just in case */
+#undef PA2DESC
+}
+
+/*
+ * Enable the receive h/w following a reset.
+ */
+static int
+ath_legacy_startrecv(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+
+ sc->sc_rxlink = NULL;
+ sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL;
+ TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+ int error = ath_rxbuf_init(sc, bf);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DEBUG_RECV,
+ "%s: ath_rxbuf_init failed %d\n",
+ __func__, error);
+ return error;
+ }
+ }
+
+ bf = TAILQ_FIRST(&sc->sc_rxbuf);
+ ath_hal_putrxbuf(ah, bf->bf_daddr, HAL_RX_QUEUE_HP);
+ ath_hal_rxena(ah); /* enable recv descriptors */
+ ath_mode_init(sc); /* set filters, etc. */
+ ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */
+ return 0;
+}
+
+static int
+ath_legacy_dma_rxsetup(struct ath_softc *sc)
+{
+ int error;
+
+ device_printf(sc->sc_dev, "%s: called\n", __func__);
+
+ error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ "rx", sizeof(struct ath_desc), ath_rxbuf, 1);
+ if (error != 0)
+ return (error);
+
+ return (0);
+}
+
+static int
+ath_legacy_dma_rxteardown(struct ath_softc *sc)
+{
+
+ device_printf(sc->sc_dev, "%s: called\n", __func__);
+
+ if (sc->sc_rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return (0);
+}
+
+void
+ath_recv_setup_legacy(struct ath_softc *sc)
+{
+
+ device_printf(sc->sc_dev, "DMA setup: legacy\n");
+
+ /* Sensible legacy defaults */
+ sc->sc_rx_statuslen = 0;
+
+ sc->sc_rx.recv_start = ath_legacy_startrecv;
+ sc->sc_rx.recv_stop = ath_legacy_stoprecv;
+ sc->sc_rx.recv_flush = ath_legacy_flushrecv;
+ sc->sc_rx.recv_tasklet = ath_legacy_rx_tasklet;
+ sc->sc_rx.recv_rxbuf_init = ath_legacy_rxbuf_init;
+
+ sc->sc_rx.recv_setup = ath_legacy_dma_rxsetup;
+ sc->sc_rx.recv_teardown = ath_legacy_dma_rxteardown;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_rx.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_rx.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: head/sys/dev/ath/if_ath_rx.h 238316 2012-07-10 00:02:19Z adrian $
+ */
+#ifndef __IF_ATH_RX_H__
+#define __IF_ATH_RX_H__
+
+extern u_int32_t ath_calcrxfilter(struct ath_softc *sc);
+extern void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
+ int subtype, int rssi, int nf);
+
+#define ath_stoprecv(_sc, _dodelay) \
+ (_sc)->sc_rx.recv_stop((_sc), (_dodelay))
+#define ath_startrecv(_sc) \
+ (_sc)->sc_rx.recv_start((_sc))
+#define ath_rx_flush(_sc) \
+ (_sc)->sc_rx.recv_flush((_sc))
+#define ath_rxbuf_init(_sc, _bf) \
+ (_sc)->sc_rx.recv_rxbuf_init((_sc), (_bf))
+#define ath_rxdma_setup(_sc) \
+ (_sc)->sc_rx.recv_setup(_sc)
+#define ath_rxdma_teardown(_sc) \
+ (_sc)->sc_rx.recv_teardown(_sc)
+
+#if 0
+extern int ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf);
+extern void ath_rx_tasklet(void *arg, int npending);
+extern void ath_rx_proc(struct ath_softc *sc, int resched);
+extern void ath_stoprecv(struct ath_softc *sc, int dodelay);
+extern int ath_startrecv(struct ath_softc *sc);
+#endif
+
+extern int ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs,
+ HAL_STATUS status, uint64_t tsf, int nf, HAL_RX_QUEUE qtype,
+ struct ath_buf *bf);
+
+extern void ath_recv_setup_legacy(struct ath_softc *sc);
+
+#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_rx_edma.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_rx_edma.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,849 @@
+/*-
+ * Copyright (c) 2012 Adrian Chadd <adrian at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_rx_edma.c 238710 2012-07-23 03:52:18Z adrian $");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h> /* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tsf.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_sysctl.h>
+#include <dev/ath/if_ath_led.h>
+#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_beacon.h>
+#include <dev/ath/if_athdfs.h>
+
+#ifdef ATH_TX99_DIAG
+#include <dev/ath/ath_tx99/ath_tx99.h>
+#endif
+
+#include <dev/ath/if_ath_rx_edma.h>
+
+/*
+ * some general macros
+ */
+#define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1)
+#define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1)
+
+MALLOC_DECLARE(M_ATHDEV);
+
+/*
+ * XXX TODO:
+ *
+ * + Add an RX lock, just to ensure we don't have things clash;
+ * + Make sure the FIFO is correctly flushed and reinitialised
+ * through a reset;
+ * + Handle the "kickpcu" state where the FIFO overflows.
+ * + Implement a "flush" routine, which doesn't push any
+ * new frames into the FIFO.
+ * + Verify multi-descriptor frames work!
+ * + There's a "memory use after free" which needs to be tracked down
+ * and fixed ASAP. I've seen this in the legacy path too, so it
+ * may be a generic RX path issue.
+ */
+
+/*
+ * XXX shuffle the function orders so these pre-declarations aren't
+ * required!
+ */
+static int ath_edma_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype,
+ int nbufs);
+static int ath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype);
+static void ath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf);
+static int ath_edma_recv_proc_queue(struct ath_softc *sc,
+ HAL_RX_QUEUE qtype, int dosched);
+
+static void
+ath_edma_stoprecv(struct ath_softc *sc, int dodelay)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ ATH_RX_LOCK(sc);
+ ath_hal_stoppcurecv(ah);
+ ath_hal_setrxfilter(ah, 0);
+ ath_hal_stopdmarecv(ah);
+
+ DELAY(3000);
+
+ /* Flush RX pending for each queue */
+ /* XXX should generic-ify this */
+ if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending) {
+ m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending);
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL;
+ }
+
+ if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending) {
+ m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending);
+ sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
+ }
+ ATH_RX_UNLOCK(sc);
+}
+
+/*
+ * Re-initialise the FIFO given the current buffer contents.
+ * Specifically, walk from head -> tail, pushing the FIFO contents
+ * back into the FIFO.
+ */
+static void
+ath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype)
+{
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+ struct ath_buf *bf;
+ int i, j;
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ i = re->m_fifo_head;
+ for (j = 0; j < re->m_fifo_depth; j++) {
+ bf = re->m_fifo[i];
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX,
+ "%s: Q%d: pos=%i, addr=0x%jx\n",
+ __func__,
+ qtype,
+ i,
+ (uintmax_t)bf->bf_daddr);
+ ath_hal_putrxbuf(sc->sc_ah, bf->bf_daddr, qtype);
+ INCR(i, re->m_fifolen);
+ }
+
+ /* Ensure this worked out right */
+ if (i != re->m_fifo_tail) {
+ device_printf(sc->sc_dev, "%s: i (%d) != tail! (%d)\n",
+ __func__,
+ i,
+ re->m_fifo_tail);
+ }
+}
+
+/*
+ * Start receive.
+ *
+ * XXX TODO: this needs to reallocate the FIFO entries when a reset
+ * occurs, in case the FIFO is filled up and no new descriptors get
+ * thrown into the FIFO.
+ */
+static int
+ath_edma_startrecv(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ ATH_RX_LOCK(sc);
+
+ /* Enable RX FIFO */
+ ath_hal_rxena(ah);
+
+ /*
+ * Entries should only be written out if the
+ * FIFO is empty.
+ *
+ * XXX This isn't correct. I should be looking
+ * at the value of AR_RXDP_SIZE (0x0070) to determine
+ * how many entries are in here.
+ *
+ * A warm reset will clear the registers but not the FIFO.
+ *
+ * And I believe this is actually the address of the last
+ * handled buffer rather than the current FIFO pointer.
+ * So if no frames have been (yet) seen, we'll reinit the
+ * FIFO.
+ *
+ * I'll chase that up at some point.
+ */
+ if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_HP) == 0) {
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX,
+ "%s: Re-initing HP FIFO\n", __func__);
+ ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_HP);
+ }
+ if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_LP) == 0) {
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX,
+ "%s: Re-initing LP FIFO\n", __func__);
+ ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_LP);
+ }
+
+ /* Add up to m_fifolen entries in each queue */
+ /*
+ * These must occur after the above write so the FIFO buffers
+ * are pushed/tracked in the same order as the hardware will
+ * process them.
+ */
+ ath_edma_rxfifo_alloc(sc, HAL_RX_QUEUE_HP,
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_fifolen);
+
+ ath_edma_rxfifo_alloc(sc, HAL_RX_QUEUE_LP,
+ sc->sc_rxedma[HAL_RX_QUEUE_LP].m_fifolen);
+
+ ath_mode_init(sc);
+ ath_hal_startpcurecv(ah);
+
+ ATH_RX_UNLOCK(sc);
+
+ return (0);
+}
+
+static void
+ath_edma_recv_flush(struct ath_softc *sc)
+{
+
+ device_printf(sc->sc_dev, "%s: called\n", __func__);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 0);
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 0);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+}
+
+/*
+ * Process frames from the current queue.
+ *
+ * TODO:
+ *
+ * + Add a "dosched" flag, so we don't reschedule any FIFO frames
+ * to the hardware or re-kick the PCU after 'kickpcu' is set.
+ *
+ * + Perhaps split "check FIFO contents" and "handle frames", so
+ * we can run the "check FIFO contents" in ath_intr(), but
+ * "handle frames" in the RX tasklet.
+ */
+static int
+ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
+ int dosched)
+{
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+ struct ath_rx_status *rs;
+ struct ath_desc *ds;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ struct ath_hal *ah = sc->sc_ah;
+ uint64_t tsf;
+ int16_t nf;
+ int ngood = 0, npkts = 0;
+ ath_bufhead rxlist;
+ struct ath_buf *next;
+
+ TAILQ_INIT(&rxlist);
+
+ tsf = ath_hal_gettsf64(ah);
+ nf = ath_hal_getchannoise(ah, sc->sc_curchan);
+ sc->sc_stats.ast_rx_noise = nf;
+
+ ATH_RX_LOCK(sc);
+
+ do {
+ bf = re->m_fifo[re->m_fifo_head];
+ /* This shouldn't occur! */
+ if (bf == NULL) {
+ device_printf(sc->sc_dev, "%s: Q%d: NULL bf?\n",
+ __func__,
+ qtype);
+ break;
+ }
+ m = bf->bf_m;
+ ds = bf->bf_desc;
+
+ /*
+ * Sync descriptor memory - this also syncs the buffer for us.
+ *
+ * EDMA descriptors are in cached memory.
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ rs = &bf->bf_status.ds_rxstat;
+ bf->bf_rxstatus = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr,
+ NULL, rs);
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
+ ath_printrxbuf(sc, bf, 0, bf->bf_rxstatus == HAL_OK);
+#endif
+ if (bf->bf_rxstatus == HAL_EINPROGRESS)
+ break;
+
+ /*
+ * Completed descriptor.
+ *
+ * In the future we'll call ath_rx_pkt(), but it first
+ * has to be taught about EDMA RX queues (so it can
+ * access sc_rxpending correctly.)
+ */
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX,
+ "%s: Q%d: completed!\n", __func__, qtype);
+ npkts++;
+
+ /*
+ * Remove the FIFO entry and place it on the completion
+ * queue.
+ */
+ re->m_fifo[re->m_fifo_head] = NULL;
+ TAILQ_INSERT_TAIL(&rxlist, bf, bf_list);
+
+ /* Bump the descriptor FIFO stats */
+ INCR(re->m_fifo_head, re->m_fifolen);
+ re->m_fifo_depth--;
+ /* XXX check it doesn't fall below 0 */
+ } while (re->m_fifo_depth > 0);
+
+ /* Append some more fresh frames to the FIFO */
+ if (dosched)
+ ath_edma_rxfifo_alloc(sc, qtype, re->m_fifolen);
+
+ ATH_RX_UNLOCK(sc);
+
+ /* Handle the completed descriptors */
+ TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) {
+ /*
+ * Skip the RX descriptor status - start at the data offset
+ */
+ m_adj(bf->bf_m, sc->sc_rx_statuslen);
+
+ /* Handle the frame */
+ /*
+ * Note: this may or may not free bf->bf_m and sync/unmap
+ * the frame.
+ */
+ rs = &bf->bf_status.ds_rxstat;
+ if (ath_rx_pkt(sc, rs, bf->bf_rxstatus, tsf, nf, qtype, bf))
+ ngood++;
+ }
+
+ /* Free in one set, inside the lock */
+ ATH_RX_LOCK(sc);
+ TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) {
+ /* Free the buffer/mbuf */
+ ath_edma_rxbuf_free(sc, bf);
+ }
+ ATH_RX_UNLOCK(sc);
+
+ /* rx signal state monitoring */
+ ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan);
+ if (ngood)
+ sc->sc_lastrx = tsf;
+
+ CTR2(ATH_KTR_INTR, "ath edma rx proc: npkts=%d, ngood=%d",
+ npkts, ngood);
+
+ /* Handle resched and kickpcu appropriately */
+ ATH_PCU_LOCK(sc);
+ if (dosched && sc->sc_kickpcu) {
+ CTR0(ATH_KTR_ERR, "ath_edma_recv_proc_queue(): kickpcu");
+ device_printf(sc->sc_dev,
+ "%s: handled npkts %d ngood %d\n",
+ __func__, npkts, ngood);
+
+ /*
+ * XXX TODO: what should occur here? Just re-poke and
+ * re-enable the RX FIFO?
+ */
+ sc->sc_kickpcu = 0;
+ }
+ ATH_PCU_UNLOCK(sc);
+
+ return (ngood);
+}
+
+static void
+ath_edma_recv_tasklet(void *arg, int npending)
+{
+ struct ath_softc *sc = (struct ath_softc *) arg;
+ struct ifnet *ifp = sc->sc_ifp;
+#ifdef IEEE80211_SUPPORT_SUPERG
+ struct ieee80211com *ic = ifp->if_l2com;
+#endif
+
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: called; npending=%d\n",
+ __func__,
+ npending);
+
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt > 0) {
+ device_printf(sc->sc_dev, "%s: sc_inreset_cnt > 0; skipping\n",
+ __func__);
+ ATH_PCU_UNLOCK(sc);
+ return;
+ }
+ sc->sc_rxproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1);
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1);
+
+ /* XXX inside IF_LOCK ? */
+ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
+#ifdef IEEE80211_SUPPORT_SUPERG
+ ieee80211_ff_age_all(ic, 100);
+#endif
+ if (! IFQ_IS_EMPTY(&ifp->if_snd))
+ ath_tx_kick(sc);
+ }
+ if (ath_dfs_tasklet_needed(sc, sc->sc_curchan))
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_dfstask);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+}
+
+/*
+ * Allocate an RX mbuf for the given ath_buf and initialise
+ * it for EDMA.
+ *
+ * + Allocate a 4KB mbuf;
+ * + Setup the DMA map for the given buffer;
+ * + Keep a pointer to the start of the mbuf - that's where the
+ * descriptor lies;
+ * + Take a pointer to the start of the RX buffer, set the
+ * mbuf "start" to be there;
+ * + Return that.
+ */
+static int
+ath_edma_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
+{
+
+ struct mbuf *m;
+ int error;
+ int len;
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+// device_printf(sc->sc_dev, "%s: called; bf=%p\n", __func__, bf);
+
+ m = m_getm(NULL, sc->sc_edma_bufsize, M_DONTWAIT, MT_DATA);
+ if (! m)
+ return (ENOBUFS); /* XXX ?*/
+
+ /* XXX warn/enforce alignment */
+
+ len = m->m_ext.ext_size;
+#if 0
+ device_printf(sc->sc_dev, "%s: called: m=%p, size=%d, mtod=%p\n",
+ __func__,
+ m,
+ len,
+ mtod(m, char *));
+#endif
+
+ m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
+
+ /*
+ * Create DMA mapping.
+ */
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat,
+ bf->bf_dmamap, m, bf->bf_segs, &bf->bf_nseg, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "%s: failed; error=%d\n",
+ __func__,
+ error);
+ m_freem(m);
+ return (error);
+ }
+
+ /*
+ * Populate ath_buf fields.
+ */
+
+ bf->bf_desc = mtod(m, struct ath_desc *);
+ bf->bf_daddr = bf->bf_segs[0].ds_addr;
+ bf->bf_lastds = bf->bf_desc; /* XXX only really for TX? */
+ bf->bf_m = m;
+
+ /* Zero the descriptor */
+ memset(bf->bf_desc, '\0', sc->sc_rx_statuslen);
+
+#if 0
+ /*
+ * Adjust mbuf header and length/size to compensate for the
+ * descriptor size.
+ */
+ m_adj(m, sc->sc_rx_statuslen);
+#endif
+
+ /* Finish! */
+
+ return (0);
+}
+
+static struct ath_buf *
+ath_edma_rxbuf_alloc(struct ath_softc *sc)
+{
+ struct ath_buf *bf;
+ int error;
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ /* Allocate buffer */
+ bf = TAILQ_FIRST(&sc->sc_rxbuf);
+ /* XXX shouldn't happen upon startup? */
+ if (bf == NULL)
+ return (NULL);
+
+ /* Remove it from the free list */
+ TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
+
+ /* Assign RX mbuf to it */
+ error = ath_edma_rxbuf_init(sc, bf);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: bf=%p, rxbuf alloc failed! error=%d\n",
+ __func__,
+ bf,
+ error);
+ TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+ return (NULL);
+ }
+
+ return (bf);
+}
+
+static void
+ath_edma_rxbuf_free(struct ath_softc *sc, struct ath_buf *bf)
+{
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ /* We're doing this multiple times? */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+
+ if (bf->bf_m) {
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+
+ /* XXX lock? */
+ TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+}
+
+/*
+ * Allocate up to 'n' entries and push them onto the hardware FIFO.
+ *
+ * Return how many entries were successfully pushed onto the
+ * FIFO.
+ */
+static int
+ath_edma_rxfifo_alloc(struct ath_softc *sc, HAL_RX_QUEUE qtype, int nbufs)
+{
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+ struct ath_buf *bf;
+ int i;
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ /*
+ * Allocate buffers until the FIFO is full or nbufs is reached.
+ */
+ for (i = 0; i < nbufs && re->m_fifo_depth < re->m_fifolen; i++) {
+ /* Ensure the FIFO is already blank, complain loudly! */
+ if (re->m_fifo[re->m_fifo_tail] != NULL) {
+ device_printf(sc->sc_dev,
+ "%s: Q%d: fifo[%d] != NULL (%p)\n",
+ __func__,
+ qtype,
+ re->m_fifo_tail,
+ re->m_fifo[re->m_fifo_tail]);
+
+ /* Free the slot */
+ ath_edma_rxbuf_free(sc, re->m_fifo[re->m_fifo_tail]);
+ re->m_fifo_depth--;
+ /* XXX check it's not < 0 */
+ re->m_fifo[re->m_fifo_tail] = NULL;
+ }
+
+ bf = ath_edma_rxbuf_alloc(sc);
+ /* XXX should ensure the FIFO is not NULL? */
+ if (bf == NULL) {
+ device_printf(sc->sc_dev, "%s: Q%d: alloc failed?\n",
+ __func__,
+ qtype);
+ break;
+ }
+
+ re->m_fifo[re->m_fifo_tail] = bf;
+
+ /*
+ * Flush the descriptor contents before it's handed to the
+ * hardware.
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_PREREAD);
+
+ /* Write to the RX FIFO */
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: Q%d: putrxbuf=%p\n",
+ __func__,
+ qtype,
+ bf->bf_desc);
+ ath_hal_putrxbuf(sc->sc_ah, bf->bf_daddr, qtype);
+
+ re->m_fifo_depth++;
+ INCR(re->m_fifo_tail, re->m_fifolen);
+ }
+
+ /*
+ * Return how many were allocated.
+ */
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX, "%s: Q%d: nbufs=%d, nalloced=%d\n",
+ __func__,
+ qtype,
+ nbufs,
+ i);
+ return (i);
+}
+
+static int
+ath_edma_rxfifo_flush(struct ath_softc *sc, HAL_RX_QUEUE qtype)
+{
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+ int i;
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ for (i = 0; i < re->m_fifolen; i++) {
+ if (re->m_fifo[i] != NULL) {
+#ifdef ATH_DEBUG
+ struct ath_buf *bf = re->m_fifo[i];
+
+ if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
+ ath_printrxbuf(sc, bf, 0, HAL_OK);
+#endif
+ ath_edma_rxbuf_free(sc, re->m_fifo[i]);
+ re->m_fifo[i] = NULL;
+ re->m_fifo_depth--;
+ }
+ }
+
+ if (re->m_rxpending != NULL) {
+ m_freem(re->m_rxpending);
+ re->m_rxpending = NULL;
+ }
+ re->m_fifo_head = re->m_fifo_tail = re->m_fifo_depth = 0;
+
+ return (0);
+}
+
+/*
+ * Setup the initial RX FIFO structure.
+ */
+static int
+ath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype)
+{
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ if (! ath_hal_getrxfifodepth(sc->sc_ah, qtype, &re->m_fifolen)) {
+ device_printf(sc->sc_dev, "%s: qtype=%d, failed\n",
+ __func__,
+ qtype);
+ return (-EINVAL);
+ }
+ device_printf(sc->sc_dev, "%s: type=%d, FIFO depth = %d entries\n",
+ __func__,
+ qtype,
+ re->m_fifolen);
+
+ /* Allocate ath_buf FIFO array, pre-zero'ed */
+ re->m_fifo = malloc(sizeof(struct ath_buf *) * re->m_fifolen,
+ M_ATHDEV,
+ M_NOWAIT | M_ZERO);
+ if (re->m_fifo == NULL) {
+ device_printf(sc->sc_dev, "%s: malloc failed\n",
+ __func__);
+ return (-ENOMEM);
+ }
+
+ /*
+ * Set initial "empty" state.
+ */
+ re->m_rxpending = NULL;
+ re->m_fifo_head = re->m_fifo_tail = re->m_fifo_depth = 0;
+
+ return (0);
+}
+
+static int
+ath_edma_rxfifo_free(struct ath_softc *sc, HAL_RX_QUEUE qtype)
+{
+ struct ath_rx_edma *re = &sc->sc_rxedma[qtype];
+
+ device_printf(sc->sc_dev, "%s: called; qtype=%d\n",
+ __func__,
+ qtype);
+
+ free(re->m_fifo, M_ATHDEV);
+
+ return (0);
+}
+
+static int
+ath_edma_dma_rxsetup(struct ath_softc *sc)
+{
+ int error;
+
+ /*
+ * Create RX DMA tag and buffers.
+ */
+ error = ath_descdma_setup_rx_edma(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ "rx", ath_rxbuf, sc->sc_rx_statuslen);
+ if (error != 0)
+ return error;
+
+ ATH_RX_LOCK(sc);
+ (void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_HP);
+ (void) ath_edma_setup_rxfifo(sc, HAL_RX_QUEUE_LP);
+ ATH_RX_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+ath_edma_dma_rxteardown(struct ath_softc *sc)
+{
+
+ device_printf(sc->sc_dev, "%s: called\n", __func__);
+
+ ATH_RX_LOCK(sc);
+ ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_HP);
+ ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_HP);
+
+ ath_edma_rxfifo_flush(sc, HAL_RX_QUEUE_LP);
+ ath_edma_rxfifo_free(sc, HAL_RX_QUEUE_LP);
+ ATH_RX_UNLOCK(sc);
+
+ /* Free RX ath_buf */
+ /* Free RX DMA tag */
+ if (sc->sc_rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+
+ return (0);
+}
+
+void
+ath_recv_setup_edma(struct ath_softc *sc)
+{
+
+ device_printf(sc->sc_dev, "DMA setup: EDMA\n");
+
+ /* Set buffer size to 4k */
+ sc->sc_edma_bufsize = 4096;
+
+ /* Fetch EDMA field and buffer sizes */
+ (void) ath_hal_getrxstatuslen(sc->sc_ah, &sc->sc_rx_statuslen);
+
+ /* Configure the hardware with the RX buffer size */
+ (void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize -
+ sc->sc_rx_statuslen);
+
+ device_printf(sc->sc_dev, "RX status length: %d\n",
+ sc->sc_rx_statuslen);
+ device_printf(sc->sc_dev, "RX buffer size: %d\n",
+ sc->sc_edma_bufsize);
+
+ sc->sc_rx.recv_stop = ath_edma_stoprecv;
+ sc->sc_rx.recv_start = ath_edma_startrecv;
+ sc->sc_rx.recv_flush = ath_edma_recv_flush;
+ sc->sc_rx.recv_tasklet = ath_edma_recv_tasklet;
+ sc->sc_rx.recv_rxbuf_init = ath_edma_rxbuf_init;
+
+ sc->sc_rx.recv_setup = ath_edma_dma_rxsetup;
+ sc->sc_rx.recv_teardown = ath_edma_dma_rxteardown;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_rx_edma.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_rx_edma.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2012 Adrian Chadd <adrian at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: head/sys/dev/ath/if_ath_rx_edma.h 238055 2012-07-03 06:59:12Z adrian $
+ */
+#ifndef __IF_ATH_RX_EDMA_H__
+#define __IF_ATH_RX_EDMA_H__
+
+extern void ath_recv_setup_edma(struct ath_softc *sc);
+
+#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_sysctl.c
--- a/head/sys/dev/ath/if_ath_sysctl.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_sysctl.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_sysctl.c 234090 2012-04-10 07:23:37Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_sysctl.c 238507 2012-07-15 20:51:41Z adrian $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -374,7 +374,20 @@
t++;
}
ATH_TXBUF_UNLOCK(sc);
- printf("Total TX buffers: %d; Total TX buffers busy: %d\n",
+ printf("Total TX buffers: %d; Total TX buffers busy: %d (%d)\n",
+ t, i, sc->sc_txbuf_cnt);
+
+ i = t = 0;
+ ATH_TXBUF_LOCK(sc);
+ TAILQ_FOREACH(bf, &sc->sc_txbuf_mgmt, bf_list) {
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ printf("Busy: %d\n", t);
+ i++;
+ }
+ t++;
+ }
+ ATH_TXBUF_UNLOCK(sc);
+ printf("Total mgmt TX buffers: %d; Total mgmt TX buffers busy: %d\n",
t, i);
return 0;
@@ -501,8 +514,8 @@
"regdomain", CTLFLAG_RD, &sc->sc_eerd, 0,
"EEPROM regdomain code");
#ifdef ATH_DEBUG
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
- "debug", CTLFLAG_RW, &sc->sc_debug, 0,
+ SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->sc_debug,
"control debugging printfs");
#endif
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -607,12 +620,11 @@
"tid_hwq_hi", CTLFLAG_RW, &sc->sc_tid_hwq_hi, 0,
"");
-#if 0
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txq_data_minfree", CTLFLAG_RW, &sc->sc_txq_data_minfree,
0, "Minimum free buffers before adding a data frame"
" to the TX queue");
-#endif
+
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txq_mcastq_maxdepth", CTLFLAG_RW,
&sc->sc_txq_mcastq_maxdepth, 0,
@@ -922,6 +934,8 @@
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_mcastq_overflow",
CTLFLAG_RD, &sc->sc_stats.ast_tx_mcastq_overflow, 0,
"Number of multicast frames exceeding maximum mcast queue depth");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_keymiss", CTLFLAG_RD,
+ &sc->sc_stats.ast_rx_keymiss, 0, "");
/* Attach the RX phy error array */
ath_sysctl_stats_attach_rxphyerr(sc, child);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tdma.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_tdma.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,476 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tdma.c 235679 2012-05-20 02:49:42Z adrian $");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h> /* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tsf.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_sysctl.h>
+#include <dev/ath/if_ath_led.h>
+#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_beacon.h>
+#include <dev/ath/if_athdfs.h>
+
+#ifdef ATH_TX99_DIAG
+#include <dev/ath/ath_tx99/ath_tx99.h>
+#endif
+
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <dev/ath/if_ath_tdma.h>
+
+static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt,
+ u_int32_t bintval);
+static void ath_tdma_bintvalsetup(struct ath_softc *sc,
+ const struct ieee80211_tdma_state *tdma);
+#endif /* IEEE80211_SUPPORT_TDMA */
+
+#ifdef IEEE80211_SUPPORT_TDMA
+static void
+ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_BEACON_TIMERS bt;
+
+ bt.bt_intval = bintval | HAL_BEACON_ENA;
+ bt.bt_nexttbtt = nexttbtt;
+ bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep;
+ bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep;
+ bt.bt_nextatim = nexttbtt+1;
+ /* Enables TBTT, DBA, SWBA timers by default */
+ bt.bt_flags = 0;
+ ath_hal_beaconsettimers(ah, &bt);
+}
+
+/*
+ * Calculate the beacon interval. This is periodic in the
+ * superframe for the bss. We assume each station is configured
+ * identically wrt transmit rate so the guard time we calculate
+ * above will be the same on all stations. Note we need to
+ * factor in the xmit time because the hardware will schedule
+ * a frame for transmit if the start of the frame is within
+ * the burst time. When we get hardware that properly kills
+ * frames in the PCU we can reduce/eliminate the guard time.
+ *
+ * Roundup to 1024 is so we have 1 TU buffer in the guard time
+ * to deal with the granularity of the nexttbtt timer. 11n MAC's
+ * with 1us timer granularity should allow us to reduce/eliminate
+ * this.
+ */
+static void
+ath_tdma_bintvalsetup(struct ath_softc *sc,
+ const struct ieee80211_tdma_state *tdma)
+{
+ /* copy from vap state (XXX check all vaps have same value?) */
+ sc->sc_tdmaslotlen = tdma->tdma_slotlen;
+
+ sc->sc_tdmabintval = roundup((sc->sc_tdmaslotlen+sc->sc_tdmaguard) *
+ tdma->tdma_slotcnt, 1024);
+ sc->sc_tdmabintval >>= 10; /* TSF -> TU */
+ if (sc->sc_tdmabintval & 1)
+ sc->sc_tdmabintval++;
+
+ if (tdma->tdma_slot == 0) {
+ /*
+ * Only slot 0 beacons; other slots respond.
+ */
+ sc->sc_imask |= HAL_INT_SWBA;
+ sc->sc_tdmaswba = 0; /* beacon immediately */
+ } else {
+ /* XXX all vaps must be slot 0 or slot !0 */
+ sc->sc_imask &= ~HAL_INT_SWBA;
+ }
+}
+
+/*
+ * Max 802.11 overhead. This assumes no 4-address frames and
+ * the encapsulation done by ieee80211_encap (llc). We also
+ * include potential crypto overhead.
+ */
+#define IEEE80211_MAXOVERHEAD \
+ (sizeof(struct ieee80211_qosframe) \
+ + sizeof(struct llc) \
+ + IEEE80211_ADDR_LEN \
+ + IEEE80211_WEP_IVLEN \
+ + IEEE80211_WEP_KIDLEN \
+ + IEEE80211_WEP_CRCLEN \
+ + IEEE80211_WEP_MICLEN \
+ + IEEE80211_CRC_LEN)
+
+/*
+ * Setup initially for tdma operation. Start the beacon
+ * timers and enable SWBA if we are slot 0. Otherwise
+ * we wait for slot 0 to arrive so we can sync up before
+ * starting to transmit.
+ */
+void
+ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ const struct ieee80211_txparam *tp;
+ const struct ieee80211_tdma_state *tdma = NULL;
+ int rix;
+
+ if (vap == NULL) {
+ vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
+ if (vap == NULL) {
+ if_printf(ifp, "%s: no vaps?\n", __func__);
+ return;
+ }
+ }
+ /* XXX should take a locked ref to iv_bss */
+ tp = vap->iv_bss->ni_txparms;
+ /*
+ * Calculate the guard time for each slot. This is the
+ * time to send a maximal-size frame according to the
+ * fixed/lowest transmit rate. Note that the interface
+ * mtu does not include the 802.11 overhead so we must
+ * tack that on (ath_hal_computetxtime includes the
+ * preamble and plcp in it's calculation).
+ */
+ tdma = vap->iv_tdma;
+ if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+ rix = ath_tx_findrix(sc, tp->ucastrate);
+ else
+ rix = ath_tx_findrix(sc, tp->mcastrate);
+ /* XXX short preamble assumed */
+ sc->sc_tdmaguard = ath_hal_computetxtime(ah, sc->sc_currates,
+ ifp->if_mtu + IEEE80211_MAXOVERHEAD, rix, AH_TRUE);
+
+ ath_hal_intrset(ah, 0);
+
+ ath_beaconq_config(sc); /* setup h/w beacon q */
+ if (sc->sc_setcca)
+ ath_hal_setcca(ah, AH_FALSE); /* disable CCA */
+ ath_tdma_bintvalsetup(sc, tdma); /* calculate beacon interval */
+ ath_tdma_settimers(sc, sc->sc_tdmabintval,
+ sc->sc_tdmabintval | HAL_BEACON_RESET_TSF);
+ sc->sc_syncbeacon = 0;
+
+ sc->sc_avgtsfdeltap = TDMA_DUMMY_MARKER;
+ sc->sc_avgtsfdeltam = TDMA_DUMMY_MARKER;
+
+ ath_hal_intrset(ah, sc->sc_imask);
+
+ DPRINTF(sc, ATH_DEBUG_TDMA, "%s: slot %u len %uus cnt %u "
+ "bsched %u guard %uus bintval %u TU dba prep %u\n", __func__,
+ tdma->tdma_slot, tdma->tdma_slotlen, tdma->tdma_slotcnt,
+ tdma->tdma_bintval, sc->sc_tdmaguard, sc->sc_tdmabintval,
+ sc->sc_tdmadbaprep);
+}
+
+/*
+ * Update tdma operation. Called from the 802.11 layer
+ * when a beacon is received from the TDMA station operating
+ * in the slot immediately preceding us in the bss. Use
+ * the rx timestamp for the beacon frame to update our
+ * beacon timers so we follow their schedule. Note that
+ * by using the rx timestamp we implicitly include the
+ * propagation delay in our schedule.
+ */
+void
+ath_tdma_update(struct ieee80211_node *ni,
+ const struct ieee80211_tdma_param *tdma, int changed)
+{
+#define TSF_TO_TU(_h,_l) \
+ ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
+#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10)
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ u_int64_t tsf, rstamp, nextslot, nexttbtt;
+ u_int32_t txtime, nextslottu;
+ int32_t tudelta, tsfdelta;
+ const struct ath_rx_status *rs;
+ int rix;
+
+ sc->sc_stats.ast_tdma_update++;
+
+ /*
+ * Check for and adopt configuration changes.
+ */
+ if (changed != 0) {
+ const struct ieee80211_tdma_state *ts = vap->iv_tdma;
+
+ ath_tdma_bintvalsetup(sc, ts);
+ if (changed & TDMA_UPDATE_SLOTLEN)
+ ath_wme_update(ic);
+
+ DPRINTF(sc, ATH_DEBUG_TDMA,
+ "%s: adopt slot %u slotcnt %u slotlen %u us "
+ "bintval %u TU\n", __func__,
+ ts->tdma_slot, ts->tdma_slotcnt, ts->tdma_slotlen,
+ sc->sc_tdmabintval);
+
+ /* XXX right? */
+ ath_hal_intrset(ah, sc->sc_imask);
+ /* NB: beacon timers programmed below */
+ }
+
+ /* extend rx timestamp to 64 bits */
+ rs = sc->sc_lastrs;
+ tsf = ath_hal_gettsf64(ah);
+ rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf);
+ /*
+ * The rx timestamp is set by the hardware on completing
+ * reception (at the point where the rx descriptor is DMA'd
+ * to the host). To find the start of our next slot we
+ * must adjust this time by the time required to send
+ * the packet just received.
+ */
+ rix = rt->rateCodeToIndex[rs->rs_rate];
+ txtime = ath_hal_computetxtime(ah, rt, rs->rs_datalen, rix,
+ rt->info[rix].shortPreamble);
+ /* NB: << 9 is to cvt to TU and /2 */
+ nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9);
+ nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD;
+
+ /*
+ * Retrieve the hardware NextTBTT in usecs
+ * and calculate the difference between what the
+ * other station thinks and what we have programmed. This
+ * lets us figure how to adjust our timers to match. The
+ * adjustments are done by pulling the TSF forward and possibly
+ * rewriting the beacon timers.
+ */
+ nexttbtt = ath_hal_getnexttbtt(ah);
+ tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt);
+
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "tsfdelta %d avg +%d/-%d\n", tsfdelta,
+ TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam));
+
+ if (tsfdelta < 0) {
+ TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0);
+ TDMA_SAMPLE(sc->sc_avgtsfdeltam, -tsfdelta);
+ tsfdelta = -tsfdelta % 1024;
+ nextslottu++;
+ } else if (tsfdelta > 0) {
+ TDMA_SAMPLE(sc->sc_avgtsfdeltap, tsfdelta);
+ TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0);
+ tsfdelta = 1024 - (tsfdelta % 1024);
+ nextslottu++;
+ } else {
+ TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0);
+ TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0);
+ }
+ tudelta = nextslottu - TSF_TO_TU(nexttbtt >> 32, nexttbtt);
+
+ /*
+ * Copy sender's timetstamp into tdma ie so they can
+ * calculate roundtrip time. We submit a beacon frame
+ * below after any timer adjustment. The frame goes out
+ * at the next TBTT so the sender can calculate the
+ * roundtrip by inspecting the tdma ie in our beacon frame.
+ *
+ * NB: This tstamp is subtlely preserved when
+ * IEEE80211_BEACON_TDMA is marked (e.g. when the
+ * slot position changes) because ieee80211_add_tdma
+ * skips over the data.
+ */
+ memcpy(ATH_VAP(vap)->av_boff.bo_tdma +
+ __offsetof(struct ieee80211_tdma_param, tdma_tstamp),
+ &ni->ni_tstamp.data, 8);
+#if 0
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "tsf %llu nextslot %llu (%d, %d) nextslottu %u nexttbtt %llu (%d)\n",
+ (unsigned long long) tsf, (unsigned long long) nextslot,
+ (int)(nextslot - tsf), tsfdelta, nextslottu, nexttbtt, tudelta);
+#endif
+ /*
+ * Adjust the beacon timers only when pulling them forward
+ * or when going back by less than the beacon interval.
+ * Negative jumps larger than the beacon interval seem to
+ * cause the timers to stop and generally cause instability.
+ * This basically filters out jumps due to missed beacons.
+ */
+ if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) {
+ ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval);
+ sc->sc_stats.ast_tdma_timers++;
+ }
+ if (tsfdelta > 0) {
+ ath_hal_adjusttsf(ah, tsfdelta);
+ sc->sc_stats.ast_tdma_tsf++;
+ }
+ ath_tdma_beacon_send(sc, vap); /* prepare response */
+#undef TU_TO_TSF
+#undef TSF_TO_TU
+}
+
+/*
+ * Transmit a beacon frame at SWBA. Dynamic updates
+ * to the frame contents are done as needed.
+ */
+void
+ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+ int otherant;
+
+ /*
+ * Check if the previous beacon has gone out. If
+ * not don't try to post another, skip this period
+ * and wait for the next. Missed beacons indicate
+ * a problem and should not occur. If we miss too
+ * many consecutive beacons reset the device.
+ */
+ if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
+ sc->sc_bmisscount++;
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: missed %u consecutive beacons\n",
+ __func__, sc->sc_bmisscount);
+ if (sc->sc_bmisscount >= ath_bstuck_threshold)
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask);
+ return;
+ }
+ if (sc->sc_bmisscount != 0) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: resume beacon xmit after %u misses\n",
+ __func__, sc->sc_bmisscount);
+ sc->sc_bmisscount = 0;
+ }
+
+ /*
+ * Check recent per-antenna transmit statistics and flip
+ * the default antenna if noticeably more frames went out
+ * on the non-default antenna.
+ * XXX assumes 2 anntenae
+ */
+ if (!sc->sc_diversity) {
+ otherant = sc->sc_defant & 1 ? 2 : 1;
+ if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
+ ath_setdefantenna(sc, otherant);
+ sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
+ }
+
+ bf = ath_beacon_generate(sc, vap);
+ if (bf != NULL) {
+ /*
+ * Stop any current dma and put the new frame on the queue.
+ * This should never fail since we check above that no frames
+ * are still pending on the queue.
+ */
+ if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: beacon queue %u did not stop?\n",
+ __func__, sc->sc_bhalq);
+ /* NB: the HAL still stops DMA, so proceed */
+ }
+ ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
+ ath_hal_txstart(ah, sc->sc_bhalq);
+
+ sc->sc_stats.ast_be_xmit++; /* XXX per-vap? */
+
+ /*
+ * Record local TSF for our last send for use
+ * in arbitrating slot collisions.
+ */
+ /* XXX should take a locked ref to iv_bss */
+ vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah);
+ }
+}
+#endif /* IEEE80211_SUPPORT_TDMA */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tdma.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_tdma.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: head/sys/dev/ath/if_ath_tdma.h 235679 2012-05-20 02:49:42Z adrian $
+ */
+#ifndef __IF_ATH_TDMA_H__
+#define __IF_ATH_TDMA_H__
+
+#define TDMA_EP_MULTIPLIER (1<<10) /* pow2 to optimize out * and / */
+#define TDMA_LPF_LEN 6
+#define TDMA_DUMMY_MARKER 0x127
+#define TDMA_EP_MUL(x, mul) ((x) * (mul))
+#define TDMA_IN(x) (TDMA_EP_MUL((x), TDMA_EP_MULTIPLIER))
+#define TDMA_LPF(x, y, len) \
+ ((x != TDMA_DUMMY_MARKER) ? (((x) * ((len)-1) + (y)) / (len)) : (y))
+#define TDMA_SAMPLE(x, y) do { \
+ x = TDMA_LPF((x), TDMA_IN(y), TDMA_LPF_LEN); \
+} while (0)
+#define TDMA_EP_RND(x,mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? \
+ ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+#define TDMA_AVG(x) TDMA_EP_RND(x, TDMA_EP_MULTIPLIER)
+
+extern void ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap);
+extern void ath_tdma_update(struct ieee80211_node *ni,
+ const struct ieee80211_tdma_param *tdma, int changed);
+extern void ath_tdma_beacon_send(struct ath_softc *sc,
+ struct ieee80211vap *vap);
+
+#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tsf.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_tsf.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: head/sys/dev/ath/if_ath_tsf.h 235676 2012-05-20 02:05:10Z adrian $
+ */
+#ifndef __IF_ATH_TSF_H__
+#define __IF_ATH_TSF_H__
+
+/*
+ * Extend 15-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the specified TSF.
+ */
+static __inline u_int64_t
+ath_extend_tsf15(u_int32_t rstamp, u_int64_t tsf)
+{
+ if ((tsf & 0x7fff) < rstamp)
+ tsf -= 0x8000;
+
+ return ((tsf &~ 0x7fff) | rstamp);
+}
+
+/*
+ * Extend 32-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the specified TSF.
+ */
+static __inline u_int64_t
+ath_extend_tsf32(u_int32_t rstamp, u_int64_t tsf)
+{
+ u_int32_t tsf_low = tsf & 0xffffffff;
+ u_int64_t tsf64 = (tsf & ~0xffffffffULL) | rstamp;
+
+ if (rstamp > tsf_low && (rstamp - tsf_low > 0x10000000))
+ tsf64 -= 0x100000000ULL;
+
+ if (rstamp < tsf_low && (tsf_low - rstamp > 0x10000000))
+ tsf64 += 0x100000000ULL;
+
+ return tsf64;
+}
+
+/*
+ * Extend the TSF from the RX descriptor to a full 64 bit TSF.
+ * Earlier hardware versions only wrote the low 15 bits of the
+ * TSF into the RX descriptor; later versions (AR5416 and up)
+ * include the 32 bit TSF value.
+ */
+static __inline u_int64_t
+ath_extend_tsf(struct ath_softc *sc, u_int32_t rstamp, u_int64_t tsf)
+{
+ if (sc->sc_rxtsf32)
+ return ath_extend_tsf32(rstamp, tsf);
+ else
+ return ath_extend_tsf15(rstamp, tsf);
+}
+
+#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tx.c
--- a/head/sys/dev/ath/if_ath_tx.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_tx.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx.c 234324 2012-04-15 20:29:39Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx.c 238729 2012-07-23 23:40:13Z adrian $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -109,10 +109,10 @@
int tid);
static int ath_tx_ampdu_running(struct ath_softc *sc, struct ath_node *an,
int tid);
+static ieee80211_seq ath_tx_tid_seqno_assign(struct ath_softc *sc,
+ struct ieee80211_node *ni, struct ath_buf *bf, struct mbuf *m0);
static int ath_tx_action_frame_override_queue(struct ath_softc *sc,
struct ieee80211_node *ni, struct mbuf *m0, int *tid);
-static int ath_tx_seqno_required(struct ath_softc *sc,
- struct ieee80211_node *ni, struct ath_buf *bf, struct mbuf *m0);
/*
* Whether to use the 11n rate scenario functions or not
@@ -184,7 +184,7 @@
TAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
/* NB: bf assumed clean */
TAILQ_REMOVE(frags, bf, bf_list);
- TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ ath_returnbuf_head(sc, bf);
ieee80211_node_decref(ni);
}
}
@@ -203,7 +203,8 @@
ATH_TXBUF_LOCK(sc);
for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
- bf = _ath_getbuf_locked(sc);
+ /* XXX non-management? */
+ bf = _ath_getbuf_locked(sc, ATH_BUFTYPE_NORMAL);
if (bf == NULL) { /* out of buffers, cleanup */
device_printf(sc->sc_dev, "%s: no buffer?\n",
__func__);
@@ -301,6 +302,11 @@
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds, *ds0;
int i;
+ /*
+ * XXX There's txdma and txdma_mgmt; the descriptor
+ * sizes must match.
+ */
+ struct ath_descdma *dd = &sc->sc_txdma;
/*
* Fillin the remainder of the descriptor info.
@@ -309,9 +315,10 @@
for (i = 0; i < bf->bf_nseg; i++, ds++) {
ds->ds_data = bf->bf_segs[i].ds_addr;
if (i == bf->bf_nseg - 1)
- ds->ds_link = 0;
+ ath_hal_settxdesclink(ah, ds, 0);
else
- ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
+ ath_hal_settxdesclink(ah, ds,
+ bf->bf_daddr + dd->dd_descsize * (i + 1));
ath_hal_filltxdesc(ah, ds
, bf->bf_segs[i].ds_len /* segment length */
, i == 0 /* first segment */
@@ -339,6 +346,11 @@
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds, *ds0;
int i;
+ /*
+ * XXX There's txdma and txdma_mgmt; the descriptor
+ * sizes must match.
+ */
+ struct ath_descdma *dd = &sc->sc_txdma;
ds0 = ds = bf->bf_desc;
@@ -349,9 +361,10 @@
for (i = 0; i < bf->bf_nseg; i++, ds++) {
ds->ds_data = bf->bf_segs[i].ds_addr;
if (i == bf->bf_nseg - 1)
- ds->ds_link = 0;
+ ath_hal_settxdesclink(ah, ds, 0);
else
- ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
+ ath_hal_settxdesclink(ah, ds,
+ bf->bf_daddr + dd->dd_descsize * (i + 1));
/*
* This performs the setup for an aggregate frame.
@@ -413,7 +426,8 @@
* to the beginning descriptor of this frame.
*/
if (bf_prev != NULL)
- bf_prev->bf_lastds->ds_link = bf->bf_daddr;
+ ath_hal_settxdesclink(sc->sc_ah, bf_prev->bf_lastds,
+ bf->bf_daddr);
/* Save a copy so we can link the next descriptor in */
bf_prev = bf;
@@ -481,7 +495,7 @@
*txq->axq_link = bf->bf_daddr;
}
ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- txq->axq_link = &bf->bf_lastds->ds_link;
+ ath_hal_gettxdesclinkptr(sc->sc_ah, bf->bf_lastds, &txq->axq_link);
}
/*
@@ -615,7 +629,7 @@
#endif /* IEEE80211_SUPPORT_TDMA */
if (bf->bf_state.bfs_aggr)
txq->axq_aggr_depth++;
- txq->axq_link = &bf->bf_lastds->ds_link;
+ ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
ath_hal_txstart(ah, txq->axq_qnum);
}
}
@@ -644,7 +658,7 @@
return;
ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- txq->axq_link = &bf_last->bf_lastds->ds_link;
+ ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
ath_hal_txstart(ah, txq->axq_qnum);
}
@@ -1171,6 +1185,15 @@
struct ath_node *an;
u_int pri;
+ /*
+ * To ensure that both sequence numbers and the CCMP PN handling
+ * is "correct", make sure that the relevant TID queue is locked.
+ * Otherwise the CCMP PN and seqno may appear out of order, causing
+ * re-ordered frames to have out of order CCMP PN's, resulting
+ * in many, many frame drops.
+ */
+ ATH_TXQ_LOCK_ASSERT(txq);
+
wh = mtod(m0, struct ieee80211_frame *);
iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
@@ -1299,6 +1322,40 @@
}
/*
+ * There are two known scenarios where the frame AC doesn't match
+ * what the destination TXQ is.
+ *
+ * + non-QoS frames (eg management?) that the net80211 stack has
+ * assigned a higher AC to, but since it's a non-QoS TID, it's
+ * being thrown into TID 16. TID 16 gets the AC_BE queue.
+ * It's quite possible that management frames should just be
+ * direct dispatched to hardware rather than go via the software
+ * queue; that should be investigated in the future. There are
+ * some specific scenarios where this doesn't make sense, mostly
+ * surrounding ADDBA request/response - hence why that is special
+ * cased.
+ *
+ * + Multicast frames going into the VAP mcast queue. That shows up
+ * as "TXQ 11".
+ *
+ * This driver should eventually support separate TID and TXQ locking,
+ * allowing for arbitrary AC frames to appear on arbitrary software
+ * queues, being queued to the "correct" hardware queue when needed.
+ */
+#if 0
+ if (txq != sc->sc_ac2q[pri]) {
+ device_printf(sc->sc_dev,
+ "%s: txq=%p (%d), pri=%d, pri txq=%p (%d)\n",
+ __func__,
+ txq,
+ txq->axq_qnum,
+ pri,
+ sc->sc_ac2q[pri],
+ sc->sc_ac2q[pri]->axq_qnum);
+ }
+#endif
+
+ /*
* Calculate miscellaneous flags.
*/
if (ismcast) {
@@ -1424,7 +1481,7 @@
int ismcast;
const struct ieee80211_frame *wh;
int is_ampdu, is_ampdu_tx, is_ampdu_pending;
- //ieee80211_seq seqno;
+ ieee80211_seq seqno;
uint8_t type, subtype;
/*
@@ -1476,9 +1533,8 @@
is_ampdu_pending = ath_tx_ampdu_pending(sc, ATH_NODE(ni), tid);
is_ampdu = is_ampdu_tx | is_ampdu_pending;
- DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: bf=%p, tid=%d, ac=%d, is_ampdu=%d\n",
- __func__, bf, tid, pri, is_ampdu);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d, ac=%d, is_ampdu=%d\n",
+ __func__, tid, pri, is_ampdu);
/*
* When servicing one or more stations in power-save mode
@@ -1494,34 +1550,33 @@
/* Do the generic frame setup */
/* XXX should just bzero the bf_state? */
bf->bf_state.bfs_dobaw = 0;
- bf->bf_state.bfs_seqno_assigned = 0;
- bf->bf_state.bfs_need_seqno = 0;
- bf->bf_state.bfs_seqno = -1; /* XXX debugging */
+
+ /*
+ * Acquire the TXQ lock early, so both the encap and seqno
+ * are allocated together.
+ */
+ ATH_TXQ_LOCK(txq);
/* A-MPDU TX? Manually set sequence number */
- /* Don't do it whilst pending; the net80211 layer still assigns them */
- /* XXX do we need locking here? */
+ /*
+ * Don't do it whilst pending; the net80211 layer still
+ * assigns them.
+ */
if (is_ampdu_tx) {
- ATH_TXQ_LOCK(txq);
/*
* Always call; this function will
* handle making sure that null data frames
* don't get a sequence number from the current
* TID and thus mess with the BAW.
*/
- //seqno = ath_tx_tid_seqno_assign(sc, ni, bf, m0);
- if (ath_tx_seqno_required(sc, ni, bf, m0)) {
+ seqno = ath_tx_tid_seqno_assign(sc, ni, bf, m0);
+
+ /*
+ * Don't add QoS NULL frames to the BAW.
+ */
+ if (IEEE80211_QOS_HAS_SEQ(wh) &&
+ subtype != IEEE80211_FC0_SUBTYPE_QOS_NULL) {
bf->bf_state.bfs_dobaw = 1;
- bf->bf_state.bfs_need_seqno = 1;
- }
- ATH_TXQ_UNLOCK(txq);
- } else {
- /* No AMPDU TX, we've been assigned a sequence number. */
- if (IEEE80211_QOS_HAS_SEQ(wh)) {
- bf->bf_state.bfs_seqno_assigned = 1;
- /* XXX we should store the frag+seqno in bfs_seqno */
- bf->bf_state.bfs_seqno =
- M_SEQNO_GET(m0) << IEEE80211_SEQ_SEQ_SHIFT;
}
}
@@ -1529,7 +1584,7 @@
* If needed, the sequence number has been assigned.
* Squirrel it away somewhere easy to get to.
*/
- //bf->bf_state.bfs_seqno = M_SEQNO_GET(m0) << IEEE80211_SEQ_SEQ_SHIFT;
+ bf->bf_state.bfs_seqno = M_SEQNO_GET(m0) << IEEE80211_SEQ_SEQ_SHIFT;
/* Is ampdu pending? fetch the seqno and print it out */
if (is_ampdu_pending)
@@ -1541,15 +1596,11 @@
r = ath_tx_normal_setup(sc, ni, bf, m0, txq);
if (r != 0)
- return r;
+ goto done;
/* At this point m0 could have changed! */
m0 = bf->bf_m;
- DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: DONE: bf=%p, tid=%d, ac=%d, is_ampdu=%d, dobaw=%d, seqno=%d\n",
- __func__, bf, tid, pri, is_ampdu, bf->bf_state.bfs_dobaw, M_SEQNO_GET(m0));
-
#if 1
/*
* If it's a multicast frame, do a direct-dispatch to the
@@ -1568,21 +1619,17 @@
* reached.)
*/
if (txq == &avp->av_mcastq) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: bf=%p: mcastq: TX'ing\n", __func__, bf);
- ATH_TXQ_LOCK(txq);
ath_tx_xmit_normal(sc, txq, bf);
- ATH_TXQ_UNLOCK(txq);
} else if (type == IEEE80211_FC0_TYPE_CTL &&
subtype == IEEE80211_FC0_SUBTYPE_BAR) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: BAR: TX'ing direct\n", __func__);
- ATH_TXQ_LOCK(txq);
ath_tx_xmit_normal(sc, txq, bf);
- ATH_TXQ_UNLOCK(txq);
} else {
/* add to software queue */
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: bf=%p: swq: TX'ing\n", __func__, bf);
ath_tx_swq(sc, ni, txq, bf);
}
@@ -1591,10 +1638,10 @@
* For now, since there's no software queue,
* direct-dispatch to the hardware.
*/
- ATH_TXQ_LOCK(txq);
ath_tx_xmit_normal(sc, txq, bf);
+#endif
+done:
ATH_TXQ_UNLOCK(txq);
-#endif
return 0;
}
@@ -1630,10 +1677,29 @@
/* XXX honor IEEE80211_BPF_DATAPAD */
pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN;
-
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: ismcast=%d\n",
__func__, ismcast);
+ pri = params->ibp_pri & 3;
+ /* Override pri if the frame isn't a QoS one */
+ if (! IEEE80211_QOS_HAS_SEQ(wh))
+ pri = ath_tx_getac(sc, m0);
+
+ /* XXX If it's an ADDBA, override the correct queue */
+ do_override = ath_tx_action_frame_override_queue(sc, ni, m0, &o_tid);
+
+ /* Map ADDBA to the correct priority */
+ if (do_override) {
+#if 0
+ device_printf(sc->sc_dev,
+ "%s: overriding tid %d pri %d -> %d\n",
+ __func__, o_tid, pri, TID_TO_WME_AC(o_tid));
+#endif
+ pri = TID_TO_WME_AC(o_tid);
+ }
+
+ ATH_TXQ_LOCK(sc->sc_ac2q[pri]);
+
/* Handle encryption twiddling if needed */
if (! ath_tx_tag_crypto(sc, ni,
m0, params->ibp_flags & IEEE80211_BPF_CRYPTO, 0,
@@ -1688,11 +1754,6 @@
if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA))
bf->bf_state.bfs_ctsrate0 = params->ibp_ctsrate;
- pri = params->ibp_pri & 3;
- /* Override pri if the frame isn't a QoS one */
- if (! IEEE80211_QOS_HAS_SEQ(wh))
- pri = ath_tx_getac(sc, m0);
-
/*
* NB: we mark all packets as type PSPOLL so the h/w won't
* set the sequence number, duration, etc.
@@ -1774,19 +1835,6 @@
/* NB: no buffered multicast in power save support */
- /* XXX If it's an ADDBA, override the correct queue */
- do_override = ath_tx_action_frame_override_queue(sc, ni, m0, &o_tid);
-
- /* Map ADDBA to the correct priority */
- if (do_override) {
-#if 0
- device_printf(sc->sc_dev,
- "%s: overriding tid %d pri %d -> %d\n",
- __func__, o_tid, pri, TID_TO_WME_AC(o_tid));
-#endif
- pri = TID_TO_WME_AC(o_tid);
- }
-
/*
* If we're overiding the ADDBA destination, dump directly
* into the hardware queue, right after any pending
@@ -1796,13 +1844,12 @@
__func__, do_override);
if (do_override) {
- ATH_TXQ_LOCK(sc->sc_ac2q[pri]);
ath_tx_xmit_normal(sc, sc->sc_ac2q[pri], bf);
- ATH_TXQ_UNLOCK(sc->sc_ac2q[pri]);
} else {
/* Queue to software queue */
ath_tx_swq(sc, ni, sc->sc_ac2q[pri], bf);
}
+ ATH_TXQ_UNLOCK(sc->sc_ac2q[pri]);
return 0;
}
@@ -1867,7 +1914,7 @@
/*
* Grab a TX buffer and associated resources.
*/
- bf = ath_getbuf(sc);
+ bf = ath_getbuf(sc, ATH_BUFTYPE_MGMT);
if (bf == NULL) {
sc->sc_stats.ast_tx_nobuf++;
m_freem(m);
@@ -1905,7 +1952,7 @@
return 0;
bad2:
ATH_TXBUF_LOCK(sc);
- TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ ath_returnbuf_head(sc, bf);
ATH_TXBUF_UNLOCK(sc);
bad:
ATH_PCU_LOCK(sc);
@@ -2027,27 +2074,27 @@
struct ieee80211_tx_ampdu *tap;
ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
+ ATH_TID_LOCK_ASSERT(sc, tid);
if (bf->bf_state.bfs_isretried)
return;
- /*
- * If this occurs we're in a lot of trouble. We should try to
- * recover from this without the session hanging?
- */
- if (! bf->bf_state.bfs_seqno_assigned) {
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+
+ if (! bf->bf_state.bfs_dobaw) {
device_printf(sc->sc_dev,
- "%s: bf=%p, seqno_assigned is 0?!\n", __func__, bf);
- return;
+ "%s: dobaw=0, seqno=%d, window %d:%d\n",
+ __func__,
+ SEQNO(bf->bf_state.bfs_seqno),
+ tap->txa_start,
+ tap->txa_wnd);
}
- tap = ath_tx_get_tx_tid(an, tid->tid);
-
if (bf->bf_state.bfs_addedbaw)
device_printf(sc->sc_dev,
- "%s: re-added? bf=%p, tid=%d, seqno %d; window %d:%d; "
+ "%s: re-added? tid=%d, seqno %d; window %d:%d; "
"baw head=%d tail=%d\n",
- __func__, bf, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
+ __func__, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
tap->txa_start, tap->txa_wnd, tid->baw_head,
tid->baw_tail);
@@ -2063,7 +2110,6 @@
__func__, bf, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
tap->txa_start, tap->txa_wnd, tid->baw_head,
tid->baw_tail);
-
}
/*
@@ -2073,9 +2119,9 @@
index = ATH_BA_INDEX(tap->txa_start, SEQNO(bf->bf_state.bfs_seqno));
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: bf=%p, tid=%d, seqno %d; window %d:%d; index=%d cindex=%d "
+ "%s: tid=%d, seqno %d; window %d:%d; index=%d cindex=%d "
"baw head=%d tail=%d\n",
- __func__, bf, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
+ __func__, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
tap->txa_start, tap->txa_wnd, index, cindex, tid->baw_head,
tid->baw_tail);
@@ -2124,6 +2170,7 @@
int seqno = SEQNO(old_bf->bf_state.bfs_seqno);
ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
+ ATH_TID_LOCK_ASSERT(sc, tid);
tap = ath_tx_get_tx_tid(an, tid->tid);
index = ATH_BA_INDEX(tap->txa_start, seqno);
@@ -2172,15 +2219,16 @@
int seqno = SEQNO(bf->bf_state.bfs_seqno);
ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
+ ATH_TID_LOCK_ASSERT(sc, tid);
tap = ath_tx_get_tx_tid(an, tid->tid);
index = ATH_BA_INDEX(tap->txa_start, seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: bf=%p: tid=%d, baw=%d:%d, seqno=%d, index=%d, cindex=%d, "
+ "%s: tid=%d, baw=%d:%d, seqno=%d, index=%d, cindex=%d, "
"baw head=%d, tail=%d\n",
- __func__, bf, tid->tid, tap->txa_start, tap->txa_wnd, seqno, index,
+ __func__, tid->tid, tap->txa_start, tap->txa_wnd, seqno, index,
cindex, tid->baw_head, tid->baw_tail);
/*
@@ -2261,51 +2309,11 @@
}
/*
- * Return whether a sequence number is actually required.
- *
- * A sequence number must only be allocated at the time that a frame
- * is considered for addition to the BAW/aggregate and being TXed.
- * The sequence number must not be allocated before the frame
- * is added to the BAW (protected by the same lock instance)
- * otherwise a the multi-entrant TX path may result in a later seqno
- * being added to the BAW first. The subsequent addition of the
- * earlier seqno would then not go into the BAW as it's now outside
- * of said BAW.
- *
- * This routine is used by ath_tx_start() to mark whether the frame
- * should get a sequence number before adding it to the BAW.
- *
- * Then the actual aggregate TX routines will check whether this
- * flag is set and if the frame needs to go into the BAW, it'll
- * have a sequence number allocated for it.
- */
-static int
-ath_tx_seqno_required(struct ath_softc *sc, struct ieee80211_node *ni,
- struct ath_buf *bf, struct mbuf *m0)
-{
- const struct ieee80211_frame *wh;
- uint8_t subtype;
-
- wh = mtod(m0, const struct ieee80211_frame *);
- subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
-
- /* XXX assert txq lock */
- /* XXX assert ampdu is set */
-
- return ((IEEE80211_QOS_HAS_SEQ(wh) &&
- subtype != IEEE80211_FC0_SUBTYPE_QOS_NULL));
-}
-
-/*
* Assign a sequence number manually to the given frame.
*
* This should only be called for A-MPDU TX frames.
- *
- * If this is called after the initial frame setup, make sure you've flushed
- * the DMA map or you'll risk sending stale data to the NIC. This routine
- * updates the actual frame contents with the relevant seqno.
*/
-int
+static ieee80211_seq
ath_tx_tid_seqno_assign(struct ath_softc *sc, struct ieee80211_node *ni,
struct ath_buf *bf, struct mbuf *m0)
{
@@ -2318,22 +2326,8 @@
wh = mtod(m0, struct ieee80211_frame *);
pri = M_WME_GETAC(m0); /* honor classification */
tid = WME_AC_TO_TID(pri);
- DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: bf=%p, pri=%d, tid=%d, qos has seq=%d\n",
- __func__, bf, pri, tid, IEEE80211_QOS_HAS_SEQ(wh));
-
- if (! bf->bf_state.bfs_need_seqno) {
- device_printf(sc->sc_dev, "%s: bf=%p: need_seqno not set?!\n",
- __func__, bf);
- return -1;
- }
- /* XXX check for bfs_need_seqno? */
- if (bf->bf_state.bfs_seqno_assigned) {
- device_printf(sc->sc_dev,
- "%s: bf=%p: seqno already assigned (%d)?!\n",
- __func__, bf, SEQNO(bf->bf_state.bfs_seqno));
- return bf->bf_state.bfs_seqno >> IEEE80211_SEQ_SEQ_SHIFT;
- }
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: pri=%d, tid=%d, qos has seq=%d\n",
+ __func__, pri, tid, IEEE80211_QOS_HAS_SEQ(wh));
/* XXX Is it a control frame? Ignore */
@@ -2341,6 +2335,8 @@
if (! IEEE80211_QOS_HAS_SEQ(wh))
return -1;
+ ATH_TID_LOCK_ASSERT(sc, &(ATH_NODE(ni)->an_tid[tid]));
+
/*
* Is it a QOS NULL Data frame? Give it a sequence number from
* the default TID (IEEE80211_NONQOS_TID.)
@@ -2352,6 +2348,7 @@
*/
subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL) {
+ /* XXX no locking for this TID? This is a bit of a problem. */
seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID];
INCR(ni->ni_txseqs[IEEE80211_NONQOS_TID], IEEE80211_SEQ_RANGE);
} else {
@@ -2361,14 +2358,9 @@
}
*(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
M_SEQNO_SET(m0, seqno);
- bf->bf_state.bfs_seqno = seqno << IEEE80211_SEQ_SEQ_SHIFT;
- bf->bf_state.bfs_seqno_assigned = 1;
/* Return so caller can do something with it if needed */
- DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: -> seqno=%d\n",
- __func__,
- bf,
- seqno);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: -> seqno=%d\n", __func__, seqno);
return seqno;
}
@@ -2380,98 +2372,27 @@
static void
ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_buf *bf)
{
- struct ieee80211_node *ni = &an->an_node;
struct ath_tid *tid = &an->an_tid[bf->bf_state.bfs_tid];
struct ath_txq *txq = bf->bf_state.bfs_txq;
struct ieee80211_tx_ampdu *tap;
ATH_TXQ_LOCK_ASSERT(txq);
+ ATH_TID_LOCK_ASSERT(sc, tid);
tap = ath_tx_get_tx_tid(an, tid->tid);
/* paused? queue */
if (tid->paused) {
- ATH_TXQ_INSERT_TAIL(tid, bf, bf_list);
+ ATH_TXQ_INSERT_HEAD(tid, bf, bf_list);
/* XXX don't sched - we're paused! */
return;
}
- /*
- * TODO: If it's _before_ the BAW left edge, complain very loudly.
- * This means something (else) has slid the left edge along
- * before we got a chance to be TXed.
- */
-
- /*
- * Is there space in this BAW for another frame?
- * If not, don't bother trying to schedule it; just
- * throw it back on the queue.
- *
- * If we allocate the sequence number before we add
- * it to the BAW, we risk racing with another TX
- * thread that gets in a frame into the BAW with
- * seqno greater than ours. We'd then fail the
- * below check and throw the frame on the tail of
- * the queue. The sender would then have a hole.
- *
- * XXX again, we're protecting ni->ni_txseqs[tid]
- * behind this hardware TXQ lock, like the rest of
- * the TIDs that map to it. Ugh.
- */
- if (bf->bf_state.bfs_dobaw) {
- ieee80211_seq seqno;
-
- /*
- * If the sequence number is allocated, use it.
- * Otherwise, use the sequence number we WOULD
- * allocate.
- */
- if (bf->bf_state.bfs_seqno_assigned)
- seqno = SEQNO(bf->bf_state.bfs_seqno);
- else
- seqno = ni->ni_txseqs[bf->bf_state.bfs_tid];
-
- /*
- * Check whether either the currently allocated
- * sequence number _OR_ the to-be allocated
- * sequence number is inside the BAW.
- */
- if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd, seqno)) {
- ATH_TXQ_INSERT_TAIL(tid, bf, bf_list);
- ath_tx_tid_sched(sc, tid);
- return;
- }
- if (! bf->bf_state.bfs_seqno_assigned) {
- int seqno;
-
- seqno = ath_tx_tid_seqno_assign(sc, ni, bf, bf->bf_m);
- if (seqno < 0) {
- device_printf(sc->sc_dev,
- "%s: bf=%p, huh, seqno=-1?\n",
- __func__,
- bf);
- /* XXX what can we even do here? */
- }
- /* Flush seqno update to RAM */
- /*
- * XXX This is required because the dmasetup
- * XXX is done early rather than at dispatch
- * XXX time. Ew, we should fix this!
- */
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
- BUS_DMASYNC_PREWRITE);
- }
- }
-
/* outside baw? queue */
if (bf->bf_state.bfs_dobaw &&
(! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
SEQNO(bf->bf_state.bfs_seqno)))) {
- device_printf(sc->sc_dev,
- "%s: bf=%p, shouldn't be outside BAW now?!\n",
- __func__,
- bf);
- ATH_TXQ_INSERT_TAIL(tid, bf, bf_list);
+ ATH_TXQ_INSERT_HEAD(tid, bf, bf_list);
ath_tx_tid_sched(sc, tid);
return;
}
@@ -2521,14 +2442,18 @@
int pri, tid;
struct mbuf *m0 = bf->bf_m;
+ ATH_TXQ_LOCK_ASSERT(txq);
+
/* Fetch the TID - non-QoS frames get assigned to TID 16 */
wh = mtod(m0, struct ieee80211_frame *);
pri = ath_tx_getac(sc, m0);
tid = ath_tx_gettid(sc, m0);
atid = &an->an_tid[tid];
- DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p, pri=%d, tid=%d, qos=%d, seqno=%d\n",
- __func__, bf, pri, tid, IEEE80211_QOS_HAS_SEQ(wh), SEQNO(bf->bf_state.bfs_seqno));
+ ATH_TID_LOCK_ASSERT(sc, atid);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p, pri=%d, tid=%d, qos=%d\n",
+ __func__, bf, pri, tid, IEEE80211_QOS_HAS_SEQ(wh));
/* Set local packet state, used to queue packets to hardware */
bf->bf_state.bfs_tid = tid;
@@ -2541,41 +2466,53 @@
* If the TID is paused or the traffic it outside BAW, software
* queue it.
*/
- ATH_TXQ_LOCK(txq);
if (atid->paused) {
/* TID is paused, queue */
- DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: paused\n", __func__, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: paused\n", __func__);
ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
} else if (ath_tx_ampdu_pending(sc, an, tid)) {
/* AMPDU pending; queue */
- DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: pending\n", __func__, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: pending\n", __func__);
ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
/* XXX sched? */
} else if (ath_tx_ampdu_running(sc, an, tid)) {
/* AMPDU running, attempt direct dispatch if possible */
+
+ /*
+ * Always queue the frame to the tail of the list.
+ */
+ ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
+
+ /*
+ * If the hardware queue isn't busy, direct dispatch
+ * the head frame in the list. Don't schedule the
+ * TID - let it build some more frames first?
+ *
+ * Otherwise, schedule the TID.
+ */
if (txq->axq_depth < sc->sc_hwq_limit) {
+ bf = TAILQ_FIRST(&atid->axq_q);
+ ATH_TXQ_REMOVE(atid, bf, bf_list);
+ ath_tx_xmit_aggr(sc, an, bf);
DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: bf=%p: xmit_aggr\n",
- __func__, bf);
- ath_tx_xmit_aggr(sc, an, bf);
+ "%s: xmit_aggr\n",
+ __func__);
} else {
DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: bf=%p: ampdu; swq'ing\n",
- __func__, bf);
- ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
+ "%s: ampdu; swq'ing\n",
+ __func__);
ath_tx_tid_sched(sc, atid);
}
} else if (txq->axq_depth < sc->sc_hwq_limit) {
/* AMPDU not running, attempt direct dispatch */
- DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: xmit_normal\n", __func__, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: xmit_normal\n", __func__);
ath_tx_xmit_normal(sc, txq, bf);
} else {
/* Busy; queue */
- DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: swq'ing\n", __func__, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: swq'ing\n", __func__);
ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
ath_tx_tid_sched(sc, atid);
}
- ATH_TXQ_UNLOCK(txq);
}
/*
@@ -2673,10 +2610,12 @@
{
ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
- DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: tid=%p, called\n",
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: tid=%p, bar_wait=%d, bar_tx=%d, called\n",
__func__,
- tid);
+ tid,
+ tid->bar_wait,
+ tid->bar_tx);
/* We shouldn't be called when bar_tx is 1 */
if (tid->bar_tx) {
@@ -2704,7 +2643,7 @@
{
ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
- DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
"%s: tid=%p, called\n",
__func__,
tid);
@@ -2732,6 +2671,9 @@
if (tid->bar_wait == 0 || tid->hwq_depth > 0)
return (0);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR, "%s: tid=%p (%d), bar ready\n",
+ __func__, tid, tid->tid);
+
return (1);
}
@@ -2754,7 +2696,7 @@
ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
- DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
"%s: tid=%p, called\n",
__func__,
tid);
@@ -2776,7 +2718,7 @@
/* Don't do anything if we still have pending frames */
if (tid->hwq_depth > 0) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
"%s: tid=%p, hwq_depth=%d, waiting\n",
__func__,
tid,
@@ -2793,7 +2735,7 @@
*
* XXX verify this is _actually_ the valid value to begin at!
*/
- DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
"%s: tid=%p, new BAW left edge=%d\n",
__func__,
tid,
@@ -2856,25 +2798,24 @@
if (t == 0) {
device_printf(sc->sc_dev,
"%s: node %p: bf=%p: addbaw=%d, dobaw=%d, "
- "seqno_assign=%d, seqno_required=%d, seqno=%d, retry=%d\n",
+ "seqno=%d, retry=%d\n",
__func__, ni, bf,
bf->bf_state.bfs_addedbaw,
bf->bf_state.bfs_dobaw,
- bf->bf_state.bfs_need_seqno,
- bf->bf_state.bfs_seqno_assigned,
SEQNO(bf->bf_state.bfs_seqno),
bf->bf_state.bfs_retries);
device_printf(sc->sc_dev,
- "%s: node %p: bf=%p: tid txq_depth=%d hwq_depth=%d\n",
+ "%s: node %p: bf=%p: tid txq_depth=%d hwq_depth=%d, bar_wait=%d\n",
__func__, ni, bf,
tid->axq_depth,
- tid->hwq_depth);
+ tid->hwq_depth,
+ tid->bar_wait);
device_printf(sc->sc_dev,
- "%s: node %p: bf=%p: tid %d: txq_depth=%d, "
+ "%s: node %p: tid %d: txq_depth=%d, "
"txq_aggr_depth=%d, sched=%d, paused=%d, "
"hwq_depth=%d, incomp=%d, baw_head=%d, "
"baw_tail=%d txa_start=%d, ni_txseqs=%d\n",
- __func__, ni, bf, tid->tid, txq->axq_depth,
+ __func__, ni, tid->tid, txq->axq_depth,
txq->axq_aggr_depth, tid->sched, tid->paused,
tid->hwq_depth, tid->incomp, tid->baw_head,
tid->baw_tail, tap == NULL ? -1 : tap->txa_start,
@@ -3088,14 +3029,14 @@
* The caller is responsible for pausing the TID.
*/
static void
-ath_tx_cleanup(struct ath_softc *sc, struct ath_node *an, int tid)
+ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid)
{
struct ath_tid *atid = &an->an_tid[tid];
struct ieee80211_tx_ampdu *tap;
struct ath_buf *bf, *bf_next;
ath_bufhead bf_cq;
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
"%s: TID %d: called\n", __func__, tid);
TAILQ_INIT(&bf_cq);
@@ -3232,7 +3173,7 @@
* the list.)
*/
ATH_TXBUF_LOCK(sc);
- TAILQ_INSERT_HEAD(&sc->sc_txbuf, nbf, bf_list);
+ ath_returnbuf_head(sc, nbf);
ATH_TXBUF_UNLOCK(sc);
return NULL;
}
@@ -3455,6 +3396,9 @@
ATH_TXQ_INSERT_HEAD(tid, bf, bf_list);
}
+ /*
+ * Schedule the TID to be re-tried.
+ */
ath_tx_tid_sched(sc, tid);
/*
@@ -3469,12 +3413,9 @@
ath_tx_tid_bar_suspend(sc, tid);
}
- ATH_TXQ_UNLOCK(sc->sc_ac2q[tid->ac]);
-
/*
* Send BAR if required
*/
- ATH_TXQ_LOCK(sc->sc_ac2q[tid->ac]);
if (ath_tx_tid_bar_tx_ready(sc, tid))
ath_tx_tid_bar_tx(sc, tid);
ATH_TXQ_UNLOCK(sc->sc_ac2q[tid->ac]);
@@ -3562,7 +3503,7 @@
int nframes = 0, nbad = 0, nf;
int pktlen;
/* XXX there's too much on the stack? */
- struct ath_rc_series rc[4];
+ struct ath_rc_series rc[ATH_RC_NUM];
int txseq;
DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: called; hwq_depth=%d\n",
@@ -3597,9 +3538,16 @@
pktlen = bf_first->bf_state.bfs_pktlen;
/*
- * handle errors first
+ * Handle errors first!
+ *
+ * Here, handle _any_ error as a "exceeded retries" error.
+ * Later on (when filtered frames are to be specially handled)
+ * it'll have to be expanded.
*/
+#if 0
if (ts.ts_status & HAL_TXERR_XRETRY) {
+#endif
+ if (ts.ts_status != 0) {
ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
ath_tx_comp_aggr_error(sc, bf_first, atid);
return;
@@ -3648,6 +3596,10 @@
"seq_st=%d\n",
__func__, hasba, tx_ok, isaggr, seq_st);
/* XXX TODO: schedule an interface reset */
+#ifdef ATH_DEBUG
+ ath_printtxbuf(sc, bf_first,
+ sc->sc_ac2q[atid->ac]->axq_qnum, 0, 0);
+#endif
}
/*
@@ -3742,24 +3694,28 @@
ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
}
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: txa_start now %d\n", __func__, tap->txa_start);
+
+ ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
+
/* Prepend all frames to the beginning of the queue */
- ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
while ((bf = TAILQ_LAST(&bf_q, ath_bufhead_s)) != NULL) {
TAILQ_REMOVE(&bf_q, bf, bf_list);
ATH_TXQ_INSERT_HEAD(atid, bf, bf_list);
}
+
+ /*
+ * Reschedule to grab some further frames.
+ */
ath_tx_tid_sched(sc, atid);
- ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
-
- DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
- "%s: txa_start now %d\n", __func__, tap->txa_start);
/*
* Send BAR if required
*/
- ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
if (ath_tx_tid_bar_tx_ready(sc, atid))
ath_tx_tid_bar_tx(sc, atid);
+
ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
/* Do deferred completion */
@@ -3835,7 +3791,10 @@
* Don't bother with the retry check if all frames
* are being failed (eg during queue deletion.)
*/
+#if 0
if (fail == 0 && ts->ts_status & HAL_TXERR_XRETRY) {
+#endif
+ if (fail == 0 && ts->ts_status != 0) {
ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: retry_unaggr\n",
__func__);
@@ -4303,9 +4262,17 @@
* it'll be "after" the left edge of the BAW and thus it'll
* fall within it.
*/
- ATH_TXQ_LOCK(sc->sc_ac2q[atid->tid]);
- ath_tx_tid_pause(sc, atid);
- ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->tid]);
+ ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
+ /*
+ * This is a bit annoying. Until net80211 HT code inherits some
+ * (any) locking, we may have this called in parallel BUT only
+ * one response/timeout will be called. Grr.
+ */
+ if (atid->addba_tx_pending == 0) {
+ ath_tx_tid_pause(sc, atid);
+ atid->addba_tx_pending = 1;
+ }
+ ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
"%s: called; dialogtoken=%d, baparamset=%d, batimeout=%d\n",
@@ -4365,6 +4332,7 @@
r = sc->sc_addba_response(ni, tap, status, code, batimeout);
ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
+ atid->addba_tx_pending = 0;
/*
* XXX dirty!
* Slide the BAW left edge to wherever net80211 left it for us.
@@ -4379,6 +4347,9 @@
/*
* Stop ADDBA on a queue.
+ *
+ * This can be called whilst BAR TX is currently active on the queue,
+ * so make sure this is unblocked before continuing.
*/
void
ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
@@ -4390,20 +4361,32 @@
DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: called\n", __func__);
- /* Pause TID traffic early, so there aren't any races */
- ATH_TXQ_LOCK(sc->sc_ac2q[atid->tid]);
+ /*
+ * Pause TID traffic early, so there aren't any races
+ * Unblock the pending BAR held traffic, if it's currently paused.
+ */
+ ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
ath_tx_tid_pause(sc, atid);
- ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->tid]);
+ if (atid->bar_wait) {
+ /*
+ * bar_unsuspend() expects bar_tx == 1, as it should be
+ * called from the TX completion path. This quietens
+ * the warning. It's cleared for us anyway.
+ */
+ atid->bar_tx = 1;
+ ath_tx_tid_bar_unsuspend(sc, atid);
+ }
+ ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
/* There's no need to hold the TXQ lock here */
sc->sc_addba_stop(ni, tap);
/*
- * ath_tx_cleanup will resume the TID if possible, otherwise
+ * ath_tx_tid_cleanup will resume the TID if possible, otherwise
* it'll set the cleanup flag, and it'll be unpaused once
* things have been cleaned up.
*/
- ath_tx_cleanup(sc, an, tid);
+ ath_tx_tid_cleanup(sc, an, tid);
}
/*
@@ -4426,8 +4409,15 @@
struct ath_tid *atid = &an->an_tid[tid];
int attempts = tap->txa_attempts;
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
- "%s: called; status=%d\n", __func__, status);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: called; tap=%p, atid=%p, txa_tid=%d, atid->tid=%d, status=%d, attempts=%d\n",
+ __func__,
+ tap,
+ atid,
+ tap->txa_tid,
+ atid->tid,
+ status,
+ attempts);
/* Note: This may update the BAW details */
sc->sc_bar_response(ni, tap, status);
@@ -4461,6 +4451,10 @@
DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
"%s: called; resuming\n", __func__);
+ ATH_TXQ_LOCK(sc->sc_ac2q[atid->ac]);
+ atid->addba_tx_pending = 0;
+ ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
+
/* Note: This updates the aggregate state to (again) pending */
sc->sc_addba_response_timeout(ni, tap);
@@ -4469,3 +4463,34 @@
ath_tx_tid_resume(sc, atid);
ATH_TXQ_UNLOCK(sc->sc_ac2q[atid->ac]);
}
+
+static int
+ath_legacy_dma_txsetup(struct ath_softc *sc)
+{
+
+ /* nothing new needed */
+ return (0);
+}
+
+static int
+ath_legacy_dma_txteardown(struct ath_softc *sc)
+{
+
+ /* nothing new needed */
+ return (0);
+}
+
+void
+ath_xmit_setup_legacy(struct ath_softc *sc)
+{
+ /*
+ * For now, just set the descriptor length to sizeof(ath_desc);
+ * worry about extracting the real length out of the HAL later.
+ */
+ sc->sc_tx_desclen = sizeof(struct ath_desc);
+ sc->sc_tx_statuslen = 0;
+ sc->sc_tx_nmaps = 1; /* only one buffer per TX desc */
+
+ sc->sc_tx.xmit_setup = ath_legacy_dma_txsetup;
+ sc->sc_tx.xmit_teardown = ath_legacy_dma_txteardown;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tx.h
--- a/head/sys/dev/ath/if_ath_tx.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_tx.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_ath_tx.h 233227 2012-03-20 04:50:25Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_ath_tx.h 238710 2012-07-23 03:52:18Z adrian $
*/
#ifndef __IF_ATH_TX_H__
#define __IF_ATH_TX_H__
@@ -109,8 +109,6 @@
struct ath_tid *tid, struct ath_buf *bf);
extern struct ieee80211_tx_ampdu * ath_tx_get_tx_tid(struct ath_node *an,
int tid);
-extern int ath_tx_tid_seqno_assign(struct ath_softc *sc,
- struct ieee80211_node *ni, struct ath_buf *bf, struct mbuf *m0);
/* TX addba handling */
extern int ath_addba_request(struct ieee80211_node *ni,
@@ -126,4 +124,13 @@
extern void ath_addba_response_timeout(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap);
+/*
+ * Setup path
+ */
+#define ath_txdma_setup(_sc) \
+ (_sc)->sc_tx.xmit_setup(_sc)
+#define ath_txdma_teardown(_sc) \
+ (_sc)->sc_tx.xmit_teardown(_sc)
+extern void ath_xmit_setup_legacy(struct ath_softc *sc);
+
#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tx_edma.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_tx_edma.c Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2012 Adrian Chadd <adrian at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_edma.c 238710 2012-07-23 03:52:18Z adrian $");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h> /* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_hal/ah_devid.h> /* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#include <dev/ath/if_ath_tsf.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_sysctl.h>
+#include <dev/ath/if_ath_led.h>
+#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_beacon.h>
+#include <dev/ath/if_athdfs.h>
+
+#ifdef ATH_TX99_DIAG
+#include <dev/ath/ath_tx99/ath_tx99.h>
+#endif
+
+#include <dev/ath/if_ath_tx_edma.h>
+
+/*
+ * some general macros
+ */
+#define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1)
+#define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1)
+
+MALLOC_DECLARE(M_ATHDEV);
+
+static int
+ath_edma_dma_txsetup(struct ath_softc *sc)
+{
+
+ /* XXX placeholder */
+ return (0);
+}
+
+static int
+ath_edma_dma_txteardown(struct ath_softc *sc)
+{
+
+ /* XXX placeholder */
+ return (0);
+}
+
+void
+ath_xmit_setup_edma(struct ath_softc *sc)
+{
+
+ /* Fetch EDMA field and buffer sizes */
+ (void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen);
+ (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen);
+ (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps);
+
+ device_printf(sc->sc_dev, "TX descriptor length: %d\n",
+ sc->sc_tx_desclen);
+ device_printf(sc->sc_dev, "TX status length: %d\n",
+ sc->sc_tx_statuslen);
+ device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n",
+ sc->sc_tx_nmaps);
+
+ sc->sc_tx.xmit_setup = ath_edma_dma_txsetup;
+ sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown;
+}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tx_edma.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/dev/ath/if_ath_tx_edma.h Wed Jul 25 17:07:47 2012 +0300
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2012 Adrian Chadd <adrian at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: head/sys/dev/ath/if_ath_tx_edma.h 238710 2012-07-23 03:52:18Z adrian $
+ */
+#ifndef __IF_ATH_TX_EDMA_H__
+#define __IF_ATH_TX_EDMA_H__
+
+extern void ath_xmit_setup_edma(struct ath_softc *sc);
+
+#endif
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_ath_tx_ht.c
--- a/head/sys/dev/ath/if_ath_tx_ht.c Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_ath_tx_ht.c Wed Jul 25 17:07:47 2012 +0300
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_ht.c 233988 2012-04-07 05:46:00Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_ht.c 238711 2012-07-23 03:55:19Z adrian $");
#include "opt_inet.h"
#include "opt_ath.h"
@@ -96,9 +96,10 @@
*/
#define IEEE80211_AMPDU_SUBFRAME_DEFAULT 32
-#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
+#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
-#define ATH_AGGR_ENCRYPTDELIM 10 /* number of delimiters for encryption padding */
+/* number of delimiters for encryption padding */
+#define ATH_AGGR_ENCRYPTDELIM 10
/*
* returns delimiter padding required given the packet length
@@ -414,7 +415,7 @@
int amin = 65530;
int i;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ATH_RC_NUM; i++) {
if (bf->bf_state.bfs_rc[i].tries == 0)
continue;
amin = MIN(amin, bf->bf_state.bfs_rc[i].max4msframelen);
@@ -438,7 +439,6 @@
ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
struct ath_buf *bf, HAL_11N_RATE_SERIES *series)
{
-#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
struct ieee80211com *ic = ni->ni_ic;
struct ath_hal *ah = sc->sc_ah;
HAL_BOOL shortPreamble = AH_FALSE;
@@ -466,7 +466,7 @@
* XXX fields.
*/
memset(series, 0, sizeof(HAL_11N_RATE_SERIES) * 4);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ATH_RC_NUM; i++) {
/* Only set flags for actual TX attempts */
if (rc[i].tries == 0)
continue;
@@ -512,7 +512,10 @@
series[i].Rate = rt->info[rc[i].rix].rateCode;
- /* PktDuration doesn't include slot, ACK, RTS, etc timing - it's just the packet duration */
+ /*
+ * PktDuration doesn't include slot, ACK, RTS, etc timing -
+ * it's just the packet duration
+ */
if (series[i].Rate & IEEE80211_RATE_MCS) {
series[i].PktDuration =
ath_computedur_ht(pktlen
@@ -528,16 +531,16 @@
rt, pktlen, rc[i].rix, shortPreamble);
}
}
-#undef HT_RC_2_STREAMS
}
#if 0
static void
-ath_rateseries_print(HAL_11N_RATE_SERIES *series)
+ath_rateseries_print(struct ath_softc *sc, HAL_11N_RATE_SERIES *series)
{
int i;
- for (i = 0; i < 4; i++) {
- printf("series %d: rate %x; tries %d; pktDuration %d; chSel %d; rateFlags %x\n",
+ for (i = 0; i < ATH_RC_NUM; i++) {
+ device_printf(sc->sc_dev ,"series %d: rate %x; tries %d; "
+ "pktDuration %d; chSel %d; rateFlags %x\n",
i,
series[i].Rate,
series[i].Tries,
@@ -582,19 +585,34 @@
#if 0
printf("pktlen: %d; flags 0x%x\n", pktlen, flags);
- ath_rateseries_print(series);
+ ath_rateseries_print(sc, series);
#endif
/* Set rate scenario */
+ /*
+ * Note: Don't allow hardware to override the duration on
+ * ps-poll packets.
+ */
ath_hal_set11nratescenario(ah, ds,
!is_pspoll, /* whether to override the duration or not */
- /* don't allow hardware to override the duration on ps-poll packets */
ctsrate, /* rts/cts rate */
series, /* 11n rate series */
4, /* number of series */
flags);
/* Setup the last descriptor in the chain */
+ /*
+ * XXX Why is this done here, and not in the upper layer?
+ * The rate control code stores a copy of the RC info in
+ * the last descriptor as well as the first, then uses
+ * the shadow copy in the last descriptor to see what the RC
+ * decisions were. I'm not sure why; perhaps earlier hardware
+ * overwrote the first descriptor contents.
+ *
+ * In the 802.11n case, it also clears the moreaggr/delim
+ * fields. Again, this should be done by the caller of
+ * ath_buf_set_rate().
+ */
ath_hal_setuplasttxdesc(ah, lastds, ds);
/* Set burst duration */
@@ -630,8 +648,9 @@
* descriptor setup, and ath_buf_set_rate() will configure the
* rate control.
*
- * Note that the TID lock is only grabbed when dequeuing packets from
- * the TID queue. If some code in another thread adds to the head of this
+ * The TID lock is required for the entirety of this function.
+ *
+ * If some code in another thread adds to the head of this
* list, very strange behaviour will occur. Since retransmission is the
* only reason this will occur, and this routine is designed to be called
* from within the scheduler task, it won't ever clash with the completion
@@ -641,10 +660,10 @@
* dispatch aggregate frames to the hardware), please keep this in mind.
*/
ATH_AGGR_STATUS
-ath_tx_form_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_tid *tid,
- ath_bufhead *bf_q)
+ath_tx_form_aggr(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, ath_bufhead *bf_q)
{
- struct ieee80211_node *ni = &an->an_node;
+ //struct ieee80211_node *ni = &an->an_node;
struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
int nframes = 0;
uint16_t aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw;
@@ -751,74 +770,11 @@
(HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA);
/*
- * TODO: If it's _before_ the BAW left edge, complain very
- * loudly.
- *
- * This means something (else) has slid the left edge along
- * before we got a chance to be TXed.
- */
-
- /*
- * Check if we have space in the BAW for this frame before
- * we add it.
- *
- * see ath_tx_xmit_aggr() for more info.
- */
- if (bf->bf_state.bfs_dobaw) {
- ieee80211_seq seqno;
-
- /*
- * If the sequence number is allocated, use it.
- * Otherwise, use the sequence number we WOULD
- * allocate.
- */
- if (bf->bf_state.bfs_seqno_assigned)
- seqno = SEQNO(bf->bf_state.bfs_seqno);
- else
- seqno = ni->ni_txseqs[bf->bf_state.bfs_tid];
-
- /*
- * Check whether either the currently allocated
- * sequence number _OR_ the to-be allocated
- * sequence number is inside the BAW.
- */
- if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
- seqno)) {
- status = ATH_AGGR_BAW_CLOSED;
- break;
- }
-
- /* XXX check for bfs_need_seqno? */
- if (! bf->bf_state.bfs_seqno_assigned) {
- int seqno;
- seqno = ath_tx_tid_seqno_assign(sc, ni, bf, bf->bf_m);
- if (seqno < 0) {
- device_printf(sc->sc_dev,
- "%s: bf=%p, huh, seqno=-1?\n",
- __func__,
- bf);
- /* XXX what can we even do here? */
- }
- /* Flush seqno update to RAM */
- /*
- * XXX This is required because the dmasetup
- * XXX is done early rather than at dispatch
- * XXX time. Ew, we should fix this!
- */
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
- BUS_DMASYNC_PREWRITE);
- }
- }
-
- /*
* If the packet has a sequence number, do not
* step outside of the block-ack window.
*/
if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
SEQNO(bf->bf_state.bfs_seqno))) {
- device_printf(sc->sc_dev,
- "%s: bf=%p, seqno=%d, outside?!\n",
- __func__, bf, SEQNO(bf->bf_state.bfs_seqno));
status = ATH_AGGR_BAW_CLOSED;
break;
}
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_athdfs.h
--- a/head/sys/dev/ath/if_athdfs.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_athdfs.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_athdfs.h 230658 2012-01-28 21:44:42Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_athdfs.h 237526 2012-06-24 08:09:06Z adrian $
*/
#ifndef __IF_ATHDFS_H__
#define __IF_ATHDFS_H__
@@ -35,7 +35,7 @@
extern int ath_dfs_detach(struct ath_softc *sc);
extern int ath_dfs_radar_enable(struct ath_softc *,
struct ieee80211_channel *chan);
-extern void ath_dfs_process_phy_err(struct ath_softc *sc, const char *buf,
+extern void ath_dfs_process_phy_err(struct ath_softc *sc, struct mbuf *m,
uint64_t tsf, struct ath_rx_status *rxstat);
extern int ath_dfs_process_radar_event(struct ath_softc *sc,
struct ieee80211_channel *chan);
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_athioctl.h
--- a/head/sys/dev/ath/if_athioctl.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_athioctl.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_athioctl.h 234090 2012-04-10 07:23:37Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_athioctl.h 238638 2012-07-20 02:17:48Z adrian $
*/
/*
@@ -161,11 +161,14 @@
u_int32_t ast_tx_aggr_ok; /* aggregate TX ok */
u_int32_t ast_tx_aggr_fail; /* aggregate TX failed */
u_int32_t ast_tx_mcastq_overflow; /* multicast queue overflow */
- u_int32_t ast_pad[1];
+ u_int32_t ast_rx_keymiss;
+
+ u_int32_t ast_pad[16];
};
#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)
#define SIOCZATHSTATS _IOWR('i', 139, struct ifreq)
+#define SIOCGATHAGSTATS _IOWR('i', 141, struct ifreq)
struct ath_diag {
char ad_name[IFNAMSIZ]; /* if name, e.g. "ath0" */
@@ -183,10 +186,56 @@
#define SIOCGATHDIAG _IOWR('i', 138, struct ath_diag)
#define SIOCGATHPHYERR _IOWR('i', 140, struct ath_diag)
+
+/*
+ * The rate control ioctl has to support multiple potential rate
+ * control classes. For now, instead of trying to support an
+ * abstraction for this in the API, let's just use a TLV
+ * representation for the payload and let userspace sort it out.
+ */
+struct ath_rateioctl_tlv {
+ uint16_t tlv_id;
+ uint16_t tlv_len; /* length excluding TLV header */
+};
+
+/*
+ * This is purely the six byte MAC address.
+ */
+#define ATH_RATE_TLV_MACADDR 0xaab0
+
+/*
+ * The rate control modules may decide to push a mapping table
+ * of rix -> net80211 ratecode as part of the update.
+ */
+#define ATH_RATE_TLV_RATETABLE_NENTRIES 64
+struct ath_rateioctl_rt {
+ uint16_t nentries;
+ uint16_t pad[1];
+ uint8_t ratecode[ATH_RATE_TLV_RATETABLE_NENTRIES];
+};
+#define ATH_RATE_TLV_RATETABLE 0xaab1
+
+/*
+ * This is the sample node statistics structure.
+ * More in ath_rate/sample/sample.h.
+ */
+#define ATH_RATE_TLV_SAMPLENODE 0xaab2
+
+struct ath_rateioctl {
+ char if_name[IFNAMSIZ]; /* if name */
+ union {
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
+ uint64_t pad;
+ } is_u;
+ uint32_t len;
+ caddr_t buf;
+};
+#define SIOCGATHNODERATESTATS _IOWR('i', 149, struct ath_rateioctl)
+
/*
* Radio capture format.
*/
-#define ATH_RX_RADIOTAP_PRESENT ( \
+#define ATH_RX_RADIOTAP_PRESENT_BASE ( \
(1 << IEEE80211_RADIOTAP_TSFT) | \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
@@ -196,8 +245,80 @@
(1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+#define ATH_RX_RADIOTAP_PRESENT \
+ (ATH_RX_RADIOTAP_PRESENT_BASE | \
+ (1 << IEEE80211_RADIOTAP_VENDOREXT) | \
+ (1 << IEEE80211_RADIOTAP_EXT) | \
+ 0)
+#else
+#define ATH_RX_RADIOTAP_PRESENT ATH_RX_RADIOTAP_PRESENT_BASE
+#endif /* ATH_ENABLE_RADIOTAP_PRESENT */
+
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+/*
+ * This is higher than the vendor bitmap used inside
+ * the Atheros reference codebase.
+ */
+
+/* Bit 8 */
+#define ATH_RADIOTAP_VENDOR_HEADER 8
+
+/*
+ * Using four chains makes all the fields in the
+ * per-chain info header be 4-byte aligned.
+ */
+#define ATH_RADIOTAP_MAX_CHAINS 4
+
+/*
+ * The vendor radiotap header data needs to be:
+ *
+ * + Aligned to a 4 byte address
+ * + .. so all internal fields are 4 bytes aligned;
+ * + .. and no 64 bit fields are allowed.
+ *
+ * So padding is required to ensure this is the case.
+ *
+ * Note that because of the lack of alignment with the
+ * vendor header (6 bytes), the first field must be
+ * two bytes so it can be accessed by alignment-strict
+ * platform (eg MIPS.)
+ */
+struct ath_radiotap_vendor_hdr { /* 30 bytes */
+ uint8_t vh_version; /* 1 */
+ uint8_t vh_rx_chainmask; /* 1 */
+
+ /* At this point it should be 4 byte aligned */
+ uint32_t evm[ATH_RADIOTAP_MAX_CHAINS]; /* 4 * 4 = 16 */
+
+ uint8_t rssi_ctl[ATH_RADIOTAP_MAX_CHAINS]; /* 4 */
+ uint8_t rssi_ext[ATH_RADIOTAP_MAX_CHAINS]; /* 4 */
+
+ uint8_t vh_phyerr_code; /* Phy error code, or 0xff */
+ uint8_t vh_rs_status; /* RX status */
+ uint8_t vh_rssi; /* Raw RSSI */
+ uint8_t vh_pad1[1]; /* Pad to 4 byte boundary */
+} __packed;
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
+
struct ath_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
+
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+ /* Vendor extension header bitmap */
+ uint32_t wr_ext_bitmap; /* 4 */
+
+ /*
+ * This padding is needed because:
+ * + the radiotap header is 8 bytes;
+ * + the extension bitmap is 4 bytes;
+ * + the tsf is 8 bytes, so it must start on an 8 byte
+ * boundary.
+ */
+ uint32_t wr_pad1;
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
+
+ /* Normal radiotap fields */
u_int64_t wr_tsf;
u_int8_t wr_flags;
u_int8_t wr_rate;
@@ -209,6 +330,26 @@
u_int16_t wr_chan_freq;
u_int8_t wr_chan_ieee;
int8_t wr_chan_maxpow;
+
+#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
+ /*
+ * Vendor header section, as required by the
+ * presence of the vendor extension bit and bitmap
+ * entry.
+ *
+ * XXX This must be aligned to a 4 byte address?
+ * XXX or 8 byte address?
+ */
+ struct ieee80211_radiotap_vendor_header wr_vh; /* 6 bytes */
+
+ /*
+ * Because of the lack of alignment enforced by the above
+ * header, this vendor section won't be aligned in any
+ * useful way. So, this will include a two-byte version
+ * value which will force the structure to be 4-byte aligned.
+ */
+ struct ath_radiotap_vendor_hdr wr_v;
+#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
} __packed;
#define ATH_TX_RADIOTAP_PRESENT ( \
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_athrate.h
--- a/head/sys/dev/ath/if_athrate.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_athrate.h Wed Jul 25 17:07:47 2012 +0300
@@ -27,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_athrate.h 227364 2011-11-08 22:43:13Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_athrate.h 238632 2012-07-20 01:27:20Z adrian $
*/
#ifndef _ATH_RATECTRL_H_
#define _ATH_RATECTRL_H_
@@ -150,4 +150,16 @@
void ath_rate_tx_complete(struct ath_softc *, struct ath_node *,
const struct ath_rc_series *, const struct ath_tx_status *,
int pktlen, int nframes, int nbad);
+
+/*
+ * Fetch the global rate control statistics.
+ */
+int ath_rate_fetch_stats(struct ath_softc *sc, struct ath_rateioctl *rs);
+
+/*
+ * Fetch the per-node statistics.
+ */
+int ath_rate_fetch_node_stats(struct ath_softc *sc, struct ath_node *an,
+ struct ath_rateioctl *rs);
+
#endif /* _ATH_RATECTRL_H_ */
diff -r 8a9451a986e0 -r 8f13631d24de head/sys/dev/ath/if_athvar.h
--- a/head/sys/dev/ath/if_athvar.h Wed Jul 25 17:04:43 2012 +0300
+++ b/head/sys/dev/ath/if_athvar.h Wed Jul 25 17:07:47 2012 +0300
@@ -26,7 +26,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: head/sys/dev/ath/if_athvar.h 234369 2012-04-17 06:02:41Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_athvar.h 238731 2012-07-24 01:18:19Z adrian $
*/
/*
@@ -44,10 +44,18 @@
#define ATH_TIMEOUT 1000
/*
+ * There is a separate TX ath_buf pool for management frames.
+ * This ensures that management frames such as probe responses
+ * and BAR frames can be transmitted during periods of high
+ * TX activity.
+ */
+#define ATH_MGMT_TXBUF 32
+
+/*
* 802.11n requires more TX and RX buffers to do AMPDU.
*/
#ifdef ATH_ENABLE_11N
-#define ATH_TXBUF 128
+#define ATH_TXBUF 512
#define ATH_RXBUF 512
#endif
@@ -106,6 +114,7 @@
TAILQ_ENTRY(ath_tid) axq_qelem;
int sched;
int paused; /* >0 if the TID has been paused */
+ int addba_tx_pending; /* TX ADDBA pending */
int bar_wait; /* waiting for BAR */
int bar_tx; /* BAR TXed */
@@ -171,10 +180,16 @@
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
#define ATH_RSSI(x) ATH_EP_RND(x, HAL_RSSI_EP_MULTIPLIER)
+typedef enum {
+ ATH_BUFTYPE_NORMAL = 0,
+ ATH_BUFTYPE_MGMT = 1,
+} ath_buf_type_t;
+
struct ath_buf {
TAILQ_ENTRY(ath_buf) bf_list;
struct ath_buf * bf_next; /* next buffer in the aggregate */
int bf_nseg;
+ HAL_STATUS bf_rxstatus;
uint16_t bf_flags; /* status flags (below) */
struct ath_desc *bf_desc; /* virtual addr of desc */
struct ath_desc_status bf_status; /* tx/rx status */
@@ -197,14 +212,15 @@
/* This state is kept to support software retries and aggregation */
struct {
- int bfs_seqno; /* sequence number of this packet */
- int bfs_retries; /* retry count */
- uint16_t bfs_tid; /* packet TID (or TID_MAX for no QoS) */
- uint16_t bfs_pri; /* packet AC priority */
+ uint16_t bfs_seqno; /* sequence number of this packet */
+ uint16_t bfs_ndelim; /* number of delims for padding */
+
+ uint8_t bfs_retries; /* retry count */
+ uint8_t bfs_tid; /* packet TID (or TID_MAX for no QoS) */
+ uint8_t bfs_nframes; /* number of frames in aggregate */
+ uint8_t bfs_pri; /* packet AC priority */
+
struct ath_txq *bfs_txq; /* eventual dest hardware TXQ */
- uint16_t bfs_pktdur; /* packet duration (at current rate?) */
- uint16_t bfs_nframes; /* number of frames in aggregate */
- uint16_t bfs_ndelim; /* number of delims for padding */
u_int32_t bfs_aggr:1, /* part of aggregate? */
bfs_aggrburst:1, /* part of aggregate burst? */
@@ -215,36 +231,44 @@
bfs_istxfrag:1, /* is fragmented */
bfs_ismrr:1, /* do multi-rate TX retry */
bfs_doprot:1, /* do RTS/CTS based protection */
- bfs_doratelookup:1, /* do rate lookup before each TX */
- bfs_need_seqno:1, /* need to assign a seqno for aggr */
- bfs_seqno_assigned:1; /* seqno has been assigned */
-
- int bfs_nfl; /* next fragment length */
+ bfs_doratelookup:1; /* do rate lookup before each TX */
/*
* These fields are passed into the
* descriptor setup functions.
*/
+
+ /* Make this an 8 bit value? */
HAL_PKT_TYPE bfs_atype; /* packet type */
- int bfs_pktlen; /* length of this packet */
- int bfs_hdrlen; /* length of this packet header */
+
+ uint32_t bfs_pktlen; /* length of this packet */
+
+ uint16_t bfs_hdrlen; /* length of this packet header */
uint16_t bfs_al; /* length of aggregate */
- int bfs_txflags; /* HAL (tx) descriptor flags */
- int bfs_txrate0; /* first TX rate */
- int bfs_try0; /* first try count */
+
+ uint16_t bfs_txflags; /* HAL (tx) descriptor flags */
+ uint8_t bfs_txrate0; /* first TX rate */
+ uint8_t bfs_try0; /* first try count */
+
+ uint16_t bfs_txpower; /* tx power */
uint8_t bfs_ctsrate0; /* Non-zero - use this as ctsrate */
- int bfs_keyix; /* crypto key index */
- int bfs_txpower; /* tx power */
- int bfs_txantenna; /* TX antenna config */
+ uint8_t bfs_ctsrate; /* CTS rate */
+
+ /* 16 bit? */
+ int32_t bfs_keyix; /* crypto key index */
+ int32_t bfs_txantenna; /* TX antenna config */
+
+ /* Make this an 8 bit value? */
enum ieee80211_protmode bfs_protmode;
- HAL_11N_RATE_SERIES bfs_rc11n[ATH_RC_NUM]; /* 11n TX series */
- int bfs_ctsrate; /* CTS rate */
- int bfs_ctsduration; /* CTS duration (pre-11n NICs) */
+
+ /* 16 bit? */
+ uint32_t bfs_ctsduration; /* CTS duration (pre-11n NICs) */
struct ath_rc_series bfs_rc[ATH_RC_NUM]; /* non-11n TX series */
} bf_state;
};
typedef TAILQ_HEAD(ath_bufhead_s, ath_buf) ath_bufhead;
+#define ATH_BUF_MGMT 0x00000001 /* (tx) desc is a mgmt desc */
#define ATH_BUF_BUSY 0x00000002 /* (tx) desc owned by h/w */
/*
@@ -253,6 +277,7 @@
struct ath_descdma {
const char* dd_name;
struct ath_desc *dd_desc; /* descriptors */
+ int dd_descsize; /* size of single descriptor */
bus_addr_t dd_desc_paddr; /* physical addr of dd_desc */
bus_size_t dd_desc_len; /* size of dd_desc */
bus_dma_segment_t dd_dseg;
@@ -304,6 +329,9 @@
#define ATH_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, MA_OWNED)
#define ATH_TXQ_IS_LOCKED(_tq) mtx_owned(&(_tq)->axq_lock)
+#define ATH_TID_LOCK_ASSERT(_sc, _tid) \
+ ATH_TXQ_LOCK_ASSERT((_sc)->sc_ac2q[(_tid)->ac])
+
#define ATH_TXQ_INSERT_HEAD(_tq, _elm, _field) do { \
TAILQ_INSERT_HEAD(&(_tq)->axq_q, (_elm), _field); \
(_tq)->axq_depth++; \
@@ -346,12 +374,40 @@
ATH_RESET_FULL = 2,
} ATH_RESET_TYPE;
+struct ath_rx_methods {
+ void (*recv_stop)(struct ath_softc *sc, int dodelay);
+ int (*recv_start)(struct ath_softc *sc);
+ void (*recv_flush)(struct ath_softc *sc);
+ void (*recv_tasklet)(void *arg, int npending);
+ int (*recv_rxbuf_init)(struct ath_softc *sc,
+ struct ath_buf *bf);
+ int (*recv_setup)(struct ath_softc *sc);
+ int (*recv_teardown)(struct ath_softc *sc);
+};
+
+/*
+ * Represent the current state of the RX FIFO.
+ */
+struct ath_rx_edma {
+ struct ath_buf **m_fifo;
+ int m_fifolen;
+ int m_fifo_head;
+ int m_fifo_tail;
+ int m_fifo_depth;
+ struct mbuf *m_rxpending;
+};
+
+struct ath_tx_methods {
+ int (*xmit_setup)(struct ath_softc *sc);
+ int (*xmit_teardown)(struct ath_softc *sc);
+};
+
struct ath_softc {
struct ifnet *sc_ifp; /* interface common */
struct ath_stats sc_stats; /* interface statistics */
struct ath_tx_aggr_stats sc_aggr_stats;
struct ath_intr_stats sc_intr_stats;
- int sc_debug;
+ uint64_t sc_debug;
int sc_nvaps; /* # vaps */
int sc_nstavaps; /* # station vaps */
int sc_nmeshvaps; /* # mbss vaps */
@@ -359,6 +415,16 @@
u_int8_t sc_nbssid0; /* # vap's using base mac */
uint32_t sc_bssidmask; /* bssid mask */
+ struct ath_rx_methods sc_rx;
+ struct ath_rx_edma sc_rxedma[HAL_NUM_RX_QUEUES]; /* HP/LP queues */
+ struct ath_tx_methods sc_tx;
+
+ int sc_rx_statuslen;
+ int sc_tx_desclen;
+ int sc_tx_statuslen;
+ int sc_tx_nmaps; /* Number of TX maps */
+ int sc_edma_bufsize;
+
void (*sc_node_cleanup)(struct ieee80211_node *);
void (*sc_node_free)(struct ieee80211_node *);
device_t sc_dev;
@@ -368,6 +434,8 @@
struct mtx sc_mtx; /* master lock (recursive) */
struct mtx sc_pcu_mtx; /* PCU access mutex */
char sc_pcu_mtx_name[32];
+ struct mtx sc_rx_mtx; /* RX access mutex */
+ char sc_rx_mtx_name[32];
struct taskqueue *sc_tq; /* private task queue */
struct ath_hal *sc_ah; /* Atheros HAL */
struct ath_ratectrl *sc_rc; /* tx rate control support */
@@ -402,7 +470,8 @@
sc_setcca : 1,/* set/clr CCA with TDMA */
sc_resetcal : 1,/* reset cal state next trip */
sc_rxslink : 1,/* do self-linked final descriptor */
- sc_rxtsf32 : 1;/* RX dec TSF is 32 bits */
+ sc_rxtsf32 : 1,/* RX dec TSF is 32 bits */
+ sc_isedma : 1;/* supports EDMA */
uint32_t sc_eerd; /* regdomain from EEPROM */
uint32_t sc_eecc; /* country code from EEPROM */
/* rate tables */
@@ -473,7 +542,6 @@
struct ath_descdma sc_rxdma; /* RX descriptors */
ath_bufhead sc_rxbuf; /* receive buffer */
- struct mbuf *sc_rxpending; /* pending receive data */
u_int32_t *sc_rxlink; /* link ptr in last RX desc */
struct task sc_rxtask; /* rx int processing */
u_int8_t sc_defant; /* current default antenna */
@@ -486,6 +554,9 @@
struct ath_descdma sc_txdma; /* TX descriptors */
ath_bufhead sc_txbuf; /* transmit buffer */
+ int sc_txbuf_cnt; /* how many buffers avail */
+ struct ath_descdma sc_txdma_mgmt; /* mgmt TX descriptors */
+ ath_bufhead sc_txbuf_mgmt; /* mgmt transmit buffer */
struct mtx sc_txbuflock; /* txbuf lock */
char sc_txname[12]; /* e.g. "ath0_buf" */
u_int sc_txqsetup; /* h/w queues setup */
@@ -494,6 +565,11 @@
struct ath_txq *sc_ac2q[5]; /* WME AC -> h/w q map */
struct task sc_txtask; /* tx int processing */
struct task sc_txqtask; /* tx proc processing */
+
+ struct ath_descdma sc_txcompdma; /* TX EDMA completion */
+ struct mtx sc_txcomplock; /* TX EDMA completion lock */
+ char sc_txcompname[12]; /* eg ath0_txcomp */
+
int sc_wd_timer; /* count down for wd timer */
struct callout sc_wd_ch; /* tx watchdog timer */
struct ath_tx_radiotap_header sc_tx_th;
@@ -636,6 +712,28 @@
#define ATH_PCU_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_pcu_mtx, \
MA_NOTOWNED)
+/*
+ * The RX lock is primarily a(nother) workaround to ensure that the
+ * RX FIFO/list isn't modified by various execution paths.
+ * Even though RX occurs in a single context (the ath taskqueue), the
+ * RX path can be executed via various reset/channel change paths.
+ */
+#define ATH_RX_LOCK_INIT(_sc) do {\
+ snprintf((_sc)->sc_rx_mtx_name, \
+ sizeof((_sc)->sc_rx_mtx_name), \
+ "%s RX lock", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_rx_mtx, (_sc)->sc_rx_mtx_name, \
+ NULL, MTX_DEF); \
+ } while (0)
+#define ATH_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_rx_mtx)
+#define ATH_RX_LOCK(_sc) mtx_lock(&(_sc)->sc_rx_mtx)
+#define ATH_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_rx_mtx)
+#define ATH_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_rx_mtx, \
+ MA_OWNED)
+#define ATH_RX_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_rx_mtx, \
+ MA_NOTOWNED)
+
#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i))
#define ATH_TXBUF_LOCK_INIT(_sc) do { \
@@ -649,6 +747,19 @@
#define ATH_TXBUF_LOCK_ASSERT(_sc) \
mtx_assert(&(_sc)->sc_txbuflock, MA_OWNED)
+#define ATH_TXSTATUS_LOCK_INIT(_sc) do { \
+ snprintf((_sc)->sc_txcompname, sizeof((_sc)->sc_txcompname), \
+ "%s_buf", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_txcomplock, (_sc)->sc_txcompname, NULL, \
+ MTX_DEF); \
+} while (0)
+#define ATH_TXSTATUS_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_txcomplock)
+#define ATH_TXSTATUS_LOCK(_sc) mtx_lock(&(_sc)->sc_txcomplock)
+#define ATH_TXSTATUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_txcomplock)
+#define ATH_TXSTATUS_LOCK_ASSERT(_sc) \
+ mtx_assert(&(_sc)->sc_txcomplock, MA_OWNED)
+
int ath_attach(u_int16_t, struct ath_softc *);
int ath_detach(struct ath_softc *);
void ath_resume(struct ath_softc *);
@@ -705,8 +816,8 @@
((*(_ah)->ah_setMulticastFilter)((_ah), (_mfilt0), (_mfilt1)))
#define ath_hal_waitforbeacon(_ah, _bf) \
((*(_ah)->ah_waitForBeaconDone)((_ah), (_bf)->bf_daddr))
-#define ath_hal_putrxbuf(_ah, _bufaddr) \
- ((*(_ah)->ah_setRxDP)((_ah), (_bufaddr)))
+#define ath_hal_putrxbuf(_ah, _bufaddr, _rxq) \
+ ((*(_ah)->ah_setRxDP)((_ah), (_bufaddr), (_rxq)))
/* NB: common across all chips */
#define AR_TSF_L32 0x804c /* MAC local clock lower 32 bits */
#define ath_hal_gettsf32(_ah) \
@@ -723,8 +834,8 @@
((*(_ah)->ah_getTxDP)((_ah), (_q)))
#define ath_hal_numtxpending(_ah, _q) \
((*(_ah)->ah_numTxPending)((_ah), (_q)))
-#define ath_hal_getrxbuf(_ah) \
- ((*(_ah)->ah_getRxDP)((_ah)))
+#define ath_hal_getrxbuf(_ah, _rxq) \
+ ((*(_ah)->ah_getRxDP)((_ah), (_rxq)))
#define ath_hal_txstart(_ah, _q) \
((*(_ah)->ah_startTxDma)((_ah), (_q)))
#define ath_hal_setchannel(_ah, _chan) \
@@ -913,8 +1024,34 @@
#define ath_hal_setintmit(_ah, _v) \
ath_hal_setcapability(_ah, HAL_CAP_INTMIT, \
HAL_CAP_INTMIT_ENABLE, _v, NULL)
+
+/* EDMA definitions */
+#define ath_hal_hasedma(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_ENHANCED_DMA_SUPPORT, \
+ 0, NULL) == HAL_OK)
+#define ath_hal_getrxfifodepth(_ah, _qtype, _req) \
+ (ath_hal_getcapability(_ah, HAL_CAP_RXFIFODEPTH, _qtype, _req) \
+ == HAL_OK)
+#define ath_hal_getntxmaps(_ah, _req) \
+ (ath_hal_getcapability(_ah, HAL_CAP_NUM_TXMAPS, 0, _req) \
+ == HAL_OK)
+#define ath_hal_gettxdesclen(_ah, _req) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TXDESCLEN, 0, _req) \
+ == HAL_OK)
+#define ath_hal_gettxstatuslen(_ah, _req) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TXSTATUSLEN, 0, _req) \
+ == HAL_OK)
+#define ath_hal_getrxstatuslen(_ah, _req) \
+ (ath_hal_getcapability(_ah, HAL_CAP_RXSTATUSLEN, 0, _req) \
+ == HAL_OK)
+#define ath_hal_setrxbufsize(_ah, _req) \
+ (ath_hal_setcapability(_ah, HAL_CAP_RXBUFSIZE, 0, _req, NULL) \
+ == HAL_OK)
+
#define ath_hal_getchannoise(_ah, _c) \
((*(_ah)->ah_getChanNoise)((_ah), (_c)))
+
+/* 802.11n HAL methods */
#define ath_hal_getrxchainmask(_ah, _prxchainmask) \
(ath_hal_getcapability(_ah, HAL_CAP_RX_CHAINMASK, 0, _prxchainmask))
#define ath_hal_gettxchainmask(_ah, _ptxchainmask) \
@@ -956,6 +1093,15 @@
((*(_ah)->ah_getTxIntrQueue)((_ah), (_txqs)))
#define ath_hal_gettxcompletionrates(_ah, _ds, _rates, _tries) \
((*(_ah)->ah_getTxCompletionRates)((_ah), (_ds), (_rates), (_tries)))
+#define ath_hal_settxdesclink(_ah, _ds, _link) \
+ ((*(_ah)->ah_setTxDescLink)((_ah), (_ds), (_link)))
+#define ath_hal_gettxdesclink(_ah, _ds, _link) \
+ ((*(_ah)->ah_getTxDescLink)((_ah), (_ds), (_link)))
+#define ath_hal_gettxdesclinkptr(_ah, _ds, _linkptr) \
+ ((*(_ah)->ah_getTxDescLinkPtr)((_ah), (_ds), (_linkptr)))
+#define ath_hal_setuptxstatusring(_ah, _tsstart, _tspstart, _size) \
+ ((*(_ah)->ah_setupTxStatusRing)((_ah), (_tsstart), (_tspstart), \
+ (_size)))
#define ath_hal_setupfirsttxdesc(_ah, _ds, _aggrlen, _flags, _txpower, \
_txr0, _txtr0, _antm, _rcr, _rcd) \
@@ -995,6 +1141,14 @@
((*(_ah)->ah_gpioSetIntr)((_ah), (_gpio), (_b)))
/*
+ * PCIe suspend/resume/poweron/poweroff related macros
+ */
+#define ath_hal_enablepcie(_ah, _restore, _poweroff) \
+ ((*(_ah)->ah_configPCIE)((_ah), (_restore), (_poweroff)))
+#define ath_hal_disablepcie(_ah) \
+ ((*(_ah)->ah_disablePCIE)((_ah)))
+
+/*
* This is badly-named; you need to set the correct parameters
* to begin to receive useful radar events; and even then
* it doesn't "enable" DFS. See the ath_dfs/null/ module for
@@ -1011,6 +1165,8 @@
((*(_ah)->ah_isFastClockEnabled)((_ah)))
#define ath_hal_radar_wait(_ah, _chan) \
((*(_ah)->ah_radarWait)((_ah), (_chan)))
+#define ath_hal_get_mib_cycle_counts(_ah, _sample) \
+ ((*(_ah)->ah_getMibCycleCounts)((_ah), (_sample)))
#define ath_hal_get_chan_ext_busy(_ah) \
((*(_ah)->ah_get11nExtBusy)((_ah)))
More information about the Zrouter-src-freebsd
mailing list