[Midnightbsd-cvs] src [10127] trunk/sys/dev/ath: update ath
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sun May 27 20:25:21 EDT 2018
Revision: 10127
http://svnweb.midnightbsd.org/src/?rev=10127
Author: laffer1
Date: 2018-05-27 20:25:20 -0400 (Sun, 27 May 2018)
Log Message:
-----------
update ath
Modified Paths:
--------------
trunk/sys/dev/ath/ah_osdep.c
trunk/sys/dev/ath/ah_osdep.h
trunk/sys/dev/ath/ath_dfs/null/dfs_null.c
trunk/sys/dev/ath/ath_hal/ah.c
trunk/sys/dev/ath/ath_hal/ah.h
trunk/sys/dev/ath/ath_hal/ah_debug.h
trunk/sys/dev/ath/ath_hal/ah_decode.h
trunk/sys/dev/ath/ath_hal/ah_desc.h
trunk/sys/dev/ath/ath_hal/ah_devid.h
trunk/sys/dev/ath/ath_hal/ah_diagcodes.h
trunk/sys/dev/ath/ath_hal/ah_eeprom.h
trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.c
trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.h
trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.c
trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.h
trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.c
trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.h
trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.c
trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.h
trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.c
trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.h
trunk/sys/dev/ath/ath_hal/ah_internal.h
trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h
trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h
trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h
trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h
trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h
trunk/sys/dev/ath/ath_hal/ah_regdomain.c
trunk/sys/dev/ath/ath_hal/ah_regdomain.h
trunk/sys/dev/ath/ath_hal/ah_soc.h
trunk/sys/dev/ath/ath_hal/ar5210/ar5210.h
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
trunk/sys/dev/ath/ath_hal/ar5210/ar5210desc.h
trunk/sys/dev/ath/ath_hal/ar5210/ar5210phy.h
trunk/sys/dev/ath/ath_hal/ar5210/ar5210reg.h
trunk/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini
trunk/sys/dev/ath/ath_hal/ar5211/ar5211.h
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
trunk/sys/dev/ath/ath_hal/ar5211/ar5211desc.h
trunk/sys/dev/ath/ath_hal/ar5211/ar5211phy.h
trunk/sys/dev/ath/ath_hal/ar5211/ar5211reg.h
trunk/sys/dev/ath/ath_hal/ar5211/boss.ini
trunk/sys/dev/ath/ath_hal/ar5212/ar2316.c
trunk/sys/dev/ath/ath_hal/ar5212/ar2317.c
trunk/sys/dev/ath/ath_hal/ar5212/ar2413.c
trunk/sys/dev/ath/ath_hal/ar5212/ar2425.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5111.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5112.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212.h
trunk/sys/dev/ath/ath_hal/ar5212/ar5212.ini
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_power.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
trunk/sys/dev/ath/ath_hal/ar5212/ar5212desc.h
trunk/sys/dev/ath/ath_hal/ar5212/ar5212phy.h
trunk/sys/dev/ath/ath_hal/ar5212/ar5212reg.h
trunk/sys/dev/ath/ath_hal/ar5212/ar5311reg.h
trunk/sys/dev/ath/ath_hal/ar5212/ar5413.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312.h
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_power.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c
trunk/sys/dev/ath/ath_hal/ar5312/ar5312phy.h
trunk/sys/dev/ath/ath_hal/ar5312/ar5312reg.h
trunk/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c
trunk/sys/dev/ath/ath_hal/ar5416/ar2133.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416.h
trunk/sys/dev/ath/ath_hal/ar5416/ar5416.ini
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_power.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416desc.h
trunk/sys/dev/ath/ath_hal/ar5416/ar5416phy.h
trunk/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
trunk/sys/dev/ath/ath_hal/ar9001/ar9130.ini
trunk/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c
trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c
trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h
trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c
trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h
trunk/sys/dev/ath/ath_hal/ar9001/ar9130reg.h
trunk/sys/dev/ath/ath_hal/ar9001/ar9160.ini
trunk/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9002phy.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9280.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9280.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9285.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9285.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285an.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9285phy.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9287.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9287.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9287.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9287an.h
trunk/sys/dev/ath/ath_hal/ar9002/ar9287phy.h
trunk/sys/dev/ath/ath_rate/amrr/amrr.c
trunk/sys/dev/ath/ath_rate/amrr/amrr.h
trunk/sys/dev/ath/ath_rate/onoe/onoe.c
trunk/sys/dev/ath/ath_rate/onoe/onoe.h
trunk/sys/dev/ath/ath_rate/sample/sample.c
trunk/sys/dev/ath/ath_rate/sample/sample.h
trunk/sys/dev/ath/ath_rate/sample/tx_schedules.h
trunk/sys/dev/ath/if_ath.c
trunk/sys/dev/ath/if_ath_ahb.c
trunk/sys/dev/ath/if_ath_debug.c
trunk/sys/dev/ath/if_ath_debug.h
trunk/sys/dev/ath/if_ath_keycache.c
trunk/sys/dev/ath/if_ath_keycache.h
trunk/sys/dev/ath/if_ath_misc.h
trunk/sys/dev/ath/if_ath_pci.c
trunk/sys/dev/ath/if_ath_sysctl.c
trunk/sys/dev/ath/if_ath_sysctl.h
trunk/sys/dev/ath/if_ath_tx.c
trunk/sys/dev/ath/if_ath_tx.h
trunk/sys/dev/ath/if_ath_tx_ht.c
trunk/sys/dev/ath/if_ath_tx_ht.h
trunk/sys/dev/ath/if_athdfs.h
trunk/sys/dev/ath/if_athioctl.h
trunk/sys/dev/ath/if_athrate.h
trunk/sys/dev/ath/if_athvar.h
Added Paths:
-----------
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h
trunk/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c
trunk/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c
trunk/sys/dev/ath/ath_hal/ar9003/
trunk/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h
trunk/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h
trunk/sys/dev/ath/if_ath_alq.c
trunk/sys/dev/ath/if_ath_alq.h
trunk/sys/dev/ath/if_ath_beacon.c
trunk/sys/dev/ath/if_ath_beacon.h
trunk/sys/dev/ath/if_ath_btcoex.c
trunk/sys/dev/ath/if_ath_btcoex.h
trunk/sys/dev/ath/if_ath_led.c
trunk/sys/dev/ath/if_ath_led.h
trunk/sys/dev/ath/if_ath_lna_div.c
trunk/sys/dev/ath/if_ath_lna_div.h
trunk/sys/dev/ath/if_ath_rx.c
trunk/sys/dev/ath/if_ath_rx.h
trunk/sys/dev/ath/if_ath_rx_edma.c
trunk/sys/dev/ath/if_ath_rx_edma.h
trunk/sys/dev/ath/if_ath_spectral.c
trunk/sys/dev/ath/if_ath_spectral.h
trunk/sys/dev/ath/if_ath_tdma.c
trunk/sys/dev/ath/if_ath_tdma.h
trunk/sys/dev/ath/if_ath_tsf.h
trunk/sys/dev/ath/if_ath_tx_edma.c
trunk/sys/dev/ath/if_ath_tx_edma.h
Property Changed:
----------------
trunk/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini
trunk/sys/dev/ath/ath_hal/ar5211/boss.ini
trunk/sys/dev/ath/ath_hal/ar5212/ar5212.ini
trunk/sys/dev/ath/ath_hal/ar5416/ar5416.ini
trunk/sys/dev/ath/ath_hal/ar9001/ar9130.ini
trunk/sys/dev/ath/ath_hal/ar9001/ar9160.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9285.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini
trunk/sys/dev/ath/ath_hal/ar9002/ar9287.ini
Modified: trunk/sys/dev/ath/ah_osdep.c
===================================================================
--- trunk/sys/dev/ath/ah_osdep.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ah_osdep.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ah_osdep.c 237864 2012-07-01 02:34:32Z adrian $
*/
#include "opt_ah.h"
@@ -38,6 +39,9 @@
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/stdarg.h>
@@ -44,6 +48,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
@@ -59,6 +64,17 @@
#define BUSTAG(ah) ((ah)->ah_st)
#endif
+/*
+ * This lock is used to seralise register access for chips which have
+ * problems w/ SMP CPUs issuing concurrent PCI transactions.
+ *
+ * XXX This is a global lock for now; it should be pushed to
+ * a per-device lock in some platform-independent fashion.
+ */
+struct mtx ah_regser_mtx;
+MTX_SYSINIT(ah_regser, &ah_regser_mtx, "Atheros register access mutex",
+ MTX_SPIN);
+
extern void ath_hal_printf(struct ath_hal *, const char*, ...)
__printflike(2,3);
extern void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
@@ -123,13 +139,11 @@
#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, ...)
{
if ((mask == HAL_DEBUG_UNMASKABLE) ||
- (ah->ah_config.ah_debug & mask) ||
+ (ah != NULL && ah->ah_config.ah_debug & mask) ||
(ath_hal_debug & mask)) {
__va_list ap;
va_start(ap, fmt);
@@ -244,6 +258,7 @@
struct ale *ale = ath_hal_alq_get(ah);
if (ale) {
struct athregrec *r = (struct athregrec *) ale->ae_data;
+ r->threadid = curthread->td_tid;
r->op = OP_WRITE;
r->reg = reg;
r->val = val;
@@ -250,12 +265,11 @@
alq_post(ath_hal_alq, ale);
}
}
-#if _BYTE_ORDER == _BIG_ENDIAN
- if (OS_REG_UNSWAPPED(reg))
- bus_space_write_4(tag, h, reg, val);
- else
-#endif
- bus_space_write_stream_4(tag, h, reg, val);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
+ bus_space_write_4(tag, h, reg, val);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
}
u_int32_t
@@ -265,16 +279,16 @@
bus_space_handle_t h = ah->ah_sh;
u_int32_t val;
-#if _BYTE_ORDER == _BIG_ENDIAN
- if (OS_REG_UNSWAPPED(reg))
- val = bus_space_read_4(tag, h, reg);
- else
-#endif
- val = bus_space_read_stream_4(tag, h, reg);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
+ val = bus_space_read_4(tag, h, reg);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
if (ath_hal_alq) {
struct ale *ale = ath_hal_alq_get(ah);
if (ale) {
struct athregrec *r = (struct athregrec *) ale->ae_data;
+ r->threadid = curthread->td_tid;
r->op = OP_READ;
r->reg = reg;
r->val = val;
@@ -291,6 +305,7 @@
struct ale *ale = ath_hal_alq_get(ah);
if (ale) {
struct athregrec *r = (struct athregrec *) ale->ae_data;
+ r->threadid = curthread->td_tid;
r->op = OP_MARK;
r->reg = id;
r->val = v;
@@ -316,12 +331,11 @@
bus_space_tag_t tag = BUSTAG(ah);
bus_space_handle_t h = ah->ah_sh;
-#if _BYTE_ORDER == _BIG_ENDIAN
- if (OS_REG_UNSWAPPED(reg))
- bus_space_write_4(tag, h, reg, val);
- else
-#endif
- bus_space_write_stream_4(tag, h, reg, val);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
+ bus_space_write_4(tag, h, reg, val);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
}
u_int32_t
@@ -331,12 +345,11 @@
bus_space_handle_t h = ah->ah_sh;
u_int32_t val;
-#if _BYTE_ORDER == _BIG_ENDIAN
- if (OS_REG_UNSWAPPED(reg))
- val = bus_space_read_4(tag, h, reg);
- else
-#endif
- val = bus_space_read_stream_4(tag, h, reg);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_lock_spin(&ah_regser_mtx);
+ val = bus_space_read_4(tag, h, reg);
+ if (ah->ah_config.ah_serialise_reg_war)
+ mtx_unlock_spin(&ah_regser_mtx);
return val;
}
#endif /* AH_DEBUG || AH_REGOPS_FUNC */
Modified: trunk/sys/dev/ath/ah_osdep.h
===================================================================
--- trunk/sys/dev/ath/ah_osdep.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ah_osdep.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ah_osdep.h 239051 2012-08-05 10:12:27Z adrian $
*/
#ifndef _ATH_AH_OSDEP_H_
#define _ATH_AH_OSDEP_H_
@@ -49,6 +50,12 @@
typedef bus_space_handle_t HAL_BUS_HANDLE;
/*
+ * Although the underlying hardware may support 64 bit DMA, the
+ * current Atheros hardware only supports 32 bit addressing.
+ */
+typedef uint32_t HAL_DMA_ADDR;
+
+/*
* Linker set writearounds for chip and RF backend registration.
*/
#define OS_DATA_SET(set, item) DATA_SET(set, item)
@@ -63,6 +70,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 +83,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 +97,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
@@ -97,31 +123,6 @@
extern void ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val);
extern u_int32_t ath_hal_reg_read(struct ath_hal *ah, u_int reg);
#else
-/*
- * The hardware registers are native little-endian byte order.
- * Big-endian hosts are handled by enabling hardware byte-swap
- * of register reads and writes at reset. But the PCI clock
- * domain registers are not byte swapped! Thus, on big-endian
- * platforms we have to explicitly byte-swap those registers.
- * Most of this code is collapsed at compile time because the
- * register values are constants.
- */
-#if _BYTE_ORDER == _BIG_ENDIAN
-#define OS_REG_WRITE(_ah, _reg, _val) do { \
- if (OS_REG_UNSWAPPED(_reg)) \
- bus_space_write_4((bus_space_tag_t)(_ah)->ah_st, \
- (bus_space_handle_t)(_ah)->ah_sh, (_reg), (_val)); \
- else \
- bus_space_write_stream_4((bus_space_tag_t)(_ah)->ah_st, \
- (bus_space_handle_t)(_ah)->ah_sh, (_reg), (_val)); \
-} while (0)
-#define OS_REG_READ(_ah, _reg) \
- (OS_REG_UNSWAPPED(_reg) ? \
- bus_space_read_4((bus_space_tag_t)(_ah)->ah_st, \
- (bus_space_handle_t)(_ah)->ah_sh, (_reg)) : \
- bus_space_read_stream_4((bus_space_tag_t)(_ah)->ah_st, \
- (bus_space_handle_t)(_ah)->ah_sh, (_reg)))
-#else /* _BYTE_ORDER == _LITTLE_ENDIAN */
#define OS_REG_WRITE(_ah, _reg, _val) \
bus_space_write_4((bus_space_tag_t)(_ah)->ah_st, \
(bus_space_handle_t)(_ah)->ah_sh, (_reg), (_val))
@@ -128,8 +129,7 @@
#define OS_REG_READ(_ah, _reg) \
bus_space_read_4((bus_space_tag_t)(_ah)->ah_st, \
(bus_space_handle_t)(_ah)->ah_sh, (_reg))
-#endif /* _BYTE_ORDER */
-#endif /* AH_DEBUG || AH_REGFUNC || AH_DEBUG_ALQ */
+#endif
#ifdef AH_DEBUG_ALQ
extern void OS_MARK(struct ath_hal *, u_int id, u_int32_t value);
Modified: trunk/sys/dev/ath/ath_dfs/null/dfs_null.c
===================================================================
--- trunk/sys/dev/ath/ath_dfs/null/dfs_null.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_dfs/null/dfs_null.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
* All rights reserved.
@@ -26,14 +27,15 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_dfs/null/dfs_null.c 244946 2013-01-02 01:36:10Z adrian $
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/ath_dfs/null/dfs_null.c 244946 2013-01-02 01:36:10Z adrian $");
/*
* This implements an empty DFS module.
*/
+#include "opt_ath.h"
#include "opt_inet.h"
#include "opt_wlan.h"
@@ -80,7 +82,7 @@
int
ath_dfs_attach(struct ath_softc *sc)
{
- return 1;
+ return (1);
}
/*
@@ -89,25 +91,89 @@
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.
*/
-void
+int
ath_dfs_radar_enable(struct ath_softc *sc, struct ieee80211_channel *chan)
{
+#if 0
+ HAL_PHYERR_PARAM pe;
+
+ /* Check if the hardware supports radar reporting */
+ /* XXX TODO: migrate HAL_CAP_RADAR/HAL_CAP_AR to somewhere public! */
+ if (ath_hal_getcapability(sc->sc_ah,
+ HAL_CAP_PHYDIAG, 0, NULL) != HAL_OK)
+ return (0);
+
/* Check if the current channel is radar-enabled */
if (! IEEE80211_IS_CHAN_DFS(chan))
- return;
+ return (0);
+
+ /* Fetch the default parameters */
+ memset(&pe, '\0', sizeof(pe));
+ if (! ath_hal_getdfsdefaultthresh(sc->sc_ah, &pe))
+ return (0);
+
+ /* Enable radar PHY error reporting */
+ sc->sc_dodfs = 1;
+
+ /* Tell the hardware to enable radar reporting */
+ pe.pe_enabled = 1;
+
+ /* Flip on extension channel events only if doing HT40 */
+ if (IEEE80211_IS_CHAN_HT40(chan))
+ pe.pe_extchannel = 1;
+ else
+ pe.pe_extchannel = 0;
+
+ ath_hal_enabledfs(sc->sc_ah, &pe);
+
+ /*
+ * Disable strong signal fast diversity - needed for
+ * AR5212 and similar PHYs for reliable short pulse
+ * duration.
+ */
+ (void) ath_hal_setcapability(sc->sc_ah, HAL_CAP_DIVERSITY, 2, 0, NULL);
+
+ return (1);
+#else
+ return (0);
+#endif
}
/*
+ * Explicity disable radar reporting.
+ *
+ * Return 0 if it was disabled, < 0 on error.
+ */
+int
+ath_dfs_radar_disable(struct ath_softc *sc)
+{
+#if 0
+ HAL_PHYERR_PARAM pe;
+
+ (void) ath_hal_getdfsthresh(sc->sc_ah, &pe);
+ pe.pe_enabled = 0;
+ (void) ath_hal_enabledfs(sc->sc_ah, &pe);
+ return (0);
+#else
+ return (0);
+#endif
+}
+
+/*
* 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)
{
@@ -124,7 +190,7 @@
ath_dfs_process_radar_event(struct ath_softc *sc,
struct ieee80211_channel *chan)
{
- return 0;
+ return (0);
}
/*
@@ -137,7 +203,7 @@
int
ath_dfs_tasklet_needed(struct ath_softc *sc, struct ieee80211_channel *chan)
{
- return 0;
+ return (0);
}
/*
@@ -214,7 +280,7 @@
free(indata, M_TEMP);
if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
free(outdata, M_TEMP);
- return error;
+ return (error);
}
/*
@@ -224,5 +290,5 @@
ath_dfs_get_thresholds(struct ath_softc *sc, HAL_PHYERR_PARAM *param)
{
ath_hal_getdfsthresh(sc->sc_ah, param);
- return 1;
+ return (1);
}
Modified: trunk/sys/dev/ath/ath_hal/ah.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah.c 252236 2013-06-26 04:46:03Z adrian $
*/
#include "opt_ah.h"
@@ -24,6 +25,7 @@
#include "ah_eeprom.h" /* for 5ghz fast clock flag */
#include "ar5416/ar5416reg.h" /* NB: includes ar5212reg.h */
+#include "ar9003/ar9300_devid.h"
/* linker set of registered chips */
OS_SET_DECLARE(ah_chips, struct ath_hal_chip);
@@ -101,9 +103,9 @@
return "5413";
case AR_SREV_VERSION_COBRA:
return "2415";
- case AR_SREV_2425:
+ case AR_SREV_2425: /* Swan */
return "2425";
- case AR_SREV_2417:
+ case AR_SREV_2417: /* Nala */
return "2417";
case AR_XSREV_VERSION_OWL_PCI:
return "5416";
@@ -114,11 +116,33 @@
case AR_XSREV_VERSION_SOWL:
return "9160";
case AR_XSREV_VERSION_MERLIN:
- return "9280";
+ if (AH_PRIVATE(ah)->ah_ispcie)
+ return "9280";
+ return "9220";
case AR_XSREV_VERSION_KITE:
return "9285";
case AR_XSREV_VERSION_KIWI:
- return "9287";
+ if (AH_PRIVATE(ah)->ah_ispcie)
+ return "9287";
+ return "9227";
+ case AR_SREV_VERSION_AR9380:
+ if (ah->ah_macRev >= AR_SREV_REVISION_AR9580_10)
+ return "9580";
+ return "9380";
+ case AR_SREV_VERSION_AR9460:
+ return "9460";
+ case AR_SREV_VERSION_AR9330:
+ return "9330";
+ case AR_SREV_VERSION_AR9340:
+ return "9340";
+ case AR_SREV_VERSION_QCA9550:
+ /* XXX should say QCA, not AR */
+ return "9550";
+ case AR_SREV_VERSION_AR9485:
+ return "9485";
+ case AR_SREV_VERSION_QCA9565:
+ /* XXX should say QCA, not AR */
+ return "9565";
}
return "????";
}
@@ -271,36 +295,42 @@
/* 11n frame - extract out the number of spatial streams */
numStreams = HT_RC_2_STREAMS(rc);
- KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix));
+ KASSERT(numStreams > 0 && numStreams <= 4,
+ ("number of spatial streams needs to be 1..3: MCS rate 0x%x!",
+ rateix));
return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
}
+static const uint16_t ht20_bps[32] = {
+ 26, 52, 78, 104, 156, 208, 234, 260,
+ 52, 104, 156, 208, 312, 416, 468, 520,
+ 78, 156, 234, 312, 468, 624, 702, 780,
+ 104, 208, 312, 416, 624, 832, 936, 1040
+};
+static const uint16_t ht40_bps[32] = {
+ 54, 108, 162, 216, 324, 432, 486, 540,
+ 108, 216, 324, 432, 648, 864, 972, 1080,
+ 162, 324, 486, 648, 972, 1296, 1458, 1620,
+ 216, 432, 648, 864, 1296, 1728, 1944, 2160
+};
+
/*
* Calculate the transmit duration of an 11n frame.
- * This only works for MCS0->MCS15.
*/
uint32_t
-ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40,
- HAL_BOOL isShortGI)
+ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams,
+ HAL_BOOL isht40, HAL_BOOL isShortGI)
{
- static const uint16_t ht20_bps[16] = {
- 26, 52, 78, 104, 156, 208, 234, 260,
- 52, 104, 156, 208, 312, 416, 468, 520
- };
- static const uint16_t ht40_bps[16] = {
- 54, 108, 162, 216, 324, 432, 486, 540,
- 108, 216, 324, 432, 648, 864, 972, 1080,
- };
uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
- KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate));
+ KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
if (isht40)
- bitsPerSymbol = ht40_bps[rate & 0xf];
+ bitsPerSymbol = ht40_bps[rate & 0x1f];
else
- bitsPerSymbol = ht20_bps[rate & 0xf];
+ bitsPerSymbol = ht20_bps[rate & 0x1f];
numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = howmany(numBits, bitsPerSymbol);
if (isShortGI)
@@ -394,6 +424,50 @@
return txTime;
}
+int
+ath_hal_get_curmode(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ /*
+ * Pick a default mode at bootup. A channel change is inevitable.
+ */
+ if (!chan)
+ return HAL_MODE_11NG_HT20;
+
+ if (IEEE80211_IS_CHAN_TURBO(chan))
+ return HAL_MODE_TURBO;
+
+ /* check for NA_HT before plain A, since IS_CHAN_A includes NA_HT */
+ if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
+ return HAL_MODE_11NA_HT20;
+ if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
+ return HAL_MODE_11NA_HT40PLUS;
+ if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
+ return HAL_MODE_11NA_HT40MINUS;
+ if (IEEE80211_IS_CHAN_A(chan))
+ return HAL_MODE_11A;
+
+ /* check for NG_HT before plain G, since IS_CHAN_G includes NG_HT */
+ if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan))
+ return HAL_MODE_11NG_HT20;
+ if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan))
+ return HAL_MODE_11NG_HT40PLUS;
+ if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan))
+ return HAL_MODE_11NG_HT40MINUS;
+
+ /*
+ * XXX For FreeBSD, will this work correctly given the DYN
+ * chan mode (OFDM+CCK dynamic) ? We have pure-G versions DYN-BG..
+ */
+ if (IEEE80211_IS_CHAN_G(chan))
+ return HAL_MODE_11G;
+ if (IEEE80211_IS_CHAN_B(chan))
+ return HAL_MODE_11B;
+
+ HALASSERT(0);
+ return HAL_MODE_11NG_HT20;
+}
+
+
typedef enum {
WIRELESS_MODE_11a = 0,
WIRELESS_MODE_TURBO = 1,
@@ -444,6 +518,13 @@
clks <<= 1;
} else
clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
+
+ /* Compensate for half/quarter rate */
+ if (c != AH_NULL && IEEE80211_IS_CHAN_HALF(c))
+ clks = clks / 2;
+ else if (c != AH_NULL && IEEE80211_IS_CHAN_QUARTER(c))
+ clks = clks / 4;
+
return clks;
}
@@ -615,6 +696,10 @@
return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_EXT_CHAN_DFS:
return pCap->halExtChanDfsSupport ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_RX_STBC:
+ return pCap->halRxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_TX_STBC:
+ return pCap->halTxStbcSupport ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_COMBINED_RADAR_RSSI:
return pCap->halUseCombinedRadarRssi ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_AUTO_SLEEP:
@@ -626,13 +711,47 @@
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:
+ *result = pCap->halNumMRRetries;
+ return HAL_OK;
case HAL_CAP_BT_COEX:
return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_SPECTRAL_SCAN:
+ return pCap->halSpectralScanSupport ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_HT20_SGI:
return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */
*result = pCap->halTstampPrecision;
return HAL_OK;
+ case HAL_CAP_ANT_DIV_COMB: /* AR9285/AR9485 LNA diversity */
+ return pCap->halAntDivCombSupport ? HAL_OK : HAL_ENOTSUPP;
+
case HAL_CAP_ENHANCED_DFS_SUPPORT:
return pCap->halEnhancedDfsSupport ? HAL_OK : HAL_ENOTSUPP;
@@ -659,6 +778,15 @@
return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_LONG_RXDESC_TSF: /* 32 bit TSF in RX descriptor? */
return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_BB_READ_WAR: /* Baseband read WAR */
+ return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_SERIALISE_WAR: /* PCI register serialisation */
+ return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_MFP: /* Management frame protection setting */
+ *result = pCap->halMfpSupport;
+ return HAL_OK;
+ case HAL_CAP_RX_LNA_MIXING: /* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */
+ return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP;
default:
return HAL_EINVAL;
}
@@ -940,7 +1068,7 @@
* populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust().
*
* The caller must supply ctl/ext NF arrays which are at least
- * AH_MIMO_MAX_CHAINS entries long.
+ * AH_MAX_CHAINS entries long.
*/
int
ath_hal_get_mimo_chan_noise(struct ath_hal *ah,
@@ -956,7 +1084,7 @@
HALDEBUG(ah, HAL_DEBUG_NFCAL,
"%s: invalid channel %u/0x%x; no mapping\n",
__func__, chan->ic_freq, chan->ic_flags);
- for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
+ for (i = 0; i < AH_MAX_CHAINS; i++) {
nf_ctl[i] = nf_ext[i] = 0;
}
return 0;
@@ -964,7 +1092,7 @@
/* Return 0 if there's no valid MIMO values (yet) */
if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) {
- for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
+ for (i = 0; i < AH_MAX_CHAINS; i++) {
nf_ctl[i] = nf_ext[i] = 0;
}
return 0;
@@ -977,7 +1105,7 @@
* stations which have a very low RSSI, below the
* 'normalised' NF values in NOISE_FLOOR[].
*/
- for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
+ for (i = 0; i < AH_MAX_CHAINS; i++) {
nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] +
ath_hal_getNfAdjust(ah, ichan);
}
@@ -996,7 +1124,7 @@
* don't "wrap" when RSSI is less than the "adjusted" NF value.
* ("Adjust" here is via ichan->noiseFloorAdjust.)
*/
- for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) {
+ for (i = 0; i < AH_MAX_CHAINS; i++) {
nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan);
nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan);
}
@@ -1258,3 +1386,45 @@
return 1;
return ((diag & 0x500000) == 0);
}
+
+/*
+ * This routine is only needed when supporting EEPROM-in-RAM setups
+ * (eg embedded SoCs and on-board PCI/PCIe devices.)
+ */
+/* NB: This is in 16 bit words; not bytes */
+/* XXX This doesn't belong here! */
+#define ATH_DATA_EEPROM_SIZE 2048
+
+HAL_BOOL
+ath_hal_EepromDataRead(struct ath_hal *ah, u_int off, uint16_t *data)
+{
+ if (ah->ah_eepromdata == AH_NULL) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__);
+ return AH_FALSE;
+ }
+ if (off > ATH_DATA_EEPROM_SIZE) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset %x > %x\n",
+ __func__, off, ATH_DATA_EEPROM_SIZE);
+ return AH_FALSE;
+ }
+ (*data) = ah->ah_eepromdata[off];
+ return AH_TRUE;
+}
+
+/*
+ * Do a 2GHz specific MHz->IEEE based on the hardware
+ * frequency.
+ *
+ * This is the unmapped frequency which is programmed into the hardware.
+ */
+int
+ath_hal_mhz2ieee_2ghz(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
+{
+
+ if (ichan->channel == 2484)
+ return 14;
+ if (ichan->channel < 2484)
+ return ((int) ichan->channel - 2407) / 5;
+ else
+ return 15 + ((ichan->channel - 2512) / 20);
+}
Modified: trunk/sys/dev/ath/ath_hal/ah.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah.h 251655 2013-06-12 14:52:57Z adrian $
*/
#ifndef _ATH_AH_H_
@@ -35,7 +36,7 @@
* This is intended to be used by various statistics gathering operations
* (NF, RSSI, EVM).
*/
-#define AH_MIMO_MAX_CHAINS 3
+#define AH_MAX_CHAINS 3
#define AH_MIMO_MAX_EVM_PILOTS 6
/*
@@ -73,6 +74,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 +111,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 */
@@ -118,7 +120,9 @@
HAL_CAP_NUM_GPIO_PINS = 36, /* number of GPIO pins */
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,13 +134,57 @@
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_RX_STBC = 58,
+ HAL_CAP_TX_STBC = 59,
+
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_SPECTRAL_SCAN = 90, /* Hardware supports spectral scan */
+
+ HAL_CAP_BB_PANIC_WATCHDOG = 92,
+
HAL_CAP_HT20_SGI = 96, /* hardware supports HT20 short GI */
+ HAL_CAP_LDPC = 99,
+
HAL_CAP_RXTSTAMP_PREC = 100, /* rx desc tstamp precision (bits) */
+
+ HAL_CAP_ANT_DIV_COMB = 105, /* Enable antenna diversity/combining */
+ HAL_CAP_PHYRESTART_CLR_WAR = 106, /* in some cases, clear phy restart to fix bb hang */
+ HAL_CAP_ENTERPRISE_MODE = 107, /* Enterprise mode features */
+ HAL_CAP_LDPCWAR = 108,
+ HAL_CAP_CHANNEL_SWITCH_TIME_USEC = 109, /* Channel change time, usec */
+ HAL_CAP_ENABLE_APM = 110, /* APM enabled */
+ HAL_CAP_PCIE_LCR_EXTSYNC_EN = 111,
+ HAL_CAP_PCIE_LCR_OFFSET = 112,
+
HAL_CAP_ENHANCED_DFS_SUPPORT = 117, /* hardware supports enhanced DFS */
+ HAL_CAP_MCI = 118,
+ HAL_CAP_SMARTANTENNA = 119,
+ HAL_CAP_TRAFFIC_FAST_RECOVER = 120,
+ HAL_CAP_TX_DIVERSITY = 121,
+ HAL_CAP_CRDC = 122,
/* The following are private to the FreeBSD HAL (224 onward) */
@@ -143,12 +191,15 @@
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 */
HAL_CAP_RXDESC_SELFLINK = 242, /* support a self-linked tail RX descriptor */
HAL_CAP_LONG_RXDESC_TSF = 243, /* hardware supports 32bit TSF in RX descriptor */
+ HAL_CAP_BB_READ_WAR = 244, /* baseband read WAR */
+ HAL_CAP_SERIALISE_WAR = 245, /* serialise register access on PCI */
+ HAL_CAP_ENFORCE_TXOP = 246, /* Enforce TXOP if supported */
+ HAL_CAP_RX_LNA_MIXING = 247, /* RX hardware uses LNA mixing */
} HAL_CAPABILITY_TYPE;
/*
@@ -178,11 +229,27 @@
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 */
/*
+ * Receive queue types. These are used to tag
+ * each transmit queue in the hardware and to identify a set
+ * of transmit queues for operations such as start/stop dma.
+ */
+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 */
+
+#define HAL_TXFIFO_DEPTH 8 /* transmit fifo depth */
+
+/*
* Transmit queue subtype. These map directly to
* WME Access Categories (except for UPSD). Refer
* to Table 5 of the WME spec.
@@ -361,6 +428,23 @@
} HAL_POWER_MODE;
/*
+ * Enterprise mode flags
+ */
+#define AH_ENT_DUAL_BAND_DISABLE 0x00000001
+#define AH_ENT_CHAIN2_DISABLE 0x00000002
+#define AH_ENT_5MHZ_DISABLE 0x00000004
+#define AH_ENT_10MHZ_DISABLE 0x00000008
+#define AH_ENT_49GHZ_DISABLE 0x00000010
+#define AH_ENT_LOOPBACK_DISABLE 0x00000020
+#define AH_ENT_TPC_PERF_DISABLE 0x00000040
+#define AH_ENT_MIN_PKT_SIZE_DISABLE 0x00000080
+#define AH_ENT_SPECTRAL_PRECISION 0x00000300
+#define AH_ENT_SPECTRAL_PRECISION_S 8
+#define AH_ENT_RTSCTS_DELIM_WAR 0x00010000
+
+#define AH_FIRST_DESC_NDELIMS 60
+
+/*
* NOTE WELL:
* These are mapped to take advantage of the common locations for many of
* the bits on all of the currently supported MAC chips. This is to make
@@ -371,7 +455,10 @@
*/
typedef enum {
HAL_INT_RX = 0x00000001, /* Non-common mapping */
- HAL_INT_RXDESC = 0x00000002,
+ HAL_INT_RXDESC = 0x00000002, /* Legacy mapping */
+ HAL_INT_RXERR = 0x00000004,
+ HAL_INT_RXHP = 0x00000001, /* EDMA */
+ HAL_INT_RXLP = 0x00000002, /* EDMA */
HAL_INT_RXNOFRM = 0x00000008,
HAL_INT_RXEOL = 0x00000010,
HAL_INT_RXORN = 0x00000020,
@@ -378,11 +465,14 @@
HAL_INT_TX = 0x00000040, /* Non-common mapping */
HAL_INT_TXDESC = 0x00000080,
HAL_INT_TIM_TIMER= 0x00000100,
+ HAL_INT_MCI = 0x00000200,
+ HAL_INT_BBPANIC = 0x00000400,
HAL_INT_TXURN = 0x00000800,
HAL_INT_MIB = 0x00001000,
HAL_INT_RXPHY = 0x00004000,
HAL_INT_RXKCM = 0x00008000,
HAL_INT_SWBA = 0x00010000,
+ HAL_INT_BRSSI = 0x00020000,
HAL_INT_BMISS = 0x00040000,
HAL_INT_BNR = 0x00100000,
HAL_INT_TIM = 0x00200000, /* Non-common mapping */
@@ -392,6 +482,8 @@
HAL_INT_CABEND = 0x02000000, /* Non-common mapping */
HAL_INT_TSFOOR = 0x04000000, /* Non-common mapping */
HAL_INT_TBTT = 0x08000000, /* Non-common mapping */
+ /* Atheros ref driver has a generic timer interrupt now..*/
+ HAL_INT_GENTIMER = 0x08000000, /* Non-common mapping */
HAL_INT_CST = 0x10000000, /* Non-common mapping */
HAL_INT_GTT = 0x20000000, /* Non-common mapping */
HAL_INT_FATAL = 0x40000000, /* Non-common mapping */
@@ -414,18 +506,85 @@
| HAL_INT_RXKCM
| HAL_INT_SWBA
| HAL_INT_BMISS
+ | HAL_INT_BRSSI
| HAL_INT_BNR
| 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;
+
+/* XXX this is duplicate information! */
+typedef struct {
+ u_int32_t cyclecnt_diff; /* delta cycle count */
+ u_int32_t rxclr_cnt; /* rx clear count */
+ u_int32_t txframecnt_diff; /* delta tx frame count */
+ u_int32_t rxframecnt_diff; /* delta rx frame count */
+ u_int32_t listen_time; /* listen time in msec - time for which ch is free */
+ u_int32_t ofdmphyerr_cnt; /* OFDM err count since last reset */
+ u_int32_t cckphyerr_cnt; /* CCK err count since last reset */
+ u_int32_t ofdmphyerrcnt_diff; /* delta OFDM Phy Error Count */
+ HAL_BOOL valid; /* if the stats are valid*/
+} HAL_ANISTATS;
+
+typedef struct {
+ u_int8_t txctl_offset;
+ u_int8_t txctl_numwords;
+ u_int8_t txstatus_offset;
+ u_int8_t txstatus_numwords;
+
+ u_int8_t rxctl_offset;
+ u_int8_t rxctl_numwords;
+ u_int8_t rxstatus_offset;
+ u_int8_t rxstatus_numwords;
+
+ u_int8_t macRevision;
+} HAL_DESC_INFO;
+
+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_OUTPUT_MUX_AS_MCI_WLAN_DATA,
+ HAL_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK,
+ HAL_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA,
+ HAL_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK,
+ HAL_GPIO_OUTPUT_MUX_AS_WL_IN_TX,
+ HAL_GPIO_OUTPUT_MUX_AS_WL_IN_RX,
+ HAL_GPIO_OUTPUT_MUX_AS_BT_IN_TX,
+ HAL_GPIO_OUTPUT_MUX_AS_BT_IN_RX,
+ HAL_GPIO_OUTPUT_MUX_AS_RUCKUS_STROBE,
+ HAL_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA,
+ HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL0,
+ HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL1,
+ HAL_GPIO_OUTPUT_MUX_AS_SMARTANT_CTRL2,
+ HAL_GPIO_OUTPUT_MUX_NUM_ENTRIES
} HAL_GPIO_MUX_TYPE;
typedef enum {
@@ -434,6 +593,15 @@
HAL_GPIO_INTR_DISABLE = 2
} HAL_GPIO_INTR_TYPE;
+typedef struct halCounters {
+ u_int32_t tx_frame_count;
+ u_int32_t rx_frame_count;
+ u_int32_t rx_clear_count;
+ u_int32_t cycle_count;
+ u_int8_t is_rx_active; // true (1) or false (0)
+ u_int8_t is_tx_active; // true (1) or false (0)
+} HAL_COUNTERS;
+
typedef enum {
HAL_RFGAIN_INACTIVE = 0,
HAL_RFGAIN_READ_REQUESTED = 1,
@@ -456,6 +624,17 @@
uint32_t beacons;
} HAL_MIB_STATS;
+/*
+ * These bits represent what's in ah_currentRDext.
+ */
+typedef enum {
+ REG_EXT_FCC_MIDBAND = 0,
+ REG_EXT_JAPAN_MIDBAND = 1,
+ REG_EXT_FCC_DFS_HT40 = 2,
+ REG_EXT_JAPAN_NONDFS_HT40 = 3,
+ REG_EXT_JAPAN_DFS_HT40 = 4
+} REG_EXT_BITMAP;
+
enum {
HAL_MODE_11A = 0x001, /* 11a channels */
HAL_MODE_TURBO = 0x002, /* 11a turbo-only channels */
@@ -483,7 +662,7 @@
typedef struct {
int rateCount; /* NB: for proper padding */
- uint8_t rateCodeToIndex[144]; /* back mapping */
+ uint8_t rateCodeToIndex[256]; /* back mapping */
struct {
uint8_t valid; /* valid for rate control use */
uint8_t phy; /* CCK/OFDM/XR */
@@ -497,12 +676,12 @@
* rate; used for dur. calcs */
uint16_t lpAckDuration; /* long preamble ACK duration */
uint16_t spAckDuration; /* short preamble ACK duration*/
- } info[32];
+ } info[64];
} HAL_RATE_TABLE;
typedef struct {
u_int rs_count; /* number of valid entries */
- uint8_t rs_rates[32]; /* rates */
+ uint8_t rs_rates[64]; /* rates */
} HAL_RATE_SET;
/*
@@ -515,7 +694,8 @@
typedef struct {
u_int Tries;
- u_int Rate;
+ u_int Rate; /* hardware rate code */
+ u_int RateIndex; /* rate series table index */
u_int PktDuration;
u_int ChSel;
u_int RateFlags;
@@ -522,6 +702,8 @@
#define HAL_RATESERIES_RTS_CTS 0x0001 /* use rts/cts w/this series */
#define HAL_RATESERIES_2040 0x0002 /* use ext channel for series */
#define HAL_RATESERIES_HALFGI 0x0004 /* use half-gi for series */
+#define HAL_RATESERIES_STBC 0x0008 /* use STBC for series */
+ u_int tx_power_cap; /* in 1/2 dBm units XXX TODO */
} HAL_11N_RATE_SERIES;
typedef enum {
@@ -545,6 +727,11 @@
HAL_RX_CLEAR_EXT_LOW = 0x2, /* force extension channel to appear busy */
} HAL_HT_RXCLEAR;
+typedef enum {
+ HAL_FREQ_BAND_5GHZ = 0,
+ HAL_FREQ_BAND_2GHZ = 1,
+} HAL_FREQ_BAND;
+
/*
* Antenna switch control. By default antenna selection
* enables multiple (2) antenna use. To force use of the
@@ -566,7 +753,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 */
@@ -573,7 +760,19 @@
uint8_t kv_txmic[8]; /* TKIP TX MIC key (optional) */
} HAL_KEYVAL;
+/*
+ * This is the TX descriptor field which marks the key padding requirement.
+ * The naming is unfortunately unclear.
+ */
+#define AH_KEYTYPE_MASK 0x0F
typedef enum {
+ HAL_KEY_TYPE_CLEAR,
+ HAL_KEY_TYPE_WEP,
+ HAL_KEY_TYPE_AES,
+ HAL_KEY_TYPE_TKIP,
+} HAL_KEY_TYPE;
+
+typedef enum {
HAL_CIPHER_WEP = 0,
HAL_CIPHER_AES_OCB = 1,
HAL_CIPHER_AES_CCM = 2,
@@ -601,9 +800,16 @@
uint32_t bs_nexttbtt; /* next beacon in TU */
uint32_t bs_nextdtim; /* next DTIM in TU */
uint32_t bs_intval; /* beacon interval+flags */
+/*
+ * HAL_BEACON_PERIOD, HAL_BEACON_ENA and HAL_BEACON_RESET_TSF
+ * are all 1:1 correspondances with the pre-11n chip AR_BEACON
+ * register.
+ */
#define HAL_BEACON_PERIOD 0x0000ffff /* beacon interval period */
+#define HAL_BEACON_PERIOD_TU8 0x0007ffff /* beacon interval, tu/8 */
#define HAL_BEACON_ENA 0x00800000 /* beacon xmit enable */
#define HAL_BEACON_RESET_TSF 0x01000000 /* clear TSF */
+#define HAL_TSFOOR_THRESHOLD 0x00004240 /* TSF OOR thresh (16k uS) */
uint32_t bs_dtimperiod;
uint16_t bs_cfpperiod; /* CFP period in TU */
uint16_t bs_cfpmaxduration; /* max CFP duration in TU */
@@ -611,6 +817,7 @@
uint16_t bs_timoffset; /* byte offset to TIM bitmap */
uint16_t bs_bmissthreshold; /* beacon miss threshold */
uint32_t bs_sleepduration; /* max sleep duration */
+ uint32_t bs_tsfoor_threshold; /* TSF out of range threshold */
} HAL_BEACON_STATE;
/*
@@ -641,6 +848,7 @@
#define HAL_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
+
struct ath_desc;
struct ath_tx_status;
struct ath_rx_status;
@@ -658,7 +866,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;
/*
@@ -691,8 +903,11 @@
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;
+#define HAL_ANI_ALL 0xffffffff
+
/*
* This is the layout of the ANI INTMIT capability.
*
@@ -731,11 +946,28 @@
*/
int32_t pe_extchannel; /* Enable DFS on ext channel */
int32_t pe_enabled; /* Whether radar detection is enabled */
+ int32_t pe_enrelpwr;
+ int32_t pe_en_relstep_check;
} HAL_PHYERR_PARAM;
#define HAL_PHYERR_PARAM_NOVAL 65535
-#define HAL_PHYERR_PARAM_ENABLE 0x8000 /* Enable/Disable if applicable */
+typedef struct {
+ u_int16_t ss_fft_period; /* Skip interval for FFT reports */
+ u_int16_t ss_period; /* Spectral scan period */
+ u_int16_t ss_count; /* # of reports to return from ss_active */
+ u_int16_t ss_short_report;/* Set to report ony 1 set of FFT results */
+ u_int8_t radar_bin_thresh_sel; /* strong signal radar FFT threshold configuration */
+ u_int16_t ss_spectral_pri; /* are we doing a noise power cal ? */
+ int8_t ss_nf_cal[AH_MAX_CHAINS*2]; /* nf calibrated values for ctl+ext from eeprom */
+ int8_t ss_nf_pwr[AH_MAX_CHAINS*2]; /* nf pwr values for ctl+ext from eeprom */
+ int32_t ss_nf_temp_data; /* temperature data taken during nf scan */
+ int ss_enabled;
+ int ss_active;
+} HAL_SPECTRAL_PARAM;
+#define HAL_SPECTRAL_PARAM_NOVAL 0xFFFF
+#define HAL_SPECTRAL_PARAM_ENABLE 0x8000 /* Enable/Disable if applicable */
+
/*
* DFS operating mode flags.
*/
@@ -746,7 +978,40 @@
HAL_DFS_MKK4_DOMAIN = 3, /* Japan dfs domain */
} HAL_DFS_DOMAIN;
+
/*
+ * MFP decryption options for initializing the MAC.
+ */
+typedef enum {
+ HAL_MFP_QOSDATA = 0, /* Decrypt MFP frames like QoS data frames. All chips before Merlin. */
+ HAL_MFP_PASSTHRU, /* Don't decrypt MFP frames at all. Passthrough */
+ HAL_MFP_HW_CRYPTO /* hardware decryption enabled. Merlin can do it. */
+} HAL_MFP_OPT_T;
+
+/* LNA config supported */
+typedef enum {
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2 = 0,
+ HAL_ANT_DIV_COMB_LNA2 = 1,
+ HAL_ANT_DIV_COMB_LNA1 = 2,
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2 = 3,
+} HAL_ANT_DIV_COMB_LNA_CONF;
+
+typedef struct {
+ u_int8_t main_lna_conf;
+ u_int8_t alt_lna_conf;
+ u_int8_t fast_div_bias;
+ u_int8_t main_gaintb;
+ u_int8_t alt_gaintb;
+ u_int8_t antdiv_configgroup;
+ int8_t lna1_lna2_delta;
+} HAL_ANT_COMB_CONFIG;
+
+#define DEFAULT_ANTDIV_CONFIG_GROUP 0x00
+#define HAL_ANTDIV_CONFIG_GROUP_1 0x01
+#define HAL_ANTDIV_CONFIG_GROUP_2 0x02
+#define HAL_ANTDIV_CONFIG_GROUP_3 0x03
+
+/*
* Flag for setting QUIET period
*/
typedef enum {
@@ -770,6 +1035,183 @@
};
typedef struct hal_dfs_event HAL_DFS_EVENT;
+/*
+ * Generic Timer domain
+ */
+typedef enum {
+ HAL_GEN_TIMER_TSF = 0,
+ HAL_GEN_TIMER_TSF2,
+ HAL_GEN_TIMER_TSF_ANY
+} HAL_GEN_TIMER_DOMAIN;
+
+typedef enum {
+ HAL_RESET_NONE = 0x0,
+ HAL_RESET_BBPANIC = 0x1,
+} HAL_RESET_TYPE;
+
+/*
+ * 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_MCI_MAX_TX_PWR, /* Set max tx power for concurrent tx */
+ HAL_BT_COEX_MCI_FTP_STOMP_RX, /* Use a different weight for stomp low */
+} 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;
+
+struct hal_bb_panic_info {
+ u_int32_t status;
+ u_int32_t tsf;
+ u_int32_t phy_panic_wd_ctl1;
+ u_int32_t phy_panic_wd_ctl2;
+ u_int32_t phy_gen_ctrl;
+ u_int32_t rxc_pcnt;
+ u_int32_t rxf_pcnt;
+ u_int32_t txf_pcnt;
+ u_int32_t cycles;
+ u_int32_t wd;
+ u_int32_t det;
+ u_int32_t rdar;
+ u_int32_t r_odfm;
+ u_int32_t r_cck;
+ u_int32_t t_odfm;
+ u_int32_t t_cck;
+ u_int32_t agc;
+ u_int32_t src;
+};
+
+/* Serialize Register Access Mode */
+typedef enum {
+ SER_REG_MODE_OFF = 0,
+ SER_REG_MODE_ON = 1,
+ SER_REG_MODE_AUTO = 2,
+} SER_REG_MODE;
+
typedef struct
{
int ah_debug; /* only used if AH_DEBUG is defined */
@@ -779,6 +1221,50 @@
int ah_dma_beacon_response_time;/* in TU's */
int ah_sw_beacon_response_time; /* in TU's */
int ah_additional_swba_backoff; /* in TU's */
+ int ah_force_full_reset; /* force full chip reset rather then warm reset */
+ int ah_serialise_reg_war; /* force serialisation of register IO */
+
+ /* XXX these don't belong here, they're just for the ar9300 HAL port effort */
+ int ath_hal_desc_tpc; /* Per-packet TPC */
+ int ath_hal_sta_update_tx_pwr_enable; /* GreenTX */
+ int ath_hal_sta_update_tx_pwr_enable_S1; /* GreenTX */
+ int ath_hal_sta_update_tx_pwr_enable_S2; /* GreenTX */
+ int ath_hal_sta_update_tx_pwr_enable_S3; /* GreenTX */
+
+ /* I'm not sure what the default values for these should be */
+ int ath_hal_pll_pwr_save;
+ int ath_hal_pcie_power_save_enable;
+ int ath_hal_intr_mitigation_rx;
+ int ath_hal_intr_mitigation_tx;
+
+ int ath_hal_pcie_clock_req;
+#define AR_PCIE_PLL_PWRSAVE_CONTROL (1<<0)
+#define AR_PCIE_PLL_PWRSAVE_ON_D3 (1<<1)
+#define AR_PCIE_PLL_PWRSAVE_ON_D0 (1<<2)
+
+ int ath_hal_pcie_waen;
+ int ath_hal_pcie_ser_des_write;
+
+ /* these are important for correct AR9300 behaviour */
+ int ath_hal_ht_enable; /* needs to be enabled for AR9300 HT */
+ int ath_hal_diversity_control;
+ int ath_hal_antenna_switch_swap;
+ int ath_hal_ext_lna_ctl_gpio;
+ int ath_hal_spur_mode;
+ int ath_hal_6mb_ack; /* should set this to 1 for 11a/11na? */
+ int ath_hal_enable_msi; /* enable MSI interrupts (needed?) */
+ int ath_hal_beacon_filter_interval; /* ok to be 0 for now? */
+
+ /* For now, set this to 0 - net80211 needs to know about hardware MFP support */
+ int ath_hal_mfp_support;
+
+ int ath_hal_enable_ani; /* should set this.. */
+ int ath_hal_cwm_ignore_ext_cca;
+ int ath_hal_show_bb_panic;
+ int ath_hal_ant_ctrl_comm2g_switch_enable;
+ int ath_hal_ext_atten_margin_cfg;
+ int ath_hal_war70c;
+ uint32_t ath_hal_mci_config;
} HAL_OPS_CONFIG;
/*
@@ -809,6 +1295,9 @@
uint16_t *ah_eepromdata; /* eeprom buffer, if needed */
+ uint32_t ah_intrstate[8]; /* last int state */
+ uint32_t ah_syncstate; /* last sync intr state */
+
HAL_OPS_CONFIG ah_config;
const HAL_RATE_TABLE *__ahdecl(*ah_getRateTable)(struct ath_hal *,
u_int mode);
@@ -820,7 +1309,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*,
@@ -865,7 +1355,8 @@
u_int txRate2, u_int txTries2,
u_int txRate3, u_int txTries3);
HAL_BOOL __ahdecl(*ah_fillTxDesc)(struct ath_hal *, struct ath_desc *,
- u_int segLen, HAL_BOOL firstSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
+ u_int descId, u_int qcuId, HAL_BOOL firstSeg,
HAL_BOOL lastSeg, const struct ath_desc *);
HAL_STATUS __ahdecl(*ah_procTxDesc)(struct ath_hal *,
struct ath_desc *, struct ath_tx_status *);
@@ -873,10 +1364,20 @@
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);
+ void __ahdecl(*ah_getTxRawTxDesc)(struct ath_hal *, u_int32_t *);
/* 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*);
@@ -902,9 +1403,6 @@
const struct ieee80211_channel *);
void __ahdecl(*ah_procMibEvent)(struct ath_hal *,
const HAL_NODE_STATS *);
- void __ahdecl(*ah_rxAntCombDiversity)(struct ath_hal *,
- struct ath_rx_status *,
- unsigned long, int);
/* Misc Functions */
HAL_STATUS __ahdecl(*ah_getCapability)(struct ath_hal *,
@@ -934,6 +1432,7 @@
void __ahdecl(*ah_gpioSetIntr)(struct ath_hal*, u_int, uint32_t);
uint32_t __ahdecl(*ah_getTsf32)(struct ath_hal*);
uint64_t __ahdecl(*ah_getTsf64)(struct ath_hal*);
+ void __ahdecl(*ah_setTsf64)(struct ath_hal *, uint64_t);
void __ahdecl(*ah_resetTsf)(struct ath_hal*);
HAL_BOOL __ahdecl(*ah_detectCardPresent)(struct ath_hal*);
void __ahdecl(*ah_updateMibCounters)(struct ath_hal*,
@@ -959,6 +1458,8 @@
HAL_STATUS __ahdecl(*ah_setQuiet)(struct ath_hal *ah, uint32_t period,
uint32_t duration, uint32_t nextStart,
HAL_QUIET_FLAG flag);
+ void __ahdecl(*ah_setChainMasks)(struct ath_hal *,
+ uint32_t, uint32_t);
/* DFS functions */
void __ahdecl(*ah_enableDfs)(struct ath_hal *ah,
@@ -965,11 +1466,24 @@
HAL_PHYERR_PARAM *pe);
void __ahdecl(*ah_getDfsThresh)(struct ath_hal *ah,
HAL_PHYERR_PARAM *pe);
+ HAL_BOOL __ahdecl(*ah_getDfsDefaultThresh)(struct ath_hal *ah,
+ HAL_PHYERR_PARAM *pe);
HAL_BOOL __ahdecl(*ah_procRadarEvent)(struct ath_hal *ah,
struct ath_rx_status *rxs, uint64_t fulltsf,
const char *buf, HAL_DFS_EVENT *event);
HAL_BOOL __ahdecl(*ah_isFastClockEnabled)(struct ath_hal *ah);
+ /* Spectral Scan functions */
+ void __ahdecl(*ah_spectralConfigure)(struct ath_hal *ah,
+ HAL_SPECTRAL_PARAM *sp);
+ void __ahdecl(*ah_spectralGetConfig)(struct ath_hal *ah,
+ HAL_SPECTRAL_PARAM *sp);
+ void __ahdecl(*ah_spectralStart)(struct ath_hal *);
+ void __ahdecl(*ah_spectralStop)(struct ath_hal *);
+ HAL_BOOL __ahdecl(*ah_spectralIsEnabled)(struct ath_hal *);
+ HAL_BOOL __ahdecl(*ah_spectralIsActive)(struct ath_hal *);
+ /* XXX getNfPri() and getNfExt() */
+
/* Key Cache Functions */
uint32_t __ahdecl(*ah_getKeyCacheSize)(struct ath_hal*);
HAL_BOOL __ahdecl(*ah_resetKeyCacheEntry)(struct ath_hal*, uint16_t);
@@ -1001,9 +1515,12 @@
/* 802.11n Functions */
HAL_BOOL __ahdecl(*ah_chainTxDesc)(struct ath_hal *,
- struct ath_desc *, u_int, u_int, HAL_PKT_TYPE,
- u_int, HAL_CIPHER, uint8_t, u_int, HAL_BOOL,
- HAL_BOOL);
+ struct ath_desc *,
+ HAL_DMA_ADDR *bufAddrList,
+ uint32_t *segLenList,
+ u_int, u_int, HAL_PKT_TYPE,
+ u_int, HAL_CIPHER, uint8_t, HAL_BOOL,
+ HAL_BOOL, HAL_BOOL);
HAL_BOOL __ahdecl(*ah_setupFirstTxDesc)(struct ath_hal *,
struct ath_desc *, u_int, u_int, u_int,
u_int, u_int, u_int, u_int, u_int);
@@ -1012,12 +1529,32 @@
void __ahdecl(*ah_set11nRateScenario)(struct ath_hal *,
struct ath_desc *, u_int, u_int,
HAL_11N_RATE_SERIES [], u_int, u_int);
+
+ /*
+ * The next 4 (set11ntxdesc -> set11naggrlast) are specific
+ * to the EDMA HAL. Descriptors are chained together by
+ * using filltxdesc (not ChainTxDesc) and then setting the
+ * aggregate flags appropriately using first/middle/last.
+ */
+ void __ahdecl(*ah_set11nTxDesc)(struct ath_hal *,
+ void *, u_int, HAL_PKT_TYPE, u_int, u_int,
+ u_int);
+ void __ahdecl(*ah_set11nAggrFirst)(struct ath_hal *,
+ struct ath_desc *, u_int, u_int);
void __ahdecl(*ah_set11nAggrMiddle)(struct ath_hal *,
struct ath_desc *, u_int);
+ void __ahdecl(*ah_set11nAggrLast)(struct ath_hal *,
+ struct ath_desc *);
void __ahdecl(*ah_clr11nAggr)(struct ath_hal *,
struct ath_desc *);
void __ahdecl(*ah_set11nBurstDuration)(struct ath_hal *,
struct ath_desc *, u_int);
+ void __ahdecl(*ah_set11nVirtMoreFrag)(struct ath_hal *,
+ struct ath_desc *, u_int);
+
+ 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 *,
HAL_HT_MACMODE);
@@ -1030,6 +1567,28 @@
HAL_BOOL __ahdecl(*ah_getPendingInterrupts)(struct ath_hal*, HAL_INT*);
HAL_INT __ahdecl(*ah_getInterrupts)(struct ath_hal*);
HAL_INT __ahdecl(*ah_setInterrupts)(struct ath_hal*, HAL_INT);
+
+ /* Bluetooth Coexistence functions */
+ void __ahdecl(*ah_btCoexSetInfo)(struct ath_hal *,
+ HAL_BT_COEX_INFO *);
+ void __ahdecl(*ah_btCoexSetConfig)(struct ath_hal *,
+ HAL_BT_COEX_CONFIG *);
+ void __ahdecl(*ah_btCoexSetQcuThresh)(struct ath_hal *,
+ int);
+ void __ahdecl(*ah_btCoexSetWeights)(struct ath_hal *,
+ uint32_t);
+ void __ahdecl(*ah_btCoexSetBmissThresh)(struct ath_hal *,
+ uint32_t);
+ void __ahdecl(*ah_btCoexSetParameter)(struct ath_hal *,
+ uint32_t, uint32_t);
+ void __ahdecl(*ah_btCoexDisable)(struct ath_hal *);
+ int __ahdecl(*ah_btCoexEnable)(struct ath_hal *);
+
+ /* LNA diversity configuration */
+ void __ahdecl(*ah_divLnaConfGet)(struct ath_hal *,
+ HAL_ANT_COMB_CONFIG *);
+ void __ahdecl(*ah_divLnaConfSet)(struct ath_hal *,
+ HAL_ANT_COMB_CONFIG *);
};
/*
@@ -1122,6 +1681,12 @@
extern u_int __ahdecl ath_hal_getwirelessmodes(struct ath_hal*);
/*
+ * Get the HAL wireless mode for the given channel.
+ */
+extern int ath_hal_get_curmode(struct ath_hal *ah,
+ const struct ieee80211_channel *chan);
+
+/*
* Calculate the packet TX time for a legacy or 11n frame
*/
extern uint32_t __ahdecl ath_hal_pkt_txtime(struct ath_hal *ah,
@@ -1156,4 +1721,20 @@
*/
int __ahdecl ath_hal_getcca(struct ath_hal *ah);
+/*
+ * Read EEPROM data from ah_eepromdata
+ */
+HAL_BOOL __ahdecl ath_hal_EepromDataRead(struct ath_hal *ah,
+ u_int off, uint16_t *data);
+
+/*
+ * For now, simply pass through MFP frames.
+ */
+static inline u_int32_t
+ath_hal_get_mfp_qos(struct ath_hal *ah)
+{
+ //return AH_PRIVATE(ah)->ah_mfp_qos;
+ return HAL_MFP_QOSDATA;
+}
+
#endif /* _ATH_AH_H_ */
Modified: trunk/sys/dev/ath/ath_hal/ah_debug.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_debug.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_debug.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_debug.h 249131 2013-04-05 07:41:47Z adrian $
*/
#ifndef _ATH_AH_DEBUG_H_
#define _ATH_AH_DEBUG_H_
@@ -47,8 +48,15 @@
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_FCS_RTT = 0x10000000,
+ HAL_DEBUG_BT_COEX = 0x20000000,
- HAL_DEBUG_UNMASKABLE = 0xf0000000, /* always printed */
+ HAL_DEBUG_UNMASKABLE = 0x80000000, /* always printed */
HAL_DEBUG_ANY = 0xffffffff
};
#endif /* _ATH_AH_DEBUG_H_ */
Modified: trunk/sys/dev/ath/ath_hal/ah_decode.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_decode.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_decode.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_decode.h 233887 2012-04-04 20:46:20Z adrian $
*/
#ifndef _ATH_AH_DECODE_H_
#define _ATH_AH_DECODE_H_
@@ -29,6 +30,7 @@
* existing file.
*/
struct athregrec {
+ uint32_t threadid;
uint32_t op : 8,
reg : 24;
uint32_t val;
Modified: trunk/sys/dev/ath/ath_hal/ah_desc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_desc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_desc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_desc.h 251399 2013-06-05 00:39:20Z adrian $
*/
#ifndef _DEV_ATH_DESC_H
@@ -23,6 +24,19 @@
#include "opt_ah.h" /* NB: required for AH_SUPPORT_AR5416 */
/*
+ * For now, define this for the structure definitions.
+ * Because of how the HAL / driver module currently builds,
+ * it's not very feasible to build the module without
+ * this defined. The rest of the code (eg in the driver
+ * body) can work fine with these fields being uninitialised;
+ * they'll be initialised to 0 anyway.
+ */
+
+#ifndef AH_SUPPORT_AR5416
+#define AH_SUPPORT_AR5416 1
+#endif
+
+/*
* Transmit descriptor status. This structure is filled
* in only after the tx descriptor process method finds a
* ``done'' descriptor; at which point it returns something
@@ -44,15 +58,19 @@
uint8_t ts_finaltsi; /* final transmit series index */
#ifdef AH_SUPPORT_AR5416
/* 802.11n status */
- uint8_t ts_flags; /* misc flags */
- int8_t ts_rssi_ctl[3]; /* tx ack RSSI [ctl, chain 0-2] */
- int8_t ts_rssi_ext[3]; /* tx ack RSSI [ext, chain 0-2] */
+ uint8_t ts_flags; /* misc flags */
+ uint8_t ts_queue_id; /* AR9300: TX queue id */
+ uint8_t ts_desc_id; /* AR9300: TX descriptor id */
+ uint8_t ts_tid; /* TID */
/* #define ts_rssi ts_rssi_combined */
- uint32_t ts_ba_low; /* blockack bitmap low */
- uint32_t ts_ba_high; /* blockack bitmap high */
- uint32_t ts_evm0; /* evm bytes */
- uint32_t ts_evm1;
- uint32_t ts_evm2;
+ uint32_t ts_ba_low; /* blockack bitmap low */
+ uint32_t ts_ba_high; /* blockack bitmap high */
+ uint32_t ts_evm0; /* evm bytes */
+ uint32_t ts_evm1;
+ uint32_t ts_evm2;
+ int8_t ts_rssi_ctl[3]; /* tx ack RSSI [ctl, chain 0-2] */
+ int8_t ts_rssi_ext[3]; /* tx ack RSSI [ext, chain 0-2] */
+ uint8_t ts_pad[2];
#endif /* AH_SUPPORT_AR5416 */
};
@@ -108,11 +126,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 */
@@ -124,17 +143,47 @@
#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 */
+#define HAL_RX_STBC 0x0200 /* Is an STBC frame */
+/*
+ * This is the format of RSSI[2] on the AR9285/AR9485.
+ * It encodes the LNA configuration information.
+ *
+ * For boards with an external diversity antenna switch,
+ * HAL_RX_LNA_EXTCFG encodes which configuration was
+ * used (antenna 1 or antenna 2.) This feeds into the
+ * switch table and ensures that the given antenna was
+ * connected to an LNA.
+ */
+#define HAL_RX_LNA_LNACFG 0x80 /* 1 = main LNA config used, 0 = ALT */
+#define HAL_RX_LNA_EXTCFG 0x40 /* 0 = external diversity ant1, 1 = ant2 */
+#define HAL_RX_LNA_CFG_USED 0x30 /* 2 bits; LNA config used on RX */
+#define HAL_RX_LNA_CFG_USED_S 4
+#define HAL_RX_LNA_CFG_MAIN 0x0c /* 2 bits; "Main" LNA config */
+#define HAL_RX_LNA_CFG_ALT 0x02 /* 2 bits; "Alt" LNA config */
+
+/*
+ * This is the format of RSSI_EXT[2] on the AR9285/AR9485.
+ * It encodes the switch table configuration and fast diversity
+ * value.
+ */
+#define HAL_RX_LNA_FASTDIV 0x40 /* 1 = fast diversity measurement done */
+#define HAL_RX_LNA_SWITCH_0 0x30 /* 2 bits; sw_0[1:0] */
+#define HAL_RX_LNA_SWITCH_COM 0x0f /* 4 bits, sw_com[3:0] */
+
enum {
HAL_PHYERR_UNDERRUN = 0, /* Transmit underrun */
HAL_PHYERR_TIMING = 1, /* Timing error */
@@ -164,6 +213,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 */
@@ -200,6 +251,12 @@
uint32_t ds_hw[HAL_DESC_HW_SIZE]; /* opaque h/w region */
};
+struct ath_desc_txedma {
+ uint32_t ds_info;
+ uint32_t ds_link;
+ uint32_t ds_hw[21]; /* includes buf/len */
+};
+
struct ath_desc_status {
union {
struct ath_tx_status tx;/* xmit status */
@@ -211,6 +268,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 */
@@ -222,6 +280,8 @@
#define HAL_TXDESC_EXT_ONLY 0x0080 /* send on ext channel only (11n) */
#define HAL_TXDESC_EXT_AND_CTL 0x0100 /* send on ext + ctl channels (11n) */
#define HAL_TXDESC_VMF 0x0200 /* virtual more frag */
+#define HAL_TXDESC_LOWRXCHAIN 0x0400 /* switch to low RX chain */
+#define HAL_TXDESC_LDPC 0x1000
/* flags passed to rx descriptor setup methods */
#define HAL_RXDESC_INTREQ 0x0020 /* enable per-descriptor interrupt */
Modified: trunk/sys/dev/ath/ath_hal/ah_devid.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_devid.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_devid.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_devid.h 250166 2013-05-02 00:59:39Z adrian $
*/
#ifndef _DEV_ATH_DEVID_H_
@@ -73,16 +74,27 @@
/* AR5416 compatible devid's */
#define AR5416_DEVID_PCI 0x0023 /* AR5416 PCI (MB/CB) Owl */
-#define AR5416_DEVID_PCIE 0x0024 /* AR5416 PCI-E (XB) Owl */
+#define AR5416_DEVID_PCIE 0x0024 /* AR5418 PCI-E (XB) Owl */
#define AR5416_AR9130_DEVID 0x000b /* AR9130 SoC WiMAC */
#define AR9160_DEVID_PCI 0x0027 /* AR9160 PCI Sowl */
#define AR9280_DEVID_PCI 0x0029 /* AR9280 PCI Merlin */
-#define AR9280_DEVID_PCIE 0x002a /* AR9280 PCI-E Merlin */
+#define AR9280_DEVID_PCIE 0x002a /* AR9220 PCI-E Merlin */
#define AR9285_DEVID_PCIE 0x002b /* AR9285 PCI-E Kite */
#define AR2427_DEVID_PCIE 0x002c /* AR2427 PCI-E w/ 802.11n bonded out */
#define AR9287_DEVID_PCI 0x002d /* AR9227 PCI Kiwi */
#define AR9287_DEVID_PCIE 0x002e /* AR9287 PCI-E Kiwi */
+/* AR9300 */
+#define AR9300_DEVID_AR9380_PCIE 0x0030
+#define AR9300_DEVID_EMU_PCIE 0xabcd
+#define AR9300_DEVID_AR9340 0x0031
+#define AR9300_DEVID_AR9485_PCIE 0x0032
+#define AR9300_DEVID_AR9580_PCIE 0x0033
+#define AR9300_DEVID_AR946X_PCIE 0x0034
+#define AR9300_DEVID_AR9330 0x0035
+#define AR9300_DEVID_QCA9565 0x0036
+#define AR9300_DEVID_QCA955X 0x0039
+
#define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */
#define AR_SUBVENDOR_ID_NEW_A 0x7065 /* Update device to new RD */
#endif /* _DEV_ATH_DEVID_H */
Modified: trunk/sys/dev/ath/ath_hal/ah_diagcodes.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_diagcodes.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_diagcodes.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_diagcodes.h 239629 2012-08-24 00:17:39Z adrian $
*/
#ifndef _ATH_AH_DIAGCODES_H_
#define _ATH_AH_DIAGCODES_H_
@@ -63,6 +64,10 @@
HAL_DIAG_CHECK_HANGS = 32, /* check h/w hangs */
HAL_DIAG_SETREGS = 33, /* write registers */
HAL_DIAG_CHANSURVEY = 34, /* channel survey */
+ HAL_DIAG_PRINT_REG = 35,
+ HAL_DIAG_PRINT_REG_ALL = 36,
+ HAL_DIAG_CHANNELS = 37,
+ HAL_DIAG_PRINT_REG_COUNTER = 38,
};
#endif /* _ATH_AH_DIAGCODES_H_ */
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom.h 239637 2012-08-24 01:14:00Z adrian $
*/
#ifndef _ATH_AH_EEPROM_H_
#define _ATH_AH_EEPROM_H_
@@ -105,6 +106,10 @@
AR_EEP_TEMPSENSE_SLOPE, /* int8_t* */
AR_EEP_TEMPSENSE_SLOPE_PAL_ON, /* int8_t* */
AR_EEP_FRAC_N_5G, /* uint8_t* */
+
+ /* New fields for AR9300 and later */
+ AR_EEP_DRIVE_STRENGTH,
+ AR_EEP_PAPRD_ENABLED,
};
typedef struct {
@@ -127,6 +132,30 @@
#define CTL_2GHT40 7
#define CTL_5GHT40 8
+/* XXX must match what FCC/MKK/ETSI are defined as in ah_regdomain.h */
+#define HAL_REG_DMN_MASK 0xf0
+#define HAL_REGDMN_FCC 0x10
+#define HAL_REGDMN_MKK 0x40
+#define HAL_REGDMN_ETSI 0x30
+
+#define is_reg_dmn_fcc(reg_dmn) \
+ (((reg_dmn & HAL_REG_DMN_MASK) == HAL_REGDMN_FCC) ? 1 : 0)
+#define is_reg_dmn_etsi(reg_dmn) \
+ (((reg_dmn & HAL_REG_DMN_MASK) == HAL_REGDMN_ETSI) ? 1 : 0)
+#define is_reg_dmn_mkk(reg_dmn) \
+ (((reg_dmn & HAL_REG_DMN_MASK) == HAL_REGDMN_MKK) ? 1 : 0)
+
+#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080
+#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100
+#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800
+
+/* regulatory capabilities prior to eeprom version 4.0 */
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
+
#define AR_NO_SPUR 0x8000
/* XXX exposed to chip code */
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2010 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_9287.c 239704 2012-08-26 04:26:49Z adrian $
*/
#include "opt_ah.h"
@@ -292,7 +293,7 @@
{
#define NW(a) (sizeof(a) / sizeof(uint16_t))
HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom;
- uint16_t *eep_data, magic = 0;
+ uint16_t *eep_data, magic;
HAL_BOOL need_swap;
u_int w, off, len;
uint32_t sum;
@@ -310,13 +311,13 @@
"%s Error reading Eeprom MAGIC\n", __func__);
return HAL_EEREAD;
}
+ HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n",
+ __func__, magic);
+ if (magic != AR5416_EEPROM_MAGIC) {
+ HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n");
+ return HAL_EEMAGIC;
+ }
}
- HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n",
- __func__, magic);
- if (magic != AR5416_EEPROM_MAGIC) {
- HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n");
- return HAL_EEMAGIC;
- }
ee = ath_hal_malloc(sizeof(HAL_EEPROM_9287));
if (ee == AH_NULL) {
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_9287.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Atheros Communications Inc.
*
@@ -13,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.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_9287.h 223615 2011-06-28 00:01:55Z adrian $
*/
#ifndef __AH_EEPROM_9287_H__
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v1.c 221896 2011-05-14 15:12:02Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v1.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v1.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _ATH_AH_EEPROM_V1_H_
#define _ATH_AH_EEPROM_V1_H_
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v14.c 224519 2011-07-30 13:45:12Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v14.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v14.h 224519 2011-07-30 13:45:12Z adrian $
*/
#ifndef _AH_EEPROM_V14_H_
#define _AH_EEPROM_V14_H_
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v3.c 221896 2011-05-14 15:12:02Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v3.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v3.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _ATH_AH_EEPROM_V3_H_
#define _ATH_AH_EEPROM_V3_H_
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2009 Rui Paulo <rpaulo at FreeBSD.org>
* Copyright (c) 2008 Sam Leffler, Errno Consulting
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v4k.c 234508 2012-04-20 21:56:13Z adrian $
*/
#include "opt_ah.h"
@@ -281,7 +282,7 @@
{
#define NW(a) (sizeof(a) / sizeof(uint16_t))
HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom;
- uint16_t *eep_data, magic = 0;
+ uint16_t *eep_data, magic;
HAL_BOOL need_swap;
u_int w, off, len;
uint32_t sum;
Modified: trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_eeprom_v4k.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2009 Rui Paulo <rpaulo at FreeBSD.org>
* Copyright (c) 2008 Sam Leffler, Errno Consulting
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_eeprom_v4k.h 220946 2011-04-22 10:57:46Z adrian $
*/
#ifndef _AH_EEPROM_V4K_H_
#define _AH_EEPROM_V4K_H_
Modified: trunk/sys/dev/ath/ath_hal/ah_internal.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_internal.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_internal.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_internal.h 252236 2013-06-26 04:46:03Z adrian $
*/
#ifndef _ATH_AH_INTERAL_H_
#define _ATH_AH_INTERAL_H_
@@ -30,6 +31,10 @@
#include <net80211/_ieee80211.h>
#include "opt_ah.h" /* needed for AH_SUPPORT_AR5416 */
+#ifndef AH_SUPPORT_AR5416
+#define AH_SUPPORT_AR5416 1
+#endif
+
#ifndef NBBY
#define NBBY 8 /* number of bits/byte */
#endif
@@ -75,6 +80,11 @@
} HAL_PHYDIAG_CAPS;
/*
+ * Enable/disable strong signal fast diversity
+ */
+#define HAL_CAP_STRONG_DIV 2
+
+/*
* Each chip or class of chips registers to offer support.
*/
struct ath_hal_chip {
@@ -127,7 +137,42 @@
#define AH_MAXCHAN 96
#endif
+#define HAL_NF_CAL_HIST_LEN_FULL 5
+#define HAL_NF_CAL_HIST_LEN_SMALL 1
+#define HAL_NUM_NF_READINGS 6 /* 3 chains * (ctl + ext) */
+#define HAL_NF_LOAD_DELAY 1000
+
/*
+ * PER_CHAN doesn't work for now, as it looks like the device layer
+ * has to pre-populate the per-channel list with nominal values.
+ */
+//#define ATH_NF_PER_CHAN 1
+
+typedef struct {
+ u_int8_t curr_index;
+ int8_t invalidNFcount; /* TO DO: REMOVE THIS! */
+ int16_t priv_nf[HAL_NUM_NF_READINGS];
+} HAL_NFCAL_BASE;
+
+typedef struct {
+ HAL_NFCAL_BASE base;
+ int16_t nf_cal_buffer[HAL_NF_CAL_HIST_LEN_FULL][HAL_NUM_NF_READINGS];
+} HAL_NFCAL_HIST_FULL;
+
+typedef struct {
+ HAL_NFCAL_BASE base;
+ int16_t nf_cal_buffer[HAL_NF_CAL_HIST_LEN_SMALL][HAL_NUM_NF_READINGS];
+} HAL_NFCAL_HIST_SMALL;
+
+#ifdef ATH_NF_PER_CHAN
+typedef HAL_NFCAL_HIST_FULL HAL_CHAN_NFCAL_HIST;
+#define AH_HOME_CHAN_NFCAL_HIST(ah, ichan) (ichan ? &ichan->nf_cal_hist: NULL)
+#else
+typedef HAL_NFCAL_HIST_SMALL HAL_CHAN_NFCAL_HIST;
+#define AH_HOME_CHAN_NFCAL_HIST(ah, ichan) (&AH_PRIVATE(ah)->nf_cal_hist)
+#endif /* ATH_NF_PER_CHAN */
+
+/*
* Internal per-channel state. These are found
* using ic_devdata in the ieee80211_channel.
*/
@@ -144,10 +189,16 @@
int16_t rawNoiseFloor;
int16_t noiseFloorAdjust;
#ifdef AH_SUPPORT_AR5416
- int16_t noiseFloorCtl[AH_MIMO_MAX_CHAINS];
- int16_t noiseFloorExt[AH_MIMO_MAX_CHAINS];
+ int16_t noiseFloorCtl[AH_MAX_CHAINS];
+ int16_t noiseFloorExt[AH_MAX_CHAINS];
#endif /* AH_SUPPORT_AR5416 */
uint16_t mainSpur; /* cached spur value for this channel */
+
+ /*XXX TODO: make these part of privFlags */
+ uint8_t paprd_done:1, /* 1: PAPRD DONE, 0: PAPRD Cal not done */
+ paprd_table_write_done:1; /* 1: DONE, 0: Cal data write not done */
+ int one_time_cals_done;
+ HAL_CHAN_NFCAL_HIST nf_cal_hist;
} HAL_CHANNEL_INTERNAL;
/* channel requires noise floor check */
@@ -208,8 +259,30 @@
halBssidMatchSupport : 1,
hal4kbSplitTransSupport : 1,
halHasRxSelfLinkedTail : 1,
- halSupportsFastClock5GHz : 1, /* Hardware supports 5ghz fast clock; check eeprom/channel before using */
- halHasLongRxDescTsf : 1;
+ halSupportsFastClock5GHz : 1,
+ halHasLongRxDescTsf : 1,
+ halHasBBReadWar : 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,
+ hal49GhzSupport : 1,
+ halAntDivCombSupport : 1,
+ halAntDivCombSupportOrg : 1,
+ halRadioRetentionSupport : 1,
+ halSpectralScanSupport : 1,
+ halRxUsingLnaMixing : 1;
+
uint32_t halWirelessModes;
uint16_t halTotalQueues;
uint16_t halKeyCacheSize;
@@ -225,11 +298,33 @@
uint32_t halIntrMask;
uint8_t halTxStreams;
uint8_t halRxStreams;
+ HAL_MFP_OPT_T halMfpSupport;
+
+ /* AR9300 HAL porting capabilities */
+ int hal_paprd_enabled;
+ int hal_pcie_lcr_offset;
+ int hal_pcie_lcr_extsync_en;
+ int halNumTxMaps;
+ int halTxDescLen;
+ int halTxStatusLen;
+ int halRxStatusLen;
+ int halRxHpFifoDepth;
+ int halRxLpFifoDepth;
+ uint32_t halRegCap; /* XXX needed? */
+ int halNumMRRetries;
+ int hal_ani_poll_interval;
+ int hal_channel_switch_time_usec;
} HAL_CAPABILITIES;
struct regDomain;
/*
+ * Definitions for ah_flags in ath_hal_private
+ */
+#define AH_USE_EEPROM 0x1
+#define AH_IS_HB63 0x2
+
+/*
* The ``private area'' follows immediately after the ``public area''
* in the data structure returned by ath_hal_attach. Private data are
* used by device-independent code such as the regulatory domain support.
@@ -288,7 +383,9 @@
uint16_t ah_phyRev; /* PHY revision */
uint16_t ah_analog5GhzRev; /* 2GHz radio revision */
uint16_t ah_analog2GhzRev; /* 5GHz radio revision */
+ uint32_t ah_flags; /* misc flags */
uint8_t ah_ispcie; /* PCIE, special treatment */
+ uint8_t ah_devType; /* card type - CB, PCI, PCIe */
HAL_OPMODE ah_opmode; /* operating mode from reset */
const struct ieee80211_channel *ah_curchan;/* operating channel */
@@ -297,6 +394,7 @@
int16_t ah_powerLimit; /* tx power cap */
uint16_t ah_maxPowerLevel; /* calculated max tx power */
u_int ah_tpScale; /* tx power scale factor */
+ u_int16_t ah_extraTxPow; /* low rates extra-txpower */
uint32_t ah_11nCompat; /* 11n compat controls */
/*
@@ -321,6 +419,10 @@
*/
uint32_t ah_fatalState[6]; /* AR_ISR+shadow regs */
int ah_rxornIsFatal; /* how to treat HAL_INT_RXORN */
+
+#ifndef ATH_NF_PER_CHAN
+ HAL_NFCAL_HIST_FULL nf_cal_hist;
+#endif /* ! ATH_NF_PER_CHAN */
};
#define AH_PRIVATE(_ah) ((struct ath_hal_private *)(_ah))
@@ -349,13 +451,20 @@
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) \
(_ah)->ah_setInterrupts(_ah, _mask)
+#define ath_hal_isrfkillenabled(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 1, AH_NULL) == HAL_OK)
+#define ath_hal_enable_rfkill(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_RFSILENT, 1, _v, AH_NULL)
+#define ath_hal_hasrfkill_int(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 3, AH_NULL) == HAL_OK)
+
#define ath_hal_eepromDetach(_ah) do { \
if (AH_PRIVATE(_ah)->ah_eepromDetach != AH_NULL) \
AH_PRIVATE(_ah)->ah_eepromDetach(_ah); \
@@ -472,10 +581,23 @@
OS_REG_WRITE(_a, _r, OS_REG_READ(_a, _r) | (_f))
#define OS_REG_CLR_BIT(_a, _r, _f) \
OS_REG_WRITE(_a, _r, OS_REG_READ(_a, _r) &~ (_f))
+#define OS_REG_IS_BIT_SET(_a, _r, _f) \
+ ((OS_REG_READ(_a, _r) & (_f)) != 0)
+#define OS_REG_RMW_FIELD_ALT(_a, _r, _f, _v) \
+ OS_REG_WRITE(_a, _r, \
+ (OS_REG_READ(_a, _r) &~(_f<<_f##_S)) | \
+ (((_v) << _f##_S) & (_f<<_f##_S)))
+#define OS_REG_READ_FIELD(_a, _r, _f) \
+ (((OS_REG_READ(_a, _r) & _f) >> _f##_S))
+#define OS_REG_READ_FIELD_ALT(_a, _r, _f) \
+ ((OS_REG_READ(_a, _r) >> (_f##_S))&(_f))
/* 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)
+ 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,
@@ -503,26 +625,15 @@
extern int ath_hal_debug; /* Global debug flags */
/*
- * This is used for global debugging, when ahp doesn't yet have the
- * related debugging state. For example, during probe/attach.
+ * The typecast is purely because some callers will pass in
+ * AH_NULL directly rather than using a NULL ath_hal pointer.
*/
-#define HALDEBUG_G(_ah, __m, ...) \
- do { \
- if ((__m) == HAL_DEBUG_UNMASKABLE || \
- ath_hal_debug & (__m)) { \
- DO_HALDEBUG((_ah), (__m), __VA_ARGS__); \
- } \
- } while (0);
-
-/*
- * This is used for local debugging, when ahp isn't NULL and
- * thus may have debug flags set.
- */
#define HALDEBUG(_ah, __m, ...) \
do { \
if ((__m) == HAL_DEBUG_UNMASKABLE || \
ath_hal_debug & (__m) || \
- (_ah)->ah_config.ah_debug & (__m)) { \
+ ((_ah) != NULL && \
+ ((struct ath_hal *) (_ah))->ah_config.ah_debug & (__m))) { \
DO_HALDEBUG((_ah), (__m), __VA_ARGS__); \
} \
} while(0);
@@ -531,7 +642,6 @@
__printflike(3,4);
#else
#define HALDEBUG(_ah, __m, ...)
-#define HALDEBUG_G(_ah, __m, ...)
#endif /* AH_DEBUG */
/*
@@ -630,6 +740,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,
@@ -649,6 +799,17 @@
| HAL_MAC_HANG_UNKNOWN,
};
+/* Merge these with above */
+typedef enum hal_hw_hangs {
+ HAL_DFS_BB_HANG_WAR = 0x1,
+ HAL_RIFS_BB_HANG_WAR = 0x2,
+ HAL_RX_STUCK_LOW_BB_HANG_WAR = 0x4,
+ HAL_MAC_HANG_WAR = 0x8,
+ HAL_PHYRESTART_CLR_WAR = 0x10,
+ HAL_MAC_HANG_DETECTED = 0x40000000,
+ HAL_BB_HANG_DETECTED = 0x80000000
+} hal_hw_hangs_t;
+
/*
* Device revision information.
*/
@@ -830,5 +991,40 @@
AH_PRIVATE((_ah))->ah_caps.halSupportsFastClock5GHz && \
ath_hal_eepromGetFlag((_ah), AR_EEP_FSTCLK_5G))
+/*
+ * Fetch the maximum regulatory domain power for the given channel
+ * in 1/2dBm steps.
+ */
+static inline int
+ath_hal_get_twice_max_regpower(struct ath_hal_private *ahp,
+ const HAL_CHANNEL_INTERNAL *ichan, const struct ieee80211_channel *chan)
+{
+ struct ath_hal *ah = &ahp->h;
+ if (! chan) {
+ ath_hal_printf(ah, "%s: called with chan=NULL!\n", __func__);
+ return (0);
+ }
+ return (chan->ic_maxpower);
+}
+
+/*
+ * Get the maximum antenna gain allowed, in 1/2dBm steps.
+ */
+static inline int
+ath_hal_getantennaallowed(struct ath_hal *ah,
+ const struct ieee80211_channel *chan)
+{
+
+ if (! chan)
+ return (0);
+
+ return (chan->ic_maxantgain);
+}
+
+/*
+ * Map the given 2GHz channel to an IEEE number.
+ */
+extern int ath_hal_mhz2ieee_2ghz(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
+
#endif /* _ATH_AH_INTERAL_H_ */
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2011 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_ctry.h 224226 2011-07-20 12:46:58Z adrian $
*/
#ifndef __AH_REGDOMAIN_CTRY_H__
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2006 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_domains.h 248677 2013-03-24 04:42:56Z adrian $
*/
#ifndef __AH_REGDOMAIN_DOMAINS_H__
@@ -741,6 +742,31 @@
WG1_2467_2467),
.chan11g_turbo = BM1(T3_2437_2437)},
+ {.regDmnEnum = WORC_WORLD,
+ .conformanceTestLimit = NO_CTL,
+ .dfsMask = DFS_FCC3 | DFS_ETSI,
+ .pscan = PSCAN_WWR,
+ .flags = ADHOC_PER_11D,
+ .chan11a = BM4(W1_5260_5320,
+ W1_5180_5240,
+ W1_5745_5825,
+ W1_5500_5700),
+ .chan11b = BM7(W1_2412_2412,
+ W1_2437_2442,
+ W1_2462_2462,
+ W1_2472_2472,
+ W1_2417_2432,
+ W1_2447_2457,
+ W1_2467_2467),
+ .chan11g = BM7(WG1_2412_2412,
+ WG1_2437_2442,
+ WG1_2462_2462,
+ WG1_2472_2472,
+ WG1_2417_2432,
+ WG1_2447_2457,
+ WG1_2467_2467),
+ .chan11g_turbo = BM1(T3_2437_2437)},
+
{.regDmnEnum = NULL1,
.conformanceTestLimit = NO_CTL,
}
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2006 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h 219442 2011-03-10 03:13:56Z adrian $
*/
#ifndef __AH_REGDOMAIN_FREQBANDS_H__
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2011 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h 224226 2011-07-20 12:46:58Z adrian $
*/
#ifndef __AH_REGDOMAIN_REGENUM_H__
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2006 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regmap.h 248677 2013-03-24 04:42:56Z adrian $
*/
#ifndef __AH_REGDOMAIN_REGMAP_H__
@@ -129,6 +130,7 @@
{WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT },
{WORA_WORLD, WORA_WORLD, WORA_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT },
{WORB_WORLD, WORB_WORLD, WORB_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT },
+ {WORC_WORLD, WORC_WORLD, WORC_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, CTRY_DEFAULT },
};
#endif
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2006 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain.c 243975 2012-12-07 06:38:30Z adrian $
*/
#include "opt_ah.h"
@@ -169,7 +170,7 @@
if (regDomainPairs[i].regDmnEnum == rd)
return AH_TRUE;
}
- HALDEBUG_G(ah, HAL_DEBUG_REGDOMAIN,
+ HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
"%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
return AH_FALSE;
}
@@ -613,7 +614,9 @@
return 1544 + freq;
if (sku == SKU_SR9)
return 3344 - freq;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ if (sku == SKU_XC900M)
+ return 1517 + freq;
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot map freq %u unknown gsm sku %u\n",
__func__, freq, sku);
return freq;
@@ -727,6 +730,7 @@
case SKU_SR9:
case SKU_XR9:
case SKU_GZ901:
+ case SKU_XC900M:
/*
* Map 900MHz sku's. The frequencies will be mapped
* according to the sku to compensate for the down-converter.
Modified: trunk/sys/dev/ath/ath_hal/ah_regdomain.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_regdomain.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_regdomain.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2006 Atheros Communications, Inc.
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_regdomain.h 219442 2011-03-10 03:13:56Z adrian $
*/
#ifndef __AH_REGDOMAIN_H__
#define __AH_REGDOMAIN_H__
Modified: trunk/sys/dev/ath/ath_hal/ah_soc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ah_soc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ah_soc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ah_soc.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _ATH_AH_SOC_H_
#define _ATH_AH_SOC_H_
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210.h 247286 2013-02-25 22:42:43Z adrian $
*/
#ifndef _ATH_AR5210_H_
#define _ATH_AR5210_H_
@@ -171,7 +172,8 @@
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5210FillTxDesc(struct ath_hal *, struct ath_desc *,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
+ u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5210ProcTxDesc(struct ath_hal *,
struct ath_desc *, struct ath_tx_status *);
@@ -179,9 +181,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 +257,13 @@
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 ar5210SetChainMasks(struct ath_hal *, uint32_t, uint32_t);
+extern void ar5210EnableDfs(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5210GetDfsThresh(struct ath_hal *, HAL_PHYERR_PARAM *);
+extern void ar5210UpdateDiagReg(struct ath_hal *ah, uint32_t val);
extern u_int ar5210GetKeyCacheSize(struct ath_hal *);
extern HAL_BOOL ar5210IsKeyCacheEntryValid(struct ath_hal *, uint16_t);
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c 247286 2013-02-25 22:42:43Z adrian $
*/
#include "opt_ah.h"
@@ -33,7 +34,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 +76,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 +134,15 @@
.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_setChainMasks = ar5210SetChainMasks,
+ .ah_enableDfs = ar5210EnableDfs,
+ .ah_getDfsThresh = ar5210GetDfsThresh,
+ /* XXX procRadarEvent */
+ /* XXX isFastClockEnabled */
/* Key Cache Functions */
.ah_getKeyCacheSize = ar5210GetKeyCacheSize,
@@ -182,7 +194,7 @@
HAL_STATUS ecode;
int i;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH,
"%s: devid 0x%x sc %p st %p sh %p\n", __func__, devid,
sc, (void*) st, (void*) sh);
@@ -189,7 +201,7 @@
/* NB: memory is returned zero'd */
ahp = ath_hal_malloc(sizeof (struct ath_hal_5210));
if (ahp == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: no memory for state block\n", __func__);
ecode = HAL_ENOMEM;
goto bad;
@@ -326,7 +338,7 @@
}
static void
-ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar5210ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
}
@@ -351,6 +363,8 @@
pCap->halSleepAfterBeaconBroken = AH_TRUE;
pCap->halPSPollBroken = AH_FALSE;
+ pCap->halNumMRRetries = 1; /* No hardware MRR support */
+ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
pCap->halKeyCacheSize = 64;
@@ -359,6 +373,12 @@
pCap->halChanHalfRate = AH_FALSE;
pCap->halChanQuarterRate = AH_FALSE;
+ /*
+ * RSSI uses the combined field; some 11n NICs may use
+ * the control chain RSSI.
+ */
+ pCap->halUseCombinedRadarRssi = AH_TRUE;
+
if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL)) {
/*
* Setup initial rfsilent settings based on the EEPROM
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c 225444 2011-09-08 01:23:05Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_interrupts.c 192397 2009-05-19 17:35:15Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_keycache.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c 247286 2013-02-25 22:42:43Z adrian $
*/
#include "opt_ah.h"
@@ -576,8 +577,6 @@
{
}
-#define AR_DIAG_SW_DIS_CRYPTO (AR_DIAG_SW_DIS_ENC | AR_DIAG_SW_DIS_DEC)
-
HAL_STATUS
ar5210GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
uint32_t capability, uint32_t *result)
@@ -585,7 +584,11 @@
switch (type) {
case HAL_CAP_CIPHER: /* cipher handled in hardware */
+#if 0
return (capability == HAL_CIPHER_WEP ? HAL_OK : HAL_ENOTSUPP);
+#else
+ return HAL_ENOTSUPP;
+#endif
default:
return ath_hal_getcapability(ah, type, capability, result);
}
@@ -608,7 +611,7 @@
#else
AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */
#endif
- OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
+ ar5210UpdateDiagReg(ah, AH_PRIVATE(ah)->ah_diagreg);
return AH_TRUE;
case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */
return AH_FALSE; /* NB: disallow */
@@ -646,3 +649,55 @@
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
+ar5210SetChainMasks(struct ath_hal *ah, uint32_t txchainmask,
+ uint32_t rxchainmask)
+{
+}
+
+void
+ar5210EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+void
+ar5210GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+/*
+ * Update the diagnostic register.
+ *
+ * This merges in the diagnostic register setting with the default
+ * value, which may or may not involve disabling hardware encryption.
+ */
+void
+ar5210UpdateDiagReg(struct ath_hal *ah, uint32_t val)
+{
+
+ /* Disable all hardware encryption */
+ val |= AR_DIAG_SW_DIS_CRYPTO;
+ OS_REG_WRITE(ah, AR_DIAG_SW, val);
+}
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_phy.c 191022 2009-04-13 21:01:08Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_power.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_power.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_power.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_recv.c 243317 2012-11-19 23:42:46Z adrian $
*/
#include "opt_ah.h"
@@ -30,8 +31,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 +42,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);
}
@@ -82,7 +87,7 @@
void
ar5210StartPcuReceive(struct ath_hal *ah)
{
- OS_REG_WRITE(ah, AR_DIAG_SW,
+ ar5210UpdateDiagReg(ah,
OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_RX));
}
@@ -92,7 +97,7 @@
void
ar5210StopPcuReceive(struct ath_hal *ah)
{
- OS_REG_WRITE(ah, AR_DIAG_SW,
+ ar5210UpdateDiagReg(ah,
OS_REG_READ(ah, AR_DIAG_SW) | AR_DIAG_SW_DIS_RX);
}
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c 243317 2012-11-19 23:42:46Z adrian $
*/
#include "opt_ah.h"
@@ -190,7 +191,7 @@
OS_REG_WRITE(ah, AR_CLR_TMASK, 1);
OS_REG_WRITE(ah, AR_TRIG_LEV, 1); /* minimum */
- OS_REG_WRITE(ah, AR_DIAG_SW, 0);
+ ar5210UpdateDiagReg(ah, 0);
OS_REG_WRITE(ah, AR_CFP_PERIOD, 0);
OS_REG_WRITE(ah, AR_TIMER0, 0); /* next beacon time */
@@ -285,7 +286,7 @@
if (ahp->ah_ctstimeout != (u_int) -1)
ar5210SetCTSTimeout(ah, ahp->ah_ctstimeout);
if (AH_PRIVATE(ah)->ah_diagreg != 0)
- OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg);
+ ar5210UpdateDiagReg(ah, AH_PRIVATE(ah)->ah_diagreg);
AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */
@@ -454,7 +455,7 @@
if (ichan == AH_NULL)
return AH_FALSE;
/* Disable tx and rx */
- OS_REG_WRITE(ah, AR_DIAG_SW,
+ ar5210UpdateDiagReg(ah,
OS_REG_READ(ah, AR_DIAG_SW) | (AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX));
/* Disable Beacon Enable */
@@ -551,7 +552,7 @@
}
/* Clear tx and rx disable bit */
- OS_REG_WRITE(ah, AR_DIAG_SW,
+ ar5210UpdateDiagReg(ah,
OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX));
/* Re-enable Beacons */
@@ -594,12 +595,10 @@
if ((resetMask & AR_RC_RMAC) == 0) {
if (isBigEndian()) {
/*
- * Set CFG, little-endian for register
- * and descriptor accesses.
+ * Set CFG, little-endian for descriptor accesses.
*/
- mask = INIT_CONFIG_STATUS |
- AR_CFG_SWTD | AR_CFG_SWRD | AR_CFG_SWRG;
- OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask));
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD;
+ OS_REG_WRITE(ah, AR_CFG, mask);
} else
OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
}
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c 243174 2012-11-17 02:39:37Z adrian $
*/
#include "opt_ah.h"
@@ -518,7 +519,8 @@
ads->ds_ctl1 = 0;
if (flags & HAL_TXDESC_RTSENA) {
ads->ds_ctl0 |= AR_RTSCTSEnable;
- ads->ds_ctl1 |= rtsctsDuration & AR_RTSDuration;
+ ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S)
+ & AR_RTSDuration;
}
return AH_TRUE;
}
@@ -546,13 +548,17 @@
HAL_BOOL
ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
+ u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5210_desc *ads = AR5210DESC(ds);
+ uint32_t segLen = segLenList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);
+ ds->ds_data = bufAddrList[0];
+
if (firstSeg) {
/*
* First descriptor, don't clobber xmit control data
@@ -630,3 +636,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;
+}
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210desc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210desc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210desc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,13 +15,11 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210desc.h 243173 2012-11-17 02:39:09Z adrian $
*/
#ifndef _DEV_ATH_AR5210DESC_H
#define _DEV_ATH_AR5210DESC_H
-#include "ah_desc.h"
-
/*
* Defintions for the DMA descriptors used by the Atheros
* AR5210/AR5211 and AR5110 Wireless Lan controller parts.
@@ -57,6 +56,7 @@
#define AR_ClearDestMask 0x01000000 /* Clear destination mask bit */
#define AR_AntModeXmit 0x02000000 /* TX antenna seslection */
#define AR_FrmType 0x1c000000 /* frame type indication */
+#define AR_FrmType_S 26
#define AR_Frm_Normal 0x00000000 /* normal frame */
#define AR_Frm_ATIM 0x04000000 /* ATIM frame */
#define AR_Frm_PSPOLL 0x08000000 /* PS poll frame */
@@ -71,6 +71,7 @@
#define AR_EncryptKeyIdx 0x0007e000 /* ecnrypt key table index */
#define AR_EncryptKeyIdx_S 13
#define AR_RTSDuration 0xfff80000 /* lower 13bit of duration */
+#define AR_RTSDuration_S 19
/* RX ds_ctl1 */
/* AR_BufLen 0x00000fff data buffer length */
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210phy.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _DEV_ATH_AR5210PHY_H
#define _DEV_ATH_AR5210PHY_H
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5210reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5210reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5210reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2004 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5210reg.h 243317 2012-11-19 23:42:46Z adrian $
*/
#ifndef _DEV_ATH_AR5210REG_H
#define _DEV_ATH_AR5210REG_H
@@ -385,6 +386,7 @@
#define AR_DIAG_SW_SCVRAM_SEED 0x0003f800 /* fixed scrambler seed */
#define AR_DIAG_SW_DIS_SEQ_INC 0x00040000 /* seq increment disable */
#define AR_DIAG_SW_FRAME_NV0 0x00080000 /* accept frame vers != 0 */
+#define AR_DIAG_SW_DIS_CRYPTO (AR_DIAG_SW_DIS_ENC | AR_DIAG_SW_DIS_DEC)
#define AR_DIAG_SW_BITS \
"\20\1DIS_WEP_ACK\2DIS_ACK\3DIS_CTS\4DIS_ENC\5DIS_DEC\6DIS_TX"\
"\7DIS_RX\10LOOP_BACK\11CORR_FCS\12CHAN_INFO\13EN_SCRAM_SEED"\
Modified: trunk/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini 204644 2010-03-03 17:32:32Z rpaulo $
*/
/* crete register init */
Property changes on: trunk/sys/dev/ath/ath_hal/ar5210/ar5k_0007.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211.h 247286 2013-02-25 22:42:43Z adrian $
*/
#ifndef _ATH_AR5211_H_
#define _ATH_AR5211_H_
@@ -196,7 +197,8 @@
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5211FillTxDesc(struct ath_hal *, struct ath_desc *,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
+ u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5211ProcTxDesc(struct ath_hal *,
struct ath_desc *, struct ath_tx_status *);
@@ -204,9 +206,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,7 +284,14 @@
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 ar5211SetChainMasks(struct ath_hal *ah, uint32_t, uint32_t);
+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);
extern HAL_BOOL ar5211ResetKeyCacheEntry(struct ath_hal *, uint16_t entry);
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c 247286 2013-02-25 22:42:43Z adrian $
*/
#include "opt_ah.h"
@@ -33,7 +34,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 +76,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 +134,15 @@
.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_setChainMasks = ar5211SetChainMasks,
+ .ah_enableDfs = ar5211EnableDfs,
+ .ah_getDfsThresh = ar5211GetDfsThresh,
+ /* XXX procRadarEvent */
+ /* XXX isFastClockEnabled */
/* Key Cache Functions */
.ah_getKeyCacheSize = ar5211GetKeyCacheSize,
@@ -201,13 +213,13 @@
uint16_t eeval;
HAL_STATUS ecode;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp = ath_hal_malloc(sizeof (struct ath_hal_5211));
if (ahp == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
ecode = HAL_ENOMEM;
goto bad;
@@ -449,7 +461,7 @@
}
static void
-ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore)
+ar5211ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL power_off)
{
}
@@ -486,6 +498,8 @@
pCap->halSleepAfterBeaconBroken = AH_TRUE;
pCap->halPSPollBroken = AH_TRUE;
pCap->halVEOLSupport = AH_TRUE;
+ pCap->halNumMRRetries = 1; /* No hardware MRR support */
+ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
pCap->halTotalQueues = HAL_NUM_TX_QUEUES;
pCap->halKeyCacheSize = 128;
@@ -494,6 +508,12 @@
pCap->halChanHalfRate = AH_FALSE;
pCap->halChanQuarterRate = AH_FALSE;
+ /*
+ * RSSI uses the combined field; some 11n NICs may use
+ * the control chain RSSI.
+ */
+ pCap->halUseCombinedRadarRssi = AH_TRUE;
+
if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) &&
ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) {
/* NB: enabled by default */
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c 225444 2011-09-08 01:23:05Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_interrupts.c 192397 2009-05-19 17:35:15Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_keycache.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_misc.c 247286 2013-02-25 22:42:43Z adrian $
*/
#include "opt_ah.h"
@@ -688,3 +689,40 @@
}
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
+ar5211SetChainMasks(struct ath_hal *ah, uint32_t txchainmask,
+ uint32_t rxchainmask)
+{
+}
+
+void
+ar5211EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
+
+void
+ar5211GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+}
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_phy.c 191022 2009-04-13 21:01:08Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_power.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_power.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_power.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_recv.c 238278 2012-07-09 07:19:11Z adrian $
*/
#include "opt_ah.h"
@@ -30,8 +31,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 +42,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);
}
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_reset.c 234450 2012-04-19 03:26:21Z adrian $
*/
#include "opt_ah.h"
@@ -764,12 +765,10 @@
if ((resetMask & AR_RC_MAC) == 0) {
if (isBigEndian()) {
/*
- * Set CFG, little-endian for register
- * and descriptor accesses.
+ * Set CFG, little-endian for descriptor accesses.
*/
- mask = INIT_CONFIG_STATUS |
- AR_CFG_SWTD | AR_CFG_SWRD | AR_CFG_SWRG;
- OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask));
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWTD | AR_CFG_SWRD;
+ OS_REG_WRITE(ah, AR_CFG, mask);
} else
OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
}
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 239051 2012-08-05 10:12:27Z adrian $
*/
#include "opt_ah.h"
@@ -577,11 +578,15 @@
HAL_BOOL
ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
+ u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5211_desc *ads = AR5211DESC(ds);
+ uint32_t segLen = segLenList[0];
+ ds->ds_data = bufAddrList[0];
+
HALASSERT((segLen &~ AR_BufLen) == 0);
if (firstSeg) {
@@ -671,3 +676,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;
+}
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211desc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211desc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211desc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,13 +15,11 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211desc.h 243249 2012-11-18 20:41:46Z adrian $
*/
#ifndef _DEV_ATH_AR5211DESC_H
#define _DEV_ATH_AR5211DESC_H
-#include "ah_desc.h"
-
/*
* Defintions for the DMA descriptors used by the Atheros
* AR5211 and AR5110 Wireless Lan controller parts.
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211phy.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _DEV_ATH_AR5211PHY_H
#define _DEV_ATH_AR5211PHY_H
Modified: trunk/sys/dev/ath/ath_hal/ar5211/ar5211reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/ar5211reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/ar5211reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2006 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/ar5211reg.h 228980 2011-12-30 02:58:37Z dim $
*/
#ifndef _DEV_ATH_AR5211REG_H
#define _DEV_ATH_AR5211REG_H
Modified: trunk/sys/dev/ath/ath_hal/ar5211/boss.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5211/boss.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5211/boss.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5211/boss.ini 245952 2013-01-26 22:08:21Z pfg $
*/
/* Auto Generated PCI Register Writes. Created: 09/12/02 */
Property changes on: trunk/sys/dev/ath/ath_hal/ar5211/boss.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar2316.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar2316.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar2316.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar2316.c 187831 2009-01-28 18:00:22Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar2317.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar2317.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar2317.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar2317.c 187831 2009-01-28 18:00:22Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar2413.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar2413.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar2413.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar2413.c 187831 2009-01-28 18:00:22Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar2425.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar2425.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar2425.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar2425.c 188979 2009-02-24 01:07:06Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5111.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5111.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5111.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5111.c 187831 2009-01-28 18:00:22Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5112.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5112.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5112.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5112.c 225883 2011-09-30 05:17:57Z adrian $
*/
#include "opt_ah.h"
@@ -611,7 +612,7 @@
uint16_t idxR = 1;
if (numPcdacs < 2) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: at least 2 pcdac values needed [%d]\n",
__func__, numPcdacs);
return AH_FALSE;
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212.h 256139 2013-10-08 11:28:59Z adrian $
*/
#ifndef _ATH_AR5212_H_
#define _ATH_AR5212_H_
@@ -252,6 +253,7 @@
uint8_t ah_macaddr[IEEE80211_ADDR_LEN];
uint8_t ah_bssid[IEEE80211_ADDR_LEN];
uint8_t ah_bssidmask[IEEE80211_ADDR_LEN];
+ uint16_t ah_assocId;
/*
* Runtime state.
@@ -319,6 +321,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);
@@ -333,6 +336,16 @@
uint8_t ah_txTrigLev; /* current Tx trigger level */
uint8_t ah_maxTxTrigLev; /* max tx trigger level */
+
+ /*
+ * Channel Tx, Rx, Rx Clear State
+ */
+ uint32_t ah_cycleCount;
+ uint32_t ah_ctlBusy;
+ uint32_t ah_rxBusy;
+ uint32_t ah_txBusy;
+ uint32_t ah_rx_chainmask;
+ uint32_t ah_tx_chainmask;
};
#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah))
@@ -509,6 +522,9 @@
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 void ar5212SetChainMasks(struct ath_hal *, uint32_t, uint32_t);
extern HAL_BOOL ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode,
int setChip);
@@ -515,8 +531,8 @@
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);
@@ -590,7 +606,8 @@
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
+ u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5212ProcTxDesc(struct ath_hal *ah,
struct ath_desc *, struct ath_tx_status *);
@@ -598,6 +615,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);
@@ -622,10 +645,13 @@
extern HAL_BOOL ar5212IsNFCalInProgress(struct ath_hal *ah);
extern HAL_BOOL ar5212WaitNFCalComplete(struct ath_hal *ah, int i);
extern void ar5212EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe);
+extern HAL_BOOL ar5212GetDfsDefaultThresh(struct ath_hal *ah,
+ HAL_PHYERR_PARAM *pe);
extern void ar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe);
extern HAL_BOOL ar5212ProcessRadarEvent(struct ath_hal *ah,
struct ath_rx_status *rxs, uint64_t fulltsf, const char *buf,
HAL_DFS_EVENT *event);
extern HAL_BOOL ar5212IsFastClockEnabled(struct ath_hal *ah);
+extern uint32_t ar5212Get11nExtBusy(struct ath_hal *ah);
#endif /* _ATH_AR5212_H_ */
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212.ini 204644 2010-03-03 17:32:32Z rpaulo $
*/
/* Auto Generated PCI Register Writes. Created: 09/01/04 */
Property changes on: trunk/sys/dev/ath/ath_hal/ar5212/ar5212.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c 256139 2013-10-08 11:28:59Z adrian $
*/
#include "opt_ah.h"
@@ -865,16 +866,40 @@
ar5212AniGetListenTime(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
- struct ar5212AniState *aniState;
- uint32_t txFrameCount, rxFrameCount, cycleCount;
- int32_t listenTime;
+ struct ar5212AniState *aniState = NULL;
+ int32_t listenTime = 0;
+ int good;
+ HAL_SURVEY_SAMPLE hs;
+ HAL_CHANNEL_SURVEY *cs = AH_NULL;
- txFrameCount = OS_REG_READ(ah, AR_TFCNT);
- rxFrameCount = OS_REG_READ(ah, AR_RFCNT);
- cycleCount = OS_REG_READ(ah, AR_CCCNT);
+ /*
+ * 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 (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+ cs = &ahp->ah_chansurvey;
+
+ /*
+ * Fetch the current statistics, squirrel away the current
+ * sample, bump the sequence/sample counter.
+ */
+ OS_MEMZERO(&hs, sizeof(hs));
+ good = ar5212GetMibCycleCounts(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
@@ -882,15 +907,29 @@
*/
listenTime = 0;
ahp->ah_stats.ast_ani_lzero++;
- } else {
- int32_t ccdelta = cycleCount - aniState->cycleCount;
- int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
- int32_t tfdelta = txFrameCount - aniState->txFrameCount;
+ } else if (ANI_ENA(ah)) {
+ /*
+ * Only calculate and update the cycle count if we have
+ * an ANI state.
+ */
+ int32_t ccdelta =
+ AH5212(ah)->ah_cycleCount - aniState->cycleCount;
+ int32_t rfdelta =
+ AH5212(ah)->ah_rxBusy - aniState->rxFrameCount;
+ int32_t tfdelta =
+ AH5212(ah)->ah_txBusy - aniState->txFrameCount;
listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
}
- aniState->cycleCount = cycleCount;
- aniState->txFrameCount = txFrameCount;
- aniState->rxFrameCount = rxFrameCount;
+
+ /*
+ * Again, only update ANI state if we have it.
+ */
+ if (ANI_ENA(ah)) {
+ aniState->cycleCount = AH5212(ah)->ah_cycleCount;
+ aniState->rxFrameCount = AH5212(ah)->ah_rxBusy;
+ aniState->txFrameCount = AH5212(ah)->ah_txBusy;
+ }
+
return listenTime;
}
@@ -956,6 +995,9 @@
const struct ar5212AniParams *params;
int32_t listenTime;
+ /* Always update from the MIB, for statistics gathering */
+ listenTime = ar5212AniGetListenTime(ah);
+
/* XXX can aniState be null? */
if (aniState == AH_NULL)
return;
@@ -962,7 +1004,6 @@
if (!ANI_ENA(ah))
return;
- listenTime = ar5212AniGetListenTime(ah);
if (listenTime < 0) {
ahp->ah_stats.ast_ani_lneg++;
/* restart ANI period if listenTime is invalid */
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c 305615 2016-09-08 15:06:28Z pfg $
*/
#include "opt_ah.h"
@@ -29,7 +30,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 +72,9 @@
.ah_getTxIntrQueue = ar5212GetTxIntrQueue,
.ah_reqTxIntrDesc = ar5212IntrReqTxDesc,
.ah_getTxCompletionRates = ar5212GetTxCompletionRates,
+ .ah_setTxDescLink = ar5212SetTxDescLink,
+ .ah_getTxDescLink = ar5212GetTxDescLink,
+ .ah_getTxDescLinkPtr = ar5212GetTxDescLinkPtr,
/* RX Functions */
.ah_getRxDP = ar5212GetRxDP,
@@ -107,6 +112,7 @@
.ah_gpioSetIntr = ar5212GpioSetIntr,
.ah_getTsf32 = ar5212GetTsf32,
.ah_getTsf64 = ar5212GetTsf64,
+ .ah_setTsf64 = ar5212SetTsf64,
.ah_resetTsf = ar5212ResetTsf,
.ah_detectCardPresent = ar5212DetectCardPresent,
.ah_updateMibCounters = ar5212UpdateMibCounters,
@@ -125,15 +131,19 @@
.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,
+ .ah_setChainMasks = ar5212SetChainMasks,
/* DFS Functions */
.ah_enableDfs = ar5212EnableDfs,
.ah_getDfsThresh = ar5212GetDfsThresh,
+ .ah_getDfsDefaultThresh = ar5212GetDfsDefaultThresh,
.ah_procRadarEvent = ar5212ProcessRadarEvent,
.ah_isFastClockEnabled = ar5212IsFastClockEnabled,
+ .ah_get11nExtBusy = ar5212Get11nExtBusy,
/* Key Cache Functions */
.ah_getKeyCacheSize = ar5212GetKeyCacheSize,
@@ -261,8 +271,8 @@
ahp->ah_acktimeout = (u_int) -1;
ahp->ah_ctstimeout = (u_int) -1;
ahp->ah_sifstime = (u_int) -1;
- ahp->ah_txTrigLev = INIT_TX_FIFO_THRESHOLD,
- ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD,
+ ahp->ah_txTrigLev = INIT_TX_FIFO_THRESHOLD;
+ ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD;
OS_MEMCPY(&ahp->ah_bssidmask, defbssidmask, IEEE80211_ADDR_LEN);
#undef N
@@ -319,13 +329,13 @@
uint16_t eeval;
HAL_STATUS ecode;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp = ath_hal_malloc(sizeof (struct ath_hal_5212));
if (ahp == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -368,7 +378,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)) {
@@ -664,7 +674,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);
@@ -779,7 +789,29 @@
else
pCap->halHigh2GhzChan = 2732;
- pCap->halLow5GhzChan = 4915;
+ /*
+ * For AR5111 version < 4, the lowest centre frequency supported is
+ * 5130MHz. For AR5111 version 4, the 4.9GHz channels are supported
+ * but only in 10MHz increments.
+ *
+ * In addition, the programming method is wrong - it uses the IEEE
+ * channel number to calculate the frequency, rather than the
+ * channel centre. Since half/quarter rates re-use some of the
+ * 5GHz channel IEEE numbers, this will result in a badly programmed
+ * synth.
+ *
+ * Until the relevant support is written, just limit lower frequency
+ * support for AR5111 so things aren't incorrectly programmed.
+ *
+ * XXX It's also possible this code doesn't correctly limit the
+ * centre frequencies of potential channels; this is very important
+ * for half/quarter rate!
+ */
+ if (AH_RADIO_MAJOR(ah) == AR_RAD5111_SREV_MAJOR) {
+ pCap->halLow5GhzChan = 5120; /* XXX lowest centre = 5130MHz */
+ } else {
+ pCap->halLow5GhzChan = 4915;
+ }
pCap->halHigh5GhzChan = 6100;
pCap->halCipherCkipSupport = AH_FALSE;
@@ -818,6 +850,8 @@
pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G;
pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */
+ pCap->halNumMRRetries = 4; /* Hardware supports 4 MRR */
+ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
pCap->halVEOLSupport = AH_TRUE;
pCap->halBssIdMaskSupport = AH_TRUE;
pCap->halMcastKeySrchSupport = AH_TRUE;
@@ -839,6 +873,12 @@
pCap->halChanHalfRate = AH_TRUE;
pCap->halChanQuarterRate = AH_TRUE;
+ /*
+ * RSSI uses the combined field; some 11n NICs may use
+ * the control chain RSSI.
+ */
+ pCap->halUseCombinedRadarRssi = AH_TRUE;
+
if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) &&
ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) {
/* NB: enabled by default */
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c 243588 2012-11-27 02:18:41Z adrian $
*/
#include "opt_ah.h"
@@ -44,12 +45,22 @@
void
ar5212SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
{
+ struct ath_hal_5212 *ahp = AH5212(ah);
- OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt);
- OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba);
- OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba);
- OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim);
/*
+ * Limit the timers to their specific resolutions:
+ *
+ * + Timer 0 - 0..15 0xffff TU
+ * + Timer 1 - 0..18 0x7ffff TU/8
+ * + Timer 2 - 0..24 0x1ffffff TU/8
+ * + Timer 3 - 0..15 0xffff TU
+ */
+ OS_REG_WRITE(ah, AR_TIMER0, bt->bt_nexttbtt & 0xffff);
+ OS_REG_WRITE(ah, AR_TIMER1, bt->bt_nextdba & 0x7ffff);
+ OS_REG_WRITE(ah, AR_TIMER2, bt->bt_nextswba & 0x1ffffff);
+ /* XXX force nextatim to be non-zero? */
+ OS_REG_WRITE(ah, AR_TIMER3, bt->bt_nextatim & 0xffff);
+ /*
* Set the Beacon register after setting all timers.
*/
if (bt->bt_intval & AR_BEACON_RESET_TSF) {
@@ -65,6 +76,7 @@
OS_REG_WRITE(ah, AR_BEACON, AR_BEACON_RESET_TSF);
}
OS_REG_WRITE(ah, AR_BEACON, bt->bt_intval);
+ ahp->ah_beaconInterval = (bt->bt_intval & HAL_BEACON_PERIOD);
}
/*
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_eeprom.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_gpio.c 188974 2009-02-24 00:12:16Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_interrupts.c 201758 2010-01-07 21:01:37Z mbr $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c 218483 2011-02-09 15:23:16Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c 256139 2013-10-08 11:28:59Z adrian $
*/
#include "opt_ah.h"
@@ -218,8 +219,9 @@
{
struct ath_hal_5212 *ahp = AH5212(ah);
- /* XXX save bssid for possible re-use on reset */
+ /* save bssid for possible re-use on reset */
OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
+ ahp->ah_assocId = assocId;
OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |
((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));
@@ -842,6 +844,10 @@
return HAL_OK;
case 1: /* current setting */
return ahp->ah_diversity ? HAL_OK : HAL_ENXIO;
+ case HAL_CAP_STRONG_DIV:
+ *result = OS_REG_READ(ah, AR_PHY_RESTART);
+ *result = MS(*result, AR_PHY_RESTART_DIV_GC);
+ return HAL_OK;
}
return HAL_EINVAL;
case HAL_CAP_DIAG:
@@ -949,16 +955,34 @@
OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);
return AH_TRUE;
case HAL_CAP_DIVERSITY:
- if (ahp->ah_phyPowerOn) {
- v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
- if (setting)
- v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- else
- v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+ switch (capability) {
+ case 0:
+ return AH_FALSE;
+ case 1: /* setting */
+ if (ahp->ah_phyPowerOn) {
+ if (capability == HAL_CAP_STRONG_DIV) {
+ v = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
+ if (setting)
+ v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+ else
+ v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+ OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+ }
+ }
+ ahp->ah_diversity = (setting != 0);
+ return AH_TRUE;
+
+ case HAL_CAP_STRONG_DIV:
+ if (! ahp->ah_phyPowerOn)
+ return AH_FALSE;
+ v = OS_REG_READ(ah, AR_PHY_RESTART);
+ v &= ~AR_PHY_RESTART_DIV_GC;
+ v |= SM(setting, AR_PHY_RESTART_DIV_GC);
+ OS_REG_WRITE(ah, AR_PHY_RESTART, v);
+ return AH_TRUE;
+ default:
+ return AH_FALSE;
}
- ahp->ah_diversity = (setting != 0);
- return AH_TRUE;
case HAL_CAP_DIAG: /* hardware diagnostic support */
/*
* NB: could split this up into virtual capabilities,
@@ -1089,6 +1113,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;
}
@@ -1154,9 +1183,122 @@
val &= ~AR_PHY_RADAR_0_INBAND;
val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
}
- OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA);
+ if (pe->pe_enabled)
+ val |= AR_PHY_RADAR_0_ENA;
+ else
+ val &= ~ AR_PHY_RADAR_0_ENA;
+
+ if (IS_5413(ah)) {
+
+ if (pe->pe_blockradar == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_BLOCKOFDMWEAK);
+ else
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_BLOCKOFDMWEAK);
+
+ if (pe->pe_en_relstep_check == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_ENRELSTEPCHK);
+ else
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_ENRELSTEPCHK);
+
+ if (pe->pe_usefir128 == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_USEFIR128);
+ else
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_USEFIR128);
+
+ if (pe->pe_enmaxrssi == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_ENMAXRSSI);
+ else
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_ENMAXRSSI);
+
+ if (pe->pe_enrelpwr == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_ENRELPWRCHK);
+ else
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_ENRELPWRCHK);
+
+ if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL)
+ OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_RELPWR, pe->pe_relpwr);
+
+ if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL)
+ OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_RELSTEP, pe->pe_relstep);
+
+ if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL)
+ OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_2,
+ AR_PHY_RADAR_2_MAXLEN, pe->pe_maxlen);
+ }
+
+ OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
}
+/*
+ * Parameters for the AR5212 PHY.
+ */
+#define AR5212_DFS_FIRPWR -35
+#define AR5212_DFS_RRSSI 20
+#define AR5212_DFS_HEIGHT 14
+#define AR5212_DFS_PRSSI 6
+#define AR5212_DFS_INBAND 4
+
+/*
+ * Default parameters for the AR5413 PHY.
+ */
+#define AR5413_DFS_FIRPWR -34
+#define AR5413_DFS_RRSSI 20
+#define AR5413_DFS_HEIGHT 10
+#define AR5413_DFS_PRSSI 15
+#define AR5413_DFS_INBAND 6
+#define AR5413_DFS_RELPWR 8
+#define AR5413_DFS_RELSTEP 31
+#define AR5413_DFS_MAXLEN 255
+
+HAL_BOOL
+ar5212GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+
+ if (IS_5413(ah)) {
+ pe->pe_firpwr = AR5413_DFS_FIRPWR;
+ pe->pe_rrssi = AR5413_DFS_RRSSI;
+ pe->pe_height = AR5413_DFS_HEIGHT;
+ pe->pe_prssi = AR5413_DFS_PRSSI;
+ pe->pe_inband = AR5413_DFS_INBAND;
+ pe->pe_relpwr = AR5413_DFS_RELPWR;
+ pe->pe_relstep = AR5413_DFS_RELSTEP;
+ pe->pe_maxlen = AR5413_DFS_MAXLEN;
+ pe->pe_usefir128 = 0;
+ pe->pe_blockradar = 1;
+ pe->pe_enmaxrssi = 1;
+ pe->pe_enrelpwr = 1;
+ pe->pe_en_relstep_check = 0;
+ } else {
+ pe->pe_firpwr = AR5212_DFS_FIRPWR;
+ pe->pe_rrssi = AR5212_DFS_RRSSI;
+ pe->pe_height = AR5212_DFS_HEIGHT;
+ pe->pe_prssi = AR5212_DFS_PRSSI;
+ pe->pe_inband = AR5212_DFS_INBAND;
+ pe->pe_relpwr = 0;
+ pe->pe_relstep = 0;
+ pe->pe_maxlen = 0;
+ pe->pe_usefir128 = 0;
+ pe->pe_blockradar = 0;
+ pe->pe_enmaxrssi = 0;
+ pe->pe_enrelpwr = 0;
+ pe->pe_en_relstep_check = 0;
+ }
+
+ return (AH_TRUE);
+}
+
void
ar5212GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
{
@@ -1171,11 +1313,31 @@
pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);
pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
+ pe->pe_enabled = !! (val & AR_PHY_RADAR_0_ENA);
pe->pe_relpwr = 0;
pe->pe_relstep = 0;
pe->pe_maxlen = 0;
+ pe->pe_usefir128 = 0;
+ pe->pe_blockradar = 0;
+ pe->pe_enmaxrssi = 0;
+ pe->pe_enrelpwr = 0;
+ pe->pe_en_relstep_check = 0;
pe->pe_extchannel = AH_FALSE;
+
+ if (IS_5413(ah)) {
+ val = OS_REG_READ(ah, AR_PHY_RADAR_2);
+ pe->pe_relpwr = !! MS(val, AR_PHY_RADAR_2_RELPWR);
+ pe->pe_relstep = !! MS(val, AR_PHY_RADAR_2_RELSTEP);
+ pe->pe_maxlen = !! MS(val, AR_PHY_RADAR_2_MAXLEN);
+
+ pe->pe_usefir128 = !! (val & AR_PHY_RADAR_2_USEFIR128);
+ pe->pe_blockradar = !! (val & AR_PHY_RADAR_2_BLOCKOFDMWEAK);
+ pe->pe_enmaxrssi = !! (val & AR_PHY_RADAR_2_ENMAXRSSI);
+ pe->pe_enrelpwr = !! (val & AR_PHY_RADAR_2_ENRELPWRCHK);
+ pe->pe_en_relstep_check =
+ !! (val & AR_PHY_RADAR_2_ENRELSTEPCHK);
+ }
}
/*
@@ -1232,3 +1394,63 @@
{
return AH_FALSE;
}
+
+/*
+ * Return what percentage of the extension channel is busy.
+ * This is always disabled for AR5212 series NICs.
+ */
+uint32_t
+ar5212Get11nExtBusy(struct ath_hal *ah)
+{
+ return 0;
+}
+
+/*
+ * Channel survey support.
+ */
+HAL_BOOL
+ar5212GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+ struct ath_hal_5212 *ahp = AH5212(ah);
+ u_int32_t good = AH_TRUE;
+
+ /* XXX freeze/unfreeze mib counters */
+ uint32_t rc = OS_REG_READ(ah, AR_RCCNT);
+ uint32_t rf = OS_REG_READ(ah, AR_RFCNT);
+ uint32_t tf = OS_REG_READ(ah, AR_TFCNT);
+ uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */
+
+ if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) {
+ /*
+ * Cycle counter wrap (or initial call); it's not possible
+ * to accurately calculate a value because the registers
+ * right shift rather than wrap--so punt and return 0.
+ */
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cycle counter wrap. ExtBusy = 0\n", __func__);
+ good = AH_FALSE;
+ } else {
+ hsample->cycle_count = cc - ahp->ah_cycleCount;
+ hsample->chan_busy = rc - ahp->ah_ctlBusy;
+ hsample->ext_chan_busy = 0;
+ hsample->rx_busy = rf - ahp->ah_rxBusy;
+ hsample->tx_busy = tf - ahp->ah_txBusy;
+ }
+
+ /*
+ * 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;
+
+ return (good);
+}
+
+void
+ar5212SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask,
+ uint32_t rx_chainmask)
+{
+}
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_phy.c 191022 2009-04-13 21:01:08Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_power.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_power.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_power.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_power.c 203159 2010-01-29 10:10:14Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,12 +15,13 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_recv.c 243169 2012-11-17 02:02:36Z adrian $
*/
#include "opt_ah.h"
#include "ah.h"
#include "ah_internal.h"
+#include "ah_desc.h"
#include "ar5212/ar5212.h"
#include "ar5212/ar5212reg.h"
@@ -29,8 +31,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 +42,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);
}
@@ -272,6 +278,14 @@
rs->rs_antenna = MS(ads->ds_rxstatus0, AR_RcvAntenna);
rs->rs_more = (ads->ds_rxstatus0 & AR_More) ? 1 : 0;
+ /*
+ * The AR5413 (at least) 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_rxstatus1 & AR_FrmRcvOK) == 0) {
/*
* These four bits should not be set together. The
@@ -282,9 +296,7 @@
* Consequently we filter them out here so we don't
* confuse and/or complicate drivers.
*/
- if (ads->ds_rxstatus1 & AR_CRCErr)
- rs->rs_status |= HAL_RXERR_CRC;
- else if (ads->ds_rxstatus1 & AR_PHYErr) {
+ if (ads->ds_rxstatus1 & AR_PHYErr) {
u_int phyerr;
rs->rs_status |= HAL_RXERR_PHY;
@@ -293,7 +305,11 @@
if (!AH5212(ah)->ah_hasHwPhyCounters &&
phyerr != HAL_PHYERR_RADAR)
ar5212AniPhyErrReport(ah, rs);
- } else if (ads->ds_rxstatus1 & AR_DecryptCRCErr)
+ }
+
+ if (ads->ds_rxstatus1 & AR_CRCErr)
+ rs->rs_status |= HAL_RXERR_CRC;
+ else if (ads->ds_rxstatus1 & AR_DecryptCRCErr)
rs->rs_status |= HAL_RXERR_DECRYPT;
else if (ads->ds_rxstatus1 & AR_MichaelErr)
rs->rs_status |= HAL_RXERR_MIC;
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c 275471 2014-12-04 01:10:50Z dim $
*/
#include "opt_ah.h"
@@ -96,6 +97,16 @@
#define IS_DISABLE_FAST_ADC_CHAN(x) (((x) == 2462) || ((x) == 2467))
/*
+ * XXX NDIS 5.x code had MAX_RESET_WAIT set to 2000 for AP code
+ * and 10 for Client code
+ */
+#define MAX_RESET_WAIT 10
+
+#define TX_QUEUEPEND_CHECK 1
+#define TX_ENABLE_CHECK 2
+#define RX_ENABLE_CHECK 4
+
+/*
* Places the device in and out of reset and then places sane
* values in the registers based on EEPROM config, initialization
* vectors (as determined by the mode), and station configuration
@@ -185,6 +196,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
@@ -428,9 +442,10 @@
/* Restore previous antenna */
OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
- /* then our BSSID */
+ /* then our BSSID and associate id */
OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
- OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));
+ OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4) |
+ (ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S);
/* Restore bmiss rssi & count thresholds */
OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
@@ -1104,6 +1119,76 @@
return AH_TRUE;
}
+/**************************************************************
+ * ar5212MacStop
+ *
+ * Disables all active QCUs and ensure that the mac is in a
+ * quiessence state.
+ */
+static HAL_BOOL
+ar5212MacStop(struct ath_hal *ah)
+{
+ HAL_BOOL status;
+ uint32_t count;
+ uint32_t pendFrameCount;
+ uint32_t macStateFlag;
+ uint32_t queue;
+
+ status = AH_FALSE;
+
+ /* Disable Rx Operation ***********************************/
+ OS_REG_SET_BIT(ah, AR_CR, AR_CR_RXD);
+
+ /* Disable TX Operation ***********************************/
+#ifdef NOT_YET
+ ar5212SetTxdpInvalid(ah);
+#endif
+ OS_REG_SET_BIT(ah, AR_Q_TXD, AR_Q_TXD_M);
+
+ /* Polling operation for completion of disable ************/
+ macStateFlag = TX_ENABLE_CHECK | RX_ENABLE_CHECK;
+
+ for (count = 0; count < MAX_RESET_WAIT; count++) {
+ if (macStateFlag & RX_ENABLE_CHECK) {
+ if (!OS_REG_IS_BIT_SET(ah, AR_CR, AR_CR_RXE)) {
+ macStateFlag &= ~RX_ENABLE_CHECK;
+ }
+ }
+
+ if (macStateFlag & TX_ENABLE_CHECK) {
+ if (!OS_REG_IS_BIT_SET(ah, AR_Q_TXE, AR_Q_TXE_M)) {
+ macStateFlag &= ~TX_ENABLE_CHECK;
+ macStateFlag |= TX_QUEUEPEND_CHECK;
+ }
+ }
+ if (macStateFlag & TX_QUEUEPEND_CHECK) {
+ pendFrameCount = 0;
+ for (queue = 0; queue < AR_NUM_DCU; queue++) {
+ pendFrameCount += OS_REG_READ(ah,
+ AR_Q0_STS + (queue * 4)) &
+ AR_Q_STS_PEND_FR_CNT;
+ }
+ if (pendFrameCount == 0) {
+ macStateFlag &= ~TX_QUEUEPEND_CHECK;
+ }
+ }
+ if (macStateFlag == 0) {
+ status = AH_TRUE;
+ break;
+ }
+ OS_DELAY(50);
+ }
+
+ if (status != AH_TRUE) {
+ HALDEBUG(ah, HAL_DEBUG_RESET,
+ "%s:Failed to stop the MAC state 0x%x\n",
+ __func__, macStateFlag);
+ }
+
+ return status;
+}
+
+
/*
* Write the given reset bit mask into the reset register
*/
@@ -1113,12 +1198,75 @@
uint32_t mask = resetMask ? resetMask : ~0;
HAL_BOOL rt;
- /* XXX ar5212MacStop & co. */
-
+ /* Never reset the PCIE core */
if (AH_PRIVATE(ah)->ah_ispcie) {
resetMask &= ~AR_RC_PCI;
}
+ if (resetMask & (AR_RC_MAC | AR_RC_PCI)) {
+ /*
+ * To ensure that the driver can reset the
+ * MAC, wake up the chip
+ */
+ rt = ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE);
+
+ if (rt != AH_TRUE) {
+ return rt;
+ }
+
+ /*
+ * Disable interrupts
+ */
+ OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+ OS_REG_READ(ah, AR_IER);
+
+ if (ar5212MacStop(ah) != AH_TRUE) {
+ /*
+ * Failed to stop the MAC gracefully; let's be more forceful then
+ */
+
+ /* need some delay before flush any pending MMR writes */
+ OS_DELAY(15);
+ OS_REG_READ(ah, AR_RXDP);
+
+ resetMask |= AR_RC_MAC | AR_RC_BB;
+ /* _Never_ reset PCI Express core */
+ if (! AH_PRIVATE(ah)->ah_ispcie) {
+ resetMask |= AR_RC_PCI;
+ }
+#if 0
+ /*
+ * Flush the park address of the PCI controller
+ */
+ /* Read PCI slot information less than Hainan revision */
+ if (AH_PRIVATE(ah)->ah_bustype == HAL_BUS_TYPE_PCI) {
+ if (!IS_5112_REV5_UP(ah)) {
+#define PCI_COMMON_CONFIG_STATUS 0x06
+ u_int32_t i;
+ u_int16_t reg16;
+
+ for (i = 0; i < 32; i++) {
+ ath_hal_read_pci_config_space(ah,
+ PCI_COMMON_CONFIG_STATUS,
+ ®16, sizeof(reg16));
+ }
+ }
+#undef PCI_COMMON_CONFIG_STATUS
+ }
+#endif
+ } else {
+ /*
+ * MAC stopped gracefully; no need to warm-reset the PCI bus
+ */
+
+ resetMask &= ~AR_RC_PCI;
+
+ /* need some delay before flush any pending MMR writes */
+ OS_DELAY(15);
+ OS_REG_READ(ah, AR_RXDP);
+ }
+ }
+
(void) OS_REG_READ(ah, AR_RXDP);/* flush any pending MMR writes */
OS_REG_WRITE(ah, AR_RC, resetMask);
OS_DELAY(15); /* need to wait at least 128 clocks
@@ -1129,14 +1277,13 @@
if ((resetMask & AR_RC_MAC) == 0) {
if (isBigEndian()) {
/*
- * Set CFG, little-endian for register
- * and descriptor accesses.
+ * Set CFG, little-endian for descriptor accesses.
*/
- mask = INIT_CONFIG_STATUS | AR_CFG_SWRD | AR_CFG_SWRG;
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
#ifndef AH_NEED_DESC_SWAP
mask |= AR_CFG_SWTD;
#endif
- OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask));
+ OS_REG_WRITE(ah, AR_CFG, mask);
} else
OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
if (ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
@@ -2459,6 +2606,12 @@
powInfo[ixlo].twicePwr54, powInfo[ixhi].twicePwr54);
}
+static uint32_t
+udiff(uint32_t u, uint32_t v)
+{
+ return (u >= v ? u - v : v - u);
+}
+
/*
* Search a list for a specified value v that is within
* EEP_DELTA of the search values. Return the closest
@@ -2493,7 +2646,7 @@
* If value is close to the current value of the list
* then target is not between values, it is one of the values
*/
- if (abs(lp[0] * EEP_SCALE - target) < EEP_DELTA) {
+ if (udiff(lp[0] * EEP_SCALE, target) < EEP_DELTA) {
*vlo = *vhi = lp[0];
return;
}
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_rfgain.c 188197 2009-02-05 21:13:31Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,12 +15,13 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c 243169 2012-11-17 02:02:36Z adrian $
*/
#include "opt_ah.h"
#include "ah.h"
#include "ah_internal.h"
+#include "ah_desc.h"
#include "ar5212/ar5212.h"
#include "ar5212/ar5212reg.h"
@@ -263,6 +265,7 @@
* Assumes:
* phwChannel has been set to point to the current channel
*/
+#define TU_TO_USEC(_tu) ((_tu) << 10)
HAL_BOOL
ar5212ResetTxQueue(struct ath_hal *ah, u_int q)
{
@@ -270,7 +273,7 @@
HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
HAL_TX_QUEUE_INFO *qi;
- uint32_t cwMin, chanCwMin, value, qmisc, dmisc;
+ uint32_t cwMin, chanCwMin, qmisc, dmisc;
if (q >= pCap->halTotalQueues) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
@@ -409,17 +412,40 @@
| AR_Q_MISC_CBR_INCR_DIS1
| AR_Q_MISC_CBR_INCR_DIS0;
- if (!qi->tqi_readyTime) {
+ if (qi->tqi_readyTime) {
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
+ "%s: using tqi_readyTime\n", __func__);
+ OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) |
+ AR_Q_RDYTIMECFG_ENA);
+ } else {
+ int value;
/*
* NB: don't set default ready time if driver
* has explicitly specified something. This is
* here solely for backwards compatibility.
*/
- value = (ahp->ah_beaconInterval
+ /*
+ * XXX for now, hard-code a CAB interval of 70%
+ * XXX of the total beacon interval.
+ */
+
+ value = (ahp->ah_beaconInterval * 70 / 100)
- (ah->ah_config.ah_sw_beacon_response_time -
- ah->ah_config.ah_dma_beacon_response_time)
- - ah->ah_config.ah_additional_swba_backoff) * 1024;
- OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_ENA);
+ + ah->ah_config.ah_dma_beacon_response_time)
+ - ah->ah_config.ah_additional_swba_backoff;
+ /*
+ * XXX Ensure it isn't too low - nothing lower
+ * XXX than 10 TU
+ */
+ if (value < 10)
+ value = 10;
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
+ "%s: defaulting to rdytime = %d uS\n",
+ __func__, value);
+ OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ SM(TU_TO_USEC(value), AR_Q_RDYTIMECFG_INT) |
+ AR_Q_RDYTIMECFG_ENA);
}
dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
AR_D_MISC_ARB_LOCKOUT_CNTRL);
@@ -481,6 +507,7 @@
return AH_TRUE;
}
+#undef TU_TO_USEC
/*
* Get the TXDP for the specified queue
@@ -777,13 +804,17 @@
HAL_BOOL
ar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
+ u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5212_desc *ads = AR5212DESC(ds);
+ uint32_t segLen = segLenList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);
+ ds->ds_data = bufAddrList[0];
+
if (firstSeg) {
/*
* First descriptor, don't clobber xmit control data
@@ -796,12 +827,14 @@
* copy the multi-rate transmit parameters from
* the first frame for processing on completion.
*/
- ads->ds_ctl0 = 0;
ads->ds_ctl1 = segLen;
#ifdef AH_NEED_DESC_SWAP
+ ads->ds_ctl0 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl0)
+ & AR_TxInterReq;
ads->ds_ctl2 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl2);
ads->ds_ctl3 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl3);
#else
+ ads->ds_ctl0 = AR5212DESC_CONST(ds0)->ds_ctl0 & AR_TxInterReq;
ads->ds_ctl2 = AR5212DESC_CONST(ds0)->ds_ctl2;
ads->ds_ctl3 = AR5212DESC_CONST(ds0)->ds_ctl3;
#endif
@@ -809,7 +842,12 @@
/*
* Intermediate descriptor in a multi-descriptor frame.
*/
- ads->ds_ctl0 = 0;
+#ifdef AH_NEED_DESC_SWAP
+ ads->ds_ctl0 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl0)
+ & AR_TxInterReq;
+#else
+ ads->ds_ctl0 = AR5212DESC_CONST(ds0)->ds_ctl0 & AR_TxInterReq;
+#endif
ads->ds_ctl1 = segLen | AR_More;
ads->ds_ctl2 = 0;
ads->ds_ctl3 = 0;
@@ -939,3 +977,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;
+}
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212desc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212desc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212desc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212desc.h 243168 2012-11-17 02:00:33Z adrian $
*/
#ifndef _ATH_AR5212_DESC_H_
#define _ATH_AR5212_DESC_H_
@@ -22,7 +23,6 @@
/*
* Hardware-specific descriptor structures.
*/
-#include "ah_desc.h"
/*
* AR5212-specific tx/rx descriptor definition.
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212phy.h 239801 2012-08-29 03:58:13Z adrian $
*/
#ifndef _DEV_ATH_AR5212PHY_H_
#define _DEV_ATH_AR5212PHY_H_
@@ -221,6 +222,19 @@
#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 /* Radar firpwr threshold */
#define AR_PHY_RADAR_0_FIRPWR_S 24
+/* ar5413 specific */
+#define AR_PHY_RADAR_2 0x9958 /* radar detection settings */
+#define AR_PHY_RADAR_2_ENRELSTEPCHK 0x00002000 /* Enable using max rssi */
+#define AR_PHY_RADAR_2_ENMAXRSSI 0x00004000 /* Enable using max rssi */
+#define AR_PHY_RADAR_2_BLOCKOFDMWEAK 0x00008000 /* En block OFDM weak sig as radar */
+#define AR_PHY_RADAR_2_USEFIR128 0x00400000 /* En measuring pwr over 128 cycles */
+#define AR_PHY_RADAR_2_ENRELPWRCHK 0x00800000 /* Enable using max rssi */
+#define AR_PHY_RADAR_2_MAXLEN 0x000000FF /* Max Pulse duration threshold */
+#define AR_PHY_RADAR_2_MAXLEN_S 0
+#define AR_PHY_RADAR_2_RELSTEP 0x00001F00 /* Pulse relative step threshold */
+#define AR_PHY_RADAR_2_RELSTEP_S 8
+#define AR_PHY_RADAR_2_RELPWR 0x003F0000 /* pulse relative power threshold */
+#define AR_PHY_RADAR_2_RELPWR_S 16
#define AR_PHY_SIGMA_DELTA 0x996C /* AR5312 only */
#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5212reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5212reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5212reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5212reg.h 226489 2011-10-18 03:17:06Z adrian $
*/
#ifndef _DEV_ATH_AR5212REG_H_
#define _DEV_ATH_AR5212REG_H_
@@ -94,7 +95,9 @@
#define AR_QTXDP(_i) (AR_Q0_TXDP + ((_i)<<2))
#define AR_Q_TXE 0x0840 /* MAC Transmit Queue enable */
+#define AR_Q_TXE_M 0x000003FF /* Mask for TXE (QCU 0-9) */
#define AR_Q_TXD 0x0880 /* MAC Transmit Queue disable */
+#define AR_Q_TXD_M 0x000003FF /* Mask for TXD (QCU 0-9) */
#define AR_Q0_CBRCFG 0x08c0 /* MAC CBR configuration */
#define AR_Q1_CBRCFG 0x08c4 /* MAC CBR configuration */
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5311reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5311reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5311reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5311reg.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _DEV_ATH_AR5311REG_H_
#define _DEV_ATH_AR5311REG_H_
Modified: trunk/sys/dev/ath/ath_hal/ar5212/ar5413.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5212/ar5413.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5212/ar5413.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5212/ar5413.c 188979 2009-02-24 01:07:06Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312.h 188974 2009-02-24 00:12:16Z sam $
*/
#ifndef _ATH_AR5312_H_
#define _ATH_AR5312_H_
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c 225883 2011-09-30 05:17:57Z adrian $
*/
#include "opt_ah.h"
@@ -71,13 +72,13 @@
uint16_t eeval;
HAL_STATUS ecode;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, st, (void*) sh);
/* NB: memory is returned zero'd */
ahp = ath_hal_malloc(sizeof (struct ath_hal_5212));
if (ahp == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_eeprom.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_gpio.c 188974 2009-02-24 00:12:16Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_interrupts.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_misc.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_power.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_power.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_power.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_power.c 204644 2010-03-03 17:32:32Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312_reset.c 234450 2012-04-19 03:26:21Z adrian $
*/
#include "opt_ah.h"
@@ -740,8 +741,7 @@
if ((resetMask & AR_RC_MAC) == 0) {
if (isBigEndian()) {
/*
- * Set CFG, little-endian for register
- * and descriptor accesses.
+ * Set CFG, little-endian for descriptor accesses.
*/
#ifdef AH_NEED_DESC_SWAP
mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312phy.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _DEV_ATH_AR5312PHY_H_
#define _DEV_ATH_AR5312PHY_H_
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5312reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5312reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5312reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5312reg.h 204644 2010-03-03 17:32:32Z rpaulo $
*/
#ifndef _DEV_ATH_AR5312REG_H_
#define _DEV_ATH_AR5312REG_H_
Modified: trunk/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5312/ar5315_gpio.c 188974 2009-02-24 00:12:16Z sam $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar2133.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar2133.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar2133.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar2133.c 241195 2012-10-04 15:42:45Z adrian $
*/
#include "opt_ah.h"
@@ -163,6 +164,33 @@
OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
}
+ /*
+ * Handle programming the RF synth for odd frequencies in the
+ * 4.9->5GHz range. This matches the programming from the
+ * later model 802.11abg RF synths.
+ *
+ * This interoperates on the quarter rate channels with the
+ * AR5112 and later RF synths. Please note that the synthesiser
+ * isn't able to completely accurately represent these frequencies
+ * (as the resolution in this reference is 2.5MHz) and thus it will
+ * be slightly "off centre." This matches the same slightly
+ * incorrect * centre frequency behaviour that the AR5112 and later
+ * channel selection code has.
+ *
+ * This is disabled because it hasn't been tested for regulatory
+ * compliance and neither have the NICs which would use it.
+ * So if you enable this code, you must first ensure that you've
+ * re-certified the NICs in question beforehand or you will be
+ * violating your local regulatory rules and breaking the law.
+ */
+#if 0
+ } else if (((freq % 5) == 2) && (freq <= 5435)) {
+ freq = freq - 2;
+ channelSel = ath_hal_reverseBits(
+ (uint32_t) (((freq - 4800) * 10) / 25 + 1), 8);
+ /* XXX what about for Howl/Sowl? */
+ aModeRefSel = ath_hal_reverseBits(0, 2);
+#endif
} else if ((freq % 20) == 0 && freq >= 5120) {
channelSel = ath_hal_reverseBits(((freq - 4800) / 20 << 2), 8);
if (AR_SREV_HOWL(ah) || AR_SREV_SOWL_10_OR_LATER(ah))
@@ -179,7 +207,8 @@
channelSel = ath_hal_reverseBits((freq - 4800) / 5, 8);
aModeRefSel = ath_hal_reverseBits(1, 2);
} else {
- HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
+ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
+ "%s: invalid channel %u MHz\n",
__func__, freq);
return AH_FALSE;
}
@@ -549,3 +578,11 @@
return AH_TRUE;
}
+
+static HAL_BOOL
+ar2133Probe(struct ath_hal *ah)
+{
+ return (AR_SREV_OWL(ah) || AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah));
+}
+
+AH_RF(RF2133, ar2133Probe, ar2133RfAttach);
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416.h 249580 2013-04-17 07:31:53Z adrian $
*/
#ifndef _ATH_AR5416_H_
#define _ATH_AR5416_H_
@@ -107,16 +108,21 @@
void (*ah_initPLL) (struct ath_hal *ah,
const struct ieee80211_channel *chan);
+ /* bluetooth coexistence operations */
+ void (*ah_btCoexSetDiversity)(struct ath_hal *ah);
+
u_int ah_globaltxtimeout; /* global tx timeout */
u_int ah_gpioMask;
int ah_hangs; /* h/w hangs state */
uint8_t ah_keytype[AR5416_KEYTABLE_SIZE];
/*
- * Extension Channel Rx Clear State
+ * Primary/Extension Channel Tx, Rx, Rx Clear State
*/
uint32_t ah_cycleCount;
uint32_t ah_ctlBusy;
uint32_t ah_extBusy;
+ uint32_t ah_rxBusy;
+ uint32_t ah_txBusy;
uint32_t ah_rx_chainmask;
uint32_t ah_tx_chainmask;
@@ -127,9 +133,36 @@
struct ar5416NfLimits nf_2g;
struct ar5416NfLimits nf_5g;
+ /*
+ * TX power configuration related structures
+ */
int initPDADC;
+ int ah_ht40PowerIncForPdadc;
+ int16_t ah_ratesArray[Ar5416RateSize];
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))
@@ -171,6 +204,22 @@
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 ar5416BTCoexAntennaDiversity(struct ath_hal *ah);
+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);
@@ -190,9 +239,13 @@
extern uint64_t ar5416GetTsf64(struct ath_hal *ah);
extern void ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64);
extern void ar5416ResetTsf(struct ath_hal *ah);
+extern uint32_t ar5416GetCurRssi(struct ath_hal *ah);
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 HAL_BOOL ar5416GetMibCycleCounts(struct ath_hal *ah,
+ HAL_SURVEY_SAMPLE *hsample);
+extern void ar5416SetChainMasks(struct ath_hal *ah, uint32_t, uint32_t);
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);
@@ -201,12 +254,18 @@
uint32_t duration, uint32_t nextStart, HAL_QUIET_FLAG flag);
extern HAL_STATUS ar5416GetCapability(struct ath_hal *ah,
HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t *result);
+extern HAL_BOOL ar5416SetCapability(struct ath_hal *ah,
+ HAL_CAPABILITY_TYPE type, uint32_t capability, uint32_t val,
+ HAL_STATUS *status);
extern HAL_BOOL ar5416GetDiagState(struct ath_hal *ah, int request,
const void *args, uint32_t argsize,
void **result, uint32_t *resultsize);
extern HAL_BOOL ar5416SetRifsDelay(struct ath_hal *ah,
const struct ieee80211_channel *chan, HAL_BOOL enable);
+
extern void ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe);
+extern HAL_BOOL ar5416GetDfsDefaultThresh(struct ath_hal *ah,
+ HAL_PHYERR_PARAM *pe);
extern void ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe);
extern HAL_BOOL ar5416ProcessRadarEvent(struct ath_hal *ah,
struct ath_rx_status *rxs, uint64_t fulltsf, const char *buf,
@@ -213,6 +272,16 @@
HAL_DFS_EVENT *event);
extern HAL_BOOL ar5416IsFastClockEnabled(struct ath_hal *ah);
+/* ar9280_spectral.c */
+extern void ar5416ConfigureSpectralScan(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss);
+extern void ar5416GetSpectralParams(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss);
+extern HAL_BOOL ar5416IsSpectralActive(struct ath_hal *ah);
+extern HAL_BOOL ar5416IsSpectralEnabled(struct ath_hal *ah);
+extern void ar5416StartSpectralScan(struct ath_hal *ah);
+extern void ar5416StopSpectralScan(struct ath_hal *ah);
+extern uint32_t ar5416GetSpectralConfig(struct ath_hal *ah);
+extern void ar5416RestoreSpectralConfig(struct ath_hal *ah, uint32_t restoreval);
+
extern HAL_BOOL ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode,
int setChip);
extern HAL_POWER_MODE ar5416GetPowerMode(struct ath_hal *ah);
@@ -224,6 +293,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 *,
@@ -313,7 +383,8 @@
u_int txRate2, u_int txRetries2,
u_int txRate3, u_int txRetries3);
extern HAL_BOOL ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
+ u_int descId, u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0);
extern HAL_STATUS ar5416ProcTxDesc(struct ath_hal *ah,
struct ath_desc *, struct ath_tx_status *);
@@ -325,9 +396,10 @@
const HAL_TXQ_INFO *qInfo);
extern HAL_BOOL ar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList,
u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int keyIx,
- HAL_CIPHER cipher, uint8_t delims, u_int segLen, HAL_BOOL firstSeg,
- HAL_BOOL lastSeg);
+ HAL_CIPHER cipher, uint8_t delims,
+ HAL_BOOL firstSeg, HAL_BOOL lastSeg, HAL_BOOL lastAggr);
extern HAL_BOOL ar5416SetupFirstTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int aggrLen, u_int flags, u_int txPower, u_int txRate0, u_int txTries0,
u_int antMode, u_int rtsctsRate, u_int rtsctsDuration);
@@ -338,8 +410,15 @@
extern void ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
u_int durUpdateEn, u_int rtsctsRate, HAL_11N_RATE_SERIES series[],
u_int nseries, u_int flags);
+
+extern void ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds,
+ u_int aggrLen, u_int numDelims);
extern void ar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims);
+extern void ar5416Set11nAggrLast(struct ath_hal *ah, struct ath_desc *ds);
extern void ar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds);
+extern void ar5416Set11nVirtualMoreFrag(struct ath_hal *ah,
+ struct ath_desc *ds, u_int vmf);
+
extern void ar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds, u_int burstDuration);
extern const HAL_RATE_TABLE *ar5416GetRateTable(struct ath_hal *, u_int mode);
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416.ini 225420 2011-09-06 10:49:05Z adrian $
*/
/* Auto Generated PCI Register Writes. Created: 09/20/06 */
Property changes on: trunk/sys/dev/ath/ath_hal/ar5416/ar5416.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c 240984 2012-09-27 06:05:54Z adrian $
*/
#include "opt_ah.h"
@@ -227,7 +228,7 @@
u_int level = param;
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_NOISE_IMMUNITY_LEVEL: set level = %d\n", __func__, level);
- if (level >= params->maxNoiseImmunityLevel) {
+ if (level > params->maxNoiseImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: immunity level out of range (%u > %u)\n",
__func__, level, params->maxNoiseImmunityLevel);
@@ -314,7 +315,7 @@
u_int level = param;
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_FIRSTEP_LEVEL: level = %d\n", __func__, level);
- if (level >= params->maxFirstepLevel) {
+ if (level > params->maxFirstepLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: firstep level out of range (%u > %u)\n",
__func__, level, params->maxFirstepLevel);
@@ -333,7 +334,7 @@
u_int level = param;
HALDEBUG(ah, HAL_DEBUG_ANI, "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL: level = %d\n", __func__, level);
- if (level >= params->maxSpurImmunityLevel) {
+ if (level > params->maxSpurImmunityLevel) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: spur immunity level out of range (%u > %u)\n",
__func__, level, params->maxSpurImmunityLevel);
@@ -379,20 +380,30 @@
aniState = ahp->ah_curani;
params = aniState->params;
/* First, raise noise immunity level, up to max */
- if ((AH5416(ah)->ah_ani_function & (1 << HAL_ANI_NOISE_IMMUNITY_LEVEL)) &&
- (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel)) {
- ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
- aniState->noiseImmunityLevel + 1);
- return;
+ if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) {
+ if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel + 1))
+ return;
}
/* then, raise spur immunity level, up to max */
- if ((AH5416(ah)->ah_ani_function & (1 << HAL_ANI_SPUR_IMMUNITY_LEVEL)) &&
- (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel)) {
- ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
- aniState->spurImmunityLevel + 1);
- return;
+ if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) {
+ if (ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
+ aniState->spurImmunityLevel + 1))
+ return;
}
+ /*
+ * In the case of AP mode operation, we cannot bucketize beacons
+ * according to RSSI. Instead, raise Firstep level, up to max, and
+ * simply return.
+ */
+ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
+ if (aniState->firstepLevel < params->maxFirstepLevel) {
+ if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1))
+ return;
+ }
+ }
if (ANI_ENA_RSSI(ah)) {
int32_t rssi = BEACON_RSSI(ahp);
if (rssi > params->rssiThrHigh) {
@@ -412,10 +423,10 @@
* If weak sig detect is already off, as last resort,
* raise firstep level
*/
- if (aniState->firstepLevel+1 < params->maxFirstepLevel) {
- ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel + 1);
- return;
+ if (aniState->firstepLevel < params->maxFirstepLevel) {
+ if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1))
+ return;
}
} else if (rssi > params->rssiThrLow) {
/*
@@ -426,10 +437,10 @@
ar5416AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_TRUE);
- if (aniState->firstepLevel+1 < params->maxFirstepLevel)
- ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel + 1);
- return;
+ if (aniState->firstepLevel < params->maxFirstepLevel)
+ if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1))
+ return;
} else {
/*
* Beacon rssi is low, if in 11b/g mode, turn off ofdm
@@ -442,9 +453,9 @@
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
AH_FALSE);
if (aniState->firstepLevel > 0)
- ar5416AniControl(ah,
- HAL_ANI_FIRSTEP_LEVEL, 0);
- return;
+ if (ar5416AniControl(ah,
+ HAL_ANI_FIRSTEP_LEVEL, 0))
+ return;
}
}
}
@@ -480,7 +491,7 @@
* Beacon signal in mid and high range,
* raise firstep level.
*/
- if (aniState->firstepLevel+1 < params->maxFirstepLevel)
+ if (aniState->firstepLevel < params->maxFirstepLevel)
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
aniState->firstepLevel + 1);
} else {
@@ -577,6 +588,16 @@
goto finish;
}
+ /*
+ * Use a restrictive set of ANI parameters for hostap mode.
+ */
+ if (opmode == HAL_M_HOSTAP) {
+ if (IEEE80211_IS_CHAN_2GHZ(chan))
+ AH5416(ah)->ah_ani_function =
+ HAL_ANI_SPUR_IMMUNITY_LEVEL | HAL_ANI_FIRSTEP_LEVEL;
+ else
+ AH5416(ah)->ah_ani_function = 0;
+ }
/*
* Automatic processing is done only in station mode right now.
@@ -606,7 +627,7 @@
ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
ar5416AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
- AH_TRUE);
+ AH_FALSE);
ar5416AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE);
ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
ichan->privFlags |= CHANNEL_ANI_SETUP;
@@ -710,6 +731,19 @@
aniState = ahp->ah_curani;
params = aniState->params;
+
+ /*
+ * In the case of AP mode operation, we cannot bucketize beacons
+ * according to RSSI. Instead, lower Firstep level, down to min, and
+ * simply return.
+ */
+ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
+ if (aniState->firstepLevel > 0) {
+ if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1))
+ return;
+ }
+ }
if (ANI_ENA_RSSI(ah)) {
int32_t rssi = BEACON_RSSI(ahp);
if (rssi > params->rssiThrHigh) {
@@ -724,15 +758,15 @@
* detection or lower firstep level.
*/
if (aniState->ofdmWeakSigDetectOff) {
- ar5416AniControl(ah,
+ if (ar5416AniControl(ah,
HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
- AH_TRUE);
- return;
+ AH_TRUE))
+ return;
}
if (aniState->firstepLevel > 0) {
- ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel - 1);
- return;
+ if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1))
+ return;
}
} else {
/*
@@ -739,17 +773,17 @@
* Beacon rssi is low, reduce firstep level.
*/
if (aniState->firstepLevel > 0) {
- ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel - 1);
- return;
+ if (ar5416AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1))
+ return;
}
}
}
/* then lower spur immunity level, down to zero */
if (aniState->spurImmunityLevel > 0) {
- ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
- aniState->spurImmunityLevel - 1);
- return;
+ if (ar5416AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
+ aniState->spurImmunityLevel - 1))
+ return;
}
/*
* if all else fails, lower noise immunity level down to a min value
@@ -756,9 +790,9 @@
* zero for now
*/
if (aniState->noiseImmunityLevel > 0) {
- ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
- aniState->noiseImmunityLevel - 1);
- return;
+ if (ar5416AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel - 1))
+ return;
}
}
@@ -771,21 +805,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 txFrameCount, rxFrameCount, cycleCount;
- int32_t listenTime;
+ struct ar5212AniState *aniState = NULL;
+ int32_t listenTime = 0;
+ int good;
+ HAL_SURVEY_SAMPLE hs;
+ HAL_CHANNEL_SURVEY *cs = AH_NULL;
- txFrameCount = OS_REG_READ(ah, AR_TFCNT);
- rxFrameCount = OS_REG_READ(ah, AR_RFCNT);
- cycleCount = OS_REG_READ(ah, AR_CCCNT);
+ /*
+ * 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 (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+ 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
@@ -793,15 +856,29 @@
*/
listenTime = 0;
ahp->ah_stats.ast_ani_lzero++;
- } else {
- int32_t ccdelta = cycleCount - aniState->cycleCount;
- int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
- int32_t tfdelta = txFrameCount - 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 = cycleCount;
- aniState->txFrameCount = txFrameCount;
- aniState->rxFrameCount = rxFrameCount;
+
+ /*
+ * Again, only update ANI state if we have it.
+ */
+ if (ANI_ENA(ah)) {
+ aniState->cycleCount = AH5416(ah)->ah_cycleCount;
+ aniState->rxFrameCount = AH5416(ah)->ah_rxBusy;
+ aniState->txFrameCount = AH5416(ah)->ah_txBusy;
+ }
+
return listenTime;
}
@@ -865,16 +942,21 @@
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;
+
if (!ANI_ENA(ah))
return;
- listenTime = ar5416AniGetListenTime(ah);
if (listenTime < 0) {
ahp->ah_stats.ast_ani_lneg++;
/* restart ANI period if listenTime is invalid */
+ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: invalid listenTime\n",
+ __func__);
ar5416AniRestart(ah, aniState);
}
/* XXX beware of overflow? */
@@ -894,6 +976,8 @@
aniState->cckPhyErrCount <= aniState->listenTime *
params->cckTrigLow/1000)
ar5416AniLowerImmunity(ah);
+ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower immunity\n",
+ __func__);
ar5416AniRestart(ah, aniState);
} else if (aniState->listenTime > params->period) {
updateMIBStats(ah, aniState);
@@ -909,7 +993,7 @@
params->cckTrigHigh / 1000) {
HALDEBUG(ah, HAL_DEBUG_ANI,
"%s: CCK err %u listenTime %u\n", __func__,
- aniState->ofdmPhyErrCount, aniState->listenTime);
+ aniState->cckPhyErrCount, aniState->listenTime);
ar5416AniCckErrTrigger(ah);
ar5416AniRestart(ah, aniState);
}
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c 305615 2016-09-08 15:06:28Z pfg $
*/
#include "opt_ah.h"
@@ -30,7 +31,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,
@@ -45,8 +48,8 @@
.coarseHigh = { -14, -14, -14, -14, -12 },
.coarseLow = { -64, -64, -64, -64, -70 },
.firpwr = { -78, -78, -78, -78, -80 },
- .maxSpurImmunityLevel = 2,
- .cycPwrThr1 = { 2, 4, 6 },
+ .maxSpurImmunityLevel = 7,
+ .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 },
.maxFirstepLevel = 2, /* levels 0..2 */
.firstep = { 0, 4, 8 },
.ofdmTrigHigh = 500,
@@ -99,9 +102,10 @@
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,
+ ah->ah_perCalibrationN = ar5416PerCalibrationN;
+ ah->ah_resetCalValid = ar5416ResetCalValid;
ah->ah_setTxPowerLimit = ar5416SetTxPowerLimit;
ah->ah_setTxPower = ar5416SetTransmitPower;
ah->ah_setBoardValues = ar5416SetBoardValues;
@@ -119,6 +123,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;
@@ -129,6 +134,7 @@
/* Misc Functions */
ah->ah_getCapability = ar5416GetCapability;
+ ah->ah_setCapability = ar5416SetCapability;
ah->ah_getDiagState = ar5416GetDiagState;
ah->ah_setLedState = ar5416SetLedState;
ah->ah_gpioCfgOutput = ar5416GpioCfgOutput;
@@ -137,6 +143,7 @@
ah->ah_gpioSet = ar5416GpioSet;
ah->ah_gpioSetIntr = ar5416GpioSetIntr;
ah->ah_getTsf64 = ar5416GetTsf64;
+ ah->ah_setTsf64 = ar5416SetTsf64;
ah->ah_resetTsf = ar5416ResetTsf;
ah->ah_getRfGain = ar5416GetRfgain;
ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch;
@@ -143,6 +150,8 @@
ah->ah_setDecompMask = ar5416SetDecompMask;
ah->ah_setCoverageClass = ar5416SetCoverageClass;
ah->ah_setQuiet = ar5416SetQuiet;
+ ah->ah_getMibCycleCounts = ar5416GetMibCycleCounts;
+ ah->ah_setChainMasks = ar5416SetChainMasks;
ah->ah_resetKeyCacheEntry = ar5416ResetKeyCacheEntry;
ah->ah_setKeyCacheEntry = ar5416SetKeyCacheEntry;
@@ -150,9 +159,18 @@
/* DFS Functions */
ah->ah_enableDfs = ar5416EnableDfs;
ah->ah_getDfsThresh = ar5416GetDfsThresh;
+ ah->ah_getDfsDefaultThresh = ar5416GetDfsDefaultThresh;
ah->ah_procRadarEvent = ar5416ProcessRadarEvent;
ah->ah_isFastClockEnabled = ar5416IsFastClockEnabled;
+ /* Spectral Scan Functions */
+ ah->ah_spectralConfigure = ar5416ConfigureSpectralScan;
+ ah->ah_spectralGetConfig = ar5416GetSpectralParams;
+ ah->ah_spectralStart = ar5416StartSpectralScan;
+ ah->ah_spectralStop = ar5416StopSpectralScan;
+ ah->ah_spectralIsEnabled = ar5416IsSpectralEnabled;
+ ah->ah_spectralIsActive = ar5416IsSpectralActive;
+
/* Power Management Functions */
ah->ah_setPowerMode = ar5416SetPowerMode;
@@ -168,7 +186,9 @@
ah->ah_setupFirstTxDesc = ar5416SetupFirstTxDesc;
ah->ah_setupLastTxDesc = ar5416SetupLastTxDesc;
ah->ah_set11nRateScenario = ar5416Set11nRateScenario;
+ ah->ah_set11nAggrFirst = ar5416Set11nAggrFirst;
ah->ah_set11nAggrMiddle = ar5416Set11nAggrMiddle;
+ ah->ah_set11nAggrLast = ar5416Set11nAggrLast;
ah->ah_clr11nAggr = ar5416Clr11nAggr;
ah->ah_set11nBurstDuration = ar5416Set11nBurstDuration;
ah->ah_get11nExtBusy = ar5416Get11nExtBusy;
@@ -175,6 +195,7 @@
ah->ah_set11nMac2040 = ar5416Set11nMac2040;
ah->ah_get11nRxClear = ar5416Get11nRxClear;
ah->ah_set11nRxClear = ar5416Set11nRxClear;
+ ah->ah_set11nVirtMoreFrag = ar5416Set11nVirtualMoreFrag;
/* Interrupt functions */
ah->ah_isInterruptPending = ar5416IsInterruptPending;
@@ -181,6 +202,17 @@
ah->ah_getPendingInterrupts = ar5416GetPendingInterrupts;
ah->ah_setInterrupts = ar5416SetInterrupts;
+ /* Bluetooth Coexistence functions */
+ ah->ah_btCoexSetInfo = ar5416SetBTCoexInfo;
+ ah->ah_btCoexSetConfig = ar5416BTCoexConfig;
+ ah->ah_btCoexSetQcuThresh = ar5416BTCoexSetQcuThresh;
+ ah->ah_btCoexSetWeights = ar5416BTCoexSetWeights;
+ ah->ah_btCoexSetBmissThresh = ar5416BTCoexSetupBmissThresh;
+ ah->ah_btCoexSetParameter = ar5416BTCoexSetParameter;
+ ah->ah_btCoexDisable = ar5416BTCoexDisable;
+ ah->ah_btCoexEnable = ar5416BTCoexEnable;
+ AH5416(ah)->ah_btCoexSetDiversity = ar5416BTCoexAntennaDiversity;
+
ahp->ah_priv.ah_getWirelessModes= ar5416GetWirelessModes;
ahp->ah_priv.ah_eepromRead = ar5416EepromRead;
#ifdef AH_SUPPORT_WRITE_EEPROM
@@ -212,8 +244,37 @@
/* Enable all ANI functions to begin with */
AH5416(ah)->ah_ani_function = 0xffffffff;
- /* Set overridable ANI methods */
- AH5212(ah)->ah_aniControl = ar5416AniControl;
+ /* Set overridable ANI methods */
+ AH5212(ah)->ah_aniControl = ar5416AniControl;
+
+ /*
+ * Default FIFO Trigger levels
+ *
+ * These define how filled the TX FIFO needs to be before
+ * the baseband begins to be given some data.
+ *
+ * To be paranoid, we ensure that the TX trigger level always
+ * has at least enough space for two TX DMA to occur.
+ * The TX DMA size is currently hard-coded to AR_TXCFG_DMASZ_128B.
+ * That means we need to leave at least 256 bytes available in
+ * the TX DMA FIFO.
+ */
+#define AR_FTRIG_512B 0x00000080 // 5 bits total
+ /*
+ * AR9285/AR9271 have half the size TX FIFO compared to
+ * other devices
+ */
+ if (AR_SREV_KITE(ah) || AR_SREV_9271(ah)) {
+ AH5212(ah)->ah_txTrigLev = (AR_FTRIG_256B >> AR_FTRIG_S);
+ AH5212(ah)->ah_maxTxTrigLev = ((2048 / 64) - 1);
+ } else {
+ AH5212(ah)->ah_txTrigLev = (AR_FTRIG_512B >> AR_FTRIG_S);
+ AH5212(ah)->ah_maxTxTrigLev = ((4096 / 64) - 1);
+ }
+#undef AR_FTRIG_512B
+
+ /* And now leave some headspace - 256 bytes */
+ AH5212(ah)->ah_maxTxTrigLev -= 4;
}
uint32_t
@@ -246,7 +307,7 @@
HAL_STATUS ecode;
HAL_BOOL rfStatus;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
@@ -255,7 +316,7 @@
sizeof(ar5416Addac)
);
if (ahp5416 == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -337,7 +398,7 @@
OS_REG_WRITE(ah, AR_PHY(0), 0x00000007);
/* Read Radio Chip Rev Extract */
- AH_PRIVATE(ah)->ah_analog5GhzRev = ar5212GetRadioRev(ah);
+ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah);
switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) {
case AR_RAD5122_SREV_MAJOR: /* Fowl: 5G/2x2 */
case AR_RAD2122_SREV_MAJOR: /* Fowl: 2+5G/2x2 */
@@ -452,23 +513,74 @@
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)
{
u_int modesIndex, freqIndex;
@@ -578,6 +690,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 |
@@ -762,6 +876,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);
}
/*
@@ -821,7 +938,13 @@
pCap->halCompressSupport = AH_FALSE;
pCap->halBurstSupport = AH_TRUE;
- pCap->halFastFramesSupport = AH_FALSE; /* XXX? */
+ /*
+ * This is disabled for now; the net80211 layer needs to be
+ * taught when it is and isn't appropriate to enable FF processing
+ * with 802.11n NICs (it tries to enable both A-MPDU and
+ * fast frames, with very tragic crash-y results.)
+ */
+ pCap->halFastFramesSupport = AH_FALSE;
pCap->halChapTuningSupport = AH_TRUE;
pCap->halTurboPrimeSupport = AH_TRUE;
@@ -828,11 +951,14 @@
pCap->halTurboGSupport = pCap->halWirelessModes & HAL_MODE_108G;
pCap->halPSPollBroken = AH_TRUE; /* XXX fixed in later revs? */
+ pCap->halNumMRRetries = 4; /* Hardware supports 4 MRR */
+ pCap->halNumTxMaps = 1; /* Single TX ptr per descr */
pCap->halVEOLSupport = AH_TRUE;
pCap->halBssIdMaskSupport = AH_TRUE;
pCap->halMcastKeySrchSupport = AH_TRUE; /* Works on AR5416 and later */
pCap->halTsfAddSupport = AH_TRUE;
pCap->hal4AddrAggrSupport = AH_FALSE; /* Broken in Owl */
+ pCap->halSpectralScanSupport = AH_FALSE; /* AR9280 and later */
if (ath_hal_eepromGet(ah, AR_EEP_MAXQCU, &val) == HAL_OK)
pCap->halTotalQueues = val;
@@ -844,9 +970,9 @@
else
pCap->halKeyCacheSize = AR5416_KEYTABLE_SIZE;
- /* XXX not needed */
- pCap->halChanHalfRate = AH_FALSE; /* XXX ? */
- pCap->halChanQuarterRate = AH_FALSE; /* XXX ? */
+ /* XXX Which chips? */
+ pCap->halChanHalfRate = AH_TRUE;
+ pCap->halChanQuarterRate = AH_TRUE;
pCap->halTstampPrecision = 32;
pCap->halHwPhyCounterSupport = AH_TRUE;
@@ -863,7 +989,7 @@
;
pCap->halFastCCSupport = AH_TRUE;
- pCap->halNumGpioPins = 6;
+ pCap->halNumGpioPins = 14;
pCap->halWowSupport = AH_FALSE;
pCap->halWowMatchPatternExact = AH_FALSE;
pCap->halBtCoexSupport = AH_FALSE; /* XXX need support */
@@ -882,6 +1008,16 @@
/* AR5416 may have 3 antennas but is a 2x2 stream device */
pCap->halTxStreams = 2;
pCap->halRxStreams = 2;
+
+ /*
+ * If the TX or RX chainmask has less than 2 chains active,
+ * mark it as a 1-stream device for the relevant stream.
+ */
+ if (owl_get_ntxchains(pCap->halTxChainMask) == 1)
+ pCap->halTxStreams = 1;
+ /* XXX Eww */
+ if (owl_get_ntxchains(pCap->halRxChainMask) == 1)
+ pCap->halRxStreams = 1;
pCap->halRtsAggrLimit = 8*1024; /* Owl 2.0 limit */
pCap->halMbssidAggrSupport = AH_FALSE; /* Broken on Owl */
pCap->halForcePpmSupport = AH_TRUE;
@@ -892,6 +1028,12 @@
pCap->halEnhancedDfsSupport = AH_FALSE;
/* Hardware supports 32 bit TSF values in the RX descriptor */
pCap->halHasLongRxDescTsf = AH_TRUE;
+ /*
+ * BB Read WAR: this is only for AR5008/AR9001 NICs
+ * It is also set individually in the AR91xx attach functions.
+ */
+ if (AR_SREV_OWL(ah))
+ pCap->halHasBBReadWar = AH_TRUE;
if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) &&
ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) {
@@ -900,8 +1042,24 @@
pCap->halRfSilentSupport = AH_TRUE;
}
+ /*
+ * The MAC will mark frames as RXed if there's a descriptor
+ * to write them to. So if it hits a self-linked final descriptor,
+ * it'll keep ACKing frames even though they're being silently
+ * dropped. Thus, this particular feature of the driver can't
+ * be used for 802.11n devices.
+ */
ahpriv->ah_rxornIsFatal = AH_FALSE;
+ /*
+ * If it's a PCI NIC, ask the HAL OS layer to serialise
+ * register access, or SMP machines may cause the hardware
+ * to hang. This is applicable to AR5416 and AR9220; I'm not
+ * sure about AR9160 or AR9227.
+ */
+ if (! AH_PRIVATE(ah)->ah_ispcie)
+ pCap->halSerialiseRegWar = 1;
+
return AH_TRUE;
}
@@ -908,9 +1066,12 @@
static const char*
ar5416Probe(uint16_t vendorid, uint16_t devid)
{
- if (vendorid == ATHEROS_VENDOR_ID &&
- (devid == AR5416_DEVID_PCI || devid == AR5416_DEVID_PCIE))
- return "Atheros 5416";
+ if (vendorid == ATHEROS_VENDOR_ID) {
+ if (devid == AR5416_DEVID_PCI)
+ return "Atheros 5416";
+ if (devid == AR5416_DEVID_PCIE)
+ return "Atheros 5418";
+ }
return AH_NULL;
}
AH_CHIP(AR5416, ar5416Probe, ar5416Attach);
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c 225819 2011-09-28 03:03:23Z adrian $
*/
#include "opt_ah.h"
@@ -46,6 +47,7 @@
ar5416SetBeaconTimers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt)
{
uint32_t bperiod;
+ struct ath_hal_5212 *ahp = AH5212(ah);
OS_REG_WRITE(ah, AR_NEXT_TBTT, TU_TO_USEC(bt->bt_nexttbtt));
OS_REG_WRITE(ah, AR_NEXT_DBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextdba));
@@ -53,6 +55,7 @@
OS_REG_WRITE(ah, AR_NEXT_NDP, TU_TO_USEC(bt->bt_nextatim));
bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD);
+ ahp->ah_beaconInterval = bt->bt_intval & HAL_BEACON_PERIOD;
OS_REG_WRITE(ah, AR5416_BEACON_PERIOD, bperiod);
OS_REG_WRITE(ah, AR_DBA_PERIOD, bperiod);
OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod);
Added: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c (rev 0)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,395 @@
+/* $MidnightBSD$ */
+/*
+ * 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: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c 251483 2013-06-07 05:17:58Z 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.
+ */
+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);
+
+ /* Added Select GPIO5~8 instaed SPI */
+ if (AR_SREV_9271(ah)) {
+ uint32_t val;
+
+ val = OS_REG_READ(ah, AR9271_CLOCK_CONTROL);
+ val &= 0xFFFFFEFF;
+ OS_REG_WRITE(ah, AR9271_CLOCK_CONTROL, val);
+ }
+
+ 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);
+
+ HALDEBUG(ah, HAL_DEBUG_BT_COEX,
+ "%s: called; configType=%d\n",
+ __func__,
+ ahp->ah_btCoexConfigType);
+
+ 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);
+
+ /*
+ * Configure the antenna diversity setup.
+ * It's a no-op for AR9287; AR9285 overrides this
+ * as required.
+ */
+ AH5416(ah)->ah_btCoexSetDiversity(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);
+ }
+ }
+}
Property changes on: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h (rev 0)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,32 @@
+/* $MidnightBSD$ */
+/*
+ * 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: stable/10/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__ */
Property changes on: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_btcoex.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c 227411 2011-11-09 23:28:47Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_cal.h 219480 2011-03-11 11:35:36Z adrian $
*/
#ifndef _ATH_AR5416_CAL_H_
#define _ATH_AR5416_CAL_H_
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c 203158 2010-01-29 10:07:17Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c 203158 2010-01-29 10:07:17Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_cal_iq.c 211306 2010-08-14 15:28:15Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_eeprom.c 203158 2010-01-29 10:07:17Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c 237611 2012-06-26 22:16:53Z adrian $
*/
#include "opt_ah.h"
@@ -35,8 +36,11 @@
cfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type)
{
int addr;
- uint32_t gpio_shift, reg;
+ uint32_t gpio_shift, tmp;
+ HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d, type=%d\n",
+ __func__, gpio, type);
+
/* each MUX controls 6 GPIO pins */
if (gpio > 11)
addr = AR_GPIO_OUTPUT_MUX3;
@@ -61,12 +65,17 @@
* will never be used. So it should be fine that bit 4 won't be
* able to recover.
*/
- reg = OS_REG_READ(ah, addr);
- if (addr == AR_GPIO_OUTPUT_MUX1 && !AR_SREV_MERLIN_20_OR_LATER(ah))
- reg = ((reg & 0x1F0) << 1) | (reg & ~0x1F0);
- reg &= ~(0x1f << gpio_shift);
- reg |= type << gpio_shift;
- OS_REG_WRITE(ah, addr, reg);
+ if (AR_SREV_MERLIN_20_OR_LATER(ah) ||
+ (addr != AR_GPIO_OUTPUT_MUX1)) {
+ OS_REG_RMW(ah, addr, (type << gpio_shift),
+ (0x1f << gpio_shift));
+ } else {
+ tmp = OS_REG_READ(ah, addr);
+ tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
+ tmp &= ~(0x1f << gpio_shift);
+ tmp |= type << gpio_shift;
+ OS_REG_WRITE(ah, addr, tmp);
+ }
}
/*
@@ -77,12 +86,42 @@
{
uint32_t gpio_shift, reg;
+#define N(a) (sizeof(a) / sizeof(a[0]))
+
HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
- /* NB: type maps directly to hardware */
- cfgOutputMux(ah, gpio, type);
- gpio_shift = gpio << 1; /* 2 bits per output mode */
+ /*
+ * 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);
+
+ /*
+ * 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);
reg |= AR_GPIO_OE_OUT_DRV_ALL << gpio_shift;
@@ -89,6 +128,7 @@
OS_REG_WRITE(ah, AR_GPIO_OE_OUT, reg);
return AH_TRUE;
+#undef N
}
/*
@@ -101,6 +141,8 @@
HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
+ HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d\n", __func__, gpio);
+
/* TODO: configure input mux for AR5416 */
/* If configured as input, set output to tristate */
gpio_shift = gpio << 1;
@@ -122,6 +164,8 @@
uint32_t reg;
HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
+ HALDEBUG(ah, HAL_DEBUG_GPIO,
+ "%s: gpio=%d, val=%d\n", __func__, gpio, val);
reg = OS_REG_READ(ah, AR_GPIO_IN_OUT);
if (val & 1)
@@ -146,6 +190,8 @@
* Read output value for all gpio's, shift it,
* and verify whether the specific bit is set.
*/
+ if (AR_SREV_KIWI_10_OR_LATER(ah))
+ bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9287_GPIO_IN_VAL);
if (AR_SREV_KITE_10_OR_LATER(ah))
bits = MS(OS_REG_READ(ah, AR_GPIO_IN_OUT), AR9285_GPIO_IN_VAL);
else if (AR_SREV_MERLIN_10_OR_LATER(ah))
@@ -165,6 +211,8 @@
uint32_t val, mask;
HALASSERT(gpio < AH_PRIVATE(ah)->ah_caps.halNumGpioPins);
+ HALDEBUG(ah, HAL_DEBUG_GPIO,
+ "%s: gpio=%d, ilevel=%d\n", __func__, gpio, ilevel);
if (ilevel == HAL_GPIO_INTR_DISABLE) {
val = MS(OS_REG_READ(ah, AR_INTR_ASYNC_ENABLE),
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c 247030 2013-02-20 11:24:11Z adrian $
*/
#include "opt_ah.h"
@@ -67,9 +68,18 @@
HAL_BOOL
ar5416GetPendingInterrupts(struct ath_hal *ah, HAL_INT *masked)
{
- uint32_t isr, isr0, isr1, sync_cause = 0;
+ uint32_t isr, isr0, isr1, sync_cause = 0, o_sync_cause = 0;
+ HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
+#ifdef AH_INTERRUPT_DEBUGGING
/*
+ * Blank the interrupt debugging area regardless.
+ */
+ bzero(&ah->ah_intrstate, sizeof(ah->ah_intrstate));
+ ah->ah_syncstate = 0;
+#endif
+
+ /*
* Verify there's a mac interrupt and the RTC is on.
*/
if (AR_SREV_HOWL(ah)) {
@@ -81,7 +91,10 @@
isr = OS_REG_READ(ah, AR_ISR);
else
isr = 0;
- sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);
+#ifdef AH_INTERRUPT_DEBUGGING
+ ah->ah_syncstate =
+#endif
+ o_sync_cause = sync_cause = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);
sync_cause &= AR_INTR_SYNC_DEFAULT;
*masked = 0;
@@ -89,6 +102,16 @@
return AH_FALSE;
}
+#ifdef AH_INTERRUPT_DEBUGGING
+ ah->ah_intrstate[0] = isr;
+ ah->ah_intrstate[1] = OS_REG_READ(ah, AR_ISR_S0);
+ ah->ah_intrstate[2] = OS_REG_READ(ah, AR_ISR_S1);
+ ah->ah_intrstate[3] = OS_REG_READ(ah, AR_ISR_S2);
+ ah->ah_intrstate[4] = OS_REG_READ(ah, AR_ISR_S3);
+ ah->ah_intrstate[5] = OS_REG_READ(ah, AR_ISR_S4);
+ ah->ah_intrstate[6] = OS_REG_READ(ah, AR_ISR_S5);
+#endif
+
if (isr != 0) {
struct ath_hal_5212 *ahp = AH5212(ah);
uint32_t mask2;
@@ -110,9 +133,15 @@
mask2 |= HAL_INT_CST;
if (isr2 & AR_ISR_S2_TSFOOR)
mask2 |= HAL_INT_TSFOOR;
+
+ /*
+ * Don't mask out AR_BCNMISC; instead mask
+ * out what causes it.
+ */
+ OS_REG_WRITE(ah, AR_ISR_S2, isr2);
+ isr &= ~AR_ISR_BCNMISC;
}
- isr = OS_REG_READ(ah, AR_ISR_RAC);
if (isr == 0xffffffff) {
*masked = 0;
return AH_FALSE;
@@ -119,39 +148,87 @@
}
*masked = isr & HAL_INT_COMMON;
+
+ if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+ *masked |= HAL_INT_RX;
+ if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
+ *masked |= HAL_INT_TX;
+
+ /*
+ * When doing RX interrupt mitigation, the RXOK bit is set
+ * in AR_ISR even if the relevant bit in AR_IMR is clear.
+ * Since this interrupt may be due to another source, don't
+ * just automatically set HAL_INT_RX if it's set, otherwise
+ * we could prematurely service the RX queue.
+ *
+ * In some cases, the driver can even handle all the RX
+ * frames just before the mitigation interrupt fires.
+ * The subsequent RX processing trip will then end up
+ * processing 0 frames.
+ */
+#ifdef AH_AR5416_INTERRUPT_MITIGATION
+ if (isr & AR_ISR_RXERR)
+ *masked |= HAL_INT_RX;
+#else
if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
*masked |= HAL_INT_RX;
- if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) {
+#endif
+
+ if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
+ AR_ISR_TXEOL)) {
*masked |= HAL_INT_TX;
- isr0 = OS_REG_READ(ah, AR_ISR_S0_S);
+
+ isr0 = OS_REG_READ(ah, AR_ISR_S0);
+ OS_REG_WRITE(ah, AR_ISR_S0, isr0);
+ isr1 = OS_REG_READ(ah, AR_ISR_S1);
+ OS_REG_WRITE(ah, AR_ISR_S1, isr1);
+
+ /*
+ * Don't clear the primary ISR TX bits, clear
+ * what causes them (S0/S1.)
+ */
+ isr &= ~(AR_ISR_TXOK | AR_ISR_TXDESC |
+ AR_ISR_TXERR | AR_ISR_TXEOL);
+
ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXOK);
ahp->ah_intrTxqs |= MS(isr0, AR_ISR_S0_QCU_TXDESC);
- isr1 = OS_REG_READ(ah, AR_ISR_S1_S);
ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXERR);
ahp->ah_intrTxqs |= MS(isr1, AR_ISR_S1_QCU_TXEOL);
}
- if (AR_SREV_MERLIN(ah) || AR_SREV_KITE(ah)) {
+ if ((isr & AR_ISR_GENTMR) || (! pCap->halAutoSleepSupport)) {
uint32_t isr5;
- isr5 = OS_REG_READ(ah, AR_ISR_S5_S);
- if (isr5 & AR_ISR_S5_TIM_TIMER)
- *masked |= HAL_INT_TIM_TIMER;
+ isr5 = OS_REG_READ(ah, AR_ISR_S5);
+ OS_REG_WRITE(ah, AR_ISR_S5, isr5);
+ isr &= ~AR_ISR_GENTMR;
+
+ if (! pCap->halAutoSleepSupport)
+ if (isr5 & AR_ISR_S5_TIM_TIMER)
+ *masked |= HAL_INT_TIM_TIMER;
}
-
- /* Interrupt Mitigation on AR5416 */
-#ifdef AH_AR5416_INTERRUPT_MITIGATION
- if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
- *masked |= HAL_INT_RX;
- if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
- *masked |= HAL_INT_TX;
-#endif
*masked |= mask2;
}
+ /*
+ * Since we're not using AR_ISR_RAC, clear the status bits
+ * for handled interrupts here. For bits whose interrupt
+ * source is a secondary register, those bits should've been
+ * masked out - instead of those bits being written back,
+ * their source (ie, the secondary status registers) should
+ * be cleared. That way there are no race conditions with
+ * new triggers coming in whilst they've been read/cleared.
+ */
+ OS_REG_WRITE(ah, AR_ISR, isr);
+ /* Flush previous write */
+ OS_REG_READ(ah, AR_ISR);
+
if (AR_SREV_HOWL(ah))
return AH_TRUE;
if (sync_cause != 0) {
+ HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: sync_cause=0x%x\n",
+ __func__,
+ o_sync_cause);
if (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) {
*masked |= HAL_INT_FATAL;
}
@@ -216,18 +293,12 @@
* Overwrite default mask if Interrupt mitigation
* is specified for AR5416
*/
- mask = ints & HAL_INT_COMMON;
- if (ints & HAL_INT_TX)
- mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM;
if (ints & HAL_INT_RX)
mask |= AR_IMR_RXERR | AR_IMR_RXMINTR | AR_IMR_RXINTM;
- if (ints & HAL_INT_TX) {
- if (ahp->ah_txErrInterruptMask)
- mask |= AR_IMR_TXERR;
- if (ahp->ah_txEolInterruptMask)
- mask |= AR_IMR_TXEOL;
- }
#else
+ if (ints & HAL_INT_RX)
+ mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC;
+#endif
if (ints & HAL_INT_TX) {
if (ahp->ah_txOkInterruptMask)
mask |= AR_IMR_TXOK;
@@ -237,10 +308,9 @@
mask |= AR_IMR_TXDESC;
if (ahp->ah_txEolInterruptMask)
mask |= AR_IMR_TXEOL;
+ if (ahp->ah_txUrnInterruptMask)
+ mask |= AR_IMR_TXURN;
}
- if (ints & HAL_INT_RX)
- mask |= AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXDESC;
-#endif
if (ints & (HAL_INT_BMISC)) {
mask |= AR_IMR_BCNMISC;
if (ints & HAL_INT_TIM)
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_keycache.c 203158 2010-01-29 10:07:17Z rpaulo $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 250856 2013-05-21 14:28:05Z adrian $
*/
#include "opt_ah.h"
@@ -21,14 +22,14 @@
#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 "ah_eeprom_v14.h" /* for owl_get_ntxchains() */
+
/*
* Return the wireless modes (a,b,g,n,t) supported by hardware.
*
@@ -75,21 +76,29 @@
AR_MAC_LED_ASSOC_NONE,
AR_MAC_LED_ASSOC_NONE,
};
- uint32_t bits;
if (AR_SREV_HOWL(ah))
return;
- bits = OS_REG_READ(ah, AR_MAC_LED);
- bits = (bits &~ AR_MAC_LED_MODE)
- | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE)
-#if 1
- | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE)
-#endif
- ;
- bits = (bits &~ AR_MAC_LED_ASSOC)
- | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC);
- OS_REG_WRITE(ah, AR_MAC_LED, bits);
+ /*
+ * Set the blink operating mode.
+ */
+ OS_REG_RMW_FIELD(ah, AR_MAC_LED,
+ AR_MAC_LED_ASSOC, ledbits[state & 0x7]);
+
+ /* XXX Blink slow mode? */
+ /* XXX Blink threshold? */
+ /* XXX Blink sleep hystersis? */
+
+ /*
+ * Set the LED blink configuration to be proportional
+ * to the current TX and RX filter bytes. (Ie, RX'ed
+ * frames that don't match the filter are ignored.)
+ * This means that higher TX/RX throughput will result
+ * in the blink rate increasing.
+ */
+ OS_REG_RMW_FIELD(ah, AR_MAC_LED, AR_MAC_LED_MODE,
+ AR_MAC_LED_MODE_PROP);
}
/*
@@ -120,9 +129,36 @@
return (((uint64_t) u32) << 32) | ((uint64_t) low2);
}
+/*
+ * Update the TSF.
+ *
+ * The full TSF is only updated once the upper 32 bits have
+ * been written. Writing only the lower 32 bits of the TSF
+ * will not actually correctly update the TSF.
+ *
+ * The #if 0'ed code is to check whether the previous TSF
+ * reset or write has completed before writing to the
+ * TSF. Strictly speaking, it should be also checked before
+ * reading the TSF as the write/reset may not have completed.
+ */
void
ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64)
{
+ /* XXX check if this is correct! */
+#if 0
+ int i;
+ uint32_t v;
+
+ for (i = 0; i < 10; i++) {
+ v = OS_REG_READ(ah, AR_SLP32_MODE);
+ if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0)
+ break;
+ OS_DELAY(10);
+ }
+ if (i == 10)
+ ath_hal_printf(ah, "%s: couldn't slew things right!\n", __func__);
+#endif
+
OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
}
@@ -145,6 +181,14 @@
OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
}
+uint32_t
+ar5416GetCurRssi(struct ath_hal *ah)
+{
+ if (AR_SREV_OWL(ah))
+ return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
+ return (OS_REG_READ(ah, AR9130_PHY_CURRENT_RSSI) & 0xff);
+}
+
HAL_BOOL
ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
{
@@ -162,13 +206,76 @@
void
ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
{
- AH_PRIVATE(ah)->ah_coverageClass = coverageclass;
+
+ ar5212SetCoverageClass(ah, coverageclass, now);
}
/*
+ * Return the busy for rx_frame, rx_clear, and tx_frame
+ */
+HAL_BOOL
+ar5416GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u_int32_t good = AH_TRUE;
+
+ /* XXX freeze/unfreeze mib counters */
+ uint32_t rc = OS_REG_READ(ah, AR_RCCNT);
+ uint32_t ec = OS_REG_READ(ah, AR_EXTRCCNT);
+ uint32_t rf = OS_REG_READ(ah, AR_RFCNT);
+ uint32_t tf = OS_REG_READ(ah, AR_TFCNT);
+ uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */
+
+ if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) {
+ /*
+ * Cycle counter wrap (or initial call); it's not possible
+ * to accurately calculate a value because the registers
+ * right shift rather than wrap--so punt and return 0.
+ */
+ HALDEBUG(ah, HAL_DEBUG_ANY,
+ "%s: cycle counter wrap. ExtBusy = 0\n", __func__);
+ good = AH_FALSE;
+ } else {
+ 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;
+ }
+
+ /*
+ * 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);
+}
+
+/*
+ * Setup the TX/RX chainmasks - this needs to be done before a call
+ * to the reset method as it doesn't update the hardware.
+ */
+void
+ar5416SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask,
+ uint32_t rx_chainmask)
+{
+ HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
+
+ AH5416(ah)->ah_tx_chainmask = tx_chainmask & pCap->halTxChainMask;
+ AH5416(ah)->ah_rx_chainmask = rx_chainmask & pCap->halRxChainMask;
+}
+
+/*
* 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)
@@ -278,7 +385,7 @@
rxclear |= HAL_RX_CLEAR_CTL_LOW;
}
/* extension channel */
- if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
+ if (val & AR_DIAG_RXCLEAR_EXT_LOW) {
rxclear |= HAL_RX_CLEAR_EXT_LOW;
}
return rxclear;
@@ -359,6 +466,14 @@
HAL_OK : HAL_ENOTSUPP;
case HAL_CAP_DIVERSITY: /* disable classic fast diversity */
return HAL_ENXIO;
+ case HAL_CAP_ENFORCE_TXOP:
+ if (capability == 0)
+ return (HAL_OK);
+ if (capability != 1)
+ return (HAL_ENOTSUPP);
+ (*result) =
+ !! (AH5212(ah)->ah_miscMode & AR_PCU_TXOP_TBTT_LIMIT_ENA);
+ return (HAL_OK);
default:
break;
}
@@ -365,6 +480,50 @@
return ar5212GetCapability(ah, type, capability, result);
}
+HAL_BOOL
+ar5416SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
+ u_int32_t capability, u_int32_t setting, HAL_STATUS *status)
+{
+ HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
+
+ switch (type) {
+ case HAL_CAP_RX_CHAINMASK:
+ setting &= ath_hal_eepromGet(ah, AR_EEP_RXMASK, NULL);
+ pCap->halRxChainMask = setting;
+ if (owl_get_ntxchains(setting) > 2)
+ pCap->halRxStreams = 2;
+ else
+ pCap->halRxStreams = 1;
+ return AH_TRUE;
+ case HAL_CAP_TX_CHAINMASK:
+ setting &= ath_hal_eepromGet(ah, AR_EEP_TXMASK, NULL);
+ pCap->halTxChainMask = setting;
+ if (owl_get_ntxchains(setting) > 2)
+ pCap->halTxStreams = 2;
+ else
+ pCap->halTxStreams = 1;
+ return AH_TRUE;
+ case HAL_CAP_ENFORCE_TXOP:
+ if (capability != 1)
+ return AH_FALSE;
+ if (setting) {
+ AH5212(ah)->ah_miscMode
+ |= AR_PCU_TXOP_TBTT_LIMIT_ENA;
+ OS_REG_SET_BIT(ah, AR_MISC_MODE,
+ AR_PCU_TXOP_TBTT_LIMIT_ENA);
+ } else {
+ AH5212(ah)->ah_miscMode
+ &= ~AR_PCU_TXOP_TBTT_LIMIT_ENA;
+ OS_REG_CLR_BIT(ah, AR_MISC_MODE,
+ AR_PCU_TXOP_TBTT_LIMIT_ENA);
+ }
+ return AH_TRUE;
+ default:
+ break;
+ }
+ return ar5212SetCapability(ah, type, capability, setting, status);
+}
+
static int ar5416DetectMacHang(struct ath_hal *ah);
static int ar5416DetectBBHang(struct ath_hal *ah);
@@ -400,36 +559,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)
@@ -624,157 +753,3 @@
#undef N
}
#undef NUM_STATUS_READS
-
-/*
- * Get the radar parameter values and return them in the pe
- * structure
- */
-void
-ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
-{
- uint32_t val, temp;
-
- val = OS_REG_READ(ah, AR_PHY_RADAR_0);
-
- temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
- temp |= 0xFFFFFF80;
- pe->pe_firpwr = temp;
- pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
- pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);
- pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
- pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
-
- val = OS_REG_READ(ah, AR_PHY_RADAR_1);
- temp = val & AR_PHY_RADAR_1_RELPWR_ENA;
- pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
- if (temp)
- pe->pe_relpwr |= HAL_PHYERR_PARAM_ENABLE;
- temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK;
- pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
- if (temp)
- pe->pe_enabled = 1;
- else
- pe->pe_enabled = 0;
-
- pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
- pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
- AR_PHY_RADAR_EXT_ENA);
-
- pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
- AR_PHY_RADAR_1_USE_FIR128);
- pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
- AR_PHY_RADAR_1_BLOCK_CHECK);
- pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
- AR_PHY_RADAR_1_MAX_RRSSI);
-}
-
-/*
- * Enable radar detection and set the radar parameters per the
- * values in pe
- */
-void
-ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
-{
- uint32_t val;
-
- val = OS_REG_READ(ah, AR_PHY_RADAR_0);
-
- if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
- val &= ~AR_PHY_RADAR_0_FIRPWR;
- val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
- }
- if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
- val &= ~AR_PHY_RADAR_0_RRSSI;
- val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
- }
- if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
- val &= ~AR_PHY_RADAR_0_HEIGHT;
- val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
- }
- if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
- val &= ~AR_PHY_RADAR_0_PRSSI;
- val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
- }
- if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
- val &= ~AR_PHY_RADAR_0_INBAND;
- val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
- }
-
- /*Enable FFT data*/
- val |= AR_PHY_RADAR_0_FFT_ENA;
-
- OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA);
-
- if (pe->pe_usefir128 == 1)
- OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
- else if (pe->pe_usefir128 == 0)
- OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
-
- if (pe->pe_enmaxrssi == 1)
- OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
- else if (pe->pe_enmaxrssi == 0)
- OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
-
- if (pe->pe_blockradar == 1)
- OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
- else if (pe->pe_blockradar == 0)
- OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
-
- if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
- val = OS_REG_READ(ah, AR_PHY_RADAR_1);
- val &= ~AR_PHY_RADAR_1_MAXLEN;
- val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
- OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
- }
-
- /*
- * Enable HT/40 if the upper layer asks;
- * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
- * is available.
- */
- if (pe->pe_extchannel == 1)
- OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
- else if (pe->pe_extchannel == 0)
- OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
-
- if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
- val = OS_REG_READ(ah, AR_PHY_RADAR_1);
- val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
- val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
- OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
- }
- if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
- val = OS_REG_READ(ah, AR_PHY_RADAR_1);
- val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
- val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
- OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
- }
-}
-
-/*
- * Extract the radar event information from the given phy error.
- *
- * Returns AH_TRUE if the phy error was actually a phy error,
- * AH_FALSE if the phy error wasn't a phy error.
- */
-HAL_BOOL
-ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
- uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
-{
- /*
- * For now, this isn't implemented.
- */
- return AH_FALSE;
-}
-
-/*
- * Return whether fast-clock is currently enabled for this
- * channel.
- */
-HAL_BOOL
-ar5416IsFastClockEnabled(struct ath_hal *ah)
-{
- struct ath_hal_private *ahp = AH_PRIVATE(ah);
-
- return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
-}
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_phy.c 218908 2011-02-21 05:10:34Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_power.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_power.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_power.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_power.c 234269 2012-04-14 04:40:11Z adrian $
*/
#include "opt_ah.h"
@@ -50,6 +51,7 @@
& AR_RTC_PM_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
goto bad;
+ AH5416(ah)->ah_initPLL(ah, AH_NULL);
}
if (AR_SREV_HOWL(ah))
Added: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c (rev 0)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,433 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 2010-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: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c 239638 2012-08-24 01:29:46Z adrian $
+ */
+#include "opt_ah.h"
+
+#include "ah.h"
+#include "ah_internal.h"
+#include "ah_devid.h"
+#include "ah_desc.h" /* NB: for HAL_PHYERR* */
+
+#include "ar5416/ar5416.h"
+#include "ar5416/ar5416reg.h"
+#include "ar5416/ar5416phy.h"
+
+#include "ah_eeprom_v14.h" /* for owl_get_ntxchains() */
+
+/*
+ * These are default parameters for the AR5416 and
+ * later 802.11n NICs. They simply enable some
+ * radar pulse event generation.
+ *
+ * These are very likely not valid for the AR5212 era
+ * NICs.
+ *
+ * Since these define signal sizing and threshold
+ * parameters, they may need changing based on the
+ * specific antenna and receive amplifier
+ * configuration.
+ */
+#define AR5416_DFS_FIRPWR -33
+#define AR5416_DFS_RRSSI 20
+#define AR5416_DFS_HEIGHT 10
+#define AR5416_DFS_PRSSI 15
+#define AR5416_DFS_INBAND 15
+#define AR5416_DFS_RELPWR 8
+#define AR5416_DFS_RELSTEP 12
+#define AR5416_DFS_MAXLEN 255
+
+HAL_BOOL
+ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+
+ /*
+ * These are general examples of the parameter values
+ * to use when configuring radar pulse detection for
+ * the AR5416, AR91xx, AR92xx NICs. They are only
+ * for testing and do require tuning depending upon the
+ * hardware and deployment specifics.
+ */
+ pe->pe_firpwr = AR5416_DFS_FIRPWR;
+ pe->pe_rrssi = AR5416_DFS_RRSSI;
+ pe->pe_height = AR5416_DFS_HEIGHT;
+ pe->pe_prssi = AR5416_DFS_PRSSI;
+ pe->pe_inband = AR5416_DFS_INBAND;
+ pe->pe_relpwr = AR5416_DFS_RELPWR;
+ pe->pe_relstep = AR5416_DFS_RELSTEP;
+ pe->pe_maxlen = AR5416_DFS_MAXLEN;
+
+ return (AH_TRUE);
+}
+
+/*
+ * Get the radar parameter values and return them in the pe
+ * structure
+ */
+void
+ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+ uint32_t val, temp;
+
+ val = OS_REG_READ(ah, AR_PHY_RADAR_0);
+
+ temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
+ temp |= 0xFFFFFF80;
+ pe->pe_firpwr = temp;
+ pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
+ pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT);
+ pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
+ pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
+
+ /* RADAR_1 values */
+ val = OS_REG_READ(ah, AR_PHY_RADAR_1);
+ pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
+ pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
+ pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
+
+ pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
+ AR_PHY_RADAR_EXT_ENA);
+
+ pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
+ AR_PHY_RADAR_1_USE_FIR128);
+ pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
+ AR_PHY_RADAR_1_BLOCK_CHECK);
+ pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
+ AR_PHY_RADAR_1_MAX_RRSSI);
+ pe->pe_enabled = !!
+ (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
+ pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
+ AR_PHY_RADAR_1_RELPWR_ENA);
+ pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
+ AR_PHY_RADAR_1_RELSTEP_CHECK);
+}
+
+/*
+ * Enable radar detection and set the radar parameters per the
+ * values in pe
+ */
+void
+ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
+{
+ uint32_t val;
+
+ val = OS_REG_READ(ah, AR_PHY_RADAR_0);
+
+ if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
+ val &= ~AR_PHY_RADAR_0_FIRPWR;
+ val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
+ }
+ if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
+ val &= ~AR_PHY_RADAR_0_RRSSI;
+ val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
+ }
+ if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
+ val &= ~AR_PHY_RADAR_0_HEIGHT;
+ val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
+ }
+ if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
+ val &= ~AR_PHY_RADAR_0_PRSSI;
+ val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
+ }
+ if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
+ val &= ~AR_PHY_RADAR_0_INBAND;
+ val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
+ }
+
+ /*Enable FFT data*/
+ val |= AR_PHY_RADAR_0_FFT_ENA;
+ OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
+
+ /* Implicitly enable */
+ if (pe->pe_enabled == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+ else if (pe->pe_enabled == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+
+ if (pe->pe_usefir128 == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
+ else if (pe->pe_usefir128 == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
+
+ if (pe->pe_enmaxrssi == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
+ else if (pe->pe_enmaxrssi == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
+
+ if (pe->pe_blockradar == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
+ else if (pe->pe_blockradar == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
+
+ if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
+ val = OS_REG_READ(ah, AR_PHY_RADAR_1);
+ val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
+ val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
+ OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
+ }
+ if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
+ val = OS_REG_READ(ah, AR_PHY_RADAR_1);
+ val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
+ val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
+ OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
+ }
+
+ if (pe->pe_en_relstep_check == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
+ AR_PHY_RADAR_1_RELSTEP_CHECK);
+ else if (pe->pe_en_relstep_check == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
+ AR_PHY_RADAR_1_RELSTEP_CHECK);
+
+ if (pe->pe_enrelpwr == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
+ AR_PHY_RADAR_1_RELPWR_ENA);
+ else if (pe->pe_enrelpwr == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
+ AR_PHY_RADAR_1_RELPWR_ENA);
+
+ if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
+ val = OS_REG_READ(ah, AR_PHY_RADAR_1);
+ val &= ~AR_PHY_RADAR_1_MAXLEN;
+ val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
+ OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
+ }
+
+ /*
+ * Enable HT/40 if the upper layer asks;
+ * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
+ * is available.
+ */
+ if (pe->pe_extchannel == 1)
+ OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+ else if (pe->pe_extchannel == 0)
+ OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+}
+
+/*
+ * Extract the radar event information from the given phy error.
+ *
+ * Returns AH_TRUE if the phy error was actually a phy error,
+ * AH_FALSE if the phy error wasn't a phy error.
+ */
+
+/* Flags for pulse_bw_info */
+#define PRI_CH_RADAR_FOUND 0x01
+#define EXT_CH_RADAR_FOUND 0x02
+#define EXT_CH_RADAR_EARLY_FOUND 0x04
+
+HAL_BOOL
+ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
+ uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
+{
+ HAL_BOOL doDfsExtCh;
+ HAL_BOOL doDfsEnhanced;
+ HAL_BOOL doDfsCombinedRssi;
+
+ uint8_t rssi = 0, ext_rssi = 0;
+ uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
+ uint32_t dur = 0;
+ int pri_found = 1, ext_found = 0;
+ int early_ext = 0;
+ int is_dc = 0;
+ uint16_t datalen; /* length from the RX status field */
+
+ /* Check whether the given phy error is a radar event */
+ if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
+ (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
+ return AH_FALSE;
+ }
+
+ /* Grab copies of the capabilities; just to make the code clearer */
+ doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
+ doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
+ doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
+
+ datalen = rxs->rs_datalen;
+
+ /* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
+ if (doDfsCombinedRssi)
+ rssi = (uint8_t) rxs->rs_rssi;
+ else
+ rssi = (uint8_t) rxs->rs_rssi_ctl[0];
+
+ /* Set this; but only use it if doDfsExtCh is set */
+ ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
+
+ /* Cap it at 0 if the RSSI is a negative number */
+ if (rssi & 0x80)
+ rssi = 0;
+
+ if (ext_rssi & 0x80)
+ ext_rssi = 0;
+
+ /*
+ * Fetch the relevant data from the frame
+ */
+ if (doDfsExtCh) {
+ if (datalen < 3)
+ return AH_FALSE;
+
+ /* Last three bytes of the frame are of interest */
+ pulse_length_pri = *(buf + datalen - 3);
+ pulse_length_ext = *(buf + datalen - 2);
+ pulse_bw_info = *(buf + datalen - 1);
+ HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
+ " pulse_length_ext=%d, pulse_bw_info=%x\n",
+ __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
+ pulse_bw_info);
+ } else {
+ /* The pulse width is byte 0 of the data */
+ if (datalen >= 1)
+ dur = ((uint8_t) buf[0]) & 0xff;
+ else
+ dur = 0;
+
+ if (dur == 0 && rssi == 0) {
+ HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
+ return AH_FALSE;
+ }
+
+ HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
+
+ /* Single-channel only */
+ pri_found = 1;
+ ext_found = 0;
+ }
+
+ /*
+ * If doing extended channel data, pulse_bw_info must
+ * have one of the flags set.
+ */
+ if (doDfsExtCh && pulse_bw_info == 0x0)
+ return AH_FALSE;
+
+ /*
+ * If the extended channel data is available, calculate
+ * which to pay attention to.
+ */
+ if (doDfsExtCh) {
+ /* If pulse is on DC, take the larger duration of the two */
+ if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
+ (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
+ is_dc = 1;
+ if (pulse_length_ext > pulse_length_pri) {
+ dur = pulse_length_ext;
+ pri_found = 0;
+ ext_found = 1;
+ } else {
+ dur = pulse_length_pri;
+ pri_found = 1;
+ ext_found = 0;
+ }
+ } else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
+ dur = pulse_length_ext;
+ pri_found = 0;
+ ext_found = 1;
+ early_ext = 1;
+ } else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
+ dur = pulse_length_pri;
+ pri_found = 1;
+ ext_found = 0;
+ } else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
+ dur = pulse_length_ext;
+ pri_found = 0;
+ ext_found = 1;
+ }
+
+ }
+
+ /*
+ * For enhanced DFS (Merlin and later), pulse_bw_info has
+ * implications for selecting the correct RSSI value.
+ */
+ if (doDfsEnhanced) {
+ switch (pulse_bw_info & 0x03) {
+ case 0:
+ /* No radar? */
+ rssi = 0;
+ break;
+ case PRI_CH_RADAR_FOUND:
+ /* Radar in primary channel */
+ /* Cannot use ctrl channel RSSI if ext channel is stronger */
+ if (ext_rssi >= (rssi + 3)) {
+ rssi = 0;
+ };
+ break;
+ case EXT_CH_RADAR_FOUND:
+ /* Radar in extended channel */
+ /* Cannot use ext channel RSSI if ctrl channel is stronger */
+ if (rssi >= (ext_rssi + 12)) {
+ rssi = 0;
+ } else {
+ rssi = ext_rssi;
+ }
+ break;
+ case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
+ /* When both are present, use stronger one */
+ if (rssi < ext_rssi)
+ rssi = ext_rssi;
+ break;
+ }
+ }
+
+ /*
+ * If not doing enhanced DFS, choose the ext channel if
+ * it is stronger than the main channel
+ */
+ if (doDfsExtCh && !doDfsEnhanced) {
+ if ((ext_rssi > rssi) && (ext_rssi < 128))
+ rssi = ext_rssi;
+ }
+
+ /*
+ * XXX what happens if the above code decides the RSSI
+ * XXX wasn't valid, an sets it to 0?
+ */
+
+ /*
+ * Fill out dfs_event structure.
+ */
+ event->re_full_ts = fulltsf;
+ event->re_ts = rxs->rs_tstamp;
+ event->re_rssi = rssi;
+ event->re_dur = dur;
+
+ event->re_flags = 0;
+ if (pri_found)
+ event->re_flags |= HAL_DFS_EVENT_PRICH;
+ if (ext_found)
+ event->re_flags |= HAL_DFS_EVENT_EXTCH;
+ if (early_ext)
+ event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
+ if (is_dc)
+ event->re_flags |= HAL_DFS_EVENT_ISDC;
+
+ return AH_TRUE;
+}
+
+/*
+ * Return whether fast-clock is currently enabled for this
+ * channel.
+ */
+HAL_BOOL
+ar5416IsFastClockEnabled(struct ath_hal *ah)
+{
+ struct ath_hal_private *ahp = AH_PRIVATE(ah);
+
+ return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
+}
Property changes on: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_recv.c 250346 2013-05-08 01:11:25Z adrian $
*/
#include "opt_ah.h"
@@ -67,6 +68,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
@@ -107,7 +142,6 @@
uint32_t size, u_int flags)
{
struct ar5416_desc *ads = AR5416DESC(ds);
- HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
HALASSERT((size &~ AR_BufLen) == 0);
@@ -119,8 +153,7 @@
ads->ds_rxstatus8 &= ~AR_RxDone;
/* clear the rest of the status fields */
- if (! pCap->halAutoSleepSupport)
- OS_MEMZERO(&(ads->u), sizeof(ads->u));
+ OS_MEMZERO(&(ads->u), sizeof(ads->u));
return AH_TRUE;
}
@@ -177,6 +210,14 @@
if (ads->ds_rxstatus3 & AR_2040)
rs->rs_flags |= HAL_RX_2040;
+ /*
+ * Only the AR9280 and later chips support STBC RX, so
+ * ensure we only set this bit for those chips.
+ */
+ if (AR_SREV_MERLIN_10_OR_LATER(ah)
+ && ads->ds_rxstatus3 & AR_STBCFrame)
+ rs->rs_flags |= HAL_RX_STBC;
+
if (ads->ds_rxstatus8 & AR_PreDelimCRCErr)
rs->rs_flags |= HAL_RX_DELIM_CRC_PRE;
if (ads->ds_rxstatus8 & AR_PostDelimCRCErr)
@@ -196,15 +237,40 @@
* Consequently we filter them out here so we don't
* confuse and/or complicate drivers.
*/
- if (ads->ds_rxstatus8 & AR_CRCErr)
- rs->rs_status |= HAL_RXERR_CRC;
- else if (ads->ds_rxstatus8 & AR_PHYErr) {
+
+ /*
+ * 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;
- rs->rs_status |= HAL_RXERR_PHY;
+ /*
+ * 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);
- rs->rs_phyerr = phyerr;
- } else if (ads->ds_rxstatus8 & AR_DecryptCRCErr)
+
+ 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_DecryptCRCErr)
rs->rs_status |= HAL_RXERR_DECRYPT;
else if (ads->ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= HAL_RXERR_MIC;
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c 251483 2013-06-07 05:17:58Z adrian $
*/
#include "opt_ah.h"
@@ -44,7 +45,6 @@
static void ar5416InitIMR(struct ath_hal *ah, HAL_OPMODE opmode);
static void ar5416InitQoS(struct ath_hal *ah);
static void ar5416InitUserSettings(struct ath_hal *ah);
-static void ar5416UpdateChainMasks(struct ath_hal *ah, HAL_BOOL is_ht);
static void ar5416OverrideIni(struct ath_hal *ah, const struct ieee80211_channel *);
#if 0
@@ -62,6 +62,8 @@
uint16_t powerLimit);
static void ar5416Set11nRegs(struct ath_hal *ah, const struct ieee80211_channel *chan);
static void ar5416MarkPhyInactive(struct ath_hal *ah);
+static void ar5416SetIFSTiming(struct ath_hal *ah,
+ const struct ieee80211_channel *chan);
/*
* Places the device in and out of reset and then places sane
@@ -118,6 +120,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
@@ -132,7 +137,20 @@
* Preserve the antenna on a channel change
*/
saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA);
- if (saveDefAntenna == 0) /* XXX magic constants */
+
+ /*
+ * Don't do this for the AR9285 - it breaks RX for single
+ * antenna designs when diversity is disabled.
+ *
+ * I'm not sure what this was working around; it may be
+ * something to do with the AR5416. Certainly this register
+ * isn't supposed to be used by the MIMO chips for anything
+ * except for defining the default antenna when an external
+ * phase array / smart antenna is connected.
+ *
+ * See PR: kern/179269 .
+ */
+ if ((! AR_SREV_KITE(ah)) && saveDefAntenna == 0) /* XXX magic constants */
saveDefAntenna = 1;
/* Save hardware flag before chip reset clears the register */
@@ -146,7 +164,9 @@
/* For chips on which the RTC reset is done, save TSF before it gets cleared */
if (AR_SREV_HOWL(ah) ||
- (AR_SREV_MERLIN(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)))
+ (AR_SREV_MERLIN(ah) &&
+ ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) ||
+ (ah->ah_config.ah_force_full_reset))
tsf = ar5416GetTsf64(ah);
/* Mark PHY as inactive; marked active in ar5416InitBB() */
@@ -203,11 +223,6 @@
__func__, OS_REG_READ(ah,AR_PHY_ADC_CTL));
/*
- * Setup ah_tx_chainmask / ah_rx_chainmask before we fiddle
- * with enabling the TX/RX radio chains.
- */
- ar5416UpdateChainMasks(ah, IEEE80211_IS_CHAN_HT(chan));
- /*
* This routine swaps the analog chains - it should be done
* before any radio register twiddling is done.
*/
@@ -275,12 +290,19 @@
ar5416StartTsf2(ah);
#endif
+ /*
+ * Enable Bluetooth Coexistence if it's enabled.
+ */
+ if (AH5416(ah)->ah_btCoexConfigType != HAL_BT_COEX_CFG_NONE)
+ ar5416InitBTCoex(ah);
+
/* Restore previous antenna */
OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
- /* then our BSSID */
+ /* then our BSSID and associate id */
OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
- OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));
+ OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4) |
+ (ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S);
/* Restore bmiss rssi & count thresholds */
OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr);
@@ -304,11 +326,26 @@
ah->ah_resetTxQueue(ah, i);
ar5416InitIMR(ah, opmode);
- ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);
+ ar5416SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1);
ar5416InitQoS(ah);
/* This may override the AR_DIAG_SW register */
ar5416InitUserSettings(ah);
+ /* XXX this won't work for AR9287! */
+ if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {
+ ar5416SetIFSTiming(ah, chan);
+#if 0
+ /*
+ * AR5413?
+ * Force window_length for 1/2 and 1/4 rate channels,
+ * the ini file sets this to zero otherwise.
+ */
+ OS_REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
+ AR_PHY_FRAME_CTL_WINLEN, 3);
+ }
+#endif
+ }
+
if (AR_SREV_KIWI_13_OR_LATER(ah)) {
/*
* Enable ASYNC FIFO
@@ -357,13 +394,33 @@
*/
OS_REG_WRITE(ah, AR_OBS, 8);
-#ifdef AH_AR5416_INTERRUPT_MITIGATION
+ /*
+ * Disable the "general" TX/RX mitigation timers.
+ */
OS_REG_WRITE(ah, AR_MIRT, 0);
- OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
- OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
- OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300);
- OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750);
+#ifdef AH_AR5416_INTERRUPT_MITIGATION
+ /*
+ * This initialises the RX interrupt mitigation timers.
+ *
+ * The mitigation timers begin at idle and are triggered
+ * upon the RXOK of a single frame (or sub-frame, for A-MPDU.)
+ * Then, the RX mitigation interrupt will fire:
+ *
+ * + 250uS after the last RX'ed frame, or
+ * + 700uS after the first RX'ed frame
+ *
+ * Thus, the LAST field dictates the extra latency
+ * induced by the RX mitigation method and the FIRST
+ * field dictates how long to delay before firing an
+ * RX mitigation interrupt.
+ *
+ * Please note this only seems to be for RXOK frames;
+ * not CRC or PHY error frames.
+ *
+ */
+ OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 250);
+ OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 700);
#endif
ar5416InitBB(ah, chan);
@@ -527,6 +584,10 @@
/*
* let mac dma writes be in 128 byte chunks
*/
+ /*
+ * XXX If you change this, you must change the headroom
+ * assigned in ah_maxTxTrigLev - see ar5416InitState().
+ */
OS_REG_WRITE(ah, AR_RXCFG,
(OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK) | AR_RXCFG_DMASZ_128B);
@@ -610,11 +671,11 @@
| AR_IMR_BCNMISC;
#ifdef AH_AR5416_INTERRUPT_MITIGATION
- ahp->ah_maskReg |= AR_IMR_TXINTM | AR_IMR_RXINTM
- | AR_IMR_TXMINTR | AR_IMR_RXMINTR;
+ ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
#else
- ahp->ah_maskReg |= AR_IMR_TXOK | AR_IMR_RXOK;
+ ahp->ah_maskReg |= AR_IMR_RXOK;
#endif
+ ahp->ah_maskReg |= AR_IMR_TXOK;
if (opmode == HAL_M_HOSTAP)
ahp->ah_maskReg |= AR_IMR_MIB;
@@ -666,7 +727,8 @@
/* Restore user-specified settings */
if (ahp->ah_miscMode != 0)
- OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode);
+ OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE)
+ | ahp->ah_miscMode);
if (ahp->ah_sifstime != (u_int) -1)
ar5212SetSifsTime(ah, ahp->ah_sifstime);
if (ahp->ah_slottime != (u_int) -1)
@@ -701,6 +763,7 @@
rfMode |= IEEE80211_IS_CHAN_5GHZ(chan) ?
AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
}
+
OS_REG_WRITE(ah, AR_PHY_MODE, rfMode);
}
@@ -712,12 +775,15 @@
{
OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0);
/*
- * Warm reset is optimistic.
+ * Warm reset is optimistic for open-loop TX power control.
*/
if (AR_SREV_MERLIN(ah) &&
ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
return AH_FALSE;
+ } else if (ah->ah_config.ah_force_full_reset) {
+ if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON))
+ return AH_FALSE;
} else {
if (!ar5416SetResetReg(ah, HAL_RESET_WARM))
return AH_FALSE;
@@ -959,6 +1025,14 @@
| POW_SM(ratesArray[rateDupCck], 0)
);
}
+
+ /*
+ * Set max power to 30 dBm and, optionally,
+ * enable TPC in tx descriptors.
+ */
+ OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER |
+ (AH5212(ah)->ah_tpcEnabled ? AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE : 0));
+#undef POW_SM
}
@@ -973,12 +1047,11 @@
const struct ieee80211_channel *chan, uint16_t *rfXpdGain)
{
#define N(a) (sizeof (a) / sizeof (a[0]))
+#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
MODAL_EEP_HEADER *pModal;
struct ath_hal_5212 *ahp = AH5212(ah);
- int16_t ratesArray[Ar5416RateSize];
int16_t txPowerIndexOffset = 0;
- uint8_t ht40PowerIncForPdadc = 2;
int i;
uint16_t cfgCtl;
@@ -991,8 +1064,13 @@
HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
+ /*
+ * Default to 2, is overridden based on the EEPROM version / value.
+ */
+ AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
+
/* Setup info for the actual eeprom */
- OS_MEMZERO(ratesArray, sizeof(ratesArray));
+ OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray));
cfgCtl = ath_hal_getctl(ah, chan);
powerLimit = chan->ic_maxregpower * 2;
twiceAntennaReduction = chan->ic_maxantgain;
@@ -1002,11 +1080,12 @@
__func__,chan->ic_freq, cfgCtl );
if (IS_EEP_MINOR_V2(ah)) {
- ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
}
if (!ar5416SetPowerPerRateTable(ah, pEepData, chan,
- &ratesArray[0],cfgCtl,
+ &AH5416(ah)->ah_ratesArray[0],
+ cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower, powerLimit)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
@@ -1020,14 +1099,15 @@
return AH_FALSE;
}
- maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
+ maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
+ AH5416(ah)->ah_ratesArray[rateHt20_0]);
if (IEEE80211_IS_CHAN_2GHZ(chan)) {
- maxPower = AH_MAX(maxPower, ratesArray[rate1l]);
+ maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]);
}
if (IEEE80211_IS_CHAN_HT40(chan)) {
- maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]);
+ maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]);
}
ahp->ah_tx6PowerInHalfDbm = maxPower;
@@ -1038,10 +1118,11 @@
* txPowerIndexOffset is set by the SetPowerTable() call -
* adjust the rate table (0 offset if rates EEPROM not loaded)
*/
- for (i = 0; i < N(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
+ for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
+ AH5416(ah)->ah_ratesArray[i] =
+ (int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]);
+ if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
+ AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
}
#ifdef AH_EEPROM_DUMP
@@ -1052,7 +1133,7 @@
* this debugging; the values won't necessarily be what's being
* programmed into the hardware.
*/
- ar5416PrintPowerPerRate(ah, ratesArray);
+ ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
#endif
/*
@@ -1068,16 +1149,16 @@
&pwr_table_offset);
/* Underflow power gets clamped at raw value 0 */
/* Overflow power gets camped at AR5416_MAX_RATE_POWER */
- for (i = 0; i < N(ratesArray); i++) {
+ for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
/*
* + pwr_table_offset is in dBm
* + ratesArray is in 1/2 dBm
*/
- ratesArray[i] -= (pwr_table_offset * 2);
- if (ratesArray[i] < 0)
- ratesArray[i] = 0;
- else if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
+ AH5416(ah)->ah_ratesArray[i] -= (pwr_table_offset * 2);
+ if (AH5416(ah)->ah_ratesArray[i] < 0)
+ AH5416(ah)->ah_ratesArray[i] = 0;
+ else if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
+ AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
}
}
@@ -1104,9 +1185,9 @@
int cck_ofdm_delta = 2;
int i;
for (i = 0; i < N(adj); i++) {
- ratesArray[adj[i]] -= cck_ofdm_delta;
- if (ratesArray[adj[i]] < 0)
- ratesArray[adj[i]] = 0;
+ AH5416(ah)->ah_ratesArray[adj[i]] -= cck_ofdm_delta;
+ if (AH5416(ah)->ah_ratesArray[adj[i]] < 0)
+ AH5416(ah)->ah_ratesArray[adj[i]] = 0;
}
}
@@ -1118,18 +1199,20 @@
* XXX handle overflow/too high power level?
*/
if (IEEE80211_IS_CHAN_HT40(chan)) {
- ratesArray[rateHt40_0] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_1] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_2] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_3] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_4] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_5] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_6] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_7] += ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_0] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_1] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_2] += AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_3] += AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_4] += AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_5] += AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_6] += AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_7] += AH5416(ah)->ah_ht40PowerIncForPdadc;
}
/* Write the TX power rate registers */
- ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray);
+ ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
/* Write the Power subtraction for dynamic chain changing, for per-packet powertx */
OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
@@ -1148,7 +1231,8 @@
HAL_RFGAIN
ar5416GetRfgain(struct ath_hal *ah)
{
- return HAL_RFGAIN_INACTIVE;
+
+ return (HAL_RFGAIN_INACTIVE);
}
/*
@@ -1157,13 +1241,14 @@
HAL_BOOL
ar5416Disable(struct ath_hal *ah)
{
- if (!ar5212SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
+
+ if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE))
return AH_FALSE;
if (! ar5416SetResetReg(ah, HAL_RESET_COLD))
return AH_FALSE;
AH5416(ah)->ah_initPLL(ah, AH_NULL);
- return AH_TRUE;
+ return (AH_TRUE);
}
/*
@@ -1175,11 +1260,12 @@
HAL_BOOL
ar5416PhyDisable(struct ath_hal *ah)
{
+
if (! ar5416SetResetReg(ah, HAL_RESET_WARM))
return AH_FALSE;
AH5416(ah)->ah_initPLL(ah, AH_NULL);
- return AH_TRUE;
+ return (AH_TRUE);
}
/*
@@ -1188,6 +1274,12 @@
HAL_BOOL
ar5416SetResetReg(struct ath_hal *ah, uint32_t type)
{
+ /*
+ * Set force wake
+ */
+ OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+
switch (type) {
case HAL_RESET_POWER_ON:
return ar5416SetResetPowerOn(ah);
@@ -1218,10 +1310,15 @@
AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
/*
- * RTC reset and clear
+ * PowerOn reset can be used in open loop power control or failure recovery.
+ * If we do RTC reset while DMA is still running, hardware may corrupt memory.
+ * Therefore, we need to reset AHB first to stop DMA.
*/
if (! AR_SREV_HOWL(ah))
OS_REG_WRITE(ah, AR_RC, AR_RC_AHB);
+ /*
+ * RTC reset and clear
+ */
OS_REG_WRITE(ah, AR_RTC_RESET, 0);
OS_DELAY(20);
@@ -1272,6 +1369,11 @@
#endif /* AH_SUPPORT_AR9130 */
/*
* Reset AHB
+ *
+ * (In case the last interrupt source was a bus timeout.)
+ * XXX TODO: this is not the way to do it! It should be recorded
+ * XXX by the interrupt handler and passed _into_ the
+ * XXX reset path routine so this occurs.
*/
tmpReg = OS_REG_READ(ah, AR_INTR_SYNC_CAUSE);
if (tmpReg & (AR_INTR_SYNC_LOCAL_TIMEOUT|AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
@@ -1327,16 +1429,15 @@
if (type == HAL_RESET_COLD) {
if (isBigEndian()) {
/*
- * Set CFG, little-endian for register
- * and descriptor accesses.
+ * Set CFG, little-endian for descriptor accesses.
*/
- mask = INIT_CONFIG_STATUS | AR_CFG_SWRD | AR_CFG_SWRG;
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWRD;
#ifndef AH_NEED_DESC_SWAP
mask |= AR_CFG_SWTD;
#endif
HALDEBUG(ah, HAL_DEBUG_RESET,
"%s Applying descriptor swap\n", __func__);
- OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask));
+ OS_REG_WRITE(ah, AR_CFG, mask);
} else
OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS);
}
@@ -1394,31 +1495,6 @@
}
}
-/*
- * Update the chainmask based on the current channel configuration.
- *
- * XXX ath9k checks bluetooth co-existence here
- * XXX ath9k checks whether the current state is "off-channel".
- * XXX ath9k sticks the hardware into 1x1 mode for legacy;
- * we're going to leave multi-RX on for multi-path cancellation.
- */
-static void
-ar5416UpdateChainMasks(struct ath_hal *ah, HAL_BOOL is_ht)
-{
- struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
- HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
-
- if (is_ht) {
- AH5416(ah)->ah_tx_chainmask = pCap->halTxChainMask;
- } else {
- AH5416(ah)->ah_tx_chainmask = 1;
- }
- AH5416(ah)->ah_rx_chainmask = pCap->halRxChainMask;
- HALDEBUG(ah, HAL_DEBUG_RESET, "TX chainmask: 0x%x; RX chainmask: 0x%x\n",
- AH5416(ah)->ah_tx_chainmask,
- AH5416(ah)->ah_rx_chainmask);
-}
-
void
ar5416InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
{
@@ -1453,6 +1529,7 @@
const struct ar5416eeprom *eep,
uint8_t txRxAttenLocal, int regChainOffset, int i)
{
+
if (IS_EEP_MINOR_V3(ah)) {
txRxAttenLocal = pModal->txRxAttenCh[i];
@@ -1649,7 +1726,7 @@
eep->baseEepHeader.desiredScaleCCK);
}
- return AH_TRUE;
+ return (AH_TRUE);
}
/*
@@ -1683,7 +1760,8 @@
/* Set rates Array from collected data */
ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
- ratesArray[rate18mb] = ratesArray[rate24mb] = targetPowerOfdm->tPow2x[0];
+ ratesArray[rate18mb] = ratesArray[rate24mb] =
+ targetPowerOfdm->tPow2x[0];
ratesArray[rate36mb] = targetPowerOfdm->tPow2x[1];
ratesArray[rate48mb] = targetPowerOfdm->tPow2x[2];
ratesArray[rate54mb] = targetPowerOfdm->tPow2x[3];
@@ -2587,7 +2665,7 @@
if (!AR_SREV_9271(ah))
val &= ~AR_PCU_MISC_MODE2_HWWAR1;
- if (AR_SREV_KIWI_11_OR_LATER(ah))
+ if (AR_SREV_KIWI_10_OR_LATER(ah))
val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
@@ -2687,3 +2765,125 @@
{
OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
}
+
+#define AR5416_IFS_SLOT_FULL_RATE_40 0x168 /* 9 us half, 40 MHz core clock (9*40) */
+#define AR5416_IFS_SLOT_HALF_RATE_40 0x104 /* 13 us half, 20 MHz core clock (13*20) */
+#define AR5416_IFS_SLOT_QUARTER_RATE_40 0xD2 /* 21 us quarter, 10 MHz core clock (21*10) */
+
+#define AR5416_IFS_EIFS_FULL_RATE_40 0xE60 /* (74 + (2 * 9)) * 40MHz core clock */
+#define AR5416_IFS_EIFS_HALF_RATE_40 0xDAC /* (149 + (2 * 13)) * 20MHz core clock */
+#define AR5416_IFS_EIFS_QUARTER_RATE_40 0xD48 /* (298 + (2 * 21)) * 10MHz core clock */
+
+#define AR5416_IFS_SLOT_FULL_RATE_44 0x18c /* 9 us half, 44 MHz core clock (9*44) */
+#define AR5416_IFS_SLOT_HALF_RATE_44 0x11e /* 13 us half, 22 MHz core clock (13*22) */
+#define AR5416_IFS_SLOT_QUARTER_RATE_44 0xe7 /* 21 us quarter, 11 MHz core clock (21*11) */
+
+#define AR5416_IFS_EIFS_FULL_RATE_44 0xfd0 /* (74 + (2 * 9)) * 44MHz core clock */
+#define AR5416_IFS_EIFS_HALF_RATE_44 0xf0a /* (149 + (2 * 13)) * 22MHz core clock */
+#define AR5416_IFS_EIFS_QUARTER_RATE_44 0xe9c /* (298 + (2 * 21)) * 11MHz core clock */
+
+#define AR5416_INIT_USEC_40 40
+#define AR5416_HALF_RATE_USEC_40 19 /* ((40 / 2) - 1 ) */
+#define AR5416_QUARTER_RATE_USEC_40 9 /* ((40 / 4) - 1 ) */
+
+#define AR5416_INIT_USEC_44 44
+#define AR5416_HALF_RATE_USEC_44 21 /* ((44 / 2) - 1 ) */
+#define AR5416_QUARTER_RATE_USEC_44 10 /* ((44 / 4) - 1 ) */
+
+
+/* XXX What should these be for 40/44MHz clocks (and half/quarter) ? */
+#define AR5416_RX_NON_FULL_RATE_LATENCY 63
+#define AR5416_TX_HALF_RATE_LATENCY 108
+#define AR5416_TX_QUARTER_RATE_LATENCY 216
+
+/*
+ * Adjust various register settings based on half/quarter rate clock setting.
+ * This includes:
+ *
+ * + USEC, TX/RX latency,
+ * + IFS params: slot, eifs, misc etc.
+ *
+ * TODO:
+ *
+ * + Verify which other registers need to be tweaked;
+ * + Verify the behaviour of this for 5GHz fast and non-fast clock mode;
+ * + This just plain won't work for long distance links - the coverage class
+ * code isn't aware of the slot/ifs/ACK/RTS timeout values that need to
+ * change;
+ * + Verify whether the 32KHz USEC value needs to be kept for the 802.11n
+ * series chips?
+ * + Calculate/derive values for 2GHz, 5GHz, 5GHz fast clock
+ */
+static void
+ar5416SetIFSTiming(struct ath_hal *ah, const struct ieee80211_channel *chan)
+{
+ uint32_t txLat, rxLat, usec, slot, refClock, eifs, init_usec;
+ int clk_44 = 0;
+
+ HALASSERT(IEEE80211_IS_CHAN_HALF(chan) ||
+ IEEE80211_IS_CHAN_QUARTER(chan));
+
+ /* 2GHz and 5GHz fast clock - 44MHz; else 40MHz */
+ if (IEEE80211_IS_CHAN_2GHZ(chan))
+ clk_44 = 1;
+ else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
+ IS_5GHZ_FAST_CLOCK_EN(ah, chan))
+ clk_44 = 1;
+
+ /* XXX does this need save/restoring for the 11n chips? */
+ refClock = OS_REG_READ(ah, AR_USEC) & AR_USEC_USEC32;
+
+ /*
+ * XXX This really should calculate things, not use
+ * hard coded values! Ew.
+ */
+ if (IEEE80211_IS_CHAN_HALF(chan)) {
+ if (clk_44) {
+ slot = AR5416_IFS_SLOT_HALF_RATE_44;
+ rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
+ AR5416_USEC_RX_LAT_S;
+ txLat = AR5416_TX_HALF_RATE_LATENCY <<
+ AR5416_USEC_TX_LAT_S;
+ usec = AR5416_HALF_RATE_USEC_44;
+ eifs = AR5416_IFS_EIFS_HALF_RATE_44;
+ init_usec = AR5416_INIT_USEC_44 >> 1;
+ } else {
+ slot = AR5416_IFS_SLOT_HALF_RATE_40;
+ rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
+ AR5416_USEC_RX_LAT_S;
+ txLat = AR5416_TX_HALF_RATE_LATENCY <<
+ AR5416_USEC_TX_LAT_S;
+ usec = AR5416_HALF_RATE_USEC_40;
+ eifs = AR5416_IFS_EIFS_HALF_RATE_40;
+ init_usec = AR5416_INIT_USEC_40 >> 1;
+ }
+ } else { /* quarter rate */
+ if (clk_44) {
+ slot = AR5416_IFS_SLOT_QUARTER_RATE_44;
+ rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
+ AR5416_USEC_RX_LAT_S;
+ txLat = AR5416_TX_QUARTER_RATE_LATENCY <<
+ AR5416_USEC_TX_LAT_S;
+ usec = AR5416_QUARTER_RATE_USEC_44;
+ eifs = AR5416_IFS_EIFS_QUARTER_RATE_44;
+ init_usec = AR5416_INIT_USEC_44 >> 2;
+ } else {
+ slot = AR5416_IFS_SLOT_QUARTER_RATE_40;
+ rxLat = AR5416_RX_NON_FULL_RATE_LATENCY <<
+ AR5416_USEC_RX_LAT_S;
+ txLat = AR5416_TX_QUARTER_RATE_LATENCY <<
+ AR5416_USEC_TX_LAT_S;
+ usec = AR5416_QUARTER_RATE_USEC_40;
+ eifs = AR5416_IFS_EIFS_QUARTER_RATE_40;
+ init_usec = AR5416_INIT_USEC_40 >> 2;
+ }
+ }
+
+ /* XXX verify these! */
+ OS_REG_WRITE(ah, AR_USEC, (usec | refClock | txLat | rxLat));
+ OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot);
+ OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs);
+ OS_REG_RMW_FIELD(ah, AR_D_GBL_IFS_MISC,
+ AR_D_GBL_IFS_MISC_USEC_DURATION, init_usec);
+}
+
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c 249580 2013-04-17 07:31:53Z adrian $
*/
#include "opt_ah.h"
@@ -135,6 +136,7 @@
#define set11nRateFlags(_series, _index) \
((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \
|((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \
+ |((_series)[_index].RateFlags & HAL_RATESERIES_STBC ? AR_STBC##_index : 0) \
|SM((_series)[_index].ChSel, AR_ChainSel##_index)
/*
@@ -154,6 +156,169 @@
/* NB: accept HT rates */
#define isValidTxRate(_r) ((1<<((_r) & 0x7f)) & VALID_TX_RATES)
+static inline int
+ar5416RateToRateTable(struct ath_hal *ah, uint8_t rate, HAL_BOOL is_ht40)
+{
+
+ /*
+ * Handle the non-MCS rates
+ */
+ switch (rate) {
+ case /* 1 Mb */ 0x1b:
+ case /* 1 MbS*/ 0x1b | 0x4:
+ return (AH5416(ah)->ah_ratesArray[rate1l]);
+ case /* 2 Mb */ 0x1a:
+ return (AH5416(ah)->ah_ratesArray[rate2l]);
+ case /* 2 MbS*/ 0x1a | 0x4:
+ return (AH5416(ah)->ah_ratesArray[rate2s]);
+ case /* 5.5 Mb */ 0x19:
+ return (AH5416(ah)->ah_ratesArray[rate5_5l]);
+ case /* 5.5 MbS*/ 0x19 | 0x4:
+ return (AH5416(ah)->ah_ratesArray[rate5_5s]);
+ case /* 11 Mb */ 0x18:
+ return (AH5416(ah)->ah_ratesArray[rate11l]);
+ case /* 11 MbS*/ 0x18 | 0x4:
+ return (AH5416(ah)->ah_ratesArray[rate11s]);
+ }
+
+ /* OFDM rates */
+ switch (rate) {
+ case /* 6 Mb */ 0x0b:
+ return (AH5416(ah)->ah_ratesArray[rate6mb]);
+ case /* 9 Mb */ 0x0f:
+ return (AH5416(ah)->ah_ratesArray[rate9mb]);
+ case /* 12 Mb */ 0x0a:
+ return (AH5416(ah)->ah_ratesArray[rate12mb]);
+ case /* 18 Mb */ 0x0e:
+ return (AH5416(ah)->ah_ratesArray[rate18mb]);
+ case /* 24 Mb */ 0x09:
+ return (AH5416(ah)->ah_ratesArray[rate24mb]);
+ case /* 36 Mb */ 0x0d:
+ return (AH5416(ah)->ah_ratesArray[rate36mb]);
+ case /* 48 Mb */ 0x08:
+ return (AH5416(ah)->ah_ratesArray[rate48mb]);
+ case /* 54 Mb */ 0x0c:
+ return (AH5416(ah)->ah_ratesArray[rate54mb]);
+ }
+
+ /*
+ * Handle HT20/HT40 - we only have to do MCS0-7;
+ * there's no stream differences.
+ */
+ if ((rate & 0x80) && is_ht40) {
+ return (AH5416(ah)->ah_ratesArray[rateHt40_0 + (rate & 0x7)]);
+ } else if (rate & 0x80) {
+ return (AH5416(ah)->ah_ratesArray[rateHt20_0 + (rate & 0x7)]);
+ }
+
+ /* XXX default (eg XR, bad bad person!) */
+ return (AH5416(ah)->ah_ratesArray[rate6mb]);
+}
+
+/*
+ * Return the TX power to be used for the given rate/chains/TX power.
+ *
+ * There are a bunch of tweaks to make to a given TX power based on
+ * the current configuration, so...
+ */
+static uint16_t
+ar5416GetTxRatePower(struct ath_hal *ah, uint8_t rate, uint8_t tx_chainmask,
+ uint16_t txPower, HAL_BOOL is_ht40)
+{
+ int n_txpower, max_txpower;
+ const int cck_ofdm_delta = 2;
+#define EEP_MINOR(_ah) \
+ (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
+#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
+
+ /* Take a copy ; we may underflow and thus need to clamp things */
+ n_txpower = txPower;
+
+ /* HT40? Need to adjust the TX power by this */
+ if (is_ht40)
+ n_txpower += AH5416(ah)->ah_ht40PowerIncForPdadc;
+
+ /*
+ * Merlin? Offset the target TX power offset - it defaults to
+ * starting at -5.0dBm, but that can change!
+ *
+ * Kiwi/Kite? Always -5.0dBm offset.
+ */
+ if (AR_SREV_KIWI_10_OR_LATER(ah)) {
+ n_txpower -= (AR5416_PWR_TABLE_OFFSET_DB * 2);
+ } else if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
+ int8_t pwr_table_offset = 0;
+ /* This is in dBm, convert to 1/2 dBm */
+ (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET,
+ &pwr_table_offset);
+ n_txpower -= (pwr_table_offset * 2);
+ }
+
+ /*
+ * If Open-loop TX power control is used, the CCK rates need
+ * to be offset by that.
+ *
+ * Rates: 2S, 2L, 1S, 1L, 5.5S, 5.5L
+ *
+ * XXX Odd, we don't have a PHY table entry for long preamble
+ * 1mbit CCK?
+ */
+ if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
+ ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
+
+ if (rate == 0x19 || rate == 0x1a || rate == 0x1b ||
+ rate == (0x19 | 0x04) || rate == (0x1a | 0x04) ||
+ rate == (0x1b | 0x04)) {
+ n_txpower -= cck_ofdm_delta;
+ }
+ }
+
+ /*
+ * We're now offset by the same amount that the static maximum
+ * PHY power tables are. So, clamp the value based on that rate.
+ */
+ max_txpower = ar5416RateToRateTable(ah, rate, is_ht40);
+#if 0
+ ath_hal_printf(ah, "%s: n_txpower = %d, max_txpower = %d, "
+ "rate = 0x%x , is_ht40 = %d\n",
+ __func__,
+ n_txpower,
+ max_txpower,
+ rate,
+ is_ht40);
+#endif
+ n_txpower = MIN(max_txpower, n_txpower);
+
+ /*
+ * We don't have to offset the TX power for two or three
+ * chain operation here - it's done by the AR_PHY_POWER_TX_SUB
+ * register setting via the EEPROM.
+ *
+ * So for vendors that programmed the maximum target power assuming
+ * that 2/3 chains are always on, things will just plain work.
+ * (They won't reach that target power if only one chain is on, but
+ * that's a different problem.)
+ */
+
+ /* Over/underflow? Adjust */
+ if (n_txpower < 0)
+ n_txpower = 0;
+ else if (n_txpower > 63)
+ n_txpower = 63;
+
+ /*
+ * For some odd reason the AR9160 with txpower=0 results in a
+ * much higher (max?) TX power. So, if it's a chipset before
+ * AR9220/AR9280, just clamp the minimum value at 1.
+ */
+ if ((! AR_SREV_MERLIN_10_OR_LATER(ah)) && (n_txpower == 0))
+ n_txpower = 1;
+
+ return (n_txpower);
+#undef EEP_MINOR
+#undef IS_EEP_MINOR_V2
+}
+
HAL_BOOL
ar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
u_int pktLen,
@@ -186,6 +351,16 @@
if (txPower > 63)
txPower = 63;
+ /*
+ * XXX For now, just assume that this isn't a HT40 frame.
+ */
+ if (AH5212(ah)->ah_tpcEnabled) {
+ txPower = ar5416GetTxRatePower(ah, txRate0,
+ ahp->ah_tx_chainmask,
+ txPower,
+ AH_FALSE);
+ }
+
ads->ds_ctl0 = (pktLen & AR_FrameLen)
| (txPower << AR_XmitPower_S)
| (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
@@ -237,6 +412,8 @@
* Set the TX antenna to 0 for Kite
* To preserve existing behaviour, also set the TPC bits to 0;
* when TPC is enabled these should be filled in appropriately.
+ *
+ * XXX TODO: when doing TPC, set the TX power up appropriately?
*/
if (AR_SREV_KITE(ah)) {
ads->ds_ctl8 = SM(0, AR_AntCtl0);
@@ -276,13 +453,17 @@
HAL_BOOL
ar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
- u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
+ HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
+ u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
const struct ath_desc *ds0)
{
struct ar5416_desc *ads = AR5416DESC(ds);
+ uint32_t segLen = segLenList[0];
HALASSERT((segLen &~ AR_BufLen) == 0);
+ ds->ds_data = bufAddrList[0];
+
if (firstSeg) {
/*
* First descriptor, don't clobber xmit control data
@@ -295,20 +476,33 @@
* copy the multi-rate transmit parameters from
* the first frame for processing on completion.
*/
- ads->ds_ctl0 = 0;
ads->ds_ctl1 = segLen;
#ifdef AH_NEED_DESC_SWAP
+ ads->ds_ctl0 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl0)
+ & AR_TxIntrReq;
ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2);
ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3);
+ /* ctl6 - we only need encrtype; the rest are blank */
+ ads->ds_ctl6 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType);
#else
+ ads->ds_ctl0 = AR5416DESC_CONST(ds0)->ds_ctl0 & AR_TxIntrReq;
ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+ /* ctl6 - we only need encrtype; the rest are blank */
+ ads->ds_ctl6 = AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType;
#endif
} else { /* !firstSeg && !lastSeg */
/*
* Intermediate descriptor in a multi-descriptor frame.
*/
- ads->ds_ctl0 = 0;
+#ifdef AH_NEED_DESC_SWAP
+ ads->ds_ctl0 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl0)
+ & AR_TxIntrReq;
+ ads->ds_ctl6 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType);
+#else
+ ads->ds_ctl0 = AR5416DESC_CONST(ds0)->ds_ctl0 & AR_TxIntrReq;
+ ads->ds_ctl6 = AR5416DESC_CONST(ds0)->ds_ctl6 & AR_EncrType;
+#endif
ads->ds_ctl1 = segLen | AR_TxMore;
ads->ds_ctl2 = 0;
ads->ds_ctl3 = 0;
@@ -318,8 +512,13 @@
return AH_TRUE;
}
+/*
+ * NB: cipher is no longer used, it's calculated.
+ */
HAL_BOOL
ar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds,
+ HAL_DMA_ADDR *bufAddrList,
+ uint32_t *segLenList,
u_int pktLen,
u_int hdrLen,
HAL_PKT_TYPE type,
@@ -326,34 +525,60 @@
u_int keyIx,
HAL_CIPHER cipher,
uint8_t delims,
- u_int segLen,
HAL_BOOL firstSeg,
- HAL_BOOL lastSeg)
+ HAL_BOOL lastSeg,
+ HAL_BOOL lastAggr)
{
struct ar5416_desc *ads = AR5416DESC(ds);
uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads);
struct ath_hal_5416 *ahp = AH5416(ah);
+ u_int segLen = segLenList[0];
int isaggr = 0;
+ uint32_t last_aggr = 0;
(void) hdrLen;
(void) ah;
HALASSERT((segLen &~ AR_BufLen) == 0);
+ ds->ds_data = bufAddrList[0];
HALASSERT(isValidPktType(type));
if (type == HAL_PKT_TYPE_AMPDU) {
type = HAL_PKT_TYPE_NORMAL;
isaggr = 1;
+ if (lastAggr == AH_FALSE)
+ last_aggr = AR_MoreAggr;
}
- if (!firstSeg) {
- OS_MEMZERO(ds->ds_hw, AR5416_DESC_TX_CTL_SZ);
- }
+ /*
+ * Since this function is called before any of the other
+ * descriptor setup functions (at least in this particular
+ * 802.11n aggregation implementation), always bzero() the
+ * descriptor. Previously this would be done for all but
+ * the first segment.
+ * XXX TODO: figure out why; perhaps I'm using this slightly
+ * XXX incorrectly.
+ */
+ OS_MEMZERO(ds->ds_hw, AR5416_DESC_TX_CTL_SZ);
+ /*
+ * Note: VEOL should only be for the last descriptor in the chain.
+ */
ads->ds_ctl0 = (pktLen & AR_FrameLen);
+
+ /*
+ * For aggregates:
+ * + IsAggr must be set for all descriptors of all subframes of
+ * the aggregate
+ * + MoreAggr must be set for all descriptors of all subframes
+ * of the aggregate EXCEPT the last subframe;
+ * + MoreAggr must be _CLEAR_ for all descrpitors of the last
+ * subframe of the aggregate.
+ */
ads->ds_ctl1 = (type << AR_FrameType_S)
- | (isaggr ? (AR_IsAggr | AR_MoreAggr) : 0);
+ | (isaggr ? (AR_IsAggr | last_aggr) : 0);
+
ads->ds_ctl2 = 0;
ads->ds_ctl3 = 0;
if (keyIx != HAL_TXKEYIX_INVALID) {
@@ -362,7 +587,7 @@
ads->ds_ctl0 |= AR_DestIdxValid;
}
- ads->ds_ctl6 = SM(ahp->ah_keytype[cipher], AR_EncrType);
+ ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType);
if (isaggr) {
ads->ds_ctl6 |= SM(delims, AR_PadDelim);
}
@@ -463,7 +688,6 @@
ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
#endif
-
return AH_TRUE;
}
@@ -504,6 +728,7 @@
/* Update software copies of the HW status */
ts->ts_seqnum = MS(ds_txstatus[9], AR_SeqNum);
ts->ts_tstamp = AR_SendTimestamp(ds_txstatus);
+ ts->ts_tid = MS(ds_txstatus[9], AR_TxTid);
ts->ts_status = 0;
if (ds_txstatus[1] & AR_ExcessiveRetries)
@@ -620,6 +845,26 @@
return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT);
}
+#define HT_RC_2_MCS(_rc) ((_rc) & 0x0f)
+static const u_int8_t baDurationDelta[] = {
+ 24, // 0: BPSK
+ 12, // 1: QPSK 1/2
+ 12, // 2: QPSK 3/4
+ 4, // 3: 16-QAM 1/2
+ 4, // 4: 16-QAM 3/4
+ 4, // 5: 64-QAM 2/3
+ 4, // 6: 64-QAM 3/4
+ 4, // 7: 64-QAM 5/6
+ 24, // 8: BPSK
+ 12, // 9: QPSK 1/2
+ 12, // 10: QPSK 3/4
+ 4, // 11: 16-QAM 1/2
+ 4, // 12: 16-QAM 3/4
+ 4, // 13: 64-QAM 2/3
+ 4, // 14: 64-QAM 3/4
+ 4, // 15: 64-QAM 5/6
+};
+
void
ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
u_int durUpdateEn, u_int rtsctsRate,
@@ -632,20 +877,6 @@
(void)nseries;
/*
- * XXX since the upper layers doesn't know the current chainmask
- * XXX setup, just override its decisions here.
- * XXX The upper layers need to be taught this!
- */
- if (series[0].Tries != 0)
- series[0].ChSel = AH5416(ah)->ah_tx_chainmask;
- if (series[1].Tries != 0)
- series[1].ChSel = AH5416(ah)->ah_tx_chainmask;
- if (series[2].Tries != 0)
- series[2].ChSel = AH5416(ah)->ah_tx_chainmask;
- if (series[3].Tries != 0)
- series[3].ChSel = AH5416(ah)->ah_tx_chainmask;
-
- /*
* Only one of RTS and CTS enable must be set.
* If a frame has both set, just do RTS protection -
* that's enough to satisfy legacy protection.
@@ -689,9 +920,91 @@
| set11nRateFlags(series, 2)
| set11nRateFlags(series, 3)
| SM(rtsctsRate, AR_RTSCTSRate);
+
+ /*
+ * Doing per-packet TPC - update the TX power for the first
+ * field; program in the other series.
+ */
+ if (AH5212(ah)->ah_tpcEnabled) {
+ uint32_t ds_ctl0;
+ uint16_t txPower;
+
+ /* Modify the tx power field for rate 0 */
+ txPower = ar5416GetTxRatePower(ah, series[0].Rate,
+ series[0].ChSel,
+ series[0].tx_power_cap,
+ !! (series[0].RateFlags & HAL_RATESERIES_2040));
+ ds_ctl0 = ads->ds_ctl0 & ~AR_XmitPower;
+ ds_ctl0 |= (txPower << AR_XmitPower_S);
+ ads->ds_ctl0 = ds_ctl0;
+
+ /*
+ * Override the whole descriptor field for each TX power.
+ *
+ * This will need changing if we ever support antenna control
+ * programming.
+ */
+ txPower = ar5416GetTxRatePower(ah, series[1].Rate,
+ series[1].ChSel,
+ series[1].tx_power_cap,
+ !! (series[1].RateFlags & HAL_RATESERIES_2040));
+ ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(txPower, AR_XmitPower1);
+
+ txPower = ar5416GetTxRatePower(ah, series[2].Rate,
+ series[2].ChSel,
+ series[2].tx_power_cap,
+ !! (series[2].RateFlags & HAL_RATESERIES_2040));
+ ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(txPower, AR_XmitPower2);
+
+ txPower = ar5416GetTxRatePower(ah, series[3].Rate,
+ series[3].ChSel,
+ series[3].tx_power_cap,
+ !! (series[3].RateFlags & HAL_RATESERIES_2040));
+ ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(txPower, AR_XmitPower3);
+ }
}
+/*
+ * Note: this should be called before calling ar5416SetBurstDuration()
+ * (if it is indeed called) in order to ensure that the burst duration
+ * is correctly updated with the BA delta workaround.
+ */
void
+ar5416Set11nAggrFirst(struct ath_hal *ah, struct ath_desc *ds, u_int aggrLen,
+ u_int numDelims)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ uint32_t flags;
+ uint32_t burstDur;
+ uint8_t rate;
+
+ ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+ ads->ds_ctl6 &= ~(AR_AggrLen | AR_PadDelim);
+ ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+ ads->ds_ctl6 |= SM(numDelims, AR_PadDelim);
+
+ if (! AR_SREV_MERLIN_10_OR_LATER(ah)) {
+ /*
+ * XXX It'd be nice if I were passed in the rate scenario
+ * at this point..
+ */
+ rate = MS(ads->ds_ctl3, AR_XmitRate0);
+ flags = ads->ds_ctl0 & (AR_CTSEnable | AR_RTSEnable);
+ /*
+ * WAR - MAC assumes normal ACK time instead of
+ * block ACK while computing packet duration.
+ * Add this delta to the burst duration in the descriptor.
+ */
+ if (flags && (ads->ds_ctl1 & AR_IsAggr)) {
+ burstDur = baDurationDelta[HT_RC_2_MCS(rate)];
+ ads->ds_ctl2 &= ~(AR_BurstDur);
+ ads->ds_ctl2 |= SM(burstDur, AR_BurstDur);
+ }
+ }
+}
+
+void
ar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims)
{
struct ar5416_desc *ads = AR5416DESC(ds);
@@ -711,6 +1024,16 @@
}
void
+ar5416Set11nAggrLast(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 |= AR_IsAggr;
+ ads->ds_ctl1 &= ~AR_MoreAggr;
+ ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+void
ar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds)
{
struct ar5416_desc *ads = AR5416DESC(ds);
@@ -721,13 +1044,46 @@
}
void
+ar5416Set11nVirtualMoreFrag(struct ath_hal *ah, struct ath_desc *ds,
+ u_int vmf)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ if (vmf)
+ ads->ds_ctl0 |= AR_VirtMoreFrag;
+ else
+ ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+/*
+ * Program the burst duration, with the included BA delta if it's
+ * applicable.
+ */
+void
ar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds,
u_int burstDuration)
{
struct ar5416_desc *ads = AR5416DESC(ds);
+ uint32_t burstDur = 0;
+ uint8_t rate;
+ if (! AR_SREV_MERLIN_10_OR_LATER(ah)) {
+ /*
+ * XXX It'd be nice if I were passed in the rate scenario
+ * at this point..
+ */
+ rate = MS(ads->ds_ctl3, AR_XmitDataTries0);
+ /*
+ * WAR - MAC assumes normal ACK time instead of
+ * block ACK while computing packet duration.
+ * Add this delta to the burst duration in the descriptor.
+ */
+ if (ads->ds_ctl1 & AR_IsAggr) {
+ burstDur = baDurationDelta[HT_RC_2_MCS(rate)];
+ }
+ }
+
ads->ds_ctl2 &= ~AR_BurstDur;
- ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+ ads->ds_ctl2 |= SM(burstDur + burstDuration, AR_BurstDur);
}
/*
@@ -879,6 +1235,7 @@
* Assumes:
* phwChannel has been set to point to the current channel
*/
+#define TU_TO_USEC(_tu) ((_tu) << 10)
HAL_BOOL
ar5416ResetTxQueue(struct ath_hal *ah, u_int q)
{
@@ -886,7 +1243,7 @@
HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
HAL_TX_QUEUE_INFO *qi;
- uint32_t cwMin, chanCwMin, value, qmisc, dmisc;
+ uint32_t cwMin, chanCwMin, qmisc, dmisc;
if (q >= pCap->halTotalQueues) {
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
@@ -956,7 +1313,8 @@
if (qi->tqi_cbrOverflowLimit)
qmisc |= AR_Q_MISC_CBR_EXP_CNTR_LIMIT;
}
- if (qi->tqi_readyTime) {
+
+ if (qi->tqi_readyTime && (qi->tqi_type != HAL_TX_QUEUE_CAB)) {
OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT)
| AR_Q_RDYTIMECFG_ENA);
@@ -1027,18 +1385,46 @@
qmisc |= AR_Q_MISC_FSP_DBA_GATED
| AR_Q_MISC_CBR_INCR_DIS1
| AR_Q_MISC_CBR_INCR_DIS0;
-
- if (!qi->tqi_readyTime) {
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: CAB: tqi_readyTime = %d\n",
+ __func__, qi->tqi_readyTime);
+ if (qi->tqi_readyTime) {
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
+ "%s: using tqi_readyTime\n", __func__);
+ OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) |
+ AR_Q_RDYTIMECFG_ENA);
+ } else {
+ int value;
/*
* NB: don't set default ready time if driver
* has explicitly specified something. This is
* here solely for backwards compatibility.
*/
- value = (ahp->ah_beaconInterval
- - (ah->ah_config.ah_sw_beacon_response_time -
- ah->ah_config.ah_dma_beacon_response_time)
- - ah->ah_config.ah_additional_swba_backoff) * 1024;
- OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_ENA);
+ /*
+ * XXX for now, hard-code a CAB interval of 70%
+ * XXX of the total beacon interval.
+ *
+ * XXX This keeps Merlin and later based MACs
+ * XXX quite a bit happier (stops stuck beacons,
+ * XXX which I gather is because of such a long
+ * XXX cabq time.)
+ */
+ value = (ahp->ah_beaconInterval * 50 / 100)
+ - ah->ah_config.ah_additional_swba_backoff
+ - ah->ah_config.ah_sw_beacon_response_time
+ + ah->ah_config.ah_dma_beacon_response_time;
+ /*
+ * XXX Ensure it isn't too low - nothing lower
+ * XXX than 10 TU
+ */
+ if (value < 10)
+ value = 10;
+ HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
+ "%s: defaulting to rdytime = %d uS\n",
+ __func__, value);
+ OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ SM(TU_TO_USEC(value), AR_Q_RDYTIMECFG_INT) |
+ AR_Q_RDYTIMECFG_ENA);
}
dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
AR_D_MISC_ARB_LOCKOUT_CNTRL);
@@ -1106,3 +1492,4 @@
return AH_TRUE;
}
+#undef TU_TO_USEC
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416desc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416desc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416desc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,15 +15,14 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416desc.h 250346 2013-05-08 01:11:25Z adrian $
*/
-#ifndef _ATH_AR5416_DESC_H
-#define _ATH_AR5416_DESC_H
+#ifndef _ATH_AR5416_DESC_H_
+#define _ATH_AR5416_DESC_H_
/*
* Hardware-specific descriptor structures.
*/
-#include "ah_desc.h"
/* XXX Need to replace this with a dynamic
* method of determining Owl2 if possible
@@ -302,6 +302,8 @@
#define AR_FinalTxIdx_S 21
#define AR_TxStatusRsvd82 0x01800000
#define AR_PowerMgmt 0x02000000
+#define AR_TxTid 0xf0000000
+#define AR_TxTid_S 28
#define AR_TxStatusRsvd83 0xfc000000
/***********
@@ -356,6 +358,7 @@
#define AR_RxStatusRsvd30 0xfffff800
/* Owl 2.x only */
#define AR_DupFrame 0x00000004
+#define AR_STBCFrame 0x00000008
#define AR_RxAntenna 0xffffff00
#define AR_RxAntenna_S 8
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416phy.h 244943 2013-01-02 00:38:01Z adrian $
*/
#ifndef _DEV_ATH_AR5416PHY_H_
#define _DEV_ATH_AR5416PHY_H_
@@ -21,6 +22,73 @@
#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
+
+#define AR_PHY_SPECTRAL_SCAN 0x9910
+#define AR_PHY_SPECTRAL_SCAN_ENA 0x00000001
+#define AR_PHY_SPECTRAL_SCAN_ENA_S 0
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
+
+/* Scan count and Short repeat flags are different for Kiwi and Merlin */
+#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
+#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16
+
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI_S 28
+
+/*
+ * Kiwi only, bit 30 is used to set the error type, if set it is 0x5 (HAL_PHYERR_RADAR)
+ * Else it is 38 (new error type)
+ */
+#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT_KIWI 0x40000000 /* Spectral Error select bit mask */
+#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT_KIWI_S 30 /* Spectral Error select bit 30 */
+
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY_SELECT_KIWI 0x20000000 /* Spectral Error select bit mask */
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY_SELECT_SELECT_KIWI_S 29 /* Spectral Error select bit 30 */
+
/* For AR_PHY_RADAR0 */
#define AR_PHY_RADAR_0_FFT_ENA 0x80000000
@@ -28,6 +96,8 @@
#define AR_PHY_RADAR_EXT_ENA 0x00004000
#define AR_PHY_RADAR_1 0x9958
+#define AR_PHY_RADAR_1_BIN_THRESH_SELECT 0x07000000
+#define AR_PHY_RADAR_1_BIN_THRESH_SELECT_S 24
#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000
#define AR_PHY_RADAR_1_USE_FIR128 0x00400000
#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000
@@ -121,12 +191,6 @@
#define AR_PHY_EXT_MINCCA_PWR_S 23
#define AR_PHY_EXT_CCA_THRESH62 0x007F0000
#define AR_PHY_EXT_CCA_THRESH62_S 16
-/*
- * This duplicates AR_PHY_EXT_CCA_CYCPWR_THR1; it reads more like
- * an ANI register this way.
- */
-#define AR_PHY_EXT_TIMING5_CYCPWR_THR1 0x0000FE00
-#define AR_PHY_EXT_TIMING5_CYCPWR_THR1_S 9
#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000
#define AR9280_PHY_EXT_MINCCA_PWR_S 16
@@ -156,8 +220,14 @@
#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12))
#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12))
#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12))
+/* This is AR9130 and later */
#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12))
+/*
+ * AR5416 still uses AR_PHY(263) for current RSSI;
+ * AR9130 and later uses AR_PHY(271).
+ */
+#define AR9130_PHY_CURRENT_RSSI 0x9c3c /* rssi of current frame rx'd */
#define AR_PHY_CCA 0x9864
#define AR_PHY_MINCCA_PWR 0x0FF80000
Modified: trunk/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar5416/ar5416reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar5416/ar5416reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar5416/ar5416reg.h 249516 2013-04-15 17:58:11Z adrian $
*/
#ifndef _DEV_ATH_AR5416REG_H
#define _DEV_ATH_AR5416REG_H
@@ -47,14 +48,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
@@ -79,6 +124,12 @@
#define AR_RTC_DERIVED_CLK_PERIOD_S 1
#endif /* AH_SUPPORT_AR9130 */
+/* AR_USEC: 0x801c */
+#define AR5416_USEC_TX_LAT 0x007FC000 /* tx latency to start of SIGNAL (usec) */
+#define AR5416_USEC_TX_LAT_S 14 /* tx latency to start of SIGNAL (usec) */
+#define AR5416_USEC_RX_LAT 0x1F800000 /* rx latency to start of SIGNAL (usec) */
+#define AR5416_USEC_RX_LAT_S 23 /* rx latency to start of SIGNAL (usec) */
+
#define AR_RESET_TSF 0x8020
/*
@@ -95,6 +146,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
@@ -128,6 +180,7 @@
#define AR_2040_MODE 0x8318
#define AR_EXTRCCNT 0x8328 /* extension channel rx clear count */
#define AR_SELFGEN_MASK 0x832c /* rx and cal chain masks */
+#define AR_PHY_ERR_MASK_REG 0x8338
#define AR_PCU_TXBUF_CTRL 0x8340
#define AR_PCU_MISC_MODE2 0x8344
@@ -203,18 +256,23 @@
#define AR_MAC_LED_MODE_POWON 5 /* Power LED on (s/w control) */
#define AR_MAC_LED_MODE_NETON 6 /* Network LED on (s/w control) */
#define AR_MAC_LED_ASSOC 0x00000c00
-#define AR_MAC_LED_ASSOC_NONE 0x00000000 /* STA is not associated or trying */
-#define AR_MAC_LED_ASSOC_ACTIVE 0x00000400 /* STA is associated */
-#define AR_MAC_LED_ASSOC_PEND 0x00000800 /* STA is trying to associate */
+#define AR_MAC_LED_ASSOC_NONE 0x0 /* STA is not associated or trying */
+#define AR_MAC_LED_ASSOC_ACTIVE 0x1 /* STA is associated */
+#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_BIT22 0x00400000
+#define AR_WA_BIT23 0x00800000
#define AR_WA_DEFAULT 0x0000073f
-#define AR9280_WA_DEFAULT 0x0040073f
+#define AR9280_WA_DEFAULT 0x0040073b /* disable bit 2, see commit */
#define AR9285_WA_DEFAULT 0x004a05cb
#define AR_PCIE_PM_CTRL_ENA 0x00080000
@@ -250,6 +308,7 @@
/* Interrupts */
#define AR_ISR_TXMINTR 0x00080000 /* Maximum interrupt tx rate */
#define AR_ISR_RXMINTR 0x01000000 /* Maximum interrupt rx rate */
+#define AR_ISR_GENTMR 0x10000000 /* OR of generic timer bits in S5 */
#define AR_ISR_TXINTM 0x40000000 /* Tx int after mitigation */
#define AR_ISR_RXINTM 0x80000000 /* Rx int after mitigation */
@@ -259,7 +318,13 @@
#define AR_ISR_S5 0x0098
#define AR_ISR_S5_S 0x00d8
-#define AR_ISR_S5_TIM_TIMER 0x00000010
+#define AR_ISR_S5_GENTIMER7 0x00000080 // Mask for timer 7 trigger
+#define AR_ISR_S5_TIM_TIMER 0x00000010 // TIM Timer ISR
+#define AR_ISR_S5_DTIM_TIMER 0x00000020 // DTIM Timer ISR
+#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80 // ISR for generic timer trigger 7-15
+#define AR_ISR_S5_GENTIMER_TRIG_S 0
+#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000 // ISR for generic timer threshold 7-15
+#define AR_ISR_S5_GENTIMER_THRESH_S 16
#define AR_INTR_SPURIOUS 0xffffffff
#define AR_INTR_RTC_IRQ 0x00000001 /* rtc in shutdown state */
@@ -452,9 +517,12 @@
#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 */
+#define AR_PCU_SEL_EVM 0x08000000 /* select EVM data or PLCP header */
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
@@ -497,6 +565,8 @@
#define AR928X_GPIO_IN_VAL_S 10
#define AR9285_GPIO_IN_VAL 0x00FFF000
#define AR9285_GPIO_IN_VAL_S 12
+#define AR9287_GPIO_IN_VAL 0x003FF800
+#define AR9287_GPIO_IN_VAL_S 11
#define AR_GPIO_OE_OUT_DRV 0x3 /* 2 bit mask shifted by 2*bitpos */
#define AR_GPIO_OE_OUT_DRV_NO 0x0 /* tristate */
@@ -534,6 +604,25 @@
#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000
#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000
+/* K2 (9271) */
+#define AR9271_CLOCK_CONTROL 0x50040
+#define AR9271_CLOCK_SELECTION_22 0x0
+#define AR9271_CLOCK_SELECTION_88 0x1
+#define AR9271_CLOCK_SELECTION_44 0x2
+#define AR9271_CLOCK_SELECTION_117 0x4
+#define AR9271_CLOCK_SELECTION_OSC_40 0x6
+#define AR9271_CLOCK_SELECTION_RTC 0x7
+#define AR9271_SPI_SEL 0x100
+#define AR9271_UART_SEL 0x200
+
+#define AR9271_RESET_POWER_DOWN_CONTROL 0x50044
+#define AR9271_RADIO_RF_RST 0x20
+#define AR9271_GATE_MAC_CTL 0x4000
+#define AR9271_MAIN_PLL_PWD_CTL 0x40000
+
+#define AR9271_CLKMISC 0x4090
+#define AR9271_OSC_to_10M_EN 0x00000001
+
/*
* AR5212 defines the MAC revision mask as 0xF, but both ath9k and
* the Atheros HAL define it as 0x7.
@@ -605,10 +694,10 @@
#define AR_XSREV_REVISION_KITE_11 1 /* Kite 1.1 */
#define AR_XSREV_REVISION_KITE_12 2 /* Kite 1.2 */
#define AR_XSREV_VERSION_KIWI 0x180 /* Kiwi (AR9287) */
-#define AR_XSREV_REVISION_KIWI_10 0
-#define AR_XSREV_REVISION_KIWI_11 1
-#define AR_XSREV_REVISION_KIWI_12 2
-#define AR_XSREV_REVISION_KIWI_13 3
+#define AR_XSREV_REVISION_KIWI_10 0 /* Kiwi 1.0 */
+#define AR_XSREV_REVISION_KIWI_11 1 /* Kiwi 1.1 */
+#define AR_XSREV_REVISION_KIWI_12 2 /* Kiwi 1.2 */
+#define AR_XSREV_REVISION_KIWI_13 3 /* Kiwi 1.3 */
/* Owl (AR5416) */
#define AR_SREV_OWL(_ah) \
@@ -694,6 +783,10 @@
#define AR_SREV_KIWI(_ah) \
(AH_PRIVATE((_ah))->ah_macVersion == AR_XSREV_VERSION_KIWI)
+#define AR_SREV_KIWI_10_OR_LATER(_ah) \
+ (AH_PRIVATE((_ah))->ah_macVersion >= AR_XSREV_VERSION_KIWI)
+
+/* XXX TODO: make these handle macVersion > Kiwi */
#define AR_SREV_KIWI_11_OR_LATER(_ah) \
(AR_SREV_KIWI(_ah) && \
AH_PRIVATE((_ah))->ah_macRev >= AR_XSREV_REVISION_KIWI_11)
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130.ini 221163 2011-04-28 12:47:40Z adrian $
*/
static const uint32_t ar5416Modes_9100[][6] = {
Property changes on: trunk/sys/dev/ath/ath_hal/ar9001/ar9130.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
* Copyright (c) 2008 Sam Leffler, Errno Consulting
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c 242412 2012-10-31 21:14:25Z adrian $
*/
#include "opt_ah.h"
@@ -78,13 +79,13 @@
HAL_STATUS ecode;
HAL_BOOL rfStatus;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416));
if (ahp5416 == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -119,11 +120,11 @@
/*
* Use the "local" EEPROM data given to us by the higher layers.
- * This is a private copy out of system flash. The Linux ath9k
- * commit for the initial AR9130 support mentions MMIO flash
- * access is "unreliable." -adrian
+ * This is a private copy out of system flash.
+ * By this stage the SoC SPI flash may have disabled the memory-
+ * mapping and rely purely on port-based SPI IO.
*/
- AH_PRIVATE((ah))->ah_eepromRead = ar9130EepromRead;
+ AH_PRIVATE((ah))->ah_eepromRead = ath_hal_EepromDataRead;
AH_PRIVATE((ah))->ah_eepromWrite = NULL;
ah->ah_eepromdata = eepromdata;
@@ -298,7 +299,16 @@
*/
pCap->halMbssidAggrSupport = AH_FALSE;
pCap->hal4AddrAggrSupport = AH_TRUE;
+ /* BB Read WAR */
+ pCap->halHasBBReadWar = AH_TRUE;
+ /*
+ * Implement the PLL/config changes needed for half/quarter
+ * rates before re-enabling them here.
+ */
+ pCap->halChanHalfRate = AH_FALSE;
+ pCap->halChanQuarterRate = AH_FALSE;
+
return AH_TRUE;
}
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
* Copyright (c) 2010 Atheros Communications, Inc.
@@ -14,30 +15,5 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.c 230147 2012-01-15 19:22:34Z adrian $
*/
-#include "opt_ah.h"
-
-#include "ah.h"
-#include "ah_internal.h"
-
-#include "ar9001/ar9130_eeprom.h"
-
-/* XXX this shouldn't be done here */
-/* This is in 16 bit words; not bytes -adrian */
-#define ATH_DATA_EEPROM_SIZE 2048
-
-HAL_BOOL
-ar9130EepromRead(struct ath_hal *ah, u_int off, uint16_t *data)
-{
- if (ah->ah_eepromdata == AH_NULL) {
- HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__);
- return AH_FALSE;
- }
- if (off > ATH_DATA_EEPROM_SIZE) {
- HALDEBUG(ah, HAL_DEBUG_ANY, "ar9130EepromRead: offset %x > %x\n", off, ATH_DATA_EEPROM_SIZE);
- return AH_FALSE;
- }
- (*data) = ah->ah_eepromdata[off];
- return AH_TRUE;
-}
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Adrian Chadd, Xenion Pty Ltd
* Copyright (c) 2010 Atheros Communications, Inc.
@@ -14,11 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130_eeprom.h 230147 2012-01-15 19:22:34Z adrian $
*/
#ifndef __AR9130_EEPROM_H__
#define __AR9130_EEPROM_H__
-extern HAL_BOOL ar9130EepromRead(struct ath_hal *ah, u_int off, uint16_t *data);
-
#endif
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
* Copyright (c) 2010 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130_phy.c 242412 2012-10-31 21:14:25Z adrian $
*/
#include "opt_ah.h"
@@ -33,6 +34,9 @@
uint32_t pll;
+ /*
+ * XXX TODO: support half/quarter rates
+ */
if (chan && IEEE80211_IS_CHAN_5GHZ(chan))
pll = 0x1450;
else
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Adrian Chadd, Xenion Pty Ltd
* Copyright (c) 2008 Sam Leffler, Errno Consulting
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130_phy.h 221163 2011-04-28 12:47:40Z adrian $
*/
#ifndef __AR9130_PHY_H__
#define __AR9130_PHY_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9130reg.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9130reg.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9130reg.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Adrian Chadd, Xenion Pty Ltd
* Copyright (c) 2008 Sam Leffler, Errno Consulting
@@ -15,7 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9130reg.h 221163 2011-04-28 12:47:40Z adrian $
*/
#ifndef __AR9130REG_H__
#define __AR9130REG_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9160.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9160.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9160.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9160.ini 220293 2011-04-03 11:59:52Z adrian $
*/
/* Auto Generated PCI Register Writes. Created: 05/22/08 */
Property changes on: trunk/sys/dev/ath/ath_hal/ar9001/ar9160.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c 249579 2013-04-17 07:22:23Z adrian $
*/
#include "opt_ah.h"
@@ -68,8 +69,8 @@
.coarseHigh = { -14, -14, -14, -14, -12 },
.coarseLow = { -64, -64, -64, -64, -70 },
.firpwr = { -78, -78, -78, -78, -80 },
- .maxSpurImmunityLevel = 2,
- .cycPwrThr1 = { 2, 4, 6 },
+ .maxSpurImmunityLevel = 7,
+ .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 },
.maxFirstepLevel = 2, /* levels 0..2 */
.firstep = { 0, 4, 8 },
.ofdmTrigHigh = 500,
@@ -123,13 +124,13 @@
HAL_STATUS ecode;
HAL_BOOL rfStatus;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416));
if (ahp5416 == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -183,7 +184,7 @@
HAL_INI_INIT(&AH5416(ah)->ah_ini_bank1, ar9160Bank1, 2);
HAL_INI_INIT(&AH5416(ah)->ah_ini_bank2, ar9160Bank2, 2);
HAL_INI_INIT(&AH5416(ah)->ah_ini_bank3, ar9160Bank3, 3);
- HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar9160Bank6, 3);
+ HAL_INI_INIT(&AH5416(ah)->ah_ini_bank6, ar9160Bank6TPC, 3);
HAL_INI_INIT(&AH5416(ah)->ah_ini_bank7, ar9160Bank7, 2);
if (AR_SREV_SOWL_11(ah))
HAL_INI_INIT(&AH5416(ah)->ah_ini_addac, ar9160Addac_1_1, 2);
@@ -320,6 +321,8 @@
pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */
pCap->halMbssidAggrSupport = AH_TRUE;
pCap->hal4AddrAggrSupport = AH_TRUE;
+ /* BB Read WAR */
+ pCap->halHasBBReadWar = AH_TRUE;
/* AR9160 is a 2x2 stream device */
pCap->halTxStreams = 2;
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9002phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9002phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9002phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd.
*
@@ -22,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9002phy.h 220590 2011-04-13 04:40:59Z adrian $
*/
#ifndef __ATH_AR9002PHY_H__
#define __ATH_AR9002PHY_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280.c 241195 2012-10-04 15:42:45Z adrian $
*/
#include "opt_ah.h"
@@ -112,7 +113,17 @@
switch (frac_n_5g) {
case 0:
- if ((freq % 20) == 0) {
+ /*
+ * Enable fractional mode for half/quarter rate
+ * channels.
+ *
+ * This is from the Linux ath9k code, rather than
+ * the Atheros HAL code.
+ */
+ if (IEEE80211_IS_CHAN_QUARTER(chan) ||
+ IEEE80211_IS_CHAN_HALF(chan))
+ aModeRefSel = 0;
+ else if ((freq % 20) == 0) {
aModeRefSel = 3;
} else if ((freq % 10) == 0) {
aModeRefSel = 2;
@@ -122,10 +133,64 @@
default:
aModeRefSel = 0;
/* Enable 2G (fractional) mode for channels which are 5MHz spaced */
- fracMode = 1;
- refDivA = 1;
- channelSel = (freq * 0x8000)/15;
+ /*
+ * Workaround for talking on PSB non-5MHz channels;
+ * the pre-Merlin chips only had a 2.5MHz channel
+ * spacing so some channels aren't reachable.
+
+ *
+ * This interoperates on the quarter rate channels
+ * with the AR5112 and later RF synths. Please note
+ * that the synthesiser isn't able to completely
+ * accurately represent these frequencies (as the
+ * resolution in this reference is 2.5MHz) and thus
+ * it will be slightly "off centre." This matches
+ * the same slightly incorrect centre frequency
+ * behaviour that the AR5112 and later channel
+ * selection code has.
+ *
+ * This also interoperates with the AR5416
+ * synthesiser modification for programming
+ * fractional frequencies in 5GHz mode. However
+ * that modification is also disabled by default.
+ *
+ * This is disabled because it hasn't been tested for
+ * regulatory compliance and neither have the NICs
+ * which would use it. So if you enable this code,
+ * you must first ensure that you've re-certified the
+ * NICs in question beforehand or you will be
+ * violating your local regulatory rules and breaking
+ * the law.
+ */
+#if 0
+ if (freq % 5 == 0) {
+#endif
+ /* Normal */
+ fracMode = 1;
+ refDivA = 1;
+ channelSel = (freq * 0x8000)/15;
+#if 0
+ } else {
+ /* Offset by 500KHz */
+ uint32_t f, ch, ch2;
+
+ fracMode = 1;
+ refDivA = 1;
+
+ /* Calculate the "adjusted" frequency */
+ f = freq - 2;
+ ch = (((f - 4800) * 10) / 25) + 1;
+
+ ch2 = ((ch * 25) / 5) + 9600;
+ channelSel = (ch2 * 0x4000) / 15;
+ //ath_hal_printf(ah,
+ // "%s: freq=%d, ch=%d, ch2=%d, "
+ // "channelSel=%d\n",
+ // __func__, freq, ch, ch2, channelSel);
+ }
+#endif
+
/* RefDivA setting */
OS_A_REG_RMW_FIELD(ah, AR_AN_SYNTH9,
AR_AN_SYNTH9_REFDIVA, refDivA);
@@ -384,3 +449,11 @@
return AH_TRUE;
}
+
+static HAL_BOOL
+ar9280RfProbe(struct ath_hal *ah)
+{
+ return (AR_SREV_MERLIN(ah));
+}
+
+AH_RF(RF9280, ar9280RfProbe, ar9280RfAttach);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280.h 224243 2011-07-21 08:35:10Z adrian $
*/
#ifndef _ATH_AR9280_H_
#define _ATH_AR9280_H_
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c 244943 2013-01-02 00:38:01Z adrian $
*/
#include "opt_ah.h"
@@ -61,7 +62,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);
@@ -80,8 +83,8 @@
.coarseHigh = { -14, -14, -14, -14, -12 },
.coarseLow = { -64, -64, -64, -64, -70 },
.firpwr = { -78, -78, -78, -78, -80 },
- .maxSpurImmunityLevel = 2,
- .cycPwrThr1 = { 2, 4, 6 },
+ .maxSpurImmunityLevel = 7,
+ .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 },
.maxFirstepLevel = 2, /* levels 0..2 */
.firstep = { 0, 4, 8 },
.ofdmTrigHigh = 500,
@@ -112,6 +115,10 @@
* Else, set PLL to 0x2850 to prevent reset-to-reset variation
*/
pll = IS_5GHZ_FAST_CLOCK_EN(ah, chan) ? 0x142c : 0x2850;
+ if (IEEE80211_IS_CHAN_HALF(chan))
+ pll |= SM(0x1, AR_RTC_SOWL_PLL_CLKSEL);
+ else if (IEEE80211_IS_CHAN_QUARTER(chan))
+ pll |= SM(0x2, AR_RTC_SOWL_PLL_CLKSEL);
} else if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
pll = SM(0x5, AR_RTC_SOWL_PLL_REFDIV);
if (chan != AH_NULL) {
@@ -153,13 +160,13 @@
int8_t pwr_table_offset;
uint8_t pwr;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280));
if (ahp9280 == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -169,6 +176,18 @@
ar5416InitState(AH5416(ah), devid, sc, st, sh, status);
+ /*
+ * Use the "local" EEPROM data given to us by the higher layers.
+ * This is a private copy out of system flash. The Linux ath9k
+ * commit for the initial AR9130 support mentions MMIO flash
+ * access is "unreliable." -adrian
+ */
+ if (eepromdata != AH_NULL) {
+ AH_PRIVATE((ah))->ah_eepromRead = ath_hal_EepromDataRead;
+ AH_PRIVATE((ah))->ah_eepromWrite = NULL;
+ ah->ah_eepromdata = eepromdata;
+ }
+
/* XXX override with 9280 specific state */
/* override 5416 methods for our needs */
AH5416(ah)->ah_initPLL = ar9280InitPLL;
@@ -175,6 +194,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;
@@ -403,17 +423,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;
@@ -809,10 +885,6 @@
#if 0
pCap->halWowMatchPatternDword = AH_TRUE;
#endif
- /* AR9280 is a 2x2 stream device */
- pCap->halTxStreams = 2;
- pCap->halRxStreams = 2;
-
pCap->halCSTSupport = AH_TRUE;
pCap->halRifsRxSupport = AH_TRUE;
pCap->halRifsTxSupport = AH_TRUE;
@@ -829,6 +901,7 @@
pCap->halHasRxSelfLinkedTail = AH_FALSE;
pCap->halMbssidAggrSupport = AH_TRUE;
pCap->hal4AddrAggrSupport = AH_TRUE;
+ pCap->halSpectralScanSupport = AH_TRUE;
if (AR_SREV_MERLIN_20(ah)) {
pCap->halPSPollBroken = AH_FALSE;
@@ -892,9 +965,12 @@
static const char*
ar9280Probe(uint16_t vendorid, uint16_t devid)
{
- if (vendorid == ATHEROS_VENDOR_ID &&
- (devid == AR9280_DEVID_PCI || devid == AR9280_DEVID_PCIE))
- return "Atheros 9280";
+ if (vendorid == ATHEROS_VENDOR_ID) {
+ if (devid == AR9280_DEVID_PCI)
+ return "Atheros 9220";
+ if (devid == AR9280_DEVID_PCIE)
+ return "Atheros 9280";
+ }
return AH_NULL;
}
AH_CHIP(AR9280, ar9280Probe, ar9280Attach);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
*
@@ -22,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280_olc.c 221837 2011-05-13 14:33:45Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd.
*
@@ -22,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280_olc.h 219393 2011-03-08 06:59:59Z adrian $
*/
#ifndef __ATH_AR9280_OLC_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini 217631 2011-01-20 09:03:40Z adrian $
*/
/* Auto Generated PCI Register Writes. Created: 10/12/07 */
Property changes on: trunk/sys/dev/ath/ath_hal/ar9002/ar9280v1.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini 217751 2011-01-23 14:30:35Z adrian $
*/
static const uint32_t ar9280Modes_v2[][6] = {
Property changes on: trunk/sys/dev/ath/ath_hal/ar9002/ar9280v2.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285.c 228517 2011-12-15 00:59:11Z adrian $
*/
#include "opt_ah.h"
@@ -77,3 +78,11 @@
return AH_TRUE;
}
+
+static HAL_BOOL
+ar9285RfProbe(struct ath_hal *ah)
+{
+ return (AR_SREV_KITE(ah));
+}
+
+AH_RF(RF9285, ar9285RfProbe, ar9285RfAttach);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285.h 251655 2013-06-12 14:52:57Z adrian $
*/
#ifndef _ATH_AR9285_H_
#define _ATH_AR9285_H_
@@ -20,41 +21,6 @@
#include "ar5416/ar5416.h"
-enum ar9285_ant_div_comb_lna_conf {
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2 = 0,
- ATH_ANT_DIV_COMB_LNA2 = 1,
- ATH_ANT_DIV_COMB_LNA1 = 2,
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2 = 3,
-};
-
-struct ar9285_ant_comb {
- uint16_t count;
- uint16_t total_pkt_count;
- HAL_BOOL scan;
- HAL_BOOL scan_not_start;
- int main_total_rssi;
- int alt_total_rssi;
- int alt_recv_cnt;
- int main_recv_cnt;
- int rssi_lna1;
- int rssi_lna2;
- int rssi_add;
- int rssi_sub;
- int rssi_first;
- int rssi_second;
- int rssi_third;
- HAL_BOOL alt_good;
- int quick_scan_cnt;
- int main_conf;
- enum ar9285_ant_div_comb_lna_conf first_quick_scan_conf;
- enum ar9285_ant_div_comb_lna_conf second_quick_scan_conf;
- int first_bias;
- int second_bias;
- HAL_BOOL first_ratio;
- HAL_BOOL second_ratio;
- unsigned long scan_start_time;
-};
-
struct ath_hal_9285 {
struct ath_hal_5416 ah_5416;
@@ -61,8 +27,6 @@
HAL_INI_ARRAY ah_ini_txgain;
HAL_INI_ARRAY ah_ini_rxgain;
- struct ar9285_ant_comb ant_comb; /* Kite Antenna comb/diversity */
-
struct {
int32_t prev_offset; /* Previous value of PA offset value */
int8_t max_skipcount; /* Max No. of times PACAL can be skipped */
@@ -78,7 +42,6 @@
#define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ -127
#define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ -108
-HAL_BOOL ar9285SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING);
HAL_BOOL ar9285RfAttach(struct ath_hal *, HAL_STATUS *);
extern HAL_BOOL ar9285SetTransmitPower(struct ath_hal *,
@@ -86,4 +49,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_ */
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285.ini 217631 2011-01-20 09:03:40Z adrian $
*/
/* AR9285 Revsion 10 */
Property changes on: trunk/sys/dev/ath/ath_hal/ar9002/ar9285.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c 251655 2013-06-12 14:52:57Z adrian $
*/
#include "opt_ah.h"
@@ -66,7 +67,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);
@@ -85,8 +88,8 @@
.coarseHigh = { -14, -14, -14, -14, -12 },
.coarseLow = { -64, -64, -64, -64, -70 },
.firpwr = { -78, -78, -78, -78, -80 },
- .maxSpurImmunityLevel = 2,
- .cycPwrThr1 = { 2, 4, 6 },
+ .maxSpurImmunityLevel = 7,
+ .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 },
.maxFirstepLevel = 2, /* levels 0..2 */
.firstep = { 0, 4, 8 },
.ofdmTrigHigh = 500,
@@ -103,6 +106,28 @@
ar5416AniAttach(ah, &aniparams, &aniparams, AH_TRUE);
}
+static const char * ar9285_lna_conf[] = {
+ "LNA1-LNA2",
+ "LNA2",
+ "LNA1",
+ "LNA1+LNA2",
+};
+
+static void
+ar9285_eeprom_print_diversity_settings(struct ath_hal *ah)
+{
+ const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom;
+ const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader;
+
+ ath_hal_printf(ah, "[ath] AR9285 Main LNA config: %s\n",
+ ar9285_lna_conf[(pModal->antdiv_ctl2 >> 2) & 0x3]);
+ ath_hal_printf(ah, "[ath] AR9285 Alt LNA config: %s\n",
+ ar9285_lna_conf[pModal->antdiv_ctl2 & 0x3]);
+ ath_hal_printf(ah, "[ath] LNA diversity %s, Diversity %s\n",
+ ((pModal->antdiv_ctl1 & 0x1) ? "enabled" : "disabled"),
+ ((pModal->antdiv_ctl1 & 0x8) ? "enabled" : "disabled"));
+}
+
/*
* Attach for an AR9285 part.
*/
@@ -118,13 +143,13 @@
HAL_STATUS ecode;
HAL_BOOL rfStatus;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285));
if (ahp9285 == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -134,14 +159,30 @@
ar5416InitState(AH5416(ah), devid, sc, st, sh, status);
- /* XXX override with 9285 specific state */
- /* override 5416 methods for our needs */
+ /*
+ * Use the "local" EEPROM data given to us by the higher layers.
+ * This is a private copy out of system flash. The Linux ath9k
+ * commit for the initial AR9130 support mentions MMIO flash
+ * access is "unreliable." -adrian
+ */
+ if (eepromdata != AH_NULL) {
+ AH_PRIVATE(ah)->ah_eepromRead = ath_hal_EepromDataRead;
+ AH_PRIVATE(ah)->ah_eepromWrite = NULL;
+ ah->ah_eepromdata = eepromdata;
+ }
+
+ /* override with 9285 specific state */
AH5416(ah)->ah_initPLL = ar9280InitPLL;
+ AH5416(ah)->ah_btCoexSetDiversity = ar9285BTCoexAntennaDiversity;
ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch;
ah->ah_configPCIE = ar9285ConfigPCIE;
+ ah->ah_disablePCIE = ar9285DisablePCIE;
ah->ah_setTxPower = ar9285SetTransmitPower;
ah->ah_setBoardValues = ar9285SetBoardValues;
+ ah->ah_btCoexSetParameter = ar9285BTCoexSetParameter;
+ ah->ah_divLnaConfGet = ar9285_antdiv_comb_conf_get;
+ ah->ah_divLnaConfSet = ar9285_antdiv_comb_conf_set;
AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal;
AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal;
@@ -293,10 +334,16 @@
goto bad;
}
+ /*
+ * Print out the EEPROM antenna configuration mapping.
+ * Some devices have a hard-coded LNA configuration profile;
+ * others enable diversity.
+ */
+ ar9285_eeprom_print_diversity_settings(ah);
+
/* Print out whether the EEPROM settings enable AR9285 diversity */
if (ar9285_check_div_comb(ah)) {
ath_hal_printf(ah, "[ath] Enabling diversity for Kite\n");
- ah->ah_rxAntCombDiversity = ar9285_ant_comb_scan;
}
/* Disable 11n for the AR2427 */
@@ -350,17 +397,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;
@@ -411,6 +536,9 @@
pCap->halTxStreams = 1;
pCap->halRxStreams = 1;
+ if (ar9285_check_div_comb(ah))
+ pCap->halAntDivCombSupport = AH_TRUE;
+
pCap->halCSTSupport = AH_TRUE;
pCap->halRifsRxSupport = AH_TRUE;
pCap->halRifsTxSupport = AH_TRUE;
@@ -417,7 +545,7 @@
pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */
pCap->halExtChanDfsSupport = AH_TRUE;
pCap->halUseCombinedRadarRssi = AH_TRUE;
-#if 0
+#if 1
/* XXX bluetooth */
pCap->halBtCoexSupport = AH_TRUE;
#endif
@@ -427,6 +555,8 @@
pCap->halHasRxSelfLinkedTail = AH_FALSE;
pCap->halMbssidAggrSupport = AH_TRUE;
pCap->hal4AddrAggrSupport = AH_TRUE;
+ pCap->halSpectralScanSupport = AH_TRUE;
+ pCap->halRxUsingLnaMixing = AH_TRUE;
if (AR_SREV_KITE_12_OR_LATER(ah))
pCap->halPSPollBroken = AH_FALSE;
Added: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c (rev 0)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,153 @@
+/* $MidnightBSD$ */
+/*
+ * 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: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c 251483 2013-06-07 05:17:58Z 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;
+
+ HALDEBUG(ah, HAL_DEBUG_BT_COEX,
+ "%s: btCoexFlag: ALLOW=%d, ENABLE=%d\n",
+ __func__,
+ !! (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ALLOW),
+ !! (ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ENABLE));
+
+ 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_antControl == 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_antControl == 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 table 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 table 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;
+ }
+}
+
+
Property changes on: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_cal.c 221806 2011-05-12 10:11:24Z adrian $
*/
#include "opt_ah.h"
#include "ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_cal.h 219481 2011-03-11 11:58:54Z adrian $
*/
#ifndef __AR9285_CAL_H__
#define __AR9285_CAL_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.c 251655 2013-06-12 14:52:57Z adrian $
*/
#include "opt_ah.h"
@@ -33,7 +34,6 @@
#include "ah_eeprom_v4k.h"
#include "ar9002/ar9280.h"
-#include "ar9002/ar9285_diversity.h"
#include "ar9002/ar9285.h"
#include "ar5416/ar5416reg.h"
#include "ar5416/ar5416phy.h"
@@ -40,603 +40,9 @@
#include "ar9002/ar9285phy.h"
#include "ar9002/ar9285_phy.h"
+#include "ar9002/ar9285_diversity.h"
-/* Linux compability macros */
/*
- * XXX these don't handle rounding, underflow, overflow, wrapping!
- */
-#define msecs_to_jiffies(a) ( (a) * hz / 1000 )
-#define time_after(a, b) ( (long) (b) - (long) (a) < 0 )
-
-static HAL_BOOL
-ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
- int main_rssi_avg, int alt_rssi_avg, int pkt_count)
-{
- return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
- (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
- (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
-}
-
-static void
-ath_lnaconf_alt_good_scan(struct ar9285_ant_comb *antcomb,
- struct ar9285_antcomb_conf ant_conf, int main_rssi_avg)
-{
- antcomb->quick_scan_cnt = 0;
-
- if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = main_rssi_avg;
- else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = main_rssi_avg;
-
- switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
- case (0x10): /* LNA2 A-B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
- break;
- case (0x20): /* LNA1 A-B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
- break;
- case (0x21): /* LNA1 LNA2 */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case (0x12): /* LNA2 LNA1 */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case (0x13): /* LNA2 A+B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
- break;
- case (0x23): /* LNA1 A+B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
- break;
- default:
- break;
- }
-}
-
-static void
-ath_select_ant_div_from_quick_scan(struct ar9285_ant_comb *antcomb,
- struct ar9285_antcomb_conf *div_ant_conf, int main_rssi_avg,
- int alt_rssi_avg, int alt_ratio)
-{
- /* alt_good */
- switch (antcomb->quick_scan_cnt) {
- case 0:
- /* set alt to main, and alt to first conf */
- div_ant_conf->main_lna_conf = antcomb->main_conf;
- div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
- break;
- case 1:
- /* set alt to main, and alt to first conf */
- div_ant_conf->main_lna_conf = antcomb->main_conf;
- div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
- antcomb->rssi_first = main_rssi_avg;
- antcomb->rssi_second = alt_rssi_avg;
-
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
- /* main is LNA1 */
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = AH_TRUE;
- else
- antcomb->first_ratio = AH_FALSE;
- } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = AH_TRUE;
- else
- antcomb->first_ratio = AH_FALSE;
- } else {
- if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
- (alt_rssi_avg > main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
- (alt_rssi_avg > main_rssi_avg)) &&
- (antcomb->total_pkt_count > 50))
- antcomb->first_ratio = AH_TRUE;
- else
- antcomb->first_ratio = AH_FALSE;
- }
- break;
- case 2:
- antcomb->alt_good = AH_FALSE;
- antcomb->scan_not_start = AH_FALSE;
- antcomb->scan = AH_FALSE;
- antcomb->rssi_first = main_rssi_avg;
- antcomb->rssi_third = alt_rssi_avg;
-
- if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = alt_rssi_avg;
- else if (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = alt_rssi_avg;
- else if (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = main_rssi_avg;
- else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = main_rssi_avg;
- }
-
- if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
- ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
-
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = AH_TRUE;
- else
- antcomb->second_ratio = AH_FALSE;
- } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
- if (ath_is_alt_ant_ratio_better(alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = AH_TRUE;
- else
- antcomb->second_ratio = AH_FALSE;
- } else {
- if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
- (alt_rssi_avg > main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
- (alt_rssi_avg > main_rssi_avg)) &&
- (antcomb->total_pkt_count > 50))
- antcomb->second_ratio = AH_TRUE;
- else
- antcomb->second_ratio = AH_FALSE;
- }
-
- /* set alt to the conf with maximun ratio */
- if (antcomb->first_ratio && antcomb->second_ratio) {
- if (antcomb->rssi_second > antcomb->rssi_third) {
- /* first alt*/
- if ((antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2*/
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->first_quick_scan_conf;
- } else if ((antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2)) {
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- } else {
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->second_quick_scan_conf;
- }
- } else if (antcomb->first_ratio) {
- /* first alt */
- if ((antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->first_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->first_quick_scan_conf;
- } else if (antcomb->second_ratio) {
- /* second alt */
- if ((antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->second_quick_scan_conf ==
- ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf =
- antcomb->second_quick_scan_conf;
- } else {
- /* main is largest */
- if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (div_ant_conf->main_lna_conf ==
- ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else
- div_ant_conf->alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- div_ant_conf->alt_lna_conf = antcomb->main_conf;
- }
- break;
- default:
- break;
- }
-}
-
-static void
-ath_ant_div_conf_fast_divbias(struct ar9285_antcomb_conf *ant_conf)
-{
- /* Adjust the fast_div_bias based on main and alt lna conf */
- switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
- case (0x01): /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case (0x02): /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- case (0x03): /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case (0x10): /* LNA2 A-B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case (0x12): /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x2;
- break;
- case (0x13): /* LNA2 A+B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case (0x20): /* LNA1 A-B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case (0x21): /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x0;
- break;
- case (0x23): /* LNA1 A+B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case (0x30): /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case (0x31): /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case (0x32): /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- default:
- break;
- }
-}
-
-/* Antenna diversity and combining */
-void
-ar9285_ant_comb_scan(struct ath_hal *ah, struct ath_rx_status *rs,
- unsigned long ticks, int hz)
-{
- struct ar9285_antcomb_conf div_ant_conf;
- struct ar9285_ant_comb *antcomb = &AH9285(ah)->ant_comb;
- int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
- int curr_main_set, curr_bias;
- int main_rssi = rs->rs_rssi_ctl[0];
- int alt_rssi = rs->rs_rssi_ctl[1];
- int rx_ant_conf, main_ant_conf, alt_ant_conf;
- HAL_BOOL short_scan = AH_FALSE;
-
- rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK;
- main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK;
- alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK;
-
-#if 0
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; FastDiv: %d\n",
- __func__, main_rssi, alt_rssi, main_ant_conf,alt_ant_conf, rx_ant_conf,
- !!(rs->rs_rssi_ctl[2] & 0x80), !!(rs->rs_rssi_ctl[2] & 0x40), !!(rs->rs_rssi_ext[2] & 0x40));
-#endif
-
- if (! ar9285_check_div_comb(ah))
- return;
-
- if (AH5212(ah)->ah_diversity == AH_FALSE)
- return;
-
-#if 0
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main: %d, alt: %d, rx_ant_conf: %x, main_ant_conf: %x\n",
- __func__, main_rssi, alt_rssi, rx_ant_conf, main_ant_conf);
-#endif
-
- /* Record packet only when alt_rssi is positive */
- if (main_rssi > 0 && alt_rssi > 0) {
- antcomb->total_pkt_count++;
- antcomb->main_total_rssi += main_rssi;
- antcomb->alt_total_rssi += alt_rssi;
- if (main_ant_conf == rx_ant_conf)
- antcomb->main_recv_cnt++;
- else
- antcomb->alt_recv_cnt++;
- }
-
- /* Short scan check */
- if (antcomb->scan && antcomb->alt_good) {
- if (time_after(ticks, antcomb->scan_start_time +
- msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
- short_scan = AH_TRUE;
- else
- if (antcomb->total_pkt_count ==
- ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
- alt_ratio = ((antcomb->alt_recv_cnt * 100) /
- antcomb->total_pkt_count);
- if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
- short_scan = AH_TRUE;
- }
- }
-
- if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
- rs->rs_moreaggr) && !short_scan)
- return;
-
- if (antcomb->total_pkt_count) {
- alt_ratio = ((antcomb->alt_recv_cnt * 100) /
- antcomb->total_pkt_count);
- main_rssi_avg = (antcomb->main_total_rssi /
- antcomb->total_pkt_count);
- alt_rssi_avg = (antcomb->alt_total_rssi /
- antcomb->total_pkt_count);
- }
-
- ar9285_antdiv_comb_conf_get(ah, &div_ant_conf);
- curr_alt_set = div_ant_conf.alt_lna_conf;
- curr_main_set = div_ant_conf.main_lna_conf;
- curr_bias = div_ant_conf.fast_div_bias;
-
- antcomb->count++;
-
- if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
- ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
- main_rssi_avg);
- antcomb->alt_good = AH_TRUE;
- } else {
- antcomb->alt_good = AH_FALSE;
- }
-
- antcomb->count = 0;
- antcomb->scan = AH_TRUE;
- antcomb->scan_not_start = AH_TRUE;
- }
-
- if (!antcomb->scan) {
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
- if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
- /* Switch main and alt LNA */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
-
- goto div_comb_done;
- } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
- (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
- /* Set alt to another LNA */
- if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
-
- goto div_comb_done;
- }
-
- if ((alt_rssi_avg < (main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
- goto div_comb_done;
- }
-
- if (!antcomb->scan_not_start) {
- switch (curr_alt_set) {
- case ATH_ANT_DIV_COMB_LNA2:
- antcomb->rssi_lna2 = alt_rssi_avg;
- antcomb->rssi_lna1 = main_rssi_avg;
- antcomb->scan = AH_TRUE;
- /* set to A+B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1:
- antcomb->rssi_lna1 = alt_rssi_avg;
- antcomb->rssi_lna2 = main_rssi_avg;
- antcomb->scan = AH_TRUE;
- /* set to A+B */
- div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
- antcomb->rssi_add = alt_rssi_avg;
- antcomb->scan = AH_TRUE;
- /* set to A-B */
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
- antcomb->rssi_sub = alt_rssi_avg;
- antcomb->scan = AH_FALSE;
- if (antcomb->rssi_lna2 >
- (antcomb->rssi_lna1 +
- ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
- /* use LNA2 as main LNA */
- if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
- (antcomb->rssi_add > antcomb->rssi_sub)) {
- /* set to A+B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- } else if (antcomb->rssi_sub >
- antcomb->rssi_lna1) {
- /* set to A-B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- } else {
- /* set to LNA1 */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- }
- } else {
- /* use LNA1 as main LNA */
- if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
- (antcomb->rssi_add > antcomb->rssi_sub)) {
- /* set to A+B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- } else if (antcomb->rssi_sub >
- antcomb->rssi_lna1) {
- /* set to A-B */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- } else {
- /* set to LNA2 */
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
- }
- break;
- default:
- break;
- }
- } else {
- if (!antcomb->alt_good) {
- antcomb->scan_not_start = AH_FALSE;
- /* Set alt to another LNA */
- if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
- goto div_comb_done;
- }
- }
-
- ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
- main_rssi_avg, alt_rssi_avg,
- alt_ratio);
-
- antcomb->quick_scan_cnt++;
-
-div_comb_done:
- ath_ant_div_conf_fast_divbias(&div_ant_conf);
-
- ar9285_antdiv_comb_conf_set(ah, &div_ant_conf);
-
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
- __func__, antcomb->total_pkt_count);
-
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n",
- __func__, antcomb->main_total_rssi);
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n",
- __func__, antcomb->alt_total_rssi);
-
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n",
- __func__, main_rssi_avg);
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n",
- __func__, alt_rssi_avg);
-
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n",
- __func__, antcomb->main_recv_cnt);
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n",
- __func__, antcomb->alt_recv_cnt);
-
-// if (curr_alt_set != div_ant_conf.alt_lna_conf)
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n",
- __func__, curr_alt_set, div_ant_conf.alt_lna_conf);
-// if (curr_main_set != div_ant_conf.main_lna_conf)
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n",
- __func__, curr_main_set, div_ant_conf.main_lna_conf);
-// if (curr_bias != div_ant_conf.fast_div_bias)
- HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n",
- __func__, curr_bias, div_ant_conf.fast_div_bias);
-
- antcomb->scan_start_time = ticks;
- antcomb->total_pkt_count = 0;
- antcomb->main_total_rssi = 0;
- antcomb->alt_total_rssi = 0;
- antcomb->main_recv_cnt = 0;
- antcomb->alt_recv_cnt = 0;
-}
-
-/*
* Set the antenna switch to control RX antenna diversity.
*
* If a fixed configuration is used, the LNA and div bias
@@ -697,8 +103,8 @@
/* Diversity disabled, RX = LNA1 */
HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_FIXED_A\n",
__func__);
- regVal |= SM(ATH_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
- regVal |= SM(ATH_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+ regVal |= SM(HAL_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+ regVal |= SM(HAL_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_0, AR_PHY_9285_ANT_DIV_ALT_GAINTB);
regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_1, AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
}
@@ -706,8 +112,8 @@
/* Diversity disabled, RX = LNA2 */
HALDEBUG(ah, HAL_DEBUG_DIVERSITY, "%s: HAL_ANT_FIXED_B\n",
__func__);
- regVal |= SM(ATH_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
- regVal |= SM(ATH_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+ regVal |= SM(HAL_ANT_DIV_COMB_LNA1, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+ regVal |= SM(HAL_ANT_DIV_COMB_LNA2, AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_1, AR_PHY_9285_ANT_DIV_ALT_GAINTB);
regVal |= SM(AR_PHY_9285_ANT_DIV_GAINTB_0, AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
}
@@ -740,8 +146,8 @@
__func__);
regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF | AR_PHY_9285_ANT_DIV_ALT_LNACONF));
- regVal |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S);
- regVal |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S);
+ regVal |= (HAL_ANT_DIV_COMB_LNA1 << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S);
+ regVal |= (HAL_ANT_DIV_COMB_LNA2 << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S);
regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S);
OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,31 +24,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_diversity.h 251655 2013-06-12 14:52:57Z adrian $
*/
#ifndef __AR9285_DIVERSITY_H__
#define __AR9285_DIVERSITY_H__
-/* Antenna diversity/combining */
-#define ATH_ANT_RX_CURRENT_SHIFT 4
-#define ATH_ANT_RX_MAIN_SHIFT 2
-#define ATH_ANT_RX_MASK 0x3
+extern HAL_BOOL ar9285SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING);
-#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
-#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
-#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
-#define ATH_ANT_DIV_COMB_INIT_COUNT 95
-#define ATH_ANT_DIV_COMB_MAX_COUNT 100
-#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
-#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
-
-#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
-#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
-#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
-#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
-#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
-
-extern void ar9285_ant_comb_scan(struct ath_hal *ah, struct ath_rx_status *rs,
- unsigned long ticks, int hz);
-
#endif
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_phy.c 251656 2013-06-12 15:18:10Z adrian $
*/
#include "opt_ah.h"
@@ -40,8 +41,7 @@
#include "ar9002/ar9285_phy.h"
void
-ar9285_antdiv_comb_conf_get(struct ath_hal *ah,
- struct ar9285_antcomb_conf *antconf)
+ar9285_antdiv_comb_conf_get(struct ath_hal *ah, HAL_ANT_COMB_CONFIG *antconf)
{
uint32_t regval;
@@ -52,11 +52,11 @@
AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
AR_PHY_9285_FAST_DIV_BIAS_S;
+ antconf->antdiv_configgroup = DEFAULT_ANTDIV_CONFIG_GROUP;
}
void
-ar9285_antdiv_comb_conf_set(struct ath_hal *ah,
- struct ar9285_antcomb_conf *antconf)
+ar9285_antdiv_comb_conf_set(struct ath_hal *ah, HAL_ANT_COMB_CONFIG *antconf)
{
uint32_t regval;
@@ -87,8 +87,10 @@
HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom;
const MODAL_EEP4K_HEADER *pModal = &ee->ee_base.modalHeader;
+#if 0
/* For now, simply disable this until it's better debugged. -adrian */
return AH_FALSE;
+#endif
if (! AR_SREV_KITE(ah))
return AH_FALSE;
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_phy.h 251643 2013-06-12 06:01:53Z adrian $
*/
#ifndef __AR9285_PHY_H__
#define __AR9285_PHY_H__
@@ -31,16 +32,11 @@
/*
* Manipulate AR9285 antenna diversity configuration
*/
-struct ar9285_antcomb_conf {
- uint8_t main_lna_conf;
- uint8_t alt_lna_conf;
- uint8_t fast_div_bias;
-};
extern void ar9285_antdiv_comb_conf_set(struct ath_hal *ah,
- struct ar9285_antcomb_conf *antconf);
+ HAL_ANT_COMB_CONFIG *antconf);
extern void ar9285_antdiv_comb_conf_get(struct ath_hal *ah,
- struct ar9285_antcomb_conf *antconf);
+ HAL_ANT_COMB_CONFIG *antconf);
extern HAL_BOOL ar9285_check_div_comb(struct ath_hal *ah);
#endif
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c 251655 2013-06-12 14:52:57Z adrian $
*/
/*
@@ -38,6 +39,7 @@
#include "ar9002/ar9002phy.h"
#include "ar9002/ar9285phy.h"
#include "ar9002/ar9285an.h"
+#include "ar9002/ar9285_diversity.h"
/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */
#define EEP_MINOR(_ah) \
@@ -76,9 +78,7 @@
MODAL_EEP4K_HEADER *pModal;
struct ath_hal_5212 *ahp = AH5212(ah);
- int16_t ratesArray[Ar5416RateSize];
int16_t txPowerIndexOffset = 0;
- uint8_t ht40PowerIncForPdadc = 2;
int i;
uint16_t cfgCtl;
@@ -91,8 +91,10 @@
HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
+ AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
+
/* Setup info for the actual eeprom */
- OS_MEMZERO(ratesArray, sizeof(ratesArray));
+ OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray));
cfgCtl = ath_hal_getctl(ah, chan);
powerLimit = chan->ic_maxregpower * 2;
twiceAntennaReduction = chan->ic_maxantgain;
@@ -102,11 +104,11 @@
__func__,chan->ic_freq, cfgCtl );
if (IS_EEP_MINOR_V2(ah)) {
- ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
}
if (!ar9285SetPowerPerRateTable(ah, pEepData, chan,
- &ratesArray[0],cfgCtl,
+ &AH5416(ah)->ah_ratesArray[0],cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower, powerLimit)) {
HALDEBUG(ah, HAL_DEBUG_ANY,
@@ -120,11 +122,12 @@
return AH_FALSE;
}
- maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
- maxPower = AH_MAX(maxPower, ratesArray[rate1l]);
+ maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
+ AH5416(ah)->ah_ratesArray[rateHt20_0]);
+ maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]);
if (IEEE80211_IS_CHAN_HT40(chan)) {
- maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]);
+ maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]);
}
ahp->ah_tx6PowerInHalfDbm = maxPower;
@@ -135,18 +138,18 @@
* txPowerIndexOffset is set by the SetPowerTable() call -
* adjust the rate table (0 offset if rates EEPROM not loaded)
*/
- for (i = 0; i < N(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
+ AH5416(ah)->ah_ratesArray[i] = (int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]);
/* -5 dBm offset for Merlin and later; this includes Kite */
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
- if (ratesArray[i] < 0)
- ratesArray[i] = 0;
+ AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
+ if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
+ AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
+ if (AH5416(ah)->ah_ratesArray[i] < 0)
+ AH5416(ah)->ah_ratesArray[i] = 0;
}
#ifdef AH_EEPROM_DUMP
- ar5416PrintPowerPerRate(ah, ratesArray);
+ ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
#endif
/*
@@ -157,18 +160,26 @@
* XXX handle overflow/too high power level?
*/
if (IEEE80211_IS_CHAN_HT40(chan)) {
- ratesArray[rateHt40_0] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_1] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_2] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_3] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_4] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_5] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_6] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_7] += ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_0] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_1] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_2] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_3] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_4] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_5] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_6] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_7] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
}
/* Write the TX power rate registers */
- ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray);
+ ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
return AH_TRUE;
#undef POW_SM
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285an.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285an.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285an.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285an.h 221806 2011-05-12 10:11:24Z adrian $
*/
#ifndef __AR9285_AN_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285phy.h 219481 2011-03-11 11:58:54Z adrian $
*/
#ifndef __ATH_AR9285PHY_H__
#define __ATH_AR9285PHY_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini 217811 2011-01-25 05:36:29Z adrian $
*/
static const u_int32_t ar9285Modes_v2[][6] = {
Property changes on: trunk/sys/dev/ath/ath_hal/ar9002/ar9285v2.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287.c 228517 2011-12-15 00:59:11Z adrian $
*/
#include "opt_ah.h"
@@ -390,3 +391,11 @@
return AH_TRUE;
}
+
+static HAL_BOOL
+ar9287RfProbe(struct ath_hal *ah)
+{
+ return (AR_SREV_KIWI(ah));
+}
+
+AH_RF(RF9287, ar9287RfProbe, ar9287RfAttach);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Atheros Communications, Inc.
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287.h 228833 2011-12-23 04:05:39Z adrian $
*/
#ifndef _ATH_AR9287_H_
@@ -45,9 +46,7 @@
#define AH9287(_ah) ((struct ath_hal_9287 *)(_ah))
#define AR9287_DEFAULT_RXCHAINMASK 3
-#define AR9285_DEFAULT_RXCHAINMASK 1
#define AR9287_DEFAULT_TXCHAINMASK 3
-#define AR9285_DEFAULT_TXCHAINMASK 1
#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -112
#define AR_PHY_CCA_NOM_VAL_9287_5GHZ -112
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287.ini
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287.ini 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287.ini 2018-05-28 00:25:20 UTC (rev 10127)
@@ -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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287.ini 222301 2011-05-26 09:15:33Z adrian $
*/
static const uint32_t ar9287Modes_9287_1_1[][6] = {
Property changes on: trunk/sys/dev/ath/ath_hal/ar9002/ar9287.ini
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c 244943 2013-01-02 00:38:01Z adrian $
*/
#include "opt_ah.h"
@@ -65,7 +66,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);
@@ -76,7 +79,7 @@
/*
* These are the parameters from the AR5416 ANI code;
* they likely need quite a bit of adjustment for the
- * AR9280.
+ * AR9287.
*/
static const struct ar5212AniParams aniparams = {
.maxNoiseImmunityLevel = 4, /* levels 0..4 */
@@ -84,8 +87,8 @@
.coarseHigh = { -14, -14, -14, -14, -12 },
.coarseLow = { -64, -64, -64, -64, -70 },
.firpwr = { -78, -78, -78, -78, -80 },
- .maxSpurImmunityLevel = 2,
- .cycPwrThr1 = { 2, 4, 6 },
+ .maxSpurImmunityLevel = 7,
+ .cycPwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 },
.maxFirstepLevel = 2, /* levels 0..2 */
.firstep = { 0, 4, 8 },
.ofdmTrigHigh = 500,
@@ -119,13 +122,13 @@
HAL_BOOL rfStatus;
int8_t pwr_table_offset;
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
+ HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n",
__func__, sc, (void*) st, (void*) sh);
/* NB: memory is returned zero'd */
ahp9287 = ath_hal_malloc(sizeof (struct ath_hal_9287));
if (ahp9287 == AH_NULL) {
- HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
+ HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
"%s: cannot allocate memory for state block\n", __func__);
*status = HAL_ENOMEM;
return AH_NULL;
@@ -135,6 +138,13 @@
ar5416InitState(AH5416(ah), devid, sc, st, sh, status);
+ if (eepromdata != AH_NULL) {
+ AH_PRIVATE(ah)->ah_eepromRead = ath_hal_EepromDataRead;
+ AH_PRIVATE(ah)->ah_eepromWrite = NULL;
+ ah->ah_eepromdata = eepromdata;
+ }
+
+
/* XXX override with 9280 specific state */
/* override 5416 methods for our needs */
AH5416(ah)->ah_initPLL = ar9280InitPLL;
@@ -141,6 +151,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;
@@ -357,17 +368,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;
@@ -402,13 +420,6 @@
regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites);
}
-#define AR_BASE_FREQ_2GHZ 2300
-#define AR_BASE_FREQ_5GHZ 4900
-#define AR_SPUR_FEEQ_BOUND_HT40 19
-#define AR_SPUR_FEEQ_BOUND_HT20 10
-
-
-
/*
* Fill all software cached or static hardware state information.
* Return failure if capabilities are to come from EEPROM and
@@ -443,6 +454,7 @@
/* Disable this so Block-ACK works correctly */
pCap->halHasRxSelfLinkedTail = AH_FALSE;
pCap->halPSPollBroken = AH_FALSE;
+ pCap->halSpectralScanSupport = AH_TRUE;
/* Hardware supports (at least) single-stream STBC TX/RX */
pCap->halRxStbcSupport = 1;
@@ -460,7 +472,7 @@
* This has been disabled - having the HAL flip chainmasks on/off
* when attempting to implement 11n disrupts things. For now, just
* leave this flipped off and worry about implementing TX diversity
- * for legacy and MCS0-7 when 11n is fully functioning.
+ * for legacy and MCS0-15 when 11n is fully functioning.
*/
HAL_BOOL
ar9287SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
@@ -471,9 +483,12 @@
static const char*
ar9287Probe(uint16_t vendorid, uint16_t devid)
{
- if (vendorid == ATHEROS_VENDOR_ID &&
- (devid == AR9287_DEVID_PCI || devid == AR9287_DEVID_PCIE))
- return "Atheros 9287";
+ if (vendorid == ATHEROS_VENDOR_ID) {
+ if (devid == AR9287_DEVID_PCI)
+ return "Atheros 9227";
+ if (devid == AR9287_DEVID_PCIE)
+ return "Atheros 9287";
+ }
return AH_NULL;
}
AH_CHIP(AR9287, ar9287Probe, ar9287Attach);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_cal.c 222301 2011-05-26 09:15:33Z adrian $
*/
#include "opt_ah.h"
#include "ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2008-2010 Atheros Communications Inc.
*
@@ -22,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_cal.h 222301 2011-05-26 09:15:33Z adrian $
*/
#ifndef __AR9287_CAL_H__
#define __AR9287_CAL_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
*
@@ -22,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c 222314 2011-05-26 16:52:37Z adrian $
*/
#include "opt_ah.h"
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Atheros Communications, Inc.
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h 222308 2011-05-26 14:29:05Z adrian $
*/
#ifndef __AR9287_OLC_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2002-2008 Atheros Communications, Inc.
@@ -14,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c 249580 2013-04-17 07:31:53Z adrian $
*/
#include "opt_ah.h"
@@ -45,70 +46,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,41 +330,44 @@
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 txPowerIndexOffset = 0;
+ 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;
+ AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
+
/* Setup info for the actual eeprom */
- OS_MEMZERO(ratesArray, sizeof(ratesArray));
+ OS_MEMZERO(AH5416(ah)->ah_ratesArray,
+ sizeof(AH5416(ah)->ah_ratesArray));
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 );
/* XXX Assume Minor is v2 or later */
- ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
/* Fetch per-rate power table for the given channel */
if (! ar9287SetPowerPerRateTable(ah, pEepData, chan,
- &ratesArray[0],cfgCtl,
- twiceAntennaReduction,
- twiceMaxRegulatoryPower, powerLimit)) {
+ &AH5416(ah)->ah_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;
@@ -373,11 +377,14 @@
ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset);
/* Calculate maximum power level */
- maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
- maxPower = AH_MAX(maxPower, ratesArray[rate1l]);
+ maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
+ AH5416(ah)->ah_ratesArray[rateHt20_0]);
+ maxPower = AH_MAX(maxPower,
+ AH5416(ah)->ah_ratesArray[rate1l]);
if (IEEE80211_IS_CHAN_HT40(chan))
- maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]);
+ maxPower = AH_MAX(maxPower,
+ AH5416(ah)->ah_ratesArray[rateHt40_0]);
ahp->ah_tx6PowerInHalfDbm = maxPower;
AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower;
@@ -388,18 +395,20 @@
* adjust the rate table (0 offset if rates EEPROM not loaded)
*/
/* XXX what about the pwrTableOffset? */
- for (i = 0; i < N(ratesArray); i++) {
- ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
+ AH5416(ah)->ah_ratesArray[i] =
+ (int16_t)(txPowerIndexOffset +
+ AH5416(ah)->ah_ratesArray[i]);
/* -5 dBm offset for Merlin and later; this includes Kiwi */
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
- if (ratesArray[i] < 0)
- ratesArray[i] = 0;
+ AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
+ if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
+ AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
+ if (AH5416(ah)->ah_ratesArray[i] < 0)
+ AH5416(ah)->ah_ratesArray[i] = 0;
}
#ifdef AH_EEPROM_DUMP
- ar5416PrintPowerPerRate(ah, ratesArray);
+ ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
#endif
/*
@@ -410,18 +419,26 @@
* XXX handle overflow/too high power level?
*/
if (IEEE80211_IS_CHAN_HT40(chan)) {
- ratesArray[rateHt40_0] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_1] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_2] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_3] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_4] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_5] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_6] += ht40PowerIncForPdadc;
- ratesArray[rateHt40_7] += ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_0] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_1] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_2] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_3] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_4] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_5] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_6] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
+ AH5416(ah)->ah_ratesArray[rateHt40_7] +=
+ AH5416(ah)->ah_ht40PowerIncForPdadc;
}
/* Write the TX power rate registers */
- ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray);
+ ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
return AH_TRUE;
#undef POW_SM
@@ -476,7 +493,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 +518,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 +556,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 +573,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);
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Atheros Communications, Inc.
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287_reset.h 222301 2011-05-26 09:15:33Z adrian $
*/
#ifndef __AR9287_RESET_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287an.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287an.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287an.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Atheros Communications, Inc.
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287an.h 222301 2011-05-26 09:15:33Z adrian $
*/
#ifndef __AR9287AN_H__
Modified: trunk/sys/dev/ath/ath_hal/ar9002/ar9287phy.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9002/ar9287phy.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_hal/ar9002/ar9287phy.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2010 Atheros Communications, Inc.
*
@@ -13,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$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_hal/ar9002/ar9287phy.h 222301 2011-05-26 09:15:33Z adrian $
*/
#ifndef __AR9287PHY_H__
Added: trunk/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h (rev 0)
+++ trunk/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,60 @@
+/* $MidnightBSD$ */
+/*
+ * 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: stable/10/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__ */
Property changes on: trunk/sys/dev/ath/ath_hal/ar9003/ar9300_btcoex.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h
===================================================================
--- trunk/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h (rev 0)
+++ trunk/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,79 @@
+/* $MidnightBSD$ */
+/*
+ * Copyright (c) 2012, Qualcomm Atheros, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the following conditions are met:
+ * 1. The materials contained herein are unmodified and are used
+ * unmodified.
+ * 2. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following NO
+ * ''WARRANTY'' disclaimer below (''Disclaimer''), without
+ * modification.
+ * 3. Redistributions in binary form must reproduce at minimum a
+ * disclaimer similar to the Disclaimer below and any redistribution
+ * must be conditioned upon including a substantially similar
+ * Disclaimer requirement for further binary redistribution.
+ * 4. Neither the names of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote
+ * product derived from this software without specific prior written
+ * permission.
+ *
+ * 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: stable/10/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h 250166 2013-05-02 00:59:39Z adrian $
+ *
+ */
+#ifndef __AR9300_DEVID_H__
+#define __AR9300_DEVID_H__
+
+/*
+ * AR9380 HAL device IDs.
+ */
+
+/*
+ * MAC Version and Revision
+ */
+#define AR_SREV_VERSION_AR9380 0x1C0
+#define AR_SREV_VERSION_AR9580 0x1C0
+#define AR_SREV_VERSION_AR9460 0x280
+#define AR_SREV_VERSION_QCA9565 0x2c0
+
+#define AR_SREV_VERSION_AR9330 0x200
+#define AR_SREV_VERSION_AR9340 0x300
+#define AR_SREV_VERSION_QCA9550 0x400
+#define AR_SREV_VERSION_AR9485 0x240
+
+#define AR_SREV_REVISION_AR9380_10 0 /* AR9380 1.0 */
+#define AR_SREV_REVISION_AR9380_20 2 /* AR9380 2.0/2.1 */
+#define AR_SREV_REVISION_AR9380_22 3 /* AR9380 2.2 */
+#define AR_SREV_REVISION_AR9580_10 4 /* AR9580/Peacock 1.0 */
+
+#define AR_SREV_REVISION_AR9330_10 0 /* AR9330 1.0 */
+#define AR_SREV_REVISION_AR9330_11 1 /* AR9330 1.1 */
+#define AR_SREV_REVISION_AR9330_12 2 /* AR9330 1.2 */
+#define AR_SREV_REVISION_AR9330_11_MASK 0xf /* AR9330 1.1 revision mask */
+
+#define AR_SREV_REVISION_AR9485_10 0 /* AR9485 1.0 */
+#define AR_SREV_REVISION_AR9485_11 1 /* AR9485 1.1 */
+
+#define AR_SREV_REVISION_AR9340_10 0 /* AR9340 1.0 */
+#define AR_SREV_REVISION_AR9340_11 1 /* AR9340 1.1 */
+#define AR_SREV_REVISION_AR9340_12 2 /* AR9340 1.2 */
+#define AR_SREV_REVISION_AR9340_MASK 0xf /* AR9340 revision mask */
+
+#define AR_SREV_REVISION_AR9460_10 0 /* AR946x 1.0 */
+
+#endif /* __AR9300_DEVID_H__ */
Property changes on: trunk/sys/dev/ath/ath_hal/ar9003/ar9300_devid.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/ath_rate/amrr/amrr.c
===================================================================
--- trunk/sys/dev/ath/ath_rate/amrr/amrr.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/amrr/amrr.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004 INRIA
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -37,7 +38,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/ath_rate/amrr/amrr.c 238633 2012-07-20 01:36:02Z adrian $");
/*
* AMRR rate control. See:
@@ -45,6 +46,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"
@@ -122,19 +124,21 @@
*/
void
ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
- uint8_t rix0, uint8_t *rix, uint8_t *try)
+ uint8_t rix0, struct ath_rc_series *rc)
{
struct amrr_node *amn = ATH_NODE_AMRR(an);
-/* rix[0] = amn->amn_tx_rate0; */
- rix[1] = amn->amn_tx_rate1;
- rix[2] = amn->amn_tx_rate2;
- rix[3] = amn->amn_tx_rate3;
+ rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
- try[0] = amn->amn_tx_try0;
- try[1] = amn->amn_tx_try1;
- try[2] = amn->amn_tx_try2;
- try[3] = amn->amn_tx_try3;
+ rc[0].rix = amn->amn_tx_rate0;
+ rc[1].rix = amn->amn_tx_rate1;
+ rc[2].rix = amn->amn_tx_rate2;
+ rc[3].rix = amn->amn_tx_rate3;
+
+ rc[0].tries = amn->amn_tx_try0;
+ rc[1].tries = amn->amn_tx_try1;
+ rc[2].tries = amn->amn_tx_try2;
+ rc[3].tries = amn->amn_tx_try3;
}
@@ -153,10 +157,10 @@
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
- const struct ath_buf *bf)
+ const struct ath_rc_series *rc, const struct ath_tx_status *ts,
+ int frame_size, int nframes, int nbad)
{
struct amrr_node *amn = ATH_NODE_AMRR(an);
- const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
int sr = ts->ts_shortretry;
int lr = ts->ts_longretry;
int retry_count = sr + lr;
@@ -418,6 +422,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)
{
Modified: trunk/sys/dev/ath/ath_rate/amrr/amrr.h
===================================================================
--- trunk/sys/dev/ath/ath_rate/amrr/amrr.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/amrr/amrr.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004 INRIA
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -34,7 +35,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_rate/amrr/amrr.h 178354 2008-04-20 20:35:46Z sam $
*/
#ifndef _DEV_ATH_RATE_AMRR_H
Modified: trunk/sys/dev/ath/ath_rate/onoe/onoe.c
===================================================================
--- trunk/sys/dev/ath/ath_rate/onoe/onoe.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/onoe/onoe.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -28,11 +29,12 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/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"
@@ -130,19 +132,21 @@
*/
void
ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
- uint8_t rix0, uint8_t *rix, uint8_t *try)
+ uint8_t rix0, struct ath_rc_series *rc)
{
struct onoe_node *on = ATH_NODE_ONOE(an);
-/* rix[0] = on->on_tx_rate0; */
- rix[1] = on->on_tx_rate1;
- rix[2] = on->on_tx_rate2;
- rix[3] = on->on_tx_rate3;
+ rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
- try[0] = on->on_tx_try0;
- try[1] = 2;
- try[2] = 2;
- try[3] = 2;
+ rc[0].rix = on->on_tx_rate0;
+ rc[1].rix = on->on_tx_rate1;
+ rc[2].rix = on->on_tx_rate2;
+ rc[3].rix = on->on_tx_rate3;
+
+ rc[0].tries = on->on_tx_try0;
+ rc[1].tries = 2;
+ rc[2].tries = 2;
+ rc[3].tries = 2;
}
void
@@ -160,10 +164,10 @@
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
- const struct ath_buf *bf)
+ const struct ath_rc_series *rc, const struct ath_tx_status *ts,
+ int frame_size, int nframes, int nbad)
{
struct onoe_node *on = ATH_NODE_ONOE(an);
- const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
if (ts->ts_status == 0)
on->on_tx_ok++;
@@ -404,6 +408,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)
{
Modified: trunk/sys/dev/ath/ath_rate/onoe/onoe.h
===================================================================
--- trunk/sys/dev/ath/ath_rate/onoe/onoe.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/onoe/onoe.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_rate/onoe/onoe.h 178354 2008-04-20 20:35:46Z sam $
*/
/*
Modified: trunk/sys/dev/ath/ath_rate/sample/sample.c
===================================================================
--- trunk/sys/dev/ath/ath_rate/sample/sample.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/sample/sample.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005 John Bicket
* All rights reserved.
@@ -36,13 +37,15 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/ath_rate/sample/sample.c 247372 2013-02-27 04:33:06Z adrian $");
/*
* John Bicket's SampleRate control algorithm.
*/
+#include "opt_ath.h"
#include "opt_inet.h"
#include "opt_wlan.h"
+#include "opt_ah.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -103,8 +106,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)
{
@@ -126,12 +127,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)
{
@@ -146,6 +141,8 @@
static int
dot11rate(const HAL_RATE_TABLE *rt, int rix)
{
+ if (rix < 0)
+ return -1;
return rt->info[rix].phy == IEEE80211_T_HT ?
rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2;
}
@@ -153,6 +150,8 @@
static const char *
dot11rate_label(const HAL_RATE_TABLE *rt, int rix)
{
+ if (rix < 0)
+ return "";
return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb ";
}
@@ -165,12 +164,13 @@
int size_bin, int require_acked_before)
{
struct sample_node *sn = ATH_NODE_SAMPLE(an);
- int best_rate_rix, best_rate_tt;
- uint32_t mask;
- int rix, tt;
+ int best_rate_rix, best_rate_tt, best_rate_pct;
+ uint64_t mask;
+ int rix, tt, pct;
best_rate_rix = 0;
best_rate_tt = 0;
+ best_rate_pct = 0;
for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
if ((mask & 1) == 0) /* not a supported rate */
continue;
@@ -187,14 +187,55 @@
!sn->stats[size_bin][rix].packets_acked))
continue;
+ /* Calculate percentage if possible */
+ if (sn->stats[size_bin][rix].total_packets > 0) {
+ pct = sn->stats[size_bin][rix].ewma_pct;
+ } else {
+ /* XXX for now, assume 95% ok */
+ pct = 95;
+ }
+
/* don't use a bit-rate that has been failing */
if (sn->stats[size_bin][rix].successive_failures > 3)
continue;
- if (best_rate_tt == 0 || tt < best_rate_tt) {
- best_rate_tt = tt;
- best_rate_rix = rix;
+ /*
+ * For HT, Don't use a bit rate that is much more
+ * lossy than the best.
+ *
+ * XXX this isn't optimal; it's just designed to
+ * eliminate rates that are going to be obviously
+ * worse.
+ */
+ if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
+ if (best_rate_pct > (pct + 50))
+ continue;
}
+
+ /*
+ * For non-MCS rates, use the current average txtime for
+ * comparison.
+ */
+ if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
+ if (best_rate_tt == 0 || tt <= best_rate_tt) {
+ best_rate_tt = tt;
+ best_rate_rix = rix;
+ best_rate_pct = pct;
+ }
+ }
+
+ /*
+ * Since 2 stream rates have slightly higher TX times,
+ * allow a little bit of leeway. This should later
+ * be abstracted out and properly handled.
+ */
+ if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
+ if (best_rate_tt == 0 || (tt * 8 <= best_rate_tt * 10)) {
+ best_rate_tt = tt;
+ best_rate_rix = rix;
+ best_rate_pct = pct;
+ }
+ }
}
return (best_rate_tt ? best_rate_rix : -1);
}
@@ -211,7 +252,7 @@
struct sample_node *sn = ATH_NODE_SAMPLE(an);
int current_rix, rix;
unsigned current_tt;
- uint32_t mask;
+ uint64_t mask;
current_rix = sn->current_rix[size_bin];
if (current_rix < 0) {
@@ -223,9 +264,9 @@
current_tt = sn->stats[size_bin][current_rix].average_tx_time;
rix = sn->last_sample_rix[size_bin]+1; /* next sample rate */
- mask = sn->ratemask &~ (1<<current_rix);/* don't sample current rate */
+ mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */
while (mask != 0) {
- if ((mask & (1<<rix)) == 0) { /* not a supported rate */
+ if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */
nextrate:
if (++rix >= rt->rateCount)
rix = 0;
@@ -232,16 +273,33 @@
continue;
}
+ /*
+ * The following code stops trying to sample
+ * non-MCS rates when speaking to an MCS node.
+ * However, at least for CCK rates in 2.4GHz mode,
+ * the non-MCS rates MAY actually provide better
+ * PER at the very far edge of reception.
+ *
+ * However! Until ath_rate_form_aggr() grows
+ * some logic to not form aggregates if the
+ * selected rate is non-MCS, this won't work.
+ *
+ * So don't disable this code until you've taught
+ * ath_rate_form_aggr() to drop out if any of
+ * the selected rates are non-MCS.
+ */
+#if 1
/* if the node is HT and the rate isn't HT, don't bother sample */
if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
(rt->info[rix].phy != IEEE80211_T_HT)) {
- mask &= ~(1<<rix);
+ mask &= ~((uint64_t) 1<<rix);
goto nextrate;
}
+#endif
/* this bit-rate is always worse than the current one */
if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) {
- mask &= ~(1<<rix);
+ mask &= ~((uint64_t) 1<<rix);
goto nextrate;
}
@@ -248,14 +306,26 @@
/* rarely sample bit-rates that fail a lot */
if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&
ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {
- mask &= ~(1<<rix);
+ mask &= ~((uint64_t) 1<<rix);
goto nextrate;
}
+ /*
+ * For HT, only sample a few rates on either side of the
+ * current rix; there's quite likely a lot of them.
+ */
+ if (an->an_node.ni_flags & IEEE80211_NODE_HT) {
+ if (rix < (current_rix - 3) ||
+ rix > (current_rix + 3)) {
+ mask &= ~((uint64_t) 1<<rix);
+ goto nextrate;
+ }
+ }
+
/* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */
if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {
- mask &= ~(1<<rix);
+ mask &= ~((uint64_t) 1<<rix);
goto nextrate;
}
}
@@ -315,8 +385,98 @@
}
}
+/*
+ * Pick a non-HT rate to begin using.
+ */
+static int
+ath_rate_pick_seed_rate_legacy(struct ath_softc *sc, struct ath_node *an,
+ int frameLen)
+{
+#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
+#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
+#define RATE(ix) (DOT11RATE(ix) / 2)
+ int rix = -1;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const int size_bin = size_to_bin(frameLen);
+ /* no packet has been sent successfully yet */
+ for (rix = rt->rateCount-1; rix > 0; rix--) {
+ if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
+ continue;
+ /* Skip HT rates */
+ if (rt->info[rix].phy == IEEE80211_T_HT)
+ continue;
+
+ /*
+ * Pick the highest rate <= 36 Mbps
+ * that hasn't failed.
+ */
+ if (DOT11RATE(rix) <= 72 &&
+ sn->stats[size_bin][rix].successive_failures == 0) {
+ break;
+ }
+ }
+ return rix;
+#undef RATE
+#undef MCS
+#undef DOT11RATE
+}
+
+/*
+ * Pick a HT rate to begin using.
+ *
+ * Don't use any non-HT rates; only consider HT rates.
+ */
+static int
+ath_rate_pick_seed_rate_ht(struct ath_softc *sc, struct ath_node *an,
+ int frameLen)
+{
+#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
+#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
+#define RATE(ix) (DOT11RATE(ix) / 2)
+ int rix = -1, ht_rix = -1;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const int size_bin = size_to_bin(frameLen);
+
+ /* no packet has been sent successfully yet */
+ for (rix = rt->rateCount-1; rix > 0; rix--) {
+ /* Skip rates we can't use */
+ if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
+ continue;
+
+ /* Keep a copy of the last seen HT rate index */
+ if (rt->info[rix].phy == IEEE80211_T_HT)
+ ht_rix = rix;
+
+ /* Skip non-HT rates */
+ if (rt->info[rix].phy != IEEE80211_T_HT)
+ continue;
+
+ /*
+ * Pick a medium-speed rate regardless of stream count
+ * which has not seen any failures. Higher rates may fail;
+ * we'll try them later.
+ */
+ if (((MCS(rix) & 0x7) <= 4) &&
+ sn->stats[size_bin][rix].successive_failures == 0) {
+ break;
+ }
+ }
+
+ /*
+ * If all the MCS rates have successive failures, rix should be
+ * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.)
+ */
+ return MAX(rix, ht_rix);
+#undef RATE
+#undef MCS
+#undef DOT11RATE
+}
+
+
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
int shortPreamble, size_t frameLen,
@@ -336,6 +496,14 @@
ath_rate_update_static_rix(sc, &an->an_node);
+ if (sn->currates != sc->sc_currates) {
+ device_printf(sc->sc_dev, "%s: currates != sc_currates!\n",
+ __func__);
+ rix = 0;
+ *try0 = ATH_TXMAXTRY;
+ goto done;
+ }
+
if (sn->static_rix != -1) {
rix = sn->static_rix;
*try0 = ATH_TXMAXTRY;
@@ -342,8 +510,10 @@
goto done;
}
- /* XXX TODO: this doesn't know about 11gn vs 11g protection; teach it */
- mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
+ mrr = sc->sc_mrretry;
+ /* XXX check HT protmode too */
+ if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
+ mrr = 0;
best_rix = pick_best_rate(an, rt, size_bin, !mrr);
if (best_rix >= 0) {
@@ -358,9 +528,14 @@
if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
rix = pick_sample_rate(ssc, an, rt, size_bin);
IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
- &an->an_node, "size %u sample rate %d current rate %d",
- bin_to_size(size_bin), RATE(rix),
- RATE(sn->current_rix[size_bin]));
+ &an->an_node, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s",
+ average_tx_time,
+ sn->sample_tt[size_bin],
+ bin_to_size(size_bin),
+ dot11rate(rt, rix),
+ dot11rate_label(rt, rix),
+ dot11rate(rt, sn->current_rix[size_bin]),
+ dot11rate_label(rt, sn->current_rix[size_bin]));
if (rix != sn->current_rix[size_bin]) {
sn->current_sample_rix[size_bin] = rix;
} else {
@@ -371,29 +546,58 @@
change_rates = 0;
if (!sn->packets_sent[size_bin] || best_rix == -1) {
/* no packet has been sent successfully yet */
- for (rix = rt->rateCount-1; rix > 0; rix--) {
- if ((sn->ratemask & (1<<rix)) == 0)
- continue;
- /*
- * Pick the highest rate <= 36 Mbps
- * that hasn't failed.
- */
- if (DOT11RATE(rix) <= 72 &&
- sn->stats[size_bin][rix].successive_failures == 0) {
- break;
- }
- }
change_rates = 1;
- best_rix = rix;
+ if (an->an_node.ni_flags & IEEE80211_NODE_HT)
+ best_rix =
+ ath_rate_pick_seed_rate_ht(sc, an, frameLen);
+ else
+ best_rix =
+ ath_rate_pick_seed_rate_legacy(sc, an, frameLen);
} else if (sn->packets_sent[size_bin] < 20) {
/* let the bit-rate switch quickly during the first few packets */
+ IEEE80211_NOTE(an->an_node.ni_vap,
+ IEEE80211_MSG_RATECTL, &an->an_node,
+ "%s: switching quickly..", __func__);
change_rates = 1;
} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
/* min_switch seconds have gone by */
+ IEEE80211_NOTE(an->an_node.ni_vap,
+ IEEE80211_MSG_RATECTL, &an->an_node,
+ "%s: min_switch %d > ticks_since_switch %d..",
+ __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);
change_rates = 1;
- } else if (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time) {
+ } else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&
+ (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {
/* the current bit-rate is twice as slow as the best one */
+ IEEE80211_NOTE(an->an_node.ni_vap,
+ IEEE80211_MSG_RATECTL, &an->an_node,
+ "%s: 2x att (= %d) < cur_rix att %d",
+ __func__,
+ 2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);
change_rates = 1;
+ } else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {
+ int cur_rix = sn->current_rix[size_bin];
+ int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;
+ /*
+ * If the node is HT, upgrade it if the MCS rate is
+ * higher and the average tx time is within 20% of
+ * the current rate. It can fail a little.
+ *
+ * This is likely not optimal!
+ */
+#if 0
+ printf("cur rix/att %x/%d, best rix/att %x/%d\n",
+ MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
+#endif
+ if ((MCS(best_rix) > MCS(cur_rix)) &&
+ (average_tx_time * 8) <= (cur_att * 10)) {
+ IEEE80211_NOTE(an->an_node.ni_vap,
+ IEEE80211_MSG_RATECTL, &an->an_node,
+ "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d",
+ __func__,
+ MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att);
+ change_rates = 1;
+ }
}
sn->packets_since_sample[size_bin]++;
@@ -428,6 +632,20 @@
}
*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
done:
+
+ /*
+ * This bug totally sucks and should be fixed.
+ *
+ * For now though, let's not panic, so we can start to figure
+ * out how to better reproduce it.
+ */
+ if (rix < 0 || rix >= rt->rateCount) {
+ printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",
+ __func__,
+ rix,
+ rt->rateCount);
+ rix = 0; /* XXX just default for now */
+ }
KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));
*rix0 = rix;
@@ -445,22 +663,25 @@
*/
void
ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
- uint8_t rix0, uint8_t *rix, uint8_t *try)
+ uint8_t rix0, struct ath_rc_series *rc)
{
struct sample_node *sn = ATH_NODE_SAMPLE(an);
const struct txschedule *sched = &sn->sched[rix0];
- KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", rix0, sched->r0));
+ KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
+ rix0, sched->r0));
-/* rix[0] = sched->r0; */
- rix[1] = sched->r1;
- rix[2] = sched->r2;
- rix[3] = sched->r3;
+ rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
- try[0] = sched->t0;
- try[1] = sched->t1;
- try[2] = sched->t2;
- try[3] = sched->t3;
+ rc[0].rix = sched->r0;
+ rc[1].rix = sched->r1;
+ rc[2].rix = sched->r2;
+ rc[3].rix = sched->r3;
+
+ rc[0].tries = sched->t0;
+ rc[1].tries = sched->t1;
+ rc[2].tries = sched->t2;
+ rc[3].tries = sched->t3;
}
void
@@ -495,14 +716,19 @@
int rix1, int tries1,
int rix2, int tries2,
int rix3, int tries3,
- int short_tries, int tries, int status)
+ int short_tries, int tries, int status,
+ int nframes, int nbad)
{
struct sample_node *sn = ATH_NODE_SAMPLE(an);
struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
+#ifdef IEEE80211_DEBUG
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+#endif
const int size_bin = size_to_bin(frame_size);
const int size = bin_to_size(size_bin);
int tt, tries_so_far;
int is_ht40 = (an->an_node.ni_chw == 40);
+ int pct;
if (!IS_RATE_DEFINED(sn, rix0))
return;
@@ -537,7 +763,7 @@
/* just average the first few packets */
int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
int packets = sn->stats[size_bin][rix0].total_packets;
- sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
+ sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);
} else {
/* use a ewma */
sn->stats[size_bin][rix0].average_tx_time =
@@ -545,9 +771,17 @@
(tt * (100 - ssc->smoothing_rate))) / 100;
}
- if (status != 0) {
+ /*
+ * XXX Don't mark the higher bit rates as also having failed; as this
+ * unfortunately stops those rates from being tasted when trying to
+ * TX. This happens with 11n aggregation.
+ */
+ if (nframes == nbad) {
+#if 0
int y;
- sn->stats[size_bin][rix0].successive_failures++;
+#endif
+ sn->stats[size_bin][rix0].successive_failures += nbad;
+#if 0
for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
/*
* Also say larger packets failed since we
@@ -554,29 +788,54 @@
* assume if a small packet fails at a
* bit-rate then a larger one will also.
*/
- sn->stats[y][rix0].successive_failures++;
+ sn->stats[y][rix0].successive_failures += nbad;
sn->stats[y][rix0].last_tx = ticks;
sn->stats[y][rix0].tries += tries;
- sn->stats[y][rix0].total_packets++;
+ sn->stats[y][rix0].total_packets += nframes;
}
+#endif
} else {
- sn->stats[size_bin][rix0].packets_acked++;
+ sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);
sn->stats[size_bin][rix0].successive_failures = 0;
}
sn->stats[size_bin][rix0].tries += tries;
sn->stats[size_bin][rix0].last_tx = ticks;
- sn->stats[size_bin][rix0].total_packets++;
+ sn->stats[size_bin][rix0].total_packets += nframes;
+ /* update EWMA for this rix */
+
+ /* Calculate percentage based on current rate */
+ if (nframes == 0)
+ nframes = nbad = 1;
+ pct = ((nframes - nbad) * 1000) / nframes;
+
+ if (sn->stats[size_bin][rix0].total_packets <
+ ssc->smoothing_minpackets) {
+ /* just average the first few packets */
+ int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) /
+ (sn->stats[size_bin][rix0].total_packets);
+ sn->stats[size_bin][rix0].ewma_pct = a_pct;
+ } else {
+ /* use a ewma */
+ sn->stats[size_bin][rix0].ewma_pct =
+ ((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) +
+ (pct * (100 - ssc->smoothing_rate))) / 100;
+ }
+
+
if (rix0 == sn->current_sample_rix[size_bin]) {
IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
&an->an_node,
-"%s: size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)",
+"%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d",
__func__,
size,
status ? "FAIL" : "OK",
- rix0, short_tries, tries, tt,
+ dot11rate(rt, rix0),
+ dot11rate_label(rt, rix0),
+ short_tries, tries, tt,
sn->stats[size_bin][rix0].average_tx_time,
- sn->stats[size_bin][rix0].perfect_tx_time);
+ sn->stats[size_bin][rix0].perfect_tx_time,
+ nframes, nbad);
sn->sample_tt[size_bin] = tt;
sn->current_sample_rix[size_bin] = -1;
}
@@ -591,21 +850,26 @@
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
- const struct ath_buf *bf)
+ const struct ath_rc_series *rc, const struct ath_tx_status *ts,
+ int frame_size, int nframes, int nbad)
{
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
struct sample_node *sn = ATH_NODE_SAMPLE(an);
- const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
- const struct ath_desc *ds0 = &bf->bf_desc[0];
- int final_rix, short_tries, long_tries, frame_size;
+ int final_rix, short_tries, long_tries;
const HAL_RATE_TABLE *rt = sc->sc_currates;
+ int status = ts->ts_status;
int mrr;
final_rix = rt->rateCodeToIndex[ts->ts_rate];
short_tries = ts->ts_shortretry;
long_tries = ts->ts_longretry + 1;
- frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
+
+ if (nframes == 0) {
+ device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__);
+ return;
+ }
+
if (frame_size == 0) /* NB: should not happen */
frame_size = 1500;
@@ -615,14 +879,20 @@
"%s: size %d %s rate/try %d/%d no rates yet",
__func__,
bin_to_size(size_to_bin(frame_size)),
- ts->ts_status ? "FAIL" : "OK",
+ status ? "FAIL" : "OK",
short_tries, long_tries);
return;
}
- mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
+ mrr = sc->sc_mrretry;
+ /* XXX check HT protmode too */
+ if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
+ mrr = 0;
+
if (!mrr || ts->ts_finaltsi == 0) {
if (!IS_RATE_DEFINED(sn, final_rix)) {
- badrate(ifp, 0, ts->ts_rate, long_tries, ts->ts_status);
+ device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n",
+ __func__, ts->ts_rate, ts->ts_finaltsi);
+ badrate(ifp, 0, ts->ts_rate, long_tries, status);
return;
}
/*
@@ -629,20 +899,22 @@
* Only one rate was used; optimize work.
*/
IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
- &an->an_node, "%s: size %d (%d bytes) %s rate/try %d %s/%d/%d",
+ &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]",
__func__,
bin_to_size(size_to_bin(frame_size)),
frame_size,
- ts->ts_status ? "FAIL" : "OK",
- dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), short_tries, long_tries);
+ status ? "FAIL" : "OK",
+ dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),
+ short_tries, long_tries, nframes, nbad);
update_stats(sc, an, frame_size,
final_rix, long_tries,
0, 0,
0, 0,
0, 0,
- short_tries, long_tries, ts->ts_status);
+ short_tries, long_tries, status,
+ nframes, nbad);
+
} else {
- int hwrates[4], tries[4], rix[4];
int finalTSIdx = ts->ts_finaltsi;
int i;
@@ -649,29 +921,31 @@
/*
* Process intermediate rates that failed.
*/
- ath_hal_gettxcompletionrates(sc->sc_ah, ds0, hwrates, tries);
- for (i = 0; i < 4; i++) {
- rix[i] = rt->rateCodeToIndex[hwrates[i]];
- }
-
IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
&an->an_node,
-"%s: size %d (%d bytes) finaltsidx %d tries %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d]",
+"%s: size %d (%d bytes) finaltsidx %d short %d long %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d] nframes/nbad [%d/%d]",
__func__,
bin_to_size(size_to_bin(frame_size)),
frame_size,
finalTSIdx,
- long_tries,
- ts->ts_status ? "FAIL" : "OK",
- dot11rate(rt, rix[0]), dot11rate_label(rt, rix[0]), tries[0],
- dot11rate(rt, rix[1]), dot11rate_label(rt, rix[1]), tries[1],
- dot11rate(rt, rix[2]), dot11rate_label(rt, rix[2]), tries[2],
- dot11rate(rt, rix[3]), dot11rate_label(rt, rix[3]), tries[3]);
+ short_tries,
+ long_tries,
+ status ? "FAIL" : "OK",
+ dot11rate(rt, rc[0].rix),
+ dot11rate_label(rt, rc[0].rix), rc[0].tries,
+ dot11rate(rt, rc[1].rix),
+ dot11rate_label(rt, rc[1].rix), rc[1].tries,
+ dot11rate(rt, rc[2].rix),
+ dot11rate_label(rt, rc[2].rix), rc[2].tries,
+ dot11rate(rt, rc[3].rix),
+ dot11rate_label(rt, rc[3].rix), rc[3].tries,
+ nframes, nbad);
for (i = 0; i < 4; i++) {
- if (tries[i] && !IS_RATE_DEFINED(sn, rix[i]))
- badrate(ifp, 0, hwrates[i], tries[i], ts->ts_status);
+ if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))
+ badrate(ifp, 0, rc[i].ratecode, rc[i].tries,
+ status);
}
/*
@@ -681,47 +955,51 @@
* sample higher rates 1 try at a time doing so
* may unfairly penalize them.
*/
- if (tries[0]) {
- update_stats(sc, an, frame_size,
- rix[0], tries[0],
- rix[1], tries[1],
- rix[2], tries[2],
- rix[3], tries[3],
- short_tries, long_tries,
- long_tries > tries[0]);
- long_tries -= tries[0];
+ if (rc[0].tries) {
+ update_stats(sc, an, frame_size,
+ rc[0].rix, rc[0].tries,
+ rc[1].rix, rc[1].tries,
+ rc[2].rix, rc[2].tries,
+ rc[3].rix, rc[3].tries,
+ short_tries, long_tries,
+ long_tries > rc[0].tries,
+ nframes, nbad);
+ long_tries -= rc[0].tries;
}
- if (tries[1] && finalTSIdx > 0) {
- update_stats(sc, an, frame_size,
- rix[1], tries[1],
- rix[2], tries[2],
- rix[3], tries[3],
- 0, 0,
- short_tries, long_tries,
- ts->ts_status);
- long_tries -= tries[1];
+ if (rc[1].tries && finalTSIdx > 0) {
+ update_stats(sc, an, frame_size,
+ rc[1].rix, rc[1].tries,
+ rc[2].rix, rc[2].tries,
+ rc[3].rix, rc[3].tries,
+ 0, 0,
+ short_tries, long_tries,
+ status,
+ nframes, nbad);
+ long_tries -= rc[1].tries;
}
- if (tries[2] && finalTSIdx > 1) {
- update_stats(sc, an, frame_size,
- rix[2], tries[2],
- rix[3], tries[3],
+ if (rc[2].tries && finalTSIdx > 1) {
+ update_stats(sc, an, frame_size,
+ rc[2].rix, rc[2].tries,
+ rc[3].rix, rc[3].tries,
0, 0,
0, 0,
- short_tries, long_tries,
- ts->ts_status);
- long_tries -= tries[2];
+ short_tries, long_tries,
+ status,
+ nframes, nbad);
+ long_tries -= rc[2].tries;
}
- if (tries[3] && finalTSIdx > 2) {
- update_stats(sc, an, frame_size,
- rix[3], tries[3],
+ if (rc[3].tries && finalTSIdx > 2) {
+ update_stats(sc, an, frame_size,
+ rc[3].rix, rc[3].tries,
0, 0,
0, 0,
0, 0,
- short_tries, long_tries,
- ts->ts_status);
+ short_tries, long_tries,
+ status,
+ nframes, nbad);
}
}
}
@@ -766,6 +1044,7 @@
KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,
("curmode %u", sc->sc_curmode));
+
sn->sched = mrr_schedules[sc->sc_curmode];
KASSERT(sn->sched != NULL,
("no mrr schedule for mode %u", sc->sc_curmode));
@@ -773,6 +1052,8 @@
sn->static_rix = -1;
ath_rate_update_static_rix(sc, ni);
+ sn->currates = sc->sc_currates;
+
/*
* Construct a bitmask of usable rates. This has all
* negotiated rates minus those marked by the hal as
@@ -790,7 +1071,7 @@
continue;
KASSERT(rix < SAMPLE_MAXRATES,
("mcs %u has rix %d", MCS(x), rix));
- sn->ratemask |= 1<<rix;
+ sn->ratemask |= (uint64_t) 1<<rix;
}
}
@@ -804,11 +1085,11 @@
continue;
KASSERT(rix < SAMPLE_MAXRATES,
("rate %u has rix %d", RATE(x), rix));
- sn->ratemask |= 1<<rix;
+ sn->ratemask |= (uint64_t) 1<<rix;
}
#ifdef IEEE80211_DEBUG
if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {
- uint32_t mask;
+ uint64_t mask;
ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt",
ni->ni_macaddr, ":", __func__);
@@ -824,7 +1105,7 @@
#endif
for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
int size = bin_to_size(y);
- uint32_t mask;
+ uint64_t mask;
sn->packets_sent[y] = 0;
sn->current_sample_rix[y] = -1;
@@ -844,6 +1125,7 @@
sn->stats[y][rix].total_packets = 0;
sn->stats[y][rix].packets_acked = 0;
sn->stats[y][rix].last_tx = 0;
+ sn->stats[y][rix].ewma_pct = 0;
sn->stats[y][rix].perfect_tx_time =
calc_usecs_unicast_packet(sc, size, rix, 0, 0,
@@ -872,6 +1154,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)
{
@@ -878,12 +1247,14 @@
struct ath_softc *sc = arg;
const HAL_RATE_TABLE *rt = sc->sc_currates;
struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni));
- uint32_t mask;
+ uint64_t mask;
int rix, y;
- printf("\n[%s] refcnt %d static_rix %d ratemask 0x%x\n",
+ printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n",
ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
- sn->static_rix, sn->ratemask);
+ dot11rate(rt, sn->static_rix),
+ dot11rate_label(rt, sn->static_rix),
+ (uintmax_t)sn->ratemask);
for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n",
bin_to_size(y), sn->current_rix[y],
@@ -890,9 +1261,13 @@
dot11rate(rt, sn->current_rix[y]),
dot11rate_label(rt, sn->current_rix[y]),
sn->packets_since_switch[y], sn->ticks_since_switch[y]);
- printf("[%4u] last sample %d cur sample %d packets sent %d\n",
- bin_to_size(y), sn->last_sample_rix[y],
- sn->current_sample_rix[y], sn->packets_sent[y]);
+ printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n",
+ bin_to_size(y),
+ dot11rate(rt, sn->last_sample_rix[y]),
+ dot11rate_label(rt, sn->last_sample_rix[y]),
+ dot11rate(rt, sn->current_sample_rix[y]),
+ dot11rate_label(rt, sn->current_sample_rix[y]),
+ sn->packets_sent[y]);
printf("[%4u] packets since sample %d sample tt %u\n",
bin_to_size(y), sn->packets_since_sample[y],
sn->sample_tt[y]);
@@ -903,13 +1278,16 @@
for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
if (sn->stats[y][rix].total_packets == 0)
continue;
- printf("[%2u %s:%4u] %8d:%-8d (%3d%%) T %8d F %4d avg %5u last %u\n",
+ printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n",
dot11rate(rt, rix), dot11rate_label(rt, rix),
bin_to_size(y),
- sn->stats[y][rix].total_packets,
- sn->stats[y][rix].packets_acked,
- (100*sn->stats[y][rix].packets_acked)/sn->stats[y][rix].total_packets,
- sn->stats[y][rix].tries,
+ (uintmax_t) sn->stats[y][rix].total_packets,
+ (uintmax_t) sn->stats[y][rix].packets_acked,
+ (int) ((sn->stats[y][rix].packets_acked * 100ULL) /
+ sn->stats[y][rix].total_packets),
+ sn->stats[y][rix].ewma_pct / 10,
+ sn->stats[y][rix].ewma_pct % 10,
+ (uintmax_t) sn->stats[y][rix].tries,
sn->stats[y][rix].successive_failures,
sn->stats[y][rix].average_tx_time,
ticks - sn->stats[y][rix].last_tx);
@@ -995,7 +1373,7 @@
if (ssc == NULL)
return NULL;
ssc->arc.arc_space = sizeof(struct sample_node);
- ssc->smoothing_rate = 95; /* ewma percentage ([0..99]) */
+ ssc->smoothing_rate = 75; /* ewma percentage ([0..99]) */
ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate);
ssc->sample_rate = 10; /* %time to try diff tx rates */
ssc->max_successive_failures = 3; /* threshold for rate sampling*/
Modified: trunk/sys/dev/ath/ath_rate/sample/sample.h
===================================================================
--- trunk/sys/dev/ath/ath_rate/sample/sample.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/sample/sample.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005 John Bicket
* All rights reserved.
@@ -33,7 +34,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/ath_rate/sample/sample.h 239284 2012-08-15 07:10:10Z adrian $
*/
/*
@@ -51,6 +52,7 @@
int max_successive_failures;
int stale_failure_timeout; /* how long to honor max_successive_failures */
int min_switch; /* min time between rate changes */
+ int min_good_pct; /* min good percentage for a rate to be considered */
};
#define ATH_SOFTC_SAMPLE(sc) ((struct sample_softc *)sc->sc_rc)
@@ -57,9 +59,10 @@
struct rate_stats {
unsigned average_tx_time;
int successive_failures;
- int tries;
- int total_packets;
- int packets_acked;
+ uint64_t tries;
+ uint64_t total_packets; /* pkts total since assoc */
+ uint64_t packets_acked; /* pkts acked since assoc */
+ int ewma_pct; /* EWMA percentage */
unsigned perfect_tx_time; /* transmit time for 0 retries */
int last_tx;
};
@@ -77,13 +80,23 @@
*/
#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] */
- uint32_t ratemask; /* bit mask of valid rate indices */
+#define SAMPLE_MAXRATES 64 /* NB: corresponds to hal info[32] */
+ uint64_t ratemask; /* bit mask of valid rate indices */
const struct txschedule *sched; /* tx schedule table */
+ const HAL_RATE_TABLE *currates;
+
struct rate_stats stats[NUM_PACKET_SIZE_BINS][SAMPLE_MAXRATES];
int last_sample_rix[NUM_PACKET_SIZE_BINS];
@@ -97,6 +110,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)
@@ -221,4 +237,7 @@
}
return tt;
}
+
+#endif /* _KERNEL */
+
#endif /* _DEV_ATH_RATE_SAMPLE_H */
Modified: trunk/sys/dev/ath/ath_rate/sample/tx_schedules.h
===================================================================
--- trunk/sys/dev/ath/ath_rate/sample/tx_schedules.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/ath_rate/sample/tx_schedules.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005 John Bicket
* All rights reserved.
@@ -38,7 +39,7 @@
#define __ATH_RATE_SAMPLE_TXSCHEDULES_H__
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/ath_rate/sample/tx_schedules.h 239286 2012-08-15 07:50:42Z adrian $");
#define A(_r) \
(((_r) == 6) ? 0 : (((_r) == 9) ? 1 : (((_r) == 12) ? 2 : \
@@ -63,6 +64,10 @@
(((_r) == 13) ? 16 : (((_r) == 26) ? 17 : (((_r) == 39) ? 18 : \
(((_r) == 52) ? 19 : (((_r) == 78) ? 20 : (((_r) == 104)? 21 : \
(((_r) == 117)? 22 : (((_r) == 130)? 23 : 0))))))))
+#define NA3(_r) \
+ (((_r) == 19.5) ? 24 : (((_r) == 39) ? 25 : (((_r) == 58.5) ? 26 : \
+ (((_r) == 78) ? 27 : (((_r) == 117) ? 28 : (((_r) == 156) ? 29 : \
+ (((_r) == 175.5) ? 30 : (((_r) == 195)? 31 : 0))))))))
static const struct txschedule series_11na[] = {
{ 3,A( 6), 3,A( 6), 0,A( 6), 0,A( 6) }, /* 6Mb/s */
{ 4,A( 9), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 9Mb/s */
@@ -72,6 +77,9 @@
{ 4,A(36), 3,A( 24), 4,A( 18), 2,A( 6) }, /* 36Mb/s */
{ 4,A(48), 3,A( 36), 4,A( 24), 2,A(12) }, /* 48Mb/s */
{ 4,A(54), 3,A( 48), 4,A( 36), 2,A(24) }, /* 54Mb/s */
+
+ /* 1 stream rates */
+
{ 3,NA1( 6.5), 3,NA1( 6.5), 0,NA1( 6.5), 0,NA1(6.5) }, /* 6.5Mb/s */
{ 4,NA1( 13), 3,NA1( 6.5), 4,NA1( 6.5), 0,NA1(6.5) }, /* 13Mb/s */
{ 4,NA1(19.5), 3,NA1( 6.5), 4,NA1( 6.5), 0,NA1(6.5) }, /*19.5Mb/s */
@@ -80,6 +88,9 @@
{ 4,NA1( 52), 3,NA1( 39), 4,NA1( 26), 2,NA1(6.5) }, /* 52Mb/s */
{ 4,NA1(58.5), 3,NA1( 52), 4,NA1( 39), 2,NA1( 13) }, /*58.5Mb/s */
{ 4,NA1( 65), 3,NA1(58.5), 4,NA1( 52), 2,NA1( 13) }, /* 65Mb/s */
+
+ /* 2 stream rates */
+
{ 3,NA2( 13), 3,NA2( 13), 0,NA2( 13), 0,NA2( 13) }, /* 13Mb/s */
{ 4,NA2( 26), 3,NA2( 13), 4,NA2( 13), 0,NA2( 13) }, /* 26Mb/s */
{ 4,NA2( 39), 3,NA2( 26), 4,NA2( 13), 2,NA2( 13) }, /* 39Mb/s */
@@ -87,9 +98,21 @@
{ 4,NA2( 78), 3,NA2( 52), 4,NA2( 39), 2,NA2( 13) }, /* 78Mb/s */
{ 4,NA2( 104), 3,NA2( 78), 4,NA2( 52), 2,NA2( 13) }, /* 104Mb/s */
{ 4,NA2( 117), 3,NA2( 104), 4,NA2( 78), 2,NA2( 26) }, /* 117Mb/s */
- { 4,NA2( 130), 3,NA2( 117), 4,NA2( 104), 2,NA2( 26) } /* 130Mb/s */
+ { 4,NA2( 130), 3,NA2( 117), 4,NA2( 104), 2,NA2( 26) }, /* 130Mb/s */
+
+ /* 3 stream rates */
+
+ { 3,NA3(19.5), 3,NA3(19.5), 0,NA3(19.5), 0,NA3(19.5) }, /* 19Mb/s */
+ { 3,NA3( 39), 3,NA3(19.5), 0,NA3(19.5), 0,NA3(19.5) }, /* 39Mb/s */
+ { 3,NA3(58.5), 3,NA3( 39), 0,NA3(19.5), 0,NA3(19.5) }, /* 58Mb/s */
+ { 3,NA3( 78), 3,NA3(58.5), 0,NA3( 39), 0,NA3(19.5) }, /* 78Mb/s */
+ { 3,NA3( 117), 3,NA3( 78), 0,NA3(58.5), 0,NA3(19.5) }, /* 117Mb/s */
+ { 3,NA3( 156), 3,NA3( 117), 0,NA3( 78), 0,NA3(19.5) }, /* 156Mb/s */
+ { 3,NA3(175.5), 3,NA3( 156), 0,NA3( 117), 0,NA3( 39) }, /* 175Mb/s */
+ { 3,NA3( 195), 3,NA3( 195), 0,NA3( 156), 0,NA3(58.5) }, /* 195Mb/s */
};
#undef A
+#undef NA3
#undef NA2
#undef NA1
@@ -121,6 +144,11 @@
(((_r) == 13) ? 20 : (((_r) == 26) ? 21 : (((_r) == 39) ? 22 : \
(((_r) == 52) ? 23 : (((_r) == 78) ? 24 : (((_r) == 104) ? 25 : \
(((_r) == 117) ? 26 : (((_r) == 130)? 27 : 0))))))))
+#define NG3(_r) \
+ (((_r) == 19.5) ? 28 : (((_r) == 39) ? 29 : (((_r) == 58.5) ? 30 : \
+ (((_r) == 78) ? 31 : (((_r) == 117) ? 32 : (((_r) == 156) ? 33 : \
+ (((_r) == 175.5) ? 34 : (((_r) == 195)? 35 : 0))))))))
+
static const struct txschedule series_11ng[] = {
{ 3,G( 1), 3,G( 1), 0,G( 1), 0,G( 1) }, /* 1Mb/s */
{ 4,G( 2), 3,G( 1), 4,G( 1), 0,G( 1) }, /* 2Mb/s */
@@ -134,6 +162,9 @@
{ 4,G(36), 3,G( 24), 4,G( 18), 2,G( 1) }, /* 36Mb/s */
{ 4,G(48), 3,G( 36), 4,G( 24), 2,G( 1) }, /* 48Mb/s */
{ 4,G(54), 3,G( 48), 4,G( 36), 2,G( 1) }, /* 54Mb/s */
+
+ /* 1 stream rates */
+
{ 3,NG1( 6.5), 3,NG1( 6.5), 0,NG1( 6.5), 0,NG1(6.5) }, /* 6.5Mb/s */
{ 4,NG1( 13), 3,NG1( 6.5), 4,NG1( 6.5), 0,NG1(6.5) }, /* 13Mb/s */
{ 4,NG1(19.5), 3,NG1( 6.5), 4,NG1( 6.5), 0,NG1(6.5) }, /*19.5Mb/s */
@@ -142,6 +173,9 @@
{ 4,NG1( 52), 3,NG1( 39), 4,NG1( 26), 2,NG1(6.5) }, /* 52Mb/s */
{ 4,NG1(58.5), 3,NG1( 52), 4,NG1( 39), 2,NG1( 13) }, /*58.5Mb/s */
{ 4,NG1( 65), 3,NG1(58.5), 4,NG1( 52), 2,NG1( 13) }, /* 65Mb/s */
+
+ /* 2 stream rates */
+
{ 3,NG2( 13), 3,NG2( 13), 0,NG2( 13), 0,NG2( 13) }, /* 13Mb/s */
{ 4,NG2( 26), 3,NG2( 13), 4,NG2( 13), 0,NG2( 13) }, /* 26Mb/s */
{ 4,NG2( 39), 3,NG2( 26), 4,NG2( 13), 2,NG2( 13) }, /* 39Mb/s */
@@ -149,9 +183,22 @@
{ 4,NG2( 78), 3,NG2( 52), 4,NG2( 39), 2,NG2( 13) }, /* 78Mb/s */
{ 4,NG2( 104), 3,NG2( 78), 4,NG2( 52), 2,NG2( 13) }, /* 104Mb/s */
{ 4,NG2( 117), 3,NG2( 104), 4,NG2( 78), 2,NG2( 26) }, /* 117Mb/s */
- { 4,NG2( 130), 3,NG2( 117), 4,NG2( 104), 2,NG2( 26) } /* 130Mb/s */
+ { 4,NG2( 130), 3,NG2( 117), 4,NG2( 104), 2,NG2( 26) }, /* 130Mb/s */
+
+ /* 3 stream rates */
+
+ { 3,NG3(19.5), 3,NG3(19.5), 0,NG3(19.5), 0,NG3(19.5) }, /* 19Mb/s */
+ { 3,NG3( 39), 3,NG3(19.5), 0,NG3(19.5), 0,NG3(19.5) }, /* 39Mb/s */
+ { 3,NG3(58.5), 3,NG3( 39), 0,NG3(19.5), 0,NG3(19.5) }, /* 58Mb/s */
+ { 3,NG3( 78), 3,NG3(58.5), 0,NG3( 39), 0,NG3(19.5) }, /* 78Mb/s */
+ { 3,NG3( 117), 3,NG3( 78), 0,NG3(58.5), 0,NG3(19.5) }, /* 117Mb/s */
+ { 3,NG3( 156), 3,NG3( 117), 0,NG3( 78), 0,NG3(19.5) }, /* 156Mb/s */
+ { 3,NG3(175.5), 3,NG3( 156), 0,NG3( 117), 0,NG3( 39) }, /* 175Mb/s */
+ { 3,NG3( 195), 3,NG3( 195), 0,NG3( 156), 0,NG3(58.5) }, /* 195Mb/s */
+
};
#undef G
+#undef NG3
#undef NG2
#undef NG1
Modified: trunk/sys/dev/ath/if_ath.c
===================================================================
--- trunk/sys/dev/ath/if_ath.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -28,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath.c 332321 2018-04-09 12:55:09Z emaste $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -39,6 +40,14 @@
#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>
@@ -59,6 +68,8 @@
#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>
@@ -92,9 +103,18 @@
#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_ath_btcoex.h>
+#include <dev/ath/if_ath_spectral.h>
+#include <dev/ath/if_ath_lna_div.h>
#include <dev/ath/if_athdfs.h>
#ifdef ATH_TX99_DIAG
@@ -101,8 +121,16 @@
#include <dev/ath/ath_tx99/ath_tx99.h>
#endif
+#ifdef ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
/*
+ * Only enable this if you're working on PS-POLL support.
+ */
+#define ATH_SW_PSQ
+
+/*
* ATH_BCBUF determines the number of vap's that can transmit
* beacons and also (currently) the number of vap's that can
* have unique mac addresses/bssid. When staggering beacons
@@ -116,9 +144,7 @@
* the U/L bit and tracking addresses in a byte; it would be
* worthwhile to allow more for applications like proxy sta.
*/
-#ifdef CTASSERT
CTASSERT(ATH_BCBUF <= 8);
-#endif
static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
@@ -128,8 +154,9 @@
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_transmit(struct ifnet *ifp, struct mbuf *m);
+static void ath_qflush(struct ifnet *ifp);
static int ath_media_change(struct ifnet *);
static void ath_watchdog(void *);
static int ath_ioctl(struct ifnet *, u_long, caddr_t);
@@ -140,52 +167,36 @@
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_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 void ath_reset_proc(void *, int);
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 *,
const uint8_t [IEEE80211_ADDR_LEN]);
+static void ath_node_cleanup(struct ieee80211_node *);
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(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 int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq,
+ int dosched);
static void ath_tx_proc_q0(void *, int);
static void ath_tx_proc_q0123(void *, int);
static void ath_tx_proc(void *, int);
-static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *);
+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 *);
-static void ath_stoprecv(struct ath_softc *);
-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 *);
static void ath_set_channel(struct ieee80211com *);
+#ifdef ATH_ENABLE_11N
+static void ath_update_chw(struct ieee80211com *);
+#endif /* ATH_ENABLE_11N */
static void ath_calibrate(void *);
static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void ath_setup_stationkey(struct ieee80211_node *);
@@ -196,7 +207,6 @@
static void ath_getradiocaps(struct ieee80211com *, int, int *,
struct ieee80211_channel []);
static int ath_getchannels(struct ath_softc *);
-static void ath_led_event(struct ath_softc *, int);
static int ath_rate_setup(struct ath_softc *, u_int mode);
static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
@@ -204,33 +214,14 @@
static void ath_announce(struct ath_softc *);
static void ath_dfs_tasklet(void *, int);
+static void ath_node_powersave(struct ieee80211_node *, int);
+static int ath_node_set_tim(struct ieee80211_node *, int);
+static void ath_node_recv_pspoll(struct ieee80211_node *, struct mbuf *);
#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
-#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)
-#endif /* IEEE80211_SUPPORT_TDMA */
-
SYSCTL_DECL(_hw_ath);
/* XXX validate sysctl values */
@@ -247,21 +238,47 @@
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);
+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);
-static int ath_bstuck_threshold = 4; /* max missed beacons */
+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");
-static MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers");
+MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers");
+void
+ath_legacy_attach_comp_func(struct ath_softc *sc)
+{
+
+ /*
+ * Special case certain configurations. Note the
+ * CAB queue is handled by these specially so don't
+ * include them when checking the txq setup mask.
+ */
+ switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) {
+ case 0x01:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc);
+ break;
+ case 0x0f:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc);
+ break;
+ default:
+ TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc);
+ break;
+ }
+}
+
#define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20)
#define HAL_MODE_HT40 \
(HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \
@@ -276,13 +293,16 @@
int error = 0, i;
u_int wmodes;
uint8_t macaddr[IEEE80211_ADDR_LEN];
+ int rx_chainmask, tx_chainmask;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
+ CURVNET_SET(vnet0);
ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
if (ifp == NULL) {
device_printf(sc->sc_dev, "can not if_alloc()\n");
error = ENOSPC;
+ CURVNET_RESTORE();
goto bad;
}
ic = ifp->if_l2com;
@@ -290,8 +310,10 @@
/* set these up early for if_printf use */
if_initname(ifp, device_get_name(sc->sc_dev),
device_get_unit(sc->sc_dev));
+ CURVNET_RESTORE();
- ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, sc->sc_eepromdata, &status);
+ ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh,
+ sc->sc_eepromdata, &status);
if (ah == NULL) {
if_printf(ifp, "unable to attach hardware; HAL status %u\n",
status);
@@ -305,6 +327,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
@@ -362,13 +399,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);
@@ -379,9 +434,12 @@
taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
"%s taskq", ifp->if_xname);
- TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, 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);
+ TASK_INIT(&sc->sc_txqtask, 0, ath_txq_sched_tasklet, sc);
+ TASK_INIT(&sc->sc_fataltask, 0, ath_fatal_proc, sc);
/*
* Allocate hardware transmit queues: one queue for
@@ -391,7 +449,7 @@
*
* XXX PS-Poll
*/
- sc->sc_bhalq = ath_beaconq_setup(ah);
+ sc->sc_bhalq = ath_beaconq_setup(sc);
if (sc->sc_bhalq == (u_int) -1) {
if_printf(ifp, "unable to setup a beacon xmit queue!\n");
error = EIO;
@@ -430,21 +488,12 @@
}
/*
- * Special case certain configurations. Note the
- * CAB queue is handled by these specially so don't
- * include them when checking the txq setup mask.
+ * Attach the TX completion function.
+ *
+ * The non-EDMA chips may have some special case optimisations;
+ * this method gives everyone a chance to attach cleanly.
*/
- switch (sc->sc_txqsetup &~ (1<<sc->sc_cabq->axq_qnum)) {
- case 0x01:
- TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0, sc);
- break;
- case 0x0f:
- TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc_q0123, sc);
- break;
- default:
- TASK_INIT(&sc->sc_txtask, 0, ath_tx_proc, sc);
- break;
- }
+ sc->sc_tx.xmit_attach_comp_func(sc);
/*
* Setup rate control. Some rate control modules
@@ -461,34 +510,73 @@
/* Attach DFS module */
if (! ath_dfs_attach(sc)) {
- device_printf(sc->sc_dev, "%s: unable to attach DFS\n", __func__);
+ device_printf(sc->sc_dev,
+ "%s: unable to attach DFS\n", __func__);
error = EIO;
goto bad2;
}
+ /* Attach spectral module */
+ if (ath_spectral_attach(sc) < 0) {
+ device_printf(sc->sc_dev,
+ "%s: unable to attach spectral\n", __func__);
+ error = EIO;
+ goto bad2;
+ }
+
+ /* Attach bluetooth coexistence module */
+ if (ath_btcoex_attach(sc) < 0) {
+ device_printf(sc->sc_dev,
+ "%s: unable to attach bluetooth coexistence\n", __func__);
+ error = EIO;
+ goto bad2;
+ }
+
+ /* Attach LNA diversity module */
+ if (ath_lna_div_attach(sc) < 0) {
+ device_printf(sc->sc_dev,
+ "%s: unable to attach LNA diversity\n", __func__);
+ error = EIO;
+ goto bad2;
+ }
+
/* Start DFS processing tasklet */
TASK_INIT(&sc->sc_dfstask, 0, ath_dfs_tasklet, sc);
+ /* Configure LED state */
sc->sc_blinking = 0;
sc->sc_ledstate = 1;
sc->sc_ledon = 0; /* low true */
sc->sc_ledidle = (2700*hz)/1000; /* 2.7sec */
- callout_init(&sc->sc_ledtimer, CALLOUT_MPSAFE);
+ callout_init(&sc->sc_ledtimer, 1);
+
/*
+ * Don't setup hardware-based blinking.
+ *
+ * Although some NICs may have this configured in the
+ * default reset register values, the user may wish
+ * to alter which pins have which function.
+ *
+ * The reference driver attaches the MAC network LED to GPIO1 and
+ * the MAC power LED to GPIO2. However, the DWA-552 cardbus
+ * NIC has these reversed.
+ */
+ sc->sc_hardled = (1 == 0);
+ sc->sc_led_net_pin = -1;
+ sc->sc_led_pwr_pin = -1;
+ /*
* Auto-enable soft led processing for IBM cards and for
* 5211 minipci cards. Users can also manually enable/disable
* support with a sysctl.
*/
sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID);
- if (sc->sc_softled) {
- ath_hal_gpioCfgOutput(ah, sc->sc_ledpin,
- HAL_GPIO_MUX_MAC_NETWORK_LED);
- ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon);
- }
+ ath_led_config(sc);
+ ath_hal_setledstate(ah, HAL_LED_INIT);
ifp->if_softc = sc;
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
- ifp->if_start = ath_start;
+ ifp->if_transmit = ath_transmit;
+ ifp->if_qflush = ath_qflush;
ifp->if_ioctl = ath_ioctl;
ifp->if_init = ath_init;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
@@ -510,10 +598,12 @@
| 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 DFS radar detection */
+ | IEEE80211_C_DFS /* Enable radar detection */
#endif
;
/*
@@ -598,6 +688,10 @@
sc->sc_hastsfadd = ath_hal_hastsfadjust(ah);
sc->sc_rxslink = ath_hal_self_linked_final_rxdesc(ah);
sc->sc_rxtsf32 = ath_hal_has_long_rxdesc_tsf(ah);
+ sc->sc_hasenforcetxop = ath_hal_hasenforcetxop(ah);
+ sc->sc_rx_lnamixer = ath_hal_hasrxlnamixer(ah);
+ sc->sc_hasdivcomb = ath_hal_hasdivantcomb(ah);
+
if (ath_hal_hasfastframes(ah))
ic->ic_caps |= IEEE80211_C_FF;
wmodes = ath_hal_getwirelessmodes(ah);
@@ -611,11 +705,77 @@
#endif
/*
- * 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.
+ * TODO: enforce that at least this many frames are available
+ * in the txbuf list before allowing data frames (raw or
+ * otherwise) to be transmitted.
*/
+ sc->sc_txq_data_minfree = 10;
+ /*
+ * Leave this as default to maintain legacy behaviour.
+ * Shortening the cabq/mcastq may end up causing some
+ * undesirable behaviour.
+ */
+ sc->sc_txq_mcastq_maxdepth = ath_txbuf;
+ /*
+ * How deep can the node software TX queue get whilst it's asleep.
+ */
+ sc->sc_txq_node_psq_maxdepth = 16;
+
+ /*
+ * Default the maximum queue depth for a given node
+ * to 1/4'th the TX buffers, or 64, whichever
+ * is larger.
+ */
+ sc->sc_txq_node_maxdepth = MAX(64, ath_txbuf / 4);
+
+ /* Enable CABQ by default */
+ sc->sc_cabq_enable = 1;
+
+ /*
+ * Allow the TX and RX chainmasks to be overridden by
+ * environment variables and/or device.hints.
+ *
+ * This must be done early - before the hardware is
+ * calibrated or before the 802.11n stream calculation
+ * is done.
+ */
+ if (resource_int_value(device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev), "rx_chainmask",
+ &rx_chainmask) == 0) {
+ device_printf(sc->sc_dev, "Setting RX chainmask to 0x%x\n",
+ rx_chainmask);
+ (void) ath_hal_setrxchainmask(sc->sc_ah, rx_chainmask);
+ }
+ if (resource_int_value(device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev), "tx_chainmask",
+ &tx_chainmask) == 0) {
+ device_printf(sc->sc_dev, "Setting TX chainmask to 0x%x\n",
+ tx_chainmask);
+ (void) ath_hal_settxchainmask(sc->sc_ah, tx_chainmask);
+ }
+
+ /*
+ * Query the TX/RX chainmask configuration.
+ *
+ * This is only relevant for 11n devices.
+ */
+ ath_hal_getrxchainmask(ah, &sc->sc_rxchainmask);
+ ath_hal_gettxchainmask(ah, &sc->sc_txchainmask);
+
+ /*
+ * Disable MRR with protected frames by default.
+ * Only 802.11n series NICs can handle this.
+ */
+ sc->sc_mrrprot = 0; /* XXX should be a capability */
+
+ /*
+ * Query the enterprise mode information the HAL.
+ */
+ if (ath_hal_getcapability(ah, HAL_CAP_ENTERPRISE_MODE, 0,
+ &sc->sc_ent_cfg) == HAL_OK)
+ sc->sc_use_ent = 1;
+
#ifdef ATH_ENABLE_11N
/*
* Query HT capabilities
@@ -622,14 +782,18 @@
*/
if (ath_hal_getcapability(ah, HAL_CAP_HT, 0, NULL) == HAL_OK &&
(wmodes & (HAL_MODE_HT20 | HAL_MODE_HT40))) {
- int rxs, txs;
+ uint32_t rxs, txs;
device_printf(sc->sc_dev, "[HT] enabling HT modes\n");
- ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */
- | IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */
- | IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */
- | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */
- | IEEE80211_HTCAP_SMPS_OFF; /* SM power save off */
+
+ sc->sc_mrrprot = 1; /* XXX should be a capability */
+
+ ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */
+ | IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */
+ | IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */
+ | IEEE80211_HTCAP_MAXAMSDU_3839
+ /* max A-MSDU length */
+ | IEEE80211_HTCAP_SMPS_OFF; /* SM power save off */
;
/*
@@ -650,24 +814,78 @@
| IEEE80211_HTCAP_SHORTGI40;
/*
- * rx/tx stream is not currently used anywhere; it needs to be taken
- * into account when negotiating which MCS rates it'll receive and
+ * TX/RX streams need to be taken into account when
+ * negotiating which MCS rates it'll receive and
* what MCS rates are available for TX.
*/
- (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 0, &rxs);
- (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 1, &txs);
-
- ath_hal_getrxchainmask(ah, &sc->sc_rxchainmask);
- ath_hal_gettxchainmask(ah, &sc->sc_txchainmask);
-
+ (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 0, &txs);
+ (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 1, &rxs);
ic->ic_txstream = txs;
ic->ic_rxstream = rxs;
- device_printf(sc->sc_dev, "[HT] %d RX streams; %d TX streams\n", rxs, txs);
+ /*
+ * Setup TX and RX STBC based on what the HAL allows and
+ * the currently configured chainmask set.
+ * Ie - don't enable STBC TX if only one chain is enabled.
+ * STBC RX is fine on a single RX chain; it just won't
+ * provide any real benefit.
+ */
+ if (ath_hal_getcapability(ah, HAL_CAP_RX_STBC, 0,
+ NULL) == HAL_OK) {
+ sc->sc_rx_stbc = 1;
+ device_printf(sc->sc_dev,
+ "[HT] 1 stream STBC receive enabled\n");
+ ic->ic_htcaps |= IEEE80211_HTCAP_RXSTBC_1STREAM;
+ }
+ if (txs > 1 && ath_hal_getcapability(ah, HAL_CAP_TX_STBC, 0,
+ NULL) == HAL_OK) {
+ sc->sc_tx_stbc = 1;
+ device_printf(sc->sc_dev,
+ "[HT] 1 stream STBC transmit enabled\n");
+ ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC;
+ }
+
+ (void) ath_hal_getcapability(ah, HAL_CAP_RTS_AGGR_LIMIT, 1,
+ &sc->sc_rts_aggr_limit);
+ if (sc->sc_rts_aggr_limit != (64 * 1024))
+ device_printf(sc->sc_dev,
+ "[HT] RTS aggregates limited to %d KiB\n",
+ sc->sc_rts_aggr_limit / 1024);
+
+ device_printf(sc->sc_dev,
+ "[HT] %d RX streams; %d TX streams\n", rxs, txs);
}
#endif
/*
+ * Initial aggregation settings.
+ */
+ sc->sc_hwq_limit_aggr = ATH_AGGR_MIN_QDEPTH;
+ sc->sc_hwq_limit_nonaggr = ATH_NONAGGR_MIN_QDEPTH;
+ sc->sc_tid_hwq_lo = ATH_AGGR_SCHED_LOW;
+ sc->sc_tid_hwq_hi = ATH_AGGR_SCHED_HIGH;
+ sc->sc_aggr_limit = ATH_AGGR_MAXSIZE;
+ sc->sc_delim_min_pad = 0;
+
+ /*
+ * Check if the hardware requires PCI register serialisation.
+ * Some of the Owl based MACs require this.
+ */
+ if (mp_ncpus > 1 &&
+ ath_hal_getcapability(ah, HAL_CAP_SERIALISE_WAR,
+ 0, NULL) == HAL_OK) {
+ sc->sc_ah->ah_config.ah_serialise_reg_war = 1;
+ device_printf(sc->sc_dev,
+ "Enabling register serialisation\n");
+ }
+
+ /*
+ * Initialise the deferred completed RX buffer list.
+ */
+ TAILQ_INIT(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP]);
+ TAILQ_INIT(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP]);
+
+ /*
* Indicate we need the 802.11 header padded to a
* 32-bit boundary for 4-address and QoS frames.
*/
@@ -709,18 +927,63 @@
ic->ic_node_alloc = ath_node_alloc;
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = ath_node_free;
+ sc->sc_node_cleanup = ic->ic_node_cleanup;
+ ic->ic_node_cleanup = ath_node_cleanup;
ic->ic_node_getsignal = ath_node_getsignal;
ic->ic_scan_start = ath_scan_start;
ic->ic_scan_end = ath_scan_end;
ic->ic_set_channel = ath_set_channel;
+#ifdef ATH_ENABLE_11N
+ /* 802.11n specific - but just override anyway */
+ sc->sc_addba_request = ic->ic_addba_request;
+ sc->sc_addba_response = ic->ic_addba_response;
+ sc->sc_addba_stop = ic->ic_addba_stop;
+ sc->sc_bar_response = ic->ic_bar_response;
+ sc->sc_addba_response_timeout = ic->ic_addba_response_timeout;
+ ic->ic_addba_request = ath_addba_request;
+ ic->ic_addba_response = ath_addba_response;
+ ic->ic_addba_response_timeout = ath_addba_response_timeout;
+ ic->ic_addba_stop = ath_addba_stop;
+ ic->ic_bar_response = ath_bar_response;
+
+ 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 the ALQ logging if required
+ */
+#ifdef ATH_DEBUG_ALQ
+ if_ath_alq_init(&sc->sc_alq, device_get_nameunit(sc->sc_dev));
+ if_ath_alq_setcfg(&sc->sc_alq,
+ sc->sc_ah->ah_macVersion,
+ sc->sc_ah->ah_macRev,
+ sc->sc_ah->ah_phyRev,
+ sc->sc_ah->ah_magic);
+#endif
+
+ /*
* Setup dynamic sysctl's now that country code and
* regdomain are available from the hal.
*/
@@ -735,11 +998,21 @@
bad2:
ath_tx_cleanup(sc);
ath_desc_free(sc);
+ ath_txdma_teardown(sc);
+ ath_rxdma_teardown(sc);
bad:
if (ah)
ath_hal_detach(ah);
- if (ifp != NULL)
+
+ /*
+ * To work around scoping issues with CURVNET_SET/CURVNET_RESTORE..
+ */
+ if (ifp != NULL && ifp->if_vnet) {
+ CURVNET_SET(ifp->if_vnet);
if_free(ifp);
+ CURVNET_RESTORE();
+ } else if (ifp != NULL)
+ if_free(ifp);
sc->sc_invalid = 1;
return error;
}
@@ -774,12 +1047,22 @@
sc->sc_tx99->detach(sc->sc_tx99);
#endif
ath_rate_detach(sc->sc_rc);
-
+#ifdef ATH_DEBUG_ALQ
+ if_ath_alq_tidyup(&sc->sc_alq);
+#endif
+ ath_lna_div_detach(sc);
+ ath_btcoex_detach(sc);
+ ath_spectral_detach(sc);
ath_dfs_detach(sc);
ath_desc_free(sc);
+ ath_txdma_teardown(sc);
+ ath_rxdma_teardown(sc);
ath_tx_cleanup(sc);
ath_hal_detach(sc->sc_ah); /* NB: sets chip in full sleep */
+
+ CURVNET_SET(ifp->if_vnet);
if_free(ifp);
+ CURVNET_RESTORE();
return 0;
}
@@ -950,7 +1233,7 @@
/*
* Check that a beacon buffer is available; the code below assumes it.
*/
- if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) {
+ if (needbeacon & TAILQ_EMPTY(&sc->sc_bbuf)) {
device_printf(sc->sc_dev, "no beacon buffer available\n");
goto bad;
}
@@ -990,6 +1273,15 @@
avp->av_bmiss = vap->iv_bmiss;
vap->iv_bmiss = ath_bmiss_vap;
+ avp->av_node_ps = vap->iv_node_ps;
+ vap->iv_node_ps = ath_node_powersave;
+
+ avp->av_set_tim = vap->iv_set_tim;
+ vap->iv_set_tim = ath_node_set_tim;
+
+ avp->av_recv_pspoll = vap->iv_recv_pspoll;
+ vap->iv_recv_pspoll = ath_node_recv_pspoll;
+
/* Set default parameters */
/*
@@ -1012,8 +1304,8 @@
* multicast frames. We know a beacon buffer is
* available because we checked above.
*/
- avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf);
- STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list);
+ avp->av_bcbuf = TAILQ_FIRST(&sc->sc_bbuf);
+ TAILQ_REMOVE(&sc->sc_bbuf, avp->av_bcbuf, bf_list);
if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) {
/*
* Assign the vap to a beacon xmit slot. As above
@@ -1110,6 +1402,7 @@
struct ath_hal *ah = sc->sc_ah;
struct ath_vap *avp = ATH_VAP(vap);
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
/*
* Quiesce the hardware while we remove the vap. In
@@ -1117,11 +1410,32 @@
* the vap state by any frames pending on the tx queues.
*/
ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc); /* stop xmit side */
- ath_stoprecv(sc); /* stop recv side */
+ ath_draintxq(sc, ATH_RESET_DEFAULT); /* stop hw xmit side */
+ /* XXX Do all frames from all vaps/nodes need draining here? */
+ ath_stoprecv(sc, 1); /* stop recv side */
}
ieee80211_vap_detach(vap);
+
+ /*
+ * XXX Danger Will Robinson! Danger!
+ *
+ * Because ieee80211_vap_detach() can queue a frame (the station
+ * diassociate message?) after we've drained the TXQ and
+ * flushed the software TXQ, we will end up with a frame queued
+ * to a node whose vap is about to be freed.
+ *
+ * To work around this, flush the hardware/software again.
+ * This may be racy - the ath task may be running and the packet
+ * may be being scheduled between sw->hw txq. Tsk.
+ *
+ * TODO: figure out why a new node gets allocated somewhere around
+ * here (after the ath_tx_swq() call; and after an ath_stop_locked()
+ * call!)
+ */
+
+ ath_draintxq(sc, ATH_RESET_DEFAULT);
+
ATH_LOCK(sc);
/*
* Reclaim beacon state. Note this must be done before
@@ -1144,7 +1458,6 @@
* Reclaim any pending mcast frames for the vap.
*/
ath_tx_draintxq(sc, &avp->av_mcastq);
- ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
}
/*
* Update bookkeeping.
@@ -1169,7 +1482,6 @@
sc->sc_swbmiss = 0;
}
#endif
- ATH_UNLOCK(sc);
free(avp, M_80211_VAP);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
@@ -1190,6 +1502,7 @@
}
ath_hal_intrset(ah, sc->sc_imask);
}
+ ATH_UNLOCK(sc);
}
void
@@ -1202,15 +1515,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);
}
/*
@@ -1232,6 +1552,32 @@
ieee80211_crypto_reload_keys(ic);
}
+/*
+ * Fetch the current chainmask configuration based on the current
+ * operating channel and options.
+ */
+static void
+ath_update_chainmasks(struct ath_softc *sc, struct ieee80211_channel *chan)
+{
+
+ /*
+ * Set TX chainmask to the currently configured chainmask;
+ * the TX chainmask depends upon the current operating mode.
+ */
+ sc->sc_cur_rxchainmask = sc->sc_rxchainmask;
+ if (IEEE80211_IS_CHAN_HT(chan)) {
+ sc->sc_cur_txchainmask = sc->sc_txchainmask;
+ } else {
+ sc->sc_cur_txchainmask = 1;
+ }
+
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: TX chainmask is now 0x%x, RX is now 0x%x\n",
+ __func__,
+ sc->sc_cur_txchainmask,
+ sc->sc_cur_rxchainmask);
+}
+
void
ath_resume(struct ath_softc *sc)
{
@@ -1243,10 +1589,17 @@
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.
*/
+ ath_update_chainmasks(sc,
+ sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan);
+ ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask,
+ sc->sc_cur_rxchainmask);
ath_hal_reset(ah, sc->sc_opmode,
sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan,
AH_FALSE, &status);
@@ -1255,28 +1608,30 @@
/* Let DFS at it in case it's a DFS channel */
ath_dfs_radar_enable(sc, ic->ic_curchan);
- if (sc->sc_resume_up) {
- if (ic->ic_opmode == IEEE80211_M_STA) {
- ath_init(sc);
- /*
- * 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_softled) {
- ath_hal_gpioCfgOutput(ah, sc->sc_ledpin,
- HAL_GPIO_MUX_MAC_NETWORK_LED);
- ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon);
- }
+ /* Let spectral at in case spectral is enabled */
+ ath_spectral_enable(sc, ic->ic_curchan);
+ /*
+ * Let bluetooth coexistence at in case it's needed for this channel
+ */
+ ath_btcoex_enable(sc, ic->ic_curchan);
+
+ /*
+ * If we're doing TDMA, enforce the TXOP limitation for chips that
+ * support it.
+ */
+ if (sc->sc_hasenforcetxop && sc->sc_tdma)
+ ath_hal_setenforcetxop(sc->sc_ah, 1);
+ else
+ ath_hal_setenforcetxop(sc->sc_ah, 0);
+
+ /* Restore the LED configuration */
+ ath_led_config(sc);
+ ath_hal_setledstate(ah, HAL_LED_INIT);
+
+ if (sc->sc_resume_up)
+ ieee80211_resume_all(ic);
+
/* XXX beacons ? */
}
@@ -1302,7 +1657,24 @@
struct ifnet *ifp = sc->sc_ifp;
struct ath_hal *ah = sc->sc_ah;
HAL_INT status = 0;
+ uint32_t txqs;
+ /*
+ * If we're inside a reset path, just print a warning and
+ * clear the ISR. The reset routine will finish it for us.
+ */
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt) {
+ HAL_INT status;
+ ath_hal_getisr(ah, &status); /* clear ISR */
+ ath_hal_intrset(ah, 0); /* disable further intr's */
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: in reset, ignoring: status=0x%x\n",
+ __func__, status);
+ ATH_PCU_UNLOCK(sc);
+ return;
+ }
+
if (sc->sc_invalid) {
/*
* The hardware is not ready/present, don't touch anything.
@@ -1309,10 +1681,14 @@
* Note this can happen early on if the IRQ is shared.
*/
DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid; ignored\n", __func__);
+ ATH_PCU_UNLOCK(sc);
return;
}
- if (!ath_hal_intrpend(ah)) /* shared irq, not for us */
+ if (!ath_hal_intrpend(ah)) { /* shared irq, not for us */
+ ATH_PCU_UNLOCK(sc);
return;
+ }
+
if ((ifp->if_flags & IFF_UP) == 0 ||
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
HAL_INT status;
@@ -1321,8 +1697,10 @@
__func__, ifp->if_flags);
ath_hal_getisr(ah, &status); /* clear ISR */
ath_hal_intrset(ah, 0); /* disable further intr's */
+ ATH_PCU_UNLOCK(sc);
return;
}
+
/*
* Figure out the reason(s) for the interrupt. Note
* that the hal returns a pseudo-ISR that may include
@@ -1331,16 +1709,53 @@
*/
ath_hal_getisr(ah, &status); /* NB: clears ISR too */
DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, status);
+ ATH_KTR(sc, ATH_KTR_INTERRUPTS, 1, "ath_intr: mask=0x%.8x", status);
+#ifdef ATH_DEBUG_ALQ
+ if_ath_alq_post_intr(&sc->sc_alq, status, ah->ah_intrstate,
+ ah->ah_syncstate);
+#endif /* ATH_DEBUG_ALQ */
+#ifdef ATH_KTR_INTR_DEBUG
+ ATH_KTR(sc, ATH_KTR_INTERRUPTS, 5,
+ "ath_intr: ISR=0x%.8x, ISR_S0=0x%.8x, ISR_S1=0x%.8x, ISR_S2=0x%.8x, ISR_S5=0x%.8x",
+ ah->ah_intrstate[0],
+ ah->ah_intrstate[1],
+ ah->ah_intrstate[2],
+ ah->ah_intrstate[3],
+ ah->ah_intrstate[6]);
+#endif
+
+ /* Squirrel away SYNC interrupt debugging */
+ if (ah->ah_syncstate != 0) {
+ int i;
+ for (i = 0; i < 32; i++)
+ if (ah->ah_syncstate & (i << i))
+ sc->sc_intr_stats.sync_intr[i]++;
+ }
+
status &= sc->sc_imask; /* discard unasked for bits */
/* Short-circuit un-handled interrupts */
- if (status == 0x0)
+ if (status == 0x0) {
+ ATH_PCU_UNLOCK(sc);
return;
+ }
+ /*
+ * Take a note that we're inside the interrupt handler, so
+ * the reset routines know to wait.
+ */
+ sc->sc_intr_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ /*
+ * Handle the interrupt. We won't run concurrent with the reset
+ * or channel change routines as they'll wait for sc_intr_cnt
+ * to be 0 before continuing.
+ */
if (status & HAL_INT_FATAL) {
sc->sc_stats.ast_hardware++;
ath_hal_intrset(ah, 0); /* disable intr's until reset */
- ath_fatal_proc(sc, 0);
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_fataltask);
} else {
if (status & HAL_INT_SWBA) {
/*
@@ -1370,12 +1785,14 @@
* traffic so any frames held on the staging
* queue are aged and potentially flushed.
*/
- taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
+ sc->sc_rx.recv_sched(sc, 1);
#endif
}
}
if (status & HAL_INT_RXEOL) {
- int imask = sc->sc_imask;
+ int imask;
+ ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXEOL");
+ ATH_PCU_LOCK(sc);
/*
* NB: the hardware should re-read the link when
* RXE bit is written, but it doesn't work at
@@ -1391,16 +1808,30 @@
* by a call to ath_reset() somehow, the
* interrupt mask will be correctly reprogrammed.
*/
+ imask = sc->sc_imask;
imask &= ~(HAL_INT_RXEOL | HAL_INT_RXORN);
ath_hal_intrset(ah, imask);
/*
+ * Only blank sc_rxlink if we've not yet kicked
+ * the PCU.
+ *
+ * This isn't entirely correct - the correct solution
+ * would be to have a PCU lock and engage that for
+ * the duration of the PCU fiddling; which would include
+ * running the RX process. Otherwise we could end up
+ * messing up the RX descriptor chain and making the
+ * RX desc list much shorter.
+ */
+ if (! sc->sc_kickpcu)
+ sc->sc_rxlink = NULL;
+ sc->sc_kickpcu = 1;
+ ATH_PCU_UNLOCK(sc);
+ /*
* Enqueue an RX proc, to handled whatever
* is in the RX queue.
* This will then kick the PCU.
*/
- taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
- sc->sc_rxlink = NULL;
- sc->sc_kickpcu = 1;
+ sc->sc_rx.recv_sched(sc, 1);
}
if (status & HAL_INT_TXURN) {
sc->sc_stats.ast_txurn++;
@@ -1407,10 +1838,35 @@
/* bump tx trigger level */
ath_hal_updatetxtriglevel(ah, AH_TRUE);
}
- if (status & HAL_INT_RX)
- taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
- if (status & HAL_INT_TX)
+ /*
+ * 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++;
+ sc->sc_rx.recv_sched(sc, 1);
+ }
+ if (status & HAL_INT_TX) {
+ sc->sc_stats.ast_tx_intr++;
+ /*
+ * Grab all the currently set bits in the HAL txq bitmap
+ * and blank them. This is the only place we should be
+ * doing this.
+ */
+ if (! sc->sc_isedma) {
+ ATH_PCU_LOCK(sc);
+ txqs = 0xffffffff;
+ ath_hal_gettxintrtxqs(sc->sc_ah, &txqs);
+ ATH_KTR(sc, ATH_KTR_INTERRUPTS, 3,
+ "ath_intr: TX; txqs=0x%08x, txq_active was 0x%08x, now 0x%08x",
+ txqs,
+ sc->sc_txq_active,
+ sc->sc_txq_active | txqs);
+ sc->sc_txq_active |= txqs;
+ ATH_PCU_UNLOCK(sc);
+ }
taskqueue_enqueue(sc->sc_tq, &sc->sc_txtask);
+ }
if (status & HAL_INT_BMISS) {
sc->sc_stats.ast_bmiss++;
taskqueue_enqueue(sc->sc_tq, &sc->sc_bmisstask);
@@ -1421,6 +1877,7 @@
sc->sc_stats.ast_tx_cst++;
if (status & HAL_INT_MIB) {
sc->sc_stats.ast_mib++;
+ ATH_PCU_LOCK(sc);
/*
* Disable interrupts until we service the MIB
* interrupt; otherwise it will continue to fire.
@@ -1431,13 +1888,25 @@
* clear whatever condition caused the interrupt.
*/
ath_hal_mibevent(ah, &sc->sc_halstats);
- ath_hal_intrset(ah, sc->sc_imask);
+ /*
+ * Don't reset the interrupt if we've just
+ * kicked the PCU, or we may get a nested
+ * RXEOL before the rxproc has had a chance
+ * to run.
+ */
+ if (sc->sc_kickpcu == 0)
+ ath_hal_intrset(ah, sc->sc_imask);
+ ATH_PCU_UNLOCK(sc);
}
if (status & HAL_INT_RXORN) {
/* NB: hal marks HAL_INT_FATAL when RXORN is fatal */
+ ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXORN");
sc->sc_stats.ast_rxorn++;
}
}
+ ATH_PCU_LOCK(sc);
+ sc->sc_intr_cnt--;
+ ATH_PCU_UNLOCK(sc);
}
static void
@@ -1462,7 +1931,7 @@
state[0], state[1] , state[2], state[3],
state[4], state[5]);
}
- ath_reset(ifp);
+ ath_reset(ifp, ATH_RESET_NOLOSS);
}
static void
@@ -1481,6 +1950,7 @@
struct ath_softc *sc = ifp->if_softc;
u_int64_t lastrx = sc->sc_lastrx;
u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
+ /* XXX should take a locked ref to iv_bss */
u_int bmisstimeout =
vap->iv_bmissthreshold * vap->iv_bss->ni_intval * 1024;
@@ -1498,7 +1968,7 @@
ATH_VAP(vap)->av_bmiss(vap);
}
-static int
+int
ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs)
{
uint32_t rsize;
@@ -1520,11 +1990,19 @@
DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
+ /*
+ * Do a reset upon any becaon miss event.
+ *
+ * It may be a non-recognised RX clear hang which needs a reset
+ * to clear.
+ */
if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) {
+ ath_reset(ifp, ATH_RESET_NOLOSS);
if_printf(ifp, "bb hang detected (0x%x), resetting\n", hangs);
- ath_reset(ifp);
- } else
+ } else {
+ ath_reset(ifp, ATH_RESET_NOLOSS);
ieee80211_beacon_miss(ifp->if_l2com);
+ }
}
/*
@@ -1577,6 +2055,9 @@
* and then setup of the interrupt mask.
*/
ath_settkipmic(sc);
+ ath_update_chainmasks(sc, ic->ic_curchan);
+ ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask,
+ sc->sc_cur_rxchainmask);
if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, &status)) {
if_printf(ifp, "unable to reset hardware; hal status %u\n",
status);
@@ -1588,7 +2069,24 @@
/* Let DFS at it in case it's a DFS channel */
ath_dfs_radar_enable(sc, ic->ic_curchan);
+ /* Let spectral at in case spectral is enabled */
+ ath_spectral_enable(sc, ic->ic_curchan);
+
/*
+ * Let bluetooth coexistence at in case it's needed for this channel
+ */
+ ath_btcoex_enable(sc, ic->ic_curchan);
+
+ /*
+ * If we're doing TDMA, enforce the TXOP limitation for chips that
+ * support it.
+ */
+ if (sc->sc_hasenforcetxop && sc->sc_tdma)
+ ath_hal_setenforcetxop(sc->sc_ah, 1);
+ else
+ ath_hal_setenforcetxop(sc->sc_ah, 0);
+
+ /*
* Likewise this is set during reset so update
* state cached in the driver.
*/
@@ -1624,8 +2122,17 @@
*/
sc->sc_imask = HAL_INT_RX | HAL_INT_TX
| HAL_INT_RXEOL | HAL_INT_RXORN
+ | HAL_INT_TXURN
| 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.
*/
@@ -1695,9 +2202,9 @@
}
ath_hal_intrset(ah, 0);
}
- ath_draintxq(sc);
+ ath_draintxq(sc, ATH_RESET_DEFAULT);
if (!sc->sc_invalid) {
- ath_stoprecv(sc);
+ ath_stoprecv(sc, 1);
ath_hal_phydisable(ah);
} else
sc->sc_rxlink = NULL;
@@ -1705,7 +2212,121 @@
}
}
+#define MAX_TXRX_ITERATIONS 1000
static void
+ath_txrx_stop_locked(struct ath_softc *sc)
+{
+ int i = MAX_TXRX_ITERATIONS;
+
+ ATH_UNLOCK_ASSERT(sc);
+ ATH_PCU_LOCK_ASSERT(sc);
+
+ /*
+ * Sleep until all the pending operations have completed.
+ *
+ * The caller must ensure that reset has been incremented
+ * or the pending operations may continue being queued.
+ */
+ while (sc->sc_rxproc_cnt || sc->sc_txproc_cnt ||
+ sc->sc_txstart_cnt || sc->sc_intr_cnt) {
+ if (i <= 0)
+ break;
+ msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop", 1);
+ i--;
+ }
+
+ if (i <= 0)
+ device_printf(sc->sc_dev,
+ "%s: didn't finish after %d iterations\n",
+ __func__, MAX_TXRX_ITERATIONS);
+}
+#undef MAX_TXRX_ITERATIONS
+
+#if 0
+static void
+ath_txrx_stop(struct ath_softc *sc)
+{
+ ATH_UNLOCK_ASSERT(sc);
+ ATH_PCU_UNLOCK_ASSERT(sc);
+
+ ATH_PCU_LOCK(sc);
+ ath_txrx_stop_locked(sc);
+ ATH_PCU_UNLOCK(sc);
+}
+#endif
+
+static void
+ath_txrx_start(struct ath_softc *sc)
+{
+
+ taskqueue_unblock(sc->sc_tq);
+}
+
+/*
+ * Grab the reset lock, and wait around until noone else
+ * is trying to do anything with it.
+ *
+ * This is totally horrible but we can't hold this lock for
+ * long enough to do TX/RX or we end up with net80211/ip stack
+ * LORs and eventual deadlock.
+ *
+ * "dowait" signals whether to spin, waiting for the reset
+ * lock count to reach 0. This should (for now) only be used
+ * during the reset path, as the rest of the code may not
+ * be locking-reentrant enough to behave correctly.
+ *
+ * Another, cleaner way should be found to serialise all of
+ * these operations.
+ */
+#define MAX_RESET_ITERATIONS 10
+static int
+ath_reset_grablock(struct ath_softc *sc, int dowait)
+{
+ int w = 0;
+ int i = MAX_RESET_ITERATIONS;
+
+ ATH_PCU_LOCK_ASSERT(sc);
+ do {
+ if (sc->sc_inreset_cnt == 0) {
+ w = 1;
+ break;
+ }
+ if (dowait == 0) {
+ w = 0;
+ break;
+ }
+ ATH_PCU_UNLOCK(sc);
+ pause("ath_reset_grablock", 1);
+ i--;
+ ATH_PCU_LOCK(sc);
+ } while (i > 0);
+
+ /*
+ * We always increment the refcounter, regardless
+ * of whether we succeeded to get it in an exclusive
+ * way.
+ */
+ sc->sc_inreset_cnt++;
+
+ if (i <= 0)
+ device_printf(sc->sc_dev,
+ "%s: didn't finish after %d iterations\n",
+ __func__, MAX_RESET_ITERATIONS);
+
+ if (w == 0)
+ device_printf(sc->sc_dev,
+ "%s: warning, recursive reset path!\n",
+ __func__);
+
+ return w;
+}
+#undef MAX_RESET_ITERATIONS
+
+/*
+ * XXX TODO: write ath_reset_releaselock
+ */
+
+static void
ath_stop(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
@@ -1723,18 +2344,67 @@
* to reset or reload hardware state.
*/
int
-ath_reset(struct ifnet *ifp)
+ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
{
struct ath_softc *sc = ifp->if_softc;
struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
HAL_STATUS status;
+ int i;
- ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc); /* stop xmit side */
- ath_stoprecv(sc); /* stop recv side */
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__);
+
+ /* Ensure ATH_LOCK isn't held; ath_rx_proc can't be locked */
+ ATH_PCU_UNLOCK_ASSERT(sc);
+ ATH_UNLOCK_ASSERT(sc);
+
+ /* Try to (stop any further TX/RX from occuring */
+ taskqueue_block(sc->sc_tq);
+
+ ATH_PCU_LOCK(sc);
+
+ /*
+ * Grab the reset lock before TX/RX is stopped.
+ *
+ * This is needed to ensure that when the TX/RX actually does finish,
+ * no further TX/RX/reset runs in parallel with this.
+ */
+ if (ath_reset_grablock(sc, 1) == 0) {
+ device_printf(sc->sc_dev, "%s: concurrent reset! Danger!\n",
+ __func__);
+ }
+
+ /* disable interrupts */
+ ath_hal_intrset(ah, 0);
+
+ /*
+ * Now, ensure that any in progress TX/RX completes before we
+ * continue.
+ */
+ ath_txrx_stop_locked(sc);
+
+ ATH_PCU_UNLOCK(sc);
+
+ /*
+ * Should now wait for pending TX/RX to complete
+ * and block future ones from occuring. This needs to be
+ * done before the TX queue is drained.
+ */
+ ath_draintxq(sc, reset_type); /* stop xmit side */
+
+ /*
+ * Regardless of whether we're doing a no-loss flush or
+ * not, stop the PCU and handle what's in the RX queue.
+ * That way frames aren't dropped which shouldn't be.
+ */
+ ath_stoprecv(sc, (reset_type != ATH_RESET_NOLOSS));
+ ath_rx_flush(sc);
+
ath_settkipmic(sc); /* configure TKIP MIC handling */
/* NB: indicate channel change so we do a full reset */
+ ath_update_chainmasks(sc, ic->ic_curchan);
+ ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask,
+ sc->sc_cur_rxchainmask);
if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_TRUE, &status))
if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
__func__, status);
@@ -1743,6 +2413,23 @@
/* Let DFS at it in case it's a DFS channel */
ath_dfs_radar_enable(sc, ic->ic_curchan);
+ /* Let spectral at in case spectral is enabled */
+ ath_spectral_enable(sc, ic->ic_curchan);
+
+ /*
+ * Let bluetooth coexistence at in case it's needed for this channel
+ */
+ ath_btcoex_enable(sc, ic->ic_curchan);
+
+ /*
+ * If we're doing TDMA, enforce the TXOP limitation for chips that
+ * support it.
+ */
+ if (sc->sc_hasenforcetxop && sc->sc_tdma)
+ ath_hal_setenforcetxop(sc->sc_ah, 1);
+ else
+ ath_hal_setenforcetxop(sc->sc_ah, 0);
+
if (ath_startrecv(sc) != 0) /* restart recv */
if_printf(ifp, "%s: unable to start recv logic\n", __func__);
/*
@@ -1759,9 +2446,64 @@
#endif
ath_beacon_config(sc, NULL);
}
+
+ /*
+ * Release the reset lock and re-enable interrupts here.
+ * If an interrupt was being processed in ath_intr(),
+ * it would disable interrupts at this point. So we have
+ * to atomically enable interrupts and decrement the
+ * reset counter - this way ath_intr() doesn't end up
+ * disabling interrupts without a corresponding enable
+ * in the rest or channel change path.
+ */
+ ATH_PCU_LOCK(sc);
+ sc->sc_inreset_cnt--;
+ /* XXX only do this if sc_inreset_cnt == 0? */
ath_hal_intrset(ah, sc->sc_imask);
+ ATH_PCU_UNLOCK(sc);
- ath_start(ifp); /* restart xmit */
+ /*
+ * TX and RX can be started here. If it were started with
+ * sc_inreset_cnt > 0, the TX and RX path would abort.
+ * Thus if this is a nested call through the reset or
+ * channel change code, TX completion will occur but
+ * RX completion and ath_start / ath_tx_start will not
+ * run.
+ */
+
+ /* Restart TX/RX as needed */
+ ath_txrx_start(sc);
+
+ /* Restart TX completion and pending TX */
+ if (reset_type == ATH_RESET_NOLOSS) {
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ ATH_TXQ_LOCK(&sc->sc_txq[i]);
+ ath_txq_restart_dma(sc, &sc->sc_txq[i]);
+ ATH_TXQ_UNLOCK(&sc->sc_txq[i]);
+
+ ATH_TX_LOCK(sc);
+ ath_txq_sched(sc, &sc->sc_txq[i]);
+ ATH_TX_UNLOCK(sc);
+ }
+ }
+ }
+
+ /*
+ * This may have been set during an ath_start() call which
+ * set this once it detected a concurrent TX was going on.
+ * So, clear it.
+ */
+ IF_LOCK(&ifp->if_snd);
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
+
+ /* Handle any frames in the TX queue */
+ /*
+ * XXX should this be done by the caller, rather than
+ * ath_reset() ?
+ */
+ ath_tx_kick(sc); /* restart xmit */
return 0;
}
@@ -1784,141 +2526,455 @@
ath_hal_settxpowlimit(ah, ic->ic_txpowlimit);
return 0;
}
- return ath_reset(ifp);
+ /* XXX? Full or NOLOSS? */
+ return ath_reset(ifp, ATH_RESET_FULL);
}
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 = STAILQ_FIRST(&sc->sc_txbuf);
- if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0)
- STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
+ 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 {
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ sc->sc_stats.ast_tx_getbusybuf++;
+ bf = NULL;
+ }
+ }
+
+ 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__,
- STAILQ_FIRST(&sc->sc_txbuf) == NULL ?
+ 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) */
+ bf->bf_flags = 0;
+ 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 */
+ bf->bf_comp = NULL; /* XXX again, just to be sure */
+ bzero(&bf->bf_state, sizeof(bf->bf_state));
+
+ /*
+ * Track the descriptor ID only if doing EDMA
+ */
+ if (sc->sc_isedma) {
+ bf->bf_descid = sc->sc_txbuf_descid;
+ sc->sc_txbuf_descid++;
+ }
+
return bf;
}
+/*
+ * When retrying a software frame, buffers marked ATH_BUF_BUSY
+ * can't be thrown back on the queue as they could still be
+ * in use by the hardware.
+ *
+ * This duplicates the buffer, or returns NULL.
+ *
+ * The descriptor is also copied but the link pointers and
+ * the DMA segments aren't copied; this frame should thus
+ * be again passed through the descriptor setup/chain routines
+ * so the link is correct.
+ *
+ * The caller must free the buffer using ath_freebuf().
+ */
struct ath_buf *
-ath_getbuf(struct ath_softc *sc)
+ath_buf_clone(struct ath_softc *sc, struct ath_buf *bf)
{
+ struct ath_buf *tbf;
+
+ tbf = ath_getbuf(sc,
+ (bf->bf_flags & ATH_BUF_MGMT) ?
+ ATH_BUFTYPE_MGMT : ATH_BUFTYPE_NORMAL);
+ if (tbf == NULL)
+ return NULL; /* XXX failure? Why? */
+
+ /* Copy basics */
+ tbf->bf_next = NULL;
+ tbf->bf_nseg = bf->bf_nseg;
+ tbf->bf_flags = bf->bf_flags & ATH_BUF_FLAGS_CLONE;
+ tbf->bf_status = bf->bf_status;
+ tbf->bf_m = bf->bf_m;
+ tbf->bf_node = bf->bf_node;
+ /* will be setup by the chain/setup function */
+ tbf->bf_lastds = NULL;
+ /* for now, last == self */
+ tbf->bf_last = tbf;
+ tbf->bf_comp = bf->bf_comp;
+
+ /* NOTE: DMA segments will be setup by the setup/chain functions */
+
+ /* The caller has to re-init the descriptor + links */
+
+ /*
+ * Free the DMA mapping here, before we NULL the mbuf.
+ * We must only call bus_dmamap_unload() once per mbuf chain
+ * or behaviour is undefined.
+ */
+ if (bf->bf_m != NULL) {
+ /*
+ * XXX is this POSTWRITE call required?
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ }
+
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+
+ /* Copy state */
+ memcpy(&tbf->bf_state, &bf->bf_state, sizeof(bf->bf_state));
+
+ return tbf;
+}
+
+struct ath_buf *
+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;
DPRINTF(sc, ATH_DEBUG_XMIT, "%s: stop queue\n", __func__);
sc->sc_stats.ast_tx_qstop++;
+ IF_LOCK(&ifp->if_snd);
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
}
- ATH_TXBUF_UNLOCK(sc);
return bf;
}
static void
-ath_start(struct ifnet *ifp)
+ath_qflush(struct ifnet *ifp)
{
- struct ath_softc *sc = ifp->if_softc;
+
+ /* XXX TODO */
+}
+
+/*
+ * Transmit a single frame.
+ *
+ * net80211 will free the node reference if the transmit
+ * fails, so don't free the node reference here.
+ */
+static int
+ath_transmit(struct ifnet *ifp, struct mbuf *m)
+{
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
struct ieee80211_node *ni;
+ struct mbuf *next;
struct ath_buf *bf;
- struct mbuf *m, *next;
ath_bufhead frags;
+ int retval = 0;
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
- return;
- for (;;) {
+ /*
+ * Tell the reset path that we're currently transmitting.
+ */
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt > 0) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%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);
+ ATH_KTR(sc, ATH_KTR_TX, 0, "ath_start_task: OACTIVE, finish");
+ return (ENOBUFS); /* XXX should be EINVAL or? */
+ }
+ sc->sc_txstart_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: start");
+ /*
+ * Grab the TX lock - it's ok to do this here; we haven't
+ * yet started transmitting.
+ */
+ ATH_TX_LOCK(sc);
+
+ /*
+ * Node reference, if there's one.
+ */
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+
+ /*
+ * Enforce how deep a node queue can get.
+ *
+ * XXX it would be nicer if we kept an mbuf queue per
+ * node and only whacked them into ath_bufs when we
+ * are ready to schedule some traffic from them.
+ * .. that may come later.
+ *
+ * XXX we should also track the per-node hardware queue
+ * depth so it is easy to limit the _SUM_ of the swq and
+ * hwq frames. Since we only schedule two HWQ frames
+ * at a time, this should be OK for now.
+ */
+ if ((!(m->m_flags & M_EAPOL)) &&
+ (ATH_NODE(ni)->an_swq_depth > sc->sc_txq_node_maxdepth)) {
+ sc->sc_stats.ast_tx_nodeq_overflow++;
+ m_freem(m);
+ m = NULL;
+ retval = ENOBUFS;
+ goto finish;
+ }
+
+ /*
+ * Check how many TX buffers are available.
+ *
+ * If this is for non-EAPOL traffic, just leave some
+ * space free in order for buffer cloning and raw
+ * frame transmission to occur.
+ *
+ * If it's for EAPOL traffic, ignore this for now.
+ * Management traffic will be sent via the raw transmit
+ * method which bypasses this check.
+ *
+ * This is needed to ensure that EAPOL frames during
+ * (re) keying have a chance to go out.
+ *
+ * See kern/138379 for more information.
+ */
+ if ((!(m->m_flags & M_EAPOL)) &&
+ (sc->sc_txbuf_cnt <= sc->sc_txq_data_minfree)) {
+ sc->sc_stats.ast_tx_nobuf++;
+ m_freem(m);
+ m = NULL;
+ retval = ENOBUFS;
+ goto finish;
+ }
+
+ /*
+ * Grab a TX buffer and associated resources.
+ *
+ * If it's an EAPOL frame, allocate a MGMT ath_buf.
+ * That way even with temporary buffer exhaustion due to
+ * the data path doesn't leave us without the ability
+ * to transmit management frames.
+ *
+ * Otherwise allocate a normal buffer.
+ */
+ if (m->m_flags & M_EAPOL)
+ bf = ath_getbuf(sc, ATH_BUFTYPE_MGMT);
+ else
+ bf = ath_getbuf(sc, ATH_BUFTYPE_NORMAL);
+
+ if (bf == NULL) {
/*
- * Grab a TX buffer and associated resources.
+ * If we failed to allocate a buffer, fail.
+ *
+ * We shouldn't fail normally, due to the check
+ * above.
*/
- bf = ath_getbuf(sc);
- if (bf == NULL)
- break;
+ sc->sc_stats.ast_tx_nobuf++;
+ IF_LOCK(&ifp->if_snd);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
+ m_freem(m);
+ m = NULL;
+ retval = ENOBUFS;
+ goto finish;
+ }
- IFQ_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL) {
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
- break;
- }
- ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ /*
+ * At this point we have a buffer; so we need to free it
+ * if we hit any error conditions.
+ */
+
+ /*
+ * Check for fragmentation. If this frame
+ * has been broken up verify we have enough
+ * buffers to send all the fragments so all
+ * go out or none...
+ */
+ TAILQ_INIT(&frags);
+ if ((m->m_flags & M_FRAG) &&
+ !ath_txfrag_setup(sc, &frags, m, ni)) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: out of txfrag buffers\n", __func__);
+ sc->sc_stats.ast_tx_nofrag++;
+ ifp->if_oerrors++;
+ ath_freetx(m);
+ goto bad;
+ }
+
+ /*
+ * At this point if we have any TX fragments, then we will
+ * have bumped the node reference once for each of those.
+ */
+
+ /*
+ * XXX Is there anything actually _enforcing_ that the
+ * fragments are being transmitted in one hit, rather than
+ * being interleaved with other transmissions on that
+ * hardware queue?
+ *
+ * The ATH TX output lock is the only thing serialising this
+ * right now.
+ */
+
+ /*
+ * Calculate the "next fragment" length field in ath_buf
+ * in order to let the transmit path know enough about
+ * what to next write to the hardware.
+ */
+ if (m->m_flags & M_FRAG) {
+ struct ath_buf *fbf = bf;
+ struct ath_buf *n_fbf = NULL;
+ struct mbuf *fm = m->m_nextpkt;
+
/*
- * Check for fragmentation. If this frame
- * has been broken up verify we have enough
- * buffers to send all the fragments so all
- * go out or none...
+ * We need to walk the list of fragments and set
+ * the next size to the following buffer.
+ * However, the first buffer isn't in the frag
+ * list, so we have to do some gymnastics here.
*/
- STAILQ_INIT(&frags);
- if ((m->m_flags & M_FRAG) &&
- !ath_txfrag_setup(sc, &frags, m, ni)) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: out of txfrag buffers\n", __func__);
- sc->sc_stats.ast_tx_nofrag++;
- ifp->if_oerrors++;
- ath_freetx(m);
- goto bad;
+ TAILQ_FOREACH(n_fbf, &frags, bf_list) {
+ fbf->bf_nextfraglen = fm->m_pkthdr.len;
+ fbf = n_fbf;
+ fm = fm->m_nextpkt;
}
- ifp->if_opackets++;
- nextfrag:
+ }
+
+ /*
+ * Bump the ifp output counter.
+ *
+ * XXX should use atomics?
+ */
+ ifp->if_opackets++;
+nextfrag:
+ /*
+ * Pass the frame to the h/w for transmission.
+ * Fragmented frames have each frag chained together
+ * with m_nextpkt. We know there are sufficient ath_buf's
+ * to send all the frags because of work done by
+ * ath_txfrag_setup. We leave m_nextpkt set while
+ * calling ath_tx_start so it can use it to extend the
+ * the tx duration to cover the subsequent frag and
+ * so it can reclaim all the mbufs in case of an error;
+ * ath_tx_start clears m_nextpkt once it commits to
+ * handing the frame to the hardware.
+ *
+ * Note: if this fails, then the mbufs are freed but
+ * not the node reference.
+ */
+ next = m->m_nextpkt;
+ if (ath_tx_start(sc, ni, bf, m)) {
+bad:
+ ifp->if_oerrors++;
+reclaim:
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+ ATH_TXBUF_LOCK(sc);
+ ath_returnbuf_head(sc, bf);
/*
- * Pass the frame to the h/w for transmission.
- * Fragmented frames have each frag chained together
- * with m_nextpkt. We know there are sufficient ath_buf's
- * to send all the frags because of work done by
- * ath_txfrag_setup. We leave m_nextpkt set while
- * calling ath_tx_start so it can use it to extend the
- * the tx duration to cover the subsequent frag and
- * so it can reclaim all the mbufs in case of an error;
- * ath_tx_start clears m_nextpkt once it commits to
- * handing the frame to the hardware.
+ * Free the rest of the node references and
+ * buffers for the fragment list.
*/
- next = m->m_nextpkt;
- if (ath_tx_start(sc, ni, bf, m)) {
- bad:
- ifp->if_oerrors++;
- reclaim:
- bf->bf_m = NULL;
- bf->bf_node = NULL;
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
- ath_txfrag_cleanup(sc, &frags, ni);
- ATH_TXBUF_UNLOCK(sc);
- if (ni != NULL)
- ieee80211_free_node(ni);
- continue;
+ ath_txfrag_cleanup(sc, &frags, ni);
+ ATH_TXBUF_UNLOCK(sc);
+ retval = ENOBUFS;
+ goto finish;
+ }
+
+ /*
+ * Check here if the node is in power save state.
+ */
+ ath_tx_update_tim(sc, ni, 1);
+
+ if (next != NULL) {
+ /*
+ * Beware of state changing between frags.
+ * XXX check sta power-save state?
+ */
+ if (ni->ni_vap->iv_state != IEEE80211_S_RUN) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: flush fragmented packet, state %s\n",
+ __func__,
+ ieee80211_state_name[ni->ni_vap->iv_state]);
+ /* XXX dmamap */
+ ath_freetx(next);
+ goto reclaim;
}
- if (next != NULL) {
- /*
- * Beware of state changing between frags.
- * XXX check sta power-save state?
- */
- if (ni->ni_vap->iv_state != IEEE80211_S_RUN) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: flush fragmented packet, state %s\n",
- __func__,
- ieee80211_state_name[ni->ni_vap->iv_state]);
- ath_freetx(next);
- goto reclaim;
- }
- m = next;
- bf = STAILQ_FIRST(&frags);
- KASSERT(bf != NULL, ("no buf for txfrag"));
- STAILQ_REMOVE_HEAD(&frags, bf_list);
- goto nextfrag;
- }
+ m = next;
+ bf = TAILQ_FIRST(&frags);
+ KASSERT(bf != NULL, ("no buf for txfrag"));
+ TAILQ_REMOVE(&frags, bf, bf_list);
+ goto nextfrag;
+ }
- sc->sc_wd_timer = 5;
- }
+ /*
+ * Bump watchdog timer.
+ */
+ sc->sc_wd_timer = 5;
+
+finish:
+ ATH_TX_UNLOCK(sc);
+
+ /*
+ * Finished transmitting!
+ */
+ ATH_PCU_LOCK(sc);
+ sc->sc_txstart_cnt--;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: finished");
+
+ return (retval);
}
static int
@@ -1957,99 +3013,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;
-
- if (sc->sc_dodfs) {
- rfilt |= HAL_RX_FILTER_PHYRADAR;
- }
-
- /*
- * 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;
-
- 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)
{
@@ -2099,7 +3062,7 @@
__func__, mfilt[0], mfilt[1]);
}
-static void
+void
ath_mode_init(struct ath_softc *sc)
{
struct ifnet *ifp = sc->sc_ifp;
@@ -2113,6 +3076,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));
@@ -2123,7 +3093,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;
@@ -2176,499 +3146,42 @@
}
/*
- * 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;
- 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;
-
- 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)
{
- STAILQ_CONCAT(&dst->axq_q, &src->axq_q);
+
+ ATH_TXQ_LOCK_ASSERT(src);
+ ATH_TXQ_LOCK_ASSERT(dst);
+
+ TAILQ_CONCAT(&dst->axq_q, &src->axq_q, bf_list);
dst->axq_link = src->axq_link;
src->axq_link = NULL;
dst->axq_depth += src->axq_depth;
+ dst->axq_aggr_depth += src->axq_aggr_depth;
src->axq_depth = 0;
+ src->axq_aggr_depth = 0;
}
/*
- * 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.
+ * Reset the hardware, with no loss.
+ *
+ * This can't be used for a general case reset.
*/
static void
-ath_beacon_proc(void *arg, int pending)
+ath_reset_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;
+ struct ifnet *ifp = sc->sc_ifp;
- 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++;
- }
+#if 0
+ if_printf(ifp, "%s: resetting\n", __func__);
+#endif
+ ath_reset(ifp, ATH_RESET_NOLOSS);
}
-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;
- 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 = STAILQ_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 */
- ath_hal_txstart(ah, cabq->axq_qnum);
- ATH_TXQ_UNLOCK(cabq);
- ATH_TXQ_UNLOCK(&avp->av_mcastq);
- }
- 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 after detecting beacons have stopped.
*/
@@ -2677,257 +3190,27 @@
{
struct ath_softc *sc = arg;
struct ifnet *ifp = sc->sc_ifp;
+ uint32_t hangs = 0;
+ if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0)
+ if_printf(ifp, "bb hang detected (0x%x)\n", hangs);
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_STUCK_BEACON))
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_STUCK_BEACON, 0, NULL);
+#endif
+
if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n",
sc->sc_bmisscount);
sc->sc_stats.ast_bstuck++;
- ath_reset(ifp);
+ /*
+ * This assumes that there's no simultaneous channel mode change
+ * occuring.
+ */
+ 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)
-{
-
- 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;
- }
- STAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list);
-}
-
-/*
- * Reclaim beacon resources.
- */
-static void
-ath_beacon_free(struct ath_softc *sc)
-{
- struct ath_buf *bf;
-
- STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) {
- 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 = 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;
-#undef FUDGE
-#undef TSF_TO_TU
-}
-
-static void
ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
bus_addr_t *paddr = (bus_addr_t*) arg;
@@ -2935,10 +3218,16 @@
*paddr = segs->ds_addr;
}
-static int
-ath_descdma_setup(struct ath_softc *sc,
+/*
+ * Allocate the descriptors and appropriate DMA tag/setup.
+ *
+ * For some situations (eg EDMA TX completion), there isn't a requirement
+ * for the ath_buf entries to be allocated.
+ */
+int
+ath_descdma_alloc_desc(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 ndesc)
{
#define DS2PHYS(_dd, _ds) \
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
@@ -2945,18 +3234,16 @@
#define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
struct ifnet *ifp = sc->sc_ifp;
- uint8_t *ds;
- struct ath_buf *bf;
- int i, bsize, error;
- int desc_len;
+ int error;
- desc_len = sizeof(struct ath_desc);
+ dd->dd_descsize = ds_size;
- DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n",
- __func__, name, nbuf, ndesc);
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: %s DMA: %u desc, %d bytes per descriptor\n",
+ __func__, name, ndesc, dd->dd_descsize);
dd->dd_name = name;
- dd->dd_desc_len = desc_len * nbuf * ndesc;
+ dd->dd_desc_len = dd->dd_descsize * ndesc;
/*
* Merlin work-around:
@@ -2964,12 +3251,15 @@
* Assume one skipped descriptor per 4KB page.
*/
if (! ath_hal_split4ktrans(sc->sc_ah)) {
- int numdescpage = 4096 / (desc_len * ndesc);
- dd->dd_desc_len = (nbuf / numdescpage + 1) * 4096;
+ int numpages = dd->dd_desc_len / 4096;
+ dd->dd_desc_len += ds_size * numpages;
}
/*
* Setup DMA descriptor area.
+ *
+ * BUS_DMA_ALLOCNOW is not used; we never use bounce
+ * buffers for the descriptors themselves.
*/
error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */
PAGE_SIZE, 0, /* alignment, bounds */
@@ -2979,7 +3269,7 @@
dd->dd_desc_len, /* maxsize */
1, /* nsegments */
dd->dd_desc_len, /* maxsegsize */
- BUS_DMA_ALLOCNOW, /* flags */
+ 0, /* flags */
NULL, /* lockfunc */
NULL, /* lockarg */
&dd->dd_dmat);
@@ -2989,19 +3279,12 @@
}
/* allocate descriptors */
- error = bus_dmamap_create(dd->dd_dmat, BUS_DMA_NOWAIT, &dd->dd_dmamap);
- if (error != 0) {
- if_printf(ifp, "unable to create dmamap for %s descriptors, "
- "error %u\n", dd->dd_name, error);
- goto fail0;
- }
-
error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
&dd->dd_dmamap);
if (error != 0) {
if_printf(ifp, "unable to alloc memory for %u %s descriptors, "
- "error %u\n", nbuf * ndesc, dd->dd_name, error);
+ "error %u\n", ndesc, dd->dd_name, error);
goto fail1;
}
@@ -3015,11 +3298,48 @@
goto fail2;
}
- ds = (uint8_t *) dd->dd_desc;
DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
- __func__, dd->dd_name, ds, (u_long) dd->dd_desc_len,
- (caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len);
+ __func__, dd->dd_name, (uint8_t *) dd->dd_desc,
+ (u_long) dd->dd_desc_len, (caddr_t) dd->dd_desc_paddr,
+ /*XXX*/ (u_long) dd->dd_desc_len);
+ return (0);
+
+fail2:
+ bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+fail1:
+ bus_dma_tag_destroy(dd->dd_dmat);
+ memset(dd, 0, sizeof(*dd));
+ return error;
+#undef DS2PHYS
+#undef ATH_DESC_4KB_BOUND_CHECK
+}
+
+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)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
+ ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
+ struct ifnet *ifp = sc->sc_ifp;
+ uint8_t *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ /* Allocate descriptors */
+ error = ath_descdma_alloc_desc(sc, dd, head, name, ds_size,
+ nbuf * ndesc);
+
+ /* Assume any errors during allocation were dealt with */
+ if (error != 0) {
+ return (error);
+ }
+
+ ds = (uint8_t *) dd->dd_desc;
+
/* allocate rx buffers */
bsize = sizeof(struct ath_buf) * nbuf;
bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
@@ -3030,8 +3350,8 @@
}
dd->dd_bufptr = bf;
- STAILQ_INIT(head);
- for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) {
+ TAILQ_INIT(head);
+ 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)) {
@@ -3041,7 +3361,7 @@
* in the descriptor.
*/
if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr,
- desc_len * ndesc)) {
+ dd->dd_descsize)) {
/* Start at the next page */
ds += 0x1000 - (bf->bf_daddr & 0xFFF);
bf->bf_desc = (struct ath_desc *) ds;
@@ -3056,16 +3376,20 @@
ath_descdma_cleanup(sc, dd, head);
return error;
}
- STAILQ_INSERT_TAIL(head, bf, bf_list);
+ bf->bf_lastds = bf->bf_desc; /* Just an initial value */
+ TAILQ_INSERT_TAIL(head, bf, bf_list);
}
+
+ /*
+ * XXX TODO: ensure that ds doesn't overflow the descriptor
+ * allocation otherwise weird stuff will occur and crash your
+ * machine.
+ */
return 0;
+ /* XXX this should likely just call ath_descdma_cleanup() */
fail3:
bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
-fail2:
bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
-fail1:
- bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
-fail0:
bus_dma_tag_destroy(dd->dd_dmat);
memset(dd, 0, sizeof(*dd));
return error;
@@ -3073,39 +3397,126 @@
#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;
+ int do_warning = 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);
+ 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_dma_tag_destroy(dd->dd_dmat);
+ }
- STAILQ_FOREACH(bf, head, bf_list) {
- if (bf->bf_m) {
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
+ if (head != NULL) {
+ TAILQ_FOREACH(bf, head, bf_list) {
+ if (bf->bf_m) {
+ /*
+ * XXX warn if there's buffers here.
+ * XXX it should have been freed by the
+ * owner!
+ */
+
+ if (do_warning == 0) {
+ do_warning = 1;
+ device_printf(sc->sc_dev,
+ "%s: %s: mbuf should've been"
+ " unmapped/freed!\n",
+ __func__,
+ dd->dd_name);
+ }
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_dmamap != NULL) {
+ bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
+ bf->bf_dmamap = NULL;
+ }
+ ni = bf->bf_node;
+ bf->bf_node = NULL;
+ if (ni != NULL) {
+ /*
+ * Reclaim node reference.
+ */
+ ieee80211_free_node(ni);
+ }
}
- if (bf->bf_dmamap != NULL) {
- bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
- bf->bf_dmamap = NULL;
- }
- ni = bf->bf_node;
- bf->bf_node = NULL;
- if (ni != NULL) {
- /*
- * Reclaim node reference.
- */
- ieee80211_free_node(ni);
- }
}
- STAILQ_INIT(head);
- free(dd->dd_bufptr, M_ATHDEV);
+ if (head != NULL)
+ TAILQ_INIT(head);
+
+ if (dd->dd_bufptr != NULL)
+ free(dd->dd_bufptr, M_ATHDEV);
memset(dd, 0, sizeof(*dd));
}
@@ -3114,23 +3525,32 @@
{
int error;
- error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
- "rx", ath_rxbuf, 1);
- if (error != 0)
+ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+ "tx", sc->sc_tx_desclen, ath_txbuf, ATH_MAX_SCATTER);
+ if (error != 0) {
return error;
+ }
+ sc->sc_txbuf_cnt = ath_txbuf;
- error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
- "tx", ath_txbuf, ATH_TXDESC);
+ 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_rxdma, &sc->sc_rxbuf);
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
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", ATH_BCBUF, 1);
+ "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_rxdma, &sc->sc_rxbuf);
+ ath_descdma_cleanup(sc, &sc->sc_txdma_mgmt,
+ &sc->sc_txbuf_mgmt);
return error;
}
return 0;
@@ -3144,8 +3564,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 *
@@ -3163,19 +3584,42 @@
}
ath_rate_node_init(sc, an);
- DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an);
+ /* Setup the mutex - there's no associd yet so set the name to NULL */
+ snprintf(an->an_name, sizeof(an->an_name), "%s: node %p",
+ device_get_nameunit(sc->sc_dev), an);
+ mtx_init(&an->an_mtx, an->an_name, NULL, MTX_DEF);
+
+ /* XXX setup ath_tid */
+ ath_tx_tid_init(sc, an);
+
+ DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: an %p\n", __func__, mac, ":", an);
return &an->an_node;
}
static void
-ath_node_free(struct ieee80211_node *ni)
+ath_node_cleanup(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
- DPRINTF(sc, ATH_DEBUG_NODE, "%s: ni %p\n", __func__, ni);
+ DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: an %p\n", __func__,
+ ni->ni_macaddr, ":", ATH_NODE(ni));
+ /* Cleanup ath_tid, free unused bufs, unlink bufs in TXQ */
+ ath_tx_node_flush(sc, ATH_NODE(ni));
ath_rate_node_cleanup(sc, ATH_NODE(ni));
+ sc->sc_node_cleanup(ni);
+}
+
+static void
+ath_node_free(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+
+ DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: an %p\n", __func__,
+ ni->ni_macaddr, ":", ATH_NODE(ni));
+ mtx_destroy(&ATH_NODE(ni)->an_mtx);
sc->sc_node_free(ni);
}
@@ -3193,196 +3637,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 */
- 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;
@@ -3396,458 +3654,18 @@
}
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);
- }
-}
-
-static void
-ath_rx_proc(void *arg, int npending)
-{
-#define PA2DESC(_sc, _pa) \
- ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
- ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
- struct ath_softc *sc = arg;
- 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;
-
- DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending);
- ngood = 0;
- nf = ath_hal_getchannoise(ah, sc->sc_curchan);
- sc->sc_stats.ast_rx_noise = nf;
- tsf = ath_hal_gettsf64(ah);
- do {
- bf = STAILQ_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__);
- STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, 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;
- STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
-
- /* These aren't specifically errors */
- 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++;
-
- 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 *), tsf, 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;
- ath_rx_tap(ifp, m, rs, tsf, nf);
- ieee80211_radiotap_rx_all(ic, 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;
- }
-
- 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, tsf, 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;
-
- if (rs->rs_isaggr)
- sc->sc_stats.ast_rx_agg++;
-
- 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:
- STAILQ_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;
-
- /* Queue DFS tasklet if needed */
- if (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.
- */
- if (sc->sc_kickpcu) {
- sc->sc_kickpcu = 0;
- ath_stoprecv(sc);
- sc->sc_imask |= (HAL_INT_RXEOL | HAL_INT_RXORN);
- if (ath_startrecv(sc) != 0) {
- if_printf(ifp,
- "%s: couldn't restart RX after RXEOL; resetting\n",
- __func__);
- ath_reset(ifp);
- return;
- }
- ath_hal_intrset(ah, sc->sc_imask);
- }
-
- 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_start(ifp);
- }
-#undef PA2DESC
-}
-
-static void
ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum)
{
txq->axq_qnum = qnum;
txq->axq_ac = 0;
txq->axq_depth = 0;
+ txq->axq_aggr_depth = 0;
txq->axq_intrcnt = 0;
txq->axq_link = NULL;
- STAILQ_INIT(&txq->axq_q);
+ txq->axq_softc = sc;
+ TAILQ_INIT(&txq->axq_q);
+ TAILQ_INIT(&txq->axq_tidq);
+ TAILQ_INIT(&txq->fifo.axq_q);
ATH_TXQ_LOCK_INIT(sc, txq);
}
@@ -3879,7 +3697,13 @@
* up in which case the top half of the kernel may backup
* due to a lack of tx descriptors.
*/
- qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE;
+ if (sc->sc_isedma)
+ qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE |
+ HAL_TXQ_TXOKINT_ENABLE;
+ else
+ qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE |
+ HAL_TXQ_TXDESCINT_ENABLE;
+
qnum = ath_hal_setuptxqueue(ah, qtype, &qi);
if (qnum == -1) {
/*
@@ -3973,10 +3797,15 @@
qi.tqi_burstTime = qi.tqi_readyTime;
} else {
#endif
+ /*
+ * XXX shouldn't this just use the default flags
+ * used in the previous queue setup?
+ */
qi.tqi_qflags = HAL_TXQ_TXOKINT_ENABLE
| HAL_TXQ_TXERRINT_ENABLE
| HAL_TXQ_TXDESCINT_ENABLE
| HAL_TXQ_TXURNINT_ENABLE
+ | HAL_TXQ_TXEOLINT_ENABLE
;
qi.tqi_aifs = wmep->wmep_aifsn;
qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
@@ -4008,7 +3837,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;
@@ -4027,8 +3856,8 @@
{
ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum);
+ sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
ATH_TXQ_LOCK_DESTROY(txq);
- sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
}
/*
@@ -4057,21 +3886,218 @@
return (rix == 0xff ? 0 : rix);
}
+static void
+ath_tx_update_stats(struct ath_softc *sc, struct ath_tx_status *ts,
+ struct ath_buf *bf)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ int sr, lr, pri;
+
+ if (ts->ts_status == 0) {
+ u_int8_t txant = ts->ts_antenna;
+ sc->sc_stats.ast_ant_tx[txant]++;
+ sc->sc_ant_tx[txant]++;
+ if (ts->ts_finaltsi != 0)
+ sc->sc_stats.ast_tx_altrate++;
+ pri = M_WME_GETAC(bf->bf_m);
+ if (pri >= WME_AC_VO)
+ ic->ic_wme.wme_hipri_traffic++;
+ if ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0)
+ ni->ni_inact = ni->ni_inact_reload;
+ } else {
+ if (ts->ts_status & HAL_TXERR_XRETRY)
+ sc->sc_stats.ast_tx_xretries++;
+ if (ts->ts_status & HAL_TXERR_FIFO)
+ sc->sc_stats.ast_tx_fifoerr++;
+ if (ts->ts_status & HAL_TXERR_FILT)
+ sc->sc_stats.ast_tx_filtered++;
+ if (ts->ts_status & HAL_TXERR_XTXOP)
+ sc->sc_stats.ast_tx_xtxop++;
+ if (ts->ts_status & HAL_TXERR_TIMER_EXPIRED)
+ sc->sc_stats.ast_tx_timerexpired++;
+
+ if (bf->bf_m->m_flags & M_FF)
+ sc->sc_stats.ast_ff_txerr++;
+ }
+ /* XXX when is this valid? */
+ if (ts->ts_flags & HAL_TX_DESC_CFG_ERR)
+ sc->sc_stats.ast_tx_desccfgerr++;
+ /*
+ * This can be valid for successful frame transmission!
+ * If there's a TX FIFO underrun during aggregate transmission,
+ * the MAC will pad the rest of the aggregate with delimiters.
+ * If a BA is returned, the frame is marked as "OK" and it's up
+ * to the TX completion code to notice which frames weren't
+ * successfully transmitted.
+ */
+ if (ts->ts_flags & HAL_TX_DATA_UNDERRUN)
+ sc->sc_stats.ast_tx_data_underrun++;
+ if (ts->ts_flags & HAL_TX_DELIM_UNDERRUN)
+ sc->sc_stats.ast_tx_delim_underrun++;
+
+ sr = ts->ts_shortretry;
+ lr = ts->ts_longretry;
+ sc->sc_stats.ast_tx_shortretry += sr;
+ sc->sc_stats.ast_tx_longretry += lr;
+
+}
+
/*
+ * The default completion. If fail is 1, this means
+ * "please don't retry the frame, and just return -1 status
+ * to the net80211 stack.
+ */
+void
+ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf, int fail)
+{
+ struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
+ int st;
+
+ if (fail == 1)
+ st = -1;
+ else
+ st = ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0) ?
+ ts->ts_status : HAL_TXERR_XRETRY;
+
+#if 0
+ if (bf->bf_state.bfs_dobaw)
+ device_printf(sc->sc_dev,
+ "%s: bf %p: seqno %d: dobaw should've been cleared!\n",
+ __func__,
+ bf,
+ SEQNO(bf->bf_state.bfs_seqno));
+#endif
+ if (bf->bf_next != NULL)
+ device_printf(sc->sc_dev,
+ "%s: bf %p: seqno %d: bf_next not NULL!\n",
+ __func__,
+ bf,
+ SEQNO(bf->bf_state.bfs_seqno));
+
+ /*
+ * Check if the node software queue is empty; if so
+ * then clear the TIM.
+ *
+ * This needs to be done before the buffer is freed as
+ * otherwise the node reference will have been released
+ * and the node may not actually exist any longer.
+ *
+ * XXX I don't like this belonging here, but it's cleaner
+ * to do it here right now then all the other places
+ * where ath_tx_default_comp() is called.
+ *
+ * XXX TODO: during drain, ensure that the callback is
+ * being called so we get a chance to update the TIM.
+ */
+ if (bf->bf_node) {
+ ATH_TX_LOCK(sc);
+ ath_tx_update_tim(sc, bf->bf_node, 0);
+ ATH_TX_UNLOCK(sc);
+ }
+
+ /*
+ * Do any tx complete callback. Note this must
+ * be done before releasing the node reference.
+ * This will free the mbuf, release the net80211
+ * node and recycle the ath_buf.
+ */
+ ath_tx_freebuf(sc, bf, st);
+}
+
+/*
+ * Update rate control with the given completion status.
+ */
+void
+ath_tx_update_ratectrl(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_rc_series *rc, struct ath_tx_status *ts, int frmlen,
+ int nframes, int nbad)
+{
+ struct ath_node *an;
+
+ /* Only for unicast frames */
+ if (ni == NULL)
+ return;
+
+ an = ATH_NODE(ni);
+ ATH_NODE_UNLOCK_ASSERT(an);
+
+ if ((ts->ts_status & HAL_TXERR_FILT) == 0) {
+ ATH_NODE_LOCK(an);
+ ath_rate_tx_complete(sc, an, rc, ts, frmlen, nframes, nbad);
+ ATH_NODE_UNLOCK(an);
+ }
+}
+
+/*
+ * Process the completion of the given buffer.
+ *
+ * This calls the rate control update and then the buffer completion.
+ * This will either free the buffer or requeue it. In any case, the
+ * bf pointer should be treated as invalid after this function is called.
+ */
+void
+ath_tx_process_buf_completion(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_tx_status *ts, struct ath_buf *bf)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = NULL;
+
+ ATH_TX_UNLOCK_ASSERT(sc);
+ ATH_TXQ_UNLOCK_ASSERT(txq);
+
+ /* If unicast frame, update general statistics */
+ if (ni != NULL) {
+ an = ATH_NODE(ni);
+ /* update statistics */
+ ath_tx_update_stats(sc, ts, bf);
+ }
+
+ /*
+ * Call the completion handler.
+ * The completion handler is responsible for
+ * calling the rate control code.
+ *
+ * Frames with no completion handler get the
+ * rate control code called here.
+ */
+ if (bf->bf_comp == NULL) {
+ if ((ts->ts_status & HAL_TXERR_FILT) == 0 &&
+ (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0) {
+ /*
+ * XXX assume this isn't an aggregate
+ * frame.
+ */
+ ath_tx_update_ratectrl(sc, ni,
+ bf->bf_state.bfs_rc, ts,
+ bf->bf_state.bfs_pktlen, 1,
+ (ts->ts_status == 0 ? 0 : 1));
+ }
+ ath_tx_default_comp(sc, bf, 0);
+ } else
+ bf->bf_comp(sc, bf, 0);
+}
+
+
+
+/*
* Process completed xmit descriptors from the specified queue.
+ * Kick the packet scheduler if needed. This can occur from this
+ * particular task.
*/
static int
-ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
{
struct ath_hal *ah = sc->sc_ah;
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
- struct ath_buf *bf, *last;
- struct ath_desc *ds, *ds0;
+ struct ath_buf *bf;
+ struct ath_desc *ds;
struct ath_tx_status *ts;
struct ieee80211_node *ni;
- struct ath_node *an;
- int sr, lr, pri, nacked;
+#ifdef IEEE80211_SUPPORT_SUPERG
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+#endif /* IEEE80211_SUPPORT_SUPERG */
+ int nacked;
HAL_STATUS status;
DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n",
@@ -4078,126 +4104,118 @@
__func__, txq->axq_qnum,
(caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum),
txq->axq_link);
+
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 4,
+ "ath_tx_processq: txq=%u head %p link %p depth %p",
+ txq->axq_qnum,
+ (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link,
+ txq->axq_depth);
+
nacked = 0;
for (;;) {
ATH_TXQ_LOCK(txq);
txq->axq_intrcnt = 0; /* reset periodic desc intr count */
- bf = STAILQ_FIRST(&txq->axq_q);
+ bf = TAILQ_FIRST(&txq->axq_q);
if (bf == NULL) {
ATH_TXQ_UNLOCK(txq);
break;
}
- ds0 = &bf->bf_desc[0];
- ds = &bf->bf_desc[bf->bf_nseg - 1];
+ ds = bf->bf_lastds; /* XXX must be setup correctly! */
ts = &bf->bf_status.ds_txstat;
+
status = ath_hal_txprocdesc(ah, ds, ts);
#ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_XMIT_DESC)
ath_printtxbuf(sc, bf, txq->axq_qnum, 0,
status == HAL_OK);
+ else if ((sc->sc_debug & ATH_DEBUG_RESET) && (dosched == 0))
+ ath_printtxbuf(sc, bf, txq->axq_qnum, 0,
+ status == HAL_OK);
#endif
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq,
+ ATH_ALQ_EDMA_TXSTATUS)) {
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS,
+ sc->sc_tx_statuslen,
+ (char *) ds);
+ }
+#endif
+
if (status == HAL_EINPROGRESS) {
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 3,
+ "ath_tx_processq: txq=%u, bf=%p ds=%p, HAL_EINPROGRESS",
+ txq->axq_qnum, bf, ds);
ATH_TXQ_UNLOCK(txq);
break;
}
- ATH_TXQ_REMOVE_HEAD(txq, bf_list);
-#ifdef IEEE80211_SUPPORT_TDMA
+ ATH_TXQ_REMOVE(txq, bf, bf_list);
+
+ /*
+ * Sanity check.
+ */
+ if (txq->axq_qnum != bf->bf_state.bfs_tx_queue) {
+ device_printf(sc->sc_dev,
+ "%s: TXQ=%d: bf=%p, bfs_tx_queue=%d\n",
+ __func__,
+ txq->axq_qnum,
+ bf,
+ bf->bf_state.bfs_tx_queue);
+ }
+ if (txq->axq_qnum != bf->bf_last->bf_state.bfs_tx_queue) {
+ device_printf(sc->sc_dev,
+ "%s: TXQ=%d: bf_last=%p, bfs_tx_queue=%d\n",
+ __func__,
+ txq->axq_qnum,
+ bf->bf_last,
+ bf->bf_last->bf_state.bfs_tx_queue);
+ }
+
+#if 0
if (txq->axq_depth > 0) {
/*
* More frames follow. Mark the buffer busy
* so it's not re-used while the hardware may
* still re-read the link field in the descriptor.
+ *
+ * Use the last buffer in an aggregate as that
+ * is where the hardware may be - intermediate
+ * descriptors won't be "busy".
*/
- bf->bf_flags |= ATH_BUF_BUSY;
+ bf->bf_last->bf_flags |= ATH_BUF_BUSY;
} else
+ txq->axq_link = NULL;
#else
- if (txq->axq_depth == 0)
+ bf->bf_last->bf_flags |= ATH_BUF_BUSY;
#endif
- txq->axq_link = NULL;
- ATH_TXQ_UNLOCK(txq);
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth--;
ni = bf->bf_node;
- if (ni != NULL) {
- an = ATH_NODE(ni);
- if (ts->ts_status == 0) {
- u_int8_t txant = ts->ts_antenna;
- sc->sc_stats.ast_ant_tx[txant]++;
- sc->sc_ant_tx[txant]++;
- if (ts->ts_finaltsi != 0)
- sc->sc_stats.ast_tx_altrate++;
- pri = M_WME_GETAC(bf->bf_m);
- if (pri >= WME_AC_VO)
- ic->ic_wme.wme_hipri_traffic++;
- if ((bf->bf_txflags & HAL_TXDESC_NOACK) == 0)
- ni->ni_inact = ni->ni_inact_reload;
- } else {
- if (ts->ts_status & HAL_TXERR_XRETRY)
- sc->sc_stats.ast_tx_xretries++;
- if (ts->ts_status & HAL_TXERR_FIFO)
- sc->sc_stats.ast_tx_fifoerr++;
- if (ts->ts_status & HAL_TXERR_FILT)
- sc->sc_stats.ast_tx_filtered++;
- if (ts->ts_status & HAL_TXERR_XTXOP)
- sc->sc_stats.ast_tx_xtxop++;
- if (ts->ts_status & HAL_TXERR_TIMER_EXPIRED)
- sc->sc_stats.ast_tx_timerexpired++;
- /* XXX HAL_TX_DATA_UNDERRUN */
- /* XXX HAL_TX_DELIM_UNDERRUN */
-
- if (bf->bf_m->m_flags & M_FF)
- sc->sc_stats.ast_ff_txerr++;
- }
- /* XXX when is this valid? */
- if (ts->ts_status & HAL_TX_DESC_CFG_ERR)
- sc->sc_stats.ast_tx_desccfgerr++;
-
- sr = ts->ts_shortretry;
- lr = ts->ts_longretry;
- sc->sc_stats.ast_tx_shortretry += sr;
- sc->sc_stats.ast_tx_longretry += lr;
- /*
- * Hand the descriptor to the rate control algorithm.
- */
- if ((ts->ts_status & HAL_TXERR_FILT) == 0 &&
- (bf->bf_txflags & HAL_TXDESC_NOACK) == 0) {
- /*
- * If frame was ack'd update statistics,
- * including the last rx time used to
- * workaround phantom bmiss interrupts.
- */
- if (ts->ts_status == 0) {
- nacked++;
- sc->sc_stats.ast_tx_rssi = ts->ts_rssi;
- ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi,
- ts->ts_rssi);
- }
- ath_rate_tx_complete(sc, an, bf);
- }
- /*
- * Do any tx complete callback. Note this must
- * be done before releasing the node reference.
- */
- if (bf->bf_m->m_flags & M_TXCB)
- ieee80211_process_callback(ni, bf->bf_m,
- (bf->bf_txflags & HAL_TXDESC_NOACK) == 0 ?
- ts->ts_status : HAL_TXERR_XRETRY);
- ieee80211_free_node(ni);
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 5,
+ "ath_tx_processq: txq=%u, bf=%p, ds=%p, ni=%p, ts_status=0x%08x",
+ txq->axq_qnum, bf, ds, ni, ts->ts_status);
+ /*
+ * If unicast frame was ack'd update RSSI,
+ * including the last rx time used to
+ * workaround phantom bmiss interrupts.
+ */
+ if (ni != NULL && ts->ts_status == 0 &&
+ ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0)) {
+ nacked++;
+ sc->sc_stats.ast_tx_rssi = ts->ts_rssi;
+ ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi,
+ ts->ts_rssi);
}
- bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ ATH_TXQ_UNLOCK(txq);
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
- bf->bf_node = NULL;
+ /*
+ * Update statistics and call completion
+ */
+ ath_tx_process_buf_completion(sc, txq, ts, bf);
- ATH_TXBUF_LOCK(sc);
- last = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list);
- if (last != NULL)
- last->bf_flags &= ~ATH_BUF_BUSY;
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
+ /* XXX at this point, bf and ni may be totally invalid */
}
#ifdef IEEE80211_SUPPORT_SUPERG
/*
@@ -4206,16 +4224,22 @@
if (txq->axq_depth <= 1)
ieee80211_ff_flush(ic, txq->axq_ac);
#endif
+
+ /* Kick the software TXQ scheduler */
+ if (dosched) {
+ ATH_TX_LOCK(sc);
+ ath_txq_sched(sc, txq);
+ ATH_TX_UNLOCK(sc);
+ }
+
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 1,
+ "ath_tx_processq: txq=%u: done",
+ txq->axq_qnum);
+
return nacked;
}
-static __inline int
-txqactive(struct ath_hal *ah, int qnum)
-{
- u_int32_t txqs = 1<<qnum;
- ath_hal_gettxintrtxqs(ah, &txqs);
- return (txqs & (1<<qnum));
-}
+#define TXQACTIVE(t, q) ( (t) & (1 << (q)))
/*
* Deferred processing of transmit interrupt; special-cased
@@ -4226,18 +4250,35 @@
{
struct ath_softc *sc = arg;
struct ifnet *ifp = sc->sc_ifp;
+ uint32_t txqs;
- if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0]))
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt++;
+ txqs = sc->sc_txq_active;
+ sc->sc_txq_active &= ~txqs;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 1,
+ "ath_tx_proc_q0: txqs=0x%08x", txqs);
+
+ if (TXQACTIVE(txqs, 0) && ath_tx_processq(sc, &sc->sc_txq[0], 1))
+ /* XXX why is lastrx updated in tx code? */
sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah);
- if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
- ath_tx_processq(sc, sc->sc_cabq);
+ if (TXQACTIVE(txqs, sc->sc_cabq->axq_qnum))
+ ath_tx_processq(sc, sc->sc_cabq, 1);
+ IF_LOCK(&ifp->if_snd);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
sc->sc_wd_timer = 0;
if (sc->sc_softled)
ath_led_event(sc, sc->sc_txrix);
- ath_start(ifp);
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+
+ ath_tx_kick(sc);
}
/*
@@ -4250,31 +4291,47 @@
struct ath_softc *sc = arg;
struct ifnet *ifp = sc->sc_ifp;
int nacked;
+ uint32_t txqs;
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt++;
+ txqs = sc->sc_txq_active;
+ sc->sc_txq_active &= ~txqs;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 1,
+ "ath_tx_proc_q0123: txqs=0x%08x", txqs);
+
/*
* Process each active queue.
*/
nacked = 0;
- if (txqactive(sc->sc_ah, 0))
- nacked += ath_tx_processq(sc, &sc->sc_txq[0]);
- if (txqactive(sc->sc_ah, 1))
- nacked += ath_tx_processq(sc, &sc->sc_txq[1]);
- if (txqactive(sc->sc_ah, 2))
- nacked += ath_tx_processq(sc, &sc->sc_txq[2]);
- if (txqactive(sc->sc_ah, 3))
- nacked += ath_tx_processq(sc, &sc->sc_txq[3]);
- if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
- ath_tx_processq(sc, sc->sc_cabq);
+ if (TXQACTIVE(txqs, 0))
+ nacked += ath_tx_processq(sc, &sc->sc_txq[0], 1);
+ if (TXQACTIVE(txqs, 1))
+ nacked += ath_tx_processq(sc, &sc->sc_txq[1], 1);
+ if (TXQACTIVE(txqs, 2))
+ nacked += ath_tx_processq(sc, &sc->sc_txq[2], 1);
+ if (TXQACTIVE(txqs, 3))
+ nacked += ath_tx_processq(sc, &sc->sc_txq[3], 1);
+ if (TXQACTIVE(txqs, sc->sc_cabq->axq_qnum))
+ ath_tx_processq(sc, sc->sc_cabq, 1);
if (nacked)
sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah);
+ IF_LOCK(&ifp->if_snd);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
sc->sc_wd_timer = 0;
if (sc->sc_softled)
ath_led_event(sc, sc->sc_txrix);
- ath_start(ifp);
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+
+ ath_tx_kick(sc);
}
/*
@@ -4286,33 +4343,310 @@
struct ath_softc *sc = arg;
struct ifnet *ifp = sc->sc_ifp;
int i, nacked;
+ uint32_t txqs;
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt++;
+ txqs = sc->sc_txq_active;
+ sc->sc_txq_active &= ~txqs;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc: txqs=0x%08x", txqs);
+
/*
* Process each active queue.
*/
nacked = 0;
for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i))
- nacked += ath_tx_processq(sc, &sc->sc_txq[i]);
+ if (ATH_TXQ_SETUP(sc, i) && TXQACTIVE(txqs, i))
+ nacked += ath_tx_processq(sc, &sc->sc_txq[i], 1);
if (nacked)
sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah);
+ /* XXX check this inside of IF_LOCK? */
+ IF_LOCK(&ifp->if_snd);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
sc->sc_wd_timer = 0;
if (sc->sc_softled)
ath_led_event(sc, sc->sc_txrix);
- ath_start(ifp);
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+
+ ath_tx_kick(sc);
}
+#undef TXQACTIVE
+/*
+ * Deferred processing of TXQ rescheduling.
+ */
static void
+ath_txq_sched_tasklet(void *arg, int npending)
+{
+ struct ath_softc *sc = arg;
+ int i;
+
+ /* XXX is skipping ok? */
+ ATH_PCU_LOCK(sc);
+#if 0
+ if (sc->sc_inreset_cnt > 0) {
+ device_printf(sc->sc_dev,
+ "%s: sc_inreset_cnt > 0; skipping\n", __func__);
+ ATH_PCU_UNLOCK(sc);
+ return;
+ }
+#endif
+ sc->sc_txproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_TX_LOCK(sc);
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ ath_txq_sched(sc, &sc->sc_txq[i]);
+ }
+ }
+ ATH_TX_UNLOCK(sc);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_txproc_cnt--;
+ 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;
+ }
+ }
+}
+
+/*
+ * Free the holding buffer if it exists
+ */
+void
+ath_txq_freeholdingbuf(struct ath_softc *sc, struct ath_txq *txq)
+{
+ ATH_TXBUF_UNLOCK_ASSERT(sc);
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ if (txq->axq_holdingbf == NULL)
+ return;
+
+ txq->axq_holdingbf->bf_flags &= ~ATH_BUF_BUSY;
+
+ ATH_TXBUF_LOCK(sc);
+ ath_returnbuf_tail(sc, txq->axq_holdingbf);
+ ATH_TXBUF_UNLOCK(sc);
+
+ txq->axq_holdingbf = NULL;
+}
+
+/*
+ * Add this buffer to the holding queue, freeing the previous
+ * one if it exists.
+ */
+static void
+ath_txq_addholdingbuf(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_txq *txq;
+
+ txq = &sc->sc_txq[bf->bf_state.bfs_tx_queue];
+
+ ATH_TXBUF_UNLOCK_ASSERT(sc);
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ /* XXX assert ATH_BUF_BUSY is set */
+
+ /* XXX assert the tx queue is under the max number */
+ if (bf->bf_state.bfs_tx_queue > HAL_NUM_TX_QUEUES) {
+ device_printf(sc->sc_dev, "%s: bf=%p: invalid tx queue (%d)\n",
+ __func__,
+ bf,
+ bf->bf_state.bfs_tx_queue);
+ bf->bf_flags &= ~ATH_BUF_BUSY;
+ ath_returnbuf_tail(sc, bf);
+ return;
+ }
+ ath_txq_freeholdingbuf(sc, txq);
+ txq->axq_holdingbf = bf;
+}
+
+/*
+ * Return a buffer to the pool and update the 'busy' flag on the
+ * previous 'tail' entry.
+ *
+ * This _must_ only be called when the buffer is involved in a completed
+ * TX. The logic is that if it was part of an active TX, the previous
+ * buffer on the list is now not involved in a halted TX DMA queue, waiting
+ * for restart (eg for TDMA.)
+ *
+ * The caller must free the mbuf and recycle the node reference.
+ *
+ * XXX This method of handling busy / holding buffers is insanely stupid.
+ * It requires bf_state.bfs_tx_queue to be correctly assigned. It would
+ * be much nicer if buffers in the processq() methods would instead be
+ * always completed there (pushed onto a txq or ath_bufhead) so we knew
+ * exactly what hardware queue they came from in the first place.
+ */
+void
+ath_freebuf(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_txq *txq;
+
+ txq = &sc->sc_txq[bf->bf_state.bfs_tx_queue];
+
+ KASSERT((bf->bf_node == NULL), ("%s: bf->bf_node != NULL\n", __func__));
+ KASSERT((bf->bf_m == NULL), ("%s: bf->bf_m != NULL\n", __func__));
+
+ /*
+ * If this buffer is busy, push it onto the holding queue.
+ */
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ ATH_TXQ_LOCK(txq);
+ ath_txq_addholdingbuf(sc, bf);
+ ATH_TXQ_UNLOCK(txq);
+ return;
+ }
+
+ /*
+ * Not a busy buffer, so free normally
+ */
+ ATH_TXBUF_LOCK(sc);
+ ath_returnbuf_tail(sc, bf);
+ ATH_TXBUF_UNLOCK(sc);
+}
+
+/*
+ * This is currently used by ath_tx_draintxq() and
+ * ath_tx_tid_free_pkts().
+ *
+ * It recycles a single ath_buf.
+ */
+void
+ath_tx_freebuf(struct ath_softc *sc, struct ath_buf *bf, int status)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct mbuf *m0 = bf->bf_m;
+
+ /*
+ * Make sure that we only sync/unload if there's an mbuf.
+ * If not (eg we cloned a buffer), the unload will have already
+ * occured.
+ */
+ if (bf->bf_m != NULL) {
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ }
+
+ bf->bf_node = NULL;
+ bf->bf_m = NULL;
+
+ /* Free the buffer, it's not needed any longer */
+ ath_freebuf(sc, bf);
+
+ /* Pass the buffer back to net80211 - completing it */
+ ieee80211_tx_complete(ni, m0, status);
+}
+
+static struct ath_buf *
+ath_tx_draintxq_get_one(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_buf *bf;
+
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ /*
+ * Drain the FIFO queue first, then if it's
+ * empty, move to the normal frame queue.
+ */
+ bf = TAILQ_FIRST(&txq->fifo.axq_q);
+ if (bf != NULL) {
+ /*
+ * Is it the last buffer in this set?
+ * Decrement the FIFO counter.
+ */
+ if (bf->bf_flags & ATH_BUF_FIFOEND) {
+ if (txq->axq_fifo_depth == 0) {
+ device_printf(sc->sc_dev,
+ "%s: Q%d: fifo_depth=0, fifo.axq_depth=%d?\n",
+ __func__,
+ txq->axq_qnum,
+ txq->fifo.axq_depth);
+ } else
+ txq->axq_fifo_depth--;
+ }
+ ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list);
+ return (bf);
+ }
+
+ /*
+ * Debugging!
+ */
+ if (txq->axq_fifo_depth != 0 || txq->fifo.axq_depth != 0) {
+ device_printf(sc->sc_dev,
+ "%s: Q%d: fifo_depth=%d, fifo.axq_depth=%d\n",
+ __func__,
+ txq->axq_qnum,
+ txq->axq_fifo_depth,
+ txq->fifo.axq_depth);
+ }
+
+ /*
+ * Now drain the pending queue.
+ */
+ bf = TAILQ_FIRST(&txq->axq_q);
+ if (bf == NULL) {
+ txq->axq_link = NULL;
+ return (NULL);
+ }
+ ATH_TXQ_REMOVE(txq, bf, bf_list);
+ return (bf);
+}
+
+void
ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
{
#ifdef ATH_DEBUG
struct ath_hal *ah = sc->sc_ah;
#endif
- struct ieee80211_node *ni;
struct ath_buf *bf;
u_int ix;
@@ -4320,51 +4654,65 @@
* NB: this assumes output has been stopped and
* we do not need to block ath_tx_proc
*/
- ATH_TXBUF_LOCK(sc);
- bf = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list);
- if (bf != NULL)
- bf->bf_flags &= ~ATH_BUF_BUSY;
- ATH_TXBUF_UNLOCK(sc);
for (ix = 0;; ix++) {
ATH_TXQ_LOCK(txq);
- bf = STAILQ_FIRST(&txq->axq_q);
+ bf = ath_tx_draintxq_get_one(sc, txq);
if (bf == NULL) {
- txq->axq_link = NULL;
ATH_TXQ_UNLOCK(txq);
break;
}
- ATH_TXQ_REMOVE_HEAD(txq, bf_list);
- ATH_TXQ_UNLOCK(txq);
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth--;
#ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RESET) {
struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ int status = 0;
- ath_printtxbuf(sc, bf, txq->axq_qnum, ix,
- ath_hal_txprocdesc(ah, bf->bf_desc,
+ /*
+ * EDMA operation has a TX completion FIFO
+ * separate from the TX descriptor, so this
+ * method of checking the "completion" status
+ * is wrong.
+ */
+ if (! sc->sc_isedma) {
+ status = (ath_hal_txprocdesc(ah,
+ bf->bf_lastds,
&bf->bf_status.ds_txstat) == HAL_OK);
+ }
+ ath_printtxbuf(sc, bf, txq->axq_qnum, ix, status);
ieee80211_dump_pkt(ic, mtod(bf->bf_m, const uint8_t *),
bf->bf_m->m_len, 0, -1);
}
#endif /* ATH_DEBUG */
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- ni = bf->bf_node;
- bf->bf_node = NULL;
- if (ni != NULL) {
- /*
- * Do any callback and reclaim the node reference.
- */
- if (bf->bf_m->m_flags & M_TXCB)
- ieee80211_process_callback(ni, bf->bf_m, -1);
- ieee80211_free_node(ni);
- }
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
+ /*
+ * Since we're now doing magic in the completion
+ * functions, we -must- call it for aggregation
+ * destinations or BAW tracking will get upset.
+ */
+ /*
+ * Clear ATH_BUF_BUSY; the completion handler
+ * will free the buffer.
+ */
+ ATH_TXQ_UNLOCK(txq);
bf->bf_flags &= ~ATH_BUF_BUSY;
+ if (bf->bf_comp)
+ bf->bf_comp(sc, bf, 1);
+ else
+ ath_tx_default_comp(sc, bf, 1);
+ }
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
- }
+ /*
+ * Free the holding buffer if it exists
+ */
+ ATH_TXQ_LOCK(txq);
+ ath_txq_freeholdingbuf(sc, txq);
+ ATH_TXQ_UNLOCK(txq);
+
+ /*
+ * Drain software queued frames which are on
+ * active TIDs.
+ */
+ ath_tx_txq_drain(sc, txq);
}
static void
@@ -4372,24 +4720,42 @@
{
struct ath_hal *ah = sc->sc_ah;
- DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n",
- __func__, txq->axq_qnum,
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: tx queue [%u] %p, active=%d, hwpending=%d, flags 0x%08x, "
+ "link %p, holdingbf=%p\n",
+ __func__,
+ txq->axq_qnum,
(caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, txq->axq_qnum),
- txq->axq_link);
+ (int) (!! ath_hal_txqenabled(ah, txq->axq_qnum)),
+ (int) ath_hal_numtxpending(ah, txq->axq_qnum),
+ txq->axq_flags,
+ txq->axq_link,
+ txq->axq_holdingbf);
+
(void) ath_hal_stoptxdma(ah, txq->axq_qnum);
+ /* We've stopped TX DMA, so mark this as stopped. */
+ txq->axq_flags &= ~ATH_TXQ_PUTRUNNING;
+
+#ifdef ATH_DEBUG
+ if ((sc->sc_debug & ATH_DEBUG_RESET)
+ && (txq->axq_holdingbf != NULL)) {
+ ath_printtxbuf(sc, txq->axq_holdingbf, txq->axq_qnum, 0, 0);
+ }
+#endif
}
-/*
- * Drain the transmit queues and reclaim resources.
- */
-static void
-ath_draintxq(struct ath_softc *sc)
+int
+ath_stoptxdma(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
- struct ifnet *ifp = sc->sc_ifp;
int i;
/* XXX return value */
+ if (sc->sc_invalid)
+ return 0;
+
if (!sc->sc_invalid) {
/* don't touch the hardware if marked invalid */
DPRINTF(sc, ATH_DEBUG_RESET, "%s: tx queue [%u] %p, link %p\n",
@@ -4396,100 +4762,118 @@
__func__, sc->sc_bhalq,
(caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq),
NULL);
+
+ /* stop the beacon queue */
(void) ath_hal_stoptxdma(ah, sc->sc_bhalq);
- for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
+
+ /* Stop the data queues */
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ ATH_TXQ_LOCK(&sc->sc_txq[i]);
ath_tx_stopdma(sc, &sc->sc_txq[i]);
- }
- for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_draintxq(sc, &sc->sc_txq[i]);
-#ifdef ATH_DEBUG
- if (sc->sc_debug & ATH_DEBUG_RESET) {
- struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf);
- if (bf != NULL && bf->bf_m != NULL) {
- ath_printtxbuf(sc, bf, sc->sc_bhalq, 0,
- ath_hal_txprocdesc(ah, bf->bf_desc,
- &bf->bf_status.ds_txstat) == HAL_OK);
- ieee80211_dump_pkt(ifp->if_l2com,
- mtod(bf->bf_m, const uint8_t *), bf->bf_m->m_len,
- 0, -1);
+ ATH_TXQ_UNLOCK(&sc->sc_txq[i]);
+ }
}
}
-#endif /* ATH_DEBUG */
- ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- sc->sc_wd_timer = 0;
+
+ return 1;
}
-/*
- * Disable the receive h/w in preparation for a reset.
- */
-static void
-ath_stoprecv(struct ath_softc *sc)
+#ifdef ATH_DEBUG
+void
+ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq)
{
-#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;
+ struct ath_buf *bf;
+ int i = 0;
- ath_hal_stoppcurecv(ah); /* disable PCU */
- ath_hal_setrxfilter(ah, 0); /* clear recv filter */
- ath_hal_stopdmarecv(ah); /* disable DMA engine */
- 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;
+ if (! (sc->sc_debug & ATH_DEBUG_RESET))
+ return;
- printf("%s: rx queue %p, link %p\n", __func__,
- (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink);
- ix = 0;
- STAILQ_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++;
- }
+ device_printf(sc->sc_dev, "%s: Q%d: begin\n",
+ __func__, txq->axq_qnum);
+ TAILQ_FOREACH(bf, &txq->axq_q, bf_list) {
+ ath_printtxbuf(sc, bf, txq->axq_qnum, i,
+ ath_hal_txprocdesc(ah, bf->bf_lastds,
+ &bf->bf_status.ds_txstat) == HAL_OK);
+ i++;
}
-#endif
- if (sc->sc_rxpending != NULL) {
- m_freem(sc->sc_rxpending);
- sc->sc_rxpending = NULL;
- }
- sc->sc_rxlink = NULL; /* just in case */
-#undef PA2DESC
+ device_printf(sc->sc_dev, "%s: Q%d: end\n",
+ __func__, txq->axq_qnum);
}
+#endif /* ATH_DEBUG */
/*
- * Enable the receive h/w following a reset.
+ * Drain the transmit queues and reclaim resources.
*/
-static int
-ath_startrecv(struct ath_softc *sc)
+void
+ath_legacy_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type)
{
struct ath_hal *ah = sc->sc_ah;
- struct ath_buf *bf;
+ struct ifnet *ifp = sc->sc_ifp;
+ int i;
+ struct ath_buf *bf_last;
- sc->sc_rxlink = NULL;
- sc->sc_rxpending = NULL;
- STAILQ_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;
+ (void) ath_stoptxdma(sc);
+
+ /*
+ * Dump the queue contents
+ */
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ /*
+ * XXX TODO: should we just handle the completed TX frames
+ * here, whether or not the reset is a full one or not?
+ */
+ if (ATH_TXQ_SETUP(sc, i)) {
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RESET)
+ ath_tx_dump(sc, &sc->sc_txq[i]);
+#endif /* ATH_DEBUG */
+ if (reset_type == ATH_RESET_NOLOSS) {
+ ath_tx_processq(sc, &sc->sc_txq[i], 0);
+ ATH_TXQ_LOCK(&sc->sc_txq[i]);
+ /*
+ * Free the holding buffer; DMA is now
+ * stopped.
+ */
+ ath_txq_freeholdingbuf(sc, &sc->sc_txq[i]);
+ /*
+ * Setup the link pointer to be the
+ * _last_ buffer/descriptor in the list.
+ * If there's nothing in the list, set it
+ * to NULL.
+ */
+ bf_last = ATH_TXQ_LAST(&sc->sc_txq[i],
+ axq_q_s);
+ if (bf_last != NULL) {
+ ath_hal_gettxdesclinkptr(ah,
+ bf_last->bf_lastds,
+ &sc->sc_txq[i].axq_link);
+ } else {
+ sc->sc_txq[i].axq_link = NULL;
+ }
+ ATH_TXQ_UNLOCK(&sc->sc_txq[i]);
+ } else
+ ath_tx_draintxq(sc, &sc->sc_txq[i]);
}
}
-
- bf = STAILQ_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;
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RESET) {
+ struct ath_buf *bf = TAILQ_FIRST(&sc->sc_bbuf);
+ if (bf != NULL && bf->bf_m != NULL) {
+ ath_printtxbuf(sc, bf, sc->sc_bhalq, 0,
+ ath_hal_txprocdesc(ah, bf->bf_lastds,
+ &bf->bf_status.ds_txstat) == HAL_OK);
+ ieee80211_dump_pkt(ifp->if_l2com,
+ mtod(bf->bf_m, const uint8_t *), bf->bf_m->m_len,
+ 0, -1);
+ }
+ }
+#endif /* ATH_DEBUG */
+ IF_LOCK(&ifp->if_snd);
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
+ sc->sc_wd_timer = 0;
}
/*
@@ -4522,7 +4906,30 @@
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
+ int ret = 0;
+ /* Treat this as an interface reset */
+ ATH_PCU_UNLOCK_ASSERT(sc);
+ ATH_UNLOCK_ASSERT(sc);
+
+ /* (Try to) stop TX/RX from occuring */
+ taskqueue_block(sc->sc_tq);
+
+ ATH_PCU_LOCK(sc);
+
+ /* Stop new RX/TX/interrupt completion */
+ if (ath_reset_grablock(sc, 1) == 0) {
+ device_printf(sc->sc_dev, "%s: concurrent reset! Danger!\n",
+ __func__);
+ }
+
+ ath_hal_intrset(ah, 0);
+
+ /* Stop pending RX/TX completion */
+ ath_txrx_stop_locked(sc);
+
+ ATH_PCU_UNLOCK(sc);
+
DPRINTF(sc, ATH_DEBUG_RESET, "%s: %u (%u MHz, flags 0x%x)\n",
__func__, ieee80211_chan2ieee(ic, chan),
chan->ic_freq, chan->ic_flags);
@@ -4534,28 +4941,62 @@
* hardware at the new frequency, and then re-enable
* the relevant bits of the h/w.
*/
+#if 0
ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc); /* clear pending tx frames */
- ath_stoprecv(sc); /* turn off frame recv */
+#endif
+ ath_stoprecv(sc, 1); /* turn off frame recv */
+ /*
+ * First, handle completed TX/RX frames.
+ */
+ ath_rx_flush(sc);
+ ath_draintxq(sc, ATH_RESET_NOLOSS);
+ /*
+ * Next, flush the non-scheduled frames.
+ */
+ ath_draintxq(sc, ATH_RESET_FULL); /* clear pending tx frames */
+
+ ath_update_chainmasks(sc, chan);
+ ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask,
+ sc->sc_cur_rxchainmask);
if (!ath_hal_reset(ah, sc->sc_opmode, chan, AH_TRUE, &status)) {
if_printf(ifp, "%s: unable to reset "
"channel %u (%u MHz, flags 0x%x), hal status %u\n",
__func__, ieee80211_chan2ieee(ic, chan),
chan->ic_freq, chan->ic_flags, status);
- return EIO;
+ ret = EIO;
+ goto finish;
}
sc->sc_diversity = ath_hal_getdiversity(ah);
/* Let DFS at it in case it's a DFS channel */
- ath_dfs_radar_enable(sc, ic->ic_curchan);
+ ath_dfs_radar_enable(sc, chan);
+ /* Let spectral at in case spectral is enabled */
+ ath_spectral_enable(sc, chan);
+
/*
+ * Let bluetooth coexistence at in case it's needed for this
+ * channel
+ */
+ ath_btcoex_enable(sc, ic->ic_curchan);
+
+ /*
+ * If we're doing TDMA, enforce the TXOP limitation for chips
+ * that support it.
+ */
+ if (sc->sc_hasenforcetxop && sc->sc_tdma)
+ ath_hal_setenforcetxop(sc->sc_ah, 1);
+ else
+ ath_hal_setenforcetxop(sc->sc_ah, 0);
+
+ /*
* Re-enable rx framework.
*/
if (ath_startrecv(sc) != 0) {
if_printf(ifp, "%s: unable to restart recv logic\n",
__func__);
- return EIO;
+ ret = EIO;
+ goto finish;
}
/*
@@ -4580,9 +5021,25 @@
/*
* Re-enable interrupts.
*/
+#if 0
ath_hal_intrset(ah, sc->sc_imask);
+#endif
}
- return 0;
+
+finish:
+ ATH_PCU_LOCK(sc);
+ sc->sc_inreset_cnt--;
+ /* XXX only do this if sc_inreset_cnt == 0? */
+ ath_hal_intrset(ah, sc->sc_imask);
+ ATH_PCU_UNLOCK(sc);
+
+ IF_LOCK(&ifp->if_snd);
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
+ ath_txrx_start(sc);
+ /* XXX ath_start? */
+
+ return ret;
}
/*
@@ -4596,7 +5053,7 @@
struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
- HAL_BOOL longCal, isCalDone = AH_FALSE;
+ HAL_BOOL longCal, isCalDone = AH_TRUE;
HAL_BOOL aniCal, shortCal = AH_FALSE;
int nextcal;
@@ -4625,7 +5082,11 @@
DPRINTF(sc, ATH_DEBUG_CALIBRATE,
"%s: rfgain change\n", __func__);
sc->sc_stats.ast_per_rfgain++;
- ath_reset(ifp);
+ sc->sc_resetcal = 0;
+ sc->sc_doresetcal = AH_TRUE;
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_resettask);
+ callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc);
+ return;
}
/*
* If this long cal is after an idle period, then
@@ -4642,6 +5103,7 @@
/* Only call if we're doing a short/long cal, not for ANI calibration */
if (shortCal || longCal) {
+ isCalDone = AH_FALSE;
if (ath_hal_calibrateN(ah, sc->sc_curchan, longCal, &isCalDone)) {
if (longCal) {
/*
@@ -4707,11 +5169,16 @@
/* XXX calibration timer? */
+ ATH_LOCK(sc);
sc->sc_scanning = 1;
sc->sc_syncbeacon = 0;
rfilt = ath_calcrxfilter(sc);
+ ATH_UNLOCK(sc);
+
+ ATH_PCU_LOCK(sc);
ath_hal_setrxfilter(ah, rfilt);
ath_hal_setassocid(ah, ifp->if_broadcastaddr, 0);
+ ATH_PCU_UNLOCK(sc);
DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0\n",
__func__, rfilt, ether_sprintf(ifp->if_broadcastaddr));
@@ -4725,12 +5192,17 @@
struct ath_hal *ah = sc->sc_ah;
u_int32_t rfilt;
+ ATH_LOCK(sc);
sc->sc_scanning = 0;
rfilt = ath_calcrxfilter(sc);
+ ATH_UNLOCK(sc);
+
+ ATH_PCU_LOCK(sc);
ath_hal_setrxfilter(ah, rfilt);
ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid);
ath_hal_process_noisefloor(ah);
+ ATH_PCU_UNLOCK(sc);
DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n",
__func__, rfilt, ether_sprintf(sc->sc_curbssid),
@@ -4737,7 +5209,34 @@
sc->sc_curaid);
}
+#ifdef ATH_ENABLE_11N
+/*
+ * For now, just do a channel change.
+ *
+ * Later, we'll go through the hard slog of suspending tx/rx, changing rate
+ * control state and resetting the hardware without dropping frames out
+ * of the queue.
+ *
+ * The unfortunate trouble here is making absolutely sure that the
+ * channel width change has propagated enough so the hardware
+ * absolutely isn't handed bogus frames for it's current operating
+ * mode. (Eg, 40MHz frames in 20MHz mode.) Since TX and RX can and
+ * does occur in parallel, we need to make certain we've blocked
+ * any further ongoing TX (and RX, that can cause raw TX)
+ * before we do this.
+ */
static void
+ath_update_chw(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, ATH_DEBUG_STATE, "%s: called\n", __func__);
+ ath_set_channel(ic);
+}
+#endif /* ATH_ENABLE_11N */
+
+static void
ath_set_channel(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
@@ -4750,8 +5249,10 @@
* beacon timers. Note that since we only hear beacons in
* sta/ibss mode this has no effect in other operating modes.
*/
+ ATH_LOCK(sc);
if (!sc->sc_scanning && ic->ic_curchan == ic->ic_bsschan)
sc->sc_syncbeacon = 1;
+ ATH_UNLOCK(sc);
}
/*
@@ -4783,6 +5284,7 @@
int i, error, stamode;
u_int32_t rfilt;
int csa_run_transition = 0;
+
static const HAL_LED_STATE leds[] = {
HAL_LED_INIT, /* IEEE80211_S_INIT */
HAL_LED_SCAN, /* IEEE80211_S_SCAN */
@@ -4798,6 +5300,15 @@
ieee80211_state_name[vap->iv_state],
ieee80211_state_name[nstate]);
+ /*
+ * net80211 _should_ have the comlock asserted at this point.
+ * There are some comments around the calls to vap->iv_newstate
+ * which indicate that it (newstate) may end up dropping the
+ * lock. This and the subsequent lock assert check after newstate
+ * are an attempt to catch these and figure out how/why.
+ */
+ IEEE80211_LOCK_ASSERT(ic);
+
if (vap->iv_state == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN)
csa_run_transition = 1;
@@ -4818,7 +5329,7 @@
taskqueue_unblock(sc->sc_tq);
}
- ni = vap->iv_bss;
+ ni = ieee80211_ref_node(vap->iv_bss);
rfilt = ath_calcrxfilter(sc);
stamode = (vap->iv_opmode == IEEE80211_M_STA ||
vap->iv_opmode == IEEE80211_M_AHDEMO ||
@@ -4847,9 +5358,16 @@
if (error != 0)
goto bad;
+ /*
+ * See above: ensure av_newstate() doesn't drop the lock
+ * on us.
+ */
+ IEEE80211_LOCK_ASSERT(ic);
+
if (nstate == IEEE80211_S_RUN) {
/* NB: collect bss node again, it may have changed */
- ni = vap->iv_bss;
+ ieee80211_free_node(ni);
+ ni = ieee80211_ref_node(vap->iv_bss);
DPRINTF(sc, ATH_DEBUG_STATE,
"%s(RUN): iv_flags 0x%08x bintvl %d bssid %s "
@@ -4911,10 +5429,32 @@
* force a beacon update so we pick up a lack of
* beacons from an AP in CAC and thus force a
* scan.
+ *
+ * And, there's also corner cases here where
+ * after a scan, the AP may have disappeared.
+ * In that case, we may not receive an actual
+ * beacon to update the beacon timer and thus we
+ * won't get notified of the missing beacons.
*/
sc->sc_syncbeacon = 1;
+#if 0
if (csa_run_transition)
+#endif
ath_beacon_config(sc, vap);
+
+ /*
+ * PR: kern/175227
+ *
+ * Reconfigure beacons during reset; as otherwise
+ * we won't get the beacon timers reprogrammed
+ * after a reset and thus we won't pick up a
+ * beacon miss interrupt.
+ *
+ * Hopefully we'll see a beacon before the BMISS
+ * timer fires (too often), leading to a STA
+ * disassociation.
+ */
+ sc->sc_beacons = 1;
break;
case IEEE80211_M_MONITOR:
/*
@@ -4972,6 +5512,7 @@
#endif
}
bad:
+ ieee80211_free_node(ni);
return error;
}
@@ -4990,6 +5531,7 @@
struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
ieee80211_keyix keyix, rxkeyix;
+ /* XXX should take a locked ref to vap->iv_bss */
if (!ath_key_alloc(vap, &ni->ni_ucastkey, &keyix, &rxkeyix)) {
/*
* Key cache is full; we'll fall back to doing
@@ -5005,7 +5547,7 @@
ni->ni_ucastkey.wk_flags |= IEEE80211_KEY_DEVKEY;
IEEE80211_ADDR_COPY(ni->ni_ucastkey.wk_macaddr, ni->ni_macaddr);
/* NB: this will create a pass-thru key entry */
- ath_keyset(sc, &ni->ni_ucastkey, vap->iv_bss);
+ ath_keyset(sc, vap, &ni->ni_ucastkey, vap->iv_bss);
}
}
@@ -5026,10 +5568,36 @@
an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate);
ath_rate_newassoc(sc, an, isnew);
+
if (isnew &&
(vap->iv_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey &&
ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE)
ath_setup_stationkey(ni);
+
+ /*
+ * If we're reassociating, make sure that any paused queues
+ * get unpaused.
+ *
+ * Now, we may hvae frames in the hardware queue for this node.
+ * So if we are reassociating and there are frames in the queue,
+ * we need to go through the cleanup path to ensure that they're
+ * marked as non-aggregate.
+ */
+ if (! isnew) {
+ DPRINTF(sc, ATH_DEBUG_NODE,
+ "%s: %6D: reassoc; is_powersave=%d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ an->an_is_powersave);
+
+ /* XXX for now, we can't hold the lock across assoc */
+ ath_tx_node_reassoc(sc, an);
+
+ /* XXX for now, we can't hold the lock across wakeup */
+ if (an->an_is_powersave)
+ ath_tx_node_wakeup(sc, an);
+ }
}
static int
@@ -5110,49 +5678,6 @@
return 0;
}
-static void
-ath_led_done(void *arg)
-{
- struct ath_softc *sc = arg;
-
- sc->sc_blinking = 0;
-}
-
-/*
- * Turn the LED off: flip the pin and then set a timer so no
- * update will happen for the specified duration.
- */
-static void
-ath_led_off(void *arg)
-{
- struct ath_softc *sc = arg;
-
- ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
- callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc);
-}
-
-/*
- * Blink the LED according to the specified on/off times.
- */
-static void
-ath_led_blink(struct ath_softc *sc, int on, int off)
-{
- DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off);
- ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon);
- sc->sc_blinking = 1;
- sc->sc_ledoff = off;
- callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc);
-}
-
-static void
-ath_led_event(struct ath_softc *sc, int rix)
-{
- sc->sc_ledevent = ticks; /* time of last event */
- if (sc->sc_blinking) /* don't interrupt active blink */
- return;
- ath_led_blink(sc, sc->sc_hwmap[rix].ledon, sc->sc_hwmap[rix].ledoff);
-}
-
static int
ath_rate_setup(struct ath_softc *sc, u_int mode)
{
@@ -5280,6 +5805,7 @@
ath_watchdog(void *arg)
{
struct ath_softc *sc = arg;
+ int do_reset = 0;
if (sc->sc_wd_timer != 0 && --sc->sc_wd_timer == 0) {
struct ifnet *ifp = sc->sc_ifp;
@@ -5291,13 +5817,61 @@
hangs & 0xff ? "bb" : "mac", hangs);
} else
if_printf(ifp, "device timeout\n");
- ath_reset(ifp);
+ do_reset = 1;
ifp->if_oerrors++;
sc->sc_stats.ast_watchdog++;
}
+
+ /*
+ * We can't hold the lock across the ath_reset() call.
+ *
+ * And since this routine can't hold a lock and sleep,
+ * do the reset deferred.
+ */
+ if (do_reset) {
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_resettask);
+ }
+
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
@@ -5337,7 +5911,7 @@
* pointer for us to use below in reclaiming the buffer;
* may want to be more defensive.
*/
- outdata = malloc(outsize, M_TEMP, M_NOWAIT);
+ outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO);
if (outdata == NULL) {
error = ENOMEM;
goto bad;
@@ -5425,10 +5999,18 @@
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)
+ if (error == 0) {
memset(&sc->sc_stats, 0, sizeof(sc->sc_stats));
+ memset(&sc->sc_aggr_stats, 0,
+ sizeof(sc->sc_aggr_stats));
+ memset(&sc->sc_intr_stats, 0,
+ sizeof(sc->sc_intr_stats));
+ }
break;
#ifdef ATH_DIAGAPI
case SIOCGATHDIAG:
@@ -5438,6 +6020,12 @@
error = ath_ioctl_phyerr(sc,(struct ath_diag*) ifr);
break;
#endif
+ case SIOCGATHSPECTRAL:
+ error = ath_ioctl_spectral(sc,(struct ath_diag*) ifr);
+ break;
+ case SIOCGATHNODERATESTATS:
+ error = ath_ioctl_ratestats(sc, (struct ath_rateioctl *) ifr);
+ break;
case SIOCGIFADDR:
error = ether_ioctl(ifp, cmd, data);
break;
@@ -5461,6 +6049,8 @@
if_printf(ifp, "AR%s mac %d.%d RF%s phy %d.%d\n",
ath_hal_mac_name(ah), ah->ah_macVersion, ah->ah_macRev,
ath_hal_rf_name(ah), ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf);
+ if_printf(ifp, "2GHz radio: 0x%.4x; 5GHz radio: 0x%.4x\n",
+ ah->ah_analog2GhzRev, ah->ah_analog5GhzRev);
if (bootverbose) {
int i;
for (i = 0; i <= WME_AC_VO; i++) {
@@ -5480,372 +6070,448 @@
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)
+ath_dfs_tasklet(void *p, int npending)
{
- struct ath_hal *ah = sc->sc_ah;
- HAL_BEACON_TIMERS bt;
+ struct ath_softc *sc = (struct ath_softc *) p;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
- 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);
+ /*
+ * If previous processing has found a radar event,
+ * signal this to the net80211 layer to begin DFS
+ * processing.
+ */
+ if (ath_dfs_process_radar_event(sc, sc->sc_curchan)) {
+ /* DFS event found, initiate channel change */
+ /*
+ * XXX doesn't currently tell us whether the event
+ * XXX was found in the primary or extension
+ * XXX channel!
+ */
+ IEEE80211_LOCK(ic);
+ ieee80211_dfs_notify_radar(ic, sc->sc_curchan);
+ IEEE80211_UNLOCK(ic);
+ }
}
/*
- * 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.
+ * Enable/disable power save. This must be called with
+ * no TX driver locks currently held, so it should only
+ * be called from the RX path (which doesn't hold any
+ * TX driver locks.)
*/
static void
-ath_tdma_bintvalsetup(struct ath_softc *sc,
- const struct ieee80211_tdma_state *tdma)
+ath_node_powersave(struct ieee80211_node *ni, int enable)
{
- /* copy from vap state (XXX check all vaps have same value?) */
- sc->sc_tdmaslotlen = tdma->tdma_slotlen;
+#ifdef ATH_SW_PSQ
+ struct ath_node *an = ATH_NODE(ni);
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_vap *avp = ATH_VAP(ni->ni_vap);
- 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++;
+ /* XXX and no TXQ locks should be held here */
- if (tdma->tdma_slot == 0) {
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE, "%s: %6D: enable=%d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ !! enable);
+
+ /* Suspend or resume software queue handling */
+ if (enable)
+ ath_tx_node_sleep(sc, an);
+ else
+ ath_tx_node_wakeup(sc, an);
+
+ /* Update net80211 state */
+ avp->av_node_ps(ni, enable);
+#else
+ struct ath_vap *avp = ATH_VAP(ni->ni_vap);
+
+ /* Update net80211 state */
+ avp->av_node_ps(ni, enable);
+#endif/* ATH_SW_PSQ */
+}
+
+/*
+ * Notification from net80211 that the powersave queue state has
+ * changed.
+ *
+ * Since the software queue also may have some frames:
+ *
+ * + if the node software queue has frames and the TID state
+ * is 0, we set the TIM;
+ * + if the node and the stack are both empty, we clear the TIM bit.
+ * + If the stack tries to set the bit, always set it.
+ * + If the stack tries to clear the bit, only clear it if the
+ * software queue in question is also cleared.
+ *
+ * TODO: this is called during node teardown; so let's ensure this
+ * is all correctly handled and that the TIM bit is cleared.
+ * It may be that the node flush is called _AFTER_ the net80211
+ * stack clears the TIM.
+ *
+ * Here is the racy part. Since it's possible >1 concurrent,
+ * overlapping TXes will appear complete with a TX completion in
+ * another thread, it's possible that the concurrent TIM calls will
+ * clash. We can't hold the node lock here because setting the
+ * TIM grabs the net80211 comlock and this may cause a LOR.
+ * The solution is either to totally serialise _everything_ at
+ * this point (ie, all TX, completion and any reset/flush go into
+ * one taskqueue) or a new "ath TIM lock" needs to be created that
+ * just wraps the driver state change and this call to avp->av_set_tim().
+ *
+ * The same race exists in the net80211 power save queue handling
+ * as well. Since multiple transmitting threads may queue frames
+ * into the driver, as well as ps-poll and the driver transmitting
+ * frames (and thus clearing the psq), it's quite possible that
+ * a packet entering the PSQ and a ps-poll being handled will
+ * race, causing the TIM to be cleared and not re-set.
+ */
+static int
+ath_node_set_tim(struct ieee80211_node *ni, int enable)
+{
+#ifdef ATH_SW_PSQ
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_vap *avp = ATH_VAP(ni->ni_vap);
+ int changed = 0;
+
+ ATH_TX_LOCK(sc);
+ an->an_stack_psq = enable;
+
+ /*
+ * This will get called for all operating modes,
+ * even if avp->av_set_tim is unset.
+ * It's currently set for hostap/ibss modes; but
+ * the same infrastructure is used for both STA
+ * and AP/IBSS node power save.
+ */
+ if (avp->av_set_tim == NULL) {
+ ATH_TX_UNLOCK(sc);
+ return (0);
+ }
+
+ /*
+ * If setting the bit, always set it here.
+ * If clearing the bit, only clear it if the
+ * software queue is also empty.
+ *
+ * If the node has left power save, just clear the TIM
+ * bit regardless of the state of the power save queue.
+ *
+ * XXX TODO: although atomics are used, it's quite possible
+ * that a race will occur between this and setting/clearing
+ * in another thread. TX completion will occur always in
+ * one thread, however setting/clearing the TIM bit can come
+ * from a variety of different process contexts!
+ */
+ if (enable && an->an_tim_set == 1) {
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: enable=%d, tim_set=1, ignoring\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ enable);
+ ATH_TX_UNLOCK(sc);
+ } else if (enable) {
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: enable=%d, enabling TIM\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ enable);
+ an->an_tim_set = 1;
+ ATH_TX_UNLOCK(sc);
+ changed = avp->av_set_tim(ni, enable);
+ } else if (an->an_swq_depth == 0) {
+ /* disable */
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: enable=%d, an_swq_depth == 0, disabling\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ enable);
+ an->an_tim_set = 0;
+ ATH_TX_UNLOCK(sc);
+ changed = avp->av_set_tim(ni, enable);
+ } else if (! an->an_is_powersave) {
/*
- * Only slot 0 beacons; other slots respond.
+ * disable regardless; the node isn't in powersave now
*/
- sc->sc_imask |= HAL_INT_SWBA;
- sc->sc_tdmaswba = 0; /* beacon immediately */
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: enable=%d, an_pwrsave=0, disabling\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ enable);
+ an->an_tim_set = 0;
+ ATH_TX_UNLOCK(sc);
+ changed = avp->av_set_tim(ni, enable);
} else {
- /* XXX all vaps must be slot 0 or slot !0 */
- sc->sc_imask &= ~HAL_INT_SWBA;
+ /*
+ * psq disable, node is currently in powersave, node
+ * software queue isn't empty, so don't clear the TIM bit
+ * for now.
+ */
+ ATH_TX_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: enable=%d, an_swq_depth > 0, ignoring\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ enable);
+ changed = 0;
}
+
+ return (changed);
+#else
+ struct ath_vap *avp = ATH_VAP(ni->ni_vap);
+
+ /*
+ * Some operating modes don't set av_set_tim(), so don't
+ * update it here.
+ */
+ if (avp->av_set_tim == NULL)
+ return (0);
+
+ return (avp->av_set_tim(ni, enable));
+#endif /* ATH_SW_PSQ */
}
/*
- * Max 802.11 overhead. This assumes no 4-address frames and
- * the encapsulation done by ieee80211_encap (llc). We also
- * include potential crypto overhead.
+ * Set or update the TIM from the software queue.
+ *
+ * Check the software queue depth before attempting to do lock
+ * anything; that avoids trying to obtain the lock. Then,
+ * re-check afterwards to ensure nothing has changed in the
+ * meantime.
+ *
+ * set: This is designed to be called from the TX path, after
+ * a frame has been queued; to see if the swq > 0.
+ *
+ * clear: This is designed to be called from the buffer completion point
+ * (right now it's ath_tx_default_comp()) where the state of
+ * a software queue has changed.
+ *
+ * It makes sense to place it at buffer free / completion rather
+ * than after each software queue operation, as there's no real
+ * point in churning the TIM bit as the last frames in the software
+ * queue are transmitted. If they fail and we retry them, we'd
+ * just be setting the TIM bit again anyway.
*/
-#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)
+void
+ath_tx_update_tim(struct ath_softc *sc, struct ieee80211_node *ni,
+ int enable)
{
- 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;
+#ifdef ATH_SW_PSQ
+ struct ath_node *an;
+ struct ath_vap *avp;
- if (vap == NULL) {
- vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
- if (vap == NULL) {
- if_printf(ifp, "%s: no vaps?\n", __func__);
- return;
- }
- }
- tp = vap->iv_bss->ni_txparms;
+ /* Don't do this for broadcast/etc frames */
+ if (ni == NULL)
+ return;
+
+ an = ATH_NODE(ni);
+ avp = ATH_VAP(ni->ni_vap);
+
/*
- * 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).
+ * And for operating modes without the TIM handler set, let's
+ * just skip those.
*/
- 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);
+ if (avp->av_set_tim == NULL)
+ return;
- ath_hal_intrset(ah, 0);
+ ATH_TX_LOCK_ASSERT(sc);
- 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;
+ if (enable) {
+ if (an->an_is_powersave &&
+ an->an_tim_set == 0 &&
+ an->an_swq_depth != 0) {
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: swq_depth>0, tim_set=0, set!\n",
+ __func__,
+ ni->ni_macaddr,
+ ":");
+ an->an_tim_set = 1;
+ (void) avp->av_set_tim(ni, 1);
+ }
+ } else {
+ /*
+ * Don't bother grabbing the lock unless the queue is empty.
+ */
+ if (&an->an_swq_depth != 0)
+ return;
- 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);
+ if (an->an_is_powersave &&
+ an->an_stack_psq == 0 &&
+ an->an_tim_set == 1 &&
+ an->an_swq_depth == 0) {
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: swq_depth=0, tim_set=1, psq_set=0,"
+ " clear!\n",
+ __func__,
+ ni->ni_macaddr,
+ ":");
+ an->an_tim_set = 0;
+ (void) avp->av_set_tim(ni, 0);
+ }
+ }
+#else
+ return;
+#endif /* ATH_SW_PSQ */
}
/*
- * 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.
+ * Received a ps-poll frame from net80211.
+ *
+ * Here we get a chance to serve out a software-queued frame ourselves
+ * before we punt it to net80211 to transmit us one itself - either
+ * because there's traffic in the net80211 psq, or a NULL frame to
+ * indicate there's nothing else.
*/
static void
-ath_tdma_update(struct ieee80211_node *ni,
- const struct ieee80211_tdma_param *tdma, int changed)
+ath_node_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m)
{
-#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;
+#ifdef ATH_SW_PSQ
+ struct ath_node *an;
+ struct ath_vap *avp;
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;
+ int tid;
- sc->sc_stats.ast_tdma_update++;
+ /* Just paranoia */
+ if (ni == NULL)
+ return;
/*
- * Check for and adopt configuration changes.
+ * Unassociated (temporary node) station.
*/
- if (changed != 0) {
- const struct ieee80211_tdma_state *ts = vap->iv_tdma;
+ if (ni->ni_associd == 0)
+ return;
- 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.
+ * We do have an active node, so let's begin looking into it.
*/
- 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;
+ an = ATH_NODE(ni);
+ avp = ATH_VAP(ni->ni_vap);
/*
- * 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.
+ * For now, we just call the original ps-poll method.
+ * Once we're ready to flip this on:
+ *
+ * + Set leak to 1, as no matter what we're going to have
+ * to send a frame;
+ * + Check the software queue and if there's something in it,
+ * schedule the highest TID thas has traffic from this node.
+ * Then make sure we schedule the software scheduler to
+ * run so it picks up said frame.
+ *
+ * That way whatever happens, we'll at least send _a_ frame
+ * to the given node.
+ *
+ * Again, yes, it's crappy QoS if the node has multiple
+ * TIDs worth of traffic - but let's get it working first
+ * before we optimise it.
+ *
+ * Also yes, there's definitely latency here - we're not
+ * direct dispatching to the hardware in this path (and
+ * we're likely being called from the packet receive path,
+ * so going back into TX may be a little hairy!) but again
+ * I'd like to get this working first before optimising
+ * turn-around time.
*/
- 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));
+ ATH_TX_LOCK(sc);
- 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);
+ /*
+ * Legacy - we're called and the node isn't asleep.
+ * Immediately punt.
+ */
+ if (! an->an_is_powersave) {
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: not in powersave?\n",
+ __func__,
+ ni->ni_macaddr,
+ ":");
+ ATH_TX_UNLOCK(sc);
+ avp->av_recv_pspoll(ni, m);
+ return;
}
- 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.
+ * We're in powersave.
*
- * 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.
+ * Leak a frame.
*/
- 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
-}
+ an->an_leak_count = 1;
-/*
- * 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.
+ * Now, if there's no frames in the node, just punt to
+ * recv_pspoll.
+ *
+ * Don't bother checking if the TIM bit is set, we really
+ * only care if there are any frames here!
*/
- 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);
+ if (an->an_swq_depth == 0) {
+ ATH_TX_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: SWQ empty; punting to net80211\n",
+ __func__,
+ ni->ni_macaddr,
+ ":");
+ avp->av_recv_pspoll(ni, m);
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
+ * Ok, let's schedule the highest TID that has traffic
+ * and then schedule something.
*/
- 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) {
+ for (tid = IEEE80211_TID_SIZE - 1; tid >= 0; tid--) {
+ struct ath_tid *atid = &an->an_tid[tid];
/*
- * 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.
+ * No frames? Skip.
*/
- 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? */
-
+ if (atid->axq_depth == 0)
+ continue;
+ ath_tx_tid_sched(sc, atid);
/*
- * Record local TSF for our last send for use
- * in arbitrating slot collisions.
+ * XXX we could do a direct call to the TXQ
+ * scheduler code here to optimise latency
+ * at the expense of a REALLY deep callstack.
*/
- vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah);
+ ATH_TX_UNLOCK(sc);
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_txqtask);
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: leaking frame to TID %d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ tid);
+ return;
}
-}
-#endif /* IEEE80211_SUPPORT_TDMA */
-static void
-ath_dfs_tasklet(void *p, int npending)
-{
- struct ath_softc *sc = (struct ath_softc *) p;
- struct ifnet *ifp = sc->sc_ifp;
- struct ieee80211com *ic = ifp->if_l2com;
+ ATH_TX_UNLOCK(sc);
/*
- * If previous processing has found a radar event,
- * signal this to the net80211 layer to begin DFS
- * processing.
+ * XXX nothing in the TIDs at this point? Eek.
*/
- if (ath_dfs_process_radar_event(sc, sc->sc_curchan)) {
- /* DFS event found, initiate channel change */
- ieee80211_dfs_notify_radar(ic, sc->sc_curchan);
- }
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: TIDs empty, but ath_node showed traffic?!\n",
+ __func__,
+ ni->ni_macaddr,
+ ":");
+ avp->av_recv_pspoll(ni, m);
+#else
+ avp->av_recv_pspoll(ni, m);
+#endif /* ATH_SW_PSQ */
}
MODULE_VERSION(if_ath, 1);
MODULE_DEPEND(if_ath, wlan, 1, 1, 1); /* 802.11 media layer */
+#if defined(IEEE80211_ALQ) || defined(AH_DEBUG_ALQ)
+MODULE_DEPEND(if_ath, alq, 1, 1, 1);
+#endif
Modified: trunk/sys/dev/ath/if_ath_ahb.c
===================================================================
--- trunk/sys/dev/ath/if_ath_ahb.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_ahb.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2010-2011 Adrian Chadd, Xenion Pty Ltd
@@ -29,12 +30,14 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_ahb.c 252239 2013-06-26 04:58: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>
@@ -83,11 +86,29 @@
static int
ath_ahb_probe(device_t dev)
{
+ int vendor_id, device_id;
const char* devname;
- /* Atheros / ar9130 */
- devname = ath_hal_probe(VENDOR_ATHEROS, AR9130_DEVID);
+ /*
+ * Check if a device/vendor ID is provided in hints.
+ */
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "vendor_id", &vendor_id) != 0) {
+ vendor_id = VENDOR_ATHEROS;
+ }
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "device_id", &device_id) != 0) {
+ device_id = AR9130_DEVID;
+ }
+
+ device_printf(dev, "Vendor=0x%04x, Device=0x%04x\n",
+ vendor_id & 0xffff,
+ device_id & 0xffff);
+
+ /* Attempt to probe */
+ devname = ath_hal_probe(vendor_id, device_id);
+
if (devname != NULL) {
device_set_desc(dev, devname);
return BUS_PROBE_DEFAULT;
@@ -103,7 +124,9 @@
int error = ENXIO;
int rid;
long eepromaddr;
+ int eepromsize;
uint8_t *p;
+ int device_id, vendor_id;
sc->sc_dev = dev;
@@ -114,15 +137,27 @@
goto bad;
}
- if (resource_long_value(device_get_name(dev), device_get_unit(dev),
- "eepromaddr", &eepromaddr) != 0) {
+ if (resource_long_value(device_get_name(dev), device_get_unit(dev),
+ "eepromaddr", &eepromaddr) != 0) {
device_printf(dev, "cannot fetch 'eepromaddr' from hints\n");
goto bad0;
- }
+ }
+
+ /*
+ * The default EEPROM size is 2048 * 16 bit words.
+ * Later EEPROM/OTP/flash regions may be quite a bit bigger.
+ */
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "eepromsize", &eepromsize) != 0) {
+ eepromsize = ATH_EEPROM_DATA_SIZE * 2;
+ }
+
+
rid = 0;
- device_printf(sc->sc_dev, "eeprom @ %p\n", (void *) eepromaddr);
+ device_printf(sc->sc_dev, "eeprom @ %p (%d bytes)\n",
+ (void *) eepromaddr, eepromsize);
psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, (uintptr_t) eepromaddr,
- (uintptr_t) eepromaddr + (uintptr_t) ((ATH_EEPROM_DATA_SIZE * 2) - 1), 0, RF_ACTIVE);
+ (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE);
if (psc->sc_eeprom == NULL) {
device_printf(dev, "cannot map eeprom space\n");
goto bad0;
@@ -138,7 +173,7 @@
sc->sc_invalid = 1;
/* Copy the EEPROM data out */
- sc->sc_eepromdata = malloc(ATH_EEPROM_DATA_SIZE * 2, M_TEMP, M_NOWAIT | M_ZERO);
+ sc->sc_eepromdata = malloc(eepromsize, M_TEMP, M_NOWAIT | M_ZERO);
if (sc->sc_eepromdata == NULL) {
device_printf(dev, "cannot allocate memory for eeprom data\n");
goto bad1;
@@ -149,10 +184,10 @@
bus_space_read_multi_1(
rman_get_bustag(psc->sc_eeprom),
rman_get_bushandle(psc->sc_eeprom),
- 0, (u_int8_t *) sc->sc_eepromdata, ATH_EEPROM_DATA_SIZE * 2);
+ 0, (u_int8_t *) sc->sc_eepromdata, eepromsize);
#endif
p = (void *) rman_get_bushandle(psc->sc_eeprom);
- memcpy(sc->sc_eepromdata, p, ATH_EEPROM_DATA_SIZE * 2);
+ memcpy(sc->sc_eepromdata, p, eepromsize);
/*
* Arrange interrupt line.
@@ -189,12 +224,35 @@
goto bad3;
}
+ /*
+ * Check if a device/vendor ID is provided in hints.
+ */
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "vendor_id", &vendor_id) != 0) {
+ vendor_id = VENDOR_ATHEROS;
+ }
+
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "device_id", &device_id) != 0) {
+ device_id = AR9130_DEVID;
+ }
+
ATH_LOCK_INIT(sc);
+ ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TX_LOCK_INIT(sc);
+ ATH_TX_IC_LOCK_INIT(sc);
+ ATH_TXSTATUS_LOCK_INIT(sc);
- error = ath_attach(AR9130_DEVID, sc);
+ error = ath_attach(device_id, sc);
if (error == 0) /* success */
return 0;
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
+ ATH_TX_LOCK_DESTROY(sc);
+ ATH_TX_IC_LOCK_DESTROY(sc);
+ ATH_PCU_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
bus_dma_tag_destroy(sc->sc_dmat);
bad3:
@@ -234,6 +292,11 @@
if (sc->sc_eepromdata)
free(sc->sc_eepromdata, M_TEMP);
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
+ ATH_TX_LOCK_DESTROY(sc);
+ ATH_TX_IC_LOCK_DESTROY(sc);
+ ATH_PCU_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
return (0);
Added: trunk/sys/dev/ath/if_ath_alq.c
===================================================================
--- trunk/sys/dev/ath/if_ath_alq.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_alq.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,196 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2012 Adrian Chadd
+ * 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: stable/10/sys/dev/ath/if_ath_alq.c 250618 2013-05-13 21:17:27Z adrian $
+ */
+#include "opt_ah.h"
+#include "opt_ath.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/alq.h>
+#include <sys/endian.h>
+#include <sys/time.h>
+
+#include <dev/ath/if_ath_alq.h>
+
+#ifdef ATH_DEBUG_ALQ
+static struct ale *
+if_ath_alq_get(struct if_ath_alq *alq, int len)
+{
+ struct ale *ale;
+
+ if (alq->sc_alq_isactive == 0)
+ return (NULL);
+
+ ale = alq_getn(alq->sc_alq_alq, len, ALQ_NOWAIT);
+ if (! ale)
+ alq->sc_alq_numlost++;
+ return (ale);
+}
+
+void
+if_ath_alq_init(struct if_ath_alq *alq, const char *devname)
+{
+
+ bzero(alq, sizeof(*alq));
+
+ strncpy(alq->sc_alq_devname, devname, ATH_ALQ_DEVNAME_LEN);
+ printf("%s (%s): attached\n", __func__, alq->sc_alq_devname);
+ snprintf(alq->sc_alq_filename, ATH_ALQ_FILENAME_LEN,
+ "/tmp/ath_%s_alq.log", alq->sc_alq_devname);
+
+ /* XXX too conservative, right? */
+ alq->sc_alq_qsize = (64*1024);
+}
+
+void
+if_ath_alq_setcfg(struct if_ath_alq *alq, uint32_t macVer,
+ uint32_t macRev, uint32_t phyRev, uint32_t halMagic)
+{
+
+ /* Store these in network order */
+ alq->sc_alq_cfg.sc_mac_version = htobe32(macVer);
+ alq->sc_alq_cfg.sc_mac_revision = htobe32(macRev);
+ alq->sc_alq_cfg.sc_phy_rev = htobe32(phyRev);
+ alq->sc_alq_cfg.sc_hal_magic = htobe32(halMagic);
+}
+
+void
+if_ath_alq_tidyup(struct if_ath_alq *alq)
+{
+
+ if_ath_alq_stop(alq);
+ printf("%s (%s): detached\n", __func__, alq->sc_alq_devname);
+ bzero(alq, sizeof(*alq));
+}
+
+int
+if_ath_alq_start(struct if_ath_alq *alq)
+{
+ int error;
+
+ if (alq->sc_alq_isactive)
+ return (0);
+
+ /*
+ * Create a variable-length ALQ.
+ */
+ error = alq_open(&alq->sc_alq_alq, alq->sc_alq_filename,
+ curthread->td_ucred, ALQ_DEFAULT_CMODE,
+ alq->sc_alq_qsize, 0);
+
+ if (error != 0) {
+ printf("%s (%s): failed, err=%d\n", __func__,
+ alq->sc_alq_devname, error);
+ } else {
+ printf("%s (%s): opened\n", __func__, alq->sc_alq_devname);
+ alq->sc_alq_isactive = 1;
+ if_ath_alq_post(alq, ATH_ALQ_INIT_STATE,
+ sizeof (struct if_ath_alq_init_state),
+ (char *) &alq->sc_alq_cfg);
+ }
+ return (error);
+}
+
+int
+if_ath_alq_stop(struct if_ath_alq *alq)
+{
+
+ if (alq->sc_alq_isactive == 0)
+ return (0);
+
+ printf("%s (%s): closed\n", __func__, alq->sc_alq_devname);
+
+ alq->sc_alq_isactive = 0;
+ alq_close(alq->sc_alq_alq);
+ alq->sc_alq_alq = NULL;
+
+ return (0);
+}
+
+/*
+ * Post a debug message to the ALQ.
+ *
+ * "len" is the size of the buf payload in bytes.
+ */
+void
+if_ath_alq_post(struct if_ath_alq *alq, uint16_t op, uint16_t len,
+ const char *buf)
+{
+ struct if_ath_alq_hdr *ap;
+ struct ale *ale;
+ struct timeval tv;
+
+ if (! if_ath_alq_checkdebug(alq, op))
+ return;
+
+ microtime(&tv);
+
+ /*
+ * Enforce some semblence of sanity on 'len'.
+ * Although strictly speaking, any length is possible -
+ * just be conservative so things don't get out of hand.
+ */
+ if (len > ATH_ALQ_PAYLOAD_LEN)
+ len = ATH_ALQ_PAYLOAD_LEN;
+
+ ale = if_ath_alq_get(alq, len + sizeof(struct if_ath_alq_hdr));
+
+ if (ale == NULL)
+ return;
+
+ ap = (struct if_ath_alq_hdr *) ale->ae_data;
+ ap->threadid = htobe64((uint64_t) curthread->td_tid);
+ ap->tstamp_sec = htobe32((uint32_t) tv.tv_sec);
+ ap->tstamp_usec = htobe32((uint32_t) tv.tv_usec);
+ ap->op = htobe16(op);
+ ap->len = htobe16(len);
+
+ /*
+ * Copy the payload _after_ the header field.
+ */
+ if (buf != NULL) {
+ memcpy(((char *) ap) + sizeof(struct if_ath_alq_hdr),
+ buf,
+ len);
+ }
+
+ alq_post(alq->sc_alq_alq, ale);
+}
+#endif /* ATH_DEBUG */
Property changes on: trunk/sys/dev/ath/if_ath_alq.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_alq.h
===================================================================
--- trunk/sys/dev/ath/if_ath_alq.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_alq.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,192 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2012 Adrian Chadd
+ * 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: stable/10/sys/dev/ath/if_ath_alq.h 250619 2013-05-13 21:18:00Z adrian $
+ */
+#ifndef __IF_ATH_ALQ_H__
+#define __IF_ATH_ALQ_H__
+
+#define ATH_ALQ_INIT_STATE 1
+struct if_ath_alq_init_state {
+ uint32_t sc_mac_version;
+ uint32_t sc_mac_revision;
+ uint32_t sc_phy_rev;
+ uint32_t sc_hal_magic;
+};
+
+#define ATH_ALQ_EDMA_TXSTATUS 2
+#define ATH_ALQ_EDMA_RXSTATUS 3
+#define ATH_ALQ_EDMA_TXDESC 4
+
+#define ATH_ALQ_TDMA_BEACON_STATE 5
+struct if_ath_alq_tdma_beacon_state {
+ uint64_t rx_tsf; /* RX TSF of beacon frame */
+ uint64_t beacon_tsf; /* TSF inside beacon frame */
+ uint64_t tsf64;
+ uint64_t nextslot_tsf;
+ uint32_t nextslot_tu;
+ uint32_t txtime;
+};
+
+#define ATH_ALQ_TDMA_TIMER_CONFIG 6
+struct if_ath_alq_tdma_timer_config {
+ uint32_t tdma_slot;
+ uint32_t tdma_slotlen;
+ uint32_t tdma_slotcnt;
+ uint32_t tdma_bintval;
+ uint32_t tdma_guard;
+ uint32_t tdma_scbintval;
+ uint32_t tdma_dbaprep;
+};
+
+#define ATH_ALQ_TDMA_SLOT_CALC 7
+struct if_ath_alq_tdma_slot_calc {
+ uint64_t nexttbtt;
+ uint64_t next_slot;
+ int32_t tsfdelta;
+ int32_t avg_plus;
+ int32_t avg_minus;
+};
+
+#define ATH_ALQ_TDMA_TSF_ADJUST 8
+struct if_ath_alq_tdma_tsf_adjust {
+ uint64_t tsf64_old;
+ uint64_t tsf64_new;
+ int32_t tsfdelta;
+};
+
+#define ATH_ALQ_TDMA_TIMER_SET 9
+struct if_ath_alq_tdma_timer_set {
+ uint32_t bt_intval;
+ uint32_t bt_nexttbtt;
+ uint32_t bt_nextdba;
+ uint32_t bt_nextswba;
+ uint32_t bt_nextatim;
+ uint32_t bt_flags;
+ uint32_t sc_tdmadbaprep;
+ uint32_t sc_tdmaswbaprep;
+};
+
+#define ATH_ALQ_INTR_STATUS 10
+struct if_ath_alq_interrupt {
+ uint32_t intr_status;
+ uint32_t intr_state[8];
+ uint32_t intr_syncstate;
+};
+
+#define ATH_ALQ_MIB_COUNTERS 11
+struct if_ath_alq_mib_counters {
+ uint32_t valid;
+ uint32_t tx_busy;
+ uint32_t rx_busy;
+ uint32_t chan_busy;
+ uint32_t ext_chan_busy;
+ uint32_t cycle_count;
+};
+
+#define ATH_ALQ_MISSED_BEACON 12
+#define ATH_ALQ_STUCK_BEACON 13
+#define ATH_ALQ_RESUME_BEACON 14
+
+/*
+ * These will always be logged, regardless.
+ */
+#define ATH_ALQ_LOG_ALWAYS_MASK 0x00000001
+
+#define ATH_ALQ_FILENAME_LEN 128
+#define ATH_ALQ_DEVNAME_LEN 32
+
+struct if_ath_alq {
+ uint32_t sc_alq_debug; /* Debug flags to report */
+ struct alq * sc_alq_alq; /* alq state */
+ unsigned int sc_alq_qsize; /* queue size */
+ unsigned int sc_alq_numlost; /* number of "lost" entries */
+ int sc_alq_isactive;
+ char sc_alq_devname[ATH_ALQ_DEVNAME_LEN];
+ char sc_alq_filename[ATH_ALQ_FILENAME_LEN];
+ struct if_ath_alq_init_state sc_alq_cfg;
+};
+
+/* 128 bytes in total */
+#define ATH_ALQ_PAYLOAD_LEN 112
+
+struct if_ath_alq_hdr {
+ uint64_t threadid;
+ uint32_t tstamp_sec;
+ uint32_t tstamp_usec;
+ uint16_t op;
+ uint16_t len; /* Length of (optional) payload */
+};
+
+struct if_ath_alq_payload {
+ struct if_ath_alq_hdr hdr;
+ char payload[];
+};
+
+#ifdef _KERNEL
+static inline int
+if_ath_alq_checkdebug(struct if_ath_alq *alq, uint16_t op)
+{
+
+ return ((alq->sc_alq_debug | ATH_ALQ_LOG_ALWAYS_MASK)
+ & (1 << (op - 1)));
+}
+
+extern void if_ath_alq_init(struct if_ath_alq *alq, const char *devname);
+extern void if_ath_alq_setcfg(struct if_ath_alq *alq, uint32_t macVer,
+ uint32_t macRev, uint32_t phyRev, uint32_t halMagic);
+extern void if_ath_alq_tidyup(struct if_ath_alq *alq);
+extern int if_ath_alq_start(struct if_ath_alq *alq);
+extern int if_ath_alq_stop(struct if_ath_alq *alq);
+extern void if_ath_alq_post(struct if_ath_alq *alq, uint16_t op,
+ uint16_t len, const char *buf);
+
+/* XXX maybe doesn't belong here? */
+static inline void
+if_ath_alq_post_intr(struct if_ath_alq *alq, uint32_t status,
+ uint32_t *state, uint32_t sync_state)
+{
+ int i;
+ struct if_ath_alq_interrupt intr;
+
+ if (! if_ath_alq_checkdebug(alq, ATH_ALQ_INTR_STATUS))
+ return;
+
+ intr.intr_status = htobe32(status);
+ for (i = 0; i < 8; i++)
+ intr.intr_state[i] = htobe32(state[i]);
+ intr.intr_syncstate = htobe32(sync_state);
+
+ if_ath_alq_post(alq, ATH_ALQ_INTR_STATUS, sizeof(intr),
+ (const char *) &intr);
+}
+
+#endif /* _KERNEL */
+
+#endif
Property changes on: trunk/sys/dev/ath/if_ath_alq.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_beacon.c
===================================================================
--- trunk/sys/dev/ath/if_ath_beacon.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_beacon.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,1120 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_beacon.c 250783 2013-05-18 18:27:53Z 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_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_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;
+ if (sc->sc_isedma)
+ qi.tqi_qflags |= HAL_TXQ_TXOKINT_ENABLE |
+ HAL_TXQ_TXERRINT_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;
+ HAL_DMA_ADDR bufAddrList[4];
+ uint32_t segLenList[4];
+ HAL_11N_RATE_SERIES rc[4];
+
+ 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));
+
+ /*
+ * 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 */
+ , ieee80211_get_node_txpower(ni) /* 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 */
+ );
+
+ /*
+ * The EDMA HAL currently assumes that _all_ rate control
+ * settings are done in ath_hal_set11nratescenario(), rather
+ * than in ath_hal_setuptxdesc().
+ */
+ if (sc->sc_isedma) {
+ memset(&rc, 0, sizeof(rc));
+
+ rc[0].ChSel = sc->sc_txchainmask;
+ rc[0].Tries = 1;
+ rc[0].Rate = rt->info[rix].rateCode;
+ rc[0].RateIndex = rix;
+ rc[0].tx_power_cap = 0x3f;
+ rc[0].PktDuration =
+ ath_hal_computetxtime(ah, rt, roundup(m->m_len, 4),
+ rix, 0);
+ ath_hal_set11nratescenario(ah, ds, 0, 0, rc, 4, flags);
+ }
+
+ /* NB: beacon's BufLen must be a multiple of 4 bytes */
+ segLenList[0] = roundup(m->m_len, 4);
+ segLenList[1] = segLenList[2] = segLenList[3] = 0;
+ bufAddrList[0] = bf->bf_segs[0].ds_addr;
+ bufAddrList[1] = bufAddrList[2] = bufAddrList[3] = 0;
+ ath_hal_filltxdesc(ah, ds
+ , bufAddrList
+ , segLenList
+ , 0 /* XXX desc id */
+ , sc->sc_bhalq /* hardware TXQ */
+ , 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);
+}
+
+/*
+ * Handle a beacon miss.
+ */
+static void
+ath_beacon_miss(struct ath_softc *sc)
+{
+ HAL_SURVEY_SAMPLE hs;
+ HAL_BOOL ret;
+ uint32_t hangs;
+
+ bzero(&hs, sizeof(hs));
+
+ ret = ath_hal_get_mib_cycle_counts(sc->sc_ah, &hs);
+
+ if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) && hangs != 0) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: hang=0x%08x\n",
+ __func__,
+ hangs);
+ }
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_MISSED_BEACON))
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_MISSED_BEACON, 0, NULL);
+#endif
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: valid=%d, txbusy=%u, rxbusy=%u, chanbusy=%u, "
+ "extchanbusy=%u, cyclecount=%u\n",
+ __func__,
+ ret,
+ hs.tx_busy,
+ hs.rx_busy,
+ hs.chan_busy,
+ hs.ext_chan_busy,
+ hs.cycle_count);
+}
+
+/*
+ * 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++;
+ ath_beacon_miss(sc);
+ 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;
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_RESUME_BEACON))
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_RESUME_BEACON, 0, NULL);
+#endif
+ }
+
+ 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);
+ /*
+ * XXX TODO: this should use settxdesclinkptr()
+ * otherwise it won't work for EDMA chipsets!
+ */
+ if (bf != NULL) {
+ /* XXX should do this using the ds */
+ *bflink = bf->bf_daddr;
+ ath_hal_gettxdesclinkptr(sc->sc_ah,
+ bf->bf_desc, &bflink);
+ }
+ }
+ }
+ /*
+ * XXX TODO: this should use settxdesclinkptr()
+ * otherwise it won't work for EDMA chipsets!
+ */
+ *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;
+ }
+
+ /* Program the CABQ with the contents of the CABQ txq and start it */
+ ATH_TXQ_LOCK(sc->sc_cabq);
+ ath_beacon_cabq_start(sc);
+ ATH_TXQ_UNLOCK(sc->sc_cabq);
+
+ /* Program the new beacon frame if we have one for this interval */
+ 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 (! sc->sc_isedma) {
+ 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 void
+ath_beacon_cabq_start_edma(struct ath_softc *sc)
+{
+ struct ath_buf *bf, *bf_last;
+ struct ath_txq *cabq = sc->sc_cabq;
+#if 0
+ struct ath_buf *bfi;
+ int i = 0;
+#endif
+
+ ATH_TXQ_LOCK_ASSERT(cabq);
+
+ if (TAILQ_EMPTY(&cabq->axq_q))
+ return;
+ bf = TAILQ_FIRST(&cabq->axq_q);
+ bf_last = TAILQ_LAST(&cabq->axq_q, axq_q_s);
+
+ /*
+ * This is a dirty, dirty hack to push the contents of
+ * the cabq staging queue into the FIFO.
+ *
+ * This ideally should live in the EDMA code file
+ * and only push things into the CABQ if there's a FIFO
+ * slot.
+ *
+ * We can't treat this like a normal TX queue because
+ * in the case of multi-VAP traffic, we may have to flush
+ * the CABQ each new (staggered) beacon that goes out.
+ * But for non-staggered beacons, we could in theory
+ * handle multicast traffic for all VAPs in one FIFO
+ * push. Just keep all of this in mind if you're wondering
+ * how to correctly/better handle multi-VAP CABQ traffic
+ * with EDMA.
+ */
+
+ /*
+ * Is the CABQ FIFO free? If not, complain loudly and
+ * don't queue anything. Maybe we'll flush the CABQ
+ * traffic, maybe we won't. But that'll happen next
+ * beacon interval.
+ */
+ if (cabq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) {
+ device_printf(sc->sc_dev,
+ "%s: Q%d: CAB FIFO queue=%d?\n",
+ __func__,
+ cabq->axq_qnum,
+ cabq->axq_fifo_depth);
+ return;
+ }
+
+ /*
+ * Ok, so here's the gymnastics reqiured to make this
+ * all sensible.
+ */
+
+ /*
+ * Tag the first/last buffer appropriately.
+ */
+ bf->bf_flags |= ATH_BUF_FIFOPTR;
+ bf_last->bf_flags |= ATH_BUF_FIFOEND;
+
+#if 0
+ i = 0;
+ TAILQ_FOREACH(bfi, &cabq->axq_q, bf_list) {
+ ath_printtxbuf(sc, bf, cabq->axq_qnum, i, 0);
+ i++;
+ }
+#endif
+
+ /*
+ * We now need to push this set of frames onto the tail
+ * of the FIFO queue. We don't adjust the aggregate
+ * count, only the queue depth counter(s).
+ * We also need to blank the link pointer now.
+ */
+ TAILQ_CONCAT(&cabq->fifo.axq_q, &cabq->axq_q, bf_list);
+ cabq->axq_link = NULL;
+ cabq->fifo.axq_depth += cabq->axq_depth;
+ cabq->axq_depth = 0;
+
+ /* Bump FIFO queue */
+ cabq->axq_fifo_depth++;
+
+ /* Push the first entry into the hardware */
+ ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr);
+ cabq->axq_flags |= ATH_TXQ_PUTRUNNING;
+
+ /* NB: gated by beacon so safe to start here */
+ ath_hal_txstart(sc->sc_ah, cabq->axq_qnum);
+
+}
+
+static void
+ath_beacon_cabq_start_legacy(struct ath_softc *sc)
+{
+ struct ath_buf *bf;
+ struct ath_txq *cabq = sc->sc_cabq;
+
+ ATH_TXQ_LOCK_ASSERT(cabq);
+ if (TAILQ_EMPTY(&cabq->axq_q))
+ return;
+ bf = TAILQ_FIRST(&cabq->axq_q);
+
+ /* Push the first entry into the hardware */
+ ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr);
+ cabq->axq_flags |= ATH_TXQ_PUTRUNNING;
+
+ /* NB: gated by beacon so safe to start here */
+ ath_hal_txstart(sc->sc_ah, cabq->axq_qnum);
+}
+
+/*
+ * Start CABQ transmission - this assumes that all frames are prepped
+ * and ready in the CABQ.
+ */
+void
+ath_beacon_cabq_start(struct ath_softc *sc)
+{
+ struct ath_txq *cabq = sc->sc_cabq;
+
+ ATH_TXQ_LOCK_ASSERT(cabq);
+
+ if (TAILQ_EMPTY(&cabq->axq_q))
+ return;
+
+ if (sc->sc_isedma)
+ ath_beacon_cabq_start_edma(sc);
+ else
+ ath_beacon_cabq_start_legacy(sc);
+}
+
+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
+ */
+ /*
+ * XXX TODO: this doesn't stop CABQ DMA - it assumes
+ * that since we're about to transmit a beacon, we've
+ * already stopped transmitting on the CABQ. But this
+ * doesn't at all mean that the CABQ DMA QCU will
+ * accept a new TXDP! So what, should we do a DMA
+ * stop? What if it fails?
+ *
+ * More thought is required here.
+ */
+ 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) {
+
+ /* NB: only at DTIM */
+ ATH_TXQ_LOCK(&avp->av_mcastq);
+ if (nmcastq) {
+ struct ath_buf *bfm, *bfc_last;
+
+ /*
+ * Move frames from the s/w mcast q to the h/w cab q.
+ *
+ * XXX TODO: if we chain together multiple VAPs
+ * worth of CABQ traffic, should we keep the
+ * MORE data bit set on the last frame of each
+ * intermediary VAP (ie, only clear the MORE
+ * bit of the last frame on the last vap?)
+ */
+ bfm = TAILQ_FIRST(&avp->av_mcastq.axq_q);
+ ATH_TXQ_LOCK(cabq);
+
+ /*
+ * If there's already a frame on the CABQ, we
+ * need to link to the end of the last frame.
+ * We can't use axq_link here because
+ * EDMA descriptors require some recalculation
+ * (checksum) to occur.
+ */
+ bfc_last = ATH_TXQ_LAST(cabq, axq_q_s);
+ if (bfc_last != NULL) {
+ ath_hal_settxdesclink(sc->sc_ah,
+ bfc_last->bf_lastds,
+ bfm->bf_daddr);
+ }
+ ath_txqmove(cabq, &avp->av_mcastq);
+ ATH_TXQ_UNLOCK(cabq);
+ /*
+ * XXX not entirely accurate, in case a mcast
+ * queue frame arrived before we grabbed the TX
+ * lock.
+ */
+ sc->sc_stats.ast_cabq_xmit += nmcastq;
+ }
+ ATH_TXQ_UNLOCK(&avp->av_mcastq);
+ }
+ 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_int32_t nexttbtt_u8, intval_u8;
+ u_int64_t tsf;
+
+ if (vap == NULL)
+ vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
+ /*
+ * Just ensure that we aren't being called when the last
+ * VAP is destroyed.
+ */
+ if (vap == NULL) {
+ device_printf(sc->sc_dev, "%s: called with no VAPs\n",
+ __func__);
+ return;
+ }
+
+ 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);
+ }
+
+ /*
+ * Now dirty things because for now, the EDMA HAL has
+ * nexttbtt and intval is TU/8.
+ */
+ if (sc->sc_isedma) {
+ nexttbtt_u8 = (nexttbtt << 3);
+ intval_u8 = (intval << 3);
+ if (intval & HAL_BEACON_ENA)
+ intval_u8 |= HAL_BEACON_ENA;
+ if (intval & HAL_BEACON_RESET_TSF)
+ intval_u8 |= HAL_BEACON_RESET_TSF;
+ ath_hal_beaconinit(ah, nexttbtt_u8, intval_u8);
+ } else
+ 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
+}
Property changes on: trunk/sys/dev/ath/if_ath_beacon.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_beacon.h
===================================================================
--- trunk/sys/dev/ath/if_ath_beacon.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_beacon.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,53 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_beacon.h 248671 2013-03-24 00:03:12Z adrian $
+ */
+#ifndef __IF_ATH_BEACON_H__
+#define __IF_ATH_BEACON_H__
+
+extern int ath_bstuck_threshold;
+
+extern int ath_beaconq_setup(struct ath_softc *sc);
+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 void ath_beacon_cabq_start(struct ath_softc *sc);
+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
Property changes on: trunk/sys/dev/ath/if_ath_beacon.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_btcoex.c
===================================================================
--- trunk/sys/dev/ath/if_ath_btcoex.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_btcoex.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,347 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 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: stable/10/sys/dev/ath/if_ath_btcoex.c 332320 2018-04-09 12:53:15Z emaste $
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_btcoex.c 332320 2018-04-09 12:53:15Z emaste $");
+
+/*
+ * This implements some very basic bluetooth coexistence methods for
+ * the ath(4) hardware.
+ */
+#include "opt_ath.h"
+#include "opt_inet.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <net80211/ieee80211_var.h>
+
+#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_btcoex.h>
+
+/*
+ * Initial AR9285 / (WB195) bluetooth coexistence settings,
+ * just for experimentation.
+ *
+ * Return 0 for OK; errno for error.
+ *
+ * XXX TODO: There needs to be a PCIe workaround to disable ASPM if
+ * bluetooth coexistence is enabled.
+ */
+static int
+ath_btcoex_cfg_wb195(struct ath_softc *sc)
+{
+ HAL_BT_COEX_INFO btinfo;
+ HAL_BT_COEX_CONFIG btconfig;
+ struct ath_hal *ah = sc->sc_ah;
+
+ if (! ath_hal_btcoex_supported(ah))
+ return (EINVAL);
+
+ bzero(&btinfo, sizeof(btinfo));
+ bzero(&btconfig, sizeof(btconfig));
+
+ device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n");
+
+ btinfo.bt_module = HAL_BT_MODULE_JANUS;
+ btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
+ /*
+ * These are the three GPIO pins hooked up between the AR9285 and
+ * the AR3011.
+ */
+ btinfo.bt_gpio_bt_active = 6;
+ btinfo.bt_gpio_bt_priority = 7;
+ btinfo.bt_gpio_wlan_active = 5;
+ btinfo.bt_active_polarity = 1; /* XXX not used */
+ btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */
+ btinfo.bt_isolation = 0; /* in dB, not used */
+
+ ath_hal_btcoex_set_info(ah, &btinfo);
+
+ btconfig.bt_time_extend = 0;
+ btconfig.bt_txstate_extend = 1; /* true */
+ btconfig.bt_txframe_extend = 1; /* true */
+ btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
+ btconfig.bt_quiet_collision = 1; /* true */
+ btconfig.bt_rxclear_polarity = 1; /* true */
+ btconfig.bt_priority_time = 2;
+ btconfig.bt_first_slot_time = 5;
+ btconfig.bt_hold_rxclear = 1; /* true */
+
+ ath_hal_btcoex_set_config(ah, &btconfig);
+
+ /*
+ * Enable antenna diversity.
+ */
+ ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
+
+ return (0);
+}
+
+/*
+ * Initial AR9485 / (WB225) bluetooth coexistence settings,
+ * just for experimentation.
+ *
+ * Return 0 for OK; errno for error.
+ */
+static int
+ath_btcoex_cfg_wb225(struct ath_softc *sc)
+{
+ HAL_BT_COEX_INFO btinfo;
+ HAL_BT_COEX_CONFIG btconfig;
+ struct ath_hal *ah = sc->sc_ah;
+
+ if (! ath_hal_btcoex_supported(ah))
+ return (EINVAL);
+
+ bzero(&btinfo, sizeof(btinfo));
+ bzero(&btconfig, sizeof(btconfig));
+
+ device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n");
+
+ btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */
+ btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
+ /*
+ * These are the three GPIO pins hooked up between the AR9485 and
+ * the bluetooth module.
+ */
+ btinfo.bt_gpio_bt_active = 4;
+ btinfo.bt_gpio_bt_priority = 8;
+ btinfo.bt_gpio_wlan_active = 5;
+
+ btinfo.bt_active_polarity = 1; /* XXX not used */
+ btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */
+ btinfo.bt_isolation = 0; /* in dB, not used */
+
+ ath_hal_btcoex_set_info(ah, &btinfo);
+
+ btconfig.bt_time_extend = 0;
+ btconfig.bt_txstate_extend = 1; /* true */
+ btconfig.bt_txframe_extend = 1; /* true */
+ btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
+ btconfig.bt_quiet_collision = 1; /* true */
+ btconfig.bt_rxclear_polarity = 1; /* true */
+ btconfig.bt_priority_time = 2;
+ btconfig.bt_first_slot_time = 5;
+ btconfig.bt_hold_rxclear = 1; /* true */
+
+ ath_hal_btcoex_set_config(ah, &btconfig);
+
+ /*
+ * Enable antenna diversity.
+ */
+ ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
+
+ return (0);
+}
+
+
+#if 0
+/*
+ * When using bluetooth coexistence, ASPM needs to be disabled
+ * otherwise the sleeping interferes with the bluetooth (USB)
+ * operation and the MAC sleep/wakeup hardware.
+ *
+ * The PCIe powersave routine also needs to not be called
+ * by the driver during suspend/resume, else things will get
+ * a little odd. Check Linux ath9k for more details.
+ */
+static int
+ath_btcoex_aspm_wb195(struct ath_softc *sc)
+{
+
+ /* XXX TODO: clear device ASPM L0S and L1 */
+ /* XXX TODO: clear _parent_ ASPM L0S and L1 */
+}
+#endif
+
+/*
+ * Methods which are required
+ */
+
+/*
+ * Attach btcoex to the given interface
+ */
+int
+ath_btcoex_attach(struct ath_softc *sc)
+{
+ int ret;
+ struct ath_hal *ah = sc->sc_ah;
+ const char *profname;
+
+ /*
+ * No chipset bluetooth coexistence? Then do nothing.
+ */
+ if (! ath_hal_btcoex_supported(ah))
+ return (0);
+
+ /*
+ * Look at the hints to determine which bluetooth
+ * profile to configure.
+ */
+ ret = resource_string_value(device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev),
+ "btcoex_profile",
+ &profname);
+ if (ret != 0) {
+ /* nothing to do */
+ return (0);
+ }
+
+ if (strncmp(profname, "wb195", 5) == 0) {
+ ret = ath_btcoex_cfg_wb195(sc);
+ } else if (strncmp(profname, "wb225", 5) == 0) {
+ ret = ath_btcoex_cfg_wb225(sc);
+ } else {
+ return (0);
+ }
+
+ /*
+ * Propagate up failure from the actual attach phase.
+ */
+ if (ret != 0)
+ return (ret);
+
+ return (0);
+}
+
+/*
+ * Detach btcoex from the given interface
+ */
+int
+ath_btcoex_detach(struct ath_softc *sc)
+{
+
+ return (0);
+}
+
+/*
+ * Configure or disable bluetooth coexistence on the given channel.
+ *
+ * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just
+ * assume bluetooth coexistence is always on.
+ *
+ * For AR9462, we may see a 5GHz channel; bluetooth coexistence should
+ * not be enabled on those channels.
+ */
+int
+ath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
+{
+
+ return (0);
+}
+
+/*
+ * Handle ioctl requests from the diagnostic interface.
+ *
+ * The initial part of this code resembles ath_ioctl_diag();
+ * it's likely a good idea to reduce duplication between
+ * these two routines.
+ */
+int
+ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad)
+{
+ unsigned int id = ad->ad_id & ATH_DIAG_ID;
+ void *indata = NULL;
+ void *outdata = NULL;
+ u_int32_t insize = ad->ad_in_size;
+ u_int32_t outsize = ad->ad_out_size;
+ int error = 0;
+// int val;
+
+ if (ad->ad_id & ATH_DIAG_IN) {
+ /*
+ * Copy in data.
+ */
+ indata = malloc(insize, M_TEMP, M_NOWAIT);
+ if (indata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ error = copyin(ad->ad_in_data, indata, insize);
+ if (error)
+ goto bad;
+ }
+ if (ad->ad_id & ATH_DIAG_DYN) {
+ /*
+ * Allocate a buffer for the results (otherwise the HAL
+ * returns a pointer to a buffer where we can read the
+ * results). Note that we depend on the HAL leaving this
+ * pointer for us to use below in reclaiming the buffer;
+ * may want to be more defensive.
+ */
+ outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO);
+ if (outdata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ }
+ switch (id) {
+ default:
+ error = EINVAL;
+ goto bad;
+ }
+ if (outsize < ad->ad_out_size)
+ ad->ad_out_size = outsize;
+ if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
+ error = EFAULT;
+bad:
+ if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
+ free(indata, M_TEMP);
+ if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
+ free(outdata, M_TEMP);
+ return (error);
+}
+
Property changes on: trunk/sys/dev/ath/if_ath_btcoex.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_btcoex.h
===================================================================
--- trunk/sys/dev/ath/if_ath_btcoex.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_btcoex.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,41 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 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: stable/10/sys/dev/ath/if_ath_btcoex.h 251487 2013-06-07 09:02:02Z adrian $
+ */
+#ifndef __IF_ATH_BTCOEX_H__
+#define __IF_ATH_BTCOEX_H__
+
+extern int ath_btcoex_attach(struct ath_softc *sc);
+extern int ath_btcoex_detach(struct ath_softc *sc);
+extern int ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad);
+extern int ath_btcoex_enable(struct ath_softc *sc,
+ const struct ieee80211_channel *ch);
+
+#endif /* __IF_ATH_BTCOEX_H__ */
Property changes on: trunk/sys/dev/ath/if_ath_btcoex.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/if_ath_debug.c
===================================================================
--- trunk/sys/dev/ath/if_ath_debug.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_debug.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -28,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_debug.c 242599 2012-11-05 07:08:45Z adrian $");
#include "opt_inet.h"
#include "opt_ath.h"
@@ -89,12 +90,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,39 +119,146 @@
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]);
}
}
}
-void
-ath_printtxbuf(struct ath_softc *sc, const struct ath_buf *bf,
+static void
+ath_printtxbuf_edma(struct ath_softc *sc, const struct ath_buf *first_bf,
u_int qnum, u_int ix, int done)
{
- const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
+ const struct ath_tx_status *ts =
+ &first_bf->bf_last->bf_status.ds_txstat;
+ const struct ath_buf *bf = first_bf;
+ const char *ds;
+ const struct ath_desc_txedma *eds;
+ int i, n;
+
+ printf("Q%u[%3u] (nseg=%d)", qnum, ix, bf->bf_nseg);
+ while (bf != NULL) {
+ /*
+ * XXX For now, assume the txmap size is 4.
+ */
+
+ /*
+ * Assume the TX map size is 4 for now and only walk
+ * the appropriate number of segments.
+ */
+ n = ((bf->bf_nseg - 1) / 4) + 1;
+
+ for (i = 0, ds = (const char *) bf->bf_desc;
+ i < n;
+ i ++, ds += sc->sc_tx_desclen) {
+ eds = (const struct ath_desc_txedma *) ds;
+ printf(" (DS.V:%p DS.P:%p) I: %08x L:%08x F:%04x%s\n",
+ eds, (const struct ath_desc *)bf->bf_daddr + i,
+ eds->ds_info, eds->ds_link,
+ bf->bf_state.bfs_txflags,
+ !done ? "" : (ts->ts_status == 0) ? " *" : " !");
+ printf(" (D[0] = %08x(%08x), D[1] = %08x(%08x)\n",
+ eds->ds_hw[0], eds->ds_hw[1],
+ eds->ds_hw[2], eds->ds_hw[3]);
+ printf(" (D[2] = %08x(%08x), D[3] = %08x(%08x)\n",
+ eds->ds_hw[4], eds->ds_hw[5],
+ eds->ds_hw[6], eds->ds_hw[7]);
+ printf(" Seq: %d swtry: %d ADDBAW?: %d DOBAW?: %d\n",
+ bf->bf_state.bfs_seqno,
+ bf->bf_state.bfs_retries,
+ bf->bf_state.bfs_addedbaw,
+ bf->bf_state.bfs_dobaw);
+ printf(" %08x %08x %08x %08x %08x %08x\n",
+ eds->ds_hw[8], eds->ds_hw[9],
+ eds->ds_hw[10], eds->ds_hw[11],
+ eds->ds_hw[12], eds->ds_hw[13]);
+ printf(" %08x %08x %08x %08x %08x %08x %08x\n",
+ eds->ds_hw[14], eds->ds_hw[15], eds->ds_hw[16],
+ eds->ds_hw[17], eds->ds_hw[18], eds->ds_hw[19],
+ eds->ds_hw[20]);
+#if 0
+ printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ ds->ds_hw[22],ds->ds_hw[23],ds->ds_hw[24],
+ ds->ds_hw[25],ds->ds_hw[26],ds->ds_hw[27],
+ ds->ds_hw[28], ds->ds_hw[29]);
+#endif
+ }
+ printf(" [end]\n");
+ bf = bf->bf_next;
+ }
+}
+
+static void
+ath_printtxbuf_legacy(struct ath_softc *sc, const struct ath_buf *first_bf,
+ u_int qnum, u_int ix, int done)
+{
+ const struct ath_tx_status *ts = &first_bf->bf_status.ds_txstat;
+ const struct ath_buf *bf = first_bf;
struct ath_hal *ah = sc->sc_ah;
const struct ath_desc *ds;
int i;
printf("Q%u[%3u]", qnum, ix);
- for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
- printf(" (DS.V:%p DS.P:%p) L:%08x D:%08x F:04%x%s\n"
- " %08x %08x %08x %08x %08x %08x\n",
- ds, (const struct ath_desc *)bf->bf_daddr + i,
- ds->ds_link, ds->ds_data, bf->bf_txflags,
- !done ? "" : (ts->ts_status == 0) ? " *" : " !",
- ds->ds_ctl0, ds->ds_ctl1,
- ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3]);
- if (ah->ah_magic == 0x20065416) {
- printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
- ds->ds_hw[4], ds->ds_hw[5], ds->ds_hw[6],
- ds->ds_hw[7], ds->ds_hw[8], ds->ds_hw[9],
- ds->ds_hw[10],ds->ds_hw[11]);
- printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
- ds->ds_hw[12],ds->ds_hw[13],ds->ds_hw[14],
- ds->ds_hw[15],ds->ds_hw[16],ds->ds_hw[17],
- ds->ds_hw[18], ds->ds_hw[19]);
+ while (bf != NULL) {
+ printf(" (bf=%p, lastds=%p)\n", bf, first_bf->bf_lastds);
+ printf(" Seq: %d swtry: %d ADDBAW?: %d DOBAW?: %d\n",
+ bf->bf_state.bfs_seqno,
+ bf->bf_state.bfs_retries,
+ bf->bf_state.bfs_addedbaw,
+ bf->bf_state.bfs_dobaw);
+ for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) {
+ printf(" (DS.V:%p DS.P:%p) L:%08x D:%08x F:%04x%s\n",
+ ds, (const struct ath_desc *)bf->bf_daddr + i,
+ ds->ds_link, ds->ds_data, bf->bf_state.bfs_txflags,
+ !done ? "" : (ts->ts_status == 0) ? " *" : " !");
+ printf(" %08x %08x %08x %08x %08x %08x\n",
+ ds->ds_ctl0, ds->ds_ctl1,
+ ds->ds_hw[0], ds->ds_hw[1],
+ ds->ds_hw[2], ds->ds_hw[3]);
+ if (ah->ah_magic == 0x20065416) {
+ printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ ds->ds_hw[4], ds->ds_hw[5], ds->ds_hw[6],
+ ds->ds_hw[7], ds->ds_hw[8], ds->ds_hw[9],
+ ds->ds_hw[10],ds->ds_hw[11]);
+ printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ ds->ds_hw[12],ds->ds_hw[13],ds->ds_hw[14],
+ ds->ds_hw[15],ds->ds_hw[16],ds->ds_hw[17],
+ ds->ds_hw[18], ds->ds_hw[19]);
+ }
}
+ printf(" [end]\n");
+ bf = bf->bf_next;
}
}
+void
+ath_printtxbuf(struct ath_softc *sc, const struct ath_buf *first_bf,
+ u_int qnum, u_int ix, int done)
+{
+ if (sc->sc_ah->ah_magic == 0x19741014)
+ ath_printtxbuf_edma(sc, first_bf, qnum, ix, done);
+ else
+ ath_printtxbuf_legacy(sc, first_bf, qnum, ix, done);
+}
+
+void
+ath_printtxstatbuf(struct ath_softc *sc, const struct ath_buf *first_bf,
+ const uint32_t *ds, u_int qnum, u_int ix, int done)
+{
+
+ printf("Q%u[%3u] ", qnum, ix);
+ printf(" %08x %08x %08x %08x %08x %08x\n",
+ ds[0], ds[1], ds[2], ds[3], ds[4], ds[5]);
+ printf(" %08x %08x %08x %08x %08x\n",
+ ds[6], ds[7], ds[8], ds[9], ds[10]);
+}
+
#endif /* ATH_DEBUG */
Modified: trunk/sys/dev/ath/if_ath_debug.h
===================================================================
--- trunk/sys/dev/ath/if_ath_debug.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_debug.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_ath_debug.h 251655 2013-06-12 14:52:57Z adrian $
*/
#ifndef __IF_ATH_DEBUG_H__
#define __IF_ATH_DEBUG_H__
@@ -34,35 +35,62 @@
#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_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_SW_TX_FILT = 0x400000000ULL, /* SW TX FF */
+ ATH_DEBUG_NODE_PWRSAVE = 0x800000000ULL, /* node powersave */
+ ATH_DEBUG_DIVERSITY = 0x1000000000ULL, /* Diversity logic */
+
+ ATH_DEBUG_ANY = 0xffffffffffffffffULL
};
-extern int ath_debug;
+enum {
+ ATH_KTR_RXPROC = 0x00000001,
+ ATH_KTR_TXPROC = 0x00000002,
+ ATH_KTR_TXCOMP = 0x00000004,
+ ATH_KTR_SWQ = 0x00000008,
+ ATH_KTR_INTERRUPTS = 0x00000010,
+ ATH_KTR_ERROR = 0x00000020,
+ ATH_KTR_NODE = 0x00000040,
+ ATH_KTR_TX = 0x00000080,
+};
+#define ATH_KTR(_sc, _km, _kf, ...) do { \
+ if (sc->sc_ktrdebug & (_km)) \
+ CTR##_kf(KTR_DEV, __VA_ARGS__); \
+ } while (0)
+
+extern uint64_t ath_debug;
+
#define IFF_DUMPPKTS(sc, m) \
((sc->sc_debug & (m)) || \
(sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
@@ -79,7 +107,11 @@
u_int ix, int);
extern void ath_printtxbuf(struct ath_softc *, const struct ath_buf *bf,
u_int qnum, u_int ix, int done);
+extern void ath_printtxstatbuf(struct ath_softc *sc, const struct ath_buf *bf,
+ const uint32_t *ds, u_int qnum, u_int ix, int done);
#else /* ATH_DEBUG */
+#define ATH_KTR(_sc, _km, _kf, ...) do { } while (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 { \
Modified: trunk/sys/dev/ath/if_ath_keycache.c
===================================================================
--- trunk/sys/dev/ath/if_ath_keycache.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_keycache.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -28,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_keycache.c 243318 2012-11-19 23:54:05Z adrian $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -178,7 +179,8 @@
* cache slots for TKIP with hardware MIC support.
*/
int
-ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
+ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
+ const struct ieee80211_key *k,
struct ieee80211_node *bss)
{
#define N(a) (sizeof(a)/sizeof(a[0]))
@@ -212,7 +214,32 @@
} else
hk.kv_type = HAL_CIPHER_CLR;
- if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) {
+ /*
+ * If we're installing a clear cipher key and
+ * the hardware doesn't support that, just succeed.
+ * Leave it up to the net80211 layer to figure it out.
+ */
+ if (hk.kv_type == HAL_CIPHER_CLR && sc->sc_hasclrkey == 0) {
+ return (1);
+ }
+
+ /*
+ * XXX TODO: check this:
+ *
+ * Group keys on hardware that supports multicast frame
+ * key search should only be done in adhoc/hostap mode,
+ * not STA mode.
+ *
+ * XXX TODO: what about mesh, tdma?
+ */
+#if 0
+ if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
+ vap->iv_opmode == IEEE80211_M_IBSS) &&
+#else
+ if (
+#endif
+ (k->wk_flags & IEEE80211_KEY_GROUP) &&
+ sc->sc_mcastkey) {
/*
* Group keys on hardware that supports multicast frame
* key search use a MAC that is the sender's address with
@@ -347,6 +374,14 @@
#define N(a) (sizeof(a)/sizeof(a[0]))
u_int i, keyix;
+ if (sc->sc_hasclrkey == 0) {
+ /*
+ * Map to slot 0 for the AR5210.
+ */
+ *txkeyix = *rxkeyix = 0;
+ return (1);
+ }
+
/* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
for (i = 0; i < N(sc->sc_keymap); i++) {
u_int8_t b = sc->sc_keymap[i];
@@ -493,5 +528,5 @@
{
struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
- return ath_keyset(sc, k, vap->iv_bss);
+ return ath_keyset(sc, vap, k, vap->iv_bss);
}
Modified: trunk/sys/dev/ath/if_ath_keycache.h
===================================================================
--- trunk/sys/dev/ath/if_ath_keycache.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_keycache.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2011 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_ath_keycache.h 227357 2011-11-08 19:25:52Z adrian $
*/
#ifndef __IF_ATH_CRYPTO_H__
@@ -37,7 +38,7 @@
extern int ath_key_delete(struct ieee80211vap *, const struct ieee80211_key *);
extern int ath_key_set(struct ieee80211vap *, const struct ieee80211_key *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
-extern int ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
- struct ieee80211_node *bss);
+extern int ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
+ const struct ieee80211_key *k, struct ieee80211_node *bss);
#endif
Added: trunk/sys/dev/ath/if_ath_led.c
===================================================================
--- trunk/sys/dev/ath/if_ath_led.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_led.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,191 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_led.c 237611 2012-06-26 22:16:53Z 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().
+ */
+#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_led.h>
+
+/*
+ * Software LED driver routines.
+ */
+
+/*
+ * XXX TODO: move the LED sysctls here.
+ */
+
+
+/*
+ * Configure the hardware for software and LED blinking.
+ * The user may choose to configure part of each, depending upon the
+ * NIC being used.
+ *
+ * This requires the configuration to be set before this function
+ * is called.
+ */
+void
+ath_led_config(struct ath_softc *sc)
+{
+ /* Software LED blinking - GPIO controlled LED */
+ if (sc->sc_softled) {
+ ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
+ HAL_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
+ }
+
+ /* Hardware LED blinking - MAC controlled LED */
+ if (sc->sc_hardled) {
+ /*
+ * Only enable each LED if required.
+ *
+ * Some NICs only have one LED connected; others may
+ * have GPIO1/GPIO2 connected to other hardware.
+ */
+ if (sc->sc_led_pwr_pin > 0)
+ ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_pwr_pin,
+ 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_OUTPUT_MUX_MAC_NETWORK_LED);
+ }
+}
+
+static void
+ath_led_done(void *arg)
+{
+ struct ath_softc *sc = arg;
+
+ sc->sc_blinking = 0;
+}
+
+/*
+ * Turn the LED off: flip the pin and then set a timer so no
+ * update will happen for the specified duration.
+ */
+static void
+ath_led_off(void *arg)
+{
+ struct ath_softc *sc = arg;
+
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
+ callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc);
+}
+
+/*
+ * Blink the LED according to the specified on/off times.
+ */
+static void
+ath_led_blink(struct ath_softc *sc, int on, int off)
+{
+ DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off);
+ ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon);
+ sc->sc_blinking = 1;
+ sc->sc_ledoff = off;
+ callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc);
+}
+
+void
+ath_led_event(struct ath_softc *sc, int rix)
+{
+ sc->sc_ledevent = ticks; /* time of last event */
+ if (sc->sc_blinking) /* don't interrupt active blink */
+ return;
+ ath_led_blink(sc, sc->sc_hwmap[rix].ledon, sc->sc_hwmap[rix].ledoff);
+}
Property changes on: trunk/sys/dev/ath/if_ath_led.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_led.h
===================================================================
--- trunk/sys/dev/ath/if_ath_led.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_led.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,38 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_led.h 228888 2011-12-26 05:46:22Z adrian $
+ */
+#ifndef __IF_ATH_LED_H__
+#define __IF_ATH_LED_H__
+
+extern void ath_led_event(struct ath_softc *sc, int rix);
+extern void ath_led_config(struct ath_softc *sc);
+
+#endif
Property changes on: trunk/sys/dev/ath/if_ath_led.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_lna_div.c
===================================================================
--- trunk/sys/dev/ath/if_ath_lna_div.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_lna_div.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,1014 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 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: stable/10/sys/dev/ath/if_ath_lna_div.c 332320 2018-04-09 12:53:15Z emaste $
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_lna_div.c 332320 2018-04-09 12:53:15Z emaste $");
+
+/*
+ * This module handles LNA diversity for those chips which implement LNA
+ * mixing (AR9285/AR9485.)
+ */
+#include "opt_ath.h"
+#include "opt_inet.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <net80211/ieee80211_var.h>
+
+#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_lna_div.h>
+
+/* Linux compability macros */
+/*
+ * XXX these don't handle rounding, underflow, overflow, wrapping!
+ */
+#define msecs_to_jiffies(a) ( (a) * hz / 1000 )
+
+/*
+ * Methods which are required
+ */
+
+/*
+ * Attach the LNA diversity to the given interface
+ */
+int
+ath_lna_div_attach(struct ath_softc *sc)
+{
+ struct if_ath_ant_comb_state *ss;
+ HAL_ANT_COMB_CONFIG div_ant_conf;
+
+ /* Only do this if diversity is enabled */
+ if (! ath_hal_hasdivantcomb(sc->sc_ah))
+ return (0);
+
+ ss = malloc(sizeof(struct if_ath_ant_comb_state),
+ M_TEMP, M_WAITOK | M_ZERO);
+ if (ss == NULL) {
+ device_printf(sc->sc_dev, "%s: failed to allocate\n",
+ __func__);
+ /* Don't fail at this point */
+ return (0);
+ }
+
+ /* Fetch the hardware configuration */
+ OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
+ ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
+
+ /* Figure out what the hardware specific bits should be */
+ if ((div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_1) ||
+ (div_ant_conf.antdiv_configgroup == HAL_ANTDIV_CONFIG_GROUP_2)) {
+ ss->lna1_lna2_delta = -9;
+ } else {
+ ss->lna1_lna2_delta = -3;
+ }
+
+ /* Let's flip this on */
+ sc->sc_lna_div = ss;
+ sc->sc_dolnadiv = 1;
+
+ return (0);
+}
+
+/*
+ * Detach the LNA diversity state from the given interface
+ */
+int
+ath_lna_div_detach(struct ath_softc *sc)
+{
+ if (sc->sc_lna_div != NULL) {
+ free(sc->sc_lna_div, M_TEMP);
+ sc->sc_lna_div = NULL;
+ }
+ sc->sc_dolnadiv = 0;
+ return (0);
+}
+
+/*
+ * Enable LNA diversity on the current channel if it's required.
+ */
+int
+ath_lna_div_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
+{
+
+ return (0);
+}
+
+/*
+ * Handle ioctl requests from the diagnostic interface.
+ *
+ * The initial part of this code resembles ath_ioctl_diag();
+ * it's likely a good idea to reduce duplication between
+ * these two routines.
+ */
+int
+ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad)
+{
+ unsigned int id = ad->ad_id & ATH_DIAG_ID;
+ void *indata = NULL;
+ void *outdata = NULL;
+ u_int32_t insize = ad->ad_in_size;
+ u_int32_t outsize = ad->ad_out_size;
+ int error = 0;
+// int val;
+
+ if (ad->ad_id & ATH_DIAG_IN) {
+ /*
+ * Copy in data.
+ */
+ indata = malloc(insize, M_TEMP, M_NOWAIT);
+ if (indata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ error = copyin(ad->ad_in_data, indata, insize);
+ if (error)
+ goto bad;
+ }
+ if (ad->ad_id & ATH_DIAG_DYN) {
+ /*
+ * Allocate a buffer for the results (otherwise the HAL
+ * returns a pointer to a buffer where we can read the
+ * results). Note that we depend on the HAL leaving this
+ * pointer for us to use below in reclaiming the buffer;
+ * may want to be more defensive.
+ */
+ outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO);
+ if (outdata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ }
+ switch (id) {
+ default:
+ error = EINVAL;
+ goto bad;
+ }
+ if (outsize < ad->ad_out_size)
+ ad->ad_out_size = outsize;
+ if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
+ error = EFAULT;
+bad:
+ if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
+ free(indata, M_TEMP);
+ if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
+ free(outdata, M_TEMP);
+ return (error);
+}
+
+static HAL_BOOL
+ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
+ int main_rssi_avg, int alt_rssi_avg, int pkt_count)
+{
+ return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
+ (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
+}
+
+static void
+ath_lnaconf_alt_good_scan(struct if_ath_ant_comb_state *antcomb,
+ HAL_ANT_COMB_CONFIG *ant_conf, int main_rssi_avg)
+{
+ antcomb->quick_scan_cnt = 0;
+
+ if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = main_rssi_avg;
+ else if (ant_conf->main_lna_conf == HAL_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = main_rssi_avg;
+
+ switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
+ case (0x10): /* LNA2 A-B */
+ antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
+ break;
+ case (0x20): /* LNA1 A-B */
+ antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ antcomb->main_conf = HAL_ANT_DIV_COMB_LNA2;
+ antcomb->first_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1;
+ antcomb->first_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case (0x13): /* LNA2 A+B */
+ antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA1;
+ break;
+ case (0x23): /* LNA1 A+B */
+ antcomb->main_conf = HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ antcomb->first_quick_scan_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ antcomb->second_quick_scan_conf = HAL_ANT_DIV_COMB_LNA2;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+ath_select_ant_div_from_quick_scan(struct if_ath_ant_comb_state *antcomb,
+ HAL_ANT_COMB_CONFIG *div_ant_conf, int main_rssi_avg,
+ int alt_rssi_avg, int alt_ratio)
+{
+ /* alt_good */
+ switch (antcomb->quick_scan_cnt) {
+ case 0:
+ /* set alt to main, and alt to first conf */
+ div_ant_conf->main_lna_conf = antcomb->main_conf;
+ div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
+ break;
+ case 1:
+ /* set alt to main, and alt to first conf */
+ div_ant_conf->main_lna_conf = antcomb->main_conf;
+ div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+ antcomb->rssi_first = main_rssi_avg;
+ antcomb->rssi_second = alt_rssi_avg;
+
+ if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
+ /* main is LNA1 */
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->first_ratio = AH_TRUE;
+ else
+ antcomb->first_ratio = AH_FALSE;
+ } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->first_ratio = AH_TRUE;
+ else
+ antcomb->first_ratio = AH_FALSE;
+ } else {
+ if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+ (alt_rssi_avg > main_rssi_avg)) &&
+ (antcomb->total_pkt_count > 50))
+ antcomb->first_ratio = AH_TRUE;
+ else
+ antcomb->first_ratio = AH_FALSE;
+ }
+ break;
+ case 2:
+ antcomb->alt_good = AH_FALSE;
+ antcomb->scan_not_start = AH_FALSE;
+ antcomb->scan = AH_FALSE;
+ antcomb->rssi_first = main_rssi_avg;
+ antcomb->rssi_third = alt_rssi_avg;
+
+ if (antcomb->second_quick_scan_conf == HAL_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = alt_rssi_avg;
+ else if (antcomb->second_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = alt_rssi_avg;
+ else if (antcomb->second_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+ if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2)
+ antcomb->rssi_lna2 = main_rssi_avg;
+ else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1)
+ antcomb->rssi_lna1 = main_rssi_avg;
+ }
+
+ if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+ div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
+ else
+ div_ant_conf->main_lna_conf = HAL_ANT_DIV_COMB_LNA1;
+
+ if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->second_ratio = AH_TRUE;
+ else
+ antcomb->second_ratio = AH_FALSE;
+ } else if (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2) {
+ if (ath_is_alt_ant_ratio_better(alt_ratio,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+ ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+ main_rssi_avg, alt_rssi_avg,
+ antcomb->total_pkt_count))
+ antcomb->second_ratio = AH_TRUE;
+ else
+ antcomb->second_ratio = AH_FALSE;
+ } else {
+ if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+ (alt_rssi_avg > main_rssi_avg +
+ ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+ (alt_rssi_avg > main_rssi_avg)) &&
+ (antcomb->total_pkt_count > 50))
+ antcomb->second_ratio = AH_TRUE;
+ else
+ antcomb->second_ratio = AH_FALSE;
+ }
+
+ /* set alt to the conf with maximun ratio */
+ if (antcomb->first_ratio && antcomb->second_ratio) {
+ if (antcomb->rssi_second > antcomb->rssi_third) {
+ /* first alt*/
+ if ((antcomb->first_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA1) ||
+ (antcomb->first_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2*/
+ if (div_ant_conf->main_lna_conf ==
+ HAL_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->first_quick_scan_conf;
+ } else if ((antcomb->second_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA1) ||
+ (antcomb->second_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA2)) {
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ HAL_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ } else {
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->second_quick_scan_conf;
+ }
+ } else if (antcomb->first_ratio) {
+ /* first alt */
+ if ((antcomb->first_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA1) ||
+ (antcomb->first_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ HAL_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->first_quick_scan_conf;
+ } else if (antcomb->second_ratio) {
+ /* second alt */
+ if ((antcomb->second_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA1) ||
+ (antcomb->second_quick_scan_conf ==
+ HAL_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ HAL_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf =
+ antcomb->second_quick_scan_conf;
+ } else {
+ /* main is largest */
+ if ((antcomb->main_conf == HAL_ANT_DIV_COMB_LNA1) ||
+ (antcomb->main_conf == HAL_ANT_DIV_COMB_LNA2))
+ /* Set alt LNA1 or LNA2 */
+ if (div_ant_conf->main_lna_conf ==
+ HAL_ANT_DIV_COMB_LNA2)
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ else
+ div_ant_conf->alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ else
+ /* Set alt to A+B or A-B */
+ div_ant_conf->alt_lna_conf = antcomb->main_conf;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+ath_ant_adjust_fast_divbias(struct if_ath_ant_comb_state *antcomb,
+ int alt_ratio, int alt_ant_ratio_th, u_int config_group,
+ HAL_ANT_COMB_CONFIG *pdiv_ant_conf)
+{
+
+ if (config_group == HAL_ANTDIV_CONFIG_GROUP_1) {
+ switch ((pdiv_ant_conf->main_lna_conf << 4)
+ | pdiv_ant_conf->alt_lna_conf) {
+ case (0x01): //A-B LNA2
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x02): //A-B LNA1
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x03): //A-B A+B
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x10): //LNA2 A-B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
+ pdiv_ant_conf->fast_div_bias = 0x3f;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x12): //LNA2 LNA1
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x13): //LNA2 A+B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
+ pdiv_ant_conf->fast_div_bias = 0x3f;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x20): //LNA1 A-B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
+ pdiv_ant_conf->fast_div_bias = 0x3f;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x21): //LNA1 LNA2
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x23): //LNA1 A+B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
+ pdiv_ant_conf->fast_div_bias = 0x3f;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x30): //A+B A-B
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x31): //A+B LNA2
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x32): //A+B LNA1
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ default:
+ break;
+ }
+ } else if (config_group == HAL_ANTDIV_CONFIG_GROUP_2) {
+ switch ((pdiv_ant_conf->main_lna_conf << 4)
+ | pdiv_ant_conf->alt_lna_conf) {
+ case (0x01): //A-B LNA2
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x02): //A-B LNA1
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x03): //A-B A+B
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x10): //LNA2 A-B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > alt_ant_ratio_th)) {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x2;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x12): //LNA2 LNA1
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x13): //LNA2 A+B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > alt_ant_ratio_th)) {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x2;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x20): //LNA1 A-B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > alt_ant_ratio_th)) {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x2;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x21): //LNA1 LNA2
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x23): //LNA1 A+B
+ if ((antcomb->scan == 0)
+ && (alt_ratio > alt_ant_ratio_th)) {
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ } else {
+ pdiv_ant_conf->fast_div_bias = 0x2;
+ }
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x30): //A+B A-B
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x31): //A+B LNA2
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ case (0x32): //A+B LNA1
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ pdiv_ant_conf->main_gaintb = 0;
+ pdiv_ant_conf->alt_gaintb = 0;
+ break;
+ default:
+ break;
+ }
+ } else { /* DEFAULT_ANTDIV_CONFIG_GROUP */
+ switch ((pdiv_ant_conf->main_lna_conf << 4) | pdiv_ant_conf->alt_lna_conf) {
+ case (0x01): //A-B LNA2
+ pdiv_ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x02): //A-B LNA1
+ pdiv_ant_conf->fast_div_bias = 0x3d;
+ break;
+ case (0x03): //A-B A+B
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x10): //LNA2 A-B
+ pdiv_ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x12): //LNA2 LNA1
+ pdiv_ant_conf->fast_div_bias = 0x2;
+ break;
+ case (0x13): //LNA2 A+B
+ pdiv_ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x20): //LNA1 A-B
+ pdiv_ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x21): //LNA1 LNA2
+ pdiv_ant_conf->fast_div_bias = 0x0;
+ break;
+ case (0x23): //LNA1 A+B
+ pdiv_ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x30): //A+B A-B
+ pdiv_ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x31): //A+B LNA2
+ pdiv_ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x32): //A+B LNA1
+ pdiv_ant_conf->fast_div_bias = 0x3d;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * AR9485/AR933x TODO:
+ * + Select a ratio based on whether RSSI is low or not; but I need
+ * to figure out what "low_rssi_th" is sourced from.
+ * + What's ath_ant_div_comb_alt_check() in the reference driver do?
+ * + .. and there's likely a bunch of other things to include in this.
+ */
+
+/* Antenna diversity and combining */
+void
+ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
+ unsigned long ticks, int hz)
+{
+ HAL_ANT_COMB_CONFIG div_ant_conf;
+ struct if_ath_ant_comb_state *antcomb = sc->sc_lna_div;
+ int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+ int curr_main_set, curr_bias;
+ int main_rssi = rs->rs_rssi_ctl[0];
+ int alt_rssi = rs->rs_rssi_ctl[1];
+ int rx_ant_conf, main_ant_conf, alt_ant_conf;
+ HAL_BOOL short_scan = AH_FALSE;
+
+ rx_ant_conf = (rs->rs_rssi_ctl[2] >> 4) & ATH_ANT_RX_MASK;
+ main_ant_conf = (rs->rs_rssi_ctl[2] >> 2) & ATH_ANT_RX_MASK;
+ alt_ant_conf = (rs->rs_rssi_ctl[2] >> 0) & ATH_ANT_RX_MASK;
+
+#if 0
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY,
+ "%s: RSSI %d/%d, conf %x/%x, rxconf %x, LNA: %d; ANT: %d; "
+ "FastDiv: %d\n",
+ __func__,
+ main_rssi,
+ alt_rssi,
+ main_ant_conf,
+ alt_ant_conf,
+ rx_ant_conf,
+ !!(rs->rs_rssi_ctl[2] & 0x80),
+ !!(rs->rs_rssi_ctl[2] & 0x40),
+ !!(rs->rs_rssi_ext[2] & 0x40));
+#endif
+
+ /*
+ * If LNA diversity combining isn't enabled, don't run this.
+ */
+ if (! sc->sc_dolnadiv)
+ return;
+
+ /*
+ * XXX this is ugly, but the HAL code attaches the
+ * LNA diversity to the TX antenna settings.
+ * I don't know why.
+ */
+ if (sc->sc_txantenna != HAL_ANT_VARIABLE)
+ return;
+
+ /* Record packet only when alt_rssi is positive */
+ if (main_rssi > 0 && alt_rssi > 0) {
+ antcomb->total_pkt_count++;
+ antcomb->main_total_rssi += main_rssi;
+ antcomb->alt_total_rssi += alt_rssi;
+ if (main_ant_conf == rx_ant_conf)
+ antcomb->main_recv_cnt++;
+ else
+ antcomb->alt_recv_cnt++;
+ }
+
+ /* Short scan check */
+ if (antcomb->scan && antcomb->alt_good) {
+ if (time_after(ticks, antcomb->scan_start_time +
+ msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+ short_scan = AH_TRUE;
+ else
+ if (antcomb->total_pkt_count ==
+ ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+ alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+ antcomb->total_pkt_count);
+ if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ short_scan = AH_TRUE;
+ }
+ }
+
+#if 0
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY,
+ "%s: total pkt=%d, aggr=%d, short_scan=%d\n",
+ __func__,
+ antcomb->total_pkt_count,
+ !! (rs->rs_moreaggr),
+ !! (short_scan));
+#endif
+
+ if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+ rs->rs_moreaggr) && !short_scan)
+ return;
+
+ if (antcomb->total_pkt_count) {
+ alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+ antcomb->total_pkt_count);
+ main_rssi_avg = (antcomb->main_total_rssi /
+ antcomb->total_pkt_count);
+ alt_rssi_avg = (antcomb->alt_total_rssi /
+ antcomb->total_pkt_count);
+ }
+
+ OS_MEMZERO(&div_ant_conf, sizeof(div_ant_conf));
+
+ ath_hal_div_comb_conf_get(sc->sc_ah, &div_ant_conf);
+ curr_alt_set = div_ant_conf.alt_lna_conf;
+ curr_main_set = div_ant_conf.main_lna_conf;
+ curr_bias = div_ant_conf.fast_div_bias;
+
+ antcomb->count++;
+
+ if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ ath_lnaconf_alt_good_scan(antcomb, &div_ant_conf,
+ main_rssi_avg);
+ antcomb->alt_good = AH_TRUE;
+ } else {
+ antcomb->alt_good = AH_FALSE;
+ }
+
+ antcomb->count = 0;
+ antcomb->scan = AH_TRUE;
+ antcomb->scan_not_start = AH_TRUE;
+ }
+
+ if (!antcomb->scan) {
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ if (curr_alt_set == HAL_ANT_DIV_COMB_LNA2) {
+ /* Switch main and alt LNA */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ } else if (curr_alt_set == HAL_ANT_DIV_COMB_LNA1) {
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ }
+
+ goto div_comb_done;
+ } else if ((curr_alt_set != HAL_ANT_DIV_COMB_LNA1) &&
+ (curr_alt_set != HAL_ANT_DIV_COMB_LNA2)) {
+ /* Set alt to another LNA */
+ if (curr_main_set == HAL_ANT_DIV_COMB_LNA2)
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1)
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+
+ goto div_comb_done;
+ }
+
+ if ((alt_rssi_avg < (main_rssi_avg +
+ antcomb->lna1_lna2_delta)))
+ goto div_comb_done;
+ }
+
+ if (!antcomb->scan_not_start) {
+ switch (curr_alt_set) {
+ case HAL_ANT_DIV_COMB_LNA2:
+ antcomb->rssi_lna2 = alt_rssi_avg;
+ antcomb->rssi_lna1 = main_rssi_avg;
+ antcomb->scan = AH_TRUE;
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case HAL_ANT_DIV_COMB_LNA1:
+ antcomb->rssi_lna1 = alt_rssi_avg;
+ antcomb->rssi_lna2 = main_rssi_avg;
+ antcomb->scan = AH_TRUE;
+ /* set to A+B */
+ div_ant_conf.main_lna_conf = HAL_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ break;
+ case HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+ antcomb->rssi_add = alt_rssi_avg;
+ antcomb->scan = AH_TRUE;
+ /* set to A-B */
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ break;
+ case HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+ antcomb->rssi_sub = alt_rssi_avg;
+ antcomb->scan = AH_FALSE;
+ if (antcomb->rssi_lna2 >
+ (antcomb->rssi_lna1 +
+ ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+ /* use LNA2 as main LNA */
+ if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+ (antcomb->rssi_add > antcomb->rssi_sub)) {
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ } else if (antcomb->rssi_sub >
+ antcomb->rssi_lna1) {
+ /* set to A-B */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ } else {
+ /* set to LNA1 */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ }
+ } else {
+ /* use LNA1 as main LNA */
+ if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+ (antcomb->rssi_add > antcomb->rssi_sub)) {
+ /* set to A+B */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+ } else if (antcomb->rssi_sub >
+ antcomb->rssi_lna1) {
+ /* set to A-B */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+ } else {
+ /* set to LNA2 */
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ if (!antcomb->alt_good) {
+ antcomb->scan_not_start = AH_FALSE;
+ /* Set alt to another LNA */
+ if (curr_main_set == HAL_ANT_DIV_COMB_LNA2) {
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ } else if (curr_main_set == HAL_ANT_DIV_COMB_LNA1) {
+ div_ant_conf.main_lna_conf =
+ HAL_ANT_DIV_COMB_LNA1;
+ div_ant_conf.alt_lna_conf =
+ HAL_ANT_DIV_COMB_LNA2;
+ }
+ goto div_comb_done;
+ }
+ }
+
+ ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+ main_rssi_avg, alt_rssi_avg,
+ alt_ratio);
+
+ antcomb->quick_scan_cnt++;
+
+div_comb_done:
+#if 0
+ ath_ant_div_conf_fast_divbias(&div_ant_conf);
+#endif
+
+ ath_ant_adjust_fast_divbias(antcomb,
+ alt_ratio,
+ ATH_ANT_DIV_COMB_ALT_ANT_RATIO,
+ div_ant_conf.antdiv_configgroup,
+ &div_ant_conf);
+
+ ath_hal_div_comb_conf_set(sc->sc_ah, &div_ant_conf);
+
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: total_pkt_count=%d\n",
+ __func__, antcomb->total_pkt_count);
+
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_total_rssi=%d\n",
+ __func__, antcomb->main_total_rssi);
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_total_rssi=%d\n",
+ __func__, antcomb->alt_total_rssi);
+
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_rssi_avg=%d\n",
+ __func__, main_rssi_avg);
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_alt_rssi_avg=%d\n",
+ __func__, alt_rssi_avg);
+
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_recv_cnt=%d\n",
+ __func__, antcomb->main_recv_cnt);
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: alt_recv_cnt=%d\n",
+ __func__, antcomb->alt_recv_cnt);
+
+// if (curr_alt_set != div_ant_conf.alt_lna_conf)
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: lna_conf: %x -> %x\n",
+ __func__, curr_alt_set, div_ant_conf.alt_lna_conf);
+// if (curr_main_set != div_ant_conf.main_lna_conf)
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: main_lna_conf: %x -> %x\n",
+ __func__, curr_main_set, div_ant_conf.main_lna_conf);
+// if (curr_bias != div_ant_conf.fast_div_bias)
+ DPRINTF(sc, ATH_DEBUG_DIVERSITY, "%s: fast_div_bias: %x -> %x\n",
+ __func__, curr_bias, div_ant_conf.fast_div_bias);
+
+ antcomb->scan_start_time = ticks;
+ antcomb->total_pkt_count = 0;
+ antcomb->main_total_rssi = 0;
+ antcomb->alt_total_rssi = 0;
+ antcomb->main_recv_cnt = 0;
+ antcomb->alt_recv_cnt = 0;
+}
+
Property changes on: trunk/sys/dev/ath/if_ath_lna_div.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_lna_div.h
===================================================================
--- trunk/sys/dev/ath/if_ath_lna_div.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_lna_div.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,90 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 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: stable/10/sys/dev/ath/if_ath_lna_div.h 251730 2013-06-14 03:42:10Z adrian $
+ */
+#ifndef __IF_ATH_LNA_DIV_H__
+#define __IF_ATH_LNA_DIV_H__
+
+#define ATH_ANT_RX_CURRENT_SHIFT 4
+#define ATH_ANT_RX_MAIN_SHIFT 2
+#define ATH_ANT_RX_MASK 0x3
+
+#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
+#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
+#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
+#define ATH_ANT_DIV_COMB_INIT_COUNT 95
+#define ATH_ANT_DIV_COMB_MAX_COUNT 100
+#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
+#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
+
+#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
+
+struct if_ath_ant_comb_state {
+ uint16_t count;
+ uint16_t total_pkt_count;
+ HAL_BOOL scan;
+ HAL_BOOL scan_not_start;
+ int main_total_rssi;
+ int alt_total_rssi;
+ int alt_recv_cnt;
+ int main_recv_cnt;
+ int rssi_lna1;
+ int rssi_lna2;
+ int rssi_add;
+ int rssi_sub;
+ int rssi_first;
+ int rssi_second;
+ int rssi_third;
+ HAL_BOOL alt_good;
+ int quick_scan_cnt;
+ int main_conf;
+ HAL_ANT_DIV_COMB_LNA_CONF first_quick_scan_conf;
+ HAL_ANT_DIV_COMB_LNA_CONF second_quick_scan_conf;
+ int first_bias;
+ int second_bias;
+ HAL_BOOL first_ratio;
+ HAL_BOOL second_ratio;
+ unsigned long scan_start_time;
+ int lna1_lna2_delta;
+};
+
+extern int ath_lna_div_attach(struct ath_softc *sc);
+extern int ath_lna_div_detach(struct ath_softc *sc);
+extern int ath_lna_div_ioctl(struct ath_softc *sc, struct ath_diag *ad);
+extern int ath_lna_div_enable(struct ath_softc *sc,
+ const struct ieee80211_channel *ch);
+
+extern void ath_lna_rx_comb_scan(struct ath_softc *sc,
+ struct ath_rx_status *rs, unsigned long ticks, int hz);
+
+#endif /* __IF_ATH_LNA_DIV_H__ */
Property changes on: trunk/sys/dev/ath/if_ath_lna_div.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/if_ath_misc.h
===================================================================
--- trunk/sys/dev/ath/if_ath_misc.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_misc.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_ath_misc.h 251014 2013-05-26 22:23:39Z adrian $
*/
#ifndef __IF_ATH_MISC_H__
#define __IF_ATH_MISC_H__
@@ -48,11 +49,103 @@
((((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,
+ 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 *);
+extern int ath_reset(struct ifnet *, ATH_RESET_TYPE);
+extern void ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf,
+ int fail);
+extern void ath_tx_update_ratectrl(struct ath_softc *sc,
+ struct ieee80211_node *ni, struct ath_rc_series *rc,
+ struct ath_tx_status *ts, int frmlen, int nframes, int nbad);
+extern int ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask,
+ uint32_t *hangs);
+
+extern void ath_tx_freebuf(struct ath_softc *sc, struct ath_buf *bf,
+ int status);
+extern void ath_txq_freeholdingbuf(struct ath_softc *sc,
+ struct ath_txq *txq);
+
+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_alloc_desc(struct ath_softc *sc,
+ struct ath_descdma *dd, ath_bufhead *head, const char *name,
+ int ds_size, int ndesc);
+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);
+
+extern void ath_legacy_attach_comp_func(struct ath_softc *sc);
+
+extern void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq);
+
+extern void ath_legacy_tx_drain(struct ath_softc *sc,
+ ATH_RESET_TYPE reset_type);
+
+extern void ath_tx_process_buf_completion(struct ath_softc *sc,
+ struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf);
+
+extern int ath_stoptxdma(struct ath_softc *sc);
+
+extern void ath_tx_update_tim(struct ath_softc *sc,
+ struct ieee80211_node *ni, int enable);
+
+/*
+ * 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);
+extern void ath_start_task(void *arg, int npending);
+
+extern void ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq);
+
+/*
+ * Kick the frame TX task.
+ */
+static inline void
+ath_tx_kick(struct ath_softc *sc)
+{
+
+ /* XXX NULL for now */
+}
+
+/*
+ * Kick the software TX queue task.
+ */
+static inline void
+ath_tx_swq_kick(struct ath_softc *sc)
+{
+
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_txqtask);
+}
+
#endif
Modified: trunk/sys/dev/ath/if_ath_pci.c
===================================================================
--- trunk/sys/dev/ath/if_ath_pci.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_pci.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -28,11 +29,12 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_pci.c 246453 2013-02-07 07:50:16Z adrian $");
/*
* PCI/Cardbus front-end for the Atheros Wireless LAN controller driver.
*/
+#include "opt_ath.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -60,6 +62,12 @@
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
+/* For EEPROM firmware */
+#ifdef ATH_EEPROM_FIRMWARE
+#include <sys/linker.h>
+#include <sys/firmware.h>
+#endif /* ATH_EEPROM_FIRMWARE */
+
/*
* PCI glue.
*/
@@ -73,7 +81,50 @@
#define BS_BAR 0x10
#define PCIR_RETRY_TIMEOUT 0x41
+#define PCIR_CFG_PMCSR 0x48
+#define DEFAULT_CACHESIZE 32
+
+static void
+ath_pci_setup(device_t dev)
+{
+ uint8_t cz;
+
+ /* XXX TODO: need to override the _system_ saved copies of this */
+
+ /*
+ * If the cache line size is 0, force it to a reasonable
+ * value.
+ */
+ cz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ if (cz == 0) {
+ pci_write_config(dev, PCIR_CACHELNSZ,
+ DEFAULT_CACHESIZE / 4, 1);
+ }
+
+ /* Override the system latency timer */
+ pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1);
+
+ /* If a PCI NIC, force wakeup */
+#ifdef ATH_PCI_WAKEUP_WAR
+ /* XXX TODO: don't do this for non-PCI (ie, PCIe, Cardbus!) */
+ if (1) {
+ uint16_t pmcsr;
+ pmcsr = pci_read_config(dev, PCIR_CFG_PMCSR, 2);
+ pmcsr |= 3;
+ pci_write_config(dev, PCIR_CFG_PMCSR, pmcsr, 2);
+ pmcsr &= ~3;
+ pci_write_config(dev, PCIR_CFG_PMCSR, pmcsr, 2);
+ }
+#endif
+
+ /*
+ * Disable retry timeout to keep PCI Tx retries from
+ * interfering with C3 CPU state.
+ */
+ pci_write_config(dev, PCIR_RETRY_TIMEOUT, 0, 1);
+}
+
static int
ath_pci_probe(device_t dev)
{
@@ -94,6 +145,10 @@
struct ath_softc *sc = &psc->sc_sc;
int error = ENXIO;
int rid;
+#ifdef ATH_EEPROM_FIRMWARE
+ const struct firmware *fw = NULL;
+ const char *buf;
+#endif
sc->sc_dev = dev;
@@ -103,10 +158,9 @@
pci_enable_busmaster(dev);
/*
- * Disable retry timeout to keep PCI Tx retries from
- * interfering with C3 CPU state.
+ * Setup other PCI bus configuration parameters.
*/
- pci_write_config(dev, PCIR_RETRY_TIMEOUT, 0, 1);
+ ath_pci_setup(dev);
/*
* Setup memory-mapping of PCI registers.
@@ -163,12 +217,53 @@
goto bad3;
}
+#ifdef ATH_EEPROM_FIRMWARE
+ /*
+ * If there's an EEPROM firmware image, load that in.
+ */
+ if (resource_string_value(device_get_name(dev), device_get_unit(dev),
+ "eeprom_firmware", &buf) == 0) {
+ if (bootverbose)
+ device_printf(dev, "%s: looking up firmware @ '%s'\n",
+ __func__, buf);
+
+ fw = firmware_get(buf);
+ if (fw == NULL) {
+ device_printf(dev, "%s: couldn't find firmware\n",
+ __func__);
+ goto bad3;
+ }
+
+ device_printf(dev, "%s: EEPROM firmware @ %p\n",
+ __func__, fw->data);
+ sc->sc_eepromdata =
+ malloc(fw->datasize, M_TEMP, M_WAITOK | M_ZERO);
+ if (! sc->sc_eepromdata) {
+ device_printf(dev, "%s: can't malloc eepromdata\n",
+ __func__);
+ goto bad3;
+ }
+ memcpy(sc->sc_eepromdata, fw->data, fw->datasize);
+ firmware_put(fw, 0);
+ }
+#endif /* ATH_EEPROM_FIRMWARE */
+
ATH_LOCK_INIT(sc);
+ ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TX_LOCK_INIT(sc);
+ ATH_TX_IC_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_TX_IC_LOCK_DESTROY(sc);
+ ATH_TX_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
bus_dma_tag_destroy(sc->sc_dmat);
bad3:
@@ -190,6 +285,11 @@
/* check if device was removed */
sc->sc_invalid = !bus_child_present(dev);
+ /*
+ * Do a config read to clear pre-existing pci error status.
+ */
+ (void) pci_read_config(dev, PCIR_COMMAND, 4);
+
ath_detach(sc);
bus_generic_detach(dev);
@@ -199,6 +299,14 @@
bus_dma_tag_destroy(sc->sc_dmat);
bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr);
+ 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_TX_IC_LOCK_DESTROY(sc);
+ ATH_TX_LOCK_DESTROY(sc);
ATH_LOCK_DESTROY(sc);
return (0);
@@ -228,6 +336,11 @@
{
struct ath_pci_softc *psc = device_get_softc(dev);
+ /*
+ * Suspend/resume resets the PCI configuration space.
+ */
+ ath_pci_setup(dev);
+
ath_resume(&psc->sc_sc);
return (0);
Added: trunk/sys/dev/ath/if_ath_rx.c
===================================================================
--- trunk/sys/dev/ath/if_ath_rx.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_rx.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,1262 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_rx.c 251655 2013-06-12 14:52:57Z 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 ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
+
+#include <dev/ath/if_ath_lna_div.h>
+
+/*
+ * 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;
+
+ /*
+ * Enable spectral PHY errors if requested by the
+ * spectral module.
+ */
+ if (sc->sc_dospectral)
+ 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_NOWAIT, 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;
+ /* These are only populated from the AR9300 or later */
+ sc->sc_rx_th.wr_v.evm[3] = rs->rs_evm3;
+ sc->sc_rx_th.wr_v.evm[4] = rs->rs_evm4;
+
+ /* direction */
+ sc->sc_rx_th.wr_v.vh_flags = ATH_VENDOR_PKT_RX;
+
+ /* RX rate */
+ sc->sc_rx_th.wr_v.vh_rx_hwrate = rs->rs_rate;
+
+ /* RX flags */
+ sc->sc_rx_th.wr_v.vh_rs_flags = rs->rs_flags;
+
+ if (rs->rs_isaggr)
+ sc->sc_rx_th.wr_v.vh_flags |= ATH_VENDOR_PKT_ISAGGR;
+ if (rs->rs_moreaggr)
+ sc->sc_rx_th.wr_v.vh_flags |= ATH_VENDOR_PKT_MOREAGGR;
+
+ /* phyerr info */
+ if (rs->rs_status & HAL_RXERR_PHY) {
+ sc->sc_rx_th.wr_v.vh_phyerr_code = rs->rs_phyerr;
+ sc->sc_rx_th.wr_v.vh_flags |= ATH_VENDOR_PKT_RXPHYERR;
+ } 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 (rs->rs_status & HAL_RXERR_PHY) {
+ /*
+ * PHY error - make sure the channel flags
+ * reflect the actual channel configuration,
+ * not the received frame.
+ */
+ if (IEEE80211_IS_CHAN_HT40U(sc->sc_curchan))
+ sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U;
+ else if (IEEE80211_IS_CHAN_HT40D(sc->sc_curchan))
+ sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D;
+ else if (IEEE80211_IS_CHAN_HT20(sc->sc_curchan))
+ sc->sc_rx_th.wr_chan_flags |= CHAN_HT20;
+ } else 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);
+ }
+}
+
+/*
+ * Process a single packet.
+ *
+ * The mbuf must already be synced, unmapped and removed from bf->bf_m
+ * by this stage.
+ *
+ * The mbuf must be consumed by this routine - either passed up the
+ * net80211 stack, put on the holding queue, or freed.
+ */
+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 mbuf *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++;
+ if (rs->rs_flags & HAL_RX_STBC)
+ sc->sc_stats.ast_rx_stbc++;
+#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)) {
+ /* 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)) {
+ 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)) {
+ /* NB: bpf needs the mbuf length setup */
+ len = rs->rs_datalen;
+ m->m_pkthdr.len = m->m_len = len;
+ 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);
+ }
+ /* XXX pass MIC errors up for s/w reclaculation */
+ m_freem(m); m = NULL;
+ goto rx_next;
+ }
+rx_accept:
+ 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;
+ m = NULL;
+ 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 */
+ }
+
+ /*
+ * If this is an AR9285/AR9485, then the receive and LNA
+ * configuration is stored in RSSI[2] / EXTRSSI[2].
+ * We can extract this out to build a much better
+ * receive antenna profile.
+ *
+ * Yes, this just blurts over the above RX antenna field
+ * for now. It's fine, the AR9285 doesn't really use
+ * that.
+ *
+ * Later on we should store away the fine grained LNA
+ * information and keep separate counters just for
+ * that. It'll help when debugging the AR9285/AR9485
+ * combined diversity code.
+ */
+ if (sc->sc_rx_lnamixer) {
+ rs->rs_antenna = 0;
+
+ /* Bits 0:1 - the LNA configuration used */
+ rs->rs_antenna |=
+ ((rs->rs_rssi_ctl[2] & HAL_RX_LNA_CFG_USED)
+ >> HAL_RX_LNA_CFG_USED_S);
+
+ /* Bit 2 - the external RX antenna switch */
+ if (rs->rs_rssi_ctl[2] & HAL_RX_LNA_EXTCFG)
+ rs->rs_antenna |= 0x4;
+ }
+
+ 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); m = NULL;
+ 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);
+ m = NULL;
+ /*
+ * 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);
+ m = NULL;
+ }
+
+ /*
+ * At this point we have passed the frame up the stack; thus
+ * the mbuf is no longer ours.
+ */
+
+ /*
+ * 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;
+ }
+
+ /* Handle slow diversity if enabled */
+ if (sc->sc_dolnadiv) {
+ ath_lna_rx_comb_scan(sc, 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:
+ /*
+ * Debugging - complain if we didn't NULL the mbuf pointer
+ * here.
+ */
+ if (m != NULL) {
+ device_printf(sc->sc_dev,
+ "%s: mbuf %p should've been freed!\n",
+ __func__,
+ m);
+ }
+ return (is_good);
+}
+
+#define ATH_RX_MAX 128
+
+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;
+ int kickpcu = 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++;
+ kickpcu = sc->sc_kickpcu;
+ 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 {
+ /*
+ * Don't process too many packets at a time; give the
+ * TX thread time to also run - otherwise the TX
+ * latency can jump by quite a bit, causing throughput
+ * degredation.
+ */
+ if (!kickpcu && npkts >= ATH_RX_MAX)
+ break;
+
+ 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
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_RXSTATUS))
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_RXSTATUS,
+ sc->sc_rx_statuslen, (char *) ds);
+#endif /* ATH_DEBUG_ALQ */
+
+ if (status == HAL_EINPROGRESS)
+ break;
+
+ TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
+ npkts++;
+
+ /*
+ * Process a single 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;
+ if (ath_rx_pkt(sc, rs, status, tsf, nf, HAL_RX_QUEUE_HP, bf, m))
+ 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;
+
+ ATH_KTR(sc, ATH_KTR_RXPROC, 2, "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.
+ */
+ if (resched && kickpcu) {
+ ATH_PCU_LOCK(sc);
+ ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_rx_proc: kickpcu");
+ device_printf(sc->sc_dev, "%s: kickpcu; handled %d packets\n",
+ __func__, npkts);
+
+ /*
+ * Go through the process of fully tearing down
+ * the RX buffers and reinitialising them.
+ *
+ * There's a hardware bug that causes the RX FIFO
+ * to get confused under certain conditions and
+ * constantly write over the same frame, leading
+ * the RX driver code here to get heavily confused.
+ */
+#if 1
+ ath_startrecv(sc);
+#else
+ /*
+ * Disabled for now - it'd be nice to be able to do
+ * this in order to limit the amount of CPU time spent
+ * reinitialising the RX side (and thus minimise RX
+ * drops) however there's a hardware issue that
+ * causes things to get too far out of whack.
+ */
+ /*
+ * 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 */
+#endif
+
+ 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
+
+ /*
+ * If we hit the maximum number of frames in this round,
+ * reschedule for another immediate pass. This gives
+ * the TX and TX completion routines time to run, which
+ * will reduce latency.
+ */
+ if (npkts >= ATH_RX_MAX)
+ sc->sc_rx.recv_sched(sc, resched);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt--;
+ ATH_PCU_UNLOCK(sc);
+}
+
+#undef ATH_RX_MAX
+
+/*
+ * 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;
+
+ ATH_KTR(sc, ATH_KTR_RXPROC, 1, "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;
+
+ 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)
+{
+
+ if (sc->sc_rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ return (0);
+}
+
+static void
+ath_legacy_recv_sched(struct ath_softc *sc, int dosched)
+{
+
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
+}
+
+static void
+ath_legacy_recv_sched_queue(struct ath_softc *sc, HAL_RX_QUEUE q,
+ int dosched)
+{
+
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
+}
+
+void
+ath_recv_setup_legacy(struct ath_softc *sc)
+{
+
+ /* Sensible legacy defaults */
+ /*
+ * XXX this should be changed to properly support the
+ * exact RX descriptor size for each HAL.
+ */
+ sc->sc_rx_statuslen = sizeof(struct ath_desc);
+
+ 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;
+ sc->sc_rx.recv_sched = ath_legacy_recv_sched;
+ sc->sc_rx.recv_sched_queue = ath_legacy_recv_sched_queue;
+}
Property changes on: trunk/sys/dev/ath/if_ath_rx.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_rx.h
===================================================================
--- trunk/sys/dev/ath/if_ath_rx.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_rx.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,66 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_rx.h 249085 2013-04-04 08:21:56Z 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, struct mbuf *m);
+
+extern void ath_recv_setup_legacy(struct ath_softc *sc);
+
+#endif
Property changes on: trunk/sys/dev/ath/if_ath_rx.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_rx_edma.c
===================================================================
--- trunk/sys/dev/ath/if_ath_rx_edma.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_rx_edma.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,949 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_rx_edma.c 252385 2013-06-29 19:57:57Z 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>
+
+#ifdef ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
+
+/*
+ * 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:
+ *
+ * + Make sure the FIFO is correctly flushed and reinitialised
+ * through a reset;
+ * + 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 void ath_edma_recv_proc_queue(struct ath_softc *sc,
+ HAL_RX_QUEUE qtype, int dosched);
+static int ath_edma_recv_proc_deferred_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_sched_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
+ int dosched)
+{
+
+ ath_edma_recv_proc_queue(sc, qtype, dosched);
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
+}
+
+static void
+ath_edma_recv_sched(struct ath_softc *sc, int dosched)
+{
+
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, dosched);
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, dosched);
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
+}
+
+static void
+ath_edma_recv_flush(struct ath_softc *sc)
+{
+
+ DPRINTF(sc, ATH_DEBUG_RECV, "%s: called\n", __func__);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_rxproc_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ /*
+ * Flush any active frames from FIFO -> deferred list
+ */
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 0);
+ ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 0);
+
+ /*
+ * Process what's in the deferred queue
+ */
+ ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 0);
+ ath_edma_recv_proc_deferred_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 into the deferred queue.
+ */
+static void
+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;
+ uint16_t nf;
+ int npkts = 0;
+
+ 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 | BUS_DMASYNC_POSTWRITE);
+ 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 /* ATH_DEBUG */
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_RXSTATUS))
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_RXSTATUS,
+ sc->sc_rx_statuslen, (char *) ds);
+#endif /* ATH_DEBUG */
+ if (bf->bf_rxstatus == HAL_EINPROGRESS)
+ break;
+
+ /*
+ * Completed descriptor.
+ */
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX,
+ "%s: Q%d: completed!\n", __func__, qtype);
+ npkts++;
+
+ /*
+ * We've been synced already, so unmap.
+ */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+
+ /*
+ * Remove the FIFO entry and place it on the completion
+ * queue.
+ */
+ re->m_fifo[re->m_fifo_head] = NULL;
+ TAILQ_INSERT_TAIL(&sc->sc_rx_rxlist[qtype], 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);
+
+ /* rx signal state monitoring */
+ ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan);
+
+ ATH_KTR(sc, ATH_KTR_INTERRUPTS, 1,
+ "ath edma rx proc: npkts=%d\n",
+ npkts);
+
+ /* Handle resched and kickpcu appropriately */
+ ATH_PCU_LOCK(sc);
+ if (dosched && sc->sc_kickpcu) {
+ ATH_KTR(sc, ATH_KTR_ERROR, 0,
+ "ath_edma_recv_proc_queue(): kickpcu");
+ if (npkts > 0)
+ device_printf(sc->sc_dev,
+ "%s: handled npkts %d\n",
+ __func__, npkts);
+
+ /*
+ * XXX TODO: what should occur here? Just re-poke and
+ * re-enable the RX FIFO?
+ */
+ sc->sc_kickpcu = 0;
+ }
+ ATH_PCU_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Flush the deferred queue.
+ *
+ * This destructively flushes the deferred queue - it doesn't
+ * call the wireless stack on each mbuf.
+ */
+static void
+ath_edma_flush_deferred_queue(struct ath_softc *sc)
+{
+ struct ath_buf *bf, *next;
+
+ ATH_RX_LOCK_ASSERT(sc);
+
+ /* Free in one set, inside the lock */
+ TAILQ_FOREACH_SAFE(bf,
+ &sc->sc_rx_rxlist[HAL_RX_QUEUE_LP], bf_list, next) {
+ /* Free the buffer/mbuf */
+ ath_edma_rxbuf_free(sc, bf);
+ }
+ TAILQ_FOREACH_SAFE(bf,
+ &sc->sc_rx_rxlist[HAL_RX_QUEUE_HP], bf_list, next) {
+ /* Free the buffer/mbuf */
+ ath_edma_rxbuf_free(sc, bf);
+ }
+}
+
+static int
+ath_edma_recv_proc_deferred_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
+ int dosched)
+{
+ int ngood = 0;
+ uint64_t tsf;
+ struct ath_buf *bf, *next;
+ struct ath_rx_status *rs;
+ int16_t nf;
+ ath_bufhead rxlist;
+ struct mbuf *m;
+
+ TAILQ_INIT(&rxlist);
+
+ nf = ath_hal_getchannoise(sc->sc_ah, sc->sc_curchan);
+ /*
+ * XXX TODO: the NF/TSF should be stamped on the bufs themselves,
+ * otherwise we may end up adding in the wrong values if this
+ * is delayed too far..
+ */
+ tsf = ath_hal_gettsf64(sc->sc_ah);
+
+ /* Copy the list over */
+ ATH_RX_LOCK(sc);
+ TAILQ_CONCAT(&rxlist, &sc->sc_rx_rxlist[qtype], bf_list);
+ 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 */
+
+ rs = &bf->bf_status.ds_rxstat;
+ m = bf->bf_m;
+ bf->bf_m = NULL;
+ if (ath_rx_pkt(sc, rs, bf->bf_rxstatus, tsf, nf, qtype, bf, m))
+ ngood++;
+ }
+
+ if (ngood) {
+ sc->sc_lastrx = tsf;
+ }
+
+ ATH_KTR(sc, ATH_KTR_INTERRUPTS, 1,
+ "ath edma rx deferred proc: ngood=%d\n",
+ 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);
+
+ 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);
+
+ ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 1);
+ ath_edma_recv_proc_deferred_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;
+ * + 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);
+
+ m = m_getm(NULL, sc->sc_edma_bufsize, M_NOWAIT, 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;
+
+ /*
+ * Populate ath_buf fields.
+ */
+ bf->bf_desc = mtod(m, struct ath_desc *);
+ bf->bf_lastds = bf->bf_desc; /* XXX only really for TX? */
+ bf->bf_m = m;
+
+ /*
+ * Zero the descriptor and ensure it makes it out to the
+ * bounce buffer if one is required.
+ *
+ * XXX PREWRITE will copy the whole buffer; we only needed it
+ * to sync the first 32 DWORDS. Oh well.
+ */
+ memset(bf->bf_desc, '\0', sc->sc_rx_statuslen);
+
+ /*
+ * 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);
+ }
+
+ /*
+ * Set daddr to the physical mapping page.
+ */
+ bf->bf_daddr = bf->bf_segs[0].ds_addr;
+
+ /*
+ * Prepare for the upcoming read.
+ *
+ * We need to both sync some data into the buffer (the zero'ed
+ * descriptor payload) and also prepare for the read that's going
+ * to occur.
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Finish! */
+ return (0);
+}
+
+/*
+ * Allocate a RX buffer.
+ */
+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) {
+ device_printf(sc->sc_dev, "%s: nothing on rxbuf?!\n",
+ __func__);
+ 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);
+
+ /*
+ * Only unload the frame if we haven't consumed
+ * the mbuf via ath_rx_pkt().
+ */
+ if (bf->bf_m) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ 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: i=%d, nbufs=%d?\n",
+ __func__,
+ qtype,
+ i,
+ nbufs);
+ break;
+ }
+
+ re->m_fifo[re->m_fifo_tail] = bf;
+
+ /* Write to the RX FIFO */
+ DPRINTF(sc, ATH_DEBUG_EDMA_RX,
+ "%s: Q%d: putrxbuf=%p (0x%jx)\n",
+ __func__,
+ qtype,
+ bf->bf_desc,
+ (uintmax_t) bf->bf_daddr);
+ 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)
+{
+
+ ATH_RX_LOCK(sc);
+ ath_edma_flush_deferred_queue(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)
+{
+
+ /* 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;
+
+ sc->sc_rx.recv_sched = ath_edma_recv_sched;
+ sc->sc_rx.recv_sched_queue = ath_edma_recv_sched_queue;
+}
Property changes on: trunk/sys/dev/ath/if_ath_rx_edma.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_rx_edma.h
===================================================================
--- trunk/sys/dev/ath/if_ath_rx_edma.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_rx_edma.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,37 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/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
Property changes on: trunk/sys/dev/ath/if_ath_rx_edma.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_spectral.c
===================================================================
--- trunk/sys/dev/ath/if_ath_spectral.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_spectral.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,290 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 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: stable/10/sys/dev/ath/if_ath_spectral.c 332320 2018-04-09 12:53:15Z emaste $
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_spectral.c 332320 2018-04-09 12:53:15Z emaste $");
+
+/*
+ * Implement some basic spectral scan control logic.
+ */
+#include "opt_ath.h"
+#include "opt_inet.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <net80211/ieee80211_var.h>
+
+#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_spectral.h>
+
+#include <dev/ath/ath_hal/ah_desc.h>
+
+struct ath_spectral_state {
+ HAL_SPECTRAL_PARAM spectral_state;
+
+ /*
+ * Should we enable spectral scan upon
+ * each network interface reset/change?
+ *
+ * This is intended to allow spectral scan
+ * frame reporting during channel scans.
+ *
+ * Later on it can morph into a larger
+ * scale config method where it pushes
+ * a "channel scan" config into the hardware
+ * rather than just the spectral_state
+ * config.
+ */
+ int spectral_enable_after_reset;
+};
+
+/*
+ * Methods which are required
+ */
+
+/*
+ * Attach spectral to the given interface
+ */
+int
+ath_spectral_attach(struct ath_softc *sc)
+{
+ struct ath_spectral_state *ss;
+
+ /*
+ * If spectral isn't supported, don't error - just
+ * quietly complete.
+ */
+ if (! ath_hal_spectral_supported(sc->sc_ah))
+ return (0);
+
+ ss = malloc(sizeof(struct ath_spectral_state),
+ M_TEMP, M_WAITOK | M_ZERO);
+
+ if (ss == NULL) {
+ device_printf(sc->sc_dev, "%s: failed to alloc memory\n",
+ __func__);
+ return (-ENOMEM);
+ }
+
+ sc->sc_spectral = ss;
+
+ (void) ath_hal_spectral_get_config(sc->sc_ah, &ss->spectral_state);
+
+ return (0);
+}
+
+/*
+ * Detach spectral from the given interface
+ */
+int
+ath_spectral_detach(struct ath_softc *sc)
+{
+
+ if (! ath_hal_spectral_supported(sc->sc_ah))
+ return (0);
+
+ if (sc->sc_spectral != NULL) {
+ free(sc->sc_spectral, M_TEMP);
+ }
+ return (0);
+}
+
+/*
+ * Check whether spectral needs enabling and if so,
+ * flip it on.
+ */
+int
+ath_spectral_enable(struct ath_softc *sc, struct ieee80211_channel *ch)
+{
+ struct ath_spectral_state *ss = sc->sc_spectral;
+
+ /* Default to disable spectral PHY reporting */
+ sc->sc_dospectral = 0;
+
+ if (ss == NULL)
+ return (0);
+
+ if (ss->spectral_enable_after_reset) {
+ ath_hal_spectral_configure(sc->sc_ah,
+ &ss->spectral_state);
+ (void) ath_hal_spectral_start(sc->sc_ah);
+ sc->sc_dospectral = 1;
+ }
+ return (0);
+}
+
+/*
+ * Handle ioctl requests from the diagnostic interface.
+ *
+ * The initial part of this code resembles ath_ioctl_diag();
+ * it's likely a good idea to reduce duplication between
+ * these two routines.
+ */
+int
+ath_ioctl_spectral(struct ath_softc *sc, struct ath_diag *ad)
+{
+ unsigned int id = ad->ad_id & ATH_DIAG_ID;
+ void *indata = NULL;
+ void *outdata = NULL;
+ u_int32_t insize = ad->ad_in_size;
+ u_int32_t outsize = ad->ad_out_size;
+ int error = 0;
+ HAL_SPECTRAL_PARAM peout;
+ HAL_SPECTRAL_PARAM *pe;
+ struct ath_spectral_state *ss = sc->sc_spectral;
+ int val;
+
+ if (! ath_hal_spectral_supported(sc->sc_ah))
+ return (EINVAL);
+
+ if (ad->ad_id & ATH_DIAG_IN) {
+ /*
+ * Copy in data.
+ */
+ indata = malloc(insize, M_TEMP, M_NOWAIT);
+ if (indata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ error = copyin(ad->ad_in_data, indata, insize);
+ if (error)
+ goto bad;
+ }
+ if (ad->ad_id & ATH_DIAG_DYN) {
+ /*
+ * Allocate a buffer for the results (otherwise the HAL
+ * returns a pointer to a buffer where we can read the
+ * results). Note that we depend on the HAL leaving this
+ * pointer for us to use below in reclaiming the buffer;
+ * may want to be more defensive.
+ */
+ outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO);
+ if (outdata == NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+ }
+ switch (id) {
+ case SPECTRAL_CONTROL_GET_PARAMS:
+ memset(&peout, 0, sizeof(peout));
+ outsize = sizeof(HAL_SPECTRAL_PARAM);
+ ath_hal_spectral_get_config(sc->sc_ah, &peout);
+ pe = (HAL_SPECTRAL_PARAM *) outdata;
+ memcpy(pe, &peout, sizeof(*pe));
+ break;
+ case SPECTRAL_CONTROL_SET_PARAMS:
+ if (insize < sizeof(HAL_SPECTRAL_PARAM)) {
+ error = EINVAL;
+ break;
+ }
+ pe = (HAL_SPECTRAL_PARAM *) indata;
+ ath_hal_spectral_configure(sc->sc_ah, pe);
+ /* Save a local copy of the updated parameters */
+ ath_hal_spectral_get_config(sc->sc_ah,
+ &ss->spectral_state);
+ break;
+ case SPECTRAL_CONTROL_START:
+ ath_hal_spectral_configure(sc->sc_ah,
+ &ss->spectral_state);
+ (void) ath_hal_spectral_start(sc->sc_ah);
+ sc->sc_dospectral = 1;
+ /* XXX need to update the PHY mask in the driver */
+ break;
+ case SPECTRAL_CONTROL_STOP:
+ (void) ath_hal_spectral_stop(sc->sc_ah);
+ sc->sc_dospectral = 0;
+ /* XXX need to update the PHY mask in the driver */
+ break;
+ case SPECTRAL_CONTROL_ENABLE_AT_RESET:
+ if (insize < sizeof(int)) {
+ device_printf(sc->sc_dev, "%d != %d\n",
+ insize,
+ (int) sizeof(int));
+ error = EINVAL;
+ break;
+ }
+ if (indata == NULL) {
+ device_printf(sc->sc_dev, "indata=NULL\n");
+ error = EINVAL;
+ break;
+ }
+ val = * ((int *) indata);
+ if (val == 0)
+ ss->spectral_enable_after_reset = 0;
+ else
+ ss->spectral_enable_after_reset = 1;
+ break;
+ case SPECTRAL_CONTROL_ENABLE:
+ /* XXX TODO */
+ case SPECTRAL_CONTROL_DISABLE:
+ /* XXX TODO */
+ break;
+ default:
+ error = EINVAL;
+ goto bad;
+ }
+ if (outsize < ad->ad_out_size)
+ ad->ad_out_size = outsize;
+ if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
+ error = EFAULT;
+bad:
+ if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
+ free(indata, M_TEMP);
+ if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
+ free(outdata, M_TEMP);
+ return (error);
+}
+
Property changes on: trunk/sys/dev/ath/if_ath_spectral.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_spectral.h
===================================================================
--- trunk/sys/dev/ath/if_ath_spectral.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_spectral.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,41 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2013 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: stable/10/sys/dev/ath/if_ath_spectral.h 244951 2013-01-02 03:59:02Z adrian $
+ */
+#ifndef __IF_ATH_SPECTRAL_H__
+#define __IF_ATH_SPECTRAL_H__
+
+extern int ath_spectral_attach(struct ath_softc *sc);
+extern int ath_spectral_detach(struct ath_softc *sc);
+extern int ath_ioctl_spectral(struct ath_softc *sc, struct ath_diag *ad);
+extern int ath_spectral_enable(struct ath_softc *sc,
+ struct ieee80211_channel *ch);
+
+#endif /* __IF_ATH_SPECTRAL_H__ */
Property changes on: trunk/sys/dev/ath/if_ath_spectral.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/if_ath_sysctl.c
===================================================================
--- trunk/sys/dev/ath/if_ath_sysctl.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_sysctl.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -28,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_sysctl.c 250866 2013-05-21 18:13:57Z adrian $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -90,6 +91,7 @@
#include <dev/ath/ath_hal/ah_diagcodes.h>
#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_led.h>
#include <dev/ath/if_ath_misc.h>
#include <dev/ath/if_ath_tx.h>
#include <dev/ath/if_ath_sysctl.h>
@@ -98,6 +100,10 @@
#include <dev/ath/ath_tx99/ath_tx99.h>
#endif
+#ifdef ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
+
static int
ath_sysctl_slottime(SYSCTL_HANDLER_ARGS)
{
@@ -151,10 +157,7 @@
if (softled != sc->sc_softled) {
if (softled) {
/* NB: handle any sc_ledpin change */
- ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
- HAL_GPIO_MUX_MAC_NETWORK_LED);
- ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin,
- !sc->sc_ledon);
+ ath_led_config(sc);
}
sc->sc_softled = softled;
}
@@ -174,10 +177,7 @@
if (ledpin != sc->sc_ledpin) {
sc->sc_ledpin = ledpin;
if (sc->sc_softled) {
- ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
- HAL_GPIO_MUX_MAC_NETWORK_LED);
- ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin,
- !sc->sc_ledon);
+ ath_led_config(sc);
}
}
return 0;
@@ -184,6 +184,27 @@
}
static int
+ath_sysctl_hardled(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ int hardled = sc->sc_hardled;
+ int error;
+
+ error = sysctl_handle_int(oidp, &hardled, 0, req);
+ if (error || !req->newptr)
+ return error;
+ hardled = (hardled != 0);
+ if (hardled != sc->sc_hardled) {
+ if (hardled) {
+ /* NB: handle any sc_ledpin change */
+ ath_led_config(sc);
+ }
+ sc->sc_hardled = hardled;
+ }
+ return 0;
+}
+
+static int
ath_sysctl_txantenna(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
@@ -263,7 +284,8 @@
if (error || !req->newptr)
return error;
return !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL :
- (ifp->if_drv_flags & IFF_DRV_RUNNING) ? ath_reset(ifp) : 0;
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) ?
+ ath_reset(ifp, ATH_RESET_NOLOSS) : 0;
}
static int
@@ -295,10 +317,108 @@
return 0;
if (!ath_hal_setrfkill(ah, rfkill))
return EINVAL;
- return (ifp->if_drv_flags & IFF_DRV_RUNNING) ? ath_reset(ifp) : 0;
+ return (ifp->if_drv_flags & IFF_DRV_RUNNING) ?
+ ath_reset(ifp, ATH_RESET_FULL) : 0;
}
static int
+ath_sysctl_txagg(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ int i, t, param = 0;
+ int error;
+ struct ath_buf *bf;
+
+ error = sysctl_handle_int(oidp, ¶m, 0, req);
+ if (error || !req->newptr)
+ return error;
+
+ if (param != 1)
+ return 0;
+
+ printf("no tx bufs (empty list): %d\n", sc->sc_stats.ast_tx_getnobuf);
+ printf("no tx bufs (was busy): %d\n", sc->sc_stats.ast_tx_getbusybuf);
+
+ printf("aggr single packet: %d\n",
+ sc->sc_aggr_stats.aggr_single_pkt);
+ printf("aggr single packet w/ BAW closed: %d\n",
+ sc->sc_aggr_stats.aggr_baw_closed_single_pkt);
+ printf("aggr non-baw packet: %d\n",
+ sc->sc_aggr_stats.aggr_nonbaw_pkt);
+ printf("aggr aggregate packet: %d\n",
+ sc->sc_aggr_stats.aggr_aggr_pkt);
+ printf("aggr single packet low hwq: %d\n",
+ sc->sc_aggr_stats.aggr_low_hwq_single_pkt);
+ printf("aggr single packet RTS aggr limited: %d\n",
+ sc->sc_aggr_stats.aggr_rts_aggr_limited);
+ printf("aggr sched, no work: %d\n",
+ sc->sc_aggr_stats.aggr_sched_nopkt);
+ for (i = 0; i < 64; i++) {
+ printf("%2d: %10d ", i, sc->sc_aggr_stats.aggr_pkts[i]);
+ if (i % 4 == 3)
+ printf("\n");
+ }
+ printf("\n");
+
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ printf("HW TXQ %d: axq_depth=%d, axq_aggr_depth=%d, "
+ "axq_fifo_depth=%d, holdingbf=%p\n",
+ i,
+ sc->sc_txq[i].axq_depth,
+ sc->sc_txq[i].axq_aggr_depth,
+ sc->sc_txq[i].axq_fifo_depth,
+ sc->sc_txq[i].axq_holdingbf);
+ }
+ }
+
+ i = t = 0;
+ ATH_TXBUF_LOCK(sc);
+ TAILQ_FOREACH(bf, &sc->sc_txbuf, bf_list) {
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ printf("Busy: %d\n", t);
+ i++;
+ }
+ t++;
+ }
+ ATH_TXBUF_UNLOCK(sc);
+ 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);
+
+ ATH_RX_LOCK(sc);
+ for (i = 0; i < 2; i++) {
+ printf("%d: fifolen: %d/%d; head=%d; tail=%d\n",
+ i,
+ sc->sc_rxedma[i].m_fifo_depth,
+ sc->sc_rxedma[i].m_fifolen,
+ sc->sc_rxedma[i].m_fifo_head,
+ sc->sc_rxedma[i].m_fifo_tail);
+ }
+ i = 0;
+ TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
+ i++;
+ }
+ printf("Total RX buffers in free list: %d buffers\n",
+ i);
+ ATH_RX_UNLOCK(sc);
+
+ return 0;
+}
+
+static int
ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
@@ -366,7 +486,7 @@
* things in an inconsistent state.
*/
if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- ath_reset(sc->sc_ifp);
+ ath_reset(sc->sc_ifp, ATH_RESET_NOLOSS);
return 0;
}
@@ -387,6 +507,102 @@
}
#endif /* IEEE80211_SUPPORT_TDMA */
+static int
+ath_sysctl_forcebstuck(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ int val = 0;
+ int error;
+
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || !req->newptr)
+ return error;
+ if (val == 0)
+ return 0;
+
+ taskqueue_enqueue_fast(sc->sc_tq, &sc->sc_bstucktask);
+ val = 0;
+ return 0;
+}
+
+static int
+ath_sysctl_hangcheck(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ int val = 0;
+ int error;
+ uint32_t mask = 0xffffffff;
+ uint32_t *sp;
+ uint32_t rsize;
+ struct ath_hal *ah = sc->sc_ah;
+
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || !req->newptr)
+ return error;
+ if (val == 0)
+ return 0;
+
+ /* Do a hang check */
+ if (!ath_hal_getdiagstate(ah, HAL_DIAG_CHECK_HANGS,
+ &mask, sizeof(mask),
+ (void *) &sp, &rsize))
+ return (0);
+ device_printf(sc->sc_dev, "%s: sp=0x%08x\n", __func__, *sp);
+
+ val = 0;
+ return 0;
+}
+
+#ifdef ATH_DEBUG_ALQ
+static int
+ath_sysctl_alq_log(SYSCTL_HANDLER_ARGS)
+{
+ struct ath_softc *sc = arg1;
+ int error, enable;
+
+ enable = (sc->sc_alq.sc_alq_isactive);
+
+ error = sysctl_handle_int(oidp, &enable, 0, req);
+ if (error || !req->newptr)
+ return (error);
+ else if (enable)
+ error = if_ath_alq_start(&sc->sc_alq);
+ else
+ error = if_ath_alq_stop(&sc->sc_alq);
+ return (error);
+}
+
+/*
+ * Attach the ALQ debugging if required.
+ */
+static void
+ath_sysctl_alq_attach(struct ath_softc *sc)
+{
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
+
+ tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "alq", CTLFLAG_RD,
+ NULL, "Atheros ALQ logging parameters");
+ child = SYSCTL_CHILDREN(tree);
+
+ SYSCTL_ADD_STRING(ctx, child, OID_AUTO, "filename",
+ CTLFLAG_RW, sc->sc_alq.sc_alq_filename, 0, "ALQ filename");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "enable", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_alq_log, "I", "");
+
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debugmask", CTLFLAG_RW, &sc->sc_alq.sc_alq_debug, 0,
+ "ALQ debug mask");
+
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "numlost", CTLFLAG_RW, &sc->sc_alq.sc_alq_numlost, 0,
+ "number lost");
+}
+#endif /* ATH_DEBUG_ALQ */
+
void
ath_sysctlattach(struct ath_softc *sc)
{
@@ -401,10 +617,15 @@
"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
+#ifdef ATH_DEBUG_ALQ
+ SYSCTL_ADD_QUAD(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ktrdebug", CTLFLAG_RW, &sc->sc_ktrdebug,
+ "control debugging KTR");
+#endif /* ATH_DEBUG_ALQ */
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"slottime", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_slottime, "I", "802.11 slot time (us)");
@@ -414,6 +635,7 @@
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ctstimeout", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_ctstimeout, "I", "802.11 CTS timeout (us)");
+
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"softled", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_softled, "I", "enable/disable software LED support");
@@ -426,7 +648,19 @@
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ledidle", CTLFLAG_RW, &sc->sc_ledidle, 0,
"idle time for inactivity LED (ticks)");
+
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "hardled", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_hardled, "I", "enable/disable hardware LED support");
+ /* XXX Laziness - configure pins, then flip hardled off/on */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "led_net_pin", CTLFLAG_RW, &sc->sc_led_net_pin, 0,
+ "MAC Network LED pin, or -1 to disable");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "led_pwr_pin", CTLFLAG_RW, &sc->sc_led_pwr_pin, 0,
+ "MAC Power LED pin, or -1 to disable");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"txantenna", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_txantenna, "I", "antenna switch");
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -465,6 +699,19 @@
"rfkill", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_rfkill, "I", "enable/disable RF kill switch");
}
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "txagg", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_txagg, "I", "");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "forcebstuck", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_forcebstuck, "I", "");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "hangcheck", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ ath_sysctl_hangcheck, "I", "");
+
if (ath_hal_hasintmit(ah)) {
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"intmit", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
@@ -474,6 +721,53 @@
SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"monpass", CTLFLAG_RW, &sc->sc_monpass, 0,
"mask of error frames to pass when monitoring");
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "hwq_limit_nonaggr", CTLFLAG_RW, &sc->sc_hwq_limit_nonaggr, 0,
+ "Hardware non-AMPDU queue depth before software-queuing TX frames");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "hwq_limit_aggr", CTLFLAG_RW, &sc->sc_hwq_limit_aggr, 0,
+ "Hardware AMPDU queue depth before software-queuing TX frames");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "tid_hwq_lo", CTLFLAG_RW, &sc->sc_tid_hwq_lo, 0,
+ "");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "tid_hwq_hi", CTLFLAG_RW, &sc->sc_tid_hwq_hi, 0,
+ "");
+
+ /* Aggregate length twiddles */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "aggr_limit", CTLFLAG_RW, &sc->sc_aggr_limit, 0,
+ "Maximum A-MPDU size, or 0 for 'default'");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rts_aggr_limit", CTLFLAG_RW, &sc->sc_rts_aggr_limit, 0,
+ "Maximum A-MPDU size for RTS-protected frames, or '0' "
+ "for default");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "delim_min_pad", CTLFLAG_RW, &sc->sc_delim_min_pad, 0,
+ "Enforce a minimum number of delimiters per A-MPDU "
+ " sub-frame");
+
+ 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");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "txq_mcastq_maxdepth", CTLFLAG_RW,
+ &sc->sc_txq_mcastq_maxdepth, 0,
+ "Maximum buffer depth for multicast/broadcast frames");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "txq_node_maxdepth", CTLFLAG_RW,
+ &sc->sc_txq_node_maxdepth, 0,
+ "Maximum buffer depth for a single node");
+
+#if 0
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "cabq_enable", CTLFLAG_RW,
+ &sc->sc_cabq_enable, 0,
+ "Whether to transmit on the CABQ or not");
+#endif
+
#ifdef IEEE80211_SUPPORT_TDMA
if (ath_hal_macversion(ah) > 0x78) {
sc->sc_tdmadbaprep = 2;
@@ -495,6 +789,10 @@
ath_sysctl_setcca, "I", "enable CCA control");
}
#endif
+
+#ifdef ATH_DEBUG_ALQ
+ ath_sysctl_alq_attach(sc);
+#endif
}
static int
@@ -510,6 +808,9 @@
if (val == 0)
return 0; /* Not clearing the stats is still valid */
memset(&sc->sc_stats, 0, sizeof(sc->sc_stats));
+ memset(&sc->sc_aggr_stats, 0, sizeof(sc->sc_aggr_stats));
+ memset(&sc->sc_intr_stats, 0, sizeof(sc->sc_intr_stats));
+
val = 0;
return 0;
}
@@ -531,6 +832,26 @@
}
}
+static void
+ath_sysctl_stats_attach_intr(struct ath_softc *sc,
+ struct sysctl_oid_list *parent)
+{
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+ struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
+ int i;
+ char sn[8];
+
+ tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "sync_intr",
+ CTLFLAG_RD, NULL, "Sync interrupt statistics");
+ child = SYSCTL_CHILDREN(tree);
+ for (i = 0; i < 32; i++) {
+ snprintf(sn, sizeof(sn), "%d", i);
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD,
+ &sc->sc_intr_stats.sync_intr[i], 0, "");
+ }
+}
+
void
ath_sysctl_stats_attach(struct ath_softc *sc)
{
@@ -729,9 +1050,45 @@
&sc->sc_stats.ast_tx_timerexpired, 0, "TX exceeded TX_TIMER register");
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_desccfgerr", CTLFLAG_RD,
&sc->sc_stats.ast_tx_desccfgerr, 0, "TX Descriptor Cfg Error");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_swretries", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_swretries, 0, "TX software retry count");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_swretrymax", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_swretrymax, 0, "TX software retry max reached");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_data_underrun", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_data_underrun, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_delim_underrun", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_delim_underrun, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_aggr_failall", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_aggr_failall, 0,
+ "Number of aggregate TX failures (whole frame)");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_aggr_ok", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_aggr_ok, 0,
+ "Number of aggregate TX OK completions (subframe)");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_aggr_fail", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_aggr_fail, 0,
+ "Number of aggregate TX failures (subframe)");
+
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_intr", CTLFLAG_RD,
+ &sc->sc_stats.ast_rx_intr, 0, "RX interrupts");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_intr", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_intr, 0, "TX interrupts");
+ 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, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_tx_swfiltered", CTLFLAG_RD,
+ &sc->sc_stats.ast_tx_swfiltered, 0, "");
+ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "ast_rx_stbc",
+ CTLFLAG_RD, &sc->sc_stats.ast_rx_stbc, 0,
+ "Number of STBC frames received");
+
/* Attach the RX phy error array */
ath_sysctl_stats_attach_rxphyerr(sc, child);
+
+ /* Attach the interrupt statistics array */
+ ath_sysctl_stats_attach_intr(sc, child);
}
/*
@@ -772,4 +1129,16 @@
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "swba_backoff", CTLFLAG_RW,
&sc->sc_ah->ah_config.ah_additional_swba_backoff, 0,
"Atheros HAL additional SWBA backoff time");
+
+ sc->sc_ah->ah_config.ah_force_full_reset = 0;
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "force_full_reset", CTLFLAG_RW,
+ &sc->sc_ah->ah_config.ah_force_full_reset, 0,
+ "Force full chip reset rather than a warm reset");
+
+ /*
+ * This is initialised by the driver.
+ */
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "serialise_reg_war", CTLFLAG_RW,
+ &sc->sc_ah->ah_config.ah_serialise_reg_war, 0,
+ "Force register access serialisation");
}
Modified: trunk/sys/dev/ath/if_ath_sysctl.h
===================================================================
--- trunk/sys/dev/ath/if_ath_sysctl.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_sysctl.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_ath_sysctl.h 223459 2011-06-23 02:38:36Z adrian $
*/
#ifndef __IF_ATH_SYSCTL_H__
Added: trunk/sys/dev/ath/if_ath_tdma.c
===================================================================
--- trunk/sys/dev/ath/if_ath_tdma.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_tdma.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,684 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_tdma.c 250865 2013-05-21 18:02:54Z 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 ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.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;
+#if 0
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "%s: intval=%d (0x%08x) nexttbtt=%u (0x%08x), nextdba=%u (0x%08x), nextswba=%u (0x%08x),nextatim=%u (0x%08x)\n",
+ __func__,
+ bt.bt_intval,
+ bt.bt_intval,
+ bt.bt_nexttbtt,
+ bt.bt_nexttbtt,
+ bt.bt_nextdba,
+ bt.bt_nextdba,
+ bt.bt_nextswba,
+ bt.bt_nextswba,
+ bt.bt_nextatim,
+ bt.bt_nextatim);
+#endif
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_TDMA_TIMER_SET)) {
+ struct if_ath_alq_tdma_timer_set t;
+ t.bt_intval = htobe32(bt.bt_intval);
+ t.bt_nexttbtt = htobe32(bt.bt_nexttbtt);
+ t.bt_nextdba = htobe32(bt.bt_nextdba);
+ t.bt_nextswba = htobe32(bt.bt_nextswba);
+ t.bt_nextatim = htobe32(bt.bt_nextatim);
+ t.bt_flags = htobe32(bt.bt_flags);
+ t.sc_tdmadbaprep = htobe32(sc->sc_tdmadbaprep);
+ t.sc_tdmaswbaprep = htobe32(sc->sc_tdmaswbaprep);
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_TDMA_TIMER_SET,
+ sizeof(t), (char *) &t);
+ }
+#endif
+
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "%s: nexttbtt=%u (0x%08x), nexttbtt tsf=%lld (0x%08llx)\n",
+ __func__,
+ bt.bt_nexttbtt,
+ bt.bt_nexttbtt,
+ (long long) ( ((u_int64_t) (bt.bt_nexttbtt)) << 10),
+ (long long) ( ((u_int64_t) (bt.bt_nexttbtt)) << 10));
+ 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);
+
+ /*
+ * If the chip supports enforcing TxOP on transmission,
+ * we can just delete the guard window. It isn't at all required.
+ */
+ if (sc->sc_hasenforcetxop) {
+ sc->sc_tdmaguard = 0;
+ } else {
+ /* XXX short preamble assumed */
+ /* XXX non-11n rate 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);
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_TDMA_TIMER_CONFIG)) {
+ struct if_ath_alq_tdma_timer_config t;
+
+ t.tdma_slot = htobe32(tdma->tdma_slot);
+ t.tdma_slotlen = htobe32(tdma->tdma_slotlen);
+ t.tdma_slotcnt = htobe32(tdma->tdma_slotcnt);
+ t.tdma_bintval = htobe32(tdma->tdma_bintval);
+ t.tdma_guard = htobe32(sc->sc_tdmaguard);
+ t.tdma_scbintval = htobe32(sc->sc_tdmabintval);
+ t.tdma_dbaprep = htobe32(sc->sc_tdmadbaprep);
+
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_TDMA_TIMER_CONFIG,
+ sizeof(t), (char *) &t);
+ }
+#endif /* ATH_DEBUG_ALQ */
+}
+
+/*
+ * 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.
+ *
+ * XXX TODO: since the changes for the AR5416 and later chips
+ * involved changing the TSF/TU calculations, we need to make
+ * sure that various calculations wrap consistently.
+ *
+ * A lot of the problems stemmed from the calculations wrapping
+ * at 65,535 TU. Since a lot of the math is still being done in
+ * TU, please audit it to ensure that when the TU values programmed
+ * into the timers wrap at (2^31)-1 TSF, all the various terms
+ * wrap consistently.
+ */
+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, nexttbtt_full;
+ 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];
+
+ /*
+ * To calculate the packet duration for legacy rates, we
+ * only need the rix and preamble.
+ *
+ * For 11n non-aggregate frames, we also need the channel
+ * width and short/long guard interval.
+ *
+ * For 11n aggregate frames, the required hacks are a little
+ * more subtle. You need to figure out the frame duration
+ * for each frame, including the delimiters. However, when
+ * a frame isn't received successfully, we won't hear it
+ * (unless you enable reception of CRC errored frames), so
+ * your duration calculation is going to be off.
+ *
+ * However, we can assume that the beacon frames won't be
+ * transmitted as aggregate frames, so we should be okay.
+ * Just add a check to ensure that we aren't handed something
+ * bad.
+ *
+ * For ath_hal_pkt_txtime() - for 11n rates, shortPreamble is
+ * actually short guard interval. For legacy rates,
+ * it's short preamble.
+ */
+ txtime = ath_hal_pkt_txtime(ah, rt, rs->rs_datalen,
+ rix,
+ !! (rs->rs_flags & HAL_RX_2040),
+ (rix & 0x80) ?
+ (! (rs->rs_flags & HAL_RX_GI)) : rt->info[rix].shortPreamble);
+ /* NB: << 9 is to cvt to TU and /2 */
+ nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9);
+
+ /*
+ * For 802.11n chips: nextslottu needs to be the full TSF space,
+ * not just 0..65535 TU.
+ */
+ nextslottu = TSF_TO_TU(nextslot>>32, nextslot);
+ /*
+ * 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.
+ */
+ /*
+ * The logic here assumes the nexttbtt counter is in TSF
+ * but the prr-11n NICs are in TU. The HAL shifts them
+ * to TSF but there's two important differences:
+ *
+ * + The TU->TSF values have 0's for the low 9 bits, and
+ * + The counter wraps at TU_TO_TSF(HAL_BEACON_PERIOD + 1) for
+ * the pre-11n NICs, but not for the 11n NICs.
+ *
+ * So for now, just make sure the nexttbtt value we get
+ * matches the second issue or once nexttbtt exceeds this
+ * value, tsfdelta ends up becoming very negative and all
+ * of the adjustments get very messed up.
+ */
+
+ /*
+ * We need to track the full nexttbtt rather than having it
+ * truncated at HAL_BEACON_PERIOD, as programming the
+ * nexttbtt (and related) registers for the 11n chips is
+ * actually going to take the full 32 bit space, rather than
+ * just 0..65535 TU.
+ */
+ nexttbtt_full = ath_hal_getnexttbtt(ah);
+ nexttbtt = nexttbtt_full % (TU_TO_TSF(HAL_BEACON_PERIOD + 1));
+ tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt);
+
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "rs->rstamp %llu rstamp %llu tsf %llu txtime %d, nextslot %llu, "
+ "nextslottu %d, nextslottume %d\n",
+ (unsigned long long) rs->rs_tstamp, rstamp, tsf, txtime,
+ nextslot, nextslottu, TSF_TO_TU(nextslot >> 32, nextslot));
+ DPRINTF(sc, ATH_DEBUG_TDMA,
+ " beacon tstamp: %llu (0x%016llx)\n",
+ le64toh(ni->ni_tstamp.tsf),
+ le64toh(ni->ni_tstamp.tsf));
+
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "nexttbtt %llu (0x%08llx) tsfdelta %d avg +%d/-%d\n",
+ nexttbtt,
+ (long long) nexttbtt,
+ 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_full >> 32, nexttbtt_full);
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_TDMA_BEACON_STATE)) {
+ struct if_ath_alq_tdma_beacon_state t;
+ t.rx_tsf = htobe64(rstamp);
+ t.beacon_tsf = htobe64(le64toh(ni->ni_tstamp.tsf));
+ t.tsf64 = htobe64(tsf);
+ t.nextslot_tsf = htobe64(nextslot);
+ t.nextslot_tu = htobe32(nextslottu);
+ t.txtime = htobe32(txtime);
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_TDMA_BEACON_STATE,
+ sizeof(t), (char *) &t);
+ }
+
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_TDMA_SLOT_CALC)) {
+ struct if_ath_alq_tdma_slot_calc t;
+
+ t.nexttbtt = htobe64(nexttbtt_full);
+ t.next_slot = htobe64(nextslot);
+ t.tsfdelta = htobe32(tsfdelta);
+ t.avg_plus = htobe32(TDMA_AVG(sc->sc_avgtsfdeltap));
+ t.avg_minus = htobe32(TDMA_AVG(sc->sc_avgtsfdeltam));
+
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_TDMA_SLOT_CALC,
+ sizeof(t), (char *) &t);
+ }
+#endif
+
+ /*
+ * 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)) {
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "%s: calling ath_tdma_settimers; nextslottu=%d, bintval=%d\n",
+ __func__,
+ nextslottu,
+ sc->sc_tdmabintval);
+ ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval);
+ sc->sc_stats.ast_tdma_timers++;
+ }
+ if (tsfdelta > 0) {
+ uint64_t tsf;
+
+ /* XXX should just teach ath_hal_adjusttsf() to do this */
+ tsf = ath_hal_gettsf64(ah);
+ ath_hal_settsf64(ah, tsf + tsfdelta);
+ DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
+ "%s: calling ath_hal_adjusttsf: TSF=%llu, tsfdelta=%d\n",
+ __func__,
+ tsf,
+ tsfdelta);
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq,
+ ATH_ALQ_TDMA_TSF_ADJUST)) {
+ struct if_ath_alq_tdma_tsf_adjust t;
+
+ t.tsfdelta = htobe32(tsfdelta);
+ t.tsf64_old = htobe64(tsf);
+ t.tsf64_new = htobe64(tsf + tsfdelta);
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_TDMA_TSF_ADJUST,
+ sizeof(t), (char *) &t);
+ }
+#endif /* ATH_DEBUG_ALQ */
+ 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);
+ /* XXX We don't do cabq traffic, but just for completeness .. */
+ ATH_TXQ_LOCK(sc->sc_cabq);
+ ath_beacon_cabq_start(sc);
+ ATH_TXQ_UNLOCK(sc->sc_cabq);
+
+ 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 ((! sc->sc_isedma) &&
+ (! 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 */
Property changes on: trunk/sys/dev/ath/if_ath_tdma.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_tdma.h
===================================================================
--- trunk/sys/dev/ath/if_ath_tdma.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_tdma.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,56 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/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
Property changes on: trunk/sys/dev/ath/if_ath_tdma.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_tsf.h
===================================================================
--- trunk/sys/dev/ath/if_ath_tsf.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_tsf.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,82 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/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
Property changes on: trunk/sys/dev/ath/if_ath_tsf.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/if_ath_tx.c
===================================================================
--- trunk/sys/dev/ath/if_ath_tx.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_tx.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2010-2012 Adrian Chadd, Xenion Pty Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_tx.c 262998 2014-03-11 05:58:52Z rpaulo $");
/*
* Driver for the Atheros Wireless LAN controller.
@@ -77,6 +79,7 @@
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
+#include <net80211/ieee80211_ht.h>
#include <net/bpf.h>
@@ -99,15 +102,140 @@
#include <dev/ath/if_ath_tx.h>
#include <dev/ath/if_ath_tx_ht.h>
+#ifdef ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
+
/*
+ * How many retries to perform in software
+ */
+#define SWMAX_RETRIES 10
+
+/*
+ * What queue to throw the non-QoS TID traffic into
+ */
+#define ATH_NONQOS_TID_AC WME_AC_VO
+
+#if 0
+static int ath_tx_node_is_asleep(struct ath_softc *sc, struct ath_node *an);
+#endif
+static int ath_tx_ampdu_pending(struct ath_softc *sc, struct ath_node *an,
+ 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 struct ath_buf *
+ath_tx_retry_clone(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, struct ath_buf *bf);
+
+#ifdef ATH_DEBUG_ALQ
+void
+ath_tx_alq_post(struct ath_softc *sc, struct ath_buf *bf_first)
+{
+ struct ath_buf *bf;
+ int i, n;
+ const char *ds;
+
+ /* XXX we should skip out early if debugging isn't enabled! */
+ bf = bf_first;
+
+ while (bf != NULL) {
+ /* XXX should ensure bf_nseg > 0! */
+ if (bf->bf_nseg == 0)
+ break;
+ n = ((bf->bf_nseg - 1) / sc->sc_tx_nmaps) + 1;
+ for (i = 0, ds = (const char *) bf->bf_desc;
+ i < n;
+ i++, ds += sc->sc_tx_desclen) {
+ if_ath_alq_post(&sc->sc_alq,
+ ATH_ALQ_EDMA_TXDESC,
+ sc->sc_tx_desclen,
+ ds);
+ }
+ bf = bf->bf_next;
+ }
+}
+#endif /* ATH_DEBUG_ALQ */
+
+/*
* Whether to use the 11n rate scenario functions or not
*/
static inline int
ath_tx_is_11n(struct ath_softc *sc)
{
- return (sc->sc_ah->ah_magic == 0x20065416);
+ return ((sc->sc_ah->ah_magic == 0x20065416) ||
+ (sc->sc_ah->ah_magic == 0x19741014));
}
+/*
+ * Obtain the current TID from the given frame.
+ *
+ * Non-QoS frames need to go into TID 16 (IEEE80211_NONQOS_TID.)
+ * This has implications for which AC/priority the packet is placed
+ * in.
+ */
+static int
+ath_tx_gettid(struct ath_softc *sc, const struct mbuf *m0)
+{
+ const struct ieee80211_frame *wh;
+ int pri = M_WME_GETAC(m0);
+
+ wh = mtod(m0, const struct ieee80211_frame *);
+ if (! IEEE80211_QOS_HAS_SEQ(wh))
+ return IEEE80211_NONQOS_TID;
+ else
+ return WME_AC_TO_TID(pri);
+}
+
+static void
+ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ieee80211_frame *wh;
+
+ wh = mtod(bf->bf_m, struct ieee80211_frame *);
+ /* Only update/resync if needed */
+ if (bf->bf_state.bfs_isretried == 0) {
+ wh->i_fc[1] |= IEEE80211_FC1_RETRY;
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_PREWRITE);
+ }
+ bf->bf_state.bfs_isretried = 1;
+ bf->bf_state.bfs_retries ++;
+}
+
+/*
+ * Determine what the correct AC queue for the given frame
+ * should be.
+ *
+ * This code assumes that the TIDs map consistently to
+ * the underlying hardware (or software) ath_txq.
+ * Since the sender may try to set an AC which is
+ * arbitrary, non-QoS TIDs may end up being put on
+ * completely different ACs. There's no way to put a
+ * TID into multiple ath_txq's for scheduling, so
+ * for now we override the AC/TXQ selection and set
+ * non-QOS TID frames into the BE queue.
+ *
+ * This may be completely incorrect - specifically,
+ * some management frames may end up out of order
+ * compared to the QoS traffic they're controlling.
+ * I'll look into this later.
+ */
+static int
+ath_tx_getac(struct ath_softc *sc, const struct mbuf *m0)
+{
+ const struct ieee80211_frame *wh;
+ int pri = M_WME_GETAC(m0);
+ wh = mtod(m0, const struct ieee80211_frame *);
+ if (IEEE80211_QOS_HAS_SEQ(wh))
+ return pri;
+
+ return ATH_NONQOS_TID_AC;
+}
+
void
ath_txfrag_cleanup(struct ath_softc *sc,
ath_bufhead *frags, struct ieee80211_node *ni)
@@ -116,10 +244,10 @@
ATH_TXBUF_LOCK_ASSERT(sc);
- STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
+ TAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
/* NB: bf assumed clean */
- STAILQ_REMOVE_HEAD(frags, bf_list);
- STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ TAILQ_REMOVE(frags, bf, bf_list);
+ ath_returnbuf_head(sc, bf);
ieee80211_node_decref(ni);
}
}
@@ -138,17 +266,20 @@
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 */
+ DPRINTF(sc, ATH_DEBUG_XMIT, "%s: no buffer?\n",
+ __func__);
ath_txfrag_cleanup(sc, frags, ni);
break;
}
ieee80211_node_incref(ni);
- STAILQ_INSERT_TAIL(frags, bf, bf_list);
+ TAILQ_INSERT_TAIL(frags, bf, bf_list);
}
ATH_TXBUF_UNLOCK(sc);
- return !STAILQ_EMPTY(frags);
+ return !TAILQ_EMPTY(frags);
}
/*
@@ -182,7 +313,7 @@
BUS_DMA_NOWAIT);
if (error == EFBIG) {
/* XXX packet requires too many descriptors */
- bf->bf_nseg = ATH_TXDESC+1;
+ bf->bf_nseg = ATH_MAX_SCATTER + 1;
} else if (error != 0) {
sc->sc_stats.ast_tx_busdma++;
ath_freetx(m0);
@@ -193,9 +324,9 @@
* require too many TX descriptors. We try to convert
* the latter to a cluster.
*/
- if (bf->bf_nseg > ATH_TXDESC) { /* too many desc's, linearize */
+ if (bf->bf_nseg > ATH_MAX_SCATTER) { /* too many desc's, linearize */
sc->sc_stats.ast_tx_linear++;
- m = m_collapse(m0, M_NOWAIT, ATH_TXDESC);
+ m = m_collapse(m0, M_NOWAIT, ATH_MAX_SCATTER);
if (m == NULL) {
ath_freetx(m0);
sc->sc_stats.ast_tx_nombuf++;
@@ -210,7 +341,7 @@
ath_freetx(m0);
return error;
}
- KASSERT(bf->bf_nseg <= ATH_TXDESC,
+ KASSERT(bf->bf_nseg <= ATH_MAX_SCATTER,
("too many segments after defrag; nseg %u", bf->bf_nseg));
} else if (bf->bf_nseg == 0) { /* null packet, discard */
sc->sc_stats.ast_tx_nodata++;
@@ -225,45 +356,395 @@
return 0;
}
+/*
+ * Chain together segments+descriptors for a frame - 11n or otherwise.
+ *
+ * For aggregates, this is called on each frame in the aggregate.
+ */
static void
-ath_tx_chaindesclist(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
+ath_tx_chaindesclist(struct ath_softc *sc, struct ath_desc *ds0,
+ struct ath_buf *bf, int is_aggr, int is_first_subframe,
+ int is_last_subframe)
{
struct ath_hal *ah = sc->sc_ah;
- struct ath_desc *ds, *ds0;
- int i;
+ char *ds;
+ int i, bp, dsp;
+ HAL_DMA_ADDR bufAddrList[4];
+ uint32_t segLenList[4];
+ int numTxMaps = 1;
+ int isFirstDesc = 1;
/*
+ * 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.
*/
- ds0 = ds = bf->bf_desc;
- for (i = 0; i < bf->bf_nseg; i++, ds++) {
- ds->ds_data = bf->bf_segs[i].ds_addr;
+
+ /*
+ * We need the number of TX data pointers in each descriptor.
+ * EDMA and later chips support 4 TX buffers per descriptor;
+ * previous chips just support one.
+ */
+ numTxMaps = sc->sc_tx_nmaps;
+
+ /*
+ * For EDMA and later chips ensure the TX map is fully populated
+ * before advancing to the next descriptor.
+ */
+ ds = (char *) bf->bf_desc;
+ bp = dsp = 0;
+ bzero(bufAddrList, sizeof(bufAddrList));
+ bzero(segLenList, sizeof(segLenList));
+ for (i = 0; i < bf->bf_nseg; i++) {
+ bufAddrList[bp] = bf->bf_segs[i].ds_addr;
+ segLenList[bp] = bf->bf_segs[i].ds_len;
+ bp++;
+
+ /*
+ * Go to the next segment if this isn't the last segment
+ * and there's space in the current TX map.
+ */
+ if ((i != bf->bf_nseg - 1) && (bp < numTxMaps))
+ continue;
+
+ /*
+ * Last segment or we're out of buffer pointers.
+ */
+ bp = 0;
+
if (i == bf->bf_nseg - 1)
- ds->ds_link = 0;
+ ath_hal_settxdesclink(ah, (struct ath_desc *) ds, 0);
else
- ds->ds_link = bf->bf_daddr + sizeof(*ds) * (i + 1);
- ath_hal_filltxdesc(ah, ds
- , bf->bf_segs[i].ds_len /* segment length */
- , i == 0 /* first segment */
+ ath_hal_settxdesclink(ah, (struct ath_desc *) ds,
+ bf->bf_daddr + dd->dd_descsize * (dsp + 1));
+
+ /*
+ * XXX This assumes that bfs_txq is the actual destination
+ * hardware queue at this point. It may not have been
+ * assigned, it may actually be pointing to the multicast
+ * software TXQ id. These must be fixed!
+ */
+ ath_hal_filltxdesc(ah, (struct ath_desc *) ds
+ , bufAddrList
+ , segLenList
+ , bf->bf_descid /* XXX desc id */
+ , bf->bf_state.bfs_tx_queue
+ , isFirstDesc /* first segment */
, i == bf->bf_nseg - 1 /* last segment */
- , ds0 /* first descriptor */
+ , (struct ath_desc *) ds0 /* first descriptor */
);
+
+ /*
+ * Make sure the 11n aggregate fields are cleared.
+ *
+ * XXX TODO: this doesn't need to be called for
+ * aggregate frames; as it'll be called on all
+ * sub-frames. Since the descriptors are in
+ * non-cacheable memory, this leads to some
+ * rather slow writes on MIPS/ARM platforms.
+ */
+ if (ath_tx_is_11n(sc))
+ ath_hal_clr11n_aggr(sc->sc_ah, (struct ath_desc *) ds);
+
+ /*
+ * If 11n is enabled, set it up as if it's an aggregate
+ * frame.
+ */
+ if (is_last_subframe) {
+ ath_hal_set11n_aggr_last(sc->sc_ah,
+ (struct ath_desc *) ds);
+ } else if (is_aggr) {
+ /*
+ * This clears the aggrlen field; so
+ * the caller needs to call set_aggr_first()!
+ *
+ * XXX TODO: don't call this for the first
+ * descriptor in the first frame in an
+ * aggregate!
+ */
+ ath_hal_set11n_aggr_middle(sc->sc_ah,
+ (struct ath_desc *) ds,
+ bf->bf_state.bfs_ndelim);
+ }
+ isFirstDesc = 0;
+ bf->bf_lastds = (struct ath_desc *) ds;
+
+ /*
+ * Don't forget to skip to the next descriptor.
+ */
+ ds += sc->sc_tx_desclen;
+ dsp++;
+
+ /*
+ * .. and don't forget to blank these out!
+ */
+ bzero(bufAddrList, sizeof(bufAddrList));
+ bzero(segLenList, sizeof(segLenList));
+ }
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+}
+
+/*
+ * Set the rate control fields in the given descriptor based on
+ * the bf_state fields and node state.
+ *
+ * The bfs fields should already be set with the relevant rate
+ * control information, including whether MRR is to be enabled.
+ *
+ * Since the FreeBSD HAL currently sets up the first TX rate
+ * in ath_hal_setuptxdesc(), this will setup the MRR
+ * conditionally for the pre-11n chips, and call ath_buf_set_rate
+ * unconditionally for 11n chips. These require the 11n rate
+ * scenario to be set if MCS rates are enabled, so it's easier
+ * to just always call it. The caller can then only set rates 2, 3
+ * and 4 if multi-rate retry is needed.
+ */
+static void
+ath_tx_set_ratectrl(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_buf *bf)
+{
+ struct ath_rc_series *rc = bf->bf_state.bfs_rc;
+
+ /* If mrr is disabled, blank tries 1, 2, 3 */
+ if (! bf->bf_state.bfs_ismrr)
+ rc[1].tries = rc[2].tries = rc[3].tries = 0;
+
+#if 0
+ /*
+ * If NOACK is set, just set ntries=1.
+ */
+ else if (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) {
+ rc[1].tries = rc[2].tries = rc[3].tries = 0;
+ rc[0].tries = 1;
+ }
+#endif
+
+ /*
+ * Always call - that way a retried descriptor will
+ * have the MRR fields overwritten.
+ *
+ * XXX TODO: see if this is really needed - setting up
+ * the first descriptor should set the MRR fields to 0
+ * for us anyway.
+ */
+ if (ath_tx_is_11n(sc)) {
+ ath_buf_set_rate(sc, ni, bf);
+ } else {
+ ath_hal_setupxtxdesc(sc->sc_ah, bf->bf_desc
+ , rc[1].ratecode, rc[1].tries
+ , rc[2].ratecode, rc[2].tries
+ , rc[3].ratecode, rc[3].tries
+ );
+ }
+}
+
+/*
+ * Setup segments+descriptors for an 11n aggregate.
+ * bf_first is the first buffer in the aggregate.
+ * The descriptor list must already been linked together using
+ * bf->bf_next.
+ */
+static void
+ath_tx_setds_11n(struct ath_softc *sc, struct ath_buf *bf_first)
+{
+ struct ath_buf *bf, *bf_prev = NULL;
+ struct ath_desc *ds0 = bf_first->bf_desc;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: nframes=%d, al=%d\n",
+ __func__, bf_first->bf_state.bfs_nframes,
+ bf_first->bf_state.bfs_al);
+
+ bf = bf_first;
+
+ if (bf->bf_state.bfs_txrate0 == 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: bf=%p, txrate0=%d\n",
+ __func__, bf, 0);
+ if (bf->bf_state.bfs_rc[0].ratecode == 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: bf=%p, rix0=%d\n",
+ __func__, bf, 0);
+
+ /*
+ * Setup all descriptors of all subframes - this will
+ * call ath_hal_set11naggrmiddle() on every frame.
+ */
+ while (bf != NULL) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: bf=%p, nseg=%d, pktlen=%d, seqno=%d\n",
+ __func__, bf, bf->bf_nseg, bf->bf_state.bfs_pktlen,
+ SEQNO(bf->bf_state.bfs_seqno));
+
+ /*
+ * Setup the initial fields for the first descriptor - all
+ * the non-11n specific stuff.
+ */
+ ath_hal_setuptxdesc(sc->sc_ah, bf->bf_desc
+ , bf->bf_state.bfs_pktlen /* packet length */
+ , bf->bf_state.bfs_hdrlen /* header length */
+ , bf->bf_state.bfs_atype /* Atheros packet type */
+ , bf->bf_state.bfs_txpower /* txpower */
+ , bf->bf_state.bfs_txrate0
+ , bf->bf_state.bfs_try0 /* series 0 rate/tries */
+ , bf->bf_state.bfs_keyix /* key cache index */
+ , bf->bf_state.bfs_txantenna /* antenna mode */
+ , bf->bf_state.bfs_txflags | HAL_TXDESC_INTREQ /* flags */
+ , bf->bf_state.bfs_ctsrate /* rts/cts rate */
+ , bf->bf_state.bfs_ctsduration /* rts/cts duration */
+ );
+
+ /*
+ * First descriptor? Setup the rate control and initial
+ * aggregate header information.
+ */
+ if (bf == bf_first) {
+ /*
+ * setup first desc with rate and aggr info
+ */
+ ath_tx_set_ratectrl(sc, bf->bf_node, bf);
+ }
+
+ /*
+ * Setup the descriptors for a multi-descriptor frame.
+ * This is both aggregate and non-aggregate aware.
+ */
+ ath_tx_chaindesclist(sc, ds0, bf,
+ 1, /* is_aggr */
+ !! (bf == bf_first), /* is_first_subframe */
+ !! (bf->bf_next == NULL) /* is_last_subframe */
+ );
+
+ if (bf == bf_first) {
+ /*
+ * Initialise the first 11n aggregate with the
+ * aggregate length and aggregate enable bits.
+ */
+ ath_hal_set11n_aggr_first(sc->sc_ah,
+ ds0,
+ bf->bf_state.bfs_al,
+ bf->bf_state.bfs_ndelim);
+ }
+
+ /*
+ * Link the last descriptor of the previous frame
+ * to the beginning descriptor of this frame.
+ */
+ if (bf_prev != NULL)
+ 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;
+ bf = bf->bf_next;
+ }
+
+ /*
+ * Set the first descriptor bf_lastds field to point to
+ * the last descriptor in the last subframe, that's where
+ * the status update will occur.
+ */
+ bf_first->bf_lastds = bf_prev->bf_lastds;
+
+ /*
+ * And bf_last in the first descriptor points to the end of
+ * the aggregate list.
+ */
+ bf_first->bf_last = bf_prev;
+
+ /*
+ * For non-AR9300 NICs, which require the rate control
+ * in the final descriptor - let's set that up now.
+ *
+ * This is because the filltxdesc() HAL call doesn't
+ * populate the last segment with rate control information
+ * if firstSeg is also true. For non-aggregate frames
+ * that is fine, as the first frame already has rate control
+ * info. But if the last frame in an aggregate has one
+ * descriptor, both firstseg and lastseg will be true and
+ * the rate info isn't copied.
+ *
+ * This is inefficient on MIPS/ARM platforms that have
+ * non-cachable memory for TX descriptors, but we'll just
+ * make do for now.
+ *
+ * As to why the rate table is stashed in the last descriptor
+ * rather than the first descriptor? Because proctxdesc()
+ * is called on the final descriptor in an MPDU or A-MPDU -
+ * ie, the one that gets updated by the hardware upon
+ * completion. That way proctxdesc() doesn't need to know
+ * about the first _and_ last TX descriptor.
+ */
+ ath_hal_setuplasttxdesc(sc->sc_ah, bf_prev->bf_lastds, ds0);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: end\n", __func__);
+}
+
+/*
+ * Hand-off a frame to the multicast TX queue.
+ *
+ * This is a software TXQ which will be appended to the CAB queue
+ * during the beacon setup code.
+ *
+ * XXX TODO: since the AR9300 EDMA TX queue support wants the QCU ID
+ * as part of the TX descriptor, bf_state.bfs_tx_queue must be updated
+ * with the actual hardware txq, or all of this will fall apart.
+ *
+ * XXX It may not be a bad idea to just stuff the QCU ID into bf_state
+ * and retire bfs_tx_queue; then make sure the CABQ QCU ID is populated
+ * correctly.
+ */
+static void
+ath_tx_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+ ATH_TX_LOCK_ASSERT(sc);
+
+ KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
+ ("%s: busy status 0x%x", __func__, bf->bf_flags));
+
+ /*
+ * Ensure that the tx queue is the cabq, so things get
+ * mapped correctly.
+ */
+ if (bf->bf_state.bfs_tx_queue != sc->sc_cabq->axq_qnum) {
DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: %d: %08x %08x %08x %08x %08x %08x\n",
- __func__, i, ds->ds_link, ds->ds_data,
- ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1]);
+ "%s: bf=%p, bfs_tx_queue=%d, axq_qnum=%d\n",
+ __func__, bf, bf->bf_state.bfs_tx_queue,
+ txq->axq_qnum);
}
+ ATH_TXQ_LOCK(txq);
+ if (ATH_TXQ_LAST(txq, axq_q_s) != NULL) {
+ struct ath_buf *bf_last = ATH_TXQ_LAST(txq, axq_q_s);
+ struct ieee80211_frame *wh;
+
+ /* mark previous frame */
+ wh = mtod(bf_last->bf_m, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ bus_dmamap_sync(sc->sc_dmat, bf_last->bf_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ /* link descriptor */
+ ath_hal_settxdesclink(sc->sc_ah,
+ bf_last->bf_lastds,
+ bf->bf_daddr);
+ }
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+ ATH_TXQ_UNLOCK(txq);
}
+/*
+ * Hand-off packet to a hardware queue.
+ */
static void
-ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
+ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
{
struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf_first;
- /* Fill in the details in the descriptor list */
- ath_tx_chaindesclist(sc, txq, bf);
-
/*
* Insert the frame on the outbound list and pass it on
* to the hardware. Multicast frames buffered for power
@@ -272,107 +753,256 @@
* the SWBA handler since frames only go out on DTIM and
* to avoid possible races.
*/
- ATH_TXQ_LOCK(txq);
+ ATH_TX_LOCK_ASSERT(sc);
KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
- ("busy status 0x%x", bf->bf_flags));
- if (txq->axq_qnum != ATH_TXQ_SWQ) {
-#ifdef IEEE80211_SUPPORT_TDMA
- int qbusy;
+ ("%s: busy status 0x%x", __func__, bf->bf_flags));
+ KASSERT(txq->axq_qnum != ATH_TXQ_SWQ,
+ ("ath_tx_handoff_hw called for mcast queue"));
+ /*
+ * XXX racy, should hold the PCU lock when checking this,
+ * and also should ensure that the TX counter is >0!
+ */
+ KASSERT((sc->sc_inreset_cnt == 0),
+ ("%s: TX during reset?\n", __func__));
+
+#if 0
+ /*
+ * This causes a LOR. Find out where the PCU lock is being
+ * held whilst the TXQ lock is grabbed - that shouldn't
+ * be occuring.
+ */
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt) {
+ ATH_PCU_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: called with sc_in_reset != 0\n",
+ __func__);
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: queued: TXDP[%u] = %p (%p) depth %d\n",
+ __func__, txq->axq_qnum,
+ (caddr_t)bf->bf_daddr, bf->bf_desc,
+ txq->axq_depth);
+ /* XXX axq_link needs to be set and updated! */
ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- qbusy = ath_hal_txqenabled(ah, txq->axq_qnum);
- if (txq->axq_link == NULL) {
- /*
- * Be careful writing the address to TXDP. If
- * the tx q is enabled then this write will be
- * ignored. Normally this is not an issue but
- * when tdma is in use and the q is beacon gated
- * this race can occur. If the q is busy then
- * defer the work to later--either when another
- * packet comes along or when we prepare a beacon
- * frame at SWBA.
- */
- if (!qbusy) {
- ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: TXDP[%u] = %p (%p) depth %d\n",
- __func__, txq->axq_qnum,
- (caddr_t)bf->bf_daddr, bf->bf_desc,
- txq->axq_depth);
- } else {
- txq->axq_flags |= ATH_TXQ_PUTPENDING;
- DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
- "%s: Q%u busy, defer enable\n", __func__,
- txq->axq_qnum);
- }
- } else {
- *txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
- txq->axq_qnum, txq->axq_link,
- (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
- if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) {
- /*
- * The q was busy when we previously tried
- * to write the address of the first buffer
- * in the chain. Since it's not busy now
- * handle this chore. We are certain the
- * buffer at the front is the right one since
- * axq_link is NULL only when the buffer list
- * is/was empty.
- */
- ath_hal_puttxbuf(ah, txq->axq_qnum,
- STAILQ_FIRST(&txq->axq_q)->bf_daddr);
- txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
- DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
- "%s: Q%u restarted\n", __func__,
- txq->axq_qnum);
- }
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth++;
+ return;
}
-#else
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- if (txq->axq_link == NULL) {
- ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: TXDP[%u] = %p (%p) depth %d\n",
- __func__, txq->axq_qnum,
- (caddr_t)bf->bf_daddr, bf->bf_desc,
- txq->axq_depth);
- } else {
- *txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
- txq->axq_qnum, txq->axq_link,
- (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
- }
-#endif /* IEEE80211_SUPPORT_TDMA */
- txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
- ath_hal_txstart(ah, txq->axq_qnum);
- } else {
- if (txq->axq_link != NULL) {
- struct ath_buf *last = ATH_TXQ_LAST(txq);
- struct ieee80211_frame *wh;
+ ATH_PCU_UNLOCK(sc);
+#endif
- /* mark previous frame */
- wh = mtod(last->bf_m, struct ieee80211_frame *);
- wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
- bus_dmamap_sync(sc->sc_dmat, last->bf_dmamap,
- BUS_DMASYNC_PREWRITE);
+ ATH_TXQ_LOCK(txq);
- /* link descriptor */
- *txq->axq_link = bf->bf_daddr;
- }
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
+ /*
+ * XXX TODO: if there's a holdingbf, then
+ * ATH_TXQ_PUTRUNNING should be clear.
+ *
+ * If there is a holdingbf and the list is empty,
+ * then axq_link should be pointing to the holdingbf.
+ *
+ * Otherwise it should point to the last descriptor
+ * in the last ath_buf.
+ *
+ * In any case, we should really ensure that we
+ * update the previous descriptor link pointer to
+ * this descriptor, regardless of all of the above state.
+ *
+ * For now this is captured by having axq_link point
+ * to either the holdingbf (if the TXQ list is empty)
+ * or the end of the list (if the TXQ list isn't empty.)
+ * I'd rather just kill axq_link here and do it as above.
+ */
+
+ /*
+ * Append the frame to the TX queue.
+ */
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+ ATH_KTR(sc, ATH_KTR_TX, 3,
+ "ath_tx_handoff: non-tdma: txq=%u, add bf=%p "
+ "depth=%d",
+ txq->axq_qnum,
+ bf,
+ txq->axq_depth);
+
+ /*
+ * If there's a link pointer, update it.
+ *
+ * XXX we should replace this with the above logic, just
+ * to kill axq_link with fire.
+ */
+ if (txq->axq_link != NULL) {
+ *txq->axq_link = bf->bf_daddr;
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
+ txq->axq_qnum, txq->axq_link,
+ (caddr_t)bf->bf_daddr, bf->bf_desc,
+ txq->axq_depth);
+ ATH_KTR(sc, ATH_KTR_TX, 5,
+ "ath_tx_handoff: non-tdma: link[%u](%p)=%p (%p) "
+ "lastds=%d",
+ txq->axq_qnum, txq->axq_link,
+ (caddr_t)bf->bf_daddr, bf->bf_desc,
+ bf->bf_lastds);
}
+
+ /*
+ * If we've not pushed anything into the hardware yet,
+ * push the head of the queue into the TxDP.
+ *
+ * Once we've started DMA, there's no guarantee that
+ * updating the TxDP with a new value will actually work.
+ * So we just don't do that - if we hit the end of the list,
+ * we keep that buffer around (the "holding buffer") and
+ * re-start DMA by updating the link pointer of _that_
+ * descriptor and then restart DMA.
+ */
+ if (! (txq->axq_flags & ATH_TXQ_PUTRUNNING)) {
+ bf_first = TAILQ_FIRST(&txq->axq_q);
+ txq->axq_flags |= ATH_TXQ_PUTRUNNING;
+ ath_hal_puttxbuf(ah, txq->axq_qnum, bf_first->bf_daddr);
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: TXDP[%u] = %p (%p) depth %d\n",
+ __func__, txq->axq_qnum,
+ (caddr_t)bf_first->bf_daddr, bf_first->bf_desc,
+ txq->axq_depth);
+ ATH_KTR(sc, ATH_KTR_TX, 5,
+ "ath_tx_handoff: TXDP[%u] = %p (%p) "
+ "lastds=%p depth %d",
+ txq->axq_qnum,
+ (caddr_t)bf_first->bf_daddr, bf_first->bf_desc,
+ bf_first->bf_lastds,
+ txq->axq_depth);
+ }
+
+ /*
+ * Ensure that the bf TXQ matches this TXQ, so later
+ * checking and holding buffer manipulation is sane.
+ */
+ if (bf->bf_state.bfs_tx_queue != txq->axq_qnum) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: bf=%p, bfs_tx_queue=%d, axq_qnum=%d\n",
+ __func__, bf, bf->bf_state.bfs_tx_queue,
+ txq->axq_qnum);
+ }
+
+ /*
+ * Track aggregate queue depth.
+ */
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth++;
+
+ /*
+ * Update the link pointer.
+ */
+ ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
+
+ /*
+ * Start DMA.
+ *
+ * If we wrote a TxDP above, DMA will start from here.
+ *
+ * If DMA is running, it'll do nothing.
+ *
+ * If the DMA engine hit the end of the QCU list (ie LINK=NULL,
+ * or VEOL) then it stops at the last transmitted write.
+ * We then append a new frame by updating the link pointer
+ * in that descriptor and then kick TxE here; it will re-read
+ * that last descriptor and find the new descriptor to transmit.
+ *
+ * This is why we keep the holding descriptor around.
+ */
+ ath_hal_txstart(ah, txq->axq_qnum);
ATH_TXQ_UNLOCK(txq);
+ ATH_KTR(sc, ATH_KTR_TX, 1,
+ "ath_tx_handoff: txq=%u, txstart", txq->axq_qnum);
}
+/*
+ * Restart TX DMA for the given TXQ.
+ *
+ * This must be called whether the queue is empty or not.
+ */
+static void
+ath_legacy_tx_dma_restart(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_buf *bf, *bf_last;
+
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ /* XXX make this ATH_TXQ_FIRST */
+ bf = TAILQ_FIRST(&txq->axq_q);
+ bf_last = ATH_TXQ_LAST(txq, axq_q_s);
+
+ if (bf == NULL)
+ return;
+
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: Q%d: bf=%p, bf_last=%p, daddr=0x%08x\n",
+ __func__,
+ txq->axq_qnum,
+ bf,
+ bf_last,
+ (uint32_t) bf->bf_daddr);
+
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_RESET)
+ ath_tx_dump(sc, txq);
+#endif
+
+ /*
+ * This is called from a restart, so DMA is known to be
+ * completely stopped.
+ */
+ KASSERT((!(txq->axq_flags & ATH_TXQ_PUTRUNNING)),
+ ("%s: Q%d: called with PUTRUNNING=1\n",
+ __func__,
+ txq->axq_qnum));
+
+ ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr);
+ txq->axq_flags |= ATH_TXQ_PUTRUNNING;
+
+ ath_hal_gettxdesclinkptr(sc->sc_ah, bf_last->bf_lastds,
+ &txq->axq_link);
+ ath_hal_txstart(sc->sc_ah, txq->axq_qnum);
+}
+
+/*
+ * Hand off a packet to the hardware (or mcast queue.)
+ *
+ * The relevant hardware txq should be locked.
+ */
+static void
+ath_legacy_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+ ATH_TX_LOCK_ASSERT(sc);
+
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC))
+ ath_tx_alq_post(sc, bf);
+#endif
+
+ if (txq->axq_qnum == ATH_TXQ_SWQ)
+ ath_tx_handoff_mcast(sc, txq, bf);
+ else
+ ath_tx_handoff_hw(sc, txq, bf);
+}
+
static int
ath_tx_tag_crypto(struct ath_softc *sc, struct ieee80211_node *ni,
- struct mbuf *m0, int iswep, int isfrag, int *hdrlen, int *pktlen, int *keyix)
+ struct mbuf *m0, int iswep, int isfrag, int *hdrlen, int *pktlen,
+ int *keyix)
{
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: hdrlen=%d, pktlen=%d, isfrag=%d, iswep=%d, m0=%p\n",
+ __func__,
+ *hdrlen,
+ *pktlen,
+ isfrag,
+ iswep,
+ m0);
+
if (iswep) {
const struct ieee80211_cipher *cip;
struct ieee80211_key *k;
@@ -390,7 +1020,7 @@
* 802.11 layer counts failures and provides
* debugging/diagnostics.
*/
- return 0;
+ return (0);
}
/*
* Adjust the packet + header lengths for the crypto
@@ -417,12 +1047,143 @@
} else
(*keyix) = HAL_TXKEYIX_INVALID;
- return 1;
+ return (1);
}
+/*
+ * Calculate whether interoperability protection is required for
+ * this frame.
+ *
+ * This requires the rate control information be filled in,
+ * as the protection requirement depends upon the current
+ * operating mode / PHY.
+ */
+static void
+ath_tx_calc_protection(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ieee80211_frame *wh;
+ uint8_t rix;
+ uint16_t flags;
+ int shortPreamble;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ flags = bf->bf_state.bfs_txflags;
+ rix = bf->bf_state.bfs_rc[0].rix;
+ shortPreamble = bf->bf_state.bfs_shpream;
+ wh = mtod(bf->bf_m, struct ieee80211_frame *);
+
+ /*
+ * If 802.11g protection is enabled, determine whether
+ * to use RTS/CTS or just CTS. Note that this is only
+ * done for OFDM unicast frames.
+ */
+ if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
+ rt->info[rix].phy == IEEE80211_T_OFDM &&
+ (flags & HAL_TXDESC_NOACK) == 0) {
+ bf->bf_state.bfs_doprot = 1;
+ /* XXX fragments must use CCK rates w/ protection */
+ if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
+ flags |= HAL_TXDESC_RTSENA;
+ } else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
+ flags |= HAL_TXDESC_CTSENA;
+ }
+ /*
+ * For frags it would be desirable to use the
+ * highest CCK rate for RTS/CTS. But stations
+ * farther away may detect it at a lower CCK rate
+ * so use the configured protection rate instead
+ * (for now).
+ */
+ sc->sc_stats.ast_tx_protect++;
+ }
+
+ /*
+ * If 11n protection is enabled and it's a HT frame,
+ * enable RTS.
+ *
+ * XXX ic_htprotmode or ic_curhtprotmode?
+ * XXX should it_htprotmode only matter if ic_curhtprotmode
+ * XXX indicates it's not a HT pure environment?
+ */
+ if ((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) &&
+ rt->info[rix].phy == IEEE80211_T_HT &&
+ (flags & HAL_TXDESC_NOACK) == 0) {
+ flags |= HAL_TXDESC_RTSENA;
+ sc->sc_stats.ast_tx_htprotect++;
+ }
+ bf->bf_state.bfs_txflags = flags;
+}
+
+/*
+ * Update the frame duration given the currently selected rate.
+ *
+ * This also updates the frame duration value, so it will require
+ * a DMA flush.
+ */
+static void
+ath_tx_calc_duration(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ieee80211_frame *wh;
+ uint8_t rix;
+ uint16_t flags;
+ int shortPreamble;
+ struct ath_hal *ah = sc->sc_ah;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ int isfrag = bf->bf_m->m_flags & M_FRAG;
+
+ flags = bf->bf_state.bfs_txflags;
+ rix = bf->bf_state.bfs_rc[0].rix;
+ shortPreamble = bf->bf_state.bfs_shpream;
+ wh = mtod(bf->bf_m, struct ieee80211_frame *);
+
+ /*
+ * Calculate duration. This logically belongs in the 802.11
+ * layer but it lacks sufficient information to calculate it.
+ */
+ if ((flags & HAL_TXDESC_NOACK) == 0 &&
+ (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
+ u_int16_t dur;
+ if (shortPreamble)
+ dur = rt->info[rix].spAckDuration;
+ else
+ dur = rt->info[rix].lpAckDuration;
+ if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
+ dur += dur; /* additional SIFS+ACK */
+ /*
+ * Include the size of next fragment so NAV is
+ * updated properly. The last fragment uses only
+ * the ACK duration
+ *
+ * XXX TODO: ensure that the rate lookup for each
+ * fragment is the same as the rate used by the
+ * first fragment!
+ */
+ dur += ath_hal_computetxtime(ah,
+ rt,
+ bf->bf_nextfraglen,
+ rix, shortPreamble);
+ }
+ if (isfrag) {
+ /*
+ * Force hardware to use computed duration for next
+ * fragment by disabling multi-rate retry which updates
+ * duration based on the multi-rate duration table.
+ */
+ bf->bf_state.bfs_ismrr = 0;
+ bf->bf_state.bfs_try0 = ATH_TXMGTTRY;
+ /* XXX update bfs_rc[0].try? */
+ }
+
+ /* Update the duration field itself */
+ *(u_int16_t *)wh->i_dur = htole16(dur);
+ }
+}
+
static uint8_t
ath_tx_get_rtscts_rate(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
- int rix, int cix, int shortPreamble)
+ int cix, int shortPreamble)
{
uint8_t ctsrate;
@@ -439,10 +1200,9 @@
if (shortPreamble)
ctsrate |= rt->info[cix].shortPreamble;
- return ctsrate;
+ return (ctsrate);
}
-
/*
* Calculate the RTS/CTS duration for legacy frames.
*/
@@ -457,7 +1217,7 @@
if (rt->info[cix].phy == IEEE80211_T_HT) {
printf("%s: HT rate where it shouldn't be (0x%x)\n",
__func__, rt->info[cix].rateCode);
- return -1;
+ return (-1);
}
/*
@@ -485,39 +1245,347 @@
ctsduration += rt->info[rix].lpAckDuration;
}
- return ctsduration;
+ return (ctsduration);
}
-int
-ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
- struct mbuf *m0)
+/*
+ * Update the given ath_buf with updated rts/cts setup and duration
+ * values.
+ *
+ * To support rate lookups for each software retry, the rts/cts rate
+ * and cts duration must be re-calculated.
+ *
+ * This function assumes the RTS/CTS flags have been set as needed;
+ * mrr has been disabled; and the rate control lookup has been done.
+ *
+ * XXX TODO: MRR need only be disabled for the pre-11n NICs.
+ * XXX The 11n NICs support per-rate RTS/CTS configuration.
+ */
+static void
+ath_tx_set_rtscts(struct ath_softc *sc, struct ath_buf *bf)
{
+ uint16_t ctsduration = 0;
+ uint8_t ctsrate = 0;
+ uint8_t rix = bf->bf_state.bfs_rc[0].rix;
+ uint8_t cix = 0;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+
+ /*
+ * No RTS/CTS enabled? Don't bother.
+ */
+ if ((bf->bf_state.bfs_txflags &
+ (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) == 0) {
+ /* XXX is this really needed? */
+ bf->bf_state.bfs_ctsrate = 0;
+ bf->bf_state.bfs_ctsduration = 0;
+ return;
+ }
+
+ /*
+ * If protection is enabled, use the protection rix control
+ * rate. Otherwise use the rate0 control rate.
+ */
+ if (bf->bf_state.bfs_doprot)
+ rix = sc->sc_protrix;
+ else
+ rix = bf->bf_state.bfs_rc[0].rix;
+
+ /*
+ * If the raw path has hard-coded ctsrate0 to something,
+ * use it.
+ */
+ if (bf->bf_state.bfs_ctsrate0 != 0)
+ cix = ath_tx_findrix(sc, bf->bf_state.bfs_ctsrate0);
+ else
+ /* Control rate from above */
+ cix = rt->info[rix].controlRate;
+
+ /* Calculate the rtscts rate for the given cix */
+ ctsrate = ath_tx_get_rtscts_rate(sc->sc_ah, rt, cix,
+ bf->bf_state.bfs_shpream);
+
+ /* The 11n chipsets do ctsduration calculations for you */
+ if (! ath_tx_is_11n(sc))
+ ctsduration = ath_tx_calc_ctsduration(sc->sc_ah, rix, cix,
+ bf->bf_state.bfs_shpream, bf->bf_state.bfs_pktlen,
+ rt, bf->bf_state.bfs_txflags);
+
+ /* Squirrel away in ath_buf */
+ bf->bf_state.bfs_ctsrate = ctsrate;
+ bf->bf_state.bfs_ctsduration = ctsduration;
+
+ /*
+ * Must disable multi-rate retry when using RTS/CTS.
+ */
+ if (!sc->sc_mrrprot) {
+ bf->bf_state.bfs_ismrr = 0;
+ bf->bf_state.bfs_try0 =
+ bf->bf_state.bfs_rc[0].tries = ATH_TXMGTTRY; /* XXX ew */
+ }
+}
+
+/*
+ * Setup the descriptor chain for a normal or fast-frame
+ * frame.
+ *
+ * XXX TODO: extend to include the destination hardware QCU ID.
+ * Make sure that is correct. Make sure that when being added
+ * to the mcastq, the CABQ QCUID is set or things will get a bit
+ * odd.
+ */
+static void
+ath_tx_setds(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_desc *ds = bf->bf_desc;
+ struct ath_hal *ah = sc->sc_ah;
+
+ if (bf->bf_state.bfs_txrate0 == 0)
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: bf=%p, txrate0=%d\n", __func__, bf, 0);
+
+ ath_hal_setuptxdesc(ah, ds
+ , bf->bf_state.bfs_pktlen /* packet length */
+ , bf->bf_state.bfs_hdrlen /* header length */
+ , bf->bf_state.bfs_atype /* Atheros packet type */
+ , bf->bf_state.bfs_txpower /* txpower */
+ , bf->bf_state.bfs_txrate0
+ , bf->bf_state.bfs_try0 /* series 0 rate/tries */
+ , bf->bf_state.bfs_keyix /* key cache index */
+ , bf->bf_state.bfs_txantenna /* antenna mode */
+ , bf->bf_state.bfs_txflags /* flags */
+ , bf->bf_state.bfs_ctsrate /* rts/cts rate */
+ , bf->bf_state.bfs_ctsduration /* rts/cts duration */
+ );
+
+ /*
+ * This will be overriden when the descriptor chain is written.
+ */
+ bf->bf_lastds = ds;
+ bf->bf_last = bf;
+
+ /* Set rate control and descriptor chain for this frame */
+ ath_tx_set_ratectrl(sc, bf->bf_node, bf);
+ ath_tx_chaindesclist(sc, ds, bf, 0, 0, 0);
+}
+
+/*
+ * Do a rate lookup.
+ *
+ * This performs a rate lookup for the given ath_buf only if it's required.
+ * Non-data frames and raw frames don't require it.
+ *
+ * This populates the primary and MRR entries; MRR values are
+ * then disabled later on if something requires it (eg RTS/CTS on
+ * pre-11n chipsets.
+ *
+ * This needs to be done before the RTS/CTS fields are calculated
+ * as they may depend upon the rate chosen.
+ */
+static void
+ath_tx_do_ratelookup(struct ath_softc *sc, struct ath_buf *bf)
+{
+ uint8_t rate, rix;
+ int try0;
+
+ if (! bf->bf_state.bfs_doratelookup)
+ return;
+
+ /* Get rid of any previous state */
+ bzero(bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc));
+
+ ATH_NODE_LOCK(ATH_NODE(bf->bf_node));
+ ath_rate_findrate(sc, ATH_NODE(bf->bf_node), bf->bf_state.bfs_shpream,
+ bf->bf_state.bfs_pktlen, &rix, &try0, &rate);
+
+ /* In case MRR is disabled, make sure rc[0] is setup correctly */
+ bf->bf_state.bfs_rc[0].rix = rix;
+ bf->bf_state.bfs_rc[0].ratecode = rate;
+ bf->bf_state.bfs_rc[0].tries = try0;
+
+ if (bf->bf_state.bfs_ismrr && try0 != ATH_TXMAXTRY)
+ ath_rate_getxtxrates(sc, ATH_NODE(bf->bf_node), rix,
+ bf->bf_state.bfs_rc);
+ ATH_NODE_UNLOCK(ATH_NODE(bf->bf_node));
+
+ sc->sc_txrix = rix; /* for LED blinking */
+ sc->sc_lastdatarix = rix; /* for fast frames */
+ bf->bf_state.bfs_try0 = try0;
+ bf->bf_state.bfs_txrate0 = rate;
+}
+
+/*
+ * Update the CLRDMASK bit in the ath_buf if it needs to be set.
+ */
+static void
+ath_tx_update_clrdmask(struct ath_softc *sc, struct ath_tid *tid,
+ struct ath_buf *bf)
+{
+ struct ath_node *an = ATH_NODE(bf->bf_node);
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (an->clrdmask == 1) {
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+ an->clrdmask = 0;
+ }
+}
+
+/*
+ * Return whether this frame should be software queued or
+ * direct dispatched.
+ *
+ * When doing powersave, BAR frames should be queued but other management
+ * frames should be directly sent.
+ *
+ * When not doing powersave, stick BAR frames into the hardware queue
+ * so it goes out even though the queue is paused.
+ *
+ * For now, management frames are also software queued by default.
+ */
+static int
+ath_tx_should_swq_frame(struct ath_softc *sc, struct ath_node *an,
+ struct mbuf *m0, int *queue_to_head)
+{
+ struct ieee80211_node *ni = &an->an_node;
+ struct ieee80211_frame *wh;
+ uint8_t type, subtype;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+ (*queue_to_head) = 0;
+
+ /* If it's not in powersave - direct-dispatch BAR */
+ if ((ATH_NODE(ni)->an_is_powersave == 0)
+ && type == IEEE80211_FC0_TYPE_CTL &&
+ subtype == IEEE80211_FC0_SUBTYPE_BAR) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: BAR: TX'ing direct\n", __func__);
+ return (0);
+ } else if ((ATH_NODE(ni)->an_is_powersave == 1)
+ && type == IEEE80211_FC0_TYPE_CTL &&
+ subtype == IEEE80211_FC0_SUBTYPE_BAR) {
+ /* BAR TX whilst asleep; queue */
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: swq: TX'ing\n", __func__);
+ (*queue_to_head) = 1;
+ return (1);
+ } else if ((ATH_NODE(ni)->an_is_powersave == 1)
+ && (type == IEEE80211_FC0_TYPE_MGT ||
+ type == IEEE80211_FC0_TYPE_CTL)) {
+ /*
+ * Other control/mgmt frame; bypass software queuing
+ * for now!
+ */
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: %6D: Node is asleep; sending mgmt "
+ "(type=%d, subtype=%d)\n",
+ __func__, ni->ni_macaddr, ":", type, subtype);
+ return (0);
+ } else {
+ return (1);
+ }
+}
+
+
+/*
+ * Transmit the given frame to the hardware.
+ *
+ * The frame must already be setup; rate control must already have
+ * been done.
+ *
+ * XXX since the TXQ lock is being held here (and I dislike holding
+ * it for this long when not doing software aggregation), later on
+ * break this function into "setup_normal" and "xmit_normal". The
+ * lock only needs to be held for the ath_tx_handoff call.
+ *
+ * XXX we don't update the leak count here - if we're doing
+ * direct frame dispatch, we need to be able to do it without
+ * decrementing the leak count (eg multicast queue frames.)
+ */
+static void
+ath_tx_xmit_normal(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+ struct ath_node *an = ATH_NODE(bf->bf_node);
+ struct ath_tid *tid = &an->an_tid[bf->bf_state.bfs_tid];
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * For now, just enable CLRDMASK. ath_tx_xmit_normal() does
+ * set a completion handler however it doesn't (yet) properly
+ * handle the strict ordering requirements needed for normal,
+ * non-aggregate session frames.
+ *
+ * Once this is implemented, only set CLRDMASK like this for
+ * frames that must go out - eg management/raw frames.
+ */
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+
+ /* Setup the descriptor before handoff */
+ ath_tx_do_ratelookup(sc, bf);
+ ath_tx_calc_duration(sc, bf);
+ ath_tx_calc_protection(sc, bf);
+ ath_tx_set_rtscts(sc, bf);
+ ath_tx_rate_fill_rcflags(sc, bf);
+ ath_tx_setds(sc, bf);
+
+ /* Track per-TID hardware queue depth correctly */
+ tid->hwq_depth++;
+
+ /* Assign the completion handler */
+ bf->bf_comp = ath_tx_normal_comp;
+
+ /* Hand off to hardware */
+ ath_tx_handoff(sc, txq, bf);
+}
+
+/*
+ * Do the basic frame setup stuff that's required before the frame
+ * is added to a software queue.
+ *
+ * All frames get mostly the same treatment and it's done once.
+ * Retransmits fiddle with things like the rate control setup,
+ * setting the retransmit bit in the packet; doing relevant DMA/bus
+ * syncing and relinking it (back) into the hardware TX queue.
+ *
+ * Note that this may cause the mbuf to be reallocated, so
+ * m0 may not be valid.
+ */
+static int
+ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_buf *bf, struct mbuf *m0, struct ath_txq *txq)
+{
struct ieee80211vap *vap = ni->ni_vap;
- struct ath_vap *avp = ATH_VAP(vap);
struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
int error, iswep, ismcast, isfrag, ismrr;
- int keyix, hdrlen, pktlen, try0;
- u_int8_t rix, txrate, ctsrate;
- u_int8_t cix = 0xff; /* NB: silence compiler */
+ int keyix, hdrlen, pktlen, try0 = 0;
+ u_int8_t rix = 0, txrate = 0;
struct ath_desc *ds;
- struct ath_txq *txq;
struct ieee80211_frame *wh;
- u_int subtype, flags, ctsduration;
+ u_int subtype, flags;
HAL_PKT_TYPE atype;
const HAL_RATE_TABLE *rt;
HAL_BOOL shortPreamble;
struct ath_node *an;
u_int pri;
- uint8_t try[4], rate[4];
- bzero(try, sizeof(try));
- bzero(rate, sizeof(rate));
+ /*
+ * 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_TX_LOCK_ASSERT(sc);
wh = mtod(m0, struct ieee80211_frame *);
- iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
+ iswep = wh->i_fc[1] & IEEE80211_FC1_PROTECTED;
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
isfrag = m0->m_flags & M_FRAG;
hdrlen = ieee80211_anyhdrsize(wh);
@@ -528,7 +1596,8 @@
pktlen = m0->m_pkthdr.len - (hdrlen & 3);
/* Handle encryption twiddling if needed */
- if (! ath_tx_tag_crypto(sc, ni, m0, iswep, isfrag, &hdrlen, &pktlen, &keyix)) {
+ if (! ath_tx_tag_crypto(sc, ni, m0, iswep, isfrag, &hdrlen,
+ &pktlen, &keyix)) {
ath_freetx(m0);
return EIO;
}
@@ -568,7 +1637,8 @@
}
an = ATH_NODE(ni);
- flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
+ //flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
+ flags = 0;
ismrr = 0; /* default no multi-rate retry*/
pri = M_WME_GETAC(m0); /* honor classification */
/* XXX use txparams instead of fixed values */
@@ -624,12 +1694,12 @@
txrate |= rt->info[rix].shortPreamble;
try0 = ATH_TXMAXTRY; /* XXX?too many? */
} else {
- ath_rate_findrate(sc, an, shortPreamble, pktlen,
- &rix, &try0, &txrate);
- sc->sc_txrix = rix; /* for LED blinking */
- sc->sc_lastdatarix = rix; /* for fast frames */
- if (try0 != ATH_TXMAXTRY)
- ismrr = 1;
+ /*
+ * Do rate lookup on each TX, rather than using
+ * the hard-coded TX information decided here.
+ */
+ ismrr = 1;
+ bf->bf_state.bfs_doratelookup = 1;
}
if (cap->cap_wmeParams[pri].wmep_noackPolicy)
flags |= HAL_TXDESC_NOACK;
@@ -638,19 +1708,44 @@
if_printf(ifp, "bogus frame type 0x%x (%s)\n",
wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
/* XXX statistic */
+ /* XXX free tx dmamap */
ath_freetx(m0);
return EIO;
}
- txq = sc->sc_ac2q[pri];
/*
- * When servicing one or more stations in power-save mode
- * (or) if there is some mcast data waiting on the mcast
- * queue (to prevent out of order delivery) multicast
- * frames must be buffered until after the beacon.
+ * 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 (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
- txq = &avp->av_mcastq;
+#if 0
+ if (txq != sc->sc_ac2q[pri]) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%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.
@@ -660,7 +1755,6 @@
} else if (pktlen > vap->iv_rtsthreshold &&
(ni->ni_ath_flags & IEEE80211_NODE_FF) == 0) {
flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
- cix = rt->info[rix].controlRate;
sc->sc_stats.ast_tx_rts++;
}
if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */
@@ -670,6 +1764,7 @@
DPRINTF(sc, ATH_DEBUG_TDMA,
"%s: discard frame, ACK required w/ TDMA\n", __func__);
sc->sc_stats.ast_tdma_ack++;
+ /* XXX free tx dmamap */
ath_freetx(m0);
return EIO;
}
@@ -676,105 +1771,30 @@
#endif
/*
- * If 802.11g protection is enabled, determine whether
- * to use RTS/CTS or just CTS. Note that this is only
- * done for OFDM unicast frames.
- */
- if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
- rt->info[rix].phy == IEEE80211_T_OFDM &&
- (flags & HAL_TXDESC_NOACK) == 0) {
- /* XXX fragments must use CCK rates w/ protection */
- if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
- flags |= HAL_TXDESC_RTSENA;
- else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
- flags |= HAL_TXDESC_CTSENA;
- if (isfrag) {
- /*
- * For frags it would be desirable to use the
- * highest CCK rate for RTS/CTS. But stations
- * farther away may detect it at a lower CCK rate
- * so use the configured protection rate instead
- * (for now).
- */
- cix = rt->info[sc->sc_protrix].controlRate;
- } else
- cix = rt->info[sc->sc_protrix].controlRate;
- sc->sc_stats.ast_tx_protect++;
- }
-
-#if 0
- /*
- * If 11n protection is enabled and it's a HT frame,
- * enable RTS.
+ * Determine if a tx interrupt should be generated for
+ * this descriptor. We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt. We periodically mark descriptors in this
+ * way to insure timely replenishing of the supply needed
+ * for sending frames. Defering interrupts reduces system
+ * load and potentially allows more concurrent work to be
+ * done but if done to aggressively can cause senders to
+ * backup.
*
- * XXX ic_htprotmode or ic_curhtprotmode?
- * XXX should it_htprotmode only matter if ic_curhtprotmode
- * XXX indicates it's not a HT pure environment?
+ * NB: use >= to deal with sc_txintrperiod changing
+ * dynamically through sysctl.
*/
- if ((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) &&
- rt->info[rix].phy == IEEE80211_T_HT &&
- (flags & HAL_TXDESC_NOACK) == 0) {
- cix = rt->info[sc->sc_protrix].controlRate;
- flags |= HAL_TXDESC_RTSENA;
- sc->sc_stats.ast_tx_htprotect++;
+ if (flags & HAL_TXDESC_INTREQ) {
+ txq->axq_intrcnt = 0;
+ } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) {
+ flags |= HAL_TXDESC_INTREQ;
+ txq->axq_intrcnt = 0;
}
-#endif
- /*
- * Calculate duration. This logically belongs in the 802.11
- * layer but it lacks sufficient information to calculate it.
- */
- if ((flags & HAL_TXDESC_NOACK) == 0 &&
- (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
- u_int16_t dur;
- if (shortPreamble)
- dur = rt->info[rix].spAckDuration;
- else
- dur = rt->info[rix].lpAckDuration;
- if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
- dur += dur; /* additional SIFS+ACK */
- KASSERT(m0->m_nextpkt != NULL, ("no fragment"));
- /*
- * Include the size of next fragment so NAV is
- * updated properly. The last fragment uses only
- * the ACK duration
- */
- dur += ath_hal_computetxtime(ah, rt,
- m0->m_nextpkt->m_pkthdr.len,
- rix, shortPreamble);
- }
- if (isfrag) {
- /*
- * Force hardware to use computed duration for next
- * fragment by disabling multi-rate retry which updates
- * duration based on the multi-rate duration table.
- */
- ismrr = 0;
- try0 = ATH_TXMGTTRY; /* XXX? */
- }
- *(u_int16_t *)wh->i_dur = htole16(dur);
- }
+ /* This point forward is actual TX bits */
/*
- * Calculate RTS/CTS rate and duration if needed.
- */
- ctsduration = 0;
- if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
- ctsrate = ath_tx_get_rtscts_rate(ah, rt, rix, cix, shortPreamble);
-
- /* The 11n chipsets do ctsduration calculations for you */
- if (! ath_tx_is_11n(sc))
- ctsduration = ath_tx_calc_ctsduration(ah, rix, cix, shortPreamble,
- pktlen, rt, flags);
- /*
- * Must disable multi-rate retry when using RTS/CTS.
- */
- ismrr = 0;
- try0 = ATH_TXMGTTRY; /* XXX */
- } else
- ctsrate = 0;
-
- /*
* At this point we are committed to sending the frame
* and we don't need to look at m_nextpkt; clear it in
* case this frame is part of frag chain.
@@ -795,77 +1815,271 @@
if (isfrag)
sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate;
- sc->sc_tx_th.wt_txpower = ni->ni_txpower;
+ sc->sc_tx_th.wt_txpower = ieee80211_get_node_txpower(ni);
sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
ieee80211_radiotap_tx(vap, m0);
}
+ /* Blank the legacy rate array */
+ bzero(&bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc));
+
/*
- * Determine if a tx interrupt should be generated for
- * this descriptor. We take a tx interrupt to reap
- * descriptors when the h/w hits an EOL condition or
- * when the descriptor is specifically marked to generate
- * an interrupt. We periodically mark descriptors in this
- * way to insure timely replenishing of the supply needed
- * for sending frames. Defering interrupts reduces system
- * load and potentially allows more concurrent work to be
- * done but if done to aggressively can cause senders to
- * backup.
+ * ath_buf_set_rate needs at least one rate/try to setup
+ * the rate scenario.
+ */
+ bf->bf_state.bfs_rc[0].rix = rix;
+ bf->bf_state.bfs_rc[0].tries = try0;
+ bf->bf_state.bfs_rc[0].ratecode = txrate;
+
+ /* Store the decided rate index values away */
+ bf->bf_state.bfs_pktlen = pktlen;
+ bf->bf_state.bfs_hdrlen = hdrlen;
+ bf->bf_state.bfs_atype = atype;
+ bf->bf_state.bfs_txpower = ieee80211_get_node_txpower(ni);
+ bf->bf_state.bfs_txrate0 = txrate;
+ bf->bf_state.bfs_try0 = try0;
+ bf->bf_state.bfs_keyix = keyix;
+ bf->bf_state.bfs_txantenna = sc->sc_txantenna;
+ bf->bf_state.bfs_txflags = flags;
+ bf->bf_state.bfs_shpream = shortPreamble;
+
+ /* XXX this should be done in ath_tx_setrate() */
+ bf->bf_state.bfs_ctsrate0 = 0; /* ie, no hard-coded ctsrate */
+ bf->bf_state.bfs_ctsrate = 0; /* calculated later */
+ bf->bf_state.bfs_ctsduration = 0;
+ bf->bf_state.bfs_ismrr = ismrr;
+
+ return 0;
+}
+
+/*
+ * Queue a frame to the hardware or software queue.
+ *
+ * This can be called by the net80211 code.
+ *
+ * XXX what about locking? Or, push the seqno assign into the
+ * XXX aggregate scheduler so its serialised?
+ *
+ * XXX When sending management frames via ath_raw_xmit(),
+ * should CLRDMASK be set unconditionally?
+ */
+int
+ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_buf *bf, struct mbuf *m0)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_vap *avp = ATH_VAP(vap);
+ int r = 0;
+ u_int pri;
+ int tid;
+ struct ath_txq *txq;
+ int ismcast;
+ const struct ieee80211_frame *wh;
+ int is_ampdu, is_ampdu_tx, is_ampdu_pending;
+ ieee80211_seq seqno;
+ uint8_t type, subtype;
+ int queue_to_head;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * Determine the target hardware queue.
*
- * NB: use >= to deal with sc_txintrperiod changing
- * dynamically through sysctl.
+ * For multicast frames, the txq gets overridden appropriately
+ * depending upon the state of PS.
+ *
+ * For any other frame, we do a TID/QoS lookup inside the frame
+ * to see what the TID should be. If it's a non-QoS frame, the
+ * AC and TID are overridden. The TID/TXQ code assumes the
+ * TID is on a predictable hardware TXQ, so we don't support
+ * having a node TID queued to multiple hardware TXQs.
+ * This may change in the future but would require some locking
+ * fudgery.
*/
- if (flags & HAL_TXDESC_INTREQ) {
- txq->axq_intrcnt = 0;
- } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) {
- flags |= HAL_TXDESC_INTREQ;
- txq->axq_intrcnt = 0;
+ pri = ath_tx_getac(sc, m0);
+ tid = ath_tx_gettid(sc, m0);
+
+ txq = sc->sc_ac2q[pri];
+ wh = mtod(m0, struct ieee80211_frame *);
+ ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+ /*
+ * Enforce how deep the multicast queue can grow.
+ *
+ * XXX duplicated in ath_raw_xmit().
+ */
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ if (sc->sc_cabq->axq_depth + sc->sc_cabq->fifo.axq_depth
+ > sc->sc_txq_mcastq_maxdepth) {
+ sc->sc_stats.ast_tx_mcastq_overflow++;
+ m_freem(m0);
+ return (ENOBUFS);
+ }
}
- if (ath_tx_is_11n(sc)) {
- rate[0] = rix;
- try[0] = try0;
+ /*
+ * Enforce how deep the unicast queue can grow.
+ *
+ * If the node is in power save then we don't want
+ * the software queue to grow too deep, or a node may
+ * end up consuming all of the ath_buf entries.
+ *
+ * For now, only do this for DATA frames.
+ *
+ * We will want to cap how many management/control
+ * frames get punted to the software queue so it doesn't
+ * fill up. But the correct solution isn't yet obvious.
+ * In any case, this check should at least let frames pass
+ * that we are direct-dispatching.
+ *
+ * XXX TODO: duplicate this to the raw xmit path!
+ */
+ if (type == IEEE80211_FC0_TYPE_DATA &&
+ ATH_NODE(ni)->an_is_powersave &&
+ ATH_NODE(ni)->an_swq_depth >
+ sc->sc_txq_node_psq_maxdepth) {
+ sc->sc_stats.ast_tx_node_psq_overflow++;
+ m_freem(m0);
+ return (ENOBUFS);
}
+ /* A-MPDU TX */
+ is_ampdu_tx = ath_tx_ampdu_running(sc, ATH_NODE(ni), tid);
+ 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: tid=%d, ac=%d, is_ampdu=%d\n",
+ __func__, tid, pri, is_ampdu);
+
+ /* Set local packet state, used to queue packets to hardware */
+ bf->bf_state.bfs_tid = tid;
+ bf->bf_state.bfs_tx_queue = txq->axq_qnum;
+ bf->bf_state.bfs_pri = pri;
+
+#if 1
/*
- * Formulate first tx descriptor with tx controls.
+ * When servicing one or more stations in power-save mode
+ * (or) if there is some mcast data waiting on the mcast
+ * queue (to prevent out of order delivery) multicast frames
+ * must be bufferd until after the beacon.
+ *
+ * TODO: we should lock the mcastq before we check the length.
*/
- /* XXX check return value? */
- /* XXX is this ok to call for 11n descriptors? */
- /* XXX or should it go through the first, next, last 11n calls? */
- ath_hal_setuptxdesc(ah, ds
- , pktlen /* packet length */
- , hdrlen /* header length */
- , atype /* Atheros packet type */
- , ni->ni_txpower /* txpower */
- , txrate, try0 /* series 0 rate/tries */
- , keyix /* key cache index */
- , sc->sc_txantenna /* antenna mode */
- , flags /* flags */
- , ctsrate /* rts/cts rate */
- , ctsduration /* rts/cts duration */
- );
- bf->bf_txflags = flags;
+ if (sc->sc_cabq_enable && ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth)) {
+ txq = &avp->av_mcastq;
+ /*
+ * Mark the frame as eventually belonging on the CAB
+ * queue, so the descriptor setup functions will
+ * correctly initialise the descriptor 'qcuId' field.
+ */
+ bf->bf_state.bfs_tx_queue = sc->sc_cabq->axq_qnum;
+ }
+#endif
+
+ /* Do the generic frame setup */
+ /* XXX should just bzero the bf_state? */
+ bf->bf_state.bfs_dobaw = 0;
+
+ /* A-MPDU TX? Manually set sequence number */
/*
- * Setup the multi-rate retry state only when we're
- * going to use it. This assumes ath_hal_setuptxdesc
- * initializes the descriptors (so we don't have to)
- * when the hardware supports multi-rate retry and
- * we don't use it.
+ * Don't do it whilst pending; the net80211 layer still
+ * assigns them.
*/
- if (ismrr) {
- if (ath_tx_is_11n(sc))
- ath_rate_getxtxrates(sc, an, rix, rate, try);
- else
- ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix);
- }
+ if (is_ampdu_tx) {
+ /*
+ * 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_is_11n(sc)) {
- ath_buf_set_rate(sc, ni, bf, pktlen, flags, ctsrate, (atype == HAL_PKT_TYPE_PSPOLL), rate, try);
- }
+ /*
+ * 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;
+ }
+ }
- ath_tx_handoff(sc, txq, bf);
+ /*
+ * 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;
+
+ /* Is ampdu pending? fetch the seqno and print it out */
+ if (is_ampdu_pending)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: tid %d: ampdu pending, seqno %d\n",
+ __func__, tid, M_SEQNO_GET(m0));
+
+ /* This also sets up the DMA map */
+ r = ath_tx_normal_setup(sc, ni, bf, m0, txq);
+
+ if (r != 0)
+ goto done;
+
+ /* At this point m0 could have changed! */
+ m0 = bf->bf_m;
+
+#if 1
+ /*
+ * If it's a multicast frame, do a direct-dispatch to the
+ * destination hardware queue. Don't bother software
+ * queuing it.
+ */
+ /*
+ * If it's a BAR frame, do a direct dispatch to the
+ * destination hardware queue. Don't bother software
+ * queuing it, as the TID will now be paused.
+ * Sending a BAR frame can occur from the net80211 txa timer
+ * (ie, retries) or from the ath txtask (completion call.)
+ * It queues directly to hardware because the TID is paused
+ * at this point (and won't be unpaused until the BAR has
+ * either been TXed successfully or max retries has been
+ * reached.)
+ */
+ /*
+ * Until things are better debugged - if this node is asleep
+ * and we're sending it a non-BAR frame, direct dispatch it.
+ * Why? Because we need to figure out what's actually being
+ * sent - eg, during reassociation/reauthentication after
+ * the node (last) disappeared whilst asleep, the driver should
+ * have unpaused/unsleep'ed the node. So until that is
+ * sorted out, use this workaround.
+ */
+ if (txq == &avp->av_mcastq) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: bf=%p: mcastq: TX'ing\n", __func__, bf);
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+ ath_tx_xmit_normal(sc, txq, bf);
+ } else if (ath_tx_should_swq_frame(sc, ATH_NODE(ni), m0,
+ &queue_to_head)) {
+ ath_tx_swq(sc, ni, txq, queue_to_head, bf);
+ } else {
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+ ath_tx_xmit_normal(sc, txq, bf);
+ }
+#else
+ /*
+ * For now, since there's no software queue,
+ * direct-dispatch to the hardware.
+ */
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+ /*
+ * Update the current leak count if
+ * we're leaking frames; and set the
+ * MORE flag as appropriate.
+ */
+ ath_tx_leak_count_update(sc, tid, bf);
+ ath_tx_xmit_normal(sc, txq, bf);
+#endif
+done:
return 0;
}
@@ -880,17 +2094,19 @@
struct ieee80211vap *vap = ni->ni_vap;
int error, ismcast, ismrr;
int keyix, hdrlen, pktlen, try0, txantenna;
- u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3;
+ u_int8_t rix, txrate;
struct ieee80211_frame *wh;
- u_int flags, ctsduration;
+ u_int flags;
HAL_PKT_TYPE atype;
const HAL_RATE_TABLE *rt;
struct ath_desc *ds;
u_int pri;
- uint8_t try[4], rate[4];
+ int o_tid = -1;
+ int do_override;
+ uint8_t type, subtype;
+ int queue_to_head;
- bzero(try, sizeof(try));
- bzero(rate, sizeof(rate));
+ ATH_TX_LOCK_ASSERT(sc);
wh = mtod(m0, struct ieee80211_frame *);
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
@@ -902,8 +2118,37 @@
/* XXX honor IEEE80211_BPF_DATAPAD */
pktlen = m0->m_pkthdr.len - (hdrlen & 3) + IEEE80211_CRC_LEN;
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+ ATH_KTR(sc, ATH_KTR_TX, 2,
+ "ath_tx_raw_start: ni=%p, bf=%p, raw", ni, bf);
+
+ 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
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%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);
+ }
+
/* Handle encryption twiddling if needed */
- if (! ath_tx_tag_crypto(sc, ni, m0, params->ibp_flags & IEEE80211_BPF_CRYPTO, 0, &hdrlen, &pktlen, &keyix)) {
+ if (! ath_tx_tag_crypto(sc, ni,
+ m0, params->ibp_flags & IEEE80211_BPF_CRYPTO, 0,
+ &hdrlen, &pktlen, &keyix)) {
ath_freetx(m0);
return EIO;
}
@@ -910,6 +2155,10 @@
/* packet header may have moved, reset our local pointer */
wh = mtod(m0, struct ieee80211_frame *);
+ /* Do the generic frame setup */
+ /* XXX should just bzero the bf_state? */
+ bf->bf_state.bfs_dobaw = 0;
+
error = ath_tx_dmasetup(sc, bf, m0);
if (error != 0)
return error;
@@ -917,12 +2166,16 @@
wh = mtod(m0, struct ieee80211_frame *);
bf->bf_node = ni; /* NB: held reference */
+ /* Always enable CLRDMASK for raw frames for now.. */
flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
flags |= HAL_TXDESC_INTREQ; /* force interrupt */
if (params->ibp_flags & IEEE80211_BPF_RTS)
flags |= HAL_TXDESC_RTSENA;
- else if (params->ibp_flags & IEEE80211_BPF_CTS)
+ else if (params->ibp_flags & IEEE80211_BPF_CTS) {
+ /* XXX assume 11g/11n protection? */
+ bf->bf_state.bfs_doprot = 1;
flags |= HAL_TXDESC_CTSENA;
+ }
/* XXX leave ismcast to injector? */
if ((params->ibp_flags & IEEE80211_BPF_NOACK) || ismcast)
flags |= HAL_TXDESC_NOACK;
@@ -940,23 +2193,13 @@
if (txantenna == 0) /* XXX? */
txantenna = sc->sc_txantenna;
- ctsduration = 0;
- if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
- cix = ath_tx_findrix(sc, params->ibp_ctsrate);
- ctsrate = ath_tx_get_rtscts_rate(ah, rt, rix, cix, params->ibp_flags & IEEE80211_BPF_SHORTPRE);
- /* The 11n chipsets do ctsduration calculations for you */
- if (! ath_tx_is_11n(sc))
- ctsduration = ath_tx_calc_ctsduration(ah, rix, cix,
- params->ibp_flags & IEEE80211_BPF_SHORTPRE, pktlen,
- rt, flags);
- /*
- * Must disable multi-rate retry when using RTS/CTS.
- */
- ismrr = 0; /* XXX */
- } else
- ctsrate = 0;
+ /*
+ * Since ctsrate is fixed, store it away for later
+ * use when the descriptor fields are being set.
+ */
+ if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA))
+ bf->bf_state.bfs_ctsrate0 = params->ibp_ctsrate;
- pri = params->ibp_pri & 3;
/*
* NB: we mark all packets as type PSPOLL so the h/w won't
* set the sequence number, duration, etc.
@@ -972,12 +2215,13 @@
sc->sc_tx_th.wt_tsf = htole64(tsf);
sc->sc_tx_th.wt_flags = sc->sc_hwmap[rix].txflags;
- if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)
sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
if (m0->m_flags & M_FRAG)
sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
sc->sc_tx_th.wt_rate = sc->sc_hwmap[rix].ieeerate;
- sc->sc_tx_th.wt_txpower = ni->ni_txpower;
+ sc->sc_tx_th.wt_txpower = MIN(params->ibp_power,
+ ieee80211_get_node_txpower(ni));
sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
ieee80211_radiotap_tx(vap, m0);
@@ -988,77 +2232,110 @@
*/
ds = bf->bf_desc;
/* XXX check return value? */
- ath_hal_setuptxdesc(ah, ds
- , pktlen /* packet length */
- , hdrlen /* header length */
- , atype /* Atheros packet type */
- , params->ibp_power /* txpower */
- , txrate, try0 /* series 0 rate/tries */
- , keyix /* key cache index */
- , txantenna /* antenna mode */
- , flags /* flags */
- , ctsrate /* rts/cts rate */
- , ctsduration /* rts/cts duration */
- );
- bf->bf_txflags = flags;
- if (ath_tx_is_11n(sc)) {
- rate[0] = ath_tx_findrix(sc, params->ibp_rate0);
- try[0] = params->ibp_try0;
+ /* Store the decided rate index values away */
+ bf->bf_state.bfs_pktlen = pktlen;
+ bf->bf_state.bfs_hdrlen = hdrlen;
+ bf->bf_state.bfs_atype = atype;
+ bf->bf_state.bfs_txpower = MIN(params->ibp_power,
+ ieee80211_get_node_txpower(ni));
+ bf->bf_state.bfs_txrate0 = txrate;
+ bf->bf_state.bfs_try0 = try0;
+ bf->bf_state.bfs_keyix = keyix;
+ bf->bf_state.bfs_txantenna = txantenna;
+ bf->bf_state.bfs_txflags = flags;
+ bf->bf_state.bfs_shpream =
+ !! (params->ibp_flags & IEEE80211_BPF_SHORTPRE);
- if (ismrr) {
- /* Remember, rate[] is actually an array of rix's -adrian */
- rate[0] = ath_tx_findrix(sc, params->ibp_rate0);
- rate[1] = ath_tx_findrix(sc, params->ibp_rate1);
- rate[2] = ath_tx_findrix(sc, params->ibp_rate2);
- rate[3] = ath_tx_findrix(sc, params->ibp_rate3);
+ /* Set local packet state, used to queue packets to hardware */
+ bf->bf_state.bfs_tid = WME_AC_TO_TID(pri);
+ bf->bf_state.bfs_tx_queue = sc->sc_ac2q[pri]->axq_qnum;
+ bf->bf_state.bfs_pri = pri;
- try[0] = params->ibp_try0;
- try[1] = params->ibp_try1;
- try[2] = params->ibp_try2;
- try[3] = params->ibp_try3;
- }
- } else {
- if (ismrr) {
- rix = ath_tx_findrix(sc, params->ibp_rate1);
- rate1 = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- rate1 |= rt->info[rix].shortPreamble;
- if (params->ibp_try2) {
- rix = ath_tx_findrix(sc, params->ibp_rate2);
- rate2 = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- rate2 |= rt->info[rix].shortPreamble;
- } else
- rate2 = 0;
- if (params->ibp_try3) {
- rix = ath_tx_findrix(sc, params->ibp_rate3);
- rate3 = rt->info[rix].rateCode;
- if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
- rate3 |= rt->info[rix].shortPreamble;
- } else
- rate3 = 0;
- ath_hal_setupxtxdesc(ah, ds
- , rate1, params->ibp_try1 /* series 1 */
- , rate2, params->ibp_try2 /* series 2 */
- , rate3, params->ibp_try3 /* series 3 */
- );
- }
+ /* XXX this should be done in ath_tx_setrate() */
+ bf->bf_state.bfs_ctsrate = 0;
+ bf->bf_state.bfs_ctsduration = 0;
+ bf->bf_state.bfs_ismrr = ismrr;
+
+ /* Blank the legacy rate array */
+ bzero(&bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc));
+
+ bf->bf_state.bfs_rc[0].rix =
+ ath_tx_findrix(sc, params->ibp_rate0);
+ bf->bf_state.bfs_rc[0].tries = try0;
+ bf->bf_state.bfs_rc[0].ratecode = txrate;
+
+ if (ismrr) {
+ int rix;
+
+ rix = ath_tx_findrix(sc, params->ibp_rate1);
+ bf->bf_state.bfs_rc[1].rix = rix;
+ bf->bf_state.bfs_rc[1].tries = params->ibp_try1;
+
+ rix = ath_tx_findrix(sc, params->ibp_rate2);
+ bf->bf_state.bfs_rc[2].rix = rix;
+ bf->bf_state.bfs_rc[2].tries = params->ibp_try2;
+
+ rix = ath_tx_findrix(sc, params->ibp_rate3);
+ bf->bf_state.bfs_rc[3].rix = rix;
+ bf->bf_state.bfs_rc[3].tries = params->ibp_try3;
}
+ /*
+ * All the required rate control decisions have been made;
+ * fill in the rc flags.
+ */
+ ath_tx_rate_fill_rcflags(sc, bf);
- if (ath_tx_is_11n(sc)) {
+ /* NB: no buffered multicast in power save support */
+
+ /*
+ * If we're overiding the ADDBA destination, dump directly
+ * into the hardware queue, right after any pending
+ * frames to that node are.
+ */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: dooverride=%d\n",
+ __func__, do_override);
+
+#if 1
+ /*
+ * Put addba frames in the right place in the right TID/HWQ.
+ */
+ if (do_override) {
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
/*
- * notice that rix doesn't include any of the "magic" flags txrate
- * does for communicating "other stuff" to the HAL.
+ * XXX if it's addba frames, should we be leaking
+ * them out via the frame leak method?
+ * XXX for now let's not risk it; but we may wish
+ * to investigate this later.
*/
- ath_buf_set_rate(sc, ni, bf, pktlen, flags, ctsrate, (atype == HAL_PKT_TYPE_PSPOLL), rate, try);
+ ath_tx_xmit_normal(sc, sc->sc_ac2q[pri], bf);
+ } else if (ath_tx_should_swq_frame(sc, ATH_NODE(ni), m0,
+ &queue_to_head)) {
+ /* Queue to software queue */
+ ath_tx_swq(sc, ni, sc->sc_ac2q[pri], queue_to_head, bf);
+ } else {
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+ ath_tx_xmit_normal(sc, sc->sc_ac2q[pri], bf);
}
-
- /* NB: no buffered multicast in power save support */
- ath_tx_handoff(sc, sc->sc_ac2q[pri], bf);
+#else
+ /* Direct-dispatch to the hardware */
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+ /*
+ * Update the current leak count if
+ * we're leaking frames; and set the
+ * MORE flag as appropriate.
+ */
+ ath_tx_leak_count_update(sc, tid, bf);
+ ath_tx_xmit_normal(sc, sc->sc_ac2q[pri], bf);
+#endif
return 0;
}
+/*
+ * Send a raw frame.
+ *
+ * This can be called by net80211.
+ */
int
ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_bpf_params *params)
@@ -1067,8 +2344,22 @@
struct ifnet *ifp = ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
struct ath_buf *bf;
- int error;
+ struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
+ int error = 0;
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt > 0) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: sc_inreset_cnt > 0; bailing\n", __func__);
+ error = EIO;
+ ATH_PCU_UNLOCK(sc);
+ goto bad0;
+ }
+ sc->sc_txstart_cnt++;
+ ATH_PCU_UNLOCK(sc);
+
+ ATH_TX_LOCK(sc);
+
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) {
DPRINTF(sc, ATH_DEBUG_XMIT, "%s: discard frame, %s", __func__,
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ?
@@ -1077,10 +2368,29 @@
error = ENETDOWN;
goto bad;
}
+
/*
+ * Enforce how deep the multicast queue can grow.
+ *
+ * XXX duplicated in ath_tx_start().
+ */
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ if (sc->sc_cabq->axq_depth + sc->sc_cabq->fifo.axq_depth
+ > sc->sc_txq_mcastq_maxdepth) {
+ sc->sc_stats.ast_tx_mcastq_overflow++;
+ error = ENOBUFS;
+ }
+
+ if (error != 0) {
+ m_freem(m);
+ goto bad;
+ }
+ }
+
+ /*
* 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);
@@ -1087,6 +2397,8 @@
error = ENOBUFS;
goto bad;
}
+ ATH_KTR(sc, ATH_KTR_TX, 3, "ath_raw_xmit: m=%p, params=%p, bf=%p\n",
+ m, params, bf);
if (params == NULL) {
/*
@@ -1111,14 +2423,3641 @@
ifp->if_opackets++;
sc->sc_stats.ast_tx_raw++;
+ /*
+ * Update the TIM - if there's anything queued to the
+ * software queue and power save is enabled, we should
+ * set the TIM.
+ */
+ ath_tx_update_tim(sc, ni, 1);
+
+ ATH_TX_UNLOCK(sc);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_txstart_cnt--;
+ ATH_PCU_UNLOCK(sc);
+
return 0;
bad2:
+ ATH_KTR(sc, ATH_KTR_TX, 3, "ath_raw_xmit: bad2: m=%p, params=%p, "
+ "bf=%p",
+ m,
+ params,
+ bf);
ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
+ ath_returnbuf_head(sc, bf);
ATH_TXBUF_UNLOCK(sc);
bad:
+
+ ATH_TX_UNLOCK(sc);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_txstart_cnt--;
+ ATH_PCU_UNLOCK(sc);
+bad0:
+ ATH_KTR(sc, ATH_KTR_TX, 2, "ath_raw_xmit: bad0: m=%p, params=%p",
+ m, params);
ifp->if_oerrors++;
sc->sc_stats.ast_tx_raw_fail++;
ieee80211_free_node(ni);
+
return error;
}
+
+/* Some helper functions */
+
+/*
+ * ADDBA (and potentially others) need to be placed in the same
+ * hardware queue as the TID/node it's relating to. This is so
+ * it goes out after any pending non-aggregate frames to the
+ * same node/TID.
+ *
+ * If this isn't done, the ADDBA can go out before the frames
+ * queued in hardware. Even though these frames have a sequence
+ * number -earlier- than the ADDBA can be transmitted (but
+ * no frames whose sequence numbers are after the ADDBA should
+ * be!) they'll arrive after the ADDBA - and the receiving end
+ * will simply drop them as being out of the BAW.
+ *
+ * The frames can't be appended to the TID software queue - it'll
+ * never be sent out. So these frames have to be directly
+ * dispatched to the hardware, rather than queued in software.
+ * So if this function returns true, the TXQ has to be
+ * overridden and it has to be directly dispatched.
+ *
+ * It's a dirty hack, but someone's gotta do it.
+ */
+
+/*
+ * XXX doesn't belong here!
+ */
+static int
+ieee80211_is_action(struct ieee80211_frame *wh)
+{
+ /* Type: Management frame? */
+ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
+ IEEE80211_FC0_TYPE_MGT)
+ return 0;
+
+ /* Subtype: Action frame? */
+ if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) !=
+ IEEE80211_FC0_SUBTYPE_ACTION)
+ return 0;
+
+ return 1;
+}
+
+#define MS(_v, _f) (((_v) & _f) >> _f##_S)
+/*
+ * Return an alternate TID for ADDBA request frames.
+ *
+ * Yes, this likely should be done in the net80211 layer.
+ */
+static int
+ath_tx_action_frame_override_queue(struct ath_softc *sc,
+ struct ieee80211_node *ni,
+ struct mbuf *m0, int *tid)
+{
+ struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
+ struct ieee80211_action_ba_addbarequest *ia;
+ uint8_t *frm;
+ uint16_t baparamset;
+
+ /* Not action frame? Bail */
+ if (! ieee80211_is_action(wh))
+ return 0;
+
+ /* XXX Not needed for frames we send? */
+#if 0
+ /* Correct length? */
+ if (! ieee80211_parse_action(ni, m))
+ return 0;
+#endif
+
+ /* Extract out action frame */
+ frm = (u_int8_t *)&wh[1];
+ ia = (struct ieee80211_action_ba_addbarequest *) frm;
+
+ /* Not ADDBA? Bail */
+ if (ia->rq_header.ia_category != IEEE80211_ACTION_CAT_BA)
+ return 0;
+ if (ia->rq_header.ia_action != IEEE80211_ACTION_BA_ADDBA_REQUEST)
+ return 0;
+
+ /* Extract TID, return it */
+ baparamset = le16toh(ia->rq_baparamset);
+ *tid = (int) MS(baparamset, IEEE80211_BAPS_TID);
+
+ return 1;
+}
+#undef MS
+
+/* Per-node software queue operations */
+
+/*
+ * Add the current packet to the given BAW.
+ * It is assumed that the current packet
+ *
+ * + fits inside the BAW;
+ * + already has had a sequence number allocated.
+ *
+ * Since the BAW status may be modified by both the ath task and
+ * the net80211/ifnet contexts, the TID must be locked.
+ */
+void
+ath_tx_addto_baw(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, struct ath_buf *bf)
+{
+ int index, cindex;
+ struct ieee80211_tx_ampdu *tap;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (bf->bf_state.bfs_isretried)
+ return;
+
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+
+ if (! bf->bf_state.bfs_dobaw) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: dobaw=0, seqno=%d, window %d:%d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno),
+ tap->txa_start, tap->txa_wnd);
+ }
+
+ if (bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: re-added? tid=%d, seqno %d; window %d:%d; "
+ "baw head=%d tail=%d\n",
+ __func__, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
+ tap->txa_start, tap->txa_wnd, tid->baw_head,
+ tid->baw_tail);
+
+ /*
+ * Verify that the given sequence number is not outside of the
+ * BAW. Complain loudly if that's the case.
+ */
+ if (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
+ SEQNO(bf->bf_state.bfs_seqno))) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: bf=%p: outside of BAW?? tid=%d, seqno %d; window %d:%d; "
+ "baw head=%d tail=%d\n",
+ __func__, bf, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
+ tap->txa_start, tap->txa_wnd, tid->baw_head,
+ tid->baw_tail);
+ }
+
+ /*
+ * ni->ni_txseqs[] is the currently allocated seqno.
+ * the txa state contains the current baw start.
+ */
+ 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: tid=%d, seqno %d; window %d:%d; index=%d cindex=%d "
+ "baw head=%d tail=%d\n",
+ __func__, tid->tid, SEQNO(bf->bf_state.bfs_seqno),
+ tap->txa_start, tap->txa_wnd, index, cindex, tid->baw_head,
+ tid->baw_tail);
+
+
+#if 0
+ assert(tid->tx_buf[cindex] == NULL);
+#endif
+ if (tid->tx_buf[cindex] != NULL) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: ba packet dup (index=%d, cindex=%d, "
+ "head=%d, tail=%d)\n",
+ __func__, index, cindex, tid->baw_head, tid->baw_tail);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: BA bf: %p; seqno=%d ; new bf: %p; seqno=%d\n",
+ __func__,
+ tid->tx_buf[cindex],
+ SEQNO(tid->tx_buf[cindex]->bf_state.bfs_seqno),
+ bf,
+ SEQNO(bf->bf_state.bfs_seqno)
+ );
+ }
+ tid->tx_buf[cindex] = bf;
+
+ if (index >= ((tid->baw_tail - tid->baw_head) &
+ (ATH_TID_MAX_BUFS - 1))) {
+ tid->baw_tail = cindex;
+ INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
+ }
+}
+
+/*
+ * Flip the BAW buffer entry over from the existing one to the new one.
+ *
+ * When software retransmitting a (sub-)frame, it is entirely possible that
+ * the frame ath_buf is marked as BUSY and can't be immediately reused.
+ * In that instance the buffer is cloned and the new buffer is used for
+ * retransmit. We thus need to update the ath_buf slot in the BAW buf
+ * tracking array to maintain consistency.
+ */
+static void
+ath_tx_switch_baw_buf(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, struct ath_buf *old_bf, struct ath_buf *new_bf)
+{
+ int index, cindex;
+ struct ieee80211_tx_ampdu *tap;
+ int seqno = SEQNO(old_bf->bf_state.bfs_seqno);
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ 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);
+
+ /*
+ * Just warn for now; if it happens then we should find out
+ * about it. It's highly likely the aggregation session will
+ * soon hang.
+ */
+ if (old_bf->bf_state.bfs_seqno != new_bf->bf_state.bfs_seqno) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: retransmitted buffer"
+ " has mismatching seqno's, BA session may hang.\n",
+ __func__);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: old seqno=%d, new_seqno=%d\n", __func__,
+ old_bf->bf_state.bfs_seqno, new_bf->bf_state.bfs_seqno);
+ }
+
+ if (tid->tx_buf[cindex] != old_bf) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: ath_buf pointer incorrect; "
+ " has m BA session may hang.\n", __func__);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: old bf=%p, new bf=%p\n", __func__, old_bf, new_bf);
+ }
+
+ tid->tx_buf[cindex] = new_bf;
+}
+
+/*
+ * seq_start - left edge of BAW
+ * seq_next - current/next sequence number to allocate
+ *
+ * Since the BAW status may be modified by both the ath task and
+ * the net80211/ifnet contexts, the TID must be locked.
+ */
+static void
+ath_tx_update_baw(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, const struct ath_buf *bf)
+{
+ int index, cindex;
+ struct ieee80211_tx_ampdu *tap;
+ int seqno = SEQNO(bf->bf_state.bfs_seqno);
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ 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: tid=%d, baw=%d:%d, seqno=%d, index=%d, cindex=%d, "
+ "baw head=%d, tail=%d\n",
+ __func__, tid->tid, tap->txa_start, tap->txa_wnd, seqno, index,
+ cindex, tid->baw_head, tid->baw_tail);
+
+ /*
+ * If this occurs then we have a big problem - something else
+ * has slid tap->txa_start along without updating the BAW
+ * tracking start/end pointers. Thus the TX BAW state is now
+ * completely busted.
+ *
+ * But for now, since I haven't yet fixed TDMA and buffer cloning,
+ * it's quite possible that a cloned buffer is making its way
+ * here and causing it to fire off. Disable TDMA for now.
+ */
+ if (tid->tx_buf[cindex] != bf) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: comp bf=%p, seq=%d; slot bf=%p, seqno=%d\n",
+ __func__, bf, SEQNO(bf->bf_state.bfs_seqno),
+ tid->tx_buf[cindex],
+ (tid->tx_buf[cindex] != NULL) ?
+ SEQNO(tid->tx_buf[cindex]->bf_state.bfs_seqno) : -1);
+ }
+
+ tid->tx_buf[cindex] = NULL;
+
+ while (tid->baw_head != tid->baw_tail &&
+ !tid->tx_buf[tid->baw_head]) {
+ INCR(tap->txa_start, IEEE80211_SEQ_RANGE);
+ INCR(tid->baw_head, ATH_TID_MAX_BUFS);
+ }
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: baw is now %d:%d, baw head=%d\n",
+ __func__, tap->txa_start, tap->txa_wnd, tid->baw_head);
+}
+
+static void
+ath_tx_leak_count_update(struct ath_softc *sc, struct ath_tid *tid,
+ struct ath_buf *bf)
+{
+ struct ieee80211_frame *wh;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (tid->an->an_leak_count > 0) {
+ wh = mtod(bf->bf_m, struct ieee80211_frame *);
+
+ /*
+ * Update MORE based on the software/net80211 queue states.
+ */
+ if ((tid->an->an_stack_psq > 0)
+ || (tid->an->an_swq_depth > 0))
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ else
+ wh->i_fc[1] &= ~IEEE80211_FC1_MORE_DATA;
+
+ DPRINTF(sc, ATH_DEBUG_NODE_PWRSAVE,
+ "%s: %6D: leak count = %d, psq=%d, swq=%d, MORE=%d\n",
+ __func__,
+ tid->an->an_node.ni_macaddr,
+ ":",
+ tid->an->an_leak_count,
+ tid->an->an_stack_psq,
+ tid->an->an_swq_depth,
+ !! (wh->i_fc[1] & IEEE80211_FC1_MORE_DATA));
+
+ /*
+ * Re-sync the underlying buffer.
+ */
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ tid->an->an_leak_count --;
+ }
+}
+
+static int
+ath_tx_tid_can_tx_or_sched(struct ath_softc *sc, struct ath_tid *tid)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (tid->an->an_leak_count > 0) {
+ return (1);
+ }
+ if (tid->paused)
+ return (0);
+ return (1);
+}
+
+/*
+ * Mark the current node/TID as ready to TX.
+ *
+ * This is done to make it easy for the software scheduler to
+ * find which nodes have data to send.
+ *
+ * The TXQ lock must be held.
+ */
+void
+ath_tx_tid_sched(struct ath_softc *sc, struct ath_tid *tid)
+{
+ struct ath_txq *txq = sc->sc_ac2q[tid->ac];
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * If we are leaking out a frame to this destination
+ * for PS-POLL, ensure that we allow scheduling to
+ * occur.
+ */
+ if (! ath_tx_tid_can_tx_or_sched(sc, tid))
+ return; /* paused, can't schedule yet */
+
+ if (tid->sched)
+ return; /* already scheduled */
+
+ tid->sched = 1;
+
+#if 0
+ /*
+ * If this is a sleeping node we're leaking to, given
+ * it a higher priority. This is so bad for QoS it hurts.
+ */
+ if (tid->an->an_leak_count) {
+ TAILQ_INSERT_HEAD(&txq->axq_tidq, tid, axq_qelem);
+ } else {
+ TAILQ_INSERT_TAIL(&txq->axq_tidq, tid, axq_qelem);
+ }
+#endif
+
+ /*
+ * We can't do the above - it'll confuse the TXQ software
+ * scheduler which will keep checking the _head_ TID
+ * in the list to see if it has traffic. If we queue
+ * a TID to the head of the list and it doesn't transmit,
+ * we'll check it again.
+ *
+ * So, get the rest of this leaking frames support working
+ * and reliable first and _then_ optimise it so they're
+ * pushed out in front of any other pending software
+ * queued nodes.
+ */
+ TAILQ_INSERT_TAIL(&txq->axq_tidq, tid, axq_qelem);
+}
+
+/*
+ * Mark the current node as no longer needing to be polled for
+ * TX packets.
+ *
+ * The TXQ lock must be held.
+ */
+static void
+ath_tx_tid_unsched(struct ath_softc *sc, struct ath_tid *tid)
+{
+ struct ath_txq *txq = sc->sc_ac2q[tid->ac];
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (tid->sched == 0)
+ return;
+
+ tid->sched = 0;
+ TAILQ_REMOVE(&txq->axq_tidq, tid, axq_qelem);
+}
+
+/*
+ * Assign a sequence number manually to the given frame.
+ *
+ * This should only be called for A-MPDU TX frames.
+ */
+static ieee80211_seq
+ath_tx_tid_seqno_assign(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_buf *bf, struct mbuf *m0)
+{
+ struct ieee80211_frame *wh;
+ int tid, pri;
+ ieee80211_seq seqno;
+ uint8_t subtype;
+
+ /* TID lookup */
+ 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: pri=%d, tid=%d, qos has seq=%d\n",
+ __func__, pri, tid, IEEE80211_QOS_HAS_SEQ(wh));
+
+ /* XXX Is it a control frame? Ignore */
+
+ /* Does the packet require a sequence number? */
+ if (! IEEE80211_QOS_HAS_SEQ(wh))
+ return -1;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * Is it a QOS NULL Data frame? Give it a sequence number from
+ * the default TID (IEEE80211_NONQOS_TID.)
+ *
+ * The RX path of everything I've looked at doesn't include the NULL
+ * data frame sequence number in the aggregation state updates, so
+ * assigning it a sequence number there will cause a BAW hole on the
+ * RX side.
+ */
+ 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 {
+ /* Manually assign sequence number */
+ seqno = ni->ni_txseqs[tid];
+ INCR(ni->ni_txseqs[tid], IEEE80211_SEQ_RANGE);
+ }
+ *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
+ M_SEQNO_SET(m0, seqno);
+
+ /* Return so caller can do something with it if needed */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: -> seqno=%d\n", __func__, seqno);
+ return seqno;
+}
+
+/*
+ * Attempt to direct dispatch an aggregate frame to hardware.
+ * If the frame is out of BAW, queue.
+ * Otherwise, schedule it as a single frame.
+ */
+static void
+ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an,
+ struct ath_txq *txq, struct ath_buf *bf)
+{
+ struct ath_tid *tid = &an->an_tid[bf->bf_state.bfs_tid];
+ struct ieee80211_tx_ampdu *tap;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+
+ /* paused? queue */
+ if (! ath_tx_tid_can_tx_or_sched(sc, tid)) {
+ ATH_TID_INSERT_HEAD(tid, bf, bf_list);
+ /* XXX don't sched - we're paused! */
+ return;
+ }
+
+ /* outside baw? queue */
+ if (bf->bf_state.bfs_dobaw &&
+ (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
+ SEQNO(bf->bf_state.bfs_seqno)))) {
+ ATH_TID_INSERT_HEAD(tid, bf, bf_list);
+ ath_tx_tid_sched(sc, tid);
+ return;
+ }
+
+ /*
+ * This is a temporary check and should be removed once
+ * all the relevant code paths have been fixed.
+ *
+ * During aggregate retries, it's possible that the head
+ * frame will fail (which has the bfs_aggr and bfs_nframes
+ * fields set for said aggregate) and will be retried as
+ * a single frame. In this instance, the values should
+ * be reset or the completion code will get upset with you.
+ */
+ if (bf->bf_state.bfs_aggr != 0 || bf->bf_state.bfs_nframes > 1) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: bfs_aggr=%d, bfs_nframes=%d\n", __func__,
+ bf->bf_state.bfs_aggr, bf->bf_state.bfs_nframes);
+ bf->bf_state.bfs_aggr = 0;
+ bf->bf_state.bfs_nframes = 1;
+ }
+
+ /* Update CLRDMASK just before this frame is queued */
+ ath_tx_update_clrdmask(sc, tid, bf);
+
+ /* Direct dispatch to hardware */
+ ath_tx_do_ratelookup(sc, bf);
+ ath_tx_calc_duration(sc, bf);
+ ath_tx_calc_protection(sc, bf);
+ ath_tx_set_rtscts(sc, bf);
+ ath_tx_rate_fill_rcflags(sc, bf);
+ ath_tx_setds(sc, bf);
+
+ /* Statistics */
+ sc->sc_aggr_stats.aggr_low_hwq_single_pkt++;
+
+ /* Track per-TID hardware queue depth correctly */
+ tid->hwq_depth++;
+
+ /* Add to BAW */
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_addto_baw(sc, an, tid, bf);
+ bf->bf_state.bfs_addedbaw = 1;
+ }
+
+ /* Set completion handler, multi-frame aggregate or not */
+ bf->bf_comp = ath_tx_aggr_comp;
+
+ /*
+ * Update the current leak count if
+ * we're leaking frames; and set the
+ * MORE flag as appropriate.
+ */
+ ath_tx_leak_count_update(sc, tid, bf);
+
+ /* Hand off to hardware */
+ ath_tx_handoff(sc, txq, bf);
+}
+
+/*
+ * Attempt to send the packet.
+ * If the queue isn't busy, direct-dispatch.
+ * If the queue is busy enough, queue the given packet on the
+ * relevant software queue.
+ */
+void
+ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_txq *txq, int queue_to_head, struct ath_buf *bf)
+{
+ struct ath_node *an = ATH_NODE(ni);
+ struct ieee80211_frame *wh;
+ struct ath_tid *atid;
+ int pri, tid;
+ struct mbuf *m0 = bf->bf_m;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /* 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\n",
+ __func__, bf, pri, tid, IEEE80211_QOS_HAS_SEQ(wh));
+
+ /* Set local packet state, used to queue packets to hardware */
+ /* XXX potentially duplicate info, re-check */
+ bf->bf_state.bfs_tid = tid;
+ bf->bf_state.bfs_tx_queue = txq->axq_qnum;
+ bf->bf_state.bfs_pri = pri;
+
+ /*
+ * If the hardware queue isn't busy, queue it directly.
+ * If the hardware queue is busy, queue it.
+ * If the TID is paused or the traffic it outside BAW, software
+ * queue it.
+ *
+ * If the node is in power-save and we're leaking a frame,
+ * leak a single frame.
+ */
+ if (! ath_tx_tid_can_tx_or_sched(sc, atid)) {
+ /* TID is paused, queue */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: paused\n", __func__);
+ /*
+ * If the caller requested that it be sent at a high
+ * priority, queue it at the head of the list.
+ */
+ if (queue_to_head)
+ ATH_TID_INSERT_HEAD(atid, bf, bf_list);
+ else
+ ATH_TID_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: pending\n", __func__);
+ ATH_TID_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_TID_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?
+ *
+ * When running A-MPDU, always just check the hardware
+ * queue depth against the aggregate frame limit.
+ * We don't want to burst a large number of single frames
+ * out to the hardware; we want to aggressively hold back.
+ *
+ * Otherwise, schedule the TID.
+ */
+ /* XXX TXQ locking */
+ if (txq->axq_depth + txq->fifo.axq_depth < sc->sc_hwq_limit_aggr) {
+ bf = ATH_TID_FIRST(atid);
+ ATH_TID_REMOVE(atid, bf, bf_list);
+
+ /*
+ * Ensure it's definitely treated as a non-AMPDU
+ * frame - this information may have been left
+ * over from a previous attempt.
+ */
+ bf->bf_state.bfs_aggr = 0;
+ bf->bf_state.bfs_nframes = 1;
+
+ /* Queue to the hardware */
+ ath_tx_xmit_aggr(sc, an, txq, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: xmit_aggr\n",
+ __func__);
+ } else {
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: ampdu; swq'ing\n",
+ __func__);
+
+ ath_tx_tid_sched(sc, atid);
+ }
+ /*
+ * If we're not doing A-MPDU, be prepared to direct dispatch
+ * up to both limits if possible. This particular corner
+ * case may end up with packet starvation between aggregate
+ * traffic and non-aggregate traffic: we wnat to ensure
+ * that non-aggregate stations get a few frames queued to the
+ * hardware before the aggregate station(s) get their chance.
+ *
+ * So if you only ever see a couple of frames direct dispatched
+ * to the hardware from a non-AMPDU client, check both here
+ * and in the software queue dispatcher to ensure that those
+ * non-AMPDU stations get a fair chance to transmit.
+ */
+ /* XXX TXQ locking */
+ } else if ((txq->axq_depth + txq->fifo.axq_depth < sc->sc_hwq_limit_nonaggr) &&
+ (txq->axq_aggr_depth < sc->sc_hwq_limit_aggr)) {
+ /* AMPDU not running, attempt direct dispatch */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: xmit_normal\n", __func__);
+ /* See if clrdmask needs to be set */
+ ath_tx_update_clrdmask(sc, atid, bf);
+
+ /*
+ * Update the current leak count if
+ * we're leaking frames; and set the
+ * MORE flag as appropriate.
+ */
+ ath_tx_leak_count_update(sc, atid, bf);
+
+ /*
+ * Dispatch the frame.
+ */
+ ath_tx_xmit_normal(sc, txq, bf);
+ } else {
+ /* Busy; queue */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: swq'ing\n", __func__);
+ ATH_TID_INSERT_TAIL(atid, bf, bf_list);
+ ath_tx_tid_sched(sc, atid);
+ }
+}
+
+/*
+ * Only set the clrdmask bit if none of the nodes are currently
+ * filtered.
+ *
+ * XXX TODO: go through all the callers and check to see
+ * which are being called in the context of looping over all
+ * TIDs (eg, if all tids are being paused, resumed, etc.)
+ * That'll avoid O(n^2) complexity here.
+ */
+static void
+ath_tx_set_clrdmask(struct ath_softc *sc, struct ath_node *an)
+{
+ int i;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ for (i = 0; i < IEEE80211_TID_SIZE; i++) {
+ if (an->an_tid[i].isfiltered == 1)
+ return;
+ }
+ an->clrdmask = 1;
+}
+
+/*
+ * Configure the per-TID node state.
+ *
+ * This likely belongs in if_ath_node.c but I can't think of anywhere
+ * else to put it just yet.
+ *
+ * This sets up the SLISTs and the mutex as appropriate.
+ */
+void
+ath_tx_tid_init(struct ath_softc *sc, struct ath_node *an)
+{
+ int i, j;
+ struct ath_tid *atid;
+
+ for (i = 0; i < IEEE80211_TID_SIZE; i++) {
+ atid = &an->an_tid[i];
+
+ /* XXX now with this bzer(), is the field 0'ing needed? */
+ bzero(atid, sizeof(*atid));
+
+ TAILQ_INIT(&atid->tid_q);
+ TAILQ_INIT(&atid->filtq.tid_q);
+ atid->tid = i;
+ atid->an = an;
+ for (j = 0; j < ATH_TID_MAX_BUFS; j++)
+ atid->tx_buf[j] = NULL;
+ atid->baw_head = atid->baw_tail = 0;
+ atid->paused = 0;
+ atid->sched = 0;
+ atid->hwq_depth = 0;
+ atid->cleanup_inprogress = 0;
+ if (i == IEEE80211_NONQOS_TID)
+ atid->ac = ATH_NONQOS_TID_AC;
+ else
+ atid->ac = TID_TO_WME_AC(i);
+ }
+ an->clrdmask = 1; /* Always start by setting this bit */
+}
+
+/*
+ * Pause the current TID. This stops packets from being transmitted
+ * on it.
+ *
+ * Since this is also called from upper layers as well as the driver,
+ * it will get the TID lock.
+ */
+static void
+ath_tx_tid_pause(struct ath_softc *sc, struct ath_tid *tid)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+ tid->paused++;
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: paused = %d\n",
+ __func__, tid->paused);
+}
+
+/*
+ * Unpause the current TID, and schedule it if needed.
+ */
+static void
+ath_tx_tid_resume(struct ath_softc *sc, struct ath_tid *tid)
+{
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * There's some odd places where ath_tx_tid_resume() is called
+ * when it shouldn't be; this works around that particular issue
+ * until it's actually resolved.
+ */
+ if (tid->paused == 0) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: %6D: paused=0?\n", __func__,
+ tid->an->an_node.ni_macaddr, ":");
+ } else {
+ tid->paused--;
+ }
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: unpaused = %d\n",
+ __func__, tid->paused);
+
+ if (tid->paused)
+ return;
+
+ /*
+ * Override the clrdmask configuration for the next frame
+ * from this TID, just to get the ball rolling.
+ */
+ ath_tx_set_clrdmask(sc, tid->an);
+
+ if (tid->axq_depth == 0)
+ return;
+
+ /* XXX isfiltered shouldn't ever be 0 at this point */
+ if (tid->isfiltered == 1) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: filtered?!\n",
+ __func__);
+ return;
+ }
+
+ ath_tx_tid_sched(sc, tid);
+
+ /*
+ * Queue the software TX scheduler.
+ */
+ ath_tx_swq_kick(sc);
+}
+
+/*
+ * Add the given ath_buf to the TID filtered frame list.
+ * This requires the TID be filtered.
+ */
+static void
+ath_tx_tid_filt_addbuf(struct ath_softc *sc, struct ath_tid *tid,
+ struct ath_buf *bf)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (!tid->isfiltered)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: not filtered?!\n",
+ __func__);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: bf=%p\n", __func__, bf);
+
+ /* Set the retry bit and bump the retry counter */
+ ath_tx_set_retry(sc, bf);
+ sc->sc_stats.ast_tx_swfiltered++;
+
+ ATH_TID_FILT_INSERT_TAIL(tid, bf, bf_list);
+}
+
+/*
+ * Handle a completed filtered frame from the given TID.
+ * This just enables/pauses the filtered frame state if required
+ * and appends the filtered frame to the filtered queue.
+ */
+static void
+ath_tx_tid_filt_comp_buf(struct ath_softc *sc, struct ath_tid *tid,
+ struct ath_buf *bf)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (! tid->isfiltered) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: filter transition\n",
+ __func__);
+ tid->isfiltered = 1;
+ ath_tx_tid_pause(sc, tid);
+ }
+
+ /* Add the frame to the filter queue */
+ ath_tx_tid_filt_addbuf(sc, tid, bf);
+}
+
+/*
+ * Complete the filtered frame TX completion.
+ *
+ * If there are no more frames in the hardware queue, unpause/unfilter
+ * the TID if applicable. Otherwise we will wait for a node PS transition
+ * to unfilter.
+ */
+static void
+ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
+{
+ struct ath_buf *bf;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (tid->hwq_depth != 0)
+ return;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: hwq=0, transition back\n",
+ __func__);
+ tid->isfiltered = 0;
+ /* XXX ath_tx_tid_resume() also calls ath_tx_set_clrdmask()! */
+ ath_tx_set_clrdmask(sc, tid->an);
+
+ /* XXX this is really quite inefficient */
+ while ((bf = ATH_TID_FILT_LAST(tid, ath_bufhead_s)) != NULL) {
+ ATH_TID_FILT_REMOVE(tid, bf, bf_list);
+ ATH_TID_INSERT_HEAD(tid, bf, bf_list);
+ }
+
+ ath_tx_tid_resume(sc, tid);
+}
+
+/*
+ * Called when a single (aggregate or otherwise) frame is completed.
+ *
+ * Returns 1 if the buffer could be added to the filtered list
+ * (cloned or otherwise), 0 if the buffer couldn't be added to the
+ * filtered list (failed clone; expired retry) and the caller should
+ * free it and handle it like a failure (eg by sending a BAR.)
+ */
+static int
+ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
+ struct ath_buf *bf)
+{
+ struct ath_buf *nbf;
+ int retval;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * Don't allow a filtered frame to live forever.
+ */
+ if (bf->bf_state.bfs_retries > SWMAX_RETRIES) {
+ sc->sc_stats.ast_tx_swretrymax++;
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
+ "%s: bf=%p, seqno=%d, exceeded retries\n",
+ __func__,
+ bf,
+ bf->bf_state.bfs_seqno);
+ return (0);
+ }
+
+ /*
+ * A busy buffer can't be added to the retry list.
+ * It needs to be cloned.
+ */
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ nbf = ath_tx_retry_clone(sc, tid->an, tid, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
+ "%s: busy buffer clone: %p -> %p\n",
+ __func__, bf, nbf);
+ } else {
+ nbf = bf;
+ }
+
+ if (nbf == NULL) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
+ "%s: busy buffer couldn't be cloned (%p)!\n",
+ __func__, bf);
+ retval = 1;
+ } else {
+ ath_tx_tid_filt_comp_buf(sc, tid, nbf);
+ retval = 0;
+ }
+ ath_tx_tid_filt_comp_complete(sc, tid);
+
+ return (retval);
+}
+
+static void
+ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
+ struct ath_buf *bf_first, ath_bufhead *bf_q)
+{
+ struct ath_buf *bf, *bf_next, *nbf;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ bf = bf_first;
+ while (bf) {
+ bf_next = bf->bf_next;
+ bf->bf_next = NULL; /* Remove it from the aggr list */
+
+ /*
+ * Don't allow a filtered frame to live forever.
+ */
+ if (bf->bf_state.bfs_retries > SWMAX_RETRIES) {
+ sc->sc_stats.ast_tx_swretrymax++;
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
+ "%s: bf=%p, seqno=%d, exceeded retries\n",
+ __func__,
+ bf,
+ bf->bf_state.bfs_seqno);
+ TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
+ goto next;
+ }
+
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ nbf = ath_tx_retry_clone(sc, tid->an, tid, bf);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
+ "%s: busy buffer cloned: %p -> %p",
+ __func__, bf, nbf);
+ } else {
+ nbf = bf;
+ }
+
+ /*
+ * If the buffer couldn't be cloned, add it to bf_q;
+ * the caller will free the buffer(s) as required.
+ */
+ if (nbf == NULL) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
+ "%s: buffer couldn't be cloned! (%p)\n",
+ __func__, bf);
+ TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
+ } else {
+ ath_tx_tid_filt_comp_buf(sc, tid, nbf);
+ }
+next:
+ bf = bf_next;
+ }
+
+ ath_tx_tid_filt_comp_complete(sc, tid);
+}
+
+/*
+ * Suspend the queue because we need to TX a BAR.
+ */
+static void
+ath_tx_tid_bar_suspend(struct ath_softc *sc, struct ath_tid *tid)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: tid=%d, 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) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: bar_tx is 1?!\n", __func__);
+ }
+
+ /* If we've already been called, just be patient. */
+ if (tid->bar_wait)
+ return;
+
+ /* Wait! */
+ tid->bar_wait = 1;
+
+ /* Only one pause, no matter how many frames fail */
+ ath_tx_tid_pause(sc, tid);
+}
+
+/*
+ * We've finished with BAR handling - either we succeeded or
+ * failed. Either way, unsuspend TX.
+ */
+static void
+ath_tx_tid_bar_unsuspend(struct ath_softc *sc, struct ath_tid *tid)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, called\n",
+ __func__,
+ tid->an->an_node.ni_macaddr,
+ ":",
+ tid->tid);
+
+ if (tid->bar_tx == 0 || tid->bar_wait == 0) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, bar_tx=%d, bar_wait=%d: ?\n",
+ __func__, tid->an->an_node.ni_macaddr, ":",
+ tid->tid, tid->bar_tx, tid->bar_wait);
+ }
+
+ tid->bar_tx = tid->bar_wait = 0;
+ ath_tx_tid_resume(sc, tid);
+}
+
+/*
+ * Return whether we're ready to TX a BAR frame.
+ *
+ * Requires the TID lock be held.
+ */
+static int
+ath_tx_tid_bar_tx_ready(struct ath_softc *sc, struct ath_tid *tid)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ if (tid->bar_wait == 0 || tid->hwq_depth > 0)
+ return (0);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, bar ready\n",
+ __func__,
+ tid->an->an_node.ni_macaddr,
+ ":",
+ tid->tid);
+
+ return (1);
+}
+
+/*
+ * Check whether the current TID is ready to have a BAR
+ * TXed and if so, do the TX.
+ *
+ * Since the TID/TXQ lock can't be held during a call to
+ * ieee80211_send_bar(), we have to do the dirty thing of unlocking it,
+ * sending the BAR and locking it again.
+ *
+ * Eventually, the code to send the BAR should be broken out
+ * from this routine so the lock doesn't have to be reacquired
+ * just to be immediately dropped by the caller.
+ */
+static void
+ath_tx_tid_bar_tx(struct ath_softc *sc, struct ath_tid *tid)
+{
+ struct ieee80211_tx_ampdu *tap;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, called\n",
+ __func__,
+ tid->an->an_node.ni_macaddr,
+ ":",
+ tid->tid);
+
+ tap = ath_tx_get_tx_tid(tid->an, tid->tid);
+
+ /*
+ * This is an error condition!
+ */
+ if (tid->bar_wait == 0 || tid->bar_tx == 1) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, bar_tx=%d, bar_wait=%d: ?\n",
+ __func__, tid->an->an_node.ni_macaddr, ":",
+ tid->tid, tid->bar_tx, tid->bar_wait);
+ return;
+ }
+
+ /* Don't do anything if we still have pending frames */
+ if (tid->hwq_depth > 0) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, hwq_depth=%d, waiting\n",
+ __func__,
+ tid->an->an_node.ni_macaddr,
+ ":",
+ tid->tid,
+ tid->hwq_depth);
+ return;
+ }
+
+ /* We're now about to TX */
+ tid->bar_tx = 1;
+
+ /*
+ * Override the clrdmask configuration for the next frame,
+ * just to get the ball rolling.
+ */
+ ath_tx_set_clrdmask(sc, tid->an);
+
+ /*
+ * Calculate new BAW left edge, now that all frames have either
+ * succeeded or failed.
+ *
+ * XXX verify this is _actually_ the valid value to begin at!
+ */
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, new BAW left edge=%d\n",
+ __func__,
+ tid->an->an_node.ni_macaddr,
+ ":",
+ tid->tid,
+ tap->txa_start);
+
+ /* Try sending the BAR frame */
+ /* We can't hold the lock here! */
+
+ ATH_TX_UNLOCK(sc);
+ if (ieee80211_send_bar(&tid->an->an_node, tap, tap->txa_start) == 0) {
+ /* Success? Now we wait for notification that it's done */
+ ATH_TX_LOCK(sc);
+ return;
+ }
+
+ /* Failure? For now, warn loudly and continue */
+ ATH_TX_LOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: TID=%d, failed to TX BAR, continue!\n",
+ __func__, tid->an->an_node.ni_macaddr, ":",
+ tid->tid);
+ ath_tx_tid_bar_unsuspend(sc, tid);
+}
+
+static void
+ath_tx_tid_drain_pkt(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, ath_bufhead *bf_cq, struct ath_buf *bf)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * If the current TID is running AMPDU, update
+ * the BAW.
+ */
+ if (ath_tx_ampdu_running(sc, an, tid->tid) &&
+ bf->bf_state.bfs_dobaw) {
+ /*
+ * Only remove the frame from the BAW if it's
+ * been transmitted at least once; this means
+ * the frame was in the BAW to begin with.
+ */
+ if (bf->bf_state.bfs_retries > 0) {
+ ath_tx_update_baw(sc, an, tid, bf);
+ bf->bf_state.bfs_dobaw = 0;
+ }
+#if 0
+ /*
+ * This has become a non-fatal error now
+ */
+ if (! bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+#endif
+ }
+
+ /* Strip it out of an aggregate list if it was in one */
+ bf->bf_next = NULL;
+
+ /* Insert on the free queue to be freed by the caller */
+ TAILQ_INSERT_TAIL(bf_cq, bf, bf_list);
+}
+
+static void
+ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
+ const char *pfx, struct ath_tid *tid, struct ath_buf *bf)
+{
+ struct ieee80211_node *ni = &an->an_node;
+ struct ath_txq *txq;
+ struct ieee80211_tx_ampdu *tap;
+
+ txq = sc->sc_ac2q[tid->ac];
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: %s: %6D: bf=%p: addbaw=%d, dobaw=%d, "
+ "seqno=%d, retry=%d\n",
+ __func__,
+ pfx,
+ ni->ni_macaddr,
+ ":",
+ bf,
+ bf->bf_state.bfs_addedbaw,
+ bf->bf_state.bfs_dobaw,
+ SEQNO(bf->bf_state.bfs_seqno),
+ bf->bf_state.bfs_retries);
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: %s: %6D: bf=%p: txq[%d] axq_depth=%d, axq_aggr_depth=%d\n",
+ __func__,
+ pfx,
+ ni->ni_macaddr,
+ ":",
+ bf,
+ txq->axq_qnum,
+ txq->axq_depth,
+ txq->axq_aggr_depth);
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: %s: %6D: bf=%p: tid txq_depth=%d hwq_depth=%d, bar_wait=%d, "
+ "isfiltered=%d\n",
+ __func__,
+ pfx,
+ ni->ni_macaddr,
+ ":",
+ bf,
+ tid->axq_depth,
+ tid->hwq_depth,
+ tid->bar_wait,
+ tid->isfiltered);
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: %s: %6D: tid %d: "
+ "sched=%d, paused=%d, "
+ "incomp=%d, baw_head=%d, "
+ "baw_tail=%d txa_start=%d, ni_txseqs=%d\n",
+ __func__,
+ pfx,
+ ni->ni_macaddr,
+ ":",
+ tid->tid,
+ tid->sched, tid->paused,
+ tid->incomp, tid->baw_head,
+ tid->baw_tail, tap == NULL ? -1 : tap->txa_start,
+ ni->ni_txseqs[tid->tid]);
+
+ /* XXX Dump the frame, see what it is? */
+ if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
+ ieee80211_dump_pkt(ni->ni_ic,
+ mtod(bf->bf_m, const uint8_t *),
+ bf->bf_m->m_len, 0, -1);
+}
+
+/*
+ * Free any packets currently pending in the software TX queue.
+ *
+ * This will be called when a node is being deleted.
+ *
+ * It can also be called on an active node during an interface
+ * reset or state transition.
+ *
+ * (From Linux/reference):
+ *
+ * TODO: For frame(s) that are in the retry state, we will reuse the
+ * sequence number(s) without setting the retry bit. The
+ * alternative is to give up on these and BAR the receiver's window
+ * forward.
+ */
+static void
+ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, ath_bufhead *bf_cq)
+{
+ struct ath_buf *bf;
+ struct ieee80211_tx_ampdu *tap;
+ struct ieee80211_node *ni = &an->an_node;
+ int t;
+
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /* Walk the queue, free frames */
+ t = 0;
+ for (;;) {
+ bf = ATH_TID_FIRST(tid);
+ if (bf == NULL) {
+ break;
+ }
+
+ if (t == 0) {
+ ath_tx_tid_drain_print(sc, an, "norm", tid, bf);
+ t = 1;
+ }
+
+ ATH_TID_REMOVE(tid, bf, bf_list);
+ ath_tx_tid_drain_pkt(sc, an, tid, bf_cq, bf);
+ }
+
+ /* And now, drain the filtered frame queue */
+ t = 0;
+ for (;;) {
+ bf = ATH_TID_FILT_FIRST(tid);
+ if (bf == NULL)
+ break;
+
+ if (t == 0) {
+ ath_tx_tid_drain_print(sc, an, "filt", tid, bf);
+ t = 1;
+ }
+
+ ATH_TID_FILT_REMOVE(tid, bf, bf_list);
+ ath_tx_tid_drain_pkt(sc, an, tid, bf_cq, bf);
+ }
+
+ /*
+ * Override the clrdmask configuration for the next frame
+ * in case there is some future transmission, just to get
+ * the ball rolling.
+ *
+ * This won't hurt things if the TID is about to be freed.
+ */
+ ath_tx_set_clrdmask(sc, tid->an);
+
+ /*
+ * Now that it's completed, grab the TID lock and update
+ * the sequence number and BAW window.
+ * Because sequence numbers have been assigned to frames
+ * that haven't been sent yet, it's entirely possible
+ * we'll be called with some pending frames that have not
+ * been transmitted.
+ *
+ * The cleaner solution is to do the sequence number allocation
+ * when the packet is first transmitted - and thus the "retries"
+ * check above would be enough to update the BAW/seqno.
+ */
+
+ /* But don't do it for non-QoS TIDs */
+ if (tap) {
+#if 1
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: %6D: node %p: TID %d: sliding BAW left edge to %d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ an,
+ tid->tid,
+ tap->txa_start);
+#endif
+ ni->ni_txseqs[tid->tid] = tap->txa_start;
+ tid->baw_tail = tid->baw_head;
+ }
+}
+
+/*
+ * Reset the TID state. This must be only called once the node has
+ * had its frames flushed from this TID, to ensure that no other
+ * pause / unpause logic can kick in.
+ */
+static void
+ath_tx_tid_reset(struct ath_softc *sc, struct ath_tid *tid)
+{
+
+#if 0
+ tid->bar_wait = tid->bar_tx = tid->isfiltered = 0;
+ tid->paused = tid->sched = tid->addba_tx_pending = 0;
+ tid->incomp = tid->cleanup_inprogress = 0;
+#endif
+
+ /*
+ * If we have a bar_wait set, we need to unpause the TID
+ * here. Otherwise once cleanup has finished, the TID won't
+ * have the right paused counter.
+ *
+ * XXX I'm not going through resume here - I don't want the
+ * node to be rescheuled just yet. This however should be
+ * methodized!
+ */
+ if (tid->bar_wait) {
+ if (tid->paused > 0) {
+ tid->paused --;
+ }
+ }
+
+ /*
+ * XXX same with a currently filtered TID.
+ *
+ * Since this is being called during a flush, we assume that
+ * the filtered frame list is actually empty.
+ *
+ * XXX TODO: add in a check to ensure that the filtered queue
+ * depth is actually 0!
+ */
+ if (tid->isfiltered) {
+ if (tid->paused > 0) {
+ tid->paused --;
+ }
+ }
+
+ /*
+ * Clear BAR, filtered frames, scheduled and ADDBA pending.
+ * The TID may be going through cleanup from the last association
+ * where things in the BAW are still in the hardware queue.
+ */
+ tid->bar_wait = 0;
+ tid->bar_tx = 0;
+ tid->isfiltered = 0;
+ tid->sched = 0;
+ tid->addba_tx_pending = 0;
+
+ /*
+ * XXX TODO: it may just be enough to walk the HWQs and mark
+ * frames for that node as non-aggregate; or mark the ath_node
+ * with something that indicates that aggregation is no longer
+ * occuring. Then we can just toss the BAW complaints and
+ * do a complete hard reset of state here - no pause, no
+ * complete counter, etc.
+ */
+
+}
+
+/*
+ * Flush all software queued packets for the given node.
+ *
+ * This occurs when a completion handler frees the last buffer
+ * for a node, and the node is thus freed. This causes the node
+ * to be cleaned up, which ends up calling ath_tx_node_flush.
+ */
+void
+ath_tx_node_flush(struct ath_softc *sc, struct ath_node *an)
+{
+ int tid;
+ ath_bufhead bf_cq;
+ struct ath_buf *bf;
+
+ TAILQ_INIT(&bf_cq);
+
+ ATH_KTR(sc, ATH_KTR_NODE, 1, "ath_tx_node_flush: flush node; ni=%p",
+ &an->an_node);
+
+ ATH_TX_LOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_NODE,
+ "%s: %6D: flush; is_powersave=%d, stack_psq=%d, tim=%d, "
+ "swq_depth=%d, clrdmask=%d, leak_count=%d\n",
+ __func__,
+ an->an_node.ni_macaddr,
+ ":",
+ an->an_is_powersave,
+ an->an_stack_psq,
+ an->an_tim_set,
+ an->an_swq_depth,
+ an->clrdmask,
+ an->an_leak_count);
+
+ for (tid = 0; tid < IEEE80211_TID_SIZE; tid++) {
+ struct ath_tid *atid = &an->an_tid[tid];
+
+ /* Free packets */
+ ath_tx_tid_drain(sc, an, atid, &bf_cq);
+
+ /* Remove this tid from the list of active tids */
+ ath_tx_tid_unsched(sc, atid);
+
+ /* Reset the per-TID pause, BAR, etc state */
+ ath_tx_tid_reset(sc, atid);
+ }
+
+ /*
+ * Clear global leak count
+ */
+ an->an_leak_count = 0;
+ ATH_TX_UNLOCK(sc);
+
+ /* Handle completed frames */
+ while ((bf = TAILQ_FIRST(&bf_cq)) != NULL) {
+ TAILQ_REMOVE(&bf_cq, bf, bf_list);
+ ath_tx_default_comp(sc, bf, 0);
+ }
+}
+
+/*
+ * Drain all the software TXQs currently with traffic queued.
+ */
+void
+ath_tx_txq_drain(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_tid *tid;
+ ath_bufhead bf_cq;
+ struct ath_buf *bf;
+
+ TAILQ_INIT(&bf_cq);
+ ATH_TX_LOCK(sc);
+
+ /*
+ * Iterate over all active tids for the given txq,
+ * flushing and unsched'ing them
+ */
+ while (! TAILQ_EMPTY(&txq->axq_tidq)) {
+ tid = TAILQ_FIRST(&txq->axq_tidq);
+ ath_tx_tid_drain(sc, tid->an, tid, &bf_cq);
+ ath_tx_tid_unsched(sc, tid);
+ }
+
+ ATH_TX_UNLOCK(sc);
+
+ while ((bf = TAILQ_FIRST(&bf_cq)) != NULL) {
+ TAILQ_REMOVE(&bf_cq, bf, bf_list);
+ ath_tx_default_comp(sc, bf, 0);
+ }
+}
+
+/*
+ * Handle completion of non-aggregate session frames.
+ *
+ * This (currently) doesn't implement software retransmission of
+ * non-aggregate frames!
+ *
+ * Software retransmission of non-aggregate frames needs to obey
+ * the strict sequence number ordering, and drop any frames that
+ * will fail this.
+ *
+ * For now, filtered frames and frame transmission will cause
+ * all kinds of issues. So we don't support them.
+ *
+ * So anyone queuing frames via ath_tx_normal_xmit() or
+ * ath_tx_hw_queue_norm() must override and set CLRDMASK.
+ */
+void
+ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf, int fail)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
+
+ /* The TID state is protected behind the TXQ lock */
+ ATH_TX_LOCK(sc);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: fail=%d, hwq_depth now %d\n",
+ __func__, bf, fail, atid->hwq_depth - 1);
+
+ atid->hwq_depth--;
+
+#if 0
+ /*
+ * If the frame was filtered, stick it on the filter frame
+ * queue and complain about it. It shouldn't happen!
+ */
+ if ((ts->ts_status & HAL_TXERR_FILT) ||
+ (ts->ts_status != 0 && atid->isfiltered)) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: isfiltered=%d, ts_status=%d: huh?\n",
+ __func__,
+ atid->isfiltered,
+ ts->ts_status);
+ ath_tx_tid_filt_comp_buf(sc, atid, bf);
+ }
+#endif
+ if (atid->isfiltered)
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: filtered?!\n", __func__);
+ if (atid->hwq_depth < 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: hwq_depth < 0: %d\n",
+ __func__, atid->hwq_depth);
+
+ /*
+ * If the queue is filtered, potentially mark it as complete
+ * and reschedule it as needed.
+ *
+ * This is required as there may be a subsequent TX descriptor
+ * for this end-node that has CLRDMASK set, so it's quite possible
+ * that a filtered frame will be followed by a non-filtered
+ * (complete or otherwise) frame.
+ *
+ * XXX should we do this before we complete the frame?
+ */
+ if (atid->isfiltered)
+ ath_tx_tid_filt_comp_complete(sc, atid);
+ ATH_TX_UNLOCK(sc);
+
+ /*
+ * punt to rate control if we're not being cleaned up
+ * during a hw queue drain and the frame wanted an ACK.
+ */
+ if (fail == 0 && ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0))
+ ath_tx_update_ratectrl(sc, ni, bf->bf_state.bfs_rc,
+ ts, bf->bf_state.bfs_pktlen,
+ 1, (ts->ts_status == 0) ? 0 : 1);
+
+ ath_tx_default_comp(sc, bf, fail);
+}
+
+/*
+ * Handle cleanup of aggregate session packets that aren't
+ * an A-MPDU.
+ *
+ * There's no need to update the BAW here - the session is being
+ * torn down.
+ */
+static void
+ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: TID %d: incomp=%d\n",
+ __func__, tid, atid->incomp);
+
+ ATH_TX_LOCK(sc);
+ atid->incomp--;
+ if (atid->incomp == 0) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: TID %d: cleaned up! resume!\n",
+ __func__, tid);
+ atid->cleanup_inprogress = 0;
+ ath_tx_tid_resume(sc, atid);
+ }
+ ATH_TX_UNLOCK(sc);
+
+ ath_tx_default_comp(sc, bf, 0);
+}
+
+/*
+ * Performs transmit side cleanup when TID changes from aggregated to
+ * unaggregated.
+ *
+ * - Discard all retry frames from the s/w queue.
+ * - Fix the tx completion function for all buffers in s/w queue.
+ * - Count the number of unacked frames, and let transmit completion
+ * handle it later.
+ *
+ * The caller is responsible for pausing the TID and unpausing the
+ * TID if no cleanup was required. Otherwise the cleanup path will
+ * unpause the TID once the last hardware queued frame is completed.
+ */
+static void
+ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid,
+ ath_bufhead *bf_cq)
+{
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ieee80211_tx_ampdu *tap;
+ struct ath_buf *bf, *bf_next;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: TID %d: called\n", __func__, tid);
+
+ /*
+ * Move the filtered frames to the TX queue, before
+ * we run off and discard/process things.
+ */
+ /* XXX this is really quite inefficient */
+ while ((bf = ATH_TID_FILT_LAST(atid, ath_bufhead_s)) != NULL) {
+ ATH_TID_FILT_REMOVE(atid, bf, bf_list);
+ ATH_TID_INSERT_HEAD(atid, bf, bf_list);
+ }
+
+ /*
+ * Update the frames in the software TX queue:
+ *
+ * + Discard retry frames in the queue
+ * + Fix the completion function to be non-aggregate
+ */
+ bf = ATH_TID_FIRST(atid);
+ while (bf) {
+ if (bf->bf_state.bfs_isretried) {
+ bf_next = TAILQ_NEXT(bf, bf_list);
+ ATH_TID_REMOVE(atid, bf, bf_list);
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: wasn't added: seqno %d\n",
+ __func__,
+ SEQNO(bf->bf_state.bfs_seqno));
+ }
+ bf->bf_state.bfs_dobaw = 0;
+ /*
+ * Call the default completion handler with "fail" just
+ * so upper levels are suitably notified about this.
+ */
+ TAILQ_INSERT_TAIL(bf_cq, bf, bf_list);
+ bf = bf_next;
+ continue;
+ }
+ /* Give these the default completion handler */
+ bf->bf_comp = ath_tx_normal_comp;
+ bf = TAILQ_NEXT(bf, bf_list);
+ }
+
+ /*
+ * Calculate what hardware-queued frames exist based
+ * on the current BAW size. Ie, what frames have been
+ * added to the TX hardware queue for this TID but
+ * not yet ACKed.
+ */
+ tap = ath_tx_get_tx_tid(an, tid);
+ /* Need the lock - fiddling with BAW */
+ while (atid->baw_head != atid->baw_tail) {
+ if (atid->tx_buf[atid->baw_head]) {
+ atid->incomp++;
+ atid->cleanup_inprogress = 1;
+ atid->tx_buf[atid->baw_head] = NULL;
+ }
+ INCR(atid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(tap->txa_start, IEEE80211_SEQ_RANGE);
+ }
+
+ if (atid->cleanup_inprogress)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: TID %d: cleanup needed: %d packets\n",
+ __func__, tid, atid->incomp);
+
+ /* Owner now must free completed frames */
+}
+
+static struct ath_buf *
+ath_tx_retry_clone(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, struct ath_buf *bf)
+{
+ struct ath_buf *nbf;
+ int error;
+
+ /*
+ * Clone the buffer. This will handle the dma unmap and
+ * copy the node reference to the new buffer. If this
+ * works out, 'bf' will have no DMA mapping, no mbuf
+ * pointer and no node reference.
+ */
+ nbf = ath_buf_clone(sc, bf);
+
+#if 0
+ DPRINTF(sc, ATH_DEBUG_XMIT, "%s: ATH_BUF_BUSY; cloning\n",
+ __func__);
+#endif
+
+ if (nbf == NULL) {
+ /* Failed to clone */
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: failed to clone a busy buffer\n",
+ __func__);
+ return NULL;
+ }
+
+ /* Setup the dma for the new buffer */
+ error = ath_tx_dmasetup(sc, nbf, nbf->bf_m);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: failed to setup dma for clone\n",
+ __func__);
+ /*
+ * Put this at the head of the list, not tail;
+ * that way it doesn't interfere with the
+ * busy buffer logic (which uses the tail of
+ * the list.)
+ */
+ ATH_TXBUF_LOCK(sc);
+ ath_returnbuf_head(sc, nbf);
+ ATH_TXBUF_UNLOCK(sc);
+ return NULL;
+ }
+
+ /* Update BAW if required, before we free the original buf */
+ if (bf->bf_state.bfs_dobaw)
+ ath_tx_switch_baw_buf(sc, an, tid, bf, nbf);
+
+ /* Free original buffer; return new buffer */
+ ath_freebuf(sc, bf);
+
+ return nbf;
+}
+
+/*
+ * Handle retrying an unaggregate frame in an aggregate
+ * session.
+ *
+ * If too many retries occur, pause the TID, wait for
+ * any further retransmits (as there's no reason why
+ * non-aggregate frames in an aggregate session are
+ * transmitted in-order; they just have to be in-BAW)
+ * and then queue a BAR.
+ */
+static void
+ath_tx_aggr_retry_unaggr(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ieee80211_tx_ampdu *tap;
+
+ ATH_TX_LOCK(sc);
+
+ tap = ath_tx_get_tx_tid(an, tid);
+
+ /*
+ * If the buffer is marked as busy, we can't directly
+ * reuse it. Instead, try to clone the buffer.
+ * If the clone is successful, recycle the old buffer.
+ * If the clone is unsuccessful, set bfs_retries to max
+ * to force the next bit of code to free the buffer
+ * for us.
+ */
+ if ((bf->bf_state.bfs_retries < SWMAX_RETRIES) &&
+ (bf->bf_flags & ATH_BUF_BUSY)) {
+ struct ath_buf *nbf;
+ nbf = ath_tx_retry_clone(sc, an, atid, bf);
+ if (nbf)
+ /* bf has been freed at this point */
+ bf = nbf;
+ else
+ bf->bf_state.bfs_retries = SWMAX_RETRIES + 1;
+ }
+
+ if (bf->bf_state.bfs_retries >= SWMAX_RETRIES) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_RETRIES,
+ "%s: exceeded retries; seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ sc->sc_stats.ast_tx_swretrymax++;
+
+ /* Update BAW anyway */
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (! bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ }
+ bf->bf_state.bfs_dobaw = 0;
+
+ /* Suspend the TX queue and get ready to send the BAR */
+ ath_tx_tid_bar_suspend(sc, atid);
+
+ /* Send the BAR if there are no other frames waiting */
+ if (ath_tx_tid_bar_tx_ready(sc, atid))
+ ath_tx_tid_bar_tx(sc, atid);
+
+ ATH_TX_UNLOCK(sc);
+
+ /* Free buffer, bf is free after this call */
+ ath_tx_default_comp(sc, bf, 0);
+ return;
+ }
+
+ /*
+ * This increments the retry counter as well as
+ * sets the retry flag in the ath_buf and packet
+ * body.
+ */
+ ath_tx_set_retry(sc, bf);
+ sc->sc_stats.ast_tx_swretries++;
+
+ /*
+ * Insert this at the head of the queue, so it's
+ * retried before any current/subsequent frames.
+ */
+ ATH_TID_INSERT_HEAD(atid, bf, bf_list);
+ ath_tx_tid_sched(sc, atid);
+ /* Send the BAR if there are no other frames waiting */
+ if (ath_tx_tid_bar_tx_ready(sc, atid))
+ ath_tx_tid_bar_tx(sc, atid);
+
+ ATH_TX_UNLOCK(sc);
+}
+
+/*
+ * Common code for aggregate excessive retry/subframe retry.
+ * If retrying, queues buffers to bf_q. If not, frees the
+ * buffers.
+ *
+ * XXX should unify this with ath_tx_aggr_retry_unaggr()
+ */
+static int
+ath_tx_retry_subframe(struct ath_softc *sc, struct ath_buf *bf,
+ ath_bufhead *bf_q)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /* XXX clr11naggr should be done for all subframes */
+ ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
+ ath_hal_set11nburstduration(sc->sc_ah, bf->bf_desc, 0);
+
+ /* ath_hal_set11n_virtualmorefrag(sc->sc_ah, bf->bf_desc, 0); */
+
+ /*
+ * If the buffer is marked as busy, we can't directly
+ * reuse it. Instead, try to clone the buffer.
+ * If the clone is successful, recycle the old buffer.
+ * If the clone is unsuccessful, set bfs_retries to max
+ * to force the next bit of code to free the buffer
+ * for us.
+ */
+ if ((bf->bf_state.bfs_retries < SWMAX_RETRIES) &&
+ (bf->bf_flags & ATH_BUF_BUSY)) {
+ struct ath_buf *nbf;
+ nbf = ath_tx_retry_clone(sc, an, atid, bf);
+ if (nbf)
+ /* bf has been freed at this point */
+ bf = nbf;
+ else
+ bf->bf_state.bfs_retries = SWMAX_RETRIES + 1;
+ }
+
+ if (bf->bf_state.bfs_retries >= SWMAX_RETRIES) {
+ sc->sc_stats.ast_tx_swretrymax++;
+ DPRINTF(sc, ATH_DEBUG_SW_TX_RETRIES,
+ "%s: max retries: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ bf->bf_state.bfs_dobaw = 0;
+ return 1;
+ }
+
+ ath_tx_set_retry(sc, bf);
+ sc->sc_stats.ast_tx_swretries++;
+ bf->bf_next = NULL; /* Just to make sure */
+
+ /* Clear the aggregate state */
+ bf->bf_state.bfs_aggr = 0;
+ bf->bf_state.bfs_ndelim = 0; /* ??? needed? */
+ bf->bf_state.bfs_nframes = 1;
+
+ TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
+ return 0;
+}
+
+/*
+ * error pkt completion for an aggregate destination
+ */
+static void
+ath_tx_comp_aggr_error(struct ath_softc *sc, struct ath_buf *bf_first,
+ struct ath_tid *tid)
+{
+ struct ieee80211_node *ni = bf_first->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_buf *bf_next, *bf;
+ ath_bufhead bf_q;
+ int drops = 0;
+ struct ieee80211_tx_ampdu *tap;
+ ath_bufhead bf_cq;
+
+ TAILQ_INIT(&bf_q);
+ TAILQ_INIT(&bf_cq);
+
+ /*
+ * Update rate control - all frames have failed.
+ *
+ * XXX use the length in the first frame in the series;
+ * XXX just so things are consistent for now.
+ */
+ ath_tx_update_ratectrl(sc, ni, bf_first->bf_state.bfs_rc,
+ &bf_first->bf_status.ds_txstat,
+ bf_first->bf_state.bfs_pktlen,
+ bf_first->bf_state.bfs_nframes, bf_first->bf_state.bfs_nframes);
+
+ ATH_TX_LOCK(sc);
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+ sc->sc_stats.ast_tx_aggr_failall++;
+
+ /* Retry all subframes */
+ bf = bf_first;
+ while (bf) {
+ bf_next = bf->bf_next;
+ bf->bf_next = NULL; /* Remove it from the aggr list */
+ sc->sc_stats.ast_tx_aggr_fail++;
+ if (ath_tx_retry_subframe(sc, bf, &bf_q)) {
+ drops++;
+ bf->bf_next = NULL;
+ TAILQ_INSERT_TAIL(&bf_cq, bf, bf_list);
+ }
+ bf = bf_next;
+ }
+
+ /* Prepend all frames to the beginning of the queue */
+ while ((bf = TAILQ_LAST(&bf_q, ath_bufhead_s)) != NULL) {
+ TAILQ_REMOVE(&bf_q, bf, bf_list);
+ ATH_TID_INSERT_HEAD(tid, bf, bf_list);
+ }
+
+ /*
+ * Schedule the TID to be re-tried.
+ */
+ ath_tx_tid_sched(sc, tid);
+
+ /*
+ * send bar if we dropped any frames
+ *
+ * Keep the txq lock held for now, as we need to ensure
+ * that ni_txseqs[] is consistent (as it's being updated
+ * in the ifnet TX context or raw TX context.)
+ */
+ if (drops) {
+ /* Suspend the TX queue and get ready to send the BAR */
+ ath_tx_tid_bar_suspend(sc, tid);
+ }
+
+ /*
+ * Send BAR if required
+ */
+ if (ath_tx_tid_bar_tx_ready(sc, tid))
+ ath_tx_tid_bar_tx(sc, tid);
+
+ ATH_TX_UNLOCK(sc);
+
+ /* Complete frames which errored out */
+ while ((bf = TAILQ_FIRST(&bf_cq)) != NULL) {
+ TAILQ_REMOVE(&bf_cq, bf, bf_list);
+ ath_tx_default_comp(sc, bf, 0);
+ }
+}
+
+/*
+ * Handle clean-up of packets from an aggregate list.
+ *
+ * There's no need to update the BAW here - the session is being
+ * torn down.
+ */
+static void
+ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first)
+{
+ struct ath_buf *bf, *bf_next;
+ struct ieee80211_node *ni = bf_first->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf_first->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+
+ ATH_TX_LOCK(sc);
+
+ /* update incomp */
+ bf = bf_first;
+ while (bf) {
+ atid->incomp--;
+ bf = bf->bf_next;
+ }
+
+ if (atid->incomp == 0) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: TID %d: cleaned up! resume!\n",
+ __func__, tid);
+ atid->cleanup_inprogress = 0;
+ ath_tx_tid_resume(sc, atid);
+ }
+
+ /* Send BAR if required */
+ /* XXX why would we send a BAR when transitioning to non-aggregation? */
+ /*
+ * XXX TODO: we should likely just tear down the BAR state here,
+ * rather than sending a BAR.
+ */
+ if (ath_tx_tid_bar_tx_ready(sc, atid))
+ ath_tx_tid_bar_tx(sc, atid);
+
+ ATH_TX_UNLOCK(sc);
+
+ /* Handle frame completion */
+ bf = bf_first;
+ while (bf) {
+ bf_next = bf->bf_next;
+ ath_tx_default_comp(sc, bf, 1);
+ bf = bf_next;
+ }
+}
+
+/*
+ * Handle completion of an set of aggregate frames.
+ *
+ * Note: the completion handler is the last descriptor in the aggregate,
+ * not the last descriptor in the first frame.
+ */
+static void
+ath_tx_aggr_comp_aggr(struct ath_softc *sc, struct ath_buf *bf_first,
+ int fail)
+{
+ //struct ath_desc *ds = bf->bf_lastds;
+ struct ieee80211_node *ni = bf_first->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf_first->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ath_tx_status ts;
+ struct ieee80211_tx_ampdu *tap;
+ ath_bufhead bf_q;
+ ath_bufhead bf_cq;
+ int seq_st, tx_ok;
+ int hasba, isaggr;
+ uint32_t ba[2];
+ struct ath_buf *bf, *bf_next;
+ int ba_index;
+ int drops = 0;
+ int nframes = 0, nbad = 0, nf;
+ int pktlen;
+ /* XXX there's too much on the stack? */
+ struct ath_rc_series rc[ATH_RC_NUM];
+ int txseq;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: called; hwq_depth=%d\n",
+ __func__, atid->hwq_depth);
+
+ /*
+ * Take a copy; this may be needed -after- bf_first
+ * has been completed and freed.
+ */
+ ts = bf_first->bf_status.ds_txstat;
+
+ TAILQ_INIT(&bf_q);
+ TAILQ_INIT(&bf_cq);
+
+ /* The TID state is kept behind the TXQ lock */
+ ATH_TX_LOCK(sc);
+
+ atid->hwq_depth--;
+ if (atid->hwq_depth < 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: hwq_depth < 0: %d\n",
+ __func__, atid->hwq_depth);
+
+ /*
+ * If the TID is filtered, handle completing the filter
+ * transition before potentially kicking it to the cleanup
+ * function.
+ *
+ * XXX this is duplicate work, ew.
+ */
+ if (atid->isfiltered)
+ ath_tx_tid_filt_comp_complete(sc, atid);
+
+ /*
+ * Punt cleanup to the relevant function, not our problem now
+ */
+ if (atid->cleanup_inprogress) {
+ if (atid->isfiltered)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: isfiltered=1, normal_comp?\n",
+ __func__);
+ ATH_TX_UNLOCK(sc);
+ ath_tx_comp_cleanup_aggr(sc, bf_first);
+ return;
+ }
+
+ /*
+ * If the frame is filtered, transition to filtered frame
+ * mode and add this to the filtered frame list.
+ *
+ * XXX TODO: figure out how this interoperates with
+ * BAR, pause and cleanup states.
+ */
+ if ((ts.ts_status & HAL_TXERR_FILT) ||
+ (ts.ts_status != 0 && atid->isfiltered)) {
+ if (fail != 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: isfiltered=1, fail=%d\n", __func__, fail);
+ ath_tx_tid_filt_comp_aggr(sc, atid, bf_first, &bf_cq);
+
+ /* Remove from BAW */
+ TAILQ_FOREACH_SAFE(bf, &bf_cq, bf_list, bf_next) {
+ if (bf->bf_state.bfs_addedbaw)
+ drops++;
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: wasn't added: seqno %d\n",
+ __func__,
+ SEQNO(bf->bf_state.bfs_seqno));
+ }
+ bf->bf_state.bfs_dobaw = 0;
+ }
+ /*
+ * If any intermediate frames in the BAW were dropped when
+ * handling filtering things, send a BAR.
+ */
+ if (drops)
+ ath_tx_tid_bar_suspend(sc, atid);
+
+ /*
+ * Finish up by sending a BAR if required and freeing
+ * the frames outside of the TX lock.
+ */
+ goto finish_send_bar;
+ }
+
+ /*
+ * XXX for now, use the first frame in the aggregate for
+ * XXX rate control completion; it's at least consistent.
+ */
+ pktlen = bf_first->bf_state.bfs_pktlen;
+
+ /*
+ * 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_TX_UNLOCK(sc);
+ ath_tx_comp_aggr_error(sc, bf_first, atid);
+ return;
+ }
+
+ tap = ath_tx_get_tx_tid(an, tid);
+
+ /*
+ * extract starting sequence and block-ack bitmap
+ */
+ /* XXX endian-ness of seq_st, ba? */
+ seq_st = ts.ts_seqnum;
+ hasba = !! (ts.ts_flags & HAL_TX_BA);
+ tx_ok = (ts.ts_status == 0);
+ isaggr = bf_first->bf_state.bfs_aggr;
+ ba[0] = ts.ts_ba_low;
+ ba[1] = ts.ts_ba_high;
+
+ /*
+ * Copy the TX completion status and the rate control
+ * series from the first descriptor, as it may be freed
+ * before the rate control code can get its grubby fingers
+ * into things.
+ */
+ memcpy(rc, bf_first->bf_state.bfs_rc, sizeof(rc));
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: txa_start=%d, tx_ok=%d, status=%.8x, flags=%.8x, "
+ "isaggr=%d, seq_st=%d, hasba=%d, ba=%.8x, %.8x\n",
+ __func__, tap->txa_start, tx_ok, ts.ts_status, ts.ts_flags,
+ isaggr, seq_st, hasba, ba[0], ba[1]);
+
+ /*
+ * The reference driver doesn't do this; it simply ignores
+ * this check in its entirety.
+ *
+ * I've seen this occur when using iperf to send traffic
+ * out tid 1 - the aggregate frames are all marked as TID 1,
+ * but the TXSTATUS has TID=0. So, let's just ignore this
+ * check.
+ */
+#if 0
+ /* Occasionally, the MAC sends a tx status for the wrong TID. */
+ if (tid != ts.ts_tid) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: tid %d != hw tid %d\n",
+ __func__, tid, ts.ts_tid);
+ tx_ok = 0;
+ }
+#endif
+
+ /* AR5416 BA bug; this requires an interface reset */
+ if (isaggr && tx_ok && (! hasba)) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: AR5416 bug: hasba=%d; txok=%d, isaggr=%d, "
+ "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
+ }
+
+ /*
+ * Walk the list of frames, figure out which ones were correctly
+ * sent and which weren't.
+ */
+ bf = bf_first;
+ nf = bf_first->bf_state.bfs_nframes;
+
+ /* bf_first is going to be invalid once this list is walked */
+ bf_first = NULL;
+
+ /*
+ * Walk the list of completed frames and determine
+ * which need to be completed and which need to be
+ * retransmitted.
+ *
+ * For completed frames, the completion functions need
+ * to be called at the end of this function as the last
+ * node reference may free the node.
+ *
+ * Finally, since the TXQ lock can't be held during the
+ * completion callback (to avoid lock recursion),
+ * the completion calls have to be done outside of the
+ * lock.
+ */
+ while (bf) {
+ nframes++;
+ ba_index = ATH_BA_INDEX(seq_st,
+ SEQNO(bf->bf_state.bfs_seqno));
+ bf_next = bf->bf_next;
+ bf->bf_next = NULL; /* Remove it from the aggr list */
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: checking bf=%p seqno=%d; ack=%d\n",
+ __func__, bf, SEQNO(bf->bf_state.bfs_seqno),
+ ATH_BA_ISSET(ba, ba_index));
+
+ if (tx_ok && ATH_BA_ISSET(ba, ba_index)) {
+ sc->sc_stats.ast_tx_aggr_ok++;
+ ath_tx_update_baw(sc, an, atid, bf);
+ bf->bf_state.bfs_dobaw = 0;
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ bf->bf_next = NULL;
+ TAILQ_INSERT_TAIL(&bf_cq, bf, bf_list);
+ } else {
+ sc->sc_stats.ast_tx_aggr_fail++;
+ if (ath_tx_retry_subframe(sc, bf, &bf_q)) {
+ drops++;
+ bf->bf_next = NULL;
+ TAILQ_INSERT_TAIL(&bf_cq, bf, bf_list);
+ }
+ nbad++;
+ }
+ bf = bf_next;
+ }
+
+ /*
+ * Now that the BAW updates have been done, unlock
+ *
+ * txseq is grabbed before the lock is released so we
+ * have a consistent view of what -was- in the BAW.
+ * Anything after this point will not yet have been
+ * TXed.
+ */
+ txseq = tap->txa_start;
+ ATH_TX_UNLOCK(sc);
+
+ if (nframes != nf)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: num frames seen=%d; bf nframes=%d\n",
+ __func__, nframes, nf);
+
+ /*
+ * Now we know how many frames were bad, call the rate
+ * control code.
+ */
+ if (fail == 0)
+ ath_tx_update_ratectrl(sc, ni, rc, &ts, pktlen, nframes,
+ nbad);
+
+ /*
+ * send bar if we dropped any frames
+ */
+ if (drops) {
+ /* Suspend the TX queue and get ready to send the BAR */
+ ATH_TX_LOCK(sc);
+ ath_tx_tid_bar_suspend(sc, atid);
+ ATH_TX_UNLOCK(sc);
+ }
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: txa_start now %d\n", __func__, tap->txa_start);
+
+ ATH_TX_LOCK(sc);
+
+ /* Prepend all frames to the beginning of the queue */
+ while ((bf = TAILQ_LAST(&bf_q, ath_bufhead_s)) != NULL) {
+ TAILQ_REMOVE(&bf_q, bf, bf_list);
+ ATH_TID_INSERT_HEAD(atid, bf, bf_list);
+ }
+
+ /*
+ * Reschedule to grab some further frames.
+ */
+ ath_tx_tid_sched(sc, atid);
+
+ /*
+ * If the queue is filtered, re-schedule as required.
+ *
+ * This is required as there may be a subsequent TX descriptor
+ * for this end-node that has CLRDMASK set, so it's quite possible
+ * that a filtered frame will be followed by a non-filtered
+ * (complete or otherwise) frame.
+ *
+ * XXX should we do this before we complete the frame?
+ */
+ if (atid->isfiltered)
+ ath_tx_tid_filt_comp_complete(sc, atid);
+
+finish_send_bar:
+
+ /*
+ * Send BAR if required
+ */
+ if (ath_tx_tid_bar_tx_ready(sc, atid))
+ ath_tx_tid_bar_tx(sc, atid);
+
+ ATH_TX_UNLOCK(sc);
+
+ /* Do deferred completion */
+ while ((bf = TAILQ_FIRST(&bf_cq)) != NULL) {
+ TAILQ_REMOVE(&bf_cq, bf, bf_list);
+ ath_tx_default_comp(sc, bf, 0);
+ }
+}
+
+/*
+ * Handle completion of unaggregated frames in an ADDBA
+ * session.
+ *
+ * Fail is set to 1 if the entry is being freed via a call to
+ * ath_tx_draintxq().
+ */
+static void
+ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ath_tx_status ts;
+ int drops = 0;
+
+ /*
+ * Take a copy of this; filtering/cloning the frame may free the
+ * bf pointer.
+ */
+ ts = bf->bf_status.ds_txstat;
+
+ /*
+ * Update rate control status here, before we possibly
+ * punt to retry or cleanup.
+ *
+ * Do it outside of the TXQ lock.
+ */
+ if (fail == 0 && ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0))
+ ath_tx_update_ratectrl(sc, ni, bf->bf_state.bfs_rc,
+ &bf->bf_status.ds_txstat,
+ bf->bf_state.bfs_pktlen,
+ 1, (ts.ts_status == 0) ? 0 : 1);
+
+ /*
+ * This is called early so atid->hwq_depth can be tracked.
+ * This unfortunately means that it's released and regrabbed
+ * during retry and cleanup. That's rather inefficient.
+ */
+ ATH_TX_LOCK(sc);
+
+ if (tid == IEEE80211_NONQOS_TID)
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: TID=16!\n", __func__);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: bf=%p: tid=%d, hwq_depth=%d, seqno=%d\n",
+ __func__, bf, bf->bf_state.bfs_tid, atid->hwq_depth,
+ SEQNO(bf->bf_state.bfs_seqno));
+
+ atid->hwq_depth--;
+ if (atid->hwq_depth < 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: hwq_depth < 0: %d\n",
+ __func__, atid->hwq_depth);
+
+ /*
+ * If the TID is filtered, handle completing the filter
+ * transition before potentially kicking it to the cleanup
+ * function.
+ */
+ if (atid->isfiltered)
+ ath_tx_tid_filt_comp_complete(sc, atid);
+
+ /*
+ * If a cleanup is in progress, punt to comp_cleanup;
+ * rather than handling it here. It's thus their
+ * responsibility to clean up, call the completion
+ * function in net80211, etc.
+ */
+ if (atid->cleanup_inprogress) {
+ if (atid->isfiltered)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: isfiltered=1, normal_comp?\n",
+ __func__);
+ ATH_TX_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: cleanup_unaggr\n",
+ __func__);
+ ath_tx_comp_cleanup_unaggr(sc, bf);
+ return;
+ }
+
+ /*
+ * XXX TODO: how does cleanup, BAR and filtered frame handling
+ * overlap?
+ *
+ * If the frame is filtered OR if it's any failure but
+ * the TID is filtered, the frame must be added to the
+ * filtered frame list.
+ *
+ * However - a busy buffer can't be added to the filtered
+ * list as it will end up being recycled without having
+ * been made available for the hardware.
+ */
+ if ((ts.ts_status & HAL_TXERR_FILT) ||
+ (ts.ts_status != 0 && atid->isfiltered)) {
+ int freeframe;
+
+ if (fail != 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: isfiltered=1, fail=%d\n",
+ __func__, fail);
+ freeframe = ath_tx_tid_filt_comp_single(sc, atid, bf);
+ if (freeframe) {
+ /* Remove from BAW */
+ if (bf->bf_state.bfs_addedbaw)
+ drops++;
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ }
+ bf->bf_state.bfs_dobaw = 0;
+ }
+
+ /*
+ * If the frame couldn't be filtered, treat it as a drop and
+ * prepare to send a BAR.
+ */
+ if (freeframe && drops)
+ ath_tx_tid_bar_suspend(sc, atid);
+
+ /*
+ * Send BAR if required
+ */
+ if (ath_tx_tid_bar_tx_ready(sc, atid))
+ ath_tx_tid_bar_tx(sc, atid);
+
+ ATH_TX_UNLOCK(sc);
+ /*
+ * If freeframe is set, then the frame couldn't be
+ * cloned and bf is still valid. Just complete/free it.
+ */
+ if (freeframe)
+ ath_tx_default_comp(sc, bf, fail);
+
+
+ return;
+ }
+ /*
+ * 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_TX_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: retry_unaggr\n",
+ __func__);
+ ath_tx_aggr_retry_unaggr(sc, bf);
+ return;
+ }
+
+ /* Success? Complete */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: TID=%d, seqno %d\n",
+ __func__, tid, SEQNO(bf->bf_state.bfs_seqno));
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ bf->bf_state.bfs_dobaw = 0;
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ }
+
+ /*
+ * If the queue is filtered, re-schedule as required.
+ *
+ * This is required as there may be a subsequent TX descriptor
+ * for this end-node that has CLRDMASK set, so it's quite possible
+ * that a filtered frame will be followed by a non-filtered
+ * (complete or otherwise) frame.
+ *
+ * XXX should we do this before we complete the frame?
+ */
+ if (atid->isfiltered)
+ ath_tx_tid_filt_comp_complete(sc, atid);
+
+ /*
+ * Send BAR if required
+ */
+ if (ath_tx_tid_bar_tx_ready(sc, atid))
+ ath_tx_tid_bar_tx(sc, atid);
+
+ ATH_TX_UNLOCK(sc);
+
+ ath_tx_default_comp(sc, bf, fail);
+ /* bf is freed at this point */
+}
+
+void
+ath_tx_aggr_comp(struct ath_softc *sc, struct ath_buf *bf, int fail)
+{
+ if (bf->bf_state.bfs_aggr)
+ ath_tx_aggr_comp_aggr(sc, bf, fail);
+ else
+ ath_tx_aggr_comp_unaggr(sc, bf, fail);
+}
+
+/*
+ * Schedule some packets from the given node/TID to the hardware.
+ *
+ * This is the aggregate version.
+ */
+void
+ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid)
+{
+ struct ath_buf *bf;
+ struct ath_txq *txq = sc->sc_ac2q[tid->ac];
+ struct ieee80211_tx_ampdu *tap;
+ ATH_AGGR_STATUS status;
+ ath_bufhead bf_q;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d\n", __func__, tid->tid);
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * XXX TODO: If we're called for a queue that we're leaking frames to,
+ * ensure we only leak one.
+ */
+
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+
+ if (tid->tid == IEEE80211_NONQOS_TID)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: called for TID=NONQOS_TID?\n", __func__);
+
+ for (;;) {
+ status = ATH_AGGR_DONE;
+
+ /*
+ * If the upper layer has paused the TID, don't
+ * queue any further packets.
+ *
+ * This can also occur from the completion task because
+ * of packet loss; but as its serialised with this code,
+ * it won't "appear" half way through queuing packets.
+ */
+ if (! ath_tx_tid_can_tx_or_sched(sc, tid))
+ break;
+
+ bf = ATH_TID_FIRST(tid);
+ if (bf == NULL) {
+ break;
+ }
+
+ /*
+ * If the packet doesn't fall within the BAW (eg a NULL
+ * data frame), schedule it directly; continue.
+ */
+ if (! bf->bf_state.bfs_dobaw) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: non-baw packet\n",
+ __func__);
+ ATH_TID_REMOVE(tid, bf, bf_list);
+
+ if (bf->bf_state.bfs_nframes > 1)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: aggr=%d, nframes=%d\n",
+ __func__,
+ bf->bf_state.bfs_aggr,
+ bf->bf_state.bfs_nframes);
+
+ /*
+ * This shouldn't happen - such frames shouldn't
+ * ever have been queued as an aggregate in the
+ * first place. However, make sure the fields
+ * are correctly setup just to be totally sure.
+ */
+ bf->bf_state.bfs_aggr = 0;
+ bf->bf_state.bfs_nframes = 1;
+
+ /* Update CLRDMASK just before this frame is queued */
+ ath_tx_update_clrdmask(sc, tid, bf);
+
+ ath_tx_do_ratelookup(sc, bf);
+ ath_tx_calc_duration(sc, bf);
+ ath_tx_calc_protection(sc, bf);
+ ath_tx_set_rtscts(sc, bf);
+ ath_tx_rate_fill_rcflags(sc, bf);
+ ath_tx_setds(sc, bf);
+ ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
+
+ sc->sc_aggr_stats.aggr_nonbaw_pkt++;
+
+ /* Queue the packet; continue */
+ goto queuepkt;
+ }
+
+ TAILQ_INIT(&bf_q);
+
+ /*
+ * Do a rate control lookup on the first frame in the
+ * list. The rate control code needs that to occur
+ * before it can determine whether to TX.
+ * It's inaccurate because the rate control code doesn't
+ * really "do" aggregate lookups, so it only considers
+ * the size of the first frame.
+ */
+ ath_tx_do_ratelookup(sc, bf);
+ bf->bf_state.bfs_rc[3].rix = 0;
+ bf->bf_state.bfs_rc[3].tries = 0;
+
+ ath_tx_calc_duration(sc, bf);
+ ath_tx_calc_protection(sc, bf);
+
+ ath_tx_set_rtscts(sc, bf);
+ ath_tx_rate_fill_rcflags(sc, bf);
+
+ status = ath_tx_form_aggr(sc, an, tid, &bf_q);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: ath_tx_form_aggr() status=%d\n", __func__, status);
+
+ /*
+ * No frames to be picked up - out of BAW
+ */
+ if (TAILQ_EMPTY(&bf_q))
+ break;
+
+ /*
+ * This assumes that the descriptor list in the ath_bufhead
+ * are already linked together via bf_next pointers.
+ */
+ bf = TAILQ_FIRST(&bf_q);
+
+ if (status == ATH_AGGR_8K_LIMITED)
+ sc->sc_aggr_stats.aggr_rts_aggr_limited++;
+
+ /*
+ * If it's the only frame send as non-aggregate
+ * assume that ath_tx_form_aggr() has checked
+ * whether it's in the BAW and added it appropriately.
+ */
+ if (bf->bf_state.bfs_nframes == 1) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: single-frame aggregate\n", __func__);
+
+ /* Update CLRDMASK just before this frame is queued */
+ ath_tx_update_clrdmask(sc, tid, bf);
+
+ bf->bf_state.bfs_aggr = 0;
+ bf->bf_state.bfs_ndelim = 0;
+ ath_tx_setds(sc, bf);
+ ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
+ if (status == ATH_AGGR_BAW_CLOSED)
+ sc->sc_aggr_stats.aggr_baw_closed_single_pkt++;
+ else
+ sc->sc_aggr_stats.aggr_single_pkt++;
+ } else {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: multi-frame aggregate: %d frames, "
+ "length %d\n",
+ __func__, bf->bf_state.bfs_nframes,
+ bf->bf_state.bfs_al);
+ bf->bf_state.bfs_aggr = 1;
+ sc->sc_aggr_stats.aggr_pkts[bf->bf_state.bfs_nframes]++;
+ sc->sc_aggr_stats.aggr_aggr_pkt++;
+
+ /* Update CLRDMASK just before this frame is queued */
+ ath_tx_update_clrdmask(sc, tid, bf);
+
+ /*
+ * Calculate the duration/protection as required.
+ */
+ ath_tx_calc_duration(sc, bf);
+ ath_tx_calc_protection(sc, bf);
+
+ /*
+ * Update the rate and rtscts information based on the
+ * rate decision made by the rate control code;
+ * the first frame in the aggregate needs it.
+ */
+ ath_tx_set_rtscts(sc, bf);
+
+ /*
+ * Setup the relevant descriptor fields
+ * for aggregation. The first descriptor
+ * already points to the rest in the chain.
+ */
+ ath_tx_setds_11n(sc, bf);
+
+ }
+ queuepkt:
+ /* Set completion handler, multi-frame aggregate or not */
+ bf->bf_comp = ath_tx_aggr_comp;
+
+ if (bf->bf_state.bfs_tid == IEEE80211_NONQOS_TID)
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: TID=16?\n", __func__);
+
+ /*
+ * Update leak count and frame config if were leaking frames.
+ *
+ * XXX TODO: it should update all frames in an aggregate
+ * correctly!
+ */
+ ath_tx_leak_count_update(sc, tid, bf);
+
+ /* Punt to txq */
+ ath_tx_handoff(sc, txq, bf);
+
+ /* Track outstanding buffer count to hardware */
+ /* aggregates are "one" buffer */
+ tid->hwq_depth++;
+
+ /*
+ * Break out if ath_tx_form_aggr() indicated
+ * there can't be any further progress (eg BAW is full.)
+ * Checking for an empty txq is done above.
+ *
+ * XXX locking on txq here?
+ */
+ /* XXX TXQ locking */
+ if (txq->axq_aggr_depth >= sc->sc_hwq_limit_aggr ||
+ (status == ATH_AGGR_BAW_CLOSED ||
+ status == ATH_AGGR_LEAK_CLOSED))
+ break;
+ }
+}
+
+/*
+ * Schedule some packets from the given node/TID to the hardware.
+ *
+ * XXX TODO: this routine doesn't enforce the maximum TXQ depth.
+ * It just dumps frames into the TXQ. We should limit how deep
+ * the transmit queue can grow for frames dispatched to the given
+ * TXQ.
+ *
+ * To avoid locking issues, either we need to own the TXQ lock
+ * at this point, or we need to pass in the maximum frame count
+ * from the caller.
+ */
+void
+ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid)
+{
+ struct ath_buf *bf;
+ struct ath_txq *txq = sc->sc_ac2q[tid->ac];
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: node %p: TID %d: called\n",
+ __func__, an, tid->tid);
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /* Check - is AMPDU pending or running? then print out something */
+ if (ath_tx_ampdu_pending(sc, an, tid->tid))
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d, ampdu pending?\n",
+ __func__, tid->tid);
+ if (ath_tx_ampdu_running(sc, an, tid->tid))
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d, ampdu running?\n",
+ __func__, tid->tid);
+
+ for (;;) {
+
+ /*
+ * If the upper layers have paused the TID, don't
+ * queue any further packets.
+ *
+ * XXX if we are leaking frames, make sure we decrement
+ * that counter _and_ we continue here.
+ */
+ if (! ath_tx_tid_can_tx_or_sched(sc, tid))
+ break;
+
+ bf = ATH_TID_FIRST(tid);
+ if (bf == NULL) {
+ break;
+ }
+
+ ATH_TID_REMOVE(tid, bf, bf_list);
+
+ /* Sanity check! */
+ if (tid->tid != bf->bf_state.bfs_tid) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bfs_tid %d !="
+ " tid %d\n", __func__, bf->bf_state.bfs_tid,
+ tid->tid);
+ }
+ /* Normal completion handler */
+ bf->bf_comp = ath_tx_normal_comp;
+
+ /*
+ * Override this for now, until the non-aggregate
+ * completion handler correctly handles software retransmits.
+ */
+ bf->bf_state.bfs_txflags |= HAL_TXDESC_CLRDMASK;
+
+ /* Update CLRDMASK just before this frame is queued */
+ ath_tx_update_clrdmask(sc, tid, bf);
+
+ /* Program descriptors + rate control */
+ ath_tx_do_ratelookup(sc, bf);
+ ath_tx_calc_duration(sc, bf);
+ ath_tx_calc_protection(sc, bf);
+ ath_tx_set_rtscts(sc, bf);
+ ath_tx_rate_fill_rcflags(sc, bf);
+ ath_tx_setds(sc, bf);
+
+ /*
+ * Update the current leak count if
+ * we're leaking frames; and set the
+ * MORE flag as appropriate.
+ */
+ ath_tx_leak_count_update(sc, tid, bf);
+
+ /* Track outstanding buffer count to hardware */
+ /* aggregates are "one" buffer */
+ tid->hwq_depth++;
+
+ /* Punt to hardware or software txq */
+ ath_tx_handoff(sc, txq, bf);
+ }
+}
+
+/*
+ * Schedule some packets to the given hardware queue.
+ *
+ * This function walks the list of TIDs (ie, ath_node TIDs
+ * with queued traffic) and attempts to schedule traffic
+ * from them.
+ *
+ * TID scheduling is implemented as a FIFO, with TIDs being
+ * added to the end of the queue after some frames have been
+ * scheduled.
+ */
+void
+ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_tid *tid, *next, *last;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * Don't schedule if the hardware queue is busy.
+ * This (hopefully) gives some more time to aggregate
+ * some packets in the aggregation queue.
+ *
+ * XXX It doesn't stop a parallel sender from sneaking
+ * in transmitting a frame!
+ */
+ /* XXX TXQ locking */
+ if (txq->axq_aggr_depth + txq->fifo.axq_depth >= sc->sc_hwq_limit_aggr) {
+ sc->sc_aggr_stats.aggr_sched_nopkt++;
+ return;
+ }
+ if (txq->axq_depth >= sc->sc_hwq_limit_nonaggr) {
+ sc->sc_aggr_stats.aggr_sched_nopkt++;
+ return;
+ }
+
+ last = TAILQ_LAST(&txq->axq_tidq, axq_t_s);
+
+ TAILQ_FOREACH_SAFE(tid, &txq->axq_tidq, axq_qelem, next) {
+ /*
+ * Suspend paused queues here; they'll be resumed
+ * once the addba completes or times out.
+ */
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d, paused=%d\n",
+ __func__, tid->tid, tid->paused);
+ ath_tx_tid_unsched(sc, tid);
+ /*
+ * This node may be in power-save and we're leaking
+ * a frame; be careful.
+ */
+ if (! ath_tx_tid_can_tx_or_sched(sc, tid)) {
+ continue;
+ }
+ if (ath_tx_ampdu_running(sc, tid->an, tid->tid))
+ ath_tx_tid_hw_queue_aggr(sc, tid->an, tid);
+ else
+ ath_tx_tid_hw_queue_norm(sc, tid->an, tid);
+
+ /* Not empty? Re-schedule */
+ if (tid->axq_depth != 0)
+ ath_tx_tid_sched(sc, tid);
+
+ /*
+ * Give the software queue time to aggregate more
+ * packets. If we aren't running aggregation then
+ * we should still limit the hardware queue depth.
+ */
+ /* XXX TXQ locking */
+ if (txq->axq_aggr_depth + txq->fifo.axq_depth >= sc->sc_hwq_limit_aggr) {
+ break;
+ }
+ if (txq->axq_depth >= sc->sc_hwq_limit_nonaggr) {
+ break;
+ }
+
+ /*
+ * If this was the last entry on the original list, stop.
+ * Otherwise nodes that have been rescheduled onto the end
+ * of the TID FIFO list will just keep being rescheduled.
+ *
+ * XXX What should we do about nodes that were paused
+ * but are pending a leaking frame in response to a ps-poll?
+ * They'll be put at the front of the list; so they'll
+ * prematurely trigger this condition! Ew.
+ */
+ if (tid == last)
+ break;
+ }
+}
+
+/*
+ * TX addba handling
+ */
+
+/*
+ * Return net80211 TID struct pointer, or NULL for none
+ */
+struct ieee80211_tx_ampdu *
+ath_tx_get_tx_tid(struct ath_node *an, int tid)
+{
+ struct ieee80211_node *ni = &an->an_node;
+ struct ieee80211_tx_ampdu *tap;
+
+ if (tid == IEEE80211_NONQOS_TID)
+ return NULL;
+
+ tap = &ni->ni_tx_ampdu[tid];
+ return tap;
+}
+
+/*
+ * Is AMPDU-TX running?
+ */
+static int
+ath_tx_ampdu_running(struct ath_softc *sc, struct ath_node *an, int tid)
+{
+ struct ieee80211_tx_ampdu *tap;
+
+ if (tid == IEEE80211_NONQOS_TID)
+ return 0;
+
+ tap = ath_tx_get_tx_tid(an, tid);
+ if (tap == NULL)
+ return 0; /* Not valid; default to not running */
+
+ return !! (tap->txa_flags & IEEE80211_AGGR_RUNNING);
+}
+
+/*
+ * Is AMPDU-TX negotiation pending?
+ */
+static int
+ath_tx_ampdu_pending(struct ath_softc *sc, struct ath_node *an, int tid)
+{
+ struct ieee80211_tx_ampdu *tap;
+
+ if (tid == IEEE80211_NONQOS_TID)
+ return 0;
+
+ tap = ath_tx_get_tx_tid(an, tid);
+ if (tap == NULL)
+ return 0; /* Not valid; default to not pending */
+
+ return !! (tap->txa_flags & IEEE80211_AGGR_XCHGPEND);
+}
+
+/*
+ * Is AMPDU-TX pending for the given TID?
+ */
+
+
+/*
+ * Method to handle sending an ADDBA request.
+ *
+ * We tap this so the relevant flags can be set to pause the TID
+ * whilst waiting for the response.
+ *
+ * XXX there's no timeout handler we can override?
+ */
+int
+ath_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+ int dialogtoken, int baparamset, int batimeout)
+{
+ struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+ int tid = tap->txa_tid;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_tid *atid = &an->an_tid[tid];
+
+ /*
+ * XXX danger Will Robinson!
+ *
+ * Although the taskqueue may be running and scheduling some more
+ * packets, these should all be _before_ the addba sequence number.
+ * However, net80211 will keep self-assigning sequence numbers
+ * until addba has been negotiated.
+ *
+ * In the past, these packets would be "paused" (which still works
+ * fine, as they're being scheduled to the driver in the same
+ * serialised method which is calling the addba request routine)
+ * and when the aggregation session begins, they'll be dequeued
+ * as aggregate packets and added to the BAW. However, now there's
+ * a "bf->bf_state.bfs_dobaw" flag, and this isn't set for these
+ * packets. Thus they never get included in the BAW tracking and
+ * this can cause the initial burst of packets after the addba
+ * negotiation to "hang", as they quickly fall outside the BAW.
+ *
+ * The "eventual" solution should be to tag these packets with
+ * dobaw. Although net80211 has given us a sequence number,
+ * it'll be "after" the left edge of the BAW and thus it'll
+ * fall within it.
+ */
+ ATH_TX_LOCK(sc);
+ /*
+ * 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_TX_UNLOCK(sc);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: %6D: called; dialogtoken=%d, baparamset=%d, batimeout=%d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ dialogtoken, baparamset, batimeout);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: txa_start=%d, ni_txseqs=%d\n",
+ __func__, tap->txa_start, ni->ni_txseqs[tid]);
+
+ return sc->sc_addba_request(ni, tap, dialogtoken, baparamset,
+ batimeout);
+}
+
+/*
+ * Handle an ADDBA response.
+ *
+ * We unpause the queue so TX'ing can resume.
+ *
+ * Any packets TX'ed from this point should be "aggregate" (whether
+ * aggregate or not) so the BAW is updated.
+ *
+ * Note! net80211 keeps self-assigning sequence numbers until
+ * ampdu is negotiated. This means the initially-negotiated BAW left
+ * edge won't match the ni->ni_txseq.
+ *
+ * So, being very dirty, the BAW left edge is "slid" here to match
+ * ni->ni_txseq.
+ *
+ * What likely SHOULD happen is that all packets subsequent to the
+ * addba request should be tagged as aggregate and queued as non-aggregate
+ * frames; thus updating the BAW. For now though, I'll just slide the
+ * window.
+ */
+int
+ath_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+ int status, int code, int batimeout)
+{
+ struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+ int tid = tap->txa_tid;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_tid *atid = &an->an_tid[tid];
+ int r;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: %6D: called; status=%d, code=%d, batimeout=%d\n", __func__,
+ ni->ni_macaddr,
+ ":",
+ status, code, batimeout);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: txa_start=%d, ni_txseqs=%d\n",
+ __func__, tap->txa_start, ni->ni_txseqs[tid]);
+
+ /*
+ * Call this first, so the interface flags get updated
+ * before the TID is unpaused. Otherwise a race condition
+ * exists where the unpaused TID still doesn't yet have
+ * IEEE80211_AGGR_RUNNING set.
+ */
+ r = sc->sc_addba_response(ni, tap, status, code, batimeout);
+
+ ATH_TX_LOCK(sc);
+ atid->addba_tx_pending = 0;
+ /*
+ * XXX dirty!
+ * Slide the BAW left edge to wherever net80211 left it for us.
+ * Read above for more information.
+ */
+ tap->txa_start = ni->ni_txseqs[tid];
+ ath_tx_tid_resume(sc, atid);
+ ATH_TX_UNLOCK(sc);
+ return r;
+}
+
+
+/*
+ * 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)
+{
+ struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+ int tid = tap->txa_tid;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_tid *atid = &an->an_tid[tid];
+ ath_bufhead bf_cq;
+ struct ath_buf *bf;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: %6D: called\n",
+ __func__,
+ ni->ni_macaddr,
+ ":");
+
+ /*
+ * Pause TID traffic early, so there aren't any races
+ * Unblock the pending BAR held traffic, if it's currently paused.
+ */
+ ATH_TX_LOCK(sc);
+ ath_tx_tid_pause(sc, atid);
+ 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_TX_UNLOCK(sc);
+
+ /* There's no need to hold the TXQ lock here */
+ sc->sc_addba_stop(ni, tap);
+
+ /*
+ * 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.
+ */
+ TAILQ_INIT(&bf_cq);
+ ATH_TX_LOCK(sc);
+ ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
+ /*
+ * Unpause the TID if no cleanup is required.
+ */
+ if (! atid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, atid);
+ ATH_TX_UNLOCK(sc);
+
+ /* Handle completing frames and fail them */
+ while ((bf = TAILQ_FIRST(&bf_cq)) != NULL) {
+ TAILQ_REMOVE(&bf_cq, bf, bf_list);
+ ath_tx_default_comp(sc, bf, 1);
+ }
+
+}
+
+/*
+ * Handle a node reassociation.
+ *
+ * We may have a bunch of frames queued to the hardware; those need
+ * to be marked as cleanup.
+ */
+void
+ath_tx_node_reassoc(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_tid *tid;
+ int i;
+ ath_bufhead bf_cq;
+ struct ath_buf *bf;
+
+ TAILQ_INIT(&bf_cq);
+
+ ATH_TX_UNLOCK_ASSERT(sc);
+
+ ATH_TX_LOCK(sc);
+ for (i = 0; i < IEEE80211_TID_SIZE; i++) {
+ tid = &an->an_tid[i];
+ if (tid->hwq_depth == 0)
+ continue;
+ ath_tx_tid_pause(sc, tid);
+ DPRINTF(sc, ATH_DEBUG_NODE,
+ "%s: %6D: TID %d: cleaning up TID\n",
+ __func__,
+ an->an_node.ni_macaddr,
+ ":",
+ i);
+ ath_tx_tid_cleanup(sc, an, i, &bf_cq);
+ /*
+ * Unpause the TID if no cleanup is required.
+ */
+ if (! tid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, tid);
+ }
+ ATH_TX_UNLOCK(sc);
+
+ /* Handle completing frames and fail them */
+ while ((bf = TAILQ_FIRST(&bf_cq)) != NULL) {
+ TAILQ_REMOVE(&bf_cq, bf, bf_list);
+ ath_tx_default_comp(sc, bf, 1);
+ }
+}
+
+/*
+ * Note: net80211 bar_timeout() doesn't call this function on BAR failure;
+ * it simply tears down the aggregation session. Ew.
+ *
+ * It however will call ieee80211_ampdu_stop() which will call
+ * ic->ic_addba_stop().
+ *
+ * XXX This uses a hard-coded max BAR count value; the whole
+ * XXX BAR TX success or failure should be better handled!
+ */
+void
+ath_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+ int status)
+{
+ struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+ int tid = tap->txa_tid;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_tid *atid = &an->an_tid[tid];
+ int attempts = tap->txa_attempts;
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ tap->txa_tid,
+ atid->tid,
+ status,
+ attempts);
+
+ /* Note: This may update the BAW details */
+ sc->sc_bar_response(ni, tap, status);
+
+ /* Unpause the TID */
+ /*
+ * XXX if this is attempt=50, the TID will be downgraded
+ * XXX to a non-aggregate session. So we must unpause the
+ * XXX TID here or it'll never be done.
+ *
+ * Also, don't call it if bar_tx/bar_wait are 0; something
+ * has beaten us to the punch? (XXX figure out what?)
+ */
+ if (status == 0 || attempts == 50) {
+ ATH_TX_LOCK(sc);
+ if (atid->bar_tx == 0 || atid->bar_wait == 0)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
+ "%s: huh? bar_tx=%d, bar_wait=%d\n",
+ __func__,
+ atid->bar_tx, atid->bar_wait);
+ else
+ ath_tx_tid_bar_unsuspend(sc, atid);
+ ATH_TX_UNLOCK(sc);
+ }
+}
+
+/*
+ * This is called whenever the pending ADDBA request times out.
+ * Unpause and reschedule the TID.
+ */
+void
+ath_addba_response_timeout(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap)
+{
+ struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+ int tid = tap->txa_tid;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_tid *atid = &an->an_tid[tid];
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: %6D: TID=%d, called; resuming\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ tid);
+
+ ATH_TX_LOCK(sc);
+ atid->addba_tx_pending = 0;
+ ATH_TX_UNLOCK(sc);
+
+ /* Note: This updates the aggregate state to (again) pending */
+ sc->sc_addba_response_timeout(ni, tap);
+
+ /* Unpause the TID; which reschedules it */
+ ATH_TX_LOCK(sc);
+ ath_tx_tid_resume(sc, atid);
+ ATH_TX_UNLOCK(sc);
+}
+
+/*
+ * Check if a node is asleep or not.
+ */
+int
+ath_tx_node_is_asleep(struct ath_softc *sc, struct ath_node *an)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ return (an->an_is_powersave);
+}
+
+/*
+ * Mark a node as currently "in powersaving."
+ * This suspends all traffic on the node.
+ *
+ * This must be called with the node/tx locks free.
+ *
+ * XXX TODO: the locking silliness below is due to how the node
+ * locking currently works. Right now, the node lock is grabbed
+ * to do rate control lookups and these are done with the TX
+ * queue lock held. This means the node lock can't be grabbed
+ * first here or a LOR will occur.
+ *
+ * Eventually (hopefully!) the TX path code will only grab
+ * the TXQ lock when transmitting and the ath_node lock when
+ * doing node/TID operations. There are other complications -
+ * the sched/unsched operations involve walking the per-txq
+ * 'active tid' list and this requires both locks to be held.
+ */
+void
+ath_tx_node_sleep(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_tid *atid;
+ struct ath_txq *txq;
+ int tid;
+
+ ATH_TX_UNLOCK_ASSERT(sc);
+
+ /* Suspend all traffic on the node */
+ ATH_TX_LOCK(sc);
+
+ if (an->an_is_powersave) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: %6D: node was already asleep!\n",
+ __func__, an->an_node.ni_macaddr, ":");
+ ATH_TX_UNLOCK(sc);
+ return;
+ }
+
+ for (tid = 0; tid < IEEE80211_TID_SIZE; tid++) {
+ atid = &an->an_tid[tid];
+ txq = sc->sc_ac2q[atid->ac];
+
+ ath_tx_tid_pause(sc, atid);
+ }
+
+ /* Mark node as in powersaving */
+ an->an_is_powersave = 1;
+
+ ATH_TX_UNLOCK(sc);
+}
+
+/*
+ * Mark a node as currently "awake."
+ * This resumes all traffic to the node.
+ */
+void
+ath_tx_node_wakeup(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_tid *atid;
+ struct ath_txq *txq;
+ int tid;
+
+ ATH_TX_UNLOCK_ASSERT(sc);
+
+ ATH_TX_LOCK(sc);
+
+ /* !? */
+ if (an->an_is_powersave == 0) {
+ ATH_TX_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: an=%p: node was already awake\n",
+ __func__, an);
+ return;
+ }
+
+ /* Mark node as awake */
+ an->an_is_powersave = 0;
+ /*
+ * Clear any pending leaked frame requests
+ */
+ an->an_leak_count = 0;
+
+ for (tid = 0; tid < IEEE80211_TID_SIZE; tid++) {
+ atid = &an->an_tid[tid];
+ txq = sc->sc_ac2q[atid->ac];
+
+ ath_tx_tid_resume(sc, atid);
+ }
+ ATH_TX_UNLOCK(sc);
+}
+
+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 = sizeof(struct ath_desc);
+ 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;
+ sc->sc_tx.xmit_attach_comp_func = ath_legacy_attach_comp_func;
+
+ sc->sc_tx.xmit_dma_restart = ath_legacy_tx_dma_restart;
+ sc->sc_tx.xmit_handoff = ath_legacy_xmit_handoff;
+
+ sc->sc_tx.xmit_drain = ath_legacy_tx_drain;
+}
Modified: trunk/sys/dev/ath/if_ath_tx.h
===================================================================
--- trunk/sys/dev/ath/if_ath_tx.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_tx.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,12 +27,68 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_ath_tx.h 250866 2013-05-21 18:13:57Z adrian $
*/
#ifndef __IF_ATH_TX_H__
#define __IF_ATH_TX_H__
+/*
+ * some general macros
+ */
+#define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1)
+/*
+ * return block-ack bitmap index given sequence and starting sequence
+ */
+#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_RANGE - 1))
+
+#define WME_BA_BMP_SIZE 64
+#define WME_MAX_BA WME_BA_BMP_SIZE
+
+/*
+ * How 'busy' to try and keep the hardware txq
+ */
+#define ATH_AGGR_MIN_QDEPTH 2
+#define ATH_NONAGGR_MIN_QDEPTH 32
+
+/*
+ * Watermark for scheduling TIDs in order to maximise aggregation.
+ *
+ * If hwq_depth is greater than this, don't schedule the TID
+ * for packet scheduling - the hardware is already busy servicing
+ * this TID.
+ *
+ * If hwq_depth is less than this, schedule the TID for packet
+ * scheduling in the completion handler.
+ */
+#define ATH_AGGR_SCHED_HIGH 4
+#define ATH_AGGR_SCHED_LOW 2
+
+/*
+ * return whether a bit at index _n in bitmap _bm is set
+ * _sz is the size of the bitmap
+ */
+#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \
+ ((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
+
+
+/* extracting the seqno from buffer seqno */
+#define SEQNO(_a) ((_a) >> IEEE80211_SEQ_SEQ_SHIFT)
+
+/*
+ * Whether the current sequence number is within the
+ * BAW.
+ */
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 4095) < (_bawsz))
+
+/*
+ * Maximum aggregate size
+ */
+#define ATH_AGGR_MAXSIZE 65530
+
extern void ath_freetx(struct mbuf *m);
+extern void ath_tx_node_flush(struct ath_softc *sc, struct ath_node *an);
+extern void ath_tx_txq_drain(struct ath_softc *sc, struct ath_txq *txq);
extern void ath_txfrag_cleanup(struct ath_softc *sc, ath_bufhead *frags,
struct ieee80211_node *ni);
extern int ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
@@ -41,4 +98,73 @@
extern int ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_bpf_params *params);
+/* software queue stuff */
+extern void ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_txq *txq, int queue_to_head, struct ath_buf *bf);
+extern void ath_tx_tid_init(struct ath_softc *sc, struct ath_node *an);
+extern void ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid);
+extern void ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid);
+extern void ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq);
+extern void ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf,
+ int fail);
+extern void ath_tx_aggr_comp(struct ath_softc *sc, struct ath_buf *bf,
+ int fail);
+extern void ath_tx_addto_baw(struct ath_softc *sc, struct ath_node *an,
+ 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 void ath_tx_tid_sched(struct ath_softc *sc, struct ath_tid *tid);
+
+/* TX addba handling */
+extern int ath_addba_request(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap, int dialogtoken,
+ int baparamset, int batimeout);
+extern int ath_addba_response(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap, int dialogtoken,
+ int code, int batimeout);
+extern void ath_addba_stop(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap);
+extern void ath_bar_response(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap, int status);
+extern void ath_addba_response_timeout(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap);
+
+/*
+ * AP mode power save handling (of stations)
+ */
+extern void ath_tx_node_sleep(struct ath_softc *sc, struct ath_node *an);
+extern void ath_tx_node_wakeup(struct ath_softc *sc, struct ath_node *an);
+extern int ath_tx_node_is_asleep(struct ath_softc *sc, struct ath_node *an);
+extern void ath_tx_node_reassoc(struct ath_softc *sc, struct ath_node *an);
+
+/*
+ * Hardware queue stuff
+ */
+extern void ath_tx_push_pending(struct ath_softc *sc, struct ath_txq *txq);
+
+/*
+ * Misc debugging stuff
+ */
+#ifdef ATH_DEBUG_ALQ
+extern void ath_tx_alq_post(struct ath_softc *sc, struct ath_buf *bf_first);
+#endif /* ATH_DEBUG_ALQ */
+
+/*
+ * Setup path
+ */
+#define ath_txdma_setup(_sc) \
+ (_sc)->sc_tx.xmit_setup(_sc)
+#define ath_txdma_teardown(_sc) \
+ (_sc)->sc_tx.xmit_teardown(_sc)
+#define ath_txq_restart_dma(_sc, _txq) \
+ (_sc)->sc_tx.xmit_dma_restart((_sc), (_txq))
+#define ath_tx_handoff(_sc, _txq, _bf) \
+ (_sc)->sc_tx.xmit_handoff((_sc), (_txq), (_bf))
+#define ath_draintxq(_sc, _rtype) \
+ (_sc)->sc_tx.xmit_drain((_sc), (_rtype))
+
+extern void ath_xmit_setup_legacy(struct ath_softc *sc);
+
#endif
Added: trunk/sys/dev/ath/if_ath_tx_edma.c
===================================================================
--- trunk/sys/dev/ath/if_ath_tx_edma.c (rev 0)
+++ trunk/sys/dev/ath/if_ath_tx_edma.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,883 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/sys/dev/ath/if_ath_tx_edma.c 250444 2013-05-10 10:06:45Z 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>
+
+#ifdef ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
+
+/*
+ * some general macros
+ */
+#define INCR(_l, _sz) (_l) ++; (_l) &= ((_sz) - 1)
+#define DECR(_l, _sz) (_l) --; (_l) &= ((_sz) - 1)
+
+/*
+ * XXX doesn't belong here, and should be tunable
+ */
+#define ATH_TXSTATUS_RING_SIZE 512
+
+MALLOC_DECLARE(M_ATHDEV);
+
+static void ath_edma_tx_processq(struct ath_softc *sc, int dosched);
+
+/*
+ * Push some frames into the TX FIFO if we have space.
+ */
+static void
+ath_edma_tx_fifo_fill(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_buf *bf, *bf_last;
+ int i = 0;
+
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: called\n",
+ __func__,
+ txq->axq_qnum);
+
+ TAILQ_FOREACH(bf, &txq->axq_q, bf_list) {
+ if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH)
+ break;
+
+ /*
+ * We have space in the FIFO - so let's push a frame
+ * into it.
+ */
+
+ /*
+ * Remove it from the normal list
+ */
+ ATH_TXQ_REMOVE(txq, bf, bf_list);
+
+ /*
+ * XXX for now, we only dequeue a frame at a time, so
+ * that's only one buffer. Later on when we just
+ * push this staging _list_ into the queue, we'll
+ * set bf_last to the end pointer in the list.
+ */
+ bf_last = bf;
+ DPRINTF(sc, ATH_DEBUG_TX_PROC,
+ "%s: Q%d: depth=%d; pushing %p->%p\n",
+ __func__,
+ txq->axq_qnum,
+ txq->axq_fifo_depth,
+ bf,
+ bf_last);
+
+ /*
+ * Append it to the FIFO staging list
+ */
+ ATH_TXQ_INSERT_TAIL(&txq->fifo, bf, bf_list);
+
+ /*
+ * Set fifo start / fifo end flags appropriately
+ *
+ */
+ bf->bf_flags |= ATH_BUF_FIFOPTR;
+ bf_last->bf_flags |= ATH_BUF_FIFOEND;
+
+ /*
+ * Push _into_ the FIFO.
+ */
+ ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr);
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_XMIT_DESC)
+ ath_printtxbuf(sc, bf, txq->axq_qnum, i, 0);
+#endif/* ATH_DEBUG */
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC))
+ ath_tx_alq_post(sc, bf);
+#endif /* ATH_DEBUG_ALQ */
+ txq->axq_fifo_depth++;
+ i++;
+ }
+ if (i > 0)
+ ath_hal_txstart(sc->sc_ah, txq->axq_qnum);
+}
+
+/*
+ * Re-initialise the DMA FIFO with the current contents of
+ * said TXQ.
+ *
+ * This should only be called as part of the chip reset path, as it
+ * assumes the FIFO is currently empty.
+ */
+static void
+ath_edma_dma_restart(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_buf *bf;
+ int i = 0;
+ int fifostart = 1;
+ int old_fifo_depth;
+
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: called\n",
+ __func__,
+ txq->axq_qnum);
+
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ /*
+ * Let's log if the tracked FIFO depth doesn't match
+ * what we actually push in.
+ */
+ old_fifo_depth = txq->axq_fifo_depth;
+ txq->axq_fifo_depth = 0;
+
+ /*
+ * Walk the FIFO staging list, looking for "head" entries.
+ * Since we may have a partially completed list of frames,
+ * we push the first frame we see into the FIFO and re-mark
+ * it as the head entry. We then skip entries until we see
+ * FIFO end, at which point we get ready to push another
+ * entry into the FIFO.
+ */
+ TAILQ_FOREACH(bf, &txq->fifo.axq_q, bf_list) {
+ /*
+ * If we're looking for FIFOEND and we haven't found
+ * it, skip.
+ *
+ * If we're looking for FIFOEND and we've found it,
+ * reset for another descriptor.
+ */
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_XMIT_DESC)
+ ath_printtxbuf(sc, bf, txq->axq_qnum, i, 0);
+#endif/* ATH_DEBUG */
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC))
+ ath_tx_alq_post(sc, bf);
+#endif /* ATH_DEBUG_ALQ */
+
+ if (fifostart == 0) {
+ if (bf->bf_flags & ATH_BUF_FIFOEND)
+ fifostart = 1;
+ continue;
+ }
+
+ /* Make sure we're not overflowing the FIFO! */
+ if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) {
+ device_printf(sc->sc_dev,
+ "%s: Q%d: more frames in the queue; FIFO depth=%d?!\n",
+ __func__,
+ txq->axq_qnum,
+ txq->axq_fifo_depth);
+ }
+
+#if 0
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: Q%d: depth=%d: pushing bf=%p; start=%d, end=%d\n",
+ __func__,
+ txq->axq_qnum,
+ txq->axq_fifo_depth,
+ bf,
+ !! (bf->bf_flags & ATH_BUF_FIFOPTR),
+ !! (bf->bf_flags & ATH_BUF_FIFOEND));
+#endif
+
+ /*
+ * Set this to be the first buffer in the FIFO
+ * list - even if it's also the last buffer in
+ * a FIFO list!
+ */
+ bf->bf_flags |= ATH_BUF_FIFOPTR;
+
+ /* Push it into the FIFO and bump the FIFO count */
+ ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr);
+ txq->axq_fifo_depth++;
+
+ /*
+ * If this isn't the last entry either, let's
+ * clear fifostart so we continue looking for
+ * said last entry.
+ */
+ if (! (bf->bf_flags & ATH_BUF_FIFOEND))
+ fifostart = 0;
+ i++;
+ }
+
+ /* Only bother starting the queue if there's something in it */
+ if (i > 0)
+ ath_hal_txstart(sc->sc_ah, txq->axq_qnum);
+
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: FIFO depth was %d, is %d\n",
+ __func__,
+ txq->axq_qnum,
+ old_fifo_depth,
+ txq->axq_fifo_depth);
+
+ /* And now, let's check! */
+ if (txq->axq_fifo_depth != old_fifo_depth) {
+ device_printf(sc->sc_dev,
+ "%s: Q%d: FIFO depth should be %d, is %d\n",
+ __func__,
+ txq->axq_qnum,
+ old_fifo_depth,
+ txq->axq_fifo_depth);
+ }
+}
+
+/*
+ * Hand off this frame to a hardware queue.
+ *
+ * Things are a bit hairy in the EDMA world. The TX FIFO is only
+ * 8 entries deep, so we need to keep track of exactly what we've
+ * pushed into the FIFO and what's just sitting in the TX queue,
+ * waiting to go out.
+ *
+ * So this is split into two halves - frames get appended to the
+ * TXQ; then a scheduler is called to push some frames into the
+ * actual TX FIFO.
+ */
+static void
+ath_edma_xmit_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+
+ ATH_TXQ_LOCK(txq);
+
+ KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
+ ("%s: busy status 0x%x", __func__, bf->bf_flags));
+
+ /*
+ * XXX TODO: write a hard-coded check to ensure that
+ * the queue id in the TX descriptor matches txq->axq_qnum.
+ */
+
+ /* Update aggr stats */
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth++;
+
+ /* Push and update frame stats */
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+
+ /* For now, set the link pointer in the last descriptor
+ * to be NULL.
+ *
+ * Later on, when it comes time to handling multiple descriptors
+ * in one FIFO push, we can link descriptors together this way.
+ */
+
+ /*
+ * Finally, call the FIFO schedule routine to schedule some
+ * frames to the FIFO.
+ */
+ ath_edma_tx_fifo_fill(sc, txq);
+ ATH_TXQ_UNLOCK(txq);
+}
+
+/*
+ * Hand off this frame to a multicast software queue.
+ *
+ * The EDMA TX CABQ will get a list of chained frames, chained
+ * together using the next pointer. The single head of that
+ * particular queue is pushed to the hardware CABQ.
+ */
+static void
+ath_edma_xmit_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+
+ ATH_TX_LOCK_ASSERT(sc);
+ KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
+ ("%s: busy status 0x%x", __func__, bf->bf_flags));
+
+ ATH_TXQ_LOCK(txq);
+ /*
+ * XXX this is mostly duplicated in ath_tx_handoff_mcast().
+ */
+ if (ATH_TXQ_LAST(txq, axq_q_s) != NULL) {
+ struct ath_buf *bf_last = ATH_TXQ_LAST(txq, axq_q_s);
+ struct ieee80211_frame *wh;
+
+ /* mark previous frame */
+ wh = mtod(bf_last->bf_m, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+
+ /* re-sync buffer to memory */
+ bus_dmamap_sync(sc->sc_dmat, bf_last->bf_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ /* link descriptor */
+ ath_hal_settxdesclink(sc->sc_ah,
+ bf_last->bf_lastds,
+ bf->bf_daddr);
+ }
+#ifdef ATH_DEBUG_ALQ
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC))
+ ath_tx_alq_post(sc, bf);
+#endif /* ATH_DEBUG_ALQ */
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+ ATH_TXQ_UNLOCK(txq);
+}
+
+/*
+ * Handoff this frame to the hardware.
+ *
+ * For the multicast queue, this will treat it as a software queue
+ * and append it to the list, after updating the MORE_DATA flag
+ * in the previous frame. The cabq processing code will ensure
+ * that the queue contents gets transferred over.
+ *
+ * For the hardware queues, this will queue a frame to the queue
+ * like before, then populate the FIFO from that. Since the
+ * EDMA hardware has 8 FIFO slots per TXQ, this ensures that
+ * frames such as management frames don't get prematurely dropped.
+ *
+ * This does imply that a similar flush-hwq-to-fifoq method will
+ * need to be called from the processq function, before the
+ * per-node software scheduler is called.
+ */
+static void
+ath_edma_xmit_handoff(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf)
+{
+
+ DPRINTF(sc, ATH_DEBUG_XMIT_DESC,
+ "%s: called; bf=%p, txq=%p, qnum=%d\n",
+ __func__,
+ bf,
+ txq,
+ txq->axq_qnum);
+
+ if (txq->axq_qnum == ATH_TXQ_SWQ)
+ ath_edma_xmit_handoff_mcast(sc, txq, bf);
+ else
+ ath_edma_xmit_handoff_hw(sc, txq, bf);
+}
+
+static int
+ath_edma_setup_txfifo(struct ath_softc *sc, int qnum)
+{
+ struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum];
+
+ te->m_fifo = malloc(sizeof(struct ath_buf *) * HAL_TXFIFO_DEPTH,
+ M_ATHDEV,
+ M_NOWAIT | M_ZERO);
+ if (te->m_fifo == NULL) {
+ device_printf(sc->sc_dev, "%s: malloc failed\n",
+ __func__);
+ return (-ENOMEM);
+ }
+
+ /*
+ * Set initial "empty" state.
+ */
+ te->m_fifo_head = te->m_fifo_tail = te->m_fifo_depth = 0;
+
+ return (0);
+}
+
+static int
+ath_edma_free_txfifo(struct ath_softc *sc, int qnum)
+{
+ struct ath_tx_edma_fifo *te = &sc->sc_txedma[qnum];
+
+ /* XXX TODO: actually deref the ath_buf entries? */
+ free(te->m_fifo, M_ATHDEV);
+ return (0);
+}
+
+static int
+ath_edma_dma_txsetup(struct ath_softc *sc)
+{
+ int error;
+ int i;
+
+ error = ath_descdma_alloc_desc(sc, &sc->sc_txsdma,
+ NULL, "txcomp", sc->sc_tx_statuslen, ATH_TXSTATUS_RING_SIZE);
+ if (error != 0)
+ return (error);
+
+ ath_hal_setuptxstatusring(sc->sc_ah,
+ (void *) sc->sc_txsdma.dd_desc,
+ sc->sc_txsdma.dd_desc_paddr,
+ ATH_TXSTATUS_RING_SIZE);
+
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ ath_edma_setup_txfifo(sc, i);
+ }
+
+ return (0);
+}
+
+static int
+ath_edma_dma_txteardown(struct ath_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ ath_edma_free_txfifo(sc, i);
+ }
+
+ ath_descdma_cleanup(sc, &sc->sc_txsdma, NULL);
+ return (0);
+}
+
+/*
+ * Drain all TXQs, potentially after completing the existing completed
+ * frames.
+ */
+static void
+ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ int i;
+
+ DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__);
+
+ (void) ath_stoptxdma(sc);
+
+ /*
+ * If reset type is noloss, the TX FIFO needs to be serviced
+ * and those frames need to be handled.
+ *
+ * Otherwise, just toss everything in each TX queue.
+ */
+ if (reset_type == ATH_RESET_NOLOSS) {
+ ath_edma_tx_processq(sc, 0);
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ ATH_TXQ_LOCK(&sc->sc_txq[i]);
+ /*
+ * Free the holding buffer; DMA is now
+ * stopped.
+ */
+ ath_txq_freeholdingbuf(sc, &sc->sc_txq[i]);
+ /*
+ * Reset the link pointer to NULL; there's
+ * no frames to chain DMA to.
+ */
+ sc->sc_txq[i].axq_link = NULL;
+ ATH_TXQ_UNLOCK(&sc->sc_txq[i]);
+ }
+ }
+ } else {
+ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_draintxq(sc, &sc->sc_txq[i]);
+ }
+ }
+
+ /* XXX dump out the TX completion FIFO contents */
+
+ /* XXX dump out the frames */
+
+ IF_LOCK(&ifp->if_snd);
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&ifp->if_snd);
+ sc->sc_wd_timer = 0;
+}
+
+/*
+ * TX completion tasklet.
+ */
+
+static void
+ath_edma_tx_proc(void *arg, int npending)
+{
+ struct ath_softc *sc = (struct ath_softc *) arg;
+
+#if 0
+ DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: called, npending=%d\n",
+ __func__, npending);
+#endif
+ ath_edma_tx_processq(sc, 1);
+}
+
+/*
+ * Process the TX status queue.
+ */
+static void
+ath_edma_tx_processq(struct ath_softc *sc, int dosched)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_STATUS status;
+ struct ath_tx_status ts;
+ struct ath_txq *txq;
+ struct ath_buf *bf;
+ struct ieee80211_node *ni;
+ int nacked = 0;
+ int idx;
+
+#ifdef ATH_DEBUG
+ /* XXX */
+ uint32_t txstatus[32];
+#endif
+
+ for (idx = 0; ; idx++) {
+ bzero(&ts, sizeof(ts));
+
+ ATH_TXSTATUS_LOCK(sc);
+#ifdef ATH_DEBUG
+ ath_hal_gettxrawtxdesc(ah, txstatus);
+#endif
+ status = ath_hal_txprocdesc(ah, NULL, (void *) &ts);
+ ATH_TXSTATUS_UNLOCK(sc);
+
+ if (status == HAL_EINPROGRESS)
+ break;
+
+#ifdef ATH_DEBUG
+ if (sc->sc_debug & ATH_DEBUG_TX_PROC)
+ if (ts.ts_queue_id != sc->sc_bhalq)
+ ath_printtxstatbuf(sc, NULL, txstatus, ts.ts_queue_id,
+ idx, (status == HAL_OK));
+#endif
+
+ /*
+ * If there is an error with this descriptor, continue
+ * processing.
+ *
+ * XXX TBD: log some statistics?
+ */
+ if (status == HAL_EIO) {
+ device_printf(sc->sc_dev, "%s: invalid TX status?\n",
+ __func__);
+ break;
+ }
+
+#if defined(ATH_DEBUG_ALQ) && defined(ATH_DEBUG)
+ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS))
+ if_ath_alq_post(&sc->sc_alq, ATH_ALQ_EDMA_TXSTATUS,
+ sc->sc_tx_statuslen,
+ (char *) txstatus);
+#endif /* ATH_DEBUG_ALQ */
+
+ /*
+ * At this point we have a valid status descriptor.
+ * The QID and descriptor ID (which currently isn't set)
+ * is part of the status.
+ *
+ * We then assume that the descriptor in question is the
+ * -head- of the given QID. Eventually we should verify
+ * this by using the descriptor ID.
+ */
+
+ /*
+ * The beacon queue is not currently a "real" queue.
+ * Frames aren't pushed onto it and the lock isn't setup.
+ * So skip it for now; the beacon handling code will
+ * free and alloc more beacon buffers as appropriate.
+ */
+ if (ts.ts_queue_id == sc->sc_bhalq)
+ continue;
+
+ txq = &sc->sc_txq[ts.ts_queue_id];
+
+ ATH_TXQ_LOCK(txq);
+ bf = ATH_TXQ_FIRST(&txq->fifo);
+
+ /*
+ * Work around the situation where I'm seeing notifications
+ * for Q1 when no frames are available. That needs to be
+ * debugged but not by crashing _here_.
+ */
+ if (bf == NULL) {
+ device_printf(sc->sc_dev, "%s: Q%d: empty?\n",
+ __func__,
+ ts.ts_queue_id);
+ ATH_TXQ_UNLOCK(txq);
+ continue;
+ }
+
+ DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d, bf=%p, start=%d, end=%d\n",
+ __func__,
+ ts.ts_queue_id, bf,
+ !! (bf->bf_flags & ATH_BUF_FIFOPTR),
+ !! (bf->bf_flags & ATH_BUF_FIFOEND));
+
+ /* XXX TODO: actually output debugging info about this */
+
+#if 0
+ /* XXX assert the buffer/descriptor matches the status descid */
+ if (ts.ts_desc_id != bf->bf_descid) {
+ device_printf(sc->sc_dev,
+ "%s: mismatched descid (qid=%d, tsdescid=%d, "
+ "bfdescid=%d\n",
+ __func__,
+ ts.ts_queue_id,
+ ts.ts_desc_id,
+ bf->bf_descid);
+ }
+#endif
+
+ /* This removes the buffer and decrements the queue depth */
+ ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list);
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth--;
+
+ /*
+ * If this was the end of a FIFO set, decrement FIFO depth
+ */
+ if (bf->bf_flags & ATH_BUF_FIFOEND)
+ txq->axq_fifo_depth--;
+
+ /*
+ * If this isn't the final buffer in a FIFO set, mark
+ * the buffer as busy so it goes onto the holding queue.
+ */
+ if (! (bf->bf_flags & ATH_BUF_FIFOEND))
+ bf->bf_flags |= ATH_BUF_BUSY;
+
+ DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: FIFO depth is now %d (%d)\n",
+ __func__,
+ txq->axq_qnum,
+ txq->axq_fifo_depth,
+ txq->fifo.axq_depth);
+
+ /* XXX assert FIFO depth >= 0 */
+ ATH_TXQ_UNLOCK(txq);
+
+ /*
+ * Outside of the TX lock - if the buffer is end
+ * end buffer in this FIFO, we don't need a holding
+ * buffer any longer.
+ */
+ if (bf->bf_flags & ATH_BUF_FIFOEND) {
+ ATH_TXQ_LOCK(txq);
+ ath_txq_freeholdingbuf(sc, txq);
+ ATH_TXQ_UNLOCK(txq);
+ }
+
+ /*
+ * First we need to make sure ts_rate is valid.
+ *
+ * Pre-EDMA chips pass the whole TX descriptor to
+ * the proctxdesc function which will then fill out
+ * ts_rate based on the ts_finaltsi (final TX index)
+ * in the TX descriptor. However the TX completion
+ * FIFO doesn't have this information. So here we
+ * do a separate HAL call to populate that information.
+ *
+ * The same problem exists with ts_longretry.
+ * The FreeBSD HAL corrects ts_longretry in the HAL layer;
+ * the AR9380 HAL currently doesn't. So until the HAL
+ * is imported and this can be added, we correct for it
+ * here.
+ */
+ /* XXX TODO */
+ /* XXX faked for now. Ew. */
+ if (ts.ts_finaltsi < 4) {
+ ts.ts_rate =
+ bf->bf_state.bfs_rc[ts.ts_finaltsi].ratecode;
+ switch (ts.ts_finaltsi) {
+ case 3: ts.ts_longretry +=
+ bf->bf_state.bfs_rc[2].tries;
+ case 2: ts.ts_longretry +=
+ bf->bf_state.bfs_rc[1].tries;
+ case 1: ts.ts_longretry +=
+ bf->bf_state.bfs_rc[0].tries;
+ }
+ } else {
+ device_printf(sc->sc_dev, "%s: finaltsi=%d\n",
+ __func__,
+ ts.ts_finaltsi);
+ ts.ts_rate = bf->bf_state.bfs_rc[0].ratecode;
+ }
+
+ /*
+ * XXX This is terrible.
+ *
+ * Right now, some code uses the TX status that is
+ * passed in here, but the completion handlers in the
+ * software TX path also use bf_status.ds_txstat.
+ * Ew. That should all go away.
+ *
+ * XXX It's also possible the rate control completion
+ * routine is called twice.
+ */
+ memcpy(&bf->bf_status, &ts, sizeof(ts));
+
+ ni = bf->bf_node;
+
+ /* Update RSSI */
+ /* XXX duplicate from ath_tx_processq */
+ if (ni != NULL && ts.ts_status == 0 &&
+ ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0)) {
+ nacked++;
+ sc->sc_stats.ast_tx_rssi = ts.ts_rssi;
+ ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi,
+ ts.ts_rssi);
+ }
+
+ /* Handle frame completion and rate control update */
+ ath_tx_process_buf_completion(sc, txq, &ts, bf);
+
+ /* bf is invalid at this point */
+
+ /*
+ * Now that there's space in the FIFO, let's push some
+ * more frames into it.
+ */
+ ATH_TXQ_LOCK(txq);
+ if (dosched)
+ ath_edma_tx_fifo_fill(sc, txq);
+ ATH_TXQ_UNLOCK(txq);
+ }
+
+ sc->sc_wd_timer = 0;
+
+ if (idx > 0) {
+ IF_LOCK(&sc->sc_ifp->if_snd);
+ sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ IF_UNLOCK(&sc->sc_ifp->if_snd);
+ }
+
+ /* Kick software scheduler */
+ /*
+ * XXX It's inefficient to do this if the FIFO queue is full,
+ * but there's no easy way right now to only populate
+ * the txq task for _one_ TXQ. This should be fixed.
+ */
+ if (dosched)
+ ath_tx_swq_kick(sc);
+}
+
+static void
+ath_edma_attach_comp_func(struct ath_softc *sc)
+{
+
+ TASK_INIT(&sc->sc_txtask, 0, ath_edma_tx_proc, sc);
+}
+
+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;
+ sc->sc_tx.xmit_attach_comp_func = ath_edma_attach_comp_func;
+
+ sc->sc_tx.xmit_dma_restart = ath_edma_dma_restart;
+ sc->sc_tx.xmit_handoff = ath_edma_xmit_handoff;
+ sc->sc_tx.xmit_drain = ath_edma_tx_drain;
+}
Property changes on: trunk/sys/dev/ath/if_ath_tx_edma.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/dev/ath/if_ath_tx_edma.h
===================================================================
--- trunk/sys/dev/ath/if_ath_tx_edma.h (rev 0)
+++ trunk/sys/dev/ath/if_ath_tx_edma.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -0,0 +1,37 @@
+/* $MidnightBSD$ */
+/*-
+ * 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: stable/10/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
Property changes on: trunk/sys/dev/ath/if_ath_tx_edma.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/dev/ath/if_ath_tx_ht.c
===================================================================
--- trunk/sys/dev/ath/if_ath_tx_ht.c 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_tx_ht.c 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
* All rights reserved.
@@ -28,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_tx_ht.c 250665 2013-05-15 18:33:05Z adrian $");
#include "opt_inet.h"
#include "opt_ath.h"
@@ -86,78 +87,489 @@
#include <dev/ath/ath_tx99/ath_tx99.h>
#endif
+#include <dev/ath/if_ath_tx.h> /* XXX for some support functions */
#include <dev/ath/if_ath_tx_ht.h>
+#include <dev/ath/if_athrate.h>
+#include <dev/ath/if_ath_debug.h>
/*
+ * XXX net80211?
+ */
+#define IEEE80211_AMPDU_SUBFRAME_DEFAULT 32
+
+#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
+#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
+/* number of delimiters for encryption padding */
+#define ATH_AGGR_ENCRYPTDELIM 10
+
+/*
+ * returns delimiter padding required given the packet length
+ */
+#define ATH_AGGR_GET_NDELIM(_len) \
+ (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
+ (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
+
+#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
+
+int ath_max_4ms_framelen[4][32] = {
+ [MCS_HT20] = {
+ 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
+ 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
+ 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
+ 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
+ },
+ [MCS_HT20_SGI] = {
+ 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
+ 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
+ 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
+ 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
+ },
+ [MCS_HT40] = {
+ 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
+ 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
+ 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
+ 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
+ },
+ [MCS_HT40_SGI] = {
+ 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
+ 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
+ 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
+ 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
+ }
+};
+
+/*
+ * XXX should be in net80211
+ */
+static int ieee80211_mpdudensity_map[] = {
+ 0, /* IEEE80211_HTCAP_MPDUDENSITY_NA */
+ 25, /* IEEE80211_HTCAP_MPDUDENSITY_025 */
+ 50, /* IEEE80211_HTCAP_MPDUDENSITY_05 */
+ 100, /* IEEE80211_HTCAP_MPDUDENSITY_1 */
+ 200, /* IEEE80211_HTCAP_MPDUDENSITY_2 */
+ 400, /* IEEE80211_HTCAP_MPDUDENSITY_4 */
+ 800, /* IEEE80211_HTCAP_MPDUDENSITY_8 */
+ 1600, /* IEEE80211_HTCAP_MPDUDENSITY_16 */
+};
+
+/*
+ * XXX should be in the HAL/net80211 ?
+ */
+#define BITS_PER_BYTE 8
+#define OFDM_PLCP_BITS 22
+#define HT_RC_2_MCS(_rc) ((_rc) & 0x7f)
+#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
+#define L_STF 8
+#define L_LTF 8
+#define L_SIG 4
+#define HT_SIG 8
+#define HT_STF 4
+#define HT_LTF(_ns) (4 * (_ns))
+#define SYMBOL_TIME(_ns) ((_ns) << 2) // ns * 4 us
+#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) // ns * 3.6 us
+#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
+#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
+#define IS_HT_RATE(_rate) ((_rate) & 0x80)
+
+const uint32_t bits_per_symbol[][2] = {
+ /* 20MHz 40MHz */
+ { 26, 54 }, // 0: BPSK
+ { 52, 108 }, // 1: QPSK 1/2
+ { 78, 162 }, // 2: QPSK 3/4
+ { 104, 216 }, // 3: 16-QAM 1/2
+ { 156, 324 }, // 4: 16-QAM 3/4
+ { 208, 432 }, // 5: 64-QAM 2/3
+ { 234, 486 }, // 6: 64-QAM 3/4
+ { 260, 540 }, // 7: 64-QAM 5/6
+ { 52, 108 }, // 8: BPSK
+ { 104, 216 }, // 9: QPSK 1/2
+ { 156, 324 }, // 10: QPSK 3/4
+ { 208, 432 }, // 11: 16-QAM 1/2
+ { 312, 648 }, // 12: 16-QAM 3/4
+ { 416, 864 }, // 13: 64-QAM 2/3
+ { 468, 972 }, // 14: 64-QAM 3/4
+ { 520, 1080 }, // 15: 64-QAM 5/6
+ { 78, 162 }, // 16: BPSK
+ { 156, 324 }, // 17: QPSK 1/2
+ { 234, 486 }, // 18: QPSK 3/4
+ { 312, 648 }, // 19: 16-QAM 1/2
+ { 468, 972 }, // 20: 16-QAM 3/4
+ { 624, 1296 }, // 21: 64-QAM 2/3
+ { 702, 1458 }, // 22: 64-QAM 3/4
+ { 780, 1620 }, // 23: 64-QAM 5/6
+ { 104, 216 }, // 24: BPSK
+ { 208, 432 }, // 25: QPSK 1/2
+ { 312, 648 }, // 26: QPSK 3/4
+ { 416, 864 }, // 27: 16-QAM 1/2
+ { 624, 1296 }, // 28: 16-QAM 3/4
+ { 832, 1728 }, // 29: 64-QAM 2/3
+ { 936, 1944 }, // 30: 64-QAM 3/4
+ { 1040, 2160 }, // 31: 64-QAM 5/6
+};
+
+/*
+ * Fill in the rate array information based on the current
+ * node configuration and the choices made by the rate
+ * selection code and ath_buf setup code.
+ *
+ * Later on, this may end up also being made by the
+ * rate control code, but for now it can live here.
+ *
+ * This needs to be called just before the packet is
+ * queued to the software queue or hardware queue,
+ * so all of the needed fields in bf_state are setup.
+ */
+void
+ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ieee80211com *ic = ni->ni_ic;
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct ath_rc_series *rc = bf->bf_state.bfs_rc;
+ uint8_t rate;
+ int i;
+
+ for (i = 0; i < ATH_RC_NUM; i++) {
+ rc[i].flags = 0;
+ if (rc[i].tries == 0)
+ continue;
+
+ rate = rt->info[rc[i].rix].rateCode;
+
+ /*
+ * Only enable short preamble for legacy rates
+ */
+ if ((! IS_HT_RATE(rate)) && bf->bf_state.bfs_shpream)
+ rate |= rt->info[rc[i].rix].shortPreamble;
+
+ /*
+ * Save this, used by the TX and completion code
+ */
+ rc[i].ratecode = rate;
+
+ if (bf->bf_state.bfs_txflags &
+ (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
+ rc[i].flags |= ATH_RC_RTSCTS_FLAG;
+
+ /* Only enable shortgi, 2040, dual-stream if HT is set */
+ if (IS_HT_RATE(rate)) {
+ rc[i].flags |= ATH_RC_HT_FLAG;
+
+ if (ni->ni_chw == 40)
+ rc[i].flags |= ATH_RC_CW40_FLAG;
+
+ if (ni->ni_chw == 40 &&
+ ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
+ ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
+ rc[i].flags |= ATH_RC_SGI_FLAG;
+
+ if (ni->ni_chw == 20 &&
+ ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
+ ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
+ rc[i].flags |= ATH_RC_SGI_FLAG;
+
+ /*
+ * If we have STBC TX enabled and the receiver
+ * can receive (at least) 1 stream STBC, AND it's
+ * MCS 0-7, AND we have at least two chains enabled,
+ * enable STBC.
+ */
+ if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC &&
+ ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM &&
+ (sc->sc_cur_txchainmask > 1) &&
+ HT_RC_2_STREAMS(rate) == 1) {
+ rc[i].flags |= ATH_RC_STBC_FLAG;
+ }
+
+ /*
+ * XXX TODO: LDPC
+ */
+
+ /*
+ * Dual / Triple stream rate?
+ */
+ if (HT_RC_2_STREAMS(rate) == 2)
+ rc[i].flags |= ATH_RC_DS_FLAG;
+ else if (HT_RC_2_STREAMS(rate) == 3)
+ rc[i].flags |= ATH_RC_TS_FLAG;
+ }
+
+ /*
+ * Calculate the maximum TX power cap for the current
+ * node.
+ */
+ rc[i].tx_power_cap = ieee80211_get_node_txpower(ni);
+
+ /*
+ * Calculate the maximum 4ms frame length based
+ * on the MCS rate, SGI and channel width flags.
+ */
+ if ((rc[i].flags & ATH_RC_HT_FLAG) &&
+ (HT_RC_2_MCS(rate) < 32)) {
+ int j;
+ if (rc[i].flags & ATH_RC_CW40_FLAG) {
+ if (rc[i].flags & ATH_RC_SGI_FLAG)
+ j = MCS_HT40_SGI;
+ else
+ j = MCS_HT40;
+ } else {
+ if (rc[i].flags & ATH_RC_SGI_FLAG)
+ j = MCS_HT20_SGI;
+ else
+ j = MCS_HT20;
+ }
+ rc[i].max4msframelen =
+ ath_max_4ms_framelen[j][HT_RC_2_MCS(rate)];
+ } else
+ rc[i].max4msframelen = 0;
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: i=%d, rate=0x%x, flags=0x%x, max4ms=%d\n",
+ __func__, i, rate, rc[i].flags, rc[i].max4msframelen);
+ }
+}
+
+/*
+ * Return the number of delimiters to be added to
+ * meet the minimum required mpdudensity.
+ *
+ * Caller should make sure that the rate is HT.
+ *
+ * TODO: is this delimiter calculation supposed to be the
+ * total frame length, the hdr length, the data length (including
+ * delimiters, padding, CRC, etc) or ?
+ *
+ * TODO: this should ensure that the rate control information
+ * HAS been setup for the first rate.
+ *
+ * TODO: ensure this is only called for MCS rates.
+ *
+ * TODO: enforce MCS < 31
+ */
+static int
+ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf,
+ uint16_t pktlen)
+{
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+ struct ieee80211_node *ni = first_bf->bf_node;
+ struct ieee80211vap *vap = ni->ni_vap;
+ int ndelim, mindelim = 0;
+ int mpdudensity; /* in 1/100'th of a microsecond */
+ uint8_t rc, rix, flags;
+ int width, half_gi;
+ uint32_t nsymbits, nsymbols;
+ uint16_t minlen;
+
+ /*
+ * vap->iv_ampdu_density is a value, rather than the actual
+ * density.
+ */
+ if (vap->iv_ampdu_density > IEEE80211_HTCAP_MPDUDENSITY_16)
+ mpdudensity = 1600; /* maximum density */
+ else
+ mpdudensity = ieee80211_mpdudensity_map[vap->iv_ampdu_density];
+
+ /* Select standard number of delimiters based on frame length */
+ ndelim = ATH_AGGR_GET_NDELIM(pktlen);
+
+ /*
+ * If encryption is enabled, add extra delimiters to let the
+ * crypto hardware catch up. This could be tuned per-MAC and
+ * per-rate, but for now we'll simply assume encryption is
+ * always enabled.
+ *
+ * Also note that the Atheros reference driver inserts two
+ * delimiters by default for pre-AR9380 peers. This will
+ * include "that" required delimiter.
+ */
+ ndelim += ATH_AGGR_ENCRYPTDELIM;
+
+ /*
+ * For AR9380, there's a minimum number of delimeters
+ * required when doing RTS.
+ *
+ * XXX TODO: this is only needed if (a) RTS/CTS is enabled, and
+ * XXX (b) this is the first sub-frame in the aggregate.
+ */
+ if (sc->sc_use_ent && (sc->sc_ent_cfg & AH_ENT_RTSCTS_DELIM_WAR)
+ && ndelim < AH_FIRST_DESC_NDELIMS)
+ ndelim = AH_FIRST_DESC_NDELIMS;
+
+ /*
+ * If sc_delim_min_pad is non-zero, enforce it as the minimum
+ * pad delimiter count.
+ */
+ if (sc->sc_delim_min_pad != 0)
+ ndelim = MAX(ndelim, sc->sc_delim_min_pad);
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: pktlen=%d, ndelim=%d, mpdudensity=%d\n",
+ __func__, pktlen, ndelim, mpdudensity);
+
+ /*
+ * If the MPDU density is 0, we can return here.
+ * Otherwise, we need to convert the desired mpdudensity
+ * into a byte length, based on the rate in the subframe.
+ */
+ if (mpdudensity == 0)
+ return ndelim;
+
+ /*
+ * Convert desired mpdu density from microeconds to bytes based
+ * on highest rate in rate series (i.e. first rate) to determine
+ * required minimum length for subframe. Take into account
+ * whether high rate is 20 or 40Mhz and half or full GI.
+ */
+ rix = first_bf->bf_state.bfs_rc[0].rix;
+ rc = rt->info[rix].rateCode;
+ flags = first_bf->bf_state.bfs_rc[0].flags;
+ width = !! (flags & ATH_RC_CW40_FLAG);
+ half_gi = !! (flags & ATH_RC_SGI_FLAG);
+
+ /*
+ * mpdudensity is in 1/100th of a usec, so divide by 100
+ */
+ if (half_gi)
+ nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
+ else
+ nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
+ nsymbols /= 100;
+
+ if (nsymbols == 0)
+ nsymbols = 1;
+
+ nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+ minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
+
+ /*
+ * Min length is the minimum frame length for the
+ * required MPDU density.
+ */
+ if (pktlen < minlen) {
+ mindelim = (minlen - pktlen) / ATH_AGGR_DELIM_SZ;
+ ndelim = MAX(mindelim, ndelim);
+ }
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
+ "%s: pktlen=%d, minlen=%d, rix=%x, rc=%x, width=%d, hgi=%d, ndelim=%d\n",
+ __func__, pktlen, minlen, rix, rc, width, half_gi, ndelim);
+
+ return ndelim;
+}
+
+/*
+ * Fetch the aggregation limit.
+ *
+ * It's the lowest of the four rate series 4ms frame length.
+ */
+static int
+ath_get_aggr_limit(struct ath_softc *sc, struct ath_buf *bf)
+{
+ int amin = ATH_AGGR_MAXSIZE;
+ int i;
+
+ if (sc->sc_aggr_limit > 0 && sc->sc_aggr_limit < ATH_AGGR_MAXSIZE)
+ amin = sc->sc_aggr_limit;
+
+ 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);
+ }
+
+ DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: max frame len= %d\n",
+ __func__, amin);
+
+ return amin;
+}
+
+/*
* Setup a 11n rate series structure
*
* This should be called for both legacy and MCS rates.
+ *
+ * This uses the rate series stuf from ath_tx_rate_fill_rcflags().
+ *
+ * It, along with ath_buf_set_rate, must be called -after- a burst
+ * or aggregate is setup.
*/
static void
ath_rateseries_setup(struct ath_softc *sc, struct ieee80211_node *ni,
- HAL_11N_RATE_SERIES *series, unsigned int pktlen, uint8_t *rix,
- uint8_t *try, int flags)
+ 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;
const HAL_RATE_TABLE *rt = sc->sc_currates;
int i;
+ int pktlen;
+ struct ath_rc_series *rc = bf->bf_state.bfs_rc;
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE))
shortPreamble = AH_TRUE;
+ /*
+ * If this is the first frame in an aggregate series,
+ * use the aggregate length.
+ */
+ if (bf->bf_state.bfs_aggr)
+ pktlen = bf->bf_state.bfs_al;
+ else
+ pktlen = bf->bf_state.bfs_pktlen;
+
+ /*
+ * XXX TODO: modify this routine to use the bfs_rc[x].flags
+ * 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 (try[i] == 0)
+ if (rc[i].tries == 0)
continue;
- series[i].Tries = try[i];
+ series[i].Tries = rc[i].tries;
/*
- * XXX this isn't strictly correct - sc_txchainmask
- * XXX isn't the currently active chainmask;
- * XXX it's the interface chainmask at startup.
- * XXX It's overridden in the HAL rate scenario function
- * XXX for now.
+ * XXX TODO: When the NIC is capable of three stream TX,
+ * transmit 1/2 stream rates on two streams.
+ *
+ * This reduces the power consumption of the NIC and
+ * keeps it within the PCIe slot power limits.
*/
- series[i].ChSel = sc->sc_txchainmask;
+ series[i].ChSel = sc->sc_cur_txchainmask;
- if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA))
- series[i].RateFlags |= HAL_RATESERIES_RTS_CTS;
+ /*
+ * Setup rate and TX power cap for this series.
+ */
+ series[i].Rate = rt->info[rc[i].rix].rateCode;
+ series[i].RateIndex = rc[i].rix;
+ series[i].tx_power_cap = rc[i].tx_power_cap;
/*
- * Transmit 40MHz frames only if the node has negotiated
- * it rather than whether the node is capable of it or not.
- * It's subtly different in the hostap case.
- */
- if (ni->ni_chw == 40)
- series[i].RateFlags |= HAL_RATESERIES_2040;
+ * Enable RTS/CTS as appropriate.
+ */
+ if (rc[i].flags & ATH_RC_RTSCTS_FLAG)
+ series[i].RateFlags |= HAL_RATESERIES_RTS_CTS;
/*
- * Set short-GI only if the node has advertised it
- * the channel width is suitable, and we support it.
- * We don't currently have a "negotiated" set of bits -
- * ni_htcap is what the remote end sends, not what this
- * node is capable of.
+ * 11n rate? Update 11n flags.
*/
- if (ni->ni_chw == 40 &&
- ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
- ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
- series[i].RateFlags |= HAL_RATESERIES_HALFGI;
+ if (rc[i].flags & ATH_RC_HT_FLAG) {
+ if (rc[i].flags & ATH_RC_CW40_FLAG)
+ series[i].RateFlags |= HAL_RATESERIES_2040;
- if (ni->ni_chw == 20 &&
- ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
- ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
- series[i].RateFlags |= HAL_RATESERIES_HALFGI;
+ if (rc[i].flags & ATH_RC_SGI_FLAG)
+ series[i].RateFlags |= HAL_RATESERIES_HALFGI;
- series[i].Rate = rt->info[rix[i]].rateCode;
+ if (rc[i].flags & ATH_RC_STBC_FLAG)
+ series[i].RateFlags |= HAL_RATESERIES_STBC;
+ }
- /* PktDuration doesn't include slot, ACK, RTS, etc timing - it's just the packet duration */
- if (series[i].Rate & IEEE80211_RATE_MCS) {
+ /*
+ * PktDuration doesn't include slot, ACK, RTS, etc timing -
+ * it's just the packet duration
+ */
+ if (rc[i].flags & ATH_RC_HT_FLAG) {
series[i].PktDuration =
ath_computedur_ht(pktlen
, series[i].Rate
@@ -166,26 +578,28 @@
, series[i].RateFlags & HAL_RATESERIES_HALFGI);
} else {
if (shortPreamble)
- series[i].Rate |= rt->info[rix[i]].shortPreamble;
+ series[i].Rate |=
+ rt->info[rc[i].rix].shortPreamble;
series[i].PktDuration = ath_hal_computetxtime(ah,
- rt, pktlen, rix[i], shortPreamble);
+ 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; txpowcap %d, rateFlags %x\n",
i,
series[i].Rate,
series[i].Tries,
series[i].PktDuration,
series[i].ChSel,
+ series[i].tx_power_cap,
series[i].RateFlags);
}
}
@@ -198,46 +612,286 @@
* This isn't useful for sending beacon frames, which has different needs
* wrt what's passed into the rate scenario function.
*/
-
void
-ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
- int pktlen, int flags, uint8_t ctsrate, int is_pspoll, uint8_t *rix, uint8_t *try)
+ath_buf_set_rate(struct ath_softc *sc, struct ieee80211_node *ni,
+ struct ath_buf *bf)
{
HAL_11N_RATE_SERIES series[4];
struct ath_desc *ds = bf->bf_desc;
- struct ath_desc *lastds = NULL;
struct ath_hal *ah = sc->sc_ah;
+ int is_pspoll = (bf->bf_state.bfs_atype == HAL_PKT_TYPE_PSPOLL);
+ int ctsrate = bf->bf_state.bfs_ctsrate;
+ int flags = bf->bf_state.bfs_txflags;
/* Setup rate scenario */
memset(&series, 0, sizeof(series));
- ath_rateseries_setup(sc, ni, series, pktlen, rix, try, flags);
+ ath_rateseries_setup(sc, ni, bf, series);
- /* Enforce AR5416 aggregate limit - can't do RTS w/ an agg frame > 8k */
-
- /* Enforce RTS and CTS are mutually exclusive */
-
- /* Get a pointer to the last tx descriptor in the list */
- lastds = &bf->bf_desc[bf->bf_nseg - 1];
-
#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 */
- ath_hal_setuplasttxdesc(ah, lastds, ds);
-
/* Set burst duration */
- /* This should only be done if aggregate protection is enabled */
+ /*
+ * This is only required when doing 11n burst, not aggregation
+ * ie, if there's a second frame in a RIFS or A-MPDU burst
+ * w/ >1 A-MPDU frame bursting back to back.
+ * Normal A-MPDU doesn't do bursting -between- aggregates.
+ *
+ * .. and it's highly likely this won't ever be implemented
+ */
//ath_hal_set11nburstduration(ah, ds, 8192);
}
+
+/*
+ * Form an aggregate packet list.
+ *
+ * This function enforces the aggregate restrictions/requirements.
+ *
+ * These are:
+ *
+ * + The aggregate size maximum (64k for AR9160 and later, 8K for
+ * AR5416 when doing RTS frame protection.)
+ * + Maximum number of sub-frames for an aggregate
+ * + The aggregate delimiter size, giving MACs time to do whatever is
+ * needed before each frame
+ * + Enforce the BAW limit
+ *
+ * Each descriptor queued should have the DMA setup.
+ * The rate series, descriptor setup, linking, etc is all done
+ * externally. This routine simply chains them together.
+ * ath_tx_setds_11n() will take care of configuring the per-
+ * descriptor setup, and ath_buf_set_rate() will configure the
+ * rate control.
+ *
+ * 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
+ * task.
+ *
+ * So if you want to call this from an upper layer context (eg, to direct-
+ * 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)
+{
+ //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;
+ struct ieee80211_tx_ampdu *tap;
+ int status = ATH_AGGR_DONE;
+ int prev_frames = 0; /* XXX for AR5416 burst, not done here */
+ int prev_al = 0; /* XXX also for AR5416 burst */
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ tap = ath_tx_get_tx_tid(an, tid->tid);
+ if (tap == NULL) {
+ status = ATH_AGGR_ERROR;
+ goto finish;
+ }
+
+ h_baw = tap->txa_wnd / 2;
+
+ for (;;) {
+ bf = ATH_TID_FIRST(tid);
+ if (bf_first == NULL)
+ bf_first = bf;
+ if (bf == NULL) {
+ status = ATH_AGGR_DONE;
+ break;
+ } else {
+ /*
+ * It's the first frame;
+ * set the aggregation limit based on the
+ * rate control decision that has been made.
+ */
+ aggr_limit = ath_get_aggr_limit(sc, bf_first);
+ }
+
+ /* Set this early just so things don't get confused */
+ bf->bf_next = NULL;
+
+ /*
+ * If the frame doesn't have a sequence number that we're
+ * tracking in the BAW (eg NULL QOS data frame), we can't
+ * aggregate it. Stop the aggregation process; the sender
+ * can then TX what's in the list thus far and then
+ * TX the frame individually.
+ */
+ if (! bf->bf_state.bfs_dobaw) {
+ status = ATH_AGGR_NONAGGR;
+ break;
+ }
+
+ /*
+ * If any of the rates are non-HT, this packet
+ * can't be aggregated.
+ * XXX TODO: add a bf_state flag which gets marked
+ * if any active rate is non-HT.
+ */
+
+ /*
+ * do not exceed aggregation limit
+ */
+ al_delta = ATH_AGGR_DELIM_SZ + bf->bf_state.bfs_pktlen;
+ if (nframes &&
+ (aggr_limit < (al + bpad + al_delta + prev_al))) {
+ status = ATH_AGGR_LIMITED;
+ break;
+ }
+
+ /*
+ * If RTS/CTS is set on the first frame, enforce
+ * the RTS aggregate limit.
+ */
+ if (bf_first->bf_state.bfs_txflags &
+ (HAL_TXDESC_CTSENA | HAL_TXDESC_RTSENA)) {
+ if (nframes &&
+ (sc->sc_rts_aggr_limit <
+ (al + bpad + al_delta + prev_al))) {
+ status = ATH_AGGR_8K_LIMITED;
+ break;
+ }
+ }
+
+ /*
+ * Do not exceed subframe limit.
+ */
+ if ((nframes + prev_frames) >= MIN((h_baw),
+ IEEE80211_AMPDU_SUBFRAME_DEFAULT)) {
+ status = ATH_AGGR_LIMITED;
+ break;
+ }
+
+ /*
+ * If the current frame has an RTS/CTS configuration
+ * that differs from the first frame, override the
+ * subsequent frame with this config.
+ */
+ if (bf != bf_first) {
+ bf->bf_state.bfs_txflags &=
+ ~ (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA);
+ bf->bf_state.bfs_txflags |=
+ bf_first->bf_state.bfs_txflags &
+ (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA);
+ }
+
+ /*
+ * 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))) {
+ status = ATH_AGGR_BAW_CLOSED;
+ break;
+ }
+
+ /*
+ * this packet is part of an aggregate.
+ */
+ ATH_TID_REMOVE(tid, bf, bf_list);
+
+ /* The TID lock is required for the BAW update */
+ ath_tx_addto_baw(sc, an, tid, bf);
+ bf->bf_state.bfs_addedbaw = 1;
+
+ /*
+ * XXX enforce ACK for aggregate frames (this needs to be
+ * XXX handled more gracefully?
+ */
+ if (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) {
+ device_printf(sc->sc_dev,
+ "%s: HAL_TXDESC_NOACK set for an aggregate frame?\n",
+ __func__);
+ bf->bf_state.bfs_txflags &= (~HAL_TXDESC_NOACK);
+ }
+
+ /*
+ * Add the now owned buffer (which isn't
+ * on the software TXQ any longer) to our
+ * aggregate frame list.
+ */
+ TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
+ nframes ++;
+
+ /* Completion handler */
+ bf->bf_comp = ath_tx_aggr_comp;
+
+ /*
+ * add padding for previous frame to aggregation length
+ */
+ al += bpad + al_delta;
+
+ /*
+ * Calculate delimiters needed for the current frame
+ */
+ bf->bf_state.bfs_ndelim =
+ ath_compute_num_delims(sc, bf_first,
+ bf->bf_state.bfs_pktlen);
+
+ /*
+ * Calculate the padding needed from this set of delimiters,
+ * used when calculating if the next frame will fit in
+ * the aggregate.
+ */
+ bpad = PADBYTES(al_delta) + (bf->bf_state.bfs_ndelim << 2);
+
+ /*
+ * Chain the buffers together
+ */
+ if (bf_prev)
+ bf_prev->bf_next = bf;
+ bf_prev = bf;
+
+ /*
+ * If we're leaking frames, just return at this point;
+ * we've queued a single frame and we don't want to add
+ * any more.
+ */
+ if (tid->an->an_leak_count) {
+ status = ATH_AGGR_LEAK_CLOSED;
+ break;
+ }
+
+#if 0
+ /*
+ * terminate aggregation on a small packet boundary
+ */
+ if (bf->bf_state.bfs_pktlen < ATH_AGGR_MINPLEN) {
+ status = ATH_AGGR_SHORTPKT;
+ break;
+ }
+#endif
+
+ }
+
+finish:
+ /*
+ * Just in case the list was empty when we tried to
+ * dequeue a packet ..
+ */
+ if (bf_first) {
+ bf_first->bf_state.bfs_al = al;
+ bf_first->bf_state.bfs_nframes = nframes;
+ }
+ return status;
+}
Modified: trunk/sys/dev/ath/if_ath_tx_ht.h
===================================================================
--- trunk/sys/dev/ath/if_ath_tx_ht.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_ath_tx_ht.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd.
* All rights reserved.
@@ -26,14 +27,38 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_ath_tx_ht.h 250665 2013-05-15 18:33:05Z adrian $
*/
#ifndef __IF_ATH_TX_HT_H__
#define __IF_ATH_TX_HT_H__
+enum {
+ MCS_HT20,
+ MCS_HT20_SGI,
+ MCS_HT40,
+ MCS_HT40_SGI,
+};
+
+typedef enum {
+ ATH_AGGR_DONE,
+ ATH_AGGR_BAW_CLOSED,
+ ATH_AGGR_LIMITED,
+ ATH_AGGR_SHORTPKT,
+ ATH_AGGR_8K_LIMITED,
+ ATH_AGGR_ERROR,
+ ATH_AGGR_NONAGGR,
+ ATH_AGGR_LEAK_CLOSED,
+} ATH_AGGR_STATUS;
+
+extern int ath_max_4ms_framelen[4][32];
+
+extern void ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf);
+
extern void ath_buf_set_rate(struct ath_softc *sc,
- struct ieee80211_node *ni, struct ath_buf *bf,
- int pktlen, int flags, uint8_t ctsrate, int is_pspoll,
- uint8_t *rix, uint8_t *try);
+ struct ieee80211_node *ni, struct ath_buf *bf);
+extern ATH_AGGR_STATUS
+ ath_tx_form_aggr(struct ath_softc *sc, struct ath_node *an,
+ struct ath_tid *tid, ath_bufhead *bf_q);
+
#endif
Modified: trunk/sys/dev/ath/if_athdfs.h
===================================================================
--- trunk/sys/dev/ath/if_athdfs.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_athdfs.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_athdfs.h 244946 2013-01-02 01:36:10Z adrian $
*/
#ifndef __IF_ATHDFS_H__
#define __IF_ATHDFS_H__
@@ -33,9 +34,10 @@
extern int ath_dfs_attach(struct ath_softc *sc);
extern int ath_dfs_detach(struct ath_softc *sc);
-extern void ath_dfs_radar_enable(struct ath_softc *,
+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 int ath_dfs_radar_disable(struct ath_softc *sc);
+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);
Modified: trunk/sys/dev/ath/if_athioctl.h
===================================================================
--- trunk/sys/dev/ath/if_athioctl.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_athioctl.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_athioctl.h 250665 2013-05-15 18:33:05Z adrian $
*/
/*
@@ -35,6 +36,21 @@
#ifndef _DEV_ATH_ATHIOCTL_H
#define _DEV_ATH_ATHIOCTL_H
+struct ath_tx_aggr_stats {
+ u_int32_t aggr_pkts[64];
+ u_int32_t aggr_single_pkt;
+ u_int32_t aggr_nonbaw_pkt;
+ u_int32_t aggr_aggr_pkt;
+ u_int32_t aggr_baw_closed_single_pkt;
+ u_int32_t aggr_low_hwq_single_pkt;
+ u_int32_t aggr_sched_nopkt;
+ u_int32_t aggr_rts_aggr_limited;
+};
+
+struct ath_intr_stats {
+ u_int32_t sync_intr[32];
+};
+
struct ath_stats {
u_int32_t ast_watchdog; /* device reset by watchdog */
u_int32_t ast_hardware; /* fatal hardware error interrupts */
@@ -134,11 +150,29 @@
u_int32_t ast_tx_xtxop; /* tx exceeded TXOP */
u_int32_t ast_tx_timerexpired; /* tx exceeded TX_TIMER */
u_int32_t ast_tx_desccfgerr; /* tx desc cfg error */
- u_int32_t ast_pad[13];
+ u_int32_t ast_tx_swretries; /* software TX retries */
+ u_int32_t ast_tx_swretrymax; /* software TX retry max limit reach */
+ u_int32_t ast_tx_data_underrun;
+ u_int32_t ast_tx_delim_underrun;
+ u_int32_t ast_tx_aggr_failall; /* aggregate TX failed in its entirety */
+ u_int32_t ast_tx_getnobuf;
+ u_int32_t ast_tx_getbusybuf;
+ u_int32_t ast_tx_intr;
+ u_int32_t ast_rx_intr;
+ 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_rx_keymiss;
+ u_int32_t ast_tx_swfiltered;
+ u_int32_t ast_tx_node_psq_overflow;
+ u_int32_t ast_rx_stbc; /* RX STBC frame */
+ u_int32_t ast_tx_nodeq_overflow; /* node sw queue overflow */
+ u_int32_t ast_pad[12];
};
#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" */
@@ -156,10 +190,57 @@
#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)
+#define SIOCGATHRATESTATS _IOWR('i', 150, 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) | \
@@ -169,8 +250,95 @@
(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
+
+/*
+ * AR9380 and later chips are 3x3, which requires
+ * 5 EVM DWORDs in HT40 mode.
+ */
+#define ATH_RADIOTAP_MAX_EVM 5
+
+/*
+ * 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_EVM]; /* 5 * 4 = 20 */
+
+ 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_flags; /* General flags */
+#define ATH_VENDOR_PKT_RX 0x01
+#define ATH_VENDOR_PKT_TX 0x02
+#define ATH_VENDOR_PKT_RXPHYERR 0x04
+#define ATH_VENDOR_PKT_ISAGGR 0x08
+#define ATH_VENDOR_PKT_MOREAGGR 0x10
+
+ uint8_t vh_rx_hwrate; /* hardware RX ratecode */
+ uint8_t vh_rs_flags; /* RX HAL flags */
+ uint8_t vh_pad[2]; /* pad to DWORD 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;
@@ -182,6 +350,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 ( \
@@ -236,4 +424,28 @@
#define DFS_PARAM_ENABLE 32
#define DFS_PARAM_EN_EXTCH 33
+/*
+ * Spectral ioctl parameter types
+ */
+#define SPECTRAL_PARAM_FFT_PERIOD 1
+#define SPECTRAL_PARAM_SS_PERIOD 2
+#define SPECTRAL_PARAM_SS_COUNT 3
+#define SPECTRAL_PARAM_SS_SHORT_RPT 4
+#define SPECTRAL_PARAM_ENABLED 5
+#define SPECTRAL_PARAM_ACTIVE 6
+
+/*
+ * Spectral control parameters
+ */
+#define SIOCGATHSPECTRAL _IOWR('i', 151, struct ath_diag)
+
+#define SPECTRAL_CONTROL_ENABLE 2
+#define SPECTRAL_CONTROL_DISABLE 3
+#define SPECTRAL_CONTROL_START 4
+#define SPECTRAL_CONTROL_STOP 5
+#define SPECTRAL_CONTROL_GET_PARAMS 6
+#define SPECTRAL_CONTROL_SET_PARAMS 7
+#define SPECTRAL_CONTROL_ENABLE_AT_RESET 8
+#define SPECTRAL_CONTROL_DISABLE_AT_RESET 9
+
#endif /* _DEV_ATH_ATHIOCTL_H */
Modified: trunk/sys/dev/ath/if_athrate.h
===================================================================
--- trunk/sys/dev/ath/if_athrate.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_athrate.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2004 Video54 Technologies, Inc.
@@ -27,7 +28,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_athrate.h 249578 2013-04-17 07:21:30Z adrian $
*/
#ifndef _ATH_RATECTRL_H_
#define _ATH_RATECTRL_H_
@@ -77,7 +78,25 @@
struct ath_ratectrl *ath_rate_attach(struct ath_softc *);
void ath_rate_detach(struct ath_ratectrl *);
+#define ATH_RC_NUM 4
+#define ATH_RC_DS_FLAG 0x01 /* dual-stream rate */
+#define ATH_RC_CW40_FLAG 0x02 /* use HT40 */
+#define ATH_RC_SGI_FLAG 0x04 /* use short-GI */
+#define ATH_RC_HT_FLAG 0x08 /* use HT */
+#define ATH_RC_RTSCTS_FLAG 0x10 /* enable RTS/CTS protection */
+#define ATH_RC_STBC_FLAG 0x20 /* enable STBC */
+#define ATH_RC_TS_FLAG 0x40 /* triple-stream rate */
+
+struct ath_rc_series {
+ uint8_t rix; /* ratetable index, not rate code */
+ uint8_t ratecode; /* hardware rate code */
+ uint8_t tries;
+ uint8_t tx_power_cap;
+ uint16_t flags;
+ uint16_t max4msframelen;
+};
+
/*
* State storage handling.
*/
@@ -105,7 +124,7 @@
* Return the four TX rate index and try counts for the current data packet.
*/
void ath_rate_getxtxrates(struct ath_softc *sc, struct ath_node *an,
- uint8_t rix0, uint8_t *rix, uint8_t *try);
+ uint8_t rix0, struct ath_rc_series *rc);
/*
* Return the transmit info for a data packet. If multi-rate state
@@ -127,8 +146,24 @@
* supplied transmit descriptor. The routine is invoked both
* for packets that were successfully sent and for those that
* failed (consult the descriptor for details).
+ *
+ * For A-MPDU frames, nframes and nbad indicate how many frames
+ * were in the aggregate, and how many failed.
*/
struct ath_buf;
void ath_rate_tx_complete(struct ath_softc *, struct ath_node *,
- const struct ath_buf *);
+ 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_ */
Modified: trunk/sys/dev/ath/if_athvar.h
===================================================================
--- trunk/sys/dev/ath/if_athvar.h 2018-05-28 00:22:50 UTC (rev 10126)
+++ trunk/sys/dev/ath/if_athvar.h 2018-05-28 00:25:20 UTC (rev 10127)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
* All rights reserved.
@@ -26,7 +27,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/ath/if_athvar.h 251655 2013-06-12 14:52:57Z adrian $
*/
/*
@@ -35,15 +36,28 @@
#ifndef _DEV_ATH_ATHVAR_H
#define _DEV_ATH_ATHVAR_H
+#include <machine/atomic.h>
+
#include <dev/ath/ath_hal/ah.h>
#include <dev/ath/ath_hal/ah_desc.h>
#include <net80211/ieee80211_radiotap.h>
#include <dev/ath/if_athioctl.h>
#include <dev/ath/if_athrate.h>
+#ifdef ATH_DEBUG_ALQ
+#include <dev/ath/if_ath_alq.h>
+#endif
#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
@@ -64,7 +78,7 @@
#define ATH_TXMGTTRY 4 /* xmit attempts for mgt/ctl frames */
#define ATH_TXINTR_PERIOD 5 /* max number of batched tx descriptors */
-#define ATH_BEACON_AIFS_DEFAULT 0 /* default aifs for ap beacon q */
+#define ATH_BEACON_AIFS_DEFAULT 1 /* default aifs for ap beacon q */
#define ATH_BEACON_CWMIN_DEFAULT 0 /* default cwmin for ap beacon q */
#define ATH_BEACON_CWMAX_DEFAULT 0 /* default cwmax for ap beacon q */
@@ -83,12 +97,93 @@
struct kthread;
struct ath_buf;
+#define ATH_TID_MAX_BUFS (2 * IEEE80211_AGGR_BAWMAX)
+
+/*
+ * Per-TID state
+ *
+ * Note that TID 16 (WME_NUM_TID+1) is for handling non-QoS frames.
+ */
+struct ath_tid {
+ TAILQ_HEAD(,ath_buf) tid_q; /* pending buffers */
+ struct ath_node *an; /* pointer to parent */
+ int tid; /* tid */
+ int ac; /* which AC gets this trafic */
+ int hwq_depth; /* how many buffers are on HW */
+ u_int axq_depth; /* SW queue depth */
+
+ struct {
+ TAILQ_HEAD(,ath_buf) tid_q; /* filtered queue */
+ u_int axq_depth; /* SW queue depth */
+ } filtq;
+
+ /*
+ * Entry on the ath_txq; when there's traffic
+ * to send
+ */
+ TAILQ_ENTRY(ath_tid) axq_qelem;
+ int sched;
+ int paused; /* >0 if the TID has been paused */
+
+ /*
+ * These are flags - perhaps later collapse
+ * down to a single uint32_t ?
+ */
+ int addba_tx_pending; /* TX ADDBA pending */
+ int bar_wait; /* waiting for BAR */
+ int bar_tx; /* BAR TXed */
+ int isfiltered; /* is this node currently filtered */
+
+ /*
+ * Is the TID being cleaned up after a transition
+ * from aggregation to non-aggregation?
+ * When this is set to 1, this TID will be paused
+ * and no further traffic will be queued until all
+ * the hardware packets pending for this TID have been
+ * TXed/completed; at which point (non-aggregation)
+ * traffic will resume being TXed.
+ */
+ int cleanup_inprogress;
+ /*
+ * How many hardware-queued packets are
+ * waiting to be cleaned up.
+ * This is only valid if cleanup_inprogress is 1.
+ */
+ int incomp;
+
+ /*
+ * The following implements a ring representing
+ * the frames in the current BAW.
+ * To avoid copying the array content each time
+ * the BAW is moved, the baw_head/baw_tail point
+ * to the current BAW begin/end; when the BAW is
+ * shifted the head/tail of the array are also
+ * appropriately shifted.
+ */
+ /* active tx buffers, beginning at current BAW */
+ struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+ /* where the baw head is in the array */
+ int baw_head;
+ /* where the BAW tail is in the array */
+ int baw_tail;
+};
+
/* driver-specific node state */
struct ath_node {
struct ieee80211_node an_node; /* base class */
u_int8_t an_mgmtrix; /* min h/w rate index */
u_int8_t an_mcastrix; /* mcast h/w rate index */
+ uint32_t an_is_powersave; /* node is sleeping */
+ uint32_t an_stack_psq; /* net80211 psq isn't empty */
+ uint32_t an_tim_set; /* TIM has been set */
struct ath_buf *an_ff_buf[WME_NUM_AC]; /* ff staging area */
+ struct ath_tid an_tid[IEEE80211_TID_SIZE]; /* per-TID state */
+ char an_name[32]; /* eg "wlan0_a1" */
+ struct mtx an_mtx; /* protecting the rate control state */
+ uint32_t an_swq_depth; /* how many SWQ packets for this
+ node */
+ int clrdmask; /* has clrdmask been set */
+ uint32_t an_leak_count; /* How many frames to leak during pause */
/* variable-length rate control state follows */
};
#define ATH_NODE(ni) ((struct ath_node *)(ni))
@@ -108,11 +203,18 @@
((((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 {
- STAILQ_ENTRY(ath_buf) bf_list;
+ TAILQ_ENTRY(ath_buf) bf_list;
+ struct ath_buf * bf_next; /* next buffer in the aggregate */
int bf_nseg;
- uint16_t bf_txflags; /* tx descriptor flags */
+ HAL_STATUS bf_rxstatus;
uint16_t bf_flags; /* status flags (below) */
+ uint16_t bf_descid; /* 16 bit descriptor ID */
struct ath_desc *bf_desc; /* virtual addr of desc */
struct ath_desc_status bf_status; /* tx/rx status */
bus_addr_t bf_daddr; /* physical addr of desc */
@@ -119,14 +221,84 @@
bus_dmamap_t bf_dmamap; /* DMA map for mbuf chain */
struct mbuf *bf_m; /* mbuf for buf */
struct ieee80211_node *bf_node; /* pointer to the node */
+ struct ath_desc *bf_lastds; /* last descriptor for comp status */
+ struct ath_buf *bf_last; /* last buffer in aggregate, or self for non-aggregate */
bus_size_t bf_mapsize;
#define ATH_MAX_SCATTER ATH_TXDESC /* max(tx,rx,beacon) desc's */
bus_dma_segment_t bf_segs[ATH_MAX_SCATTER];
+ uint32_t bf_nextfraglen; /* length of next fragment */
+
+ /* Completion function to call on TX complete (fail or not) */
+ /*
+ * "fail" here is set to 1 if the queue entries were removed
+ * through a call to ath_tx_draintxq().
+ */
+ void(* bf_comp) (struct ath_softc *sc, struct ath_buf *bf, int fail);
+
+ /* This state is kept to support software retries and aggregation */
+ struct {
+ 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 */
+ uint8_t bfs_tx_queue; /* destination hardware TX queue */
+
+ u_int32_t bfs_aggr:1, /* part of aggregate? */
+ bfs_aggrburst:1, /* part of aggregate burst? */
+ bfs_isretried:1, /* retried frame? */
+ bfs_dobaw:1, /* actually check against BAW? */
+ bfs_addedbaw:1, /* has been added to the BAW */
+ bfs_shpream:1, /* use short preamble */
+ 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 */
+
+ /*
+ * These fields are passed into the
+ * descriptor setup functions.
+ */
+
+ /* Make this an 8 bit value? */
+ HAL_PKT_TYPE bfs_atype; /* packet type */
+
+ uint32_t bfs_pktlen; /* length of this packet */
+
+ uint16_t bfs_hdrlen; /* length of this packet header */
+ uint16_t bfs_al; /* length of aggregate */
+
+ 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 */
+ 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;
+
+ /* 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 STAILQ_HEAD(, ath_buf) ath_bufhead;
+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 */
+#define ATH_BUF_FIFOEND 0x00000004
+#define ATH_BUF_FIFOPTR 0x00000008
+#define ATH_BUF_FLAGS_CLONE (ATH_BUF_MGMT)
+
/*
* DMA state for tx/rx descriptors.
*/
@@ -133,6 +305,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;
@@ -151,42 +324,137 @@
* hardware queue).
*/
struct ath_txq {
+ struct ath_softc *axq_softc; /* Needed for scheduling */
u_int axq_qnum; /* hardware q number */
#define ATH_TXQ_SWQ (HAL_NUM_TX_QUEUES+1) /* qnum for s/w only queue */
u_int axq_ac; /* WME AC */
u_int axq_flags;
-#define ATH_TXQ_PUTPENDING 0x0001 /* ath_hal_puttxbuf pending */
+//#define ATH_TXQ_PUTPENDING 0x0001 /* ath_hal_puttxbuf pending */
+#define ATH_TXQ_PUTRUNNING 0x0002 /* ath_hal_puttxbuf has been called */
u_int axq_depth; /* queue depth (stat only) */
+ u_int axq_aggr_depth; /* how many aggregates are queued */
u_int axq_intrcnt; /* interrupt count */
u_int32_t *axq_link; /* link ptr in last TX desc */
- STAILQ_HEAD(, ath_buf) axq_q; /* transmit queue */
+ TAILQ_HEAD(axq_q_s, ath_buf) axq_q; /* transmit queue */
struct mtx axq_lock; /* lock on q and link */
+
+ /*
+ * This is the FIFO staging buffer when doing EDMA.
+ *
+ * For legacy chips, we just push the head pointer to
+ * the hardware and we ignore this list.
+ *
+ * For EDMA, the staging buffer is treated as normal;
+ * when it's time to push a list of frames to the hardware
+ * we move that list here and we stamp buffers with
+ * flags to identify the beginning/end of that particular
+ * FIFO entry.
+ */
+ struct {
+ TAILQ_HEAD(axq_q_f_s, ath_buf) axq_q;
+ u_int axq_depth;
+ } fifo;
+ u_int axq_fifo_depth; /* depth of FIFO frames */
+
+ /*
+ * XXX the holdingbf field is protected by the TXBUF lock
+ * for now, NOT the TXQ lock.
+ *
+ * Architecturally, it would likely be better to move
+ * the holdingbf field to a separate array in ath_softc
+ * just to highlight that it's not protected by the normal
+ * TX path lock.
+ */
+ struct ath_buf *axq_holdingbf; /* holding TX buffer */
char axq_name[12]; /* e.g. "ath0_txq4" */
+
+ /* Per-TID traffic queue for software -> hardware TX */
+ /*
+ * This is protected by the general TX path lock, not (for now)
+ * by the TXQ lock.
+ */
+ TAILQ_HEAD(axq_t_s,ath_tid) axq_tidq;
};
#define ATH_TXQ_LOCK_INIT(_sc, _tq) do { \
- snprintf((_tq)->axq_name, sizeof((_tq)->axq_name), "%s_txq%u", \
- device_get_nameunit((_sc)->sc_dev), (_tq)->axq_qnum); \
- mtx_init(&(_tq)->axq_lock, (_tq)->axq_name, NULL, MTX_DEF); \
-} while (0)
+ snprintf((_tq)->axq_name, sizeof((_tq)->axq_name), "%s_txq%u", \
+ device_get_nameunit((_sc)->sc_dev), (_tq)->axq_qnum); \
+ mtx_init(&(_tq)->axq_lock, (_tq)->axq_name, NULL, MTX_DEF); \
+ } while (0)
#define ATH_TXQ_LOCK_DESTROY(_tq) mtx_destroy(&(_tq)->axq_lock)
#define ATH_TXQ_LOCK(_tq) mtx_lock(&(_tq)->axq_lock)
#define ATH_TXQ_UNLOCK(_tq) mtx_unlock(&(_tq)->axq_lock)
#define ATH_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, MA_OWNED)
+#define ATH_TXQ_UNLOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, \
+ MA_NOTOWNED)
+
+#define ATH_NODE_LOCK(_an) mtx_lock(&(_an)->an_mtx)
+#define ATH_NODE_UNLOCK(_an) mtx_unlock(&(_an)->an_mtx)
+#define ATH_NODE_LOCK_ASSERT(_an) mtx_assert(&(_an)->an_mtx, MA_OWNED)
+#define ATH_NODE_UNLOCK_ASSERT(_an) mtx_assert(&(_an)->an_mtx, \
+ MA_NOTOWNED)
+
+/*
+ * These are for the hardware queue.
+ */
+#define ATH_TXQ_INSERT_HEAD(_tq, _elm, _field) do { \
+ TAILQ_INSERT_HEAD(&(_tq)->axq_q, (_elm), _field); \
+ (_tq)->axq_depth++; \
+} while (0)
#define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
- STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
+ TAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
(_tq)->axq_depth++; \
} while (0)
-#define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
- STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \
+#define ATH_TXQ_REMOVE(_tq, _elm, _field) do { \
+ TAILQ_REMOVE(&(_tq)->axq_q, _elm, _field); \
(_tq)->axq_depth--; \
} while (0)
-/* NB: this does not do the "head empty check" that STAILQ_LAST does */
-#define ATH_TXQ_LAST(_tq) \
- ((struct ath_buf *)(void *) \
- ((char *)((_tq)->axq_q.stqh_last) - __offsetof(struct ath_buf, bf_list)))
+#define ATH_TXQ_FIRST(_tq) TAILQ_FIRST(&(_tq)->axq_q)
+#define ATH_TXQ_LAST(_tq, _field) TAILQ_LAST(&(_tq)->axq_q, _field)
+/*
+ * These are for the TID software queue.
+ */
+#define ATH_TID_INSERT_HEAD(_tq, _elm, _field) do { \
+ TAILQ_INSERT_HEAD(&(_tq)->tid_q, (_elm), _field); \
+ (_tq)->axq_depth++; \
+ (_tq)->an->an_swq_depth++; \
+} while (0)
+#define ATH_TID_INSERT_TAIL(_tq, _elm, _field) do { \
+ TAILQ_INSERT_TAIL(&(_tq)->tid_q, (_elm), _field); \
+ (_tq)->axq_depth++; \
+ (_tq)->an->an_swq_depth++; \
+} while (0)
+#define ATH_TID_REMOVE(_tq, _elm, _field) do { \
+ TAILQ_REMOVE(&(_tq)->tid_q, _elm, _field); \
+ (_tq)->axq_depth--; \
+ (_tq)->an->an_swq_depth--; \
+} while (0)
+#define ATH_TID_FIRST(_tq) TAILQ_FIRST(&(_tq)->tid_q)
+#define ATH_TID_LAST(_tq, _field) TAILQ_LAST(&(_tq)->tid_q, _field)
+
+/*
+ * These are for the TID filtered frame queue
+ */
+#define ATH_TID_FILT_INSERT_HEAD(_tq, _elm, _field) do { \
+ TAILQ_INSERT_HEAD(&(_tq)->filtq.tid_q, (_elm), _field); \
+ (_tq)->axq_depth++; \
+ (_tq)->an->an_swq_depth++; \
+} while (0)
+#define ATH_TID_FILT_INSERT_TAIL(_tq, _elm, _field) do { \
+ TAILQ_INSERT_TAIL(&(_tq)->filtq.tid_q, (_elm), _field); \
+ (_tq)->axq_depth++; \
+ (_tq)->an->an_swq_depth++; \
+} while (0)
+#define ATH_TID_FILT_REMOVE(_tq, _elm, _field) do { \
+ TAILQ_REMOVE(&(_tq)->filtq.tid_q, _elm, _field); \
+ (_tq)->axq_depth--; \
+ (_tq)->an->an_swq_depth--; \
+} while (0)
+#define ATH_TID_FILT_FIRST(_tq) TAILQ_FIRST(&(_tq)->filtq.tid_q)
+#define ATH_TID_FILT_LAST(_tq, _field) TAILQ_LAST(&(_tq)->filtq.tid_q,_field)
+
struct ath_vap {
struct ieee80211vap av_vap; /* base class */
int av_bslot; /* beacon slot index */
@@ -199,6 +467,10 @@
int (*av_newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
void (*av_bmiss)(struct ieee80211vap *);
+ void (*av_node_ps)(struct ieee80211_node *, int);
+ int (*av_set_tim)(struct ieee80211_node *, int);
+ void (*av_recv_pspoll)(struct ieee80211_node *,
+ struct mbuf *);
};
#define ATH_VAP(vap) ((struct ath_vap *)(vap))
@@ -205,10 +477,70 @@
struct taskqueue;
struct ath_tx99;
+/*
+ * Whether to reset the TX/RX queue with or without
+ * a queue flush.
+ */
+typedef enum {
+ ATH_RESET_DEFAULT = 0,
+ ATH_RESET_NOLOSS = 1,
+ ATH_RESET_FULL = 2,
+} ATH_RESET_TYPE;
+
+struct ath_rx_methods {
+ void (*recv_sched_queue)(struct ath_softc *sc,
+ HAL_RX_QUEUE q, int dosched);
+ void (*recv_sched)(struct ath_softc *sc, int dosched);
+ 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_edma_fifo {
+ struct ath_buf **m_fifo;
+ int m_fifolen;
+ int m_fifo_head;
+ int m_fifo_tail;
+ int m_fifo_depth;
+};
+
+struct ath_tx_methods {
+ int (*xmit_setup)(struct ath_softc *sc);
+ int (*xmit_teardown)(struct ath_softc *sc);
+ void (*xmit_attach_comp_func)(struct ath_softc *sc);
+
+ void (*xmit_dma_restart)(struct ath_softc *sc,
+ struct ath_txq *txq);
+ void (*xmit_handoff)(struct ath_softc *sc,
+ struct ath_txq *txq, struct ath_buf *bf);
+ void (*xmit_drain)(struct ath_softc *sc,
+ ATH_RESET_TYPE reset_type);
+};
+
struct ath_softc {
struct ifnet *sc_ifp; /* interface common */
struct ath_stats sc_stats; /* interface statistics */
- int sc_debug;
+ struct ath_tx_aggr_stats sc_aggr_stats;
+ struct ath_intr_stats sc_intr_stats;
+ uint64_t sc_debug;
+ uint64_t sc_ktrdebug;
int sc_nvaps; /* # vaps */
int sc_nstavaps; /* # station vaps */
int sc_nmeshvaps; /* # mbss vaps */
@@ -216,6 +548,26 @@
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 */
+ ath_bufhead sc_rx_rxlist[HAL_NUM_RX_QUEUES]; /* deferred RX completion */
+ struct ath_tx_methods sc_tx;
+ struct ath_tx_edma_fifo sc_txedma[HAL_NUM_TX_QUEUES];
+
+ /*
+ * This is (currently) protected by the TX queue lock;
+ * it should migrate to a separate lock later
+ * so as to minimise contention.
+ */
+ ath_bufhead sc_txbuf_list;
+
+ 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;
HAL_BUS_TAG sc_st; /* bus space tag */
@@ -222,14 +574,28 @@
HAL_BUS_HANDLE sc_sh; /* bus space handle */
bus_dma_tag_t sc_dmat; /* bus DMA tag */
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 mtx sc_tx_mtx; /* TX handling/comp mutex */
+ char sc_tx_mtx_name[32];
+ struct mtx sc_tx_ic_mtx; /* TX queue mutex */
+ char sc_tx_ic_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 */
struct ath_tx99 *sc_tx99; /* tx99 adjunct state */
void (*sc_setdefantenna)(struct ath_softc *, u_int);
- unsigned int sc_invalid : 1,/* disable hardware accesses */
+
+ /*
+ * First set of flags.
+ */
+ uint32_t sc_invalid : 1,/* disable hardware accesses */
sc_mrretry : 1,/* multi-rate retry support */
+ sc_mrrprot : 1,/* MRR + protection support */
sc_softled : 1,/* enable LED gpio status */
+ sc_hardled : 1,/* enable MAC LED status */
sc_splitmic : 1,/* split TKIP MIC keys */
sc_needmib : 1,/* enable MIB stats intr */
sc_diversity: 1,/* enable rx diversity */
@@ -255,8 +621,26 @@
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_kickpcu : 1,/* kick PCU RX on next RX proc */
- sc_rxtsf32 : 1;/* RX dec TSF is 32 bits */
+ sc_rxtsf32 : 1,/* RX dec TSF is 32 bits */
+ sc_isedma : 1;/* supports EDMA */
+
+ /*
+ * Second set of flags.
+ */
+ u_int32_t sc_use_ent : 1,
+ sc_rx_stbc : 1,
+ sc_tx_stbc : 1,
+ sc_hasenforcetxop : 1, /* support enforce TxOP */
+ sc_hasdivcomb : 1, /* RX diversity combining */
+ sc_rx_lnamixer : 1; /* RX using LNA mixing */
+
+ int sc_cabq_enable; /* Enable cabq transmission */
+
+ /*
+ * Enterprise mode configuration for AR9380 and later chipsets.
+ */
+ uint32_t sc_ent_cfg;
+
uint32_t sc_eerd; /* regdomain from EEPROM */
uint32_t sc_eecc; /* country code from EEPROM */
/* rate tables */
@@ -282,10 +666,32 @@
u_int sc_fftxqmin; /* min frames before staging */
u_int sc_fftxqmax; /* max frames before drop */
u_int sc_txantenna; /* tx antenna (fixed or auto) */
+
HAL_INT sc_imask; /* interrupt mask copy */
+
+ /*
+ * These are modified in the interrupt handler as well as
+ * the task queues and other contexts. Thus these must be
+ * protected by a mutex, or they could clash.
+ *
+ * For now, access to these is behind the ATH_LOCK,
+ * just to save time.
+ */
+ uint32_t sc_txq_active; /* bitmap of active TXQs */
+ uint32_t sc_kickpcu; /* whether to kick the PCU */
+ uint32_t sc_rxproc_cnt; /* In RX processing */
+ uint32_t sc_txproc_cnt; /* In TX processing */
+ uint32_t sc_txstart_cnt; /* In TX output (raw/start) */
+ uint32_t sc_inreset_cnt; /* In active reset/chanchange */
+ uint32_t sc_txrx_cnt; /* refcount on stop/start'ing TX */
+ uint32_t sc_intr_cnt; /* refcount on interrupt handling */
+
u_int sc_keymax; /* size of key cache */
u_int8_t sc_keymap[ATH_KEYBYTES];/* key use bit map */
+ /*
+ * Software based LED blinking
+ */
u_int sc_ledpin; /* GPIO pin for driving LED */
u_int sc_ledon; /* pin setting for LED on */
u_int sc_ledidle; /* idle polling interval */
@@ -294,12 +700,17 @@
u_int16_t sc_ledoff; /* off time for current blink */
struct callout sc_ledtimer; /* led off timer */
+ /*
+ * Hardware based LED blinking
+ */
+ int sc_led_pwr_pin; /* MAC power LED GPIO pin */
+ int sc_led_net_pin; /* MAC network LED GPIO pin */
+
u_int sc_rfsilentpin; /* GPIO pin for rfkill int */
u_int sc_rfsilentpol; /* pin setting for rfkill on */
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 */
@@ -311,7 +722,12 @@
u_int sc_monpass; /* frames to pass in mon.mode */
struct ath_descdma sc_txdma; /* TX descriptors */
+ uint16_t sc_txbuf_descid;
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 ath_descdma sc_txsdma; /* EDMA TX status desc's */
struct mtx sc_txbuflock; /* txbuf lock */
char sc_txname[12]; /* e.g. "ath0_buf" */
u_int sc_txqsetup; /* h/w queues setup */
@@ -319,6 +735,12 @@
struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
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;
@@ -332,6 +754,8 @@
struct ath_txq *sc_cabq; /* tx q for cab frames */
struct task sc_bmisstask; /* bmiss int processing */
struct task sc_bstucktask; /* stuck beacon processing */
+ struct task sc_resettask; /* interface reset task */
+ struct task sc_fataltask; /* fatal task */
enum {
OK, /* no change needed */
UPDATE, /* update pending */
@@ -357,13 +781,90 @@
u_int32_t sc_avgtsfdeltap;/* TDMA slot adjust (+) */
u_int32_t sc_avgtsfdeltam;/* TDMA slot adjust (-) */
uint16_t *sc_eepromdata; /* Local eeprom data, if AR9100 */
- int sc_txchainmask; /* currently configured TX chainmask */
- int sc_rxchainmask; /* currently configured RX chainmask */
+ uint32_t sc_txchainmask; /* hardware TX chainmask */
+ uint32_t sc_rxchainmask; /* hardware RX chainmask */
+ uint32_t sc_cur_txchainmask; /* currently configured TX chainmask */
+ uint32_t sc_cur_rxchainmask; /* currently configured RX chainmask */
+ uint32_t sc_rts_aggr_limit; /* TX limit on RTS aggregates */
+ int sc_aggr_limit; /* TX limit on all aggregates */
+ int sc_delim_min_pad; /* Minimum delimiter count */
+ /* Queue limits */
+
+ /*
+ * To avoid queue starvation in congested conditions,
+ * these parameters tune the maximum number of frames
+ * queued to the data/mcastq before they're dropped.
+ *
+ * This is to prevent:
+ * + a single destination overwhelming everything, including
+ * management/multicast frames;
+ * + multicast frames overwhelming everything (when the
+ * air is sufficiently busy that cabq can't drain.)
+ * + A node in powersave shouldn't be allowed to exhaust
+ * all available mbufs;
+ *
+ * These implement:
+ * + data_minfree is the maximum number of free buffers
+ * overall to successfully allow a data frame.
+ *
+ * + mcastq_maxdepth is the maximum depth allowed of the cabq.
+ */
+ int sc_txq_node_maxdepth;
+ int sc_txq_data_minfree;
+ int sc_txq_mcastq_maxdepth;
+ int sc_txq_node_psq_maxdepth;
+
+ /*
+ * Software queue twiddles
+ *
+ * hwq_limit_nonaggr:
+ * when to begin limiting non-aggregate frames to the
+ * hardware queue, regardless of the TID.
+ * hwq_limit_aggr:
+ * when to begin limiting A-MPDU frames to the
+ * hardware queue, regardless of the TID.
+ * tid_hwq_lo: how low the per-TID hwq count has to be before the
+ * TID will be scheduled again
+ * tid_hwq_hi: how many frames to queue to the HWQ before the TID
+ * stops being scheduled.
+ */
+ int sc_hwq_limit_nonaggr;
+ int sc_hwq_limit_aggr;
+ int sc_tid_hwq_lo;
+ int sc_tid_hwq_hi;
+
/* DFS related state */
void *sc_dfs; /* Used by an optional DFS module */
int sc_dodfs; /* Whether to enable DFS rx filter bits */
struct task sc_dfstask; /* DFS processing task */
+
+ /* Spectral related state */
+ void *sc_spectral;
+ int sc_dospectral;
+
+ /* LNA diversity related state */
+ void *sc_lna_div;
+ int sc_dolnadiv;
+
+ /* ALQ */
+#ifdef ATH_DEBUG_ALQ
+ struct if_ath_alq sc_alq;
+#endif
+
+ /* TX AMPDU handling */
+ int (*sc_addba_request)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *, int, int, int);
+ int (*sc_addba_response)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *, int, int, int);
+ void (*sc_addba_stop)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *);
+ void (*sc_addba_response_timeout)
+ (struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *);
+ void (*sc_bar_response)(struct ieee80211_node *ni,
+ struct ieee80211_tx_ampdu *tap,
+ int status);
};
#define ATH_LOCK_INIT(_sc) \
@@ -373,7 +874,105 @@
#define ATH_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define ATH_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define ATH_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
+#define ATH_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED)
+/*
+ * The TX lock is non-reentrant and serialises the TX frame send
+ * and completion operations.
+ */
+#define ATH_TX_LOCK_INIT(_sc) do {\
+ snprintf((_sc)->sc_tx_mtx_name, \
+ sizeof((_sc)->sc_tx_mtx_name), \
+ "%s TX lock", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_tx_mtx, (_sc)->sc_tx_mtx_name, \
+ NULL, MTX_DEF); \
+ } while (0)
+#define ATH_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_tx_mtx)
+#define ATH_TX_LOCK(_sc) mtx_lock(&(_sc)->sc_tx_mtx)
+#define ATH_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_tx_mtx)
+#define ATH_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_tx_mtx, \
+ MA_OWNED)
+#define ATH_TX_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_tx_mtx, \
+ MA_NOTOWNED)
+#define ATH_TX_TRYLOCK(_sc) (mtx_owned(&(_sc)->sc_tx_mtx) != 0 && \
+ mtx_trylock(&(_sc)->sc_tx_mtx))
+
+/*
+ * The IC TX lock is non-reentrant and serialises packet queuing from
+ * the upper layers.
+ */
+#define ATH_TX_IC_LOCK_INIT(_sc) do {\
+ snprintf((_sc)->sc_tx_ic_mtx_name, \
+ sizeof((_sc)->sc_tx_ic_mtx_name), \
+ "%s IC TX lock", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_tx_ic_mtx, (_sc)->sc_tx_ic_mtx_name, \
+ NULL, MTX_DEF); \
+ } while (0)
+#define ATH_TX_IC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_tx_ic_mtx)
+#define ATH_TX_IC_LOCK(_sc) mtx_lock(&(_sc)->sc_tx_ic_mtx)
+#define ATH_TX_IC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_tx_ic_mtx)
+#define ATH_TX_IC_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_tx_ic_mtx, \
+ MA_OWNED)
+#define ATH_TX_IC_UNLOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_tx_ic_mtx, \
+ MA_NOTOWNED)
+
+/*
+ * The PCU lock is non-recursive and should be treated as a spinlock.
+ * Although currently the interrupt code is run in netisr context and
+ * doesn't require this, this may change in the future.
+ * Please keep this in mind when protecting certain code paths
+ * with the PCU lock.
+ *
+ * The PCU lock is used to serialise access to the PCU so things such
+ * as TX, RX, state change (eg channel change), channel reset and updates
+ * from interrupt context (eg kickpcu, txqactive bits) do not clash.
+ *
+ * Although the current single-thread taskqueue mechanism protects the
+ * majority of these situations by simply serialising them, there are
+ * a few others which occur at the same time. These include the TX path
+ * (which only acquires ATH_LOCK when recycling buffers to the free list),
+ * ath_set_channel, the channel scanning API and perhaps quite a bit more.
+ */
+#define ATH_PCU_LOCK_INIT(_sc) do {\
+ snprintf((_sc)->sc_pcu_mtx_name, \
+ sizeof((_sc)->sc_pcu_mtx_name), \
+ "%s PCU lock", \
+ device_get_nameunit((_sc)->sc_dev)); \
+ mtx_init(&(_sc)->sc_pcu_mtx, (_sc)->sc_pcu_mtx_name, \
+ NULL, MTX_DEF); \
+ } while (0)
+#define ATH_PCU_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_pcu_mtx)
+#define ATH_PCU_LOCK(_sc) mtx_lock(&(_sc)->sc_pcu_mtx)
+#define ATH_PCU_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_pcu_mtx)
+#define ATH_PCU_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_pcu_mtx, \
+ MA_OWNED)
+#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 { \
@@ -386,7 +985,22 @@
#define ATH_TXBUF_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_txbuflock)
#define ATH_TXBUF_LOCK_ASSERT(_sc) \
mtx_assert(&(_sc)->sc_txbuflock, MA_OWNED)
+#define ATH_TXBUF_UNLOCK_ASSERT(_sc) \
+ mtx_assert(&(_sc)->sc_txbuflock, MA_NOTOWNED)
+#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 *);
@@ -443,8 +1057,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) \
@@ -451,6 +1065,8 @@
OS_REG_READ(_ah, AR_TSF_L32)
#define ath_hal_gettsf64(_ah) \
((*(_ah)->ah_getTsf64)((_ah)))
+#define ath_hal_settsf64(_ah, _val) \
+ ((*(_ah)->ah_setTsf64)((_ah), (_val)))
#define ath_hal_resettsf(_ah) \
((*(_ah)->ah_resetTsf)((_ah)))
#define ath_hal_rxena(_ah) \
@@ -461,8 +1077,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) \
@@ -643,26 +1259,74 @@
#define ath_hal_settpcts(_ah, _tpcts) \
ath_hal_setcapability(_ah, HAL_CAP_TPC_CTS, 0, _tpcts, NULL)
#define ath_hal_hasintmit(_ah) \
- (ath_hal_getcapability(_ah, HAL_CAP_INTMIT, HAL_CAP_INTMIT_PRESENT, NULL) == HAL_OK)
+ (ath_hal_getcapability(_ah, HAL_CAP_INTMIT, \
+ HAL_CAP_INTMIT_PRESENT, NULL) == HAL_OK)
#define ath_hal_getintmit(_ah) \
- (ath_hal_getcapability(_ah, HAL_CAP_INTMIT, HAL_CAP_INTMIT_ENABLE, NULL) == HAL_OK)
+ (ath_hal_getcapability(_ah, HAL_CAP_INTMIT, \
+ HAL_CAP_INTMIT_ENABLE, NULL) == HAL_OK)
#define ath_hal_setintmit(_ah, _v) \
- ath_hal_setcapability(_ah, HAL_CAP_INTMIT, HAL_CAP_INTMIT_ENABLE, _v, NULL)
+ ath_hal_setcapability(_ah, HAL_CAP_INTMIT, \
+ HAL_CAP_INTMIT_ENABLE, _v, NULL)
+
+#define ath_hal_hasenforcetxop(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_ENFORCE_TXOP, 0, NULL) == HAL_OK)
+#define ath_hal_getenforcetxop(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_ENFORCE_TXOP, 1, NULL) == HAL_OK)
+#define ath_hal_setenforcetxop(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_ENFORCE_TXOP, 1, _v, NULL)
+
+#define ath_hal_hasrxlnamixer(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_RX_LNA_MIXING, 0, NULL) == HAL_OK)
+
+#define ath_hal_hasdivantcomb(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_ANT_DIV_COMB, 0, NULL) == HAL_OK)
+
+/* 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) \
(ath_hal_getcapability(_ah, HAL_CAP_TX_CHAINMASK, 0, _ptxchainmask))
+#define ath_hal_setrxchainmask(_ah, _rx) \
+ (ath_hal_setcapability(_ah, HAL_CAP_RX_CHAINMASK, 1, _rx, NULL))
+#define ath_hal_settxchainmask(_ah, _tx) \
+ (ath_hal_setcapability(_ah, HAL_CAP_TX_CHAINMASK, 1, _tx, NULL))
#define ath_hal_split4ktrans(_ah) \
- (ath_hal_getcapability(_ah, HAL_CAP_SPLIT_4KB_TRANS, 0, NULL) == HAL_OK)
+ (ath_hal_getcapability(_ah, HAL_CAP_SPLIT_4KB_TRANS, \
+ 0, NULL) == HAL_OK)
#define ath_hal_self_linked_final_rxdesc(_ah) \
- (ath_hal_getcapability(_ah, HAL_CAP_RXDESC_SELFLINK, 0, NULL) == HAL_OK)
+ (ath_hal_getcapability(_ah, HAL_CAP_RXDESC_SELFLINK, \
+ 0, NULL) == HAL_OK)
#define ath_hal_gtxto_supported(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_GTXTO, 0, NULL) == HAL_OK)
#define ath_hal_has_long_rxdesc_tsf(_ah) \
- (ath_hal_getcapability(_ah, HAL_CAP_LONG_RXDESC_TSF, 0, NULL) == HAL_OK)
-
+ (ath_hal_getcapability(_ah, HAL_CAP_LONG_RXDESC_TSF, \
+ 0, NULL) == HAL_OK)
#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
#define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext, _rs) \
@@ -677,8 +1341,9 @@
_txr1, _txtr1, _txr2, _txtr2, _txr3, _txtr3) \
((*(_ah)->ah_setupXTxDesc)((_ah), (_ds), \
(_txr1), (_txtr1), (_txr2), (_txtr2), (_txr3), (_txtr3)))
-#define ath_hal_filltxdesc(_ah, _ds, _l, _first, _last, _ds0) \
- ((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last), (_ds0)))
+#define ath_hal_filltxdesc(_ah, _ds, _b, _l, _did, _qid, _first, _last, _ds0) \
+ ((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_b), (_l), (_did), (_qid), \
+ (_first), (_last), (_ds0)))
#define ath_hal_txprocdesc(_ah, _ds, _ts) \
((*(_ah)->ah_procTxDesc)((_ah), (_ds), (_ts)))
#define ath_hal_gettxintrtxqs(_ah, _txqs) \
@@ -685,27 +1350,66 @@
((*(_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_gettxrawtxdesc(_ah, _txstatus) \
+ ((*(_ah)->ah_getTxRawTxDesc)((_ah), (_txstatus)))
-#define ath_hal_chaintxdesc(_ah, _ds, _pktlen, _hdrlen, _type, _keyix, \
- _cipher, _delims, _seglen, _first, _last) \
- ((*(_ah)->ah_chainTxDesc((_ah), (_ds), (_pktlen), (_hdrlen), \
- (_type), (_keyix), (_cipher), (_delims), (_seglen), \
- (_first), (_last))))
#define ath_hal_setupfirsttxdesc(_ah, _ds, _aggrlen, _flags, _txpower, \
_txr0, _txtr0, _antm, _rcr, _rcd) \
((*(_ah)->ah_setupFirstTxDesc)((_ah), (_ds), (_aggrlen), (_flags), \
(_txpower), (_txr0), (_txtr0), (_antm), (_rcr), (_rcd)))
+#define ath_hal_chaintxdesc(_ah, _ds, _bl, _sl, _pktlen, _hdrlen, _type, \
+ _keyix, _cipher, _delims, _first, _last, _lastaggr) \
+ ((*(_ah)->ah_chainTxDesc)((_ah), (_ds), (_bl), (_sl), \
+ (_pktlen), (_hdrlen), (_type), (_keyix), (_cipher), (_delims), \
+ (_first), (_last), (_lastaggr)))
#define ath_hal_setuplasttxdesc(_ah, _ds, _ds0) \
((*(_ah)->ah_setupLastTxDesc)((_ah), (_ds), (_ds0)))
+
#define ath_hal_set11nratescenario(_ah, _ds, _dur, _rt, _series, _ns, _flags) \
((*(_ah)->ah_set11nRateScenario)((_ah), (_ds), (_dur), (_rt), \
(_series), (_ns), (_flags)))
-#define ath_hal_set11naggrmiddle(_ah, _ds, _num) \
- ((*(_ah)->ah_set11nAggrMiddle((_ah), (_ds), (_num))))
+
+#define ath_hal_set11n_aggr_first(_ah, _ds, _len, _num) \
+ ((*(_ah)->ah_set11nAggrFirst)((_ah), (_ds), (_len), (_num)))
+#define ath_hal_set11n_aggr_middle(_ah, _ds, _num) \
+ ((*(_ah)->ah_set11nAggrMiddle)((_ah), (_ds), (_num)))
+#define ath_hal_set11n_aggr_last(_ah, _ds) \
+ ((*(_ah)->ah_set11nAggrLast)((_ah), (_ds)))
+
#define ath_hal_set11nburstduration(_ah, _ds, _dur) \
((*(_ah)->ah_set11nBurstDuration)((_ah), (_ds), (_dur)))
+#define ath_hal_clr11n_aggr(_ah, _ds) \
+ ((*(_ah)->ah_clr11nAggr)((_ah), (_ds)))
+#define ath_hal_set11n_virtmorefrag(_ah, _ds, _v) \
+ ((*(_ah)->ah_set11nVirtMoreFrag)((_ah), (_ds), (_v)))
+#define ath_hal_gpioCfgOutput(_ah, _gpio, _type) \
+ ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio), (_type)))
+#define ath_hal_gpioset(_ah, _gpio, _b) \
+ ((*(_ah)->ah_gpioSet)((_ah), (_gpio), (_b)))
+#define ath_hal_gpioget(_ah, _gpio) \
+ ((*(_ah)->ah_gpioGet)((_ah), (_gpio)))
+#define ath_hal_gpiosetintr(_ah, _gpio, _b) \
+ ((*(_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
@@ -715,21 +1419,57 @@
((*(_ah)->ah_enableDfs)((_ah), (_param)))
#define ath_hal_getdfsthresh(_ah, _param) \
((*(_ah)->ah_getDfsThresh)((_ah), (_param)))
+#define ath_hal_getdfsdefaultthresh(_ah, _param) \
+ ((*(_ah)->ah_getDfsDefaultThresh)((_ah), (_param)))
#define ath_hal_procradarevent(_ah, _rxs, _fulltsf, _buf, _event) \
- ((*(_ah)->ah_procRadarEvent)((_ah), (_rxs), (_fulltsf), (_buf), (_event)))
+ ((*(_ah)->ah_procRadarEvent)((_ah), (_rxs), (_fulltsf), \
+ (_buf), (_event)))
#define ath_hal_is_fast_clock_enabled(_ah) \
((*(_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)))
+#define ath_hal_setchainmasks(_ah, _txchainmask, _rxchainmask) \
+ ((*(_ah)->ah_setChainMasks)((_ah), (_txchainmask), (_rxchainmask)))
-#define ath_hal_gpioCfgOutput(_ah, _gpio, _type) \
- ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio), (_type)))
-#define ath_hal_gpioset(_ah, _gpio, _b) \
- ((*(_ah)->ah_gpioSet)((_ah), (_gpio), (_b)))
-#define ath_hal_gpioget(_ah, _gpio) \
- ((*(_ah)->ah_gpioGet)((_ah), (_gpio)))
-#define ath_hal_gpiosetintr(_ah, _gpio, _b) \
- ((*(_ah)->ah_gpioSetIntr)((_ah), (_gpio), (_b)))
+#define ath_hal_spectral_supported(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_SPECTRAL_SCAN, 0, NULL) == HAL_OK)
+#define ath_hal_spectral_get_config(_ah, _p) \
+ ((*(_ah)->ah_spectralGetConfig)((_ah), (_p)))
+#define ath_hal_spectral_configure(_ah, _p) \
+ ((*(_ah)->ah_spectralConfigure)((_ah), (_p)))
+#define ath_hal_spectral_start(_ah) \
+ ((*(_ah)->ah_spectralStart)((_ah)))
+#define ath_hal_spectral_stop(_ah) \
+ ((*(_ah)->ah_spectralStop)((_ah)))
-#define ath_hal_radar_wait(_ah, _chan) \
- ((*(_ah)->ah_radarWait)((_ah), (_chan)))
+#define ath_hal_btcoex_supported(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_BT_COEX, 0, NULL) == HAL_OK)
+#define ath_hal_btcoex_set_info(_ah, _info) \
+ ((*(_ah)->ah_btCoexSetInfo)((_ah), (_info)))
+#define ath_hal_btcoex_set_config(_ah, _cfg) \
+ ((*(_ah)->ah_btCoexSetConfig)((_ah), (_cfg)))
+#define ath_hal_btcoex_set_qcu_thresh(_ah, _qcuid) \
+ ((*(_ah)->ah_btCoexSetQcuThresh)((_ah), (_qcuid)))
+#define ath_hal_btcoex_set_weights(_ah, _weight) \
+ ((*(_ah)->ah_btCoexSetWeights)((_ah), (_weight)))
+#define ath_hal_btcoex_set_weights(_ah, _weight) \
+ ((*(_ah)->ah_btCoexSetWeights)((_ah), (_weight)))
+#define ath_hal_btcoex_set_bmiss_thresh(_ah, _thr) \
+ ((*(_ah)->ah_btCoexSetBmissThresh)((_ah), (_thr)))
+#define ath_hal_btcoex_set_parameter(_ah, _attrib, _val) \
+ ((*(_ah)->ah_btCoexSetParameter)((_ah), (_attrib), (_val)))
+#define ath_hal_btcoex_enable(_ah) \
+ ((*(_ah)->ah_btCoexEnable)((_ah)))
+#define ath_hal_btcoex_disable(_ah) \
+ ((*(_ah)->ah_btCoexDisable)((_ah)))
+#define ath_hal_div_comb_conf_get(_ah, _conf) \
+ ((*(_ah)->ah_divLnaConfGet)((_ah), (_conf)))
+#define ath_hal_div_comb_conf_set(_ah, _conf) \
+ ((*(_ah)->ah_divLnaConfSet)((_ah), (_conf)))
+
#endif /* _DEV_ATH_ATHVAR_H */
More information about the Midnightbsd-cvs
mailing list