ath - Reimport fresh from FreeBSD 01-Jan-2014 for re-port
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 1 Jan 2014 18:28:42 +0000 (10:28 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 2 Jan 2014 07:15:36 +0000 (23:15 -0800)
* Bring the FreeBSD files in verbatim for the atheros driver.  Create
  a sub-directory "ath", move if_ath* and ah_* into ath/

* as-of (fbsd) git commitid 843c1c95adbb59b90772ccb36241906ccf1923ed

229 files changed:
sys/dev/netif/ath/Makefile [deleted file]
sys/dev/netif/ath/Makefile.inc [deleted file]
sys/dev/netif/ath/ath/Makefile [deleted file]
sys/dev/netif/ath/ath/if_ath.c
sys/dev/netif/ath/ath/if_ath_ahb.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_alq.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_alq.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_beacon.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_beacon.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_btcoex.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_btcoex.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_debug.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_debug.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_keycache.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_keycache.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_led.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_led.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_lna_div.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_lna_div.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_misc.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_pci.c
sys/dev/netif/ath/ath/if_ath_rx.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_rx.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_rx_edma.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_rx_edma.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_spectral.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_spectral.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_sysctl.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_sysctl.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tdma.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tdma.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tsf.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tx.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tx.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tx_edma.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tx_edma.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tx_ht.c [new file with mode: 0644]
sys/dev/netif/ath/ath/if_ath_tx_ht.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_athdfs.h [new file with mode: 0644]
sys/dev/netif/ath/ath/if_athioctl.h
sys/dev/netif/ath/ath/if_athrate.h
sys/dev/netif/ath/ath/if_athvar.h
sys/dev/netif/ath/ath_dfs/null/dfs_null.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah.c [moved from sys/dev/netif/ath/hal/ath_hal/ah.c with 58% similarity]
sys/dev/netif/ath/ath_hal/ah.h [moved from sys/dev/netif/ath/hal/ath_hal/ah.h with 53% similarity]
sys/dev/netif/ath/ath_hal/ah_debug.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_debug.h with 75% similarity]
sys/dev/netif/ath/ath_hal/ah_decode.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_decode.h with 90% similarity]
sys/dev/netif/ath/ath_hal/ah_desc.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_desc.h with 69% similarity]
sys/dev/netif/ath/ath_hal/ah_devid.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_devid.h with 83% similarity]
sys/dev/netif/ath/ath_hal/ah_diagcodes.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_eeprom.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom.h with 78% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c [copied from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v4k.c with 64% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_9287.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_eeprom_v1.c [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v1.c with 99% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v1.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v1.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v14.c [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v14.c with 85% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v14.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v14.h with 86% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v3.c [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v3.c with 99% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v3.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v3.h with 99% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.c [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v4k.c with 92% similarity]
sys/dev/netif/ath/ath_hal/ah_eeprom_v4k.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v4k.h with 79% similarity]
sys/dev/netif/ath/ath_hal/ah_internal.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_internal.h with 71% similarity]
sys/dev/netif/ath/ath_hal/ah_osdep.c [moved from sys/dev/netif/ath/hal/ah_osdep.c with 72% similarity]
sys/dev/netif/ath/ath_hal/ah_osdep.h [moved from sys/dev/netif/ath/hal/ah_osdep.h with 75% similarity]
sys/dev/netif/ath/ath_hal/ah_regdomain.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_regdomain.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_regdomain/ah_rd_ctry.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_regdomain/ah_rd_domains.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_regdomain/ah_rd_freqbands.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_regdomain/ah_rd_regenum.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_regdomain/ah_rd_regmap.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ah_soc.h [moved from sys/dev/netif/ath/hal/ath_hal/ah_soc.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210.h with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_attach.c with 90% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_beacon.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_beacon.c with 94% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_interrupts.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_interrupts.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_keycache.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_keycache.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_misc.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_misc.c with 92% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_phy.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_phy.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_power.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_power.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_recv.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_recv.c with 96% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_reset.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_reset.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210_xmit.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_xmit.c with 93% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210desc.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210desc.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210phy.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210phy.h with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5210reg.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210reg.h with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5210/ar5k_0007.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5210/ar5k_0007.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211.h with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_attach.c with 92% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_beacon.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_beacon.c with 93% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_interrupts.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_interrupts.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_keycache.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_keycache.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_misc.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_misc.c with 95% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_phy.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_phy.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_power.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_power.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_recv.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_recv.c with 96% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_reset.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_reset.c with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_xmit.c with 94% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211desc.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211desc.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211phy.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211phy.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5211/ar5211reg.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211reg.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5211/boss.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5211/boss.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar2316.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar2316.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar2317.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar2317.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar2413.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar2413.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar2425.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar2425.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5111.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5111.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5112.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5112.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212.h with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_ani.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_ani.c with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_attach.c with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_beacon.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_beacon.c with 89% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_eeprom.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_eeprom.c with 96% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_gpio.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_gpio.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_interrupts.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_interrupts.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_keycache.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_keycache.c with 92% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_misc.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_misc.c with 75% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_phy.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_phy.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_power.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_power.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_recv.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_recv.c with 89% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_reset.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_reset.c with 95% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_rfgain.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_rfgain.c with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212_xmit.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_xmit.c with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212desc.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212desc.h with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212phy.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212phy.h with 94% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5212reg.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212reg.h with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5311reg.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5311reg.h with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5212/ar5413.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5212/ar5413.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312.h with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_attach.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_eeprom.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_eeprom.c with 95% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_gpio.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_gpio.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_interrupts.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_interrupts.c with 95% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_misc.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_misc.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_power.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_power.c with 98% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312_reset.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_reset.c with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312phy.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 95% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5312reg.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312reg.h with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5312/ar5315_gpio.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5315_gpio.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar2133.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar2133.c with 77% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar5416/ar5416.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_ani.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_ani.c with 77% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_attach.c with 73% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_beacon.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_beacon.c with 87% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_btcoex.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_btcoex.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_cal.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal.c with 74% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_cal.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal.h with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_cal_adcdc.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal_adcdc.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_cal_adcgain.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal_adcgain.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_cal_iq.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal_iq.c with 97% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_eeprom.c [copied from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_eeprom.c with 93% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_gpio.c with 78% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_interrupts.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_interrupts.c with 60% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_keycache.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_keycache.c with 95% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_misc.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_misc.c with 57% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_phy.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_phy.c with 94% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_power.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_power.c with 91% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_radar.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_recv.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_recv.c with 63% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_reset.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_reset.c with 58% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_spectral.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar5416/ar5416_xmit.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar5416/ar5416desc.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416desc.h with 93% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416phy.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416phy.h with 70% similarity]
sys/dev/netif/ath/ath_hal/ar5416/ar5416reg.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416reg.h with 63% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130.ini [copied from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9160.ini with 81% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130_attach.c [copied from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9160_attach.c with 60% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130_eeprom.c [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 53% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130_eeprom.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130_phy.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_eeprom.c with 57% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130_phy.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9130reg.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9160.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9160.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar9001/ar9160_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9160_attach.c with 81% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9002phy.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9280.c [copied from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280.c with 78% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9280.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280.h with 70% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9280_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280_attach.c with 72% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9280_olc.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9280_olc.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9280v1.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280v1.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9280v2.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280v2.ini with 81% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9285.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285.c with 78% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9285.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285.h with 71% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9285.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285.ini with 99% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_attach.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285_attach.c with 57% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_btcoex.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_cal.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_cal.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_diversity.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_diversity.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_phy.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_phy.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285_reset.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285_reset.c with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9285an.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285phy.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9285v2.ini [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285v2.ini with 84% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9287.c [moved from sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280.c with 78% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9287.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287.ini [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_attach.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_cal.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_cal.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_olc.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_olc.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_reset.c [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287_reset.h [copied from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9002/ar9287an.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9002/ar9287phy.h [moved from sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h with 54% similarity]
sys/dev/netif/ath/ath_hal/ar9003/ar9300_btcoex.h [new file with mode: 0644]
sys/dev/netif/ath/ath_hal/ar9003/ar9300_devid.h [new file with mode: 0644]
sys/dev/netif/ath/ath_rate/amrr/amrr.c [moved from sys/dev/netif/ath/rate_amrr/amrr.c with 64% similarity]
sys/dev/netif/ath/ath_rate/amrr/amrr.h [moved from sys/dev/netif/ath/rate_amrr/amrr.h with 77% similarity]
sys/dev/netif/ath/ath_rate/onoe/onoe.c [moved from sys/dev/netif/ath/rate_onoe/onoe.c with 62% similarity]
sys/dev/netif/ath/ath_rate/onoe/onoe.h [moved from sys/dev/netif/ath/rate_onoe/onoe.h with 61% similarity]
sys/dev/netif/ath/ath_rate/sample/sample.c [new file with mode: 0644]
sys/dev/netif/ath/ath_rate/sample/sample.h [moved from sys/dev/netif/ath/rate_sample/sample.h with 73% similarity]
sys/dev/netif/ath/ath_rate/sample/tx_schedules.h [new file with mode: 0644]
sys/dev/netif/ath/hal/Makefile [deleted file]
sys/dev/netif/ath/hal/ath_hal/ah_regdomain.c [deleted file]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416.h [deleted file]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_xmit.c [deleted file]
sys/dev/netif/ath/rate_amrr/Makefile [deleted file]
sys/dev/netif/ath/rate_onoe/Makefile [deleted file]
sys/dev/netif/ath/rate_sample/Makefile [deleted file]
sys/dev/netif/ath/rate_sample/sample.c [deleted file]

diff --git a/sys/dev/netif/ath/Makefile b/sys/dev/netif/ath/Makefile
deleted file mode 100644 (file)
index cc63b07..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# $DragonFly: src/sys/dev/netif/ath/Makefile,v 1.1 2006/07/13 09:15:22 sephe Exp $
-
-SUBDIR = hal ath
-
-# Choose the desired rate below
-SUBDIR += rate_sample
-#SUBDIR        += rate_amrr
-#SUBDIR        += rate_onoe 
-
-.include <bsd.subdir.mk>
diff --git a/sys/dev/netif/ath/Makefile.inc b/sys/dev/netif/ath/Makefile.inc
deleted file mode 100644 (file)
index 133be9f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# $DragonFly: src/sys/dev/netif/ath/Makefile.inc,v 1.2 2007/02/22 05:17:09 sephe Exp $
-
-HAL    = ${.CURDIR}/../hal/ath_hal
-HALOSDEP= ${.CURDIR}/../hal
-CFLAGS += -I${HALOSDEP}
-
-opt_inet.h:
-       echo "#define INET      1" > ${.TARGET}
-       echo "#define INET6     1" >> ${.TARGET}
-
-opt_wlan.h:
-       echo "#define IEEE80211_DEBUG           1" > ${.TARGET}
-       echo "#define IEEE80211_SUPPORT_TDMA    1" >> ${.TARGET}
-       echo "#define IEEE80211_SUPPORT_MESH    1" >> ${.TARGET}
-
-opt_ah.h:
-       echo "#define AH_SUPPORT_AR5416         1" > ${.TARGET}
diff --git a/sys/dev/netif/ath/ath/Makefile b/sys/dev/netif/ath/ath/Makefile
deleted file mode 100644 (file)
index f7b277c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Copyright (c) 2002, 2003 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.
-# 3. Neither the names of the above-listed copyright holders nor the names
-#    of any contributors may be used to endorse or promote products derived
-#    from this software without specific prior written permission.
-#
-# Alternatively, this software may be distributed under the terms of the
-# GNU General Public License ("GPL") version 2 as published by the Free
-# Software Foundation.
-#
-# 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: src/sys/modules/ath/Makefile,v 1.1.10.1 2006/04/04 23:55:33 sam Exp $
-# $DragonFly: src/sys/dev/netif/ath/ath/Makefile,v 1.2 2007/07/19 12:40:35 sephe Exp $
-#
-
-KMOD   = if_ath
-SRCS   = if_ath.c if_ath_pci.c
-SRCS   += device_if.h bus_if.h pci_if.h opt_ath.h opt_ah.h opt_wlan.h opt_inet.h
-
-.include <bsd.kmod.mk>
index f421f46..49fd9ef 100644 (file)
  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
- *
- * $FreeBSD: head/sys/dev/ath/if_ath.c 203751 2010-02-10 11:12:39Z rpaulo $");
  */
 
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
 /*
  * Driver for the Atheros Wireless LAN controller.
  *
 
 #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/systm.h>
 #include <sys/sysctl.h>
-#include <sys/mbuf.h>   
+#include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/lock.h>
 #include <sys/mutex.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_var.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 <net/ifq_var.h>
 
-#include <netproto/802_11/ieee80211_var.h>
-#include <netproto/802_11/ieee80211_regdomain.h>
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
 #ifdef IEEE80211_SUPPORT_SUPERG
-#include <netproto/802_11/ieee80211_superg.h>
+#include <net80211/ieee80211_superg.h>
 #endif
 #ifdef IEEE80211_SUPPORT_TDMA
-#include <netproto/802_11/ieee80211_tdma.h>
+#include <net80211/ieee80211_tdma.h>
 #endif
 
 #include <net/bpf.h>
 
 #ifdef INET
-#include <netinet/in.h> 
+#include <netinet/in.h>
 #include <netinet/if_ether.h>
 #endif
 
-#include <dev/netif/ath/ath/if_athvar.h>
-#include <dev/netif/ath/hal/ath_hal/ah_devid.h>                /* XXX for softled */
+#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_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
-#include <dev/netif/ath_tx99/ath_tx99.h>
+#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
  */
 CTASSERT(ATH_BCBUF <= 8);
 
-/* unaligned little endian access */
-#define LE_READ_2(p)                                                   \
-       ((u_int16_t)                                                    \
-        ((((u_int8_t *)(p))[0]      ) | (((u_int8_t *)(p))[1] <<  8)))
-#define LE_READ_4(p)                                                   \
-       ((u_int32_t)                                                    \
-        ((((u_int8_t *)(p))[0]      ) | (((u_int8_t *)(p))[1] <<  8) | \
-         (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)))
-
 static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
-                   const char name[IFNAMSIZ], int unit,
-                   enum ieee80211_opmode opmode,
-                   int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
-                   const uint8_t mac[IEEE80211_ADDR_LEN]);
+                   const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
+                   const uint8_t [IEEE80211_ADDR_LEN],
+                   const uint8_t [IEEE80211_ADDR_LEN]);
 static void    ath_vap_delete(struct ieee80211vap *);
 static void    ath_init(void *);
 static void    ath_stop_locked(struct ifnet *);
 static void    ath_stop(struct ifnet *);
-static void    ath_start(struct ifnet *, struct ifaltq_subque *);
-static int     ath_reset(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_callout(void *);
-static int     ath_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
+static void    ath_watchdog(void *);
+static int     ath_ioctl(struct ifnet *, u_long, caddr_t);
 static void    ath_fatal_proc(void *, int);
 static void    ath_bmiss_vap(struct ieee80211vap *);
-static void    ath_bmiss_task(void *, int);
-static int     ath_keyset(struct ath_softc *, const struct ieee80211_key *,
-                       struct ieee80211_node *);
-static int     ath_key_alloc(struct ieee80211vap *,
-                       struct ieee80211_key *,
-                       ieee80211_keyix *, ieee80211_keyix *);
-static int     ath_key_delete(struct ieee80211vap *,
-                       const struct ieee80211_key *);
-static int     ath_key_set(struct ieee80211vap *, const struct ieee80211_key *,
-                       const u_int8_t mac[IEEE80211_ADDR_LEN]);
+static void    ath_bmiss_proc(void *, int);
 static void    ath_key_update_begin(struct ieee80211vap *);
 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_task(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_bstuck_proc(void *, int);
+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_task(void *, int);
 static void    ath_txq_init(struct ath_softc *sc, struct ath_txq *, int);
 static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype);
 static int     ath_tx_setup(struct ath_softc *, int, int);
-static int     ath_wme_update(struct ieee80211com *);
 static void    ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);
 static void    ath_tx_cleanup(struct ath_softc *);
-static void    ath_freetx(struct mbuf *);
-static int     ath_tx_start(struct ath_softc *, struct ieee80211_node *,
-                            struct ath_buf *, struct mbuf *);
-static void    ath_tx_task_q0(void *, int);
-static void    ath_tx_task_q0123(void *, int);
-static void    ath_tx_task(void *, int);
-static void    ath_tx_draintxq(struct ath_softc *, struct ath_txq *);
+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_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 *);
-static void    ath_calibrate_callout(void *);
+#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 *);
 static void    ath_newassoc(struct ieee80211_node *, int);
@@ -204,60 +207,20 @@ static int        ath_setregdomain(struct ieee80211com *,
 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);
 
-static void    ath_sysctlattach(struct ath_softc *);
-static int     ath_raw_xmit(struct ieee80211_node *,
-                       struct mbuf *, const struct ieee80211_bpf_params *);
 static void    ath_announce(struct ath_softc *);
-static void    ath_sysctl_stats_attach(struct ath_softc *sc);
-
-#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);
-
-static __inline void
-ath_hal_setcca(struct ath_hal *ah, int ena)
-{
-       /*
-        * NB: fill me in; this is not provided by default because disabling
-        *     CCA in most locales violates regulatory.
-        */
-}
 
-static __inline int
-ath_hal_getcca(struct ath_hal *ah)
-{
-       u_int32_t diag;
-       if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK)
-               return 1;
-       return ((diag & 0x500000) == 0);
-}
+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 *);
 
-#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 */
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <dev/ath/if_ath_tdma.h>
+#endif
 
 SYSCTL_DECL(_hw_ath);
 
@@ -271,81 +234,55 @@ SYSCTL_INT(_hw_ath, OID_AUTO, shortcal, CTLFLAG_RW, &ath_shortcalinterval,
 static int ath_resetcalinterval = 20*60;       /* reset cal state 20 mins */
 SYSCTL_INT(_hw_ath, OID_AUTO, resetcal, CTLFLAG_RW, &ath_resetcalinterval,
            0, "reset chip calibration results (secs)");
+static int ath_anicalinterval = 100;           /* ANI calibration - 100 msec */
+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");
 
-#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
-};
-static int ath_debug = 0;
-SYSCTL_INT(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug,
-           0, "control debugging printfs");
-TUNABLE_INT("hw.ath.debug", &ath_debug);
-
-#define        IFF_DUMPPKTS(sc, m) \
-       ((sc->sc_debug & (m)) || \
-           (sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
-#define        DPRINTF(sc, m, fmt, ...) do {                           \
-       if (sc->sc_debug & (m))                                 \
-               kprintf(fmt, __VA_ARGS__);                      \
-} while (0)
-#define        KEYPRINTF(sc, ix, hk, mac) do {                         \
-       if (sc->sc_debug & ATH_DEBUG_KEYCACHE)                  \
-               ath_keyprint(sc, __func__, ix, hk, mac);        \
-} while (0)
-static void ath_printrxbuf(struct ath_softc *, const struct ath_buf *bf,
-       u_int ix, int);
-static void ath_printtxbuf(struct ath_softc *, const struct ath_buf *bf,
-       u_int qnum, u_int ix, int done);
-#else
-#define        IFF_DUMPPKTS(sc, m) \
-       ((sc->sc_ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == (IFF_DEBUG|IFF_LINK2))
-#define        DPRINTF(sc, m, fmt, ...) do {                           \
-       (void) sc;                                              \
-} while (0)
-#define        KEYPRINTF(sc, k, ix, mac) do {                          \
-       (void) sc;                                              \
-} while (0)
-#endif
-
 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 | \
+       HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS)
 int
 ath_attach(u_int16_t devid, struct ath_softc *sc)
 {
@@ -356,13 +293,16 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
        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;
@@ -370,16 +310,10 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
        /* 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();
 
-       /* prepare sysctl tree for use in sub modules */
-       sysctl_ctx_init(&sc->sc_sysctl_ctx);
-       sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx,
-               SYSCTL_STATIC_CHILDREN(_hw),
-               OID_AUTO,
-               device_get_nameunit(sc->sc_dev),
-               CTLFLAG_RD, 0, "");
-
-       ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, &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);
@@ -393,6 +327,21 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
 #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
@@ -450,37 +399,57 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
        ath_setcurmode(sc, IEEE80211_MODE_11A);
 
        /*
-        * Allocate tx+rx descriptors and populate the lists.
+        * Allocate TX descriptors and populate the lists.
         */
-       wlan_assert_serialized();
-       wlan_serialize_exit();
        error = ath_desc_alloc(sc);
-       wlan_serialize_enter();
        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(&sc->sc_cal_ch);
-       callout_init(&sc->sc_wd_ch);
 
-       sc->sc_tq = taskqueue_create("ath_taskq", M_INTWAIT,
+       callout_init_mtx(&sc->sc_cal_ch, &sc->sc_mtx, 0);
+       callout_init_mtx(&sc->sc_wd_ch, &sc->sc_mtx, 0);
+
+       ATH_TXBUF_LOCK_INIT(sc);
+
+       sc->sc_tq = taskqueue_create("ath_taskq", M_NOWAIT,
                taskqueue_thread_enqueue, &sc->sc_tq);
-       taskqueue_start_threads(&sc->sc_tq, 1, TDPRI_KERN_DAEMON, -1,
+       taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
                "%s taskq", ifp->if_xname);
 
-       TASK_INIT(&sc->sc_rxtask, 0, ath_rx_task, sc);
-       TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_task, sc);
-       TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_task, 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
         * beacon frames and one data queue for each QoS
-        * priority.  Note that the hal handles reseting
+        * priority.  Note that the hal handles resetting
         * these queues at the needed time.
         *
         * 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;
@@ -519,21 +488,12 @@ ath_attach(u_int16_t devid, 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.
+        * 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_task_q0, sc);
-               break;
-       case 0x0f:
-               TASK_INIT(&sc->sc_txtask, 0, ath_tx_task_q0123, sc);
-               break;
-       default:
-               TASK_INIT(&sc->sc_txtask, 0, ath_tx_task, sc);
-               break;
-       }
+       sc->sc_tx.xmit_attach_comp_func(sc);
 
        /*
         * Setup rate control.  Some rate control modules
@@ -548,32 +508,80 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
                goto bad2;
        }
 
+       /* Attach DFS module */
+       if (! ath_dfs_attach(sc)) {
+               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_mp(&sc->sc_ledtimer);
+       callout_init(&sc->sc_ledtimer, CALLOUT_MPSAFE);
+
+       /*
+        * 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, IFQ_MAXLEN);
-#ifdef notyet
-       ifq_set_ready(&ifp->if_snd);
-#endif
+       IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+       ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
+       IFQ_SET_READY(&ifp->if_snd);
 
        ic->ic_ifp = ifp;
        /* XXX not right but it's not used anywhere important */
@@ -590,8 +598,13 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
                | IEEE80211_C_SHPREAMBLE        /* short preamble supported */
                | IEEE80211_C_SHSLOT            /* short slot time supported */
                | IEEE80211_C_WPA               /* capable of WPA1+WPA2 */
+#ifndef        ATH_ENABLE_11N
                | IEEE80211_C_BGSCAN            /* capable of bg scanning */
+#endif
                | IEEE80211_C_TXFRAG            /* handle tx frags */
+#ifdef ATH_ENABLE_DFS
+               | IEEE80211_C_DFS               /* Enable radar detection */
+#endif
                ;
        /*
         * Query the hal to figure out h/w crypto support.
@@ -673,6 +686,12 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
        sc->sc_hasbmask = ath_hal_hasbssidmask(ah);
        sc->sc_hasbmatch = ath_hal_hasbssidmatch(ah);
        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);
@@ -684,6 +703,188 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
                ic->ic_tdma_update = ath_tdma_update;
        }
 #endif
+
+       /*
+        * 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
+        */
+       if (ath_hal_getcapability(ah, HAL_CAP_HT, 0, NULL) == HAL_OK &&
+           (wmodes & (HAL_MODE_HT20 | HAL_MODE_HT40))) {
+               uint32_t rxs, txs;
+
+               device_printf(sc->sc_dev, "[HT] enabling HT modes\n");
+
+               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 */
+                       ;
+
+               /*
+                * Enable short-GI for HT20 only if the hardware
+                * advertises support.
+                * Notably, anything earlier than the AR9287 doesn't.
+                */
+               if ((ath_hal_getcapability(ah,
+                   HAL_CAP_HT20_SGI, 0, NULL) == HAL_OK) &&
+                   (wmodes & HAL_MODE_HT20)) {
+                       device_printf(sc->sc_dev,
+                           "[HT] enabling short-GI in 20MHz mode\n");
+                       ic->ic_htcaps |= IEEE80211_HTCAP_SHORTGI20;
+               }
+
+               if (wmodes & HAL_MODE_HT40)
+                       ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40
+                           |  IEEE80211_HTCAP_SHORTGI40;
+
+               /*
+                * 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, &txs);
+               (void) ath_hal_getcapability(ah, HAL_CAP_STREAMS, 1, &rxs);
+               ic->ic_txstream = txs;
+               ic->ic_rxstream = rxs;
+
+               /*
+                * 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.
@@ -726,16 +927,61 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
        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
@@ -743,6 +989,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
         */
        ath_sysctlattach(sc);
        ath_sysctl_stats_attach(sc);
+       ath_sysctl_hal_attach(sc);
 
        if (bootverbose)
                ieee80211_announce(ic);
@@ -751,10 +998,20 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
 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;
@@ -768,7 +1025,7 @@ ath_detach(struct ath_softc *sc)
        DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n",
                __func__, ifp->if_flags);
 
-       /* 
+       /*
         * NB: the order of these is important:
         * o stop the chip so no more interrupts will fire
         * o call the 802.11 layer before detaching the hal to
@@ -790,14 +1047,22 @@ ath_detach(struct ath_softc *sc)
                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 */
-       if (sc->sc_sysctl_tree) {
-               sysctl_ctx_free(&sc->sc_sysctl_ctx);
-               sc->sc_sysctl_tree = NULL;
-       }
+
+       CURVNET_SET(ifp->if_vnet);
        if_free(ifp);
+       CURVNET_RESTORE();
 
        return 0;
 }
@@ -869,23 +1134,24 @@ assign_bslot(struct ath_softc *sc)
 }
 
 static struct ieee80211vap *
-ath_vap_create(struct ieee80211com *ic,
-       const char name[IFNAMSIZ], int unit,
-       enum ieee80211_opmode opmode, int flags,
-       const uint8_t bssid[IEEE80211_ADDR_LEN],
-       const uint8_t mac0[IEEE80211_ADDR_LEN])
+ath_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
+    enum ieee80211_opmode opmode, int flags,
+    const uint8_t bssid[IEEE80211_ADDR_LEN],
+    const uint8_t mac0[IEEE80211_ADDR_LEN])
 {
        struct ath_softc *sc = ic->ic_ifp->if_softc;
        struct ath_vap *avp;
        struct ieee80211vap *vap;
        uint8_t mac[IEEE80211_ADDR_LEN];
-       int ic_opmode, needbeacon, error;
+       int needbeacon, error;
+       enum ieee80211_opmode ic_opmode;
 
-       avp = (struct ath_vap *) kmalloc(sizeof(struct ath_vap),
+       avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
            M_80211_VAP, M_WAITOK | M_ZERO);
        needbeacon = 0;
        IEEE80211_ADDR_COPY(mac, mac0);
 
+       ATH_LOCK(sc);
        ic_opmode = opmode;             /* default to opmode of new vap */
        switch (opmode) {
        case IEEE80211_M_STA:
@@ -967,7 +1233,7 @@ ath_vap_create(struct ieee80211com *ic,
        /*
         * 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;
        }
@@ -980,8 +1246,10 @@ ath_vap_create(struct ieee80211com *ic,
 
        vap = &avp->av_vap;
        /* XXX can't hold mutex across if_alloc */
+       ATH_UNLOCK(sc);
        error = ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
            bssid, mac);
+       ATH_LOCK(sc);
        if (error != 0) {
                device_printf(sc->sc_dev, "%s: error %d creating vap\n",
                    __func__, error);
@@ -1005,6 +1273,30 @@ ath_vap_create(struct ieee80211com *ic,
        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 */
+
+       /*
+        * Anything earlier than some AR9300 series MACs don't
+        * support a smaller MPDU density.
+        */
+       vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_8;
+       /*
+        * All NICs can handle the maximum size, however
+        * AR5416 based MACs can only TX aggregates w/ RTS
+        * protection when the total aggregate size is <= 8k.
+        * However, for now that's enforced by the TX path.
+        */
+       vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+
        avp->av_bslot = -1;
        if (needbeacon) {
                /*
@@ -1012,8 +1304,8 @@ ath_vap_create(struct ieee80211com *ic,
                 * 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
@@ -1087,6 +1379,7 @@ ath_vap_create(struct ieee80211com *ic,
                 */
                sc->sc_swbmiss = 1;
        }
+       ATH_UNLOCK(sc);
 
        /* complete setup */
        ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status);
@@ -1095,7 +1388,8 @@ bad2:
        reclaim_address(sc, mac);
        ath_hal_setbssidmask(sc->sc_ah, sc->sc_hwbssidmask);
 bad:
-       kfree(avp, M_80211_VAP);
+       free(avp, M_80211_VAP);
+       ATH_UNLOCK(sc);
        return NULL;
 }
 
@@ -1108,18 +1402,41 @@ ath_vap_delete(struct ieee80211vap *vap)
        struct ath_hal *ah = sc->sc_ah;
        struct ath_vap *avp = ATH_VAP(vap);
 
-       if (ifp->if_flags & IFF_RUNNING) {
+       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
                 * particular we need to reclaim all references to
                 * 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
         * the vap instance is reclaimed as we may have a reference
@@ -1165,9 +1482,9 @@ ath_vap_delete(struct ieee80211vap *vap)
                sc->sc_swbmiss = 0;
        }
 #endif
-       kfree(avp, M_80211_VAP);
+       free(avp, M_80211_VAP);
 
-       if (ifp->if_flags & IFF_RUNNING) {
+       if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
                /*
                 * Restart rx+tx machines if still running (RUNNING will
                 * be reset if we just destroyed the last vap).
@@ -1185,6 +1502,7 @@ ath_vap_delete(struct ieee80211vap *vap)
                }
                ath_hal_intrset(ah, sc->sc_imask);
        }
+       ATH_UNLOCK(sc);
 }
 
 void
@@ -1197,15 +1515,22 @@ ath_suspend(struct ath_softc *sc)
                __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);
 }
 
 /*
@@ -1227,6 +1552,32 @@ ath_reset_keycache(struct ath_softc *sc)
        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)
 {
@@ -1238,35 +1589,50 @@ ath_resume(struct ath_softc *sc)
        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);
        ath_reset_keycache(sc);
-       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 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);
+
+       /* 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 ? */
 }
 
 void
@@ -1290,43 +1656,106 @@ ath_intr(void *arg)
        struct ath_softc *sc = arg;
        struct ifnet *ifp = sc->sc_ifp;
        struct ath_hal *ah = sc->sc_ah;
-       HAL_INT status;
-       HAL_INT ostatus;
+       HAL_INT status = 0;
+       uint32_t txqs;
 
-       if (sc->sc_invalid) {
-               /*
-                * The hardware is not ready/present, don't touch anything.
-                * Note this can happen early on if the IRQ is shared.
-                */
-               DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid; ignored\n", __func__);
+       /*
+        * 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 (!ath_hal_intrpend(ah))              /* shared irq, not for us */
+       if (sc->sc_invalid) {
+               /*
+                * The hardware is not ready/present, don't touch anything.
+                * 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 */
+               ATH_PCU_UNLOCK(sc);
                return;
+       }
+
        if ((ifp->if_flags & IFF_UP) == 0 ||
-           (ifp->if_flags & IFF_RUNNING) == 0) {
+           (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
                HAL_INT status;
 
                DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n",
                        __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
         * bits we haven't explicitly enabled so we mask the
         * value to insure we only process bits we requested.
         */
-       ath_hal_getisr(ah, &ostatus);           /* NB: clears ISR too */
-       DPRINTF(sc, ATH_DEBUG_INTR, "%s: status 0x%x\n", __func__, ostatus);
-       status = ostatus & sc->sc_imask;        /* discard unasked for bits */
+       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) {
+               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) {
                        /*
@@ -1356,40 +1785,99 @@ ath_intr(void *arg)
                                 * 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
                        }
                }
-
-               /*
-                * NB: The hardware should re-read the link when the RXE
-                *     bit is written, but it doesn't work at least on
-                *     older chipsets.
-                */
                if (status & HAL_INT_RXEOL) {
+                       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
+                        *     least on older hardware revs.
+                        */
                        sc->sc_stats.ast_rxeol++;
-                       sc->sc_rxlink = NULL;
+                       /*
+                        * Disable RXEOL/RXORN - prevent an interrupt
+                        * storm until the PCU logic can be reset.
+                        * In case the interface is reset some other
+                        * way before "sc_kickpcu" is called, don't
+                        * modify sc_imask - that way if it is reset
+                        * 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.
+                        */
+                       sc->sc_rx.recv_sched(sc, 1);
                }
-
                if (status & HAL_INT_TXURN) {
                        sc->sc_stats.ast_txurn++;
                        /* 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);
                }
-
+               if (status & HAL_INT_GTT)
+                       sc->sc_stats.ast_tx_timeout++;
+               if (status & HAL_INT_CST)
+                       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.
@@ -1400,14 +1888,25 @@ ath_intr(void *arg)
                         * 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
@@ -1432,7 +1931,7 @@ ath_fatal_proc(void *arg, int pending)
                    state[0], state[1] , state[2], state[3],
                    state[4], state[5]);
        }
-       ath_reset(ifp);
+       ath_reset(ifp, ATH_RESET_NOLOSS);
 }
 
 static void
@@ -1451,6 +1950,7 @@ ath_bmiss_vap(struct ieee80211vap *vap)
                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;
 
@@ -1468,13 +1968,13 @@ ath_bmiss_vap(struct ieee80211vap *vap)
        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;
        void *sp;
 
-       if (!ath_hal_getdiagstate(ah, 32, &mask, sizeof(mask), &sp, &rsize))
+       if (!ath_hal_getdiagstate(ah, HAL_DIAG_CHECK_HANGS, &mask, sizeof(mask), &sp, &rsize))
                return 0;
        KASSERT(rsize == sizeof(uint32_t), ("resultsize %u", rsize));
        *hangs = *(uint32_t *)sp;
@@ -1482,22 +1982,27 @@ ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs)
 }
 
 static void
-ath_bmiss_task(void *arg, int pending)
+ath_bmiss_proc(void *arg, int pending)
 {
        struct ath_softc *sc = arg;
        struct ifnet *ifp = sc->sc_ifp;
        uint32_t hangs;
 
-       wlan_serialize_enter();
        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) {
-               if_printf(ifp, "bb hang detected (0x%x), reseting\n", hangs); 
-               ath_reset(ifp);
+               ath_reset(ifp, ATH_RESET_NOLOSS);
+               if_printf(ifp, "bb hang detected (0x%x), resetting\n", hangs);
        } else {
+               ath_reset(ifp, ATH_RESET_NOLOSS);
                ieee80211_beacon_miss(ifp->if_l2com);
        }
-       wlan_serialize_exit();
 }
 
 /*
@@ -1535,8 +2040,7 @@ ath_init(void *arg)
        DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n",
                __func__, ifp->if_flags);
 
-       wlan_assert_serialized();
-
+       ATH_LOCK(sc);
        /*
         * Stop anything previously setup.  This is safe
         * whether this is the first time through or not.
@@ -1551,13 +2055,37 @@ ath_init(void *arg)
         * 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);
+               ATH_UNLOCK(sc);
                return;
        }
        ath_chan_change(sc, ic->ic_curchan);
 
+       /* 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.
@@ -1566,6 +2094,15 @@ ath_init(void *arg)
        sc->sc_lastlongcal = 0;
        sc->sc_resetcal = 1;
        sc->sc_lastcalreset = 0;
+       sc->sc_lastani = 0;
+       sc->sc_lastshortcal = 0;
+       sc->sc_doresetcal = AH_FALSE;
+       /*
+        * Beacon timers were cleared here; give ath_newstate()
+        * a hint that the beacon timers should be poked when
+        * things transition to the RUN state.
+        */
+       sc->sc_beacons = 0;
 
        /*
         * Setup the hardware after reset: the key cache
@@ -1576,6 +2113,7 @@ ath_init(void *arg)
         */
        if (ath_startrecv(sc) != 0) {
                if_printf(ifp, "unable to start recv logic\n");
+               ATH_UNLOCK(sc);
                return;
        }
 
@@ -1584,7 +2122,16 @@ ath_init(void *arg)
         */
        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.
@@ -1592,10 +2139,18 @@ ath_init(void *arg)
        if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
                sc->sc_imask |= HAL_INT_MIB;
 
-       ifp->if_flags |= IFF_RUNNING;
-       callout_reset(&sc->sc_wd_ch, hz, ath_watchdog_callout, sc);
+       /* Enable global TX timeout and carrier sense timeout if available */
+       if (ath_hal_gtxto_supported(ah))
+               sc->sc_imask |= HAL_INT_GTT;
+
+       DPRINTF(sc, ATH_DEBUG_RESET, "%s: imask=0x%x\n",
+               __func__, sc->sc_imask);
+
+       ifp->if_drv_flags |= IFF_DRV_RUNNING;
+       callout_reset(&sc->sc_wd_ch, hz, ath_watchdog, sc);
        ath_hal_intrset(ah, sc->sc_imask);
 
+       ATH_UNLOCK(sc);
 
 #ifdef ATH_TX99_DIAG
        if (sc->sc_tx99 != NULL)
@@ -1614,7 +2169,8 @@ ath_stop_locked(struct ifnet *ifp)
        DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n",
                __func__, sc->sc_invalid, ifp->if_flags);
 
-       if (ifp->if_flags & IFF_RUNNING) {
+       ATH_LOCK_ASSERT(sc);
+       if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
                /*
                 * Shutdown the hardware and driver:
                 *    reset 802.11 state machine
@@ -1636,7 +2192,7 @@ ath_stop_locked(struct ifnet *ifp)
 #endif
                callout_stop(&sc->sc_wd_ch);
                sc->sc_wd_timer = 0;
-               ifp->if_flags &= ~IFF_RUNNING;
+               ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
                if (!sc->sc_invalid) {
                        if (sc->sc_softled) {
                                callout_stop(&sc->sc_ledtimer);
@@ -1646,9 +2202,9 @@ ath_stop_locked(struct ifnet *ifp)
                        }
                        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;
@@ -1656,12 +2212,128 @@ ath_stop_locked(struct ifnet *ifp)
        }
 }
 
+#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 __unused = ifp->if_softc;
+       struct ath_softc *sc = ifp->if_softc;
 
+       ATH_LOCK(sc);
        ath_stop_locked(ifp);
+       ATH_UNLOCK(sc);
 }
 
 /*
@@ -1671,23 +2343,93 @@ ath_stop(struct ifnet *ifp)
  * operational state.  Used to recover from various errors and
  * to reset or reload hardware state.
  */
-static int
-ath_reset(struct ifnet *ifp)
+int
+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;
+
+       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_hal_intrset(ah, 0);         /* disable interrupts */
-       ath_draintxq(sc);               /* stop xmit side */
-       ath_stoprecv(sc);               /* stop recv side */
        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);
        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);
+
+       /* 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__);
        /*
@@ -1704,9 +2446,64 @@ ath_reset(struct ifnet *ifp)
 #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);
+
+       /*
+        * 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);
 
-       if_devstart(ifp);       /* restart xmit */
+       /* 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;
 }
 
@@ -1729,602 +2526,463 @@ ath_reset_vap(struct ieee80211vap *vap, u_long cmd)
                        ath_hal_settxpowlimit(ah, ic->ic_txpowlimit);
                return 0;
        }
-       return ath_reset(ifp);
+       /* XXX? Full or NOLOSS? */
+       return ath_reset(ifp, ATH_RESET_FULL);
 }
 
-static struct ath_buf *
-_ath_getbuf_locked(struct ath_softc *sc)
+struct ath_buf *
+_ath_getbuf_locked(struct ath_softc *sc, ath_buf_type_t btype)
 {
        struct ath_buf *bf;
 
-       bf = STAILQ_FIRST(&sc->sc_txbuf);
-       if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0)
-               STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
+       ATH_TXBUF_LOCK_ASSERT(sc);
+
+       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) {
-               kprintf("ath: ran out of descriptors\n");
+               /* 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;
 }
 
-static struct ath_buf *
-ath_getbuf(struct ath_softc *sc)
+/*
+ * 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_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;
 
-       bf = _ath_getbuf_locked(sc);
+       ATH_TXBUF_LOCK(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++;
-               ifq_set_oactive(&ifp->if_snd);
+               IF_LOCK(&ifp->if_snd);
+               ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+               IF_UNLOCK(&ifp->if_snd);
        }
        return bf;
 }
 
-/*
- * Cleanup driver resources when we run out of buffers
- * while processing fragments; return the tx buffers
- * allocated and drop node references.
- */
 static void
-ath_txfrag_cleanup(struct ath_softc *sc,
-       ath_bufhead *frags, struct ieee80211_node *ni)
+ath_qflush(struct ifnet *ifp)
 {
-       struct ath_buf *bf, *next;
 
-       STAILQ_FOREACH_MUTABLE(bf, frags, bf_list, next) {
-               /* NB: bf assumed clean */
-               STAILQ_REMOVE_HEAD(frags, bf_list);
-               STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
-               ieee80211_node_decref(ni);
-       }
+       /* XXX TODO */
 }
 
 /*
- * Setup xmit of a fragmented frame.  Allocate a buffer
- * for each frag and bump the node reference count to
- * reflect the held reference to be setup by ath_tx_start.
+ * 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_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
-       struct mbuf *m0, struct ieee80211_node *ni)
+ath_transmit(struct ifnet *ifp, struct mbuf *m)
 {
-       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;
+       ath_bufhead frags;
+       int retval = 0;
 
-       for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
-               bf = _ath_getbuf_locked(sc);
-               if (bf == NULL) {       /* out of buffers, cleanup */
-                       ath_txfrag_cleanup(sc, frags, ni);
-                       break;
-               }
-               ieee80211_node_incref(ni);
-               STAILQ_INSERT_TAIL(frags, bf, bf_list);
+       /*
+        * 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);
 
-       return !STAILQ_EMPTY(frags);
-}
+       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);
 
-static void
-ath_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
-{
-       struct ath_softc *sc = ifp->if_softc;
-       struct ieee80211_node *ni;
-       struct ath_buf *bf;
-       struct mbuf *m, *next;
-       ath_bufhead frags;
+       /*
+        * Node reference, if there's one.
+        */
+       ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
 
-       wlan_assert_serialized();
-       ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
+       /*
+        * 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;
+       }
 
-       if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid) {
-               ifq_purge(&ifp->if_snd);
-               return;
+       /*
+        * 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;
        }
-       for (;;) {
-               /*
-                * Grab a TX buffer and associated resources.
-                */
-               bf = ath_getbuf(sc);
-               if (bf == NULL)
-                       break;
 
-               m = ifq_dequeue(&ifp->if_snd);
-               if (m == NULL) {
-                       STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
-                       break;
-               }
-               ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
-               /*
-                * 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...
-                */
-               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++;
-                       IFNET_STAT_INC(ifp, oerrors, 1);
-                       ath_freetx(m);
-                       goto bad;
-               }
-               IFNET_STAT_INC(ifp, opackets, 1);
-       nextfrag:
+       /*
+        * 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) {
                /*
-                * 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.
+                * If we failed to allocate a buffer, fail.
+                *
+                * We shouldn't fail normally, due to the check
+                * above.
                 */
-               next = m->m_nextpkt;
-               if (ath_tx_start(sc, ni, bf, m)) {
-       bad:
-                       IFNET_STAT_INC(ifp, oerrors, 1);
-       reclaim:
-                       bf->bf_m = NULL;
-                       bf->bf_node = NULL;
-                       STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
-                       ath_txfrag_cleanup(sc, &frags, ni);
-                       if (ni != NULL)
-                               ieee80211_free_node(ni);
-                       continue;
-               }
-               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;
-               }
-
-               sc->sc_wd_timer = 5;
+               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;
        }
-}
 
-static int
-ath_media_change(struct ifnet *ifp)
-{
-       int error = ieee80211_media_change(ifp);
-       /* NB: only the fixed rate can change and that doesn't need a reset */
-       return (error == ENETRESET ? 0 : error);
-}
+       /*
+        * At this point we have a buffer; so we need to free it
+        * if we hit any error conditions.
+        */
 
-#ifdef ATH_DEBUG
-static void
-ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix,
-       const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
-{
-       static const char *ciphers[] = {
-               "WEP",
-               "AES-OCB",
-               "AES-CCM",
-               "CKIP",
-               "TKIP",
-               "CLR",
-       };
-       char ethstr[ETHER_ADDRSTRLEN + 1];
-       int i, n;
-
-       kprintf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]);
-       for (i = 0, n = hk->kv_len; i < n; i++)
-               kprintf("%02x", hk->kv_val[i]);
-       kprintf(" mac %s", kether_ntoa(mac, ethstr));
-       if (hk->kv_type == HAL_CIPHER_TKIP) {
-               kprintf(" %s ", sc->sc_splitmic ? "mic" : "rxmic");
-               for (i = 0; i < sizeof(hk->kv_mic); i++)
-                       kprintf("%02x", hk->kv_mic[i]);
-               if (!sc->sc_splitmic) {
-                       kprintf(" txmic ");
-                       for (i = 0; i < sizeof(hk->kv_txmic); i++)
-                               kprintf("%02x", hk->kv_txmic[i]);
-               }
+       /*
+        * 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;
        }
-       kprintf("\n");
-}
-#endif
 
-/*
- * Set a TKIP key into the hardware.  This handles the
- * potential distribution of key state to multiple key
- * cache slots for TKIP.
- */
-static int
-ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
-       HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
-{
-#define        IEEE80211_KEY_XR        (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
-       static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
-       struct ath_hal *ah = sc->sc_ah;
+       /*
+        * At this point if we have any TX fragments, then we will
+        * have bumped the node reference once for each of those.
+        */
 
-       KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP,
-               ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher));
-       if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
-               if (sc->sc_splitmic) {
-                       /*
-                        * TX key goes at first index, RX key at the rx index.
-                        * The hal handles the MIC keys at index+64.
-                        */
-                       memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic));
-                       KEYPRINTF(sc, k->wk_keyix, hk, zerobssid);
-                       if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid))
-                               return 0;
-
-                       memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
-                       KEYPRINTF(sc, k->wk_keyix+32, hk, mac);
-                       /* XXX delete tx key on failure? */
-                       return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac);
-               } else {
-                       /*
-                        * Room for both TX+RX MIC keys in one key cache
-                        * slot, just set key at the first index; the hal
-                        * will handle the rest.
-                        */
-                       memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
-                       memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
-                       KEYPRINTF(sc, k->wk_keyix, hk, mac);
-                       return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
-               }
-       } else if (k->wk_flags & IEEE80211_KEY_XMIT) {
-               if (sc->sc_splitmic) {
-                       /*
-                        * NB: must pass MIC key in expected location when
-                        * the keycache only holds one MIC key per entry.
-                        */
-                       memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_txmic));
-               } else
-                       memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
-               KEYPRINTF(sc, k->wk_keyix, hk, mac);
-               return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
-       } else if (k->wk_flags & IEEE80211_KEY_RECV) {
-               memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
-               KEYPRINTF(sc, k->wk_keyix, hk, mac);
-               return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
-       }
-       return 0;
-#undef IEEE80211_KEY_XR
-}
+       /*
+        * 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.
+        */
 
-/*
- * Set a net80211 key into the hardware.  This handles the
- * potential distribution of key state to multiple key
- * cache slots for TKIP with hardware MIC support.
- */
-static int
-ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
-       struct ieee80211_node *bss)
-{
-       static const u_int8_t ciphermap[] = {
-               HAL_CIPHER_WEP,         /* IEEE80211_CIPHER_WEP */
-               HAL_CIPHER_TKIP,        /* IEEE80211_CIPHER_TKIP */
-               HAL_CIPHER_AES_OCB,     /* IEEE80211_CIPHER_AES_OCB */
-               HAL_CIPHER_AES_CCM,     /* IEEE80211_CIPHER_AES_CCM */
-               (u_int8_t) -1,          /* 4 is not allocated */
-               HAL_CIPHER_CKIP,        /* IEEE80211_CIPHER_CKIP */
-               HAL_CIPHER_CLR,         /* IEEE80211_CIPHER_NONE */
-       };
-       struct ath_hal *ah = sc->sc_ah;
-       const struct ieee80211_cipher *cip = k->wk_cipher;
-       u_int8_t gmac[IEEE80211_ADDR_LEN];
-       const u_int8_t *mac;
-       HAL_KEYVAL hk;
-
-       memset(&hk, 0, sizeof(hk));
-       /*
-        * Software crypto uses a "clear key" so non-crypto
-        * state kept in the key cache are maintained and
-        * so that rx frames have an entry to match.
-        */
-       if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
-               KASSERT(cip->ic_cipher < NELEM(ciphermap),
-                       ("invalid cipher type %u", cip->ic_cipher));
-               hk.kv_type = ciphermap[cip->ic_cipher];
-               hk.kv_len = k->wk_keylen;
-               memcpy(hk.kv_val, k->wk_key, k->wk_keylen);
-       } else
-               hk.kv_type = HAL_CIPHER_CLR;
+       /*
+        * 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;
 
-       if ((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
-                * the high bit set instead of the app-specified address.
+                * 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.
                 */
-               IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
-               gmac[0] |= 0x80;
-               mac = gmac;
-       } else
-               mac = k->wk_macaddr;
-
-       if (hk.kv_type == HAL_CIPHER_TKIP &&
-           (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
-               return ath_keyset_tkip(sc, k, &hk, mac);
-       } else {
-               KEYPRINTF(sc, k->wk_keyix, &hk, mac);
-               return ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
-       }
-}
-
-/*
- * Allocate tx/rx key slots for TKIP.  We allocate two slots for
- * each key, one for decrypt/encrypt and the other for the MIC.
- */
-static u_int16_t
-key_alloc_2pair(struct ath_softc *sc,
-       ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
-{
-       u_int i, keyix;
-
-       KASSERT(sc->sc_splitmic, ("key cache !split"));
-       /* XXX could optimize */
-       for (i = 0; i < NELEM(sc->sc_keymap)/4; i++) {
-               u_int8_t b = sc->sc_keymap[i];
-               if (b != 0xff) {
-                       /*
-                        * One or more slots in this byte are free.
-                        */
-                       keyix = i*NBBY;
-                       while (b & 1) {
-               again:
-                               keyix++;
-                               b >>= 1;
-                       }
-                       /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
-                       if (isset(sc->sc_keymap, keyix+32) ||
-                           isset(sc->sc_keymap, keyix+64) ||
-                           isset(sc->sc_keymap, keyix+32+64)) {
-                               /* full pair unavailable */
-                               /* XXX statistic */
-                               if (keyix == (i+1)*NBBY) {
-                                       /* no slots were appropriate, advance */
-                                       continue;
-                               }
-                               goto again;
-                       }
-                       setbit(sc->sc_keymap, keyix);
-                       setbit(sc->sc_keymap, keyix+64);
-                       setbit(sc->sc_keymap, keyix+32);
-                       setbit(sc->sc_keymap, keyix+32+64);
-                       DPRINTF(sc, ATH_DEBUG_KEYCACHE,
-                               "%s: key pair %u,%u %u,%u\n",
-                               __func__, keyix, keyix+64,
-                               keyix+32, keyix+32+64);
-                       *txkeyix = keyix;
-                       *rxkeyix = keyix+32;
-                       return 1;
-               }
-       }
-       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
-       return 0;
-}
-
-/*
- * Allocate tx/rx key slots for TKIP.  We allocate two slots for
- * each key, one for decrypt/encrypt and the other for the MIC.
- */
-static u_int16_t
-key_alloc_pair(struct ath_softc *sc,
-       ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
-{
-       u_int i, keyix;
-
-       KASSERT(!sc->sc_splitmic, ("key cache split"));
-       /* XXX could optimize */
-       for (i = 0; i < NELEM(sc->sc_keymap)/4; i++) {
-               u_int8_t b = sc->sc_keymap[i];
-               if (b != 0xff) {
-                       /*
-                        * One or more slots in this byte are free.
-                        */
-                       keyix = i*NBBY;
-                       while (b & 1) {
-               again:
-                               keyix++;
-                               b >>= 1;
-                       }
-                       if (isset(sc->sc_keymap, keyix+64)) {
-                               /* full pair unavailable */
-                               /* XXX statistic */
-                               if (keyix == (i+1)*NBBY) {
-                                       /* no slots were appropriate, advance */
-                                       continue;
-                               }
-                               goto again;
-                       }
-                       setbit(sc->sc_keymap, keyix);
-                       setbit(sc->sc_keymap, keyix+64);
-                       DPRINTF(sc, ATH_DEBUG_KEYCACHE,
-                               "%s: key pair %u,%u\n",
-                               __func__, keyix, keyix+64);
-                       *txkeyix = *rxkeyix = keyix;
-                       return 1;
+               TAILQ_FOREACH(n_fbf, &frags, bf_list) {
+                       fbf->bf_nextfraglen = fm->m_pkthdr.len;
+                       fbf = n_fbf;
+                       fm = fm->m_nextpkt;
                }
        }
-       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
-       return 0;
-}
 
-/*
- * Allocate a single key cache slot.
- */
-static int
-key_alloc_single(struct ath_softc *sc,
-       ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
-{
-       u_int i, keyix;
-
-       /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
-       for (i = 0; i < NELEM(sc->sc_keymap); i++) {
-               u_int8_t b = sc->sc_keymap[i];
-               if (b != 0xff) {
-                       /*
-                        * One or more slots are free.
-                        */
-                       keyix = i*NBBY;
-                       while (b & 1)
-                               keyix++, b >>= 1;
-                       setbit(sc->sc_keymap, keyix);
-                       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n",
-                               __func__, keyix);
-                       *txkeyix = *rxkeyix = keyix;
-                       return 1;
-               }
+       /*
+        * 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);
+               /*
+                * Free the rest of the node references and
+                * buffers for the fragment list.
+                */
+               ath_txfrag_cleanup(sc, &frags, ni);
+               ATH_TXBUF_UNLOCK(sc);
+               retval = ENOBUFS;
+               goto finish;
        }
-       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__);
-       return 0;
-}
-
-/*
- * Allocate one or more key cache slots for a uniacst key.  The
- * key itself is needed only to identify the cipher.  For hardware
- * TKIP with split cipher+MIC keys we allocate two key cache slot
- * pairs so that we can setup separate TX and RX MIC keys.  Note
- * that the MIC key for a TKIP key at slot i is assumed by the
- * hardware to be at slot i+64.  This limits TKIP keys to the first
- * 64 entries.
- */
-static int
-ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
-       ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
-{
-       struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
 
        /*
-        * Group key allocation must be handled specially for
-        * parts that do not support multicast key cache search
-        * functionality.  For those parts the key id must match
-        * the h/w key index so lookups find the right key.  On
-        * parts w/ the key search facility we install the sender's
-        * mac address (with the high bit set) and let the hardware
-        * find the key w/o using the key id.  This is preferred as
-        * it permits us to support multiple users for adhoc and/or
-        * multi-station operation.
+        * Check here if the node is in power save state.
         */
-       if (k->wk_keyix != IEEE80211_KEYIX_NONE) {
+       ath_tx_update_tim(sc, ni, 1);
+
+       if (next != NULL) {
                /*
-                * Only global keys should have key index assigned.
+                * Beware of state changing between frags.
+                * XXX check sta power-save state?
                 */
-               if (!(&vap->iv_nw_keys[0] <= k &&
-                     k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
-                       /* should not happen */
-                       DPRINTF(sc, ATH_DEBUG_KEYCACHE,
-                               "%s: bogus group key\n", __func__);
-                       return 0;
-               }
-               if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
-                   !(k->wk_flags & IEEE80211_KEY_GROUP) ||
-                   !sc->sc_mcastkey) {
-                       /*
-                        * XXX we pre-allocate the global keys so
-                        * have no way to check if they've already
-                        * been allocated.
-                        */
-                       *keyix = *rxkeyix = k - vap->iv_nw_keys;
-                       return 1;
+               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;
                }
-               /*
-                * Group key and device supports multicast key search.
-                */
-               k->wk_keyix = IEEE80211_KEYIX_NONE;
+               m = next;
+               bf = TAILQ_FIRST(&frags);
+               KASSERT(bf != NULL, ("no buf for txfrag"));
+               TAILQ_REMOVE(&frags, bf, bf_list);
+               goto nextfrag;
        }
 
        /*
-        * We allocate two pair for TKIP when using the h/w to do
-        * the MIC.  For everything else, including software crypto,
-        * we allocate a single entry.  Note that s/w crypto requires
-        * a pass-through slot on the 5211 and 5212.  The 5210 does
-        * not support pass-through cache entries and we map all
-        * those requests to slot 0.
+        * Bump watchdog timer.
         */
-       if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
-               return key_alloc_single(sc, keyix, rxkeyix);
-       } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
-           (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
-               if (sc->sc_splitmic)
-                       return key_alloc_2pair(sc, keyix, rxkeyix);
-               else
-                       return key_alloc_pair(sc, keyix, rxkeyix);
-       } else {
-               return key_alloc_single(sc, keyix, rxkeyix);
-       }
-}
-
-/*
- * Delete an entry in the key cache allocated by ath_key_alloc.
- */
-static int
-ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
-{
-       struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
-       struct ath_hal *ah = sc->sc_ah;
-       const struct ieee80211_cipher *cip = k->wk_cipher;
-       u_int keyix = k->wk_keyix;
+       sc->sc_wd_timer = 5;
 
-       DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
+finish:
+       ATH_TX_UNLOCK(sc);
 
-       ath_hal_keyreset(ah, keyix);
        /*
-        * Handle split tx/rx keying required for TKIP with h/w MIC.
+        * Finished transmitting!
         */
-       if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
-           (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic)
-               ath_hal_keyreset(ah, keyix+32);         /* RX key */
-       if (keyix >= IEEE80211_WEP_NKID) {
-               /*
-                * Don't touch keymap entries for global keys so
-                * they are never considered for dynamic allocation.
-                */
-               clrbit(sc->sc_keymap, keyix);
-               if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
-                   (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
-                       clrbit(sc->sc_keymap, keyix+64);        /* TX key MIC */
-                       if (sc->sc_splitmic) {
-                               /* +32 for RX key, +32+64 for RX key MIC */
-                               clrbit(sc->sc_keymap, keyix+32);
-                               clrbit(sc->sc_keymap, keyix+32+64);
-                       }
-               }
-       }
-       return 1;
+       ATH_PCU_LOCK(sc);
+       sc->sc_txstart_cnt--;
+       ATH_PCU_UNLOCK(sc);
+
+       ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: finished");
+       
+       return (retval);
 }
 
-/*
- * Set the key cache contents for the specified key.  Key cache
- * slot(s) must already have been allocated by ath_key_alloc.
- */
 static int
-ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
-       const u_int8_t mac[IEEE80211_ADDR_LEN])
+ath_media_change(struct ifnet *ifp)
 {
-       struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
-
-       return ath_keyset(sc, k, vap->iv_bss);
+       int error = ieee80211_media_change(ifp);
+       /* NB: only the fixed rate can change and that doesn't need a reset */
+       return (error == ENETRESET ? 0 : error);
 }
 
 /*
@@ -2341,6 +2999,7 @@ ath_key_update_begin(struct ieee80211vap *vap)
 
        DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
        taskqueue_block(sc->sc_tq);
+       IF_LOCK(&ifp->if_snd);          /* NB: doesn't block mgmt frames */
 }
 
 static void
@@ -2350,80 +3009,10 @@ ath_key_update_end(struct ieee80211vap *vap)
        struct ath_softc *sc = ifp->if_softc;
 
        DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
+       IF_UNLOCK(&ifp->if_snd);
        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 BAR frames for 11n
- * 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;
-       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;
-       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)
 {
@@ -2450,9 +3039,7 @@ ath_update_mcast(struct ifnet *ifp)
                 * Merge multicast addresses to form the hardware filter.
                 */
                mfilt[0] = mfilt[1] = 0;
-#ifdef __FreeBSD__
                if_maddr_rlock(ifp);    /* XXX need some fiddling to remove? */
-#endif
                TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
                        caddr_t dl;
                        u_int32_t val;
@@ -2467,9 +3054,7 @@ ath_update_mcast(struct ifnet *ifp)
                        pos &= 0x3f;
                        mfilt[pos / 32] |= (1 << (pos % 32));
                }
-#ifdef __FreeBSD__
                if_maddr_runlock(ifp);
-#endif
        } else
                mfilt[0] = mfilt[1] = ~0;
        ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]);
@@ -2477,7 +3062,7 @@ ath_update_mcast(struct ifnet *ifp)
                __func__, mfilt[0], mfilt[1]);
 }
 
-static void
+void
 ath_mode_init(struct ath_softc *sc)
 {
        struct ifnet *ifp = sc->sc_ifp;
@@ -2491,6 +3076,13 @@ ath_mode_init(struct ath_softc *sc)
        /* 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));
 
@@ -2501,7 +3093,7 @@ ath_mode_init(struct ath_softc *sc)
 /*
  * 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;
@@ -2554,908 +3146,377 @@ ath_updateslot(struct ifnet *ifp)
 }
 
 /*
- * Setup a h/w transmit queue for beacons.
+ * Append the contents of src to dst; both queues
+ * are assumed to be locked.
  */
-static int
-ath_beaconq_setup(struct ath_hal *ah)
+void
+ath_txqmove(struct ath_txq *dst, struct ath_txq *src)
 {
-       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);
+       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;
 }
 
 /*
- * Setup the transmit queue parameters for the beacon queue.
+ * Reset the hardware, with no loss.
+ *
+ * This can't be used for a general case reset.
  */
-static int
-ath_beaconq_config(struct ath_softc *sc)
+static void
+ath_reset_proc(void *arg, int pending)
 {
-#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;
+       struct ath_softc *sc = arg;
+       struct ifnet *ifp = sc->sc_ifp;
 
-       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
+#if 0
+       if_printf(ifp, "%s: resetting\n", __func__);
+#endif
+       ath_reset(ifp, ATH_RESET_NOLOSS);
 }
 
 /*
- * Allocate and setup an initial beacon frame.
+ * Reset the hardware after detecting beacons have stopped.
  */
-static int
-ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
+static void
+ath_bstuck_proc(void *arg, int pending)
 {
-       struct ieee80211vap *vap = ni->ni_vap;
-       struct ath_vap *avp = ATH_VAP(vap);
-       struct ath_buf *bf;
-       struct mbuf *m;
-       int error;
+       struct ath_softc *sc = arg;
+       struct ifnet *ifp = sc->sc_ifp;
+       uint32_t hangs = 0;
 
-       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;
-       }
+       if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0)
+               if_printf(ifp, "bb hang detected (0x%x)\n", hangs);
 
-       /*
-        * 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_segment(sc->sc_dmat, bf->bf_dmamap, m,
-                                    bf->bf_segs, 1, &bf->bf_nseg,
-                                    BUS_DMA_NOWAIT);
-       if (error != 0) {
-               device_printf(sc->sc_dev,
-                   "%s: cannot map mbuf, bus_dmamap_load_mbuf_segment returns %d\n",
-                   __func__, error);
-               m_freem(m);
-               return error;
-       }
+#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++;
        /*
-        * 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.
+        * This assumes that there's no simultaneous channel mode change
+        * occuring.
         */
-       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,
-                   (unsigned long long) 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
+       ath_reset(ifp, ATH_RESET_NOLOSS);
 }
 
 static void
-ath_beacon_update(struct ieee80211vap *vap, int item)
+ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
-       struct ieee80211_beacon_offsets *bo = &ATH_VAP(vap)->av_boff;
-
-       setbit(bo->bo_flags, item);
+       bus_addr_t *paddr = (bus_addr_t*) arg;
+       KASSERT(error == 0, ("error %u on bus_dma callback", error));
+       *paddr = segs->ds_addr;
 }
 
 /*
- * Append the contents of src to dst; both queues
- * are assumed to be locked.
+ * 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.
  */
-static void
-ath_txqmove(struct ath_txq *dst, struct ath_txq *src)
+int
+ath_descdma_alloc_desc(struct ath_softc *sc,
+       struct ath_descdma *dd, ath_bufhead *head,
+       const char *name, int ds_size, int ndesc)
 {
-       STAILQ_CONCAT(&dst->axq_q, &src->axq_q);
-       if (src->axq_depth)
-               dst->axq_link = src->axq_link;
-       src->axq_link = NULL;
-       dst->axq_depth += src->axq_depth;
-       src->axq_depth = 0;
-}
+#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;
+       int error;
 
-/*
- * Transmit a beacon frame at SWBA.  Dynamic updates to the
- * frame contents are done as needed and the slot time is
- * also adjusted based on current state.
- */
-static void
-ath_beacon_proc(void *arg, int pending)
-{
-       struct ath_softc *sc = arg;
-       struct ath_hal *ah = sc->sc_ah;
-       struct ieee80211vap *vap;
-       struct ath_buf *bf;
-       int slot, otherant;
-       uint32_t bfaddr;
+       dd->dd_descsize = ds_size;
 
-       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++;
-               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;
-       }
+       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 = dd->dd_descsize * ndesc;
 
        /*
-        * Stop any current dma before messing with the beacon linkages.
+        * Merlin work-around:
+        * Descriptors that cross the 4KB boundary can't be used.
+        * Assume one skipped descriptor per 4KB page.
         */
-       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);
-       }
-
-       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 */
+       if (! ath_hal_split4ktrans(sc->sc_ah)) {
+               int numpages = dd->dd_desc_len / 4096;
+               dd->dd_desc_len += ds_size * numpages;
        }
 
        /*
-        * 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.
+        * Setup DMA descriptor area.
+        *
+        * BUS_DMA_ALLOCNOW is not used; we never use bounce
+        * buffers for the descriptors themselves.
         */
-       /* 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 */
+       error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */
+                      PAGE_SIZE, 0,            /* alignment, bounds */
+                      BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+                      BUS_SPACE_MAXADDR,       /* highaddr */
+                      NULL, NULL,              /* filter, filterarg */
+                      dd->dd_desc_len,         /* maxsize */
+                      1,                       /* nsegments */
+                      dd->dd_desc_len,         /* maxsegsize */
+                      0,                       /* flags */
+                      NULL,                    /* lockfunc */
+                      NULL,                    /* lockarg */
+                      &dd->dd_dmat);
+       if (error != 0) {
+               if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name);
+               return error;
+       }
 
-       /*
-        * 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;
+       /* allocate descriptors */
+       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", ndesc, dd->dd_name, error);
+               goto fail1;
        }
 
-       if (bfaddr != 0) {
-               /* NB: cabq traffic should already be queued and primed */
-               ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr);
-               sc->sc_stats.ast_be_xmit++;
-               ath_hal_txstart(ah, sc->sc_bhalq);
+       error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
+                               dd->dd_desc, dd->dd_desc_len,
+                               ath_load_cb, &dd->dd_desc_paddr,
+                               BUS_DMA_NOWAIT);
+       if (error != 0) {
+               if_printf(ifp, "unable to map %s descriptors, error %u\n",
+                       dd->dd_name, error);
+               goto fail2;
        }
-       /* else no beacon will be generated */
+
+       DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
+           __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
 }
 
-static struct ath_buf *
-ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
+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)
 {
-       struct ath_vap *avp = ATH_VAP(vap);
-       struct ath_txq *cabq = sc->sc_cabq;
+#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;
-       struct mbuf *m;
-       int nmcastq, error;
+       int i, bsize, error;
 
-       KASSERT(vap->iv_state >= IEEE80211_S_RUN,
-           ("not running, state %d", vap->iv_state));
-       KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
+       /* Allocate descriptors */
+       error = ath_descdma_alloc_desc(sc, dd, head, name, ds_size,
+           nbuf * ndesc);
 
-       /*
-        * 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_segment(sc->sc_dmat, bf->bf_dmamap, m,
-                                            bf->bf_segs, 1, &bf->bf_nseg,
-                                            BUS_DMA_NOWAIT);
-               if (error != 0) {
-                       if_printf(vap->iv_ifp,
-                           "%s: bus_dmamap_load_mbuf_segment 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);
-               }
+       /* Assume any errors during allocation were dealt with */
+       if (error != 0) {
+               return (error);
        }
-       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;
+       ds = (uint8_t *) dd->dd_desc;
 
-               /* NB: only at DTIM */
-               if (nmcastq) {
-                       struct ath_buf *bfm;
-                       int qbusy;
+       /* 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);
+               goto fail3;
+       }
+       dd->dd_bufptr = bf;
 
+       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)) {
                        /*
-                        * Move frames from the s/w mcast q to the h/w cab q.
-                        * XXX MORE_DATA bit
+                        * Merlin WAR: Skip descriptor addresses which
+                        * cause 4KB boundary crossing along any point
+                        * in the descriptor.
                         */
-                       bfm = STAILQ_FIRST(&avp->av_mcastq.axq_q);
-                       qbusy = ath_hal_txqenabled(ah, cabq->axq_qnum);
-                       if (qbusy == 0) {
-                               if (cabq->axq_link != NULL) {
-                                       cpu_sfence();
-                                       *cabq->axq_link = bfm->bf_daddr;
-                                       cabq->axq_flags |= ATH_TXQ_PUTPENDING;
-                               } else {
-                                       cpu_sfence();
-                                       ath_hal_puttxbuf(ah, cabq->axq_qnum,
-                                               bfm->bf_daddr);
-                               }
-                       } else {
-                               if (cabq->axq_link != NULL) {
-                                       cpu_sfence();
-                                       *cabq->axq_link = bfm->bf_daddr;
-                               }
-                               cabq->axq_flags |= ATH_TXQ_PUTPENDING;
+                        if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr,
+                            dd->dd_descsize)) {
+                               /* Start at the next page */
+                               ds += 0x1000 - (bf->bf_daddr & 0xFFF);
+                               bf->bf_desc = (struct ath_desc *) ds;
+                               bf->bf_daddr = DS2PHYS(dd, ds);
                        }
-                       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);
-       }
-       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_segment(sc->sc_dmat, bf->bf_dmamap, m,
-                                            bf->bf_segs, 1, &bf->bf_nseg,
-                                            BUS_DMA_NOWAIT);
+               error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
+                               &bf->bf_dmamap);
                if (error != 0) {
-                       if_printf(vap->iv_ifp,
-                           "%s: bus_dmamap_load_mbuf_segment failed, error %u\n",
-                           __func__, error);
-                       return;
+                       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;
                }
+               bf->bf_lastds = bf->bf_desc;    /* Just an initial value */
+               TAILQ_INSERT_TAIL(head, bf, bf_list);
        }
-       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);
+       /*
+        * 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);
+       bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+       bus_dma_tag_destroy(dd->dd_dmat);
+       memset(dd, 0, sizeof(*dd));
+       return error;
+#undef DS2PHYS
+#undef ATH_DESC_4KB_BOUND_CHECK
 }
 
 /*
- * Reset the hardware after detecting beacons have stopped.
+ * Allocate ath_buf entries but no descriptor contents.
+ *
+ * This is for RX EDMA where the descriptors are the header part of
+ * the RX buffer.
  */
-static void
-ath_bstuck_task(void *arg, int pending)
+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 ath_softc *sc = arg;
        struct ifnet *ifp = sc->sc_ifp;
+       struct ath_buf *bf;
+       int i, bsize, error;
 
-       wlan_serialize_enter();
-       if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n",
-                 sc->sc_bmisscount);
-       sc->sc_stats.ast_bstuck++;
-       ath_reset(ifp);
-       wlan_serialize_exit();
-}
+       DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers\n",
+           __func__, name, nbuf);
 
-/*
- * Reclaim beacon resources and return buffer to the pool.
- */
-static void
-ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf)
-{
+       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;
 
-       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;
+       /* 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;
        }
-       STAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list);
-}
+       dd->dd_bufptr = bf;
 
-/*
- * Reclaim beacon resources.
- */
-static void
-ath_beacon_free(struct ath_softc *sc)
-{
-       struct ath_buf *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 */
 
-       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;
+               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;
                }
-               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;
-       KASSERT(error == 0, ("error %u on bus_dma callback", error));
-       *paddr = segs->ds_addr;
-}
-
-static int
-ath_descdma_setup(struct ath_softc *sc,
-       struct ath_descdma *dd, ath_bufhead *head,
-       const char *name, int nbuf, int ndesc)
-{
-#define        DS2PHYS(_dd, _ds) \
-       ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-       struct ifnet *ifp = sc->sc_ifp;
-       struct ath_desc *ds;
-       struct ath_buf *bf;
-       int i, bsize, error;
-
-       DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n",
-           __func__, name, nbuf, ndesc);
-
-       dd->dd_name = name;
-       dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
-       /*
-        * Setup DMA descriptor area.
-        */
-       error = bus_dma_tag_create(dd->dd_dmat, /* parent */
-                      PAGE_SIZE, 0,            /* alignment, bounds */
-                      BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
-                      BUS_SPACE_MAXADDR,       /* highaddr */
-                      NULL, NULL,              /* filter, filterarg */
-                      dd->dd_desc_len,         /* maxsize */
-                      1,                       /* nsegments */
-                      dd->dd_desc_len,         /* maxsegsize */
-                      BUS_DMA_ALLOCNOW,        /* flags */
-                      &dd->dd_dmat);
-       if (error != 0) {
-               if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name);
-               return error;
-       }
-
-       /* 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);
-               goto fail1;
-       }
-
-       error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
-                               dd->dd_desc, dd->dd_desc_len,
-                               ath_load_cb, &dd->dd_desc_paddr,
-                               BUS_DMA_NOWAIT);
-       if (error != 0) {
-               if_printf(ifp, "unable to map %s descriptors, error %u\n",
-                       dd->dd_name, error);
-               goto fail2;
-       }
-
-       ds = 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);
-
-       /* allocate rx buffers */
-       bsize = sizeof(struct ath_buf) * nbuf;
-       bf = kmalloc(bsize, M_ATHDEV, M_INTWAIT | M_ZERO);
-       dd->dd_bufptr = bf;
-
-       STAILQ_INIT(head);
-       for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
-               bf->bf_desc = ds;
-               bf->bf_daddr = DS2PHYS(dd, ds);
-               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;
-               }
-               STAILQ_INSERT_TAIL(head, bf, bf_list);
+               TAILQ_INSERT_TAIL(head, bf, bf_list);
        }
        return 0;
-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);
+fail3:
        memset(dd, 0, sizeof(*dd));
        return error;
-#undef DS2PHYS
 }
 
-static void
+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 (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 (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);
+                       }
                }
        }
 
-       STAILQ_INIT(head);
-       kfree(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));
 }
 
@@ -3464,23 +3525,32 @@ ath_desc_alloc(struct ath_softc *sc)
 {
        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;
@@ -3494,8 +3564,9 @@ ath_desc_free(struct ath_softc *sc)
                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 *
@@ -3506,22 +3577,49 @@ ath_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
        const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space;
        struct ath_node *an;
 
-       an = kmalloc(space, M_80211_NODE, M_INTWAIT|M_ZERO);
+       an = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO);
+       if (an == NULL) {
+               /* XXX stat+msg */
+               return NULL;
+       }
        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);
 }
 
@@ -3539,153 +3637,10 @@ ath_node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
                *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(MB_WAIT, MT_DATA, M_PKTHDR);
-               if (m == NULL) {
-                       kprintf("ath_rxbuf_init: no mbuf\n");
-                       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_segment(sc->sc_dmat,
-                                            bf->bf_dmamap, m,
-                                            bf->bf_segs, 1, &bf->bf_nseg,
-                                            BUS_DMA_NOWAIT);
-               if (error != 0) {
-                       DPRINTF(sc, ATH_DEBUG_ANY,
-                           "%s: bus_dmamap_load_mbuf_segment 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.
-        */
-       ds = bf->bf_desc;
-       ds->ds_link = bf->bf_daddr;     /* link to self */
-       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_tsf(u_int32_t rstamp, u_int64_t tsf)
-{
-       if ((tsf & 0x7fff) < rstamp)
-               tsf -= 0x8000;
-       return ((tsf &~ 0x7fff) | rstamp);
-}
-
-/*
- * 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;
-                       u_int64_t tsf = ath_extend_tsf(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;
@@ -3699,400 +3654,31 @@ ath_setdefantenna(struct ath_softc *sc, u_int antenna)
 }
 
 static void
-ath_rx_tap(struct ifnet *ifp, struct mbuf *m,
-       const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
+ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum)
 {
-#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(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
+       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;
+       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);
 }
 
-static void
-ath_handle_micerror(struct ieee80211com *ic,
-       struct ieee80211_frame *wh, int keyix)
+/*
+ * Setup a h/w transmit queue.
+ */
+static struct ath_txq *
+ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
 {
-       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_task(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;
-       struct ieee80211com *ic;
-       struct ath_hal *ah;
-       struct ath_desc *ds;
-       struct ath_rx_status *rs;
-       struct mbuf *m;
-       struct ieee80211_node *ni;
-       int len, type, ngood;
-       u_int phyerr;
-       HAL_STATUS status;
-       int16_t nf;
-       u_int64_t tsf;
-
-       wlan_serialize_enter();
-       ifp = sc->sc_ifp;
-       ic = ifp->if_l2com;
-       ah = sc->sc_ah;
-
-       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 (bf == NULL) {               /* NB: shouldn't happen */
-                       if_printf(ifp, "%s: no buffer!\n", __func__);
-                       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 */
-                       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);
-               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++;
-                               phyerr = rs->rs_phyerr & 0x1f;
-                               sc->sc_stats.ast_rx_phy[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);
-                               }
-                       }
-                       IFNET_STAT_INC(ifp, ierrors, 1);
-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;
-               }
-
-               IFNET_STAT_INC(ifp, ipackets, 1);
-               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);
-               if (ni != NULL) {
-                       /*
-                        * Sending station is known, dispatch directly.
-                        */
-                       sc->sc_lastrs = rs;
-                       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;
-               }
-               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;
-
-       if (!ifq_is_oactive(&ifp->if_snd)) {
-#ifdef IEEE80211_SUPPORT_SUPERG
-               ieee80211_ff_age_all(ic, 100);
-#endif
-               if (!ifq_is_empty(&ifp->if_snd))
-                       if_devstart(ifp);
-       }
-       wlan_serialize_exit();
-#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_intrcnt = 0;
-       txq->axq_link = NULL;
-       STAILQ_INIT(&txq->axq_q);
-}
-
-/*
- * Setup a h/w transmit queue.
- */
-static struct ath_txq *
-ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
-{
-       struct ath_hal *ah = sc->sc_ah;
-       HAL_TXQ_INFO qi;
-       int qnum;
+#define        N(a)    (sizeof(a)/sizeof(a[0]))
+       struct ath_hal *ah = sc->sc_ah;
+       HAL_TXQ_INFO qi;
+       int qnum;
 
        memset(&qi, 0, sizeof(qi));
        qi.tqi_subtype = subtype;
@@ -4111,7 +3697,13 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
         * 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) {
                /*
@@ -4120,10 +3712,10 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
                 */
                return NULL;
        }
-       if (qnum >= NELEM(sc->sc_txq)) {
+       if (qnum >= N(sc->sc_txq)) {
                device_printf(sc->sc_dev,
                        "hal qnum %u out of range, max %zu!\n",
-                       qnum, NELEM(sc->sc_txq));
+                       qnum, N(sc->sc_txq));
                ath_hal_releasetxqueue(ah, qnum);
                return NULL;
        }
@@ -4132,6 +3724,7 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
                sc->sc_txqsetup |= 1<<qnum;
        }
        return &sc->sc_txq[qnum];
+#undef N
 }
 
 /*
@@ -4146,11 +3739,12 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
 static int
 ath_tx_setup(struct ath_softc *sc, int ac, int haltype)
 {
+#define        N(a)    (sizeof(a)/sizeof(a[0]))
        struct ath_txq *txq;
 
-       if (ac >= NELEM(sc->sc_ac2q)) {
+       if (ac >= N(sc->sc_ac2q)) {
                device_printf(sc->sc_dev, "AC %u out of range, max %zu!\n",
-                       ac, NELEM(sc->sc_ac2q));
+                       ac, N(sc->sc_ac2q));
                return 0;
        }
        txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype);
@@ -4160,6 +3754,7 @@ ath_tx_setup(struct ath_softc *sc, int ac, int haltype)
                return 1;
        } else
                return 0;
+#undef N
 }
 
 /*
@@ -4202,10 +3797,15 @@ ath_txq_update(struct ath_softc *sc, int ac)
                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);
@@ -4237,7 +3837,7 @@ ath_txq_update(struct ath_softc *sc, int ac)
 /*
  * 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;
@@ -4257,6 +3857,7 @@ ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
 
        ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum);
        sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
+       ATH_TXQ_LOCK_DESTROY(txq);
 }
 
 /*
@@ -4267,6 +3868,7 @@ ath_tx_cleanup(struct ath_softc *sc)
 {
        int i;
 
+       ATH_TXBUF_LOCK_DESTROY(sc);
        for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i))
                        ath_tx_cleanupq(sc, &sc->sc_txq[i]);
@@ -4276,7 +3878,7 @@ ath_tx_cleanup(struct ath_softc *sc)
  * Return h/w rate index for an IEEE rate (w/o basic rate bit)
  * using the current rates in sc_rixmap.
  */
-static __inline int
+int
 ath_tx_findrix(const struct ath_softc *sc, uint8_t rate)
 {
        int rix = sc->sc_rixmap[rate];
@@ -4284,737 +3886,336 @@ ath_tx_findrix(const struct ath_softc *sc, uint8_t rate)
        return (rix == 0xff ? 0 : rix);
 }
 
-/*
- * Reclaim mbuf resources.  For fragmented frames we
- * need to claim each frag chained with m_nextpkt.
- */
 static void
-ath_freetx(struct mbuf *m)
+ath_tx_update_stats(struct ath_softc *sc, struct ath_tx_status *ts,
+    struct ath_buf *bf)
 {
-       struct mbuf *next;
+       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;
 
-       do {
-               next = m->m_nextpkt;
-               m->m_nextpkt = NULL;
-               m_freem(m);
-       } while ((m = next) != NULL);
 }
 
-static int
-ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
+/*
+ * 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)
 {
-       int error;
+       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));
 
        /*
-        * 
-        * Load the DMA map so any coalescing is done.  This
-        * also calculates the number of descriptors we need.
+        * 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.
         */
-       error = bus_dmamap_load_mbuf_defrag(sc->sc_dmat, bf->bf_dmamap, &m0,
-                                    bf->bf_segs, ATH_TXDESC,
-                                    &bf->bf_nseg, BUS_DMA_NOWAIT);
-       if (error != 0) {
-               sc->sc_stats.ast_tx_busdma++;
-               ath_freetx(m0);
-               return error;
+       if (bf->bf_node) {
+               ATH_TX_LOCK(sc);
+               ath_tx_update_tim(sc, bf->bf_node, 0);
+               ATH_TX_UNLOCK(sc);
        }
 
        /*
-        * Discard null packets.
+        * 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.
         */
-       if (bf->bf_nseg == 0) {         /* null packet, discard */
-               sc->sc_stats.ast_tx_nodata++;
-               ath_freetx(m0);
-               return EIO;
-       }
-       DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n",
-               __func__, m0, m0->m_pkthdr.len);
-       bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
-       bf->bf_m = m0;
-
-       return 0;
+       ath_tx_freebuf(sc, bf, st);
 }
 
-static void
-ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
+/*
+ * 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_hal *ah = sc->sc_ah;
-       struct ath_desc *ds, *ds0;
-       int i;
+       struct ath_node *an;
 
-       /*
-        * 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;
-               if (i == bf->bf_nseg - 1)
-                       ds->ds_link = 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 */
-                       , i == bf->bf_nseg - 1  /* last segment */
-                       , ds0                   /* first descriptor */
-               );
-               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]);
-       }
-       /*
-        * Insert the frame on the outbound list and pass it on
-        * to the hardware.  Multicast frames buffered for power
-        * save stations and transmit from the CAB queue are stored
-        * on a s/w only queue and loaded on to the CAB queue in
-        * the SWBA handler since frames only go out on DTIM and
-        * to avoid possible races.
-        */
-       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
-               /*
-                * Supporting transmit dma.  If the queue is busy it is
-                * impossible to determine if we've won the race against
-                * the chipset checking the link field or not, so we don't
-                * try.  Instead we let the TX interrupt detect the case
-                * and restart the transmitter.
-                *
-                * If the queue is not busy we can start things rolling
-                * right here.
-                */
-               int qbusy;
+       /* Only for unicast frames */
+       if (ni == NULL)
+               return;
 
-               ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
-               qbusy = ath_hal_txqenabled(ah, txq->axq_qnum);
+       an = ATH_NODE(ni);
+       ATH_NODE_UNLOCK_ASSERT(an);
 
-               if (qbusy == 0) {
-                       if (txq->axq_link != NULL) {
-                               /*
-                                * We had already started one previously but
-                                * not yet processed the TX interrupt.  Don't
-                                * try to race a restart because we do not
-                                * know where it stopped, let the TX interrupt
-                                * restart us when it figures out where we
-                                * stopped.
-                                */
-                               cpu_sfence();
-                               *txq->axq_link = bf->bf_daddr;
-                               txq->axq_flags |= ATH_TXQ_PUTPENDING;
-                       } else {
-                               /*
-                                * We are first in line, we can safely start
-                                * at this address.
-                                */
-                               cpu_sfence();
-                               ath_hal_puttxbuf(ah, txq->axq_qnum,
-                                                bf->bf_daddr);
-                       }
-               } else {
-                       /*
-                        * The queue is busy, go ahead and link us in but
-                        * do not try to start/restart the tx.  We just
-                        * don't know whether it will pick up our link
-                        * or not and we don't want to double-xmit.
-                        */
-                       if (txq->axq_link != NULL) {
-                               cpu_sfence();
-                               *txq->axq_link = bf->bf_daddr;
-                       }
-                       txq->axq_flags |= ATH_TXQ_PUTPENDING;
-               }
-#if 0
-                               ath_hal_puttxbuf(ah, txq->axq_qnum,
-                                       STAILQ_FIRST(&txq->axq_q)->bf_daddr);
-#endif
-#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;
-
-                       /* 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);
-
-                       /* 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;
+       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);
        }
 }
 
-static int
-ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
-    struct mbuf *m0)
+/*
+ * 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 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 */
-       struct ath_desc *ds;
-       struct ath_txq *txq;
-       struct ieee80211_frame *wh;
-       u_int subtype, flags, ctsduration;
-       HAL_PKT_TYPE atype;
-       const HAL_RATE_TABLE *rt;
-       HAL_BOOL shortPreamble;
-       struct ath_node *an;
-       u_int pri;
+       struct ieee80211_node *ni = bf->bf_node;
+       struct ath_node *an = NULL;
 
-       wh = mtod(m0, struct ieee80211_frame *);
-       iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
-       ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
-       isfrag = m0->m_flags & M_FRAG;
-       hdrlen = ieee80211_anyhdrsize(wh);
-       /*
-        * Packet length must not include any
-        * pad bytes; deduct them here.
-        */
-       pktlen = m0->m_pkthdr.len - (hdrlen & 3);
+       ATH_TX_UNLOCK_ASSERT(sc);
+       ATH_TXQ_UNLOCK_ASSERT(txq);
 
-       if (iswep) {
-               const struct ieee80211_cipher *cip;
-               struct ieee80211_key *k;
+       /* If unicast frame, update general statistics */
+       if (ni != NULL) {
+               an = ATH_NODE(ni);
+               /* update statistics */
+               ath_tx_update_stats(sc, ts, bf);
+       }
 
-               /*
-                * Construct the 802.11 header+trailer for an encrypted
-                * frame. The only reason this can fail is because of an
-                * unknown or unsupported cipher/key type.
-                */
-               k = ieee80211_crypto_encap(ni, m0);
-               if (k == NULL) {
+       /*
+        * 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) {
                        /*
-                        * This can happen when the key is yanked after the
-                        * frame was queued.  Just discard the frame; the
-                        * 802.11 layer counts failures and provides
-                        * debugging/diagnostics.
+                        * XXX assume this isn't an aggregate
+                        * frame.
                         */
-                       ath_freetx(m0);
-                       return EIO;
+                       ath_tx_update_ratectrl(sc, ni,
+                            bf->bf_state.bfs_rc, ts,
+                           bf->bf_state.bfs_pktlen, 1,
+                           (ts->ts_status == 0 ? 0 : 1));
                }
-               /*
-                * Adjust the packet + header lengths for the crypto
-                * additions and calculate the h/w key index.  When
-                * a s/w mic is done the frame will have had any mic
-                * added to it prior to entry so m0->m_pkthdr.len will
-                * account for it. Otherwise we need to add it to the
-                * packet length.
-                */
-               cip = k->wk_cipher;
-               hdrlen += cip->ic_header;
-               pktlen += cip->ic_header + cip->ic_trailer;
-               /* NB: frags always have any TKIP MIC done in s/w */
-               if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag)
-                       pktlen += cip->ic_miclen;
-               keyix = k->wk_keyix;
-
-               /* packet header may have moved, reset our local pointer */
-               wh = mtod(m0, struct ieee80211_frame *);
-       } else if (ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
-               /*
-                * Use station key cache slot, if assigned.
-                */
-               keyix = ni->ni_ucastkey.wk_keyix;
-               if (keyix == IEEE80211_KEYIX_NONE)
-                       keyix = HAL_TXKEYIX_INVALID;
+               ath_tx_default_comp(sc, bf, 0);
        } else
-               keyix = HAL_TXKEYIX_INVALID;
+               bf->bf_comp(sc, bf, 0);
+}
 
-       pktlen += IEEE80211_CRC_LEN;
 
-       /*
-        * Load the DMA map so any coalescing is done.  This
-        * also calculates the number of descriptors we need.
-        */
-       error = ath_tx_dmasetup(sc, bf, m0);
-       if (error != 0) {
-               return error;
-       }
-       bf->bf_node = ni;                       /* NB: held reference */
-       m0 = bf->bf_m;                          /* NB: may have changed */
-       wh = mtod(m0, struct ieee80211_frame *);
 
-       /* setup descriptors */
-       ds = bf->bf_desc;
-       rt = sc->sc_currates;
-       KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+/*
+ * 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, int dosched)
+{
+       struct ath_hal *ah = sc->sc_ah;
+       struct ath_buf *bf;
+       struct ath_desc *ds;
+       struct ath_tx_status *ts;
+       struct ieee80211_node *ni;
+#ifdef IEEE80211_SUPPORT_SUPERG
+       struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+#endif /* IEEE80211_SUPPORT_SUPERG */
+       int nacked;
+       HAL_STATUS status;
 
-       /*
-        * NB: the 802.11 layer marks whether or not we should
-        * use short preamble based on the current mode and
-        * negotiated parameters.
-        */
-       if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
-           (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
-               shortPreamble = AH_TRUE;
-               sc->sc_stats.ast_tx_shortpre++;
-       } else {
-               shortPreamble = AH_FALSE;
-       }
+       DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n",
+               __func__, txq->axq_qnum,
+               (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum),
+               txq->axq_link);
 
-       an = ATH_NODE(ni);
-       flags = HAL_TXDESC_CLRDMASK;            /* XXX needed for crypto errs */
-       ismrr = 0;                              /* default no multi-rate retry*/
-       pri = M_WME_GETAC(m0);                  /* honor classification */
-       /* XXX use txparams instead of fixed values */
-       /*
-        * Calculate Atheros packet type from IEEE80211 packet header,
-        * setup for rate calculations, and select h/w transmit queue.
-        */
-       switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
-       case IEEE80211_FC0_TYPE_MGT:
-               subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
-               if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
-                       atype = HAL_PKT_TYPE_BEACON;
-               else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
-                       atype = HAL_PKT_TYPE_PROBE_RESP;
-               else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM)
-                       atype = HAL_PKT_TYPE_ATIM;
-               else
-                       atype = HAL_PKT_TYPE_NORMAL;    /* XXX */
-               rix = an->an_mgmtrix;
-               txrate = rt->info[rix].rateCode;
-               if (shortPreamble)
-                       txrate |= rt->info[rix].shortPreamble;
-               try0 = ATH_TXMGTTRY;
-               flags |= HAL_TXDESC_INTREQ;     /* force interrupt */
-               break;
-       case IEEE80211_FC0_TYPE_CTL:
-               atype = HAL_PKT_TYPE_PSPOLL;    /* stop setting of duration */
-               rix = an->an_mgmtrix;
-               txrate = rt->info[rix].rateCode;
-               if (shortPreamble)
-                       txrate |= rt->info[rix].shortPreamble;
-               try0 = ATH_TXMGTTRY;
-               flags |= HAL_TXDESC_INTREQ;     /* force interrupt */
-               break;
-       case IEEE80211_FC0_TYPE_DATA:
-               atype = HAL_PKT_TYPE_NORMAL;            /* default */
-               /*
-                * Data frames: multicast frames go out at a fixed rate,
-                * EAPOL frames use the mgmt frame rate; otherwise consult
-                * the rate control module for the rate to use.
-                */
-               if (ismcast) {
-                       rix = an->an_mcastrix;
-                       txrate = rt->info[rix].rateCode;
-                       if (shortPreamble)
-                               txrate |= rt->info[rix].shortPreamble;
-                       try0 = 1;
-               } else if (m0->m_flags & M_EAPOL) {
-                       /* XXX? maybe always use long preamble? */
-                       rix = an->an_mgmtrix;
-                       txrate = rt->info[rix].rateCode;
-                       if (shortPreamble)
-                               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;
-               }
-               if (cap->cap_wmeParams[pri].wmep_noackPolicy)
-                       flags |= HAL_TXDESC_NOACK;
-               break;
-       default:
-               if_printf(ifp, "bogus frame type 0x%x (%s)\n",
-                       wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
-               /* XXX statistic */
-               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.
-        */
-       if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
-               txq = &avp->av_mcastq;
-
-       /*
-        * Calculate miscellaneous flags.
-        */
-       if (ismcast) {
-               flags |= HAL_TXDESC_NOACK;      /* no ack on broad/multicast */
-       } 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 */
-               sc->sc_stats.ast_tx_noack++;
-#ifdef IEEE80211_SUPPORT_TDMA
-       if (sc->sc_tdma && (flags & HAL_TXDESC_NOACK) == 0) {
-               DPRINTF(sc, ATH_DEBUG_TDMA,
-                   "%s: discard frame, ACK required w/ TDMA\n", __func__);
-               sc->sc_stats.ast_tdma_ack++;
-               ath_freetx(m0);
-               return EIO;
-       }
-#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++;
-       }
-
-       /*
-        * 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);
-       }
-
-       /*
-        * Calculate RTS/CTS rate and duration if needed.
-        */
-       ctsduration = 0;
-       if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
-               /*
-                * CTS transmit rate is derived from the transmit rate
-                * by looking in the h/w rate table.  We must also factor
-                * in whether or not a short preamble is to be used.
-                */
-               /* NB: cix is set above where RTS/CTS is enabled */
-  &n